From d7ac4f486bf178ef8e1587e14b4bbfe1c901dbf1 Mon Sep 17 00:00:00 2001 From: M66B Date: Thu, 9 May 2019 14:55:59 +0200 Subject: [PATCH] Updated recyclerview-selection: to version 1.1.0-alpha05 --- app/build.gradle | 2 +- .../selection/DefaultSelectionTracker.java | 2 +- .../selection/GestureSelectionHelper.java | 62 ++++++++----------- .../recyclerview/selection/GridModel.java | 6 +- .../selection/ItemDetailsLookup.java | 7 ++- .../recyclerview/selection/MotionEvents.java | 8 --- .../selection/MotionInputHandler.java | 2 +- .../selection/MouseInputHandler.java | 2 +- .../recyclerview/selection/Selection.java | 14 ++--- .../selection/SelectionTracker.java | 44 +++++++++---- .../selection/StableIdKeyProvider.java | 28 ++++++--- .../selection/TouchInputHandler.java | 40 +++++------- .../recyclerview/selection/package-info.java | 6 +- 13 files changed, 118 insertions(+), 105 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7801ff8686..825c71598d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -134,7 +134,7 @@ dependencies { // https://mvnrepository.com/artifact/androidx.recyclerview/recyclerview // https://mvnrepository.com/artifact/androidx.recyclerview/recyclerview-selection implementation "androidx.recyclerview:recyclerview:$recyclerview_version" - //implementation "androidx.recyclerview:recyclerview-selection:1.1.0-alpha01" + //implementation "androidx.recyclerview:recyclerview-selection:1.1.0-alpha05" // https://mvnrepository.com/artifact/androidx.coordinatorlayout/coordinatorlayout implementation "androidx.coordinatorlayout:coordinatorlayout:$coordinatorlayout_version" diff --git a/app/src/main/java/androidx/recyclerview/selection/DefaultSelectionTracker.java b/app/src/main/java/androidx/recyclerview/selection/DefaultSelectionTracker.java index 014d2c64fa..0635f91ad8 100644 --- a/app/src/main/java/androidx/recyclerview/selection/DefaultSelectionTracker.java +++ b/app/src/main/java/androidx/recyclerview/selection/DefaultSelectionTracker.java @@ -348,7 +348,7 @@ public class DefaultSelectionTracker extends SelectionTracker { } @Override - AdapterDataObserver getAdapterDataObserver() { + protected AdapterDataObserver getAdapterDataObserver() { return mAdapterObserver; } diff --git a/app/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java b/app/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java index f127576102..7f2a5bb252 100644 --- a/app/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java +++ b/app/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java @@ -19,7 +19,6 @@ package androidx.recyclerview.selection; import static androidx.core.util.Preconditions.checkArgument; import static androidx.core.util.Preconditions.checkState; -import android.graphics.Point; import android.util.Log; import android.view.MotionEvent; import android.view.View; @@ -27,6 +26,7 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.core.view.ViewCompat; +import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener; @@ -41,12 +41,11 @@ final class GestureSelectionHelper implements OnItemTouchListener { private static final String TAG = "GestureSelectionHelper"; private final SelectionTracker mSelectionMgr; - private final ItemDetailsLookup mDetailsLookup; + private final SelectionTracker.SelectionPredicate mSelectionPredicate; private final AutoScroller mScroller; private final ViewDelegate mView; private final OperationMonitor mLock; - private int mLastStartedItemPos = RecyclerView.NO_POSITION; private boolean mStarted = false; /** @@ -55,19 +54,19 @@ final class GestureSelectionHelper implements OnItemTouchListener { */ GestureSelectionHelper( @NonNull SelectionTracker selectionTracker, - @NonNull ItemDetailsLookup detailsLookup, + @NonNull SelectionPredicate selectionPredicate, @NonNull ViewDelegate view, @NonNull AutoScroller scroller, @NonNull OperationMonitor lock) { checkArgument(selectionTracker != null); - checkArgument(detailsLookup != null); + checkArgument(selectionPredicate != null); checkArgument(view != null); checkArgument(scroller != null); checkArgument(lock != null); mSelectionMgr = selectionTracker; - mDetailsLookup = detailsLookup; + mSelectionPredicate = selectionPredicate; mView = view; mScroller = scroller; mLock = lock; @@ -78,16 +77,9 @@ final class GestureSelectionHelper implements OnItemTouchListener { */ void start() { checkState(!mStarted); - // See: b/70518185. It appears start() is being called via onLongPress - // even though we never received an intial handleInterceptedDownEvent - // where we would usually initialize mLastStartedItemPos. - if (mLastStartedItemPos == RecyclerView.NO_POSITION) { - Log.w(TAG, "Illegal state. Can't start without valid mLastStartedItemPos."); - return; - } // Partner code in MotionInputHandler ensures items - // are selected and range established prior to + // are selected and range anchor initialized prior to // start being called. // Verify the truth of that statement here // to make the implicit coupling less of a time bomb. @@ -102,20 +94,14 @@ final class GestureSelectionHelper implements OnItemTouchListener { @Override /** @hide */ public boolean onInterceptTouchEvent(@NonNull RecyclerView unused, @NonNull MotionEvent e) { - if (MotionEvents.isMouseEvent(e)) { - if (Shared.DEBUG) Log.w(TAG, "Unexpected Mouse event. Check configuration."); - } - - // TODO(b/109808552): It seems that mLastStartedItemPos should likely be set as a method - // parameter in start(). - if (e.getActionMasked() == MotionEvent.ACTION_DOWN) { - if (mDetailsLookup.getItemDetails(e) != null) { - mLastStartedItemPos = mView.getItemUnder(e); - } + switch (e.getActionMasked()) { + case MotionEvent.ACTION_MOVE: + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + return mStarted; + default: + return false; } - - // See handleTouch(MotionEvent) javadoc for explanation as to why this is correct. - return handleTouch(e); } @Override @@ -146,6 +132,14 @@ final class GestureSelectionHelper implements OnItemTouchListener { return false; } + if (!mSelectionMgr.isRangeActive()) { + Log.e(TAG, + "Internal state of GestureSelectionHelper out of sync w/ SelectionTracker " + + "(isRangeActive is false). Ignoring event and resetting state."); + endSelection(); + return false; + } + switch (e.getActionMasked()) { case MotionEvent.ACTION_MOVE: handleMoveEvent(e); @@ -172,9 +166,6 @@ final class GestureSelectionHelper implements OnItemTouchListener { private void handleUpEvent() { mSelectionMgr.mergeProvisionalSelection(); endSelection(); - if (mLastStartedItemPos != RecyclerView.NO_POSITION) { - mSelectionMgr.startRange(mLastStartedItemPos); - } } // Called when ACTION_CANCEL event is to be handled. @@ -188,7 +179,6 @@ final class GestureSelectionHelper implements OnItemTouchListener { private void endSelection() { checkState(mStarted); - mLastStartedItemPos = RecyclerView.NO_POSITION; mStarted = false; mScroller.reset(); mLock.stop(); @@ -197,14 +187,12 @@ final class GestureSelectionHelper implements OnItemTouchListener { // Call when an intercepted ACTION_MOVE event is passed down. // At this point, we are sure user wants to gesture multi-select. private void handleMoveEvent(@NonNull MotionEvent e) { - Point lastInterceptedPoint = MotionEvents.getOrigin(e); - int lastGlidedItemPos = mView.getLastGlidedItemPosition(e); - if (lastGlidedItemPos != RecyclerView.NO_POSITION) { + if (mSelectionPredicate.canSetStateAtPosition(lastGlidedItemPos, true)) { extendSelection(lastGlidedItemPos); } - mScroller.scroll(lastInterceptedPoint); + mScroller.scroll(MotionEvents.getOrigin(e)); } // It's possible for events to go over the top/bottom of the RecyclerView. @@ -232,14 +220,14 @@ final class GestureSelectionHelper implements OnItemTouchListener { */ static GestureSelectionHelper create( @NonNull SelectionTracker selectionMgr, - @NonNull ItemDetailsLookup detailsLookup, + @NonNull SelectionPredicate selectionPredicate, @NonNull RecyclerView recyclerView, @NonNull AutoScroller scroller, @NonNull OperationMonitor lock) { return new GestureSelectionHelper( selectionMgr, - detailsLookup, + selectionPredicate, new RecyclerViewDelegate(recyclerView), scroller, lock); diff --git a/app/src/main/java/androidx/recyclerview/selection/GridModel.java b/app/src/main/java/androidx/recyclerview/selection/GridModel.java index 406ae618ff..17958ad55a 100644 --- a/app/src/main/java/androidx/recyclerview/selection/GridModel.java +++ b/app/src/main/java/androidx/recyclerview/selection/GridModel.java @@ -33,7 +33,7 @@ import androidx.recyclerview.widget.RecyclerView.OnScrollListener; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -84,7 +84,7 @@ final class GridModel { // Array passed to registered OnSelectionChangedListeners. One array is created and reused // throughout the lifetime of the object. - private final Set mSelection = new HashSet<>(); + private final Set mSelection = new LinkedHashSet<>(); // The current pointer (in absolute positioning from the top of the view). private Point mPointer; @@ -259,7 +259,7 @@ final class GridModel { private void updateModel() { RelativePoint old = mRelPointer; mRelPointer = createRelativePoint(mPointer); - if (old != null && mRelPointer.equals(old)) { + if (mRelPointer.equals(old)) { return; } diff --git a/app/src/main/java/androidx/recyclerview/selection/ItemDetailsLookup.java b/app/src/main/java/androidx/recyclerview/selection/ItemDetailsLookup.java index 9cb6d34551..d032e2b2a9 100644 --- a/app/src/main/java/androidx/recyclerview/selection/ItemDetailsLookup.java +++ b/app/src/main/java/androidx/recyclerview/selection/ItemDetailsLookup.java @@ -16,10 +16,13 @@ package androidx.recyclerview.selection; +import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; + import android.view.MotionEvent; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RestrictTo; import androidx.recyclerview.widget.RecyclerView; /** @@ -67,8 +70,10 @@ public abstract class ItemDetailsLookup { /** * @return true if there is an item w/ a stable ID at the event coordinates. + * @hide */ - final boolean overItemWithSelectionKey(@NonNull MotionEvent e) { + @RestrictTo(LIBRARY_GROUP) + protected boolean overItemWithSelectionKey(@NonNull MotionEvent e) { return overItem(e) && hasSelectionKey(getItemDetails(e)); } diff --git a/app/src/main/java/androidx/recyclerview/selection/MotionEvents.java b/app/src/main/java/androidx/recyclerview/selection/MotionEvents.java index bc47a76ccf..fbc4014b37 100644 --- a/app/src/main/java/androidx/recyclerview/selection/MotionEvents.java +++ b/app/src/main/java/androidx/recyclerview/selection/MotionEvents.java @@ -33,18 +33,10 @@ final class MotionEvents { return e.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE; } - static boolean isTouchEvent(@NonNull MotionEvent e) { - return e.getToolType(0) == MotionEvent.TOOL_TYPE_FINGER; - } - static boolean isActionMove(@NonNull MotionEvent e) { return e.getActionMasked() == MotionEvent.ACTION_MOVE; } - static boolean isActionDown(@NonNull MotionEvent e) { - return e.getActionMasked() == MotionEvent.ACTION_DOWN; - } - static boolean isActionUp(@NonNull MotionEvent e) { return e.getActionMasked() == MotionEvent.ACTION_UP; } diff --git a/app/src/main/java/androidx/recyclerview/selection/MotionInputHandler.java b/app/src/main/java/androidx/recyclerview/selection/MotionInputHandler.java index a7eb208358..0a3d324683 100644 --- a/app/src/main/java/androidx/recyclerview/selection/MotionInputHandler.java +++ b/app/src/main/java/androidx/recyclerview/selection/MotionInputHandler.java @@ -88,7 +88,7 @@ abstract class MotionInputHandler extends SimpleOnGestureListener { mFocusDelegate.focusItem(details); } - final boolean isRangeExtension(@NonNull MotionEvent e) { + final boolean shouldExtendRange(@NonNull MotionEvent e) { return MotionEvents.isShiftKeyPressed(e) && mSelectionTracker.isRangeActive() // Without full corpus access we can't reliably implement range diff --git a/app/src/main/java/androidx/recyclerview/selection/MouseInputHandler.java b/app/src/main/java/androidx/recyclerview/selection/MouseInputHandler.java index ca45137a00..e4f4548db9 100644 --- a/app/src/main/java/androidx/recyclerview/selection/MouseInputHandler.java +++ b/app/src/main/java/androidx/recyclerview/selection/MouseInputHandler.java @@ -126,7 +126,7 @@ final class MouseInputHandler extends MotionInputHandler { checkState(mSelectionTracker.hasSelection()); checkArgument(item != null); - if (isRangeExtension(e)) { + if (shouldExtendRange(e)) { extendSelectionRange(item); } else { if (shouldClearSelection(e, item)) { diff --git a/app/src/main/java/androidx/recyclerview/selection/Selection.java b/app/src/main/java/androidx/recyclerview/selection/Selection.java index 78c816fb15..155789d91f 100644 --- a/app/src/main/java/androidx/recyclerview/selection/Selection.java +++ b/app/src/main/java/androidx/recyclerview/selection/Selection.java @@ -19,9 +19,9 @@ package androidx.recyclerview.selection; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; @@ -65,8 +65,8 @@ public class Selection implements Iterable { final Set mProvisionalSelection; Selection() { - mSelection = new HashSet<>(); - mProvisionalSelection = new HashSet<>(); + mSelection = new LinkedHashSet<>(); + mProvisionalSelection = new LinkedHashSet<>(); } /** @@ -74,7 +74,7 @@ public class Selection implements Iterable { */ Selection(@NonNull Set selection) { mSelection = selection; - mProvisionalSelection = new HashSet<>(); + mProvisionalSelection = new LinkedHashSet<>(); } /** @@ -117,7 +117,7 @@ public class Selection implements Iterable { * @return Map of ids added or removed. Added ids have a value of true, removed are false. */ Map setProvisionalSelection(@NonNull Set newSelection) { - Map delta = new HashMap<>(); + Map delta = new LinkedHashMap<>(); for (K key: mProvisionalSelection) { // Mark each item that used to be in the provisional selection @@ -128,7 +128,7 @@ public class Selection implements Iterable { } for (K key: mSelection) { - // Mark each item that used to be in the selection but is unsaved and not in the new + // Mark each item that in the selection but is not in the new // provisional selection. if (!newSelection.contains(key)) { delta.put(key, false); diff --git a/app/src/main/java/androidx/recyclerview/selection/SelectionTracker.java b/app/src/main/java/androidx/recyclerview/selection/SelectionTracker.java index f59bd9b692..1591ff4bf9 100644 --- a/app/src/main/java/androidx/recyclerview/selection/SelectionTracker.java +++ b/app/src/main/java/androidx/recyclerview/selection/SelectionTracker.java @@ -16,6 +16,7 @@ package androidx.recyclerview.selection; +import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; import static androidx.core.util.Preconditions.checkArgument; import android.content.Context; @@ -28,6 +29,7 @@ import android.view.MotionEvent; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RestrictTo; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver; import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener; @@ -177,7 +179,9 @@ public abstract class SelectionTracker { */ public abstract boolean deselect(@NonNull K key); - abstract AdapterDataObserver getAdapterDataObserver(); + /** @hide */ + @RestrictTo(LIBRARY_GROUP) + protected abstract AdapterDataObserver getAdapterDataObserver(); /** * Attempts to establish a range selection at {@code position}, selecting the item @@ -186,8 +190,10 @@ public abstract class SelectionTracker { * @param position The "anchor" position for the range. Subsequent range operations * (primarily keyboard and mouse based operations like SHIFT + click) * work with the established anchor point to define selection ranges. + * @hide */ - abstract void startRange(int position); + @RestrictTo(LIBRARY_GROUP) + public abstract void startRange(int position); /** * Sets the end point for the active range selection. @@ -200,20 +206,26 @@ public abstract class SelectionTracker { * @param position The new end position for the selection range. * @throws IllegalStateException if a range selection is not active. Range selection * must have been started by a call to {@link #startRange(int)}. + * @hide */ - abstract void extendRange(int position); + @RestrictTo(LIBRARY_GROUP) + public abstract void extendRange(int position); /** * Clears an in-progress range selection. Provisional range selection established * using {@link #extendProvisionalRange(int)} will be cleared (unless * {@link #mergeProvisionalSelection()} is called first.) + * @hide */ - abstract void endRange(); + @RestrictTo(LIBRARY_GROUP) + public abstract void endRange(); /** * @return Whether or not there is a current range selection active. + * @hide */ - abstract boolean isRangeActive(); + @RestrictTo(LIBRARY_GROUP) + public abstract boolean isRangeActive(); /** * Establishes the "anchor" at which a selection range begins. This "anchor" is consulted @@ -223,32 +235,42 @@ public abstract class SelectionTracker { * TODO: Reconcile this with startRange. Maybe just docs need to be updated. * * @param position the anchor position. Must already be selected. + * @hide */ - abstract void anchorRange(int position); + @RestrictTo(LIBRARY_GROUP) + public abstract void anchorRange(int position); /** * Creates a provisional selection from anchor to {@code position}. * * @param position the end point. + * @hide */ - abstract void extendProvisionalRange(int position); + @RestrictTo(LIBRARY_GROUP) + protected abstract void extendProvisionalRange(int position); /** * Sets the provisional selection, replacing any existing selection. * @param newSelection + * @hide */ - abstract void setProvisionalSelection(@NonNull Set newSelection); + @RestrictTo(LIBRARY_GROUP) + protected abstract void setProvisionalSelection(@NonNull Set newSelection); /** * Clears any existing provisional selection + * @hide */ - abstract void clearProvisionalSelection(); + @RestrictTo(LIBRARY_GROUP) + protected abstract void clearProvisionalSelection(); /** * Converts the provisional selection into primary selection, then clears * provisional selection. + * @hide */ - abstract void mergeProvisionalSelection(); + @RestrictTo(LIBRARY_GROUP) + protected abstract void mergeProvisionalSelection(); /** * Preserves selection, if any. Call this method from Activity#onSaveInstanceState @@ -689,7 +711,7 @@ public abstract class SelectionTracker { // of motions and gestures in order to provide gesture driven selection support // when used in conjunction with RecyclerView. final GestureSelectionHelper gestureHelper = GestureSelectionHelper.create( - tracker, mDetailsLookup, mRecyclerView, scroller, mMonitor); + tracker, mSelectionPredicate, mRecyclerView, scroller, mMonitor); // Finally hook the framework up to listening to recycle view events. mRecyclerView.addOnItemTouchListener(eventRouter); diff --git a/app/src/main/java/androidx/recyclerview/selection/StableIdKeyProvider.java b/app/src/main/java/androidx/recyclerview/selection/StableIdKeyProvider.java index b6c9a36a88..6a164ccc62 100644 --- a/app/src/main/java/androidx/recyclerview/selection/StableIdKeyProvider.java +++ b/app/src/main/java/androidx/recyclerview/selection/StableIdKeyProvider.java @@ -16,17 +16,18 @@ package androidx.recyclerview.selection; +import static androidx.recyclerview.selection.Shared.DEBUG; + +import android.util.Log; import android.util.SparseArray; import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.collection.LongSparseArray; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener; -import java.util.HashMap; -import java.util.Map; - /** * An {@link ItemKeyProvider} that provides stable ids by way of cached * {@link RecyclerView.Adapter} stable ids. Items enter the cache as they are laid out by @@ -39,8 +40,10 @@ import java.util.Map; */ public final class StableIdKeyProvider extends ItemKeyProvider { + private static final String TAG = "StableIdKeyProvider"; + private final SparseArray mPositionToKey = new SparseArray<>(); - private final Map mKeyToPosition = new HashMap(); + private final LongSparseArray mKeyToPosition = new LongSparseArray<>(); private final RecyclerView mRecyclerView; /** @@ -76,6 +79,12 @@ public final class StableIdKeyProvider extends ItemKeyProvider { @SuppressWarnings("WeakerAccess") /* synthetic access */ void onAttached(@NonNull View view) { RecyclerView.ViewHolder holder = mRecyclerView.findContainingViewHolder(view); + if (holder == null) { + if (DEBUG) { + Log.w(TAG, "Unable to find ViewHolder for View. Ignoring onAttached event."); + } + return; + } int position = holder.getAdapterPosition(); long id = holder.getItemId(); if (position != RecyclerView.NO_POSITION && id != RecyclerView.NO_ID) { @@ -87,6 +96,12 @@ public final class StableIdKeyProvider extends ItemKeyProvider { @SuppressWarnings("WeakerAccess") /* synthetic access */ void onDetached(@NonNull View view) { RecyclerView.ViewHolder holder = mRecyclerView.findContainingViewHolder(view); + if (holder == null) { + if (DEBUG) { + Log.w(TAG, "Unable to find ViewHolder for View. Ignoring onDetached event."); + } + return; + } int position = holder.getAdapterPosition(); long id = holder.getItemId(); if (position != RecyclerView.NO_POSITION && id != RecyclerView.NO_ID) { @@ -102,9 +117,6 @@ public final class StableIdKeyProvider extends ItemKeyProvider { @Override public int getPosition(@NonNull Long key) { - if (mKeyToPosition.containsKey(key)) { - return mKeyToPosition.get(key); - } - return RecyclerView.NO_POSITION; + return mKeyToPosition.get(key, RecyclerView.NO_POSITION); } } diff --git a/app/src/main/java/androidx/recyclerview/selection/TouchInputHandler.java b/app/src/main/java/androidx/recyclerview/selection/TouchInputHandler.java index b37ec2b51b..48db78ec8d 100644 --- a/app/src/main/java/androidx/recyclerview/selection/TouchInputHandler.java +++ b/app/src/main/java/androidx/recyclerview/selection/TouchInputHandler.java @@ -88,7 +88,7 @@ final class TouchInputHandler extends MotionInputHandler { } if (mSelectionTracker.hasSelection()) { - if (isRangeExtension(e)) { + if (shouldExtendRange(e)) { extendSelectionRange(item); } else if (mSelectionTracker.isSelected(item.getSelectionKey())) { mSelectionTracker.deselect(item.getSelectionKey()); @@ -126,32 +126,26 @@ final class TouchInputHandler extends MotionInputHandler { boolean handled = false; - if (isRangeExtension(e)) { + if (shouldExtendRange(e)) { extendSelectionRange(item); - handled = true; + mHapticPerformer.run(); } else { - if (!mSelectionTracker.isSelected(item.getSelectionKey()) - && mSelectionPredicate.canSetStateForKey(item.getSelectionKey(), true)) { - // If we cannot select it, we didn't apply anchoring - therefore should not - // start gesture selection - if (selectItem(item)) { - // And finally if the item was selected && we can select multiple - // we kick off gesture selection. - if (mSelectionPredicate.canSelectMultiple()) { - mGestureStarter.run(); - } - handled = true; - } - } else { - // We only initiate drag and drop on long press for touch to allow regular - // touch-based scrolling + if (mSelectionTracker.isSelected(item.getSelectionKey())) { + // Long press on existing selected item initiates drag/drop. mOnDragInitiatedListener.onDragInitiated(e); - handled = true; + mHapticPerformer.run(); + } else if (mSelectionPredicate.canSetStateForKey(item.getSelectionKey(), true) + && selectItem(item)) { + // And finally if the item was selected && we can select multiple + // we kick off gesture selection. + // NOTE: isRangeActive should ALWAYS be true at this point, but there have + // been reports indicating that assumption isn't correct. So we explicitly + // check isRangeActive. + if (mSelectionPredicate.canSelectMultiple() && mSelectionTracker.isRangeActive()) { + mGestureStarter.run(); + } + mHapticPerformer.run(); } } - - if (handled) { - mHapticPerformer.run(); - } } } diff --git a/app/src/main/java/androidx/recyclerview/selection/package-info.java b/app/src/main/java/androidx/recyclerview/selection/package-info.java index a3386ab9e2..f344ba227c 100644 --- a/app/src/main/java/androidx/recyclerview/selection/package-info.java +++ b/app/src/main/java/androidx/recyclerview/selection/package-info.java @@ -116,9 +116,9 @@ * Include Selection in Activity lifecycle events * *

- * In order to preserve state the author must the selection library in handling - * of Activity lifecycle events. See SelectionTracker#onSaveInstanceState - * and SelectionTracker#onRestoreInstanceState. + * In order to preserve state, the author must include the selection library in the handling + * of Activity lifecycle events. See SelectionTracker#onSaveInstanceState and + * SelectionTracker#onRestoreInstanceState. * *

A unique selection id must be supplied to * {@link androidx.recyclerview.selection.SelectionTracker.Builder SelectionTracker.Builder}