Loading packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +20 −2 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.LayoutManager; import android.support.v7.widget.RecyclerView.OnItemTouchListener; import android.support.v7.widget.RecyclerView.RecyclerListener; import android.support.v7.widget.RecyclerView.ViewHolder; import android.text.TextUtils; Loading @@ -78,7 +79,6 @@ import android.util.TypedValue; import android.view.ActionMode; import android.view.DragEvent; import android.view.GestureDetector; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; Loading @@ -97,6 +97,7 @@ import com.android.documentsui.RecentsProvider.StateColumns; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.RootInfo; import com.google.common.collect.Lists; import java.util.ArrayList; Loading Loading @@ -299,12 +300,29 @@ public class DirectoryFragment extends Fragment { } }; final GestureDetector detector = new GestureDetector(this.getContext(), listener); detector.setOnDoubleTapListener(listener); mRecView.addOnItemTouchListener( new OnItemTouchListener() { @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { detector.onTouchEvent(e); return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) {} @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {} }); // TODO: instead of inserting the view into the constructor, extract listener-creation code // and set the listener on the view after the fact. Then the view doesn't need to be passed // into the selection manager. mSelectionManager = new MultiSelectManager( mRecView, listener, state.allowMultiple ? MultiSelectManager.MODE_MULTIPLE : MultiSelectManager.MODE_SINGLE); Loading packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java +39 −192 Original line number Diff line number Diff line Loading @@ -37,8 +37,6 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.view.GestureDetector; import android.view.GestureDetector.OnDoubleTapListener; import android.view.GestureDetector.OnGestureListener; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; Loading @@ -46,8 +44,6 @@ import android.view.View; import com.android.documentsui.Events.InputEvent; import com.android.documentsui.Events.MotionInputEvent; import com.google.android.collect.Lists; import java.util.ArrayList; import java.util.Collections; import java.util.List; Loading Loading @@ -78,30 +74,21 @@ public final class MultiSelectManager implements View.OnKeyListener { private final List<MultiSelectManager.Callback> mCallbacks = new ArrayList<>(1); private Adapter<?> mAdapter; private ItemFinder mHelper; private boolean mSingleSelect; @Nullable private BandController mBandManager; /** * @param recyclerView * @param gestureDelegate Option delegate gesture listener. * @param mode Selection mode * @template A gestureDelegate that implements both {@link OnGestureListener} * and {@link OnDoubleTapListener} */ public <L extends OnGestureListener & OnDoubleTapListener> MultiSelectManager( final RecyclerView recyclerView, L gestureDelegate, int mode) { this( recyclerView.getAdapter(), new RuntimeItemFinder(recyclerView), mode); public MultiSelectManager(final RecyclerView recyclerView, int mode) { this(recyclerView.getAdapter(), mode); mEnvironment = new RuntimeSelectionEnvironment(recyclerView); if (mode == MODE_MULTIPLE) { mBandManager = new BandController(mHelper); mBandManager = new BandController(); } GestureDetector.SimpleOnGestureListener listener = Loading @@ -118,15 +105,8 @@ public final class MultiSelectManager implements View.OnKeyListener { } }; CompositeOnGestureListener compositeListener = new CompositeOnGestureListener( Lists.<OnGestureListener>newArrayList(listener, gestureDelegate), Lists.<OnDoubleTapListener>newArrayList(listener, gestureDelegate)); final GestureDetector detector = new GestureDetector(recyclerView.getContext(), compositeListener); detector.setOnDoubleTapListener(compositeListener); final GestureDetector detector = new GestureDetector(recyclerView.getContext(), listener); detector.setOnDoubleTapListener(listener); recyclerView.addOnItemTouchListener( new RecyclerView.OnItemTouchListener() { Loading @@ -134,37 +114,15 @@ public final class MultiSelectManager implements View.OnKeyListener { public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { detector.onTouchEvent(e); if (mBandManager == null) { return false; } // b/23793622 notes the fact that we *never* receiver ACTION_DOWN // events in onTouchEvent. Where it not for this issue, we'd // push start handling down into handleInputEvent. if (mBandManager.shouldStart(e)) { // endBandSelect is handled in handleInputEvent. mBandManager.startBandSelect( new Point((int) e.getX(), (int) e.getY())); } else if (mBandManager.isActive() && Events.isMouseEvent(e) && Events.isActionUp(e)) { // Same issue here w b/23793622. The ACTION_UP event // is only evert dispatched to onTouchEvent when // there is some associated motion. If a user taps // mouse, but doesn't move, then band select gets // started BUT not ended. Causing phantom // bands to appear when the user later clicks to start // band select. mBandManager.handleInputEvent( new MotionInputEvent(e, recyclerView)); if (mBandManager != null) { return mBandManager.handleEvent(new MotionInputEvent(e, recyclerView)); } return mBandManager.isActive(); return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { mBandManager.handleInputEvent( mBandManager.processInputEvent( new MotionInputEvent(e, recyclerView)); } @Override Loading @@ -177,13 +135,11 @@ public final class MultiSelectManager implements View.OnKeyListener { * @hide */ @VisibleForTesting MultiSelectManager(Adapter<?> adapter, ItemFinder helper, int mode) { MultiSelectManager(Adapter<?> adapter, int mode) { checkNotNull(adapter, "'adapter' cannot be null."); checkNotNull(helper, "'helper' cannot be null."); mSingleSelect = mode == MODE_SINGLE; mHelper = helper; mAdapter = adapter; mAdapter.registerAdapterDataObserver( Loading Loading @@ -873,32 +829,6 @@ public final class MultiSelectManager implements View.OnKeyListener { } } /** * Provides functionality for MultiSelectManager. Exists primarily to tests that are * fully isolated from RecyclerView. */ interface ItemFinder { int findItemPosition(MotionEvent e); } /** ItemFinder implementation backed by good ol' RecyclerView. */ private static final class RuntimeItemFinder implements ItemFinder { private final RecyclerView mView; RuntimeItemFinder(RecyclerView view) { mView = view; } @Override public int findItemPosition(MotionEvent e) { View view = mView.findChildViewUnder(e.getX(), e.getY()); return view != null ? mView.getChildAdapterPosition(view) : RecyclerView.NO_POSITION; } } /** * Provides functionality for BandController. Exists primarily to tests that are * fully isolated from RecyclerView. Loading Loading @@ -1095,110 +1025,6 @@ public final class MultiSelectManager implements View.OnKeyListener { public void onSelectionChanged(); } /** * A composite {@code OnGestureDetector} that allows us to delegate unhandled * events to an outside party (presumably DirectoryFragment). * @template A gestureDelegate that implements both {@link OnGestureListener} * and {@link OnDoubleTapListener} */ private static final class CompositeOnGestureListener implements OnGestureListener, OnDoubleTapListener { private List<OnGestureListener> mGestureListeners; private List<OnDoubleTapListener> mTapListeners; public CompositeOnGestureListener( List<OnGestureListener> gestureListeners, List<OnDoubleTapListener> tapListeners) { mGestureListeners = gestureListeners; mTapListeners = tapListeners; } @Override public boolean onDown(MotionEvent e) { for (OnGestureListener l : mGestureListeners) { if (l.onDown(e)) { return true; } } return false; } @Override public void onShowPress(MotionEvent e) { for (OnGestureListener l : mGestureListeners) { l.onShowPress(e); } } @Override public boolean onSingleTapUp(MotionEvent e) { for (OnGestureListener l : mGestureListeners) { if (l.onSingleTapUp(e)) { return true; } } return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { for (OnGestureListener l : mGestureListeners) { if (l.onScroll(e1, e2, distanceX, distanceY)) { return true; } } return false; } @Override public void onLongPress(MotionEvent e) { for (OnGestureListener l : mGestureListeners) { l.onLongPress(e); } } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { for (OnGestureListener l : mGestureListeners) { if (l.onFling(e1, e2, velocityX, velocityY)) { return true; } } return false; } @Override public boolean onSingleTapConfirmed(MotionEvent e) { for (OnDoubleTapListener listener : mTapListeners) { if (listener.onSingleTapConfirmed(e)) { return true; } } return false; } @Override public boolean onDoubleTap(MotionEvent e) { for (OnDoubleTapListener listener : mTapListeners) { if (listener.onDoubleTap(e)) { return true; } } return false; } @Override public boolean onDoubleTapEvent(MotionEvent e) { for (OnDoubleTapListener listener : mTapListeners) { if (listener.onDoubleTapEvent(e)) { return true; } } return false; } } /** * Provides mouse driven band-select support when used in conjunction with {@link RecyclerView} * and {@link MultiSelectManager}. This class is responsible for rendering the band select Loading @@ -1209,7 +1035,6 @@ public final class MultiSelectManager implements View.OnKeyListener { private static final int NOT_SET = -1; private final ItemFinder mItemFinder; private final Runnable mModelBuilder; @Nullable private Rect mBounds; Loading @@ -1222,8 +1047,7 @@ public final class MultiSelectManager implements View.OnKeyListener { private long mScrollStartTime = NOT_SET; private final Runnable mViewScroller = new ViewScroller(); public BandController(ItemFinder finder) { mItemFinder = finder; public BandController() { mEnvironment.addOnScrollListener(this); mModelBuilder = new Runnable() { Loading @@ -1235,6 +1059,29 @@ public final class MultiSelectManager implements View.OnKeyListener { }; } public boolean handleEvent(MotionInputEvent e) { // b/23793622 notes the fact that we *never* receive ACTION_DOWN // events in onTouchEvent. Where it not for this issue, we'd // push start handling down into handleInputEvent. if (mBandManager.shouldStart(e)) { // endBandSelect is handled in handleInputEvent. mBandManager.startBandSelect(e.getOrigin()); } else if (mBandManager.isActive() && e.isMouseEvent() && e.isActionUp()) { // Same issue here w b/23793622. The ACTION_UP event // is only evert dispatched to onTouchEvent when // there is some associated motion. If a user taps // mouse, but doesn't move, then band select gets // started BUT not ended. Causing phantom // bands to appear when the user later clicks to start // band select. mBandManager.processInputEvent(e); } return isActive(); } private boolean isActive() { return mModel != null; } Loading @@ -1253,12 +1100,12 @@ public final class MultiSelectManager implements View.OnKeyListener { } } boolean shouldStart(MotionEvent e) { boolean shouldStart(MotionInputEvent e) { return !isActive() && Events.isMouseEvent(e) // a mouse && Events.isActionDown(e) // the initial button press && e.isMouseEvent() // a mouse && e.isActionDown() // the initial button press && mAdapter.getItemCount() > 0 && mItemFinder.findItemPosition(e) == RecyclerView.NO_ID; // in empty space && e.getItemPosition() == RecyclerView.NO_ID; // in empty space } boolean shouldStop(InputEvent input) { Loading @@ -1271,7 +1118,7 @@ public final class MultiSelectManager implements View.OnKeyListener { * Processes a MotionEvent by starting, ending, or resizing the band select overlay. * @param input */ private void handleInputEvent(InputEvent input) { private void processInputEvent(InputEvent input) { checkArgument(input.isMouseEvent()); if (shouldStop(input)) { Loading packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java +0 −2 Original line number Diff line number Diff line Loading @@ -22,10 +22,8 @@ import android.content.ContextWrapper; import android.database.Cursor; import android.database.MatrixCursor; import android.provider.DocumentsContract.Document; import android.support.v7.widget.RecyclerView.ViewHolder; import android.support.v7.widget.RecyclerView; import android.test.AndroidTestCase; import android.test.MoreAsserts; import android.test.mock.MockContentResolver; import android.view.ViewGroup; Loading packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java +4 −23 Original line number Diff line number Diff line Loading @@ -16,13 +16,9 @@ package com.android.documentsui; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.support.v7.widget.RecyclerView; import android.test.AndroidTestCase; import android.util.SparseBooleanArray; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; Loading Loading @@ -51,13 +47,11 @@ public class MultiSelectManagerTest extends AndroidTestCase { private MultiSelectManager mManager; private TestAdapter mAdapter; private TestCallback mCallback; private EventHelper mEventHelper; public void setUp() throws Exception { mAdapter = new TestAdapter(items); mCallback = new TestCallback(); mEventHelper = new EventHelper(); mManager = new MultiSelectManager(mAdapter, mEventHelper, MultiSelectManager.MODE_MULTIPLE); mManager = new MultiSelectManager(mAdapter, MultiSelectManager.MODE_MULTIPLE); mManager.addCallback(mCallback); } Loading Loading @@ -175,7 +169,7 @@ public class MultiSelectManagerTest extends AndroidTestCase { } public void testSingleSelectMode() { mManager = new MultiSelectManager(mAdapter, mEventHelper, MultiSelectManager.MODE_SINGLE); mManager = new MultiSelectManager(mAdapter, MultiSelectManager.MODE_SINGLE); mManager.addCallback(mCallback); longPress(20); tap(13); Loading @@ -183,7 +177,7 @@ public class MultiSelectManagerTest extends AndroidTestCase { } public void testSingleSelectMode_ShiftTap() { mManager = new MultiSelectManager(mAdapter, mEventHelper, MultiSelectManager.MODE_SINGLE); mManager = new MultiSelectManager(mAdapter, MultiSelectManager.MODE_SINGLE); mManager.addCallback(mCallback); longPress(13); shiftTap(20); Loading Loading @@ -269,26 +263,13 @@ public class MultiSelectManagerTest extends AndroidTestCase { assertEquals(selection.toString(), expected, selection.size()); } private static final class EventHelper implements MultiSelectManager.ItemFinder { @Override public int findItemPosition(MotionEvent e) { throw new UnsupportedOperationException(); } } private static final class TestCallback implements MultiSelectManager.Callback { Set<Integer> ignored = new HashSet<>(); private int mLastChangedPosition; private boolean mLastChangedSelected; private boolean mSelectionChanged = false; @Override public void onItemStateChanged(int position, boolean selected) { this.mLastChangedPosition = position; this.mLastChangedSelected = selected; } public void onItemStateChanged(int position, boolean selected) {} @Override public boolean onBeforeItemStateChange(int position, boolean selected) { Loading Loading
packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +20 −2 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.LayoutManager; import android.support.v7.widget.RecyclerView.OnItemTouchListener; import android.support.v7.widget.RecyclerView.RecyclerListener; import android.support.v7.widget.RecyclerView.ViewHolder; import android.text.TextUtils; Loading @@ -78,7 +79,6 @@ import android.util.TypedValue; import android.view.ActionMode; import android.view.DragEvent; import android.view.GestureDetector; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; Loading @@ -97,6 +97,7 @@ import com.android.documentsui.RecentsProvider.StateColumns; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.RootInfo; import com.google.common.collect.Lists; import java.util.ArrayList; Loading Loading @@ -299,12 +300,29 @@ public class DirectoryFragment extends Fragment { } }; final GestureDetector detector = new GestureDetector(this.getContext(), listener); detector.setOnDoubleTapListener(listener); mRecView.addOnItemTouchListener( new OnItemTouchListener() { @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { detector.onTouchEvent(e); return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) {} @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {} }); // TODO: instead of inserting the view into the constructor, extract listener-creation code // and set the listener on the view after the fact. Then the view doesn't need to be passed // into the selection manager. mSelectionManager = new MultiSelectManager( mRecView, listener, state.allowMultiple ? MultiSelectManager.MODE_MULTIPLE : MultiSelectManager.MODE_SINGLE); Loading
packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java +39 −192 Original line number Diff line number Diff line Loading @@ -37,8 +37,6 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.view.GestureDetector; import android.view.GestureDetector.OnDoubleTapListener; import android.view.GestureDetector.OnGestureListener; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; Loading @@ -46,8 +44,6 @@ import android.view.View; import com.android.documentsui.Events.InputEvent; import com.android.documentsui.Events.MotionInputEvent; import com.google.android.collect.Lists; import java.util.ArrayList; import java.util.Collections; import java.util.List; Loading Loading @@ -78,30 +74,21 @@ public final class MultiSelectManager implements View.OnKeyListener { private final List<MultiSelectManager.Callback> mCallbacks = new ArrayList<>(1); private Adapter<?> mAdapter; private ItemFinder mHelper; private boolean mSingleSelect; @Nullable private BandController mBandManager; /** * @param recyclerView * @param gestureDelegate Option delegate gesture listener. * @param mode Selection mode * @template A gestureDelegate that implements both {@link OnGestureListener} * and {@link OnDoubleTapListener} */ public <L extends OnGestureListener & OnDoubleTapListener> MultiSelectManager( final RecyclerView recyclerView, L gestureDelegate, int mode) { this( recyclerView.getAdapter(), new RuntimeItemFinder(recyclerView), mode); public MultiSelectManager(final RecyclerView recyclerView, int mode) { this(recyclerView.getAdapter(), mode); mEnvironment = new RuntimeSelectionEnvironment(recyclerView); if (mode == MODE_MULTIPLE) { mBandManager = new BandController(mHelper); mBandManager = new BandController(); } GestureDetector.SimpleOnGestureListener listener = Loading @@ -118,15 +105,8 @@ public final class MultiSelectManager implements View.OnKeyListener { } }; CompositeOnGestureListener compositeListener = new CompositeOnGestureListener( Lists.<OnGestureListener>newArrayList(listener, gestureDelegate), Lists.<OnDoubleTapListener>newArrayList(listener, gestureDelegate)); final GestureDetector detector = new GestureDetector(recyclerView.getContext(), compositeListener); detector.setOnDoubleTapListener(compositeListener); final GestureDetector detector = new GestureDetector(recyclerView.getContext(), listener); detector.setOnDoubleTapListener(listener); recyclerView.addOnItemTouchListener( new RecyclerView.OnItemTouchListener() { Loading @@ -134,37 +114,15 @@ public final class MultiSelectManager implements View.OnKeyListener { public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { detector.onTouchEvent(e); if (mBandManager == null) { return false; } // b/23793622 notes the fact that we *never* receiver ACTION_DOWN // events in onTouchEvent. Where it not for this issue, we'd // push start handling down into handleInputEvent. if (mBandManager.shouldStart(e)) { // endBandSelect is handled in handleInputEvent. mBandManager.startBandSelect( new Point((int) e.getX(), (int) e.getY())); } else if (mBandManager.isActive() && Events.isMouseEvent(e) && Events.isActionUp(e)) { // Same issue here w b/23793622. The ACTION_UP event // is only evert dispatched to onTouchEvent when // there is some associated motion. If a user taps // mouse, but doesn't move, then band select gets // started BUT not ended. Causing phantom // bands to appear when the user later clicks to start // band select. mBandManager.handleInputEvent( new MotionInputEvent(e, recyclerView)); if (mBandManager != null) { return mBandManager.handleEvent(new MotionInputEvent(e, recyclerView)); } return mBandManager.isActive(); return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { mBandManager.handleInputEvent( mBandManager.processInputEvent( new MotionInputEvent(e, recyclerView)); } @Override Loading @@ -177,13 +135,11 @@ public final class MultiSelectManager implements View.OnKeyListener { * @hide */ @VisibleForTesting MultiSelectManager(Adapter<?> adapter, ItemFinder helper, int mode) { MultiSelectManager(Adapter<?> adapter, int mode) { checkNotNull(adapter, "'adapter' cannot be null."); checkNotNull(helper, "'helper' cannot be null."); mSingleSelect = mode == MODE_SINGLE; mHelper = helper; mAdapter = adapter; mAdapter.registerAdapterDataObserver( Loading Loading @@ -873,32 +829,6 @@ public final class MultiSelectManager implements View.OnKeyListener { } } /** * Provides functionality for MultiSelectManager. Exists primarily to tests that are * fully isolated from RecyclerView. */ interface ItemFinder { int findItemPosition(MotionEvent e); } /** ItemFinder implementation backed by good ol' RecyclerView. */ private static final class RuntimeItemFinder implements ItemFinder { private final RecyclerView mView; RuntimeItemFinder(RecyclerView view) { mView = view; } @Override public int findItemPosition(MotionEvent e) { View view = mView.findChildViewUnder(e.getX(), e.getY()); return view != null ? mView.getChildAdapterPosition(view) : RecyclerView.NO_POSITION; } } /** * Provides functionality for BandController. Exists primarily to tests that are * fully isolated from RecyclerView. Loading Loading @@ -1095,110 +1025,6 @@ public final class MultiSelectManager implements View.OnKeyListener { public void onSelectionChanged(); } /** * A composite {@code OnGestureDetector} that allows us to delegate unhandled * events to an outside party (presumably DirectoryFragment). * @template A gestureDelegate that implements both {@link OnGestureListener} * and {@link OnDoubleTapListener} */ private static final class CompositeOnGestureListener implements OnGestureListener, OnDoubleTapListener { private List<OnGestureListener> mGestureListeners; private List<OnDoubleTapListener> mTapListeners; public CompositeOnGestureListener( List<OnGestureListener> gestureListeners, List<OnDoubleTapListener> tapListeners) { mGestureListeners = gestureListeners; mTapListeners = tapListeners; } @Override public boolean onDown(MotionEvent e) { for (OnGestureListener l : mGestureListeners) { if (l.onDown(e)) { return true; } } return false; } @Override public void onShowPress(MotionEvent e) { for (OnGestureListener l : mGestureListeners) { l.onShowPress(e); } } @Override public boolean onSingleTapUp(MotionEvent e) { for (OnGestureListener l : mGestureListeners) { if (l.onSingleTapUp(e)) { return true; } } return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { for (OnGestureListener l : mGestureListeners) { if (l.onScroll(e1, e2, distanceX, distanceY)) { return true; } } return false; } @Override public void onLongPress(MotionEvent e) { for (OnGestureListener l : mGestureListeners) { l.onLongPress(e); } } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { for (OnGestureListener l : mGestureListeners) { if (l.onFling(e1, e2, velocityX, velocityY)) { return true; } } return false; } @Override public boolean onSingleTapConfirmed(MotionEvent e) { for (OnDoubleTapListener listener : mTapListeners) { if (listener.onSingleTapConfirmed(e)) { return true; } } return false; } @Override public boolean onDoubleTap(MotionEvent e) { for (OnDoubleTapListener listener : mTapListeners) { if (listener.onDoubleTap(e)) { return true; } } return false; } @Override public boolean onDoubleTapEvent(MotionEvent e) { for (OnDoubleTapListener listener : mTapListeners) { if (listener.onDoubleTapEvent(e)) { return true; } } return false; } } /** * Provides mouse driven band-select support when used in conjunction with {@link RecyclerView} * and {@link MultiSelectManager}. This class is responsible for rendering the band select Loading @@ -1209,7 +1035,6 @@ public final class MultiSelectManager implements View.OnKeyListener { private static final int NOT_SET = -1; private final ItemFinder mItemFinder; private final Runnable mModelBuilder; @Nullable private Rect mBounds; Loading @@ -1222,8 +1047,7 @@ public final class MultiSelectManager implements View.OnKeyListener { private long mScrollStartTime = NOT_SET; private final Runnable mViewScroller = new ViewScroller(); public BandController(ItemFinder finder) { mItemFinder = finder; public BandController() { mEnvironment.addOnScrollListener(this); mModelBuilder = new Runnable() { Loading @@ -1235,6 +1059,29 @@ public final class MultiSelectManager implements View.OnKeyListener { }; } public boolean handleEvent(MotionInputEvent e) { // b/23793622 notes the fact that we *never* receive ACTION_DOWN // events in onTouchEvent. Where it not for this issue, we'd // push start handling down into handleInputEvent. if (mBandManager.shouldStart(e)) { // endBandSelect is handled in handleInputEvent. mBandManager.startBandSelect(e.getOrigin()); } else if (mBandManager.isActive() && e.isMouseEvent() && e.isActionUp()) { // Same issue here w b/23793622. The ACTION_UP event // is only evert dispatched to onTouchEvent when // there is some associated motion. If a user taps // mouse, but doesn't move, then band select gets // started BUT not ended. Causing phantom // bands to appear when the user later clicks to start // band select. mBandManager.processInputEvent(e); } return isActive(); } private boolean isActive() { return mModel != null; } Loading @@ -1253,12 +1100,12 @@ public final class MultiSelectManager implements View.OnKeyListener { } } boolean shouldStart(MotionEvent e) { boolean shouldStart(MotionInputEvent e) { return !isActive() && Events.isMouseEvent(e) // a mouse && Events.isActionDown(e) // the initial button press && e.isMouseEvent() // a mouse && e.isActionDown() // the initial button press && mAdapter.getItemCount() > 0 && mItemFinder.findItemPosition(e) == RecyclerView.NO_ID; // in empty space && e.getItemPosition() == RecyclerView.NO_ID; // in empty space } boolean shouldStop(InputEvent input) { Loading @@ -1271,7 +1118,7 @@ public final class MultiSelectManager implements View.OnKeyListener { * Processes a MotionEvent by starting, ending, or resizing the band select overlay. * @param input */ private void handleInputEvent(InputEvent input) { private void processInputEvent(InputEvent input) { checkArgument(input.isMouseEvent()); if (shouldStop(input)) { Loading
packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java +0 −2 Original line number Diff line number Diff line Loading @@ -22,10 +22,8 @@ import android.content.ContextWrapper; import android.database.Cursor; import android.database.MatrixCursor; import android.provider.DocumentsContract.Document; import android.support.v7.widget.RecyclerView.ViewHolder; import android.support.v7.widget.RecyclerView; import android.test.AndroidTestCase; import android.test.MoreAsserts; import android.test.mock.MockContentResolver; import android.view.ViewGroup; Loading
packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java +4 −23 Original line number Diff line number Diff line Loading @@ -16,13 +16,9 @@ package com.android.documentsui; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.support.v7.widget.RecyclerView; import android.test.AndroidTestCase; import android.util.SparseBooleanArray; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; Loading Loading @@ -51,13 +47,11 @@ public class MultiSelectManagerTest extends AndroidTestCase { private MultiSelectManager mManager; private TestAdapter mAdapter; private TestCallback mCallback; private EventHelper mEventHelper; public void setUp() throws Exception { mAdapter = new TestAdapter(items); mCallback = new TestCallback(); mEventHelper = new EventHelper(); mManager = new MultiSelectManager(mAdapter, mEventHelper, MultiSelectManager.MODE_MULTIPLE); mManager = new MultiSelectManager(mAdapter, MultiSelectManager.MODE_MULTIPLE); mManager.addCallback(mCallback); } Loading Loading @@ -175,7 +169,7 @@ public class MultiSelectManagerTest extends AndroidTestCase { } public void testSingleSelectMode() { mManager = new MultiSelectManager(mAdapter, mEventHelper, MultiSelectManager.MODE_SINGLE); mManager = new MultiSelectManager(mAdapter, MultiSelectManager.MODE_SINGLE); mManager.addCallback(mCallback); longPress(20); tap(13); Loading @@ -183,7 +177,7 @@ public class MultiSelectManagerTest extends AndroidTestCase { } public void testSingleSelectMode_ShiftTap() { mManager = new MultiSelectManager(mAdapter, mEventHelper, MultiSelectManager.MODE_SINGLE); mManager = new MultiSelectManager(mAdapter, MultiSelectManager.MODE_SINGLE); mManager.addCallback(mCallback); longPress(13); shiftTap(20); Loading Loading @@ -269,26 +263,13 @@ public class MultiSelectManagerTest extends AndroidTestCase { assertEquals(selection.toString(), expected, selection.size()); } private static final class EventHelper implements MultiSelectManager.ItemFinder { @Override public int findItemPosition(MotionEvent e) { throw new UnsupportedOperationException(); } } private static final class TestCallback implements MultiSelectManager.Callback { Set<Integer> ignored = new HashSet<>(); private int mLastChangedPosition; private boolean mLastChangedSelected; private boolean mSelectionChanged = false; @Override public void onItemStateChanged(int position, boolean selected) { this.mLastChangedPosition = position; this.mLastChangedSelected = selected; } public void onItemStateChanged(int position, boolean selected) {} @Override public boolean onBeforeItemStateChange(int position, boolean selected) { Loading