• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.documentsui.selection;
17 
18 import static com.android.documentsui.base.SharedMinimal.DEBUG;
19 
20 import android.support.v7.widget.RecyclerView;
21 import android.util.Log;
22 import android.view.MotionEvent;
23 
24 import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
25 import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
26 
27 /**
28  * A MotionInputHandler that provides the high-level glue for touch driven selection. This class
29  * works with {@link RecyclerView}, {@link GestureRouter}, and {@link GestureSelectionHelper} to
30  * provide robust user drive selection support.
31  */
32 public final class TouchInputHandler extends MotionInputHandler {
33     private static final String TAG = "TouchInputDelegate";
34 
35     private final SelectionPredicate mSelectionPredicate;
36     private final Callbacks mCallbacks;
37     private final Runnable mGestureKicker;
38 
TouchInputHandler( SelectionHelper selectionHelper, ItemDetailsLookup detailsLookup, SelectionPredicate selectionPredicate, Runnable gestureKicker, Callbacks callbacks)39     public TouchInputHandler(
40             SelectionHelper selectionHelper,
41             ItemDetailsLookup detailsLookup,
42             SelectionPredicate selectionPredicate,
43             Runnable gestureKicker,
44             Callbacks callbacks) {
45 
46         super(selectionHelper, detailsLookup, callbacks);
47 
48         mSelectionPredicate = selectionPredicate;
49         mGestureKicker = gestureKicker;
50         mCallbacks = callbacks;
51     }
52 
TouchInputHandler( SelectionHelper selectionHelper, ItemDetailsLookup detailsLookup, SelectionPredicate selectionPredicate, GestureSelectionHelper gestureHelper, Callbacks callbacks)53     public TouchInputHandler(
54             SelectionHelper selectionHelper,
55             ItemDetailsLookup detailsLookup,
56             SelectionPredicate selectionPredicate,
57             GestureSelectionHelper gestureHelper,
58             Callbacks callbacks) {
59 
60         this(
61                 selectionHelper,
62                 detailsLookup,
63                 selectionPredicate,
64                 new Runnable() {
65                     @Override
66                     public void run() {
67                         gestureHelper.start();
68                     }
69                 },
70                 callbacks);
71     }
72 
73     @Override
onSingleTapUp(MotionEvent e)74     public boolean onSingleTapUp(MotionEvent e) {
75         if (!mDetailsLookup.overStableItem(e)) {
76             if (DEBUG) Log.d(TAG, "Tap not associated w/ model item. Clearing selection.");
77             mSelectionHelper.clearSelection();
78             return false;
79         }
80 
81         ItemDetails item = mDetailsLookup.getItemDetails(e);
82         if (mSelectionHelper.hasSelection()) {
83             if (isRangeExtension(e)) {
84                 extendSelectionRange(item);
85             } else if (mSelectionHelper.isSelected(item.getStableId())) {
86                 mSelectionHelper.deselect(item.getStableId());
87             } else {
88                 selectItem(item);
89             }
90 
91             return true;
92         }
93 
94         // Touch events select if they occur in the selection hotspot,
95         // otherwise they activate.
96         return item.inSelectionHotspot(e)
97                 ? selectItem(item)
98                 : mCallbacks.onItemActivated(item, e);
99     }
100 
101     @Override
onLongPress(MotionEvent e)102     public final void onLongPress(MotionEvent e) {
103         if (!mDetailsLookup.overStableItem(e)) {
104             if (DEBUG) Log.d(TAG, "Ignoring LongPress on non-model-backed item.");
105             return;
106         }
107 
108         ItemDetails item = mDetailsLookup.getItemDetails(e);
109         boolean handled = false;
110 
111         if (isRangeExtension(e)) {
112             extendSelectionRange(item);
113             handled = true;
114         } else {
115             if (!mSelectionHelper.isSelected(item.getStableId())
116                     && mSelectionPredicate.canSetStateForId(item.getStableId(), true)) {
117                 // If we cannot select it, we didn't apply anchoring - therefore should not
118                 // start gesture selection
119                 if (selectItem(item)) {
120                     // And finally if the item was selected && we can select multiple
121                     // we kick off gesture selection.
122                     if (mSelectionPredicate.canSelectMultiple()) {
123                         mGestureKicker.run();
124                     }
125                     handled = true;
126                 }
127             } else {
128                 // We only initiate drag and drop on long press for touch to allow regular
129                 // touch-based scrolling
130                 // mTouchDragListener.accept(e);
131                 mCallbacks.onDragInitiated(e);
132                 handled = true;
133             }
134         }
135 
136         if (handled) {
137             mCallbacks.onPerformHapticFeedback();
138         }
139     }
140 
141     public static abstract class Callbacks extends MotionInputHandler.Callbacks {
onItemActivated(ItemDetails item, MotionEvent e)142         public abstract boolean onItemActivated(ItemDetails item, MotionEvent e);
onDragInitiated(MotionEvent e)143         public boolean onDragInitiated(MotionEvent e) {
144             return false;
145         }
146     }
147 }
148