summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/speeddial/draghelper/SpeedDialItemTouchHelperCallback.java
blob: fc963a1a3f8f03c8ed9833e64eb00158d57742a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.dialer.speeddial.draghelper;

import android.graphics.Canvas;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.support.v7.widget.helper.ItemTouchHelper;

/** {@link ItemTouchHelper} for Speed Dial favorite contacts. */
public class SpeedDialItemTouchHelperCallback extends ItemTouchHelper.Callback {

  private final ItemTouchHelperAdapter adapter;

  // When dragged item is in removeView, onMove() and onChildDraw() are called in turn. This
  // behavior changes when dragged item entering/leaving removeView. The boolean field
  // movedOverRemoveView is for onMove() and onChildDraw() to flip.
  private boolean movedOverRemoveView;
  private boolean inRemoveView;

  public SpeedDialItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
    this.adapter = adapter;
  }

  @Override
  public boolean isLongPressDragEnabled() {
    // We'll manually call ItemTouchHelper#startDrag
    return false;
  }

  @Override
  public boolean isItemViewSwipeEnabled() {
    // We don't want to enable swiping
    return false;
  }

  @Override
  public boolean canDropOver(
      @NonNull RecyclerView recyclerView, @NonNull ViewHolder current, @NonNull ViewHolder target) {
    return adapter.canDropOver(target);
  }

  @Override
  public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull ViewHolder viewHolder) {
    if (!adapter.canDropOver(viewHolder)) {
      return makeMovementFlags(0, 0);
    }

    int dragFlags =
        ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.START | ItemTouchHelper.END;
    return makeMovementFlags(dragFlags, /* swipeFlags */ 0);
  }

  @Override
  public boolean onMove(
      @NonNull RecyclerView recyclerView,
      @NonNull ViewHolder viewHolder,
      @NonNull ViewHolder target) {
    if (target.getItemViewType() == 0) { // 0 for RowType.REMOVE_VIEW
      movedOverRemoveView = true;
      if (!inRemoveView) {
        // onMove() first called
        adapter.enterRemoveView();
        inRemoveView = true;
      }
      return false;
    } else if (inRemoveView) {
      // Move out of removeView fast
      inRemoveView = false;
      movedOverRemoveView = false;
      adapter.leaveRemoveView();
    }
    adapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
    return true;
  }

  @Override
  public void onChildDraw(
      @NonNull Canvas canvas,
      @NonNull RecyclerView recyclerView,
      @NonNull ViewHolder viewHolder,
      float dx,
      float dy,
      int i,
      boolean isCurrentlyActive) {
    if (inRemoveView) {
      if (!isCurrentlyActive) {
        // View animating back to its original state, which means drop in this case
        inRemoveView = false;
        adapter.dropOnRemoveView(viewHolder);
      }
      if (!movedOverRemoveView) {
        // when the view is over a droppable target, onMove() will be called before onChildDraw()
        // thus if onMove() is not called, it is not over a droppable target.
        inRemoveView = false;
        adapter.leaveRemoveView();
      }
    }
    movedOverRemoveView = false;
    super.onChildDraw(canvas, recyclerView, viewHolder, dx, dy, i, isCurrentlyActive);
  }

  @Override
  public void onSelectedChanged(@Nullable ViewHolder viewHolder, int actionState) {
    super.onSelectedChanged(viewHolder, actionState);
    adapter.onSelectedChanged(viewHolder, actionState);
  }

  @Override
  public void onSwiped(@NonNull ViewHolder viewHolder, int direction) {
    // No-op since we don't support swiping
  }

  /** RecyclerView adapters interested in drag and drop should implement this interface. */
  public interface ItemTouchHelperAdapter {

    void onItemMove(int fromPosition, int toPosition);

    boolean canDropOver(ViewHolder target);

    void onSelectedChanged(@Nullable ViewHolder viewHolder, int actionState);

    void enterRemoveView();

    void leaveRemoveView();

    void dropOnRemoveView(ViewHolder fromViewHolder);
  }
}