summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Riddle Hsu <riddlehsu@google.com> 2018-06-21 22:06:43 +0800
committer Riddle Hsu <riddlehsu@google.com> 2018-08-22 00:03:13 +0800
commit0c3759895067adbca6b7b49bbe6628639f5d2ca1 (patch)
treeef052b4b59e39d0efd560b87d9551f59c2f7de58
parentd0193072513ec0f88983407081eca541e8654b68 (diff)
Migrate to use RecyclerView-Selection library
Test: atest DocumentsUITests Bug: 110482929 Change-Id: Icb99520ac48d120b8bed0ce461c5e4f2ff885c18
-rw-r--r--build_apk.mk3
-rw-r--r--src/com/android/documentsui/AbstractActionHandler.java18
-rw-r--r--src/com/android/documentsui/ActionHandler.java9
-rw-r--r--src/com/android/documentsui/ActionModeController.java15
-rw-r--r--src/com/android/documentsui/BaseActivity.java46
-rw-r--r--src/com/android/documentsui/ContentLock.java72
-rw-r--r--src/com/android/documentsui/DirectoryLoader.java1
-rw-r--r--src/com/android/documentsui/DocsSelectionHelper.java207
-rw-r--r--src/com/android/documentsui/DragHoverListener.java5
-rw-r--r--src/com/android/documentsui/DummySelectionTracker.java131
-rw-r--r--src/com/android/documentsui/FocusManager.java27
-rw-r--r--src/com/android/documentsui/Injector.java13
-rw-r--r--src/com/android/documentsui/Model.java25
-rw-r--r--src/com/android/documentsui/SharedInputHandler.java10
-rw-r--r--src/com/android/documentsui/ViewAutoScroller.java (renamed from src/com/android/documentsui/selection/ViewAutoScroller.java)9
-rw-r--r--src/com/android/documentsui/base/Events.java42
-rw-r--r--src/com/android/documentsui/clipping/DocumentClipper.java11
-rw-r--r--src/com/android/documentsui/clipping/RuntimeDocumentClipper.java13
-rw-r--r--src/com/android/documentsui/clipping/UrisSupplier.java7
-rw-r--r--src/com/android/documentsui/dirlist/DirectoryFragment.java176
-rw-r--r--src/com/android/documentsui/dirlist/DirectoryState.java14
-rw-r--r--src/com/android/documentsui/dirlist/DocsItemDetailsLookup.java51
-rw-r--r--src/com/android/documentsui/dirlist/DocsSelectionPredicate.java7
-rw-r--r--src/com/android/documentsui/dirlist/DocsStableIdProvider.java11
-rw-r--r--src/com/android/documentsui/dirlist/DocumentHolder.java49
-rw-r--r--src/com/android/documentsui/dirlist/DocumentItemDetails.java59
-rw-r--r--src/com/android/documentsui/dirlist/DragHost.java9
-rw-r--r--src/com/android/documentsui/dirlist/DragStartListener.java51
-rw-r--r--src/com/android/documentsui/dirlist/FocusHandler.java2
-rw-r--r--src/com/android/documentsui/dirlist/InputHandlers.java139
-rw-r--r--src/com/android/documentsui/dirlist/KeyInputHandler.java39
-rw-r--r--src/com/android/documentsui/dirlist/KeyboardEventListener.java7
-rw-r--r--src/com/android/documentsui/dirlist/MessageHolder.java5
-rw-r--r--src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java7
-rw-r--r--src/com/android/documentsui/dirlist/MouseDragEventInterceptor.java80
-rw-r--r--src/com/android/documentsui/dirlist/SelectionMetadata.java7
-rw-r--r--src/com/android/documentsui/files/ActionHandler.java31
-rw-r--r--src/com/android/documentsui/files/FilesActivity.java2
-rw-r--r--src/com/android/documentsui/files/MenuManager.java8
-rw-r--r--src/com/android/documentsui/picker/ActionHandler.java11
-rw-r--r--src/com/android/documentsui/picker/PickActivity.java4
-rw-r--r--src/com/android/documentsui/selection/BandPredicate.java59
-rw-r--r--src/com/android/documentsui/selection/BandSelectionHelper.java401
-rw-r--r--src/com/android/documentsui/selection/ContentLock.java96
-rw-r--r--src/com/android/documentsui/selection/DefaultBandHost.java147
-rw-r--r--src/com/android/documentsui/selection/DefaultBandPredicate.java46
-rw-r--r--src/com/android/documentsui/selection/DefaultSelectionHelper.java554
-rw-r--r--src/com/android/documentsui/selection/GestureRouter.java98
-rw-r--r--src/com/android/documentsui/selection/GestureSelectionHelper.java350
-rw-r--r--src/com/android/documentsui/selection/GridModel.java728
-rw-r--r--src/com/android/documentsui/selection/ItemDetailsLookup.java117
-rw-r--r--src/com/android/documentsui/selection/MotionEvents.java98
-rw-r--r--src/com/android/documentsui/selection/MotionInputHandler.java100
-rw-r--r--src/com/android/documentsui/selection/MouseInputHandler.java215
-rw-r--r--src/com/android/documentsui/selection/MutableSelection.java39
-rw-r--r--src/com/android/documentsui/selection/Range.java151
-rw-r--r--src/com/android/documentsui/selection/Selection.java302
-rw-r--r--src/com/android/documentsui/selection/SelectionHelper.java237
-rw-r--r--src/com/android/documentsui/selection/Shared.java28
-rw-r--r--src/com/android/documentsui/selection/ToolHandlerRegistry.java68
-rw-r--r--src/com/android/documentsui/selection/TouchEventRouter.java102
-rw-r--r--src/com/android/documentsui/selection/TouchInputHandler.java147
-rw-r--r--src/com/android/documentsui/selection/demo/DemoDetailsLookup.java81
-rw-r--r--src/com/android/documentsui/selection/demo/DemoHolder.java118
-rw-r--r--src/com/android/documentsui/selection/demo/DemoItem.java35
-rw-r--r--src/com/android/documentsui/selection/demo/DemoStableIdProvider.java51
-rw-r--r--src/com/android/documentsui/selection/demo/SelectionDemoActivity.java360
-rw-r--r--src/com/android/documentsui/selection/demo/SelectionDemoAdapter.java108
-rw-r--r--tests/common/com/android/documentsui/SelectionHelpers.java58
-rw-r--r--tests/common/com/android/documentsui/dirlist/TestDocumentsAdapter.java4
-rw-r--r--tests/common/com/android/documentsui/dirlist/TestFocusHandler.java2
-rw-r--r--tests/common/com/android/documentsui/testing/SelectionHelpers.java69
-rw-r--r--tests/common/com/android/documentsui/testing/TestActionHandler.java7
-rw-r--r--tests/common/com/android/documentsui/testing/TestDocumentClipper.java11
-rw-r--r--tests/common/com/android/documentsui/testing/TestEnv.java1
-rw-r--r--tests/common/com/android/documentsui/testing/TestStableIdProvider.java (renamed from tests/unit/com/android/documentsui/selection/testing/TestSelectionPredicate.java)28
-rw-r--r--tests/unit/com/android/documentsui/AbstractActionHandlerTest.java6
-rw-r--r--tests/unit/com/android/documentsui/DocsSelectionHelperTest.java93
-rw-r--r--tests/unit/com/android/documentsui/DragScrollListenerTest.java2
-rw-r--r--tests/unit/com/android/documentsui/FocusManagerTest.java11
-rw-r--r--tests/unit/com/android/documentsui/SharedInputHandlerTest.java6
-rw-r--r--tests/unit/com/android/documentsui/ViewAutoScrollerTest.java (renamed from tests/unit/com/android/documentsui/selection/ViewAutoScrollerTest.java)7
-rw-r--r--tests/unit/com/android/documentsui/dirlist/DocumentHolderTest.java5
-rw-r--r--tests/unit/com/android/documentsui/dirlist/DragHostTest.java8
-rw-r--r--tests/unit/com/android/documentsui/dirlist/DragStartListenerTest.java60
-rw-r--r--tests/unit/com/android/documentsui/dirlist/KeyInputHandlerTest.java38
-rw-r--r--tests/unit/com/android/documentsui/dirlist/TestItemDetails.java (renamed from tests/unit/com/android/documentsui/selection/TestItemDetails.java)13
-rw-r--r--tests/unit/com/android/documentsui/dirlist/TestItemDetailsLookup.java (renamed from tests/unit/com/android/documentsui/selection/TestItemDetailsLookup.java)36
-rw-r--r--tests/unit/com/android/documentsui/files/MenuManagerTest.java9
-rw-r--r--tests/unit/com/android/documentsui/selection/BandSelectionHelperTest.java298
-rw-r--r--tests/unit/com/android/documentsui/selection/ContentLockTest.java76
-rw-r--r--tests/unit/com/android/documentsui/selection/DefaultSelectionHelperTest.java409
-rw-r--r--tests/unit/com/android/documentsui/selection/DefaultSelectionHelper_SingleSelectTest.java84
-rw-r--r--tests/unit/com/android/documentsui/selection/GestureRouterTest.java285
-rw-r--r--tests/unit/com/android/documentsui/selection/GestureSelectionHelperTest.java159
-rw-r--r--tests/unit/com/android/documentsui/selection/GestureSelectionHelper_RecyclerViewDelegateTest.java74
-rw-r--r--tests/unit/com/android/documentsui/selection/GridModelTest.java493
-rw-r--r--tests/unit/com/android/documentsui/selection/MouseInputHandlerTest.java285
-rw-r--r--tests/unit/com/android/documentsui/selection/MouseInputHandler_RangeTest.java187
-rw-r--r--tests/unit/com/android/documentsui/selection/SelectionTest.java200
-rw-r--r--tests/unit/com/android/documentsui/selection/TouchInputHandlerTest.java223
-rw-r--r--tests/unit/com/android/documentsui/selection/testing/SelectionHelpers.java61
-rw-r--r--tests/unit/com/android/documentsui/selection/testing/SelectionPredicates.java38
-rw-r--r--tests/unit/com/android/documentsui/selection/testing/SelectionProbe.java110
-rw-r--r--tests/unit/com/android/documentsui/selection/testing/TestAdapter.java126
-rw-r--r--tests/unit/com/android/documentsui/selection/testing/TestBandPredicate.java35
-rw-r--r--tests/unit/com/android/documentsui/selection/testing/TestData.java30
-rw-r--r--tests/unit/com/android/documentsui/selection/testing/TestEvents.java281
-rw-r--r--tests/unit/com/android/documentsui/selection/testing/TestHolder.java25
-rw-r--r--tests/unit/com/android/documentsui/selection/testing/TestMouseCallbacks.java88
-rw-r--r--tests/unit/com/android/documentsui/selection/testing/TestSelectionObserver.java99
-rw-r--r--tests/unit/com/android/documentsui/selection/testing/TestStableIdProvider.java51
112 files changed, 798 insertions, 9662 deletions
diff --git a/build_apk.mk b/build_apk.mk
index c7955bc02..e8252f64f 100644
--- a/build_apk.mk
+++ b/build_apk.mk
@@ -10,7 +10,8 @@ LOCAL_STATIC_ANDROID_LIBRARIES := \
androidx.legacy_legacy-support-v13 \
androidx.design_design \
androidx.transition_transition \
- androidx.recyclerview_recyclerview
+ androidx.recyclerview_recyclerview \
+ androidx.recyclerview_recyclerview-selection
LOCAL_USE_AAPT2 := true
diff --git a/src/com/android/documentsui/AbstractActionHandler.java b/src/com/android/documentsui/AbstractActionHandler.java
index 0bb327b0c..0eb308f8c 100644
--- a/src/com/android/documentsui/AbstractActionHandler.java
+++ b/src/com/android/documentsui/AbstractActionHandler.java
@@ -34,11 +34,15 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.provider.DocumentsContract;
-import androidx.annotation.VisibleForTesting;
import android.util.Log;
import android.util.Pair;
import android.view.DragEvent;
+import androidx.annotation.VisibleForTesting;
+import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
+import androidx.recyclerview.selection.MutableSelection;
+import androidx.recyclerview.selection.SelectionTracker;
+
import com.android.documentsui.AbstractActionHandler.CommonAddons;
import com.android.documentsui.LoadDocStackTask.LoadDocStackCallback;
import com.android.documentsui.base.BooleanConsumer;
@@ -57,10 +61,6 @@ import com.android.documentsui.queries.SearchViewManager;
import com.android.documentsui.roots.GetRootDocumentTask;
import com.android.documentsui.roots.LoadRootTask;
import com.android.documentsui.roots.ProvidersAccess;
-import com.android.documentsui.selection.ContentLock;
-import com.android.documentsui.selection.MutableSelection;
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
import com.android.documentsui.sidebar.EjectRootTask;
import com.android.documentsui.ui.Snackbars;
@@ -93,7 +93,7 @@ public abstract class AbstractActionHandler<T extends Activity & CommonAddons>
protected final ProvidersAccess mProviders;
protected final DocumentsAccess mDocs;
protected final FocusHandler mFocusHandler;
- protected final SelectionHelper mSelectionMgr;
+ protected final SelectionTracker<String> mSelectionMgr;
protected final SearchViewManager mSearchMgr;
protected final Lookup<String, Executor> mExecutors;
protected final Injector<?> mInjector;
@@ -227,7 +227,7 @@ public abstract class AbstractActionHandler<T extends Activity & CommonAddons>
}
@Override
- public boolean openItem(ItemDetails doc, @ViewType int type, @ViewType int fallback) {
+ public boolean openItem(ItemDetails<String> doc, @ViewType int type, @ViewType int fallback) {
throw new UnsupportedOperationException("Can't open document.");
}
@@ -533,8 +533,8 @@ public abstract class AbstractActionHandler<T extends Activity & CommonAddons>
loadRoot(Shared.getDefaultRootUri(mActivity));
}
- protected MutableSelection getStableSelection() {
- MutableSelection selection = new MutableSelection();
+ protected MutableSelection<String> getStableSelection() {
+ MutableSelection<String> selection = new MutableSelection<>();
mSelectionMgr.copySelection(selection);
return selection;
}
diff --git a/src/com/android/documentsui/ActionHandler.java b/src/com/android/documentsui/ActionHandler.java
index 53a746a4b..6f25f053b 100644
--- a/src/com/android/documentsui/ActionHandler.java
+++ b/src/com/android/documentsui/ActionHandler.java
@@ -24,12 +24,12 @@ import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.view.DragEvent;
+import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
+
import com.android.documentsui.base.BooleanConsumer;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.DocumentStack;
import com.android.documentsui.base.RootInfo;
-import com.android.documentsui.selection.ContentLock;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -37,6 +37,9 @@ import java.util.function.Consumer;
import javax.annotation.Nullable;
+/**
+ * Interface to handle action for document.
+ */
public interface ActionHandler {
@IntDef({
@@ -110,7 +113,7 @@ public interface ActionHandler {
* If container, then opens the container, otherwise views using the specified type of view.
* If the primary view type is unavailable, then fallback to the alternative type of view.
*/
- boolean openItem(ItemDetails doc, @ViewType int type, @ViewType int fallback);
+ boolean openItem(ItemDetails<String> doc, @ViewType int type, @ViewType int fallback);
/**
* This is called when user hovers over a doc for enough time during a drag n' drop, to open a
diff --git a/src/com/android/documentsui/ActionModeController.java b/src/com/android/documentsui/ActionModeController.java
index 4e0baef45..8b74dbf5a 100644
--- a/src/com/android/documentsui/ActionModeController.java
+++ b/src/com/android/documentsui/ActionModeController.java
@@ -31,33 +31,34 @@ import android.view.View;
import com.android.documentsui.MenuManager.SelectionDetails;
import com.android.documentsui.base.EventHandler;
import com.android.documentsui.base.Menus;
-import com.android.documentsui.selection.Selection;
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.selection.SelectionHelper.SelectionObserver;
import com.android.documentsui.ui.MessageBuilder;
+import androidx.recyclerview.selection.MutableSelection;
+import androidx.recyclerview.selection.SelectionTracker;
+import androidx.recyclerview.selection.SelectionTracker.SelectionObserver;
+
/**
* A controller that listens to selection changes and manages life cycles of action modes.
*/
-public class ActionModeController extends SelectionObserver
+public class ActionModeController extends SelectionObserver<String>
implements ActionMode.Callback, ActionModeAddons {
private static final String TAG = "ActionModeController";
private final Activity mActivity;
- private final SelectionHelper mSelectionMgr;
+ private final SelectionTracker<String> mSelectionMgr;
private final MenuManager mMenuManager;
private final MessageBuilder mMessages;
private final ContentScope mScope = new ContentScope();
- private final Selection mSelected = new Selection();
+ private final MutableSelection<String> mSelected = new MutableSelection<>();
private @Nullable ActionMode mActionMode;
private @Nullable Menu mMenu;
public ActionModeController(
Activity activity,
- SelectionHelper selectionMgr,
+ SelectionTracker<String> selectionMgr,
MenuManager menuManager,
MessageBuilder messages) {
diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java
index 8e4ea867e..7343fa888 100644
--- a/src/com/android/documentsui/BaseActivity.java
+++ b/src/com/android/documentsui/BaseActivity.java
@@ -16,8 +16,8 @@
package com.android.documentsui;
-import static com.android.documentsui.base.SharedMinimal.DEBUG;
import static com.android.documentsui.base.Shared.EXTRA_BENCHMARK;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
import static com.android.documentsui.base.State.MODE_GRID;
import android.app.Activity;
@@ -31,9 +31,6 @@ import android.os.Bundle;
import android.os.MessageQueue.IdleHandler;
import android.preference.PreferenceManager;
import android.provider.DocumentsContract;
-import androidx.annotation.CallSuper;
-import androidx.annotation.LayoutRes;
-import androidx.annotation.VisibleForTesting;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
@@ -41,6 +38,10 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.Toolbar;
+import androidx.annotation.CallSuper;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.VisibleForTesting;
+
import com.android.documentsui.AbstractActionHandler.CommonAddons;
import com.android.documentsui.Injector.Injected;
import com.android.documentsui.NavigationViewManager.Breadcrumb;
@@ -60,7 +61,6 @@ import com.android.documentsui.queries.CommandInterceptor;
import com.android.documentsui.queries.SearchViewManager;
import com.android.documentsui.queries.SearchViewManager.SearchManagerListener;
import com.android.documentsui.roots.ProvidersCache;
-import com.android.documentsui.selection.Selection;
import com.android.documentsui.sidebar.RootsFragment;
import com.android.documentsui.sorting.SortController;
import com.android.documentsui.sorting.SortModel;
@@ -82,7 +82,6 @@ public abstract class BaseActivity
@Injected
protected Injector<?> mInjector;
- protected @Nullable RetainedState mRetainedState;
protected ProvidersCache mProviders;
protected DocumentsAccess mDocs;
protected DrawerController mDrawer;
@@ -133,10 +132,6 @@ public abstract class BaseActivity
mDrawer = DrawerController.create(this, mInjector.config);
Metrics.logActivityLaunch(this, mState, intent);
- // we're really interested in retainining state in our very complex
- // DirectoryFragment. So we do a little code yoga to extend
- // support to that fragment.
- mRetainedState = (RetainedState) getLastNonConfigurationInstance();
mProviders = DocumentsApplication.getProvidersCache(this);
mDocs = DocumentsAccess.create(this);
@@ -524,29 +519,6 @@ public abstract class BaseActivity
}
@Override
- protected void onRestoreInstanceState(Bundle state) {
- super.onRestoreInstanceState(state);
- }
-
- /**
- * Delegate ths call to the current fragment so it can save selection.
- * Feel free to expand on this with other useful state.
- */
- @Override
- public RetainedState onRetainNonConfigurationInstance() {
- RetainedState retained = new RetainedState();
- DirectoryFragment fragment = DirectoryFragment.get(getFragmentManager());
- if (fragment != null) {
- fragment.retainState(retained);
- }
- return retained;
- }
-
- public @Nullable RetainedState getRetainedState() {
- return mRetainedState;
- }
-
- @Override
public boolean isSearchExpanded() {
return mSearchManager.isExpanded();
}
@@ -662,14 +634,6 @@ public abstract class BaseActivity
});
}
- public static final class RetainedState {
- public @Nullable Selection selection;
-
- public boolean hasSelection() {
- return selection != null;
- }
- }
-
@VisibleForTesting
protected interface EventListener {
/**
diff --git a/src/com/android/documentsui/ContentLock.java b/src/com/android/documentsui/ContentLock.java
new file mode 100644
index 000000000..d9f0346ca
--- /dev/null
+++ b/src/com/android/documentsui/ContentLock.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 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.documentsui;
+
+import android.annotation.Nullable;
+
+import androidx.annotation.GuardedBy;
+import androidx.recyclerview.selection.OperationMonitor;
+
+/**
+ * ContentLock provides a mechanism to block content from reloading while selection
+ * activities like gesture and band selection are active. Clients using live data
+ * (data loaded, for example by a {@link Loader}), should route calls to load
+ * content through this lock using {@link ContentLock#runWhenUnlocked(Runnable)}.
+ */
+public final class ContentLock {
+
+ private final OperationMonitor mMonitor = new OperationMonitor();
+
+ @GuardedBy("this")
+ private @Nullable Runnable mCallback;
+
+ public ContentLock() {
+ mMonitor.addListener(() -> {
+ if (!isLocked()) {
+ synchronized (this) {
+ final Runnable callback = mCallback;
+ if (callback != null) {
+ callback.run();
+ mCallback = null;
+ }
+ }
+ }
+ });
+ }
+
+ public OperationMonitor getMonitor() {
+ return mMonitor;
+ }
+
+ /**
+ * Returns true if locked.
+ */
+ private boolean isLocked() {
+ return mMonitor.isStarted();
+ }
+
+ /**
+ * Attempts to run the given Runnable if not-locked, or else the Runnable is set to be ran next
+ * (replacing any previous set Runnables).
+ */
+ public synchronized void runWhenUnlocked(Runnable runnable) {
+ if (!isLocked()) {
+ runnable.run();
+ } else {
+ mCallback = runnable;
+ }
+ }
+}
diff --git a/src/com/android/documentsui/DirectoryLoader.java b/src/com/android/documentsui/DirectoryLoader.java
index eb3ab32c3..0a749fb65 100644
--- a/src/com/android/documentsui/DirectoryLoader.java
+++ b/src/com/android/documentsui/DirectoryLoader.java
@@ -43,7 +43,6 @@ import com.android.documentsui.base.FilteringCursorWrapper;
import com.android.documentsui.base.Lookup;
import com.android.documentsui.base.RootInfo;
import com.android.documentsui.roots.RootCursorWrapper;
-import com.android.documentsui.selection.ContentLock;
import com.android.documentsui.sorting.SortModel;
import android.os.FileUtils;
diff --git a/src/com/android/documentsui/DocsSelectionHelper.java b/src/com/android/documentsui/DocsSelectionHelper.java
index c788119a7..b7a720c8b 100644
--- a/src/com/android/documentsui/DocsSelectionHelper.java
+++ b/src/com/android/documentsui/DocsSelectionHelper.java
@@ -16,50 +16,42 @@
package com.android.documentsui;
-import androidx.annotation.VisibleForTesting;
-import androidx.recyclerview.widget.RecyclerView;
+import android.os.Bundle;
+import android.view.MotionEvent;
-import com.android.documentsui.selection.DefaultSelectionHelper;
-import com.android.documentsui.selection.DefaultSelectionHelper.SelectionMode;
-import com.android.documentsui.selection.MutableSelection;
-import com.android.documentsui.selection.Selection;
-import com.android.documentsui.selection.SelectionHelper;
+import androidx.annotation.VisibleForTesting;
+import androidx.recyclerview.selection.ItemDetailsLookup;
+import androidx.recyclerview.selection.ItemKeyProvider;
+import androidx.recyclerview.selection.MutableSelection;
+import androidx.recyclerview.selection.Selection;
+import androidx.recyclerview.selection.SelectionTracker;
+import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
import java.util.Set;
-import javax.annotation.Nullable;
-
/**
* DocumentsUI SelectManager implementation that creates delegate instances
* each time reset is called.
*/
-public final class DocsSelectionHelper extends SelectionHelper {
+public final class DocsSelectionHelper extends SelectionTracker<String> {
private final DelegateFactory mFactory;
- private final @SelectionMode int mSelectionMode;
// initialize to a dummy object incase we get some input
// event drive calls before we're properly initialized.
// See: b/69306667.
- private SelectionHelper mDelegate = new DummySelectionHelper();
+ private SelectionTracker<String> mDelegate = new DummySelectionTracker<>();
@VisibleForTesting
- DocsSelectionHelper(DelegateFactory factory, @SelectionMode int mode) {
+ DocsSelectionHelper(DelegateFactory factory) {
mFactory = factory;
- mSelectionMode = mode;
}
- public SelectionHelper reset(
- RecyclerView.Adapter<?> adapter,
- StableIdProvider stableIds,
- SelectionPredicate canSetState) {
-
+ public void reset(SelectionTracker<String> selectionTracker) {
if (mDelegate != null) {
mDelegate.clearSelection();
}
-
- mDelegate = mFactory.create(mSelectionMode, adapter, stableIds, canSetState);
- return this;
+ mDelegate = mFactory.create(selectionTracker);
}
@Override
@@ -73,12 +65,12 @@ public final class DocsSelectionHelper extends SelectionHelper {
}
@Override
- public Selection getSelection() {
+ public Selection<String> getSelection() {
return mDelegate.getSelection();
}
@Override
- public void copySelection(Selection dest) {
+ public void copySelection(MutableSelection<String> dest) {
mDelegate.copySelection(dest);
}
@@ -94,18 +86,13 @@ public final class DocsSelectionHelper extends SelectionHelper {
}
@Override
- public void restoreSelection(Selection other) {
- mDelegate.restoreSelection(other);
- }
-
- @Override
public boolean setItemsSelected(Iterable<String> ids, boolean selected) {
return mDelegate.setItemsSelected(ids, selected);
}
@Override
- public void clearSelection() {
- mDelegate.clearSelection();
+ public boolean clearSelection() {
+ return mDelegate.clearSelection();
}
@Override
@@ -129,50 +116,59 @@ public final class DocsSelectionHelper extends SelectionHelper {
}
@Override
- public void extendProvisionalRange(int pos) {
- mDelegate.extendProvisionalRange(pos);
+ public void endRange() {
+ mDelegate.endRange();
}
@Override
- public void clearProvisionalSelection() {
- mDelegate.clearProvisionalSelection();
+ public boolean isRangeActive() {
+ return mDelegate.isRangeActive();
}
@Override
- public void setProvisionalSelection(Set<String> newSelection) {
- mDelegate.setProvisionalSelection(newSelection);
+ public void anchorRange(int position) {
+ mDelegate.anchorRange(position);
}
@Override
- public void mergeProvisionalSelection() {
- mDelegate.mergeProvisionalSelection();
+ public void onSaveInstanceState(Bundle state) {
+ mDelegate.onSaveInstanceState(state);
}
@Override
- public void endRange() {
- mDelegate.endRange();
+ public void onRestoreInstanceState(Bundle state) {
+ mDelegate.onRestoreInstanceState(state);
}
+ // Below overridden protected methods are not used for delegation. These empty implementations
+ // are just required by abstract declaration of parent class.
@Override
- public boolean isRangeActive() {
- return mDelegate.isRangeActive();
+ protected void restoreSelection(Selection<String> selection) {
}
@Override
- public void anchorRange(int position) {
- mDelegate.anchorRange(position);
+ protected AdapterDataObserver getAdapterDataObserver() {
+ return null;
+ }
+
+ @Override
+ protected void extendProvisionalRange(int position) {
}
- public static DocsSelectionHelper createMultiSelect() {
- return new DocsSelectionHelper(
- DelegateFactory.INSTANCE,
- DefaultSelectionHelper.MODE_MULTIPLE);
+ @Override
+ protected void setProvisionalSelection(Set<String> newSelection) {
}
- public static DocsSelectionHelper createSingleSelect() {
- return new DocsSelectionHelper(
- DelegateFactory.INSTANCE,
- DefaultSelectionHelper.MODE_SINGLE);
+ @Override
+ protected void clearProvisionalSelection() {
+ }
+
+ @Override
+ protected void mergeProvisionalSelection() {
+ }
+
+ public static DocsSelectionHelper create() {
+ return new DocsSelectionHelper(DelegateFactory.INSTANCE);
}
/**
@@ -183,107 +179,30 @@ public final class DocsSelectionHelper extends SelectionHelper {
static class DelegateFactory {
static final DelegateFactory INSTANCE = new DelegateFactory();
- SelectionHelper create(
- @SelectionMode int mode,
- RecyclerView.Adapter<?> adapter,
- StableIdProvider stableIds,
- SelectionPredicate canSetState) {
-
- return new DefaultSelectionHelper(mode, adapter, stableIds, canSetState);
+ SelectionTracker<String> create(SelectionTracker<String> selectionTracker) {
+ return selectionTracker;
}
}
/**
- * A dummy SelectHelper used by DocsSelectionHelper before a real
- * SelectionHelper has been initialized by DirectoryFragment.
+ * Facilitates the use of ItemDetailsLookup.
*/
- private static final class DummySelectionHelper extends SelectionHelper {
-
- @Override
- public void addObserver(SelectionObserver listener) {
- }
-
- @Override
- public boolean hasSelection() {
- return false;
- }
-
- @Override
- public Selection getSelection() {
- return new MutableSelection();
- }
-
- @Override
- public void copySelection(Selection dest) {
- }
+ public static abstract class DocDetailsLookup extends ItemDetailsLookup<String> {
+ // Override as public for usages in other packages.
@Override
- public boolean isSelected(String id) {
- return false;
- }
-
- @VisibleForTesting
- public void replaceSelection(Iterable<String> ids) {
- }
-
- @Override
- public void restoreSelection(Selection other) {
- }
-
- @Override
- public boolean setItemsSelected(Iterable<String> ids, boolean selected) {
- return false;
- }
-
- @Override
- public void clearSelection() {
- }
-
- @Override
- public boolean select(String modelId) {
- return false;
- }
-
- @Override
- public boolean deselect(String modelId) {
- return false;
- }
-
- @Override
- public void startRange(int pos) {
- }
-
- @Override
- public void extendRange(int pos) {
- }
-
- @Override
- public void extendProvisionalRange(int pos) {
- }
-
- @Override
- public void clearProvisionalSelection() {
- }
-
- @Override
- public void setProvisionalSelection(Set<String> newSelection) {
- }
-
- @Override
- public void mergeProvisionalSelection() {
- }
-
- @Override
- public void endRange() {
+ public boolean overItemWithSelectionKey(MotionEvent e) {
+ return super.overItemWithSelectionKey(e);
}
+ }
- @Override
- public boolean isRangeActive() {
- return false;
- }
+ /**
+ * Facilitates the use of stable ids.
+ */
+ public static abstract class StableIdProvider extends ItemKeyProvider<String> {
- @Override
- public void anchorRange(int position) {
+ protected StableIdProvider() {
+ super(ItemKeyProvider.SCOPE_MAPPED);
}
}
}
diff --git a/src/com/android/documentsui/DragHoverListener.java b/src/com/android/documentsui/DragHoverListener.java
index d26f7caa9..9994de5f3 100644
--- a/src/com/android/documentsui/DragHoverListener.java
+++ b/src/com/android/documentsui/DragHoverListener.java
@@ -24,9 +24,8 @@ import android.view.View.OnDragListener;
import android.widget.AbsListView;
import com.android.documentsui.ItemDragListener.DragHost;
-import com.android.documentsui.selection.ViewAutoScroller;
-import com.android.documentsui.selection.ViewAutoScroller.ScrollHost;
-import com.android.documentsui.selection.ViewAutoScroller.ScrollerCallbacks;
+import com.android.documentsui.ViewAutoScroller.ScrollHost;
+import com.android.documentsui.ViewAutoScroller.ScrollerCallbacks;
import java.util.function.BooleanSupplier;
import java.util.function.IntConsumer;
diff --git a/src/com/android/documentsui/DummySelectionTracker.java b/src/com/android/documentsui/DummySelectionTracker.java
new file mode 100644
index 000000000..49b9ad918
--- /dev/null
+++ b/src/com/android/documentsui/DummySelectionTracker.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 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.documentsui;
+
+import android.os.Bundle;
+
+import androidx.recyclerview.selection.MutableSelection;
+import androidx.recyclerview.selection.Selection;
+import androidx.recyclerview.selection.SelectionTracker;
+import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
+
+import java.util.Set;
+
+/**
+ * A dummy SelectionTracker used by DocsSelectionHelper before a real SelectionTracker has been
+ * initialized by DirectoryFragment.
+ */
+public class DummySelectionTracker<K> extends SelectionTracker<K> {
+
+ @Override
+ public void addObserver(SelectionObserver observer) {
+ }
+
+ @Override
+ public boolean hasSelection() {
+ return false;
+ }
+
+ @Override
+ public Selection<K> getSelection() {
+ return new MutableSelection<K>();
+ }
+
+ @Override
+ public void copySelection(MutableSelection<K> dest) {
+ }
+
+ @Override
+ public boolean isSelected(K key) {
+ return false;
+ }
+
+ @Override
+ public void restoreSelection(Selection<K> selection) {
+ }
+
+ @Override
+ public boolean clearSelection() {
+ return false;
+ }
+
+ @Override
+ public boolean setItemsSelected(Iterable<K> keys, boolean selected) {
+ return false;
+ }
+
+ @Override
+ public boolean select(K key) {
+ return false;
+ }
+
+ @Override
+ public boolean deselect(K key) {
+ return false;
+ }
+
+ @Override
+ protected AdapterDataObserver getAdapterDataObserver() {
+ return null;
+ }
+
+ @Override
+ public void startRange(int position) {
+ }
+
+ @Override
+ public void extendRange(int position) {
+ }
+
+ @Override
+ public void endRange() {
+ }
+
+ @Override
+ public boolean isRangeActive() {
+ return false;
+ }
+
+ @Override
+ public void anchorRange(int position) {
+ }
+
+ @Override
+ public void extendProvisionalRange(int position) {
+ }
+
+ @Override
+ public void setProvisionalSelection(Set<K> newSelection) {
+ }
+
+ @Override
+ public void clearProvisionalSelection() {
+ }
+
+ @Override
+ public void mergeProvisionalSelection() {
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle state) {
+ }
+
+ @Override
+ public void onRestoreInstanceState(Bundle state) {
+ }
+
+}
diff --git a/src/com/android/documentsui/FocusManager.java b/src/com/android/documentsui/FocusManager.java
index 5fe732684..7a228ffe3 100644
--- a/src/com/android/documentsui/FocusManager.java
+++ b/src/com/android/documentsui/FocusManager.java
@@ -27,8 +27,6 @@ import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.provider.DocumentsContract.Document;
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
import android.text.Editable;
import android.text.Spannable;
import android.text.method.KeyListener;
@@ -40,6 +38,13 @@ import android.view.KeyEvent;
import android.view.View;
import android.widget.TextView;
+import androidx.recyclerview.selection.FocusDelegate;
+import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
+import androidx.recyclerview.selection.SelectionTracker;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.documentsui.Model.Update;
import com.android.documentsui.base.EventListener;
import com.android.documentsui.base.Events;
import com.android.documentsui.base.Features;
@@ -47,21 +52,22 @@ import com.android.documentsui.base.Procedure;
import com.android.documentsui.dirlist.DocumentHolder;
import com.android.documentsui.dirlist.DocumentsAdapter;
import com.android.documentsui.dirlist.FocusHandler;
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.Model.Update;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
-public final class FocusManager implements FocusHandler {
+/**
+ * The implementation to handle focus and keyboard driven navigation.
+ */
+public final class FocusManager extends FocusDelegate<String> implements FocusHandler {
private static final String TAG = "FocusManager";
private final ContentScope mScope = new ContentScope();
private final Features mFeatures;
- private final SelectionHelper mSelectionMgr;
+ private final SelectionTracker<String> mSelectionMgr;
private final DrawerController mDrawer;
private final Procedure mRootsFocuser;
private final TitleSearchHelper mSearchHelper;
@@ -70,7 +76,7 @@ public final class FocusManager implements FocusHandler {
public FocusManager(
Features features,
- SelectionHelper selectionMgr,
+ SelectionTracker<String> selectionMgr,
DrawerController drawer,
Procedure rootsFocuser,
@ColorRes int color) {
@@ -205,7 +211,12 @@ public final class FocusManager implements FocusHandler {
}
@Override
- public int getFocusPosition() {
+ public void focusItem(ItemDetails<String> item) {
+ focusDocument(item.getSelectionKey());
+ }
+
+ @Override
+ public int getFocusedPosition() {
return mScope.lastFocusPosition;
}
diff --git a/src/com/android/documentsui/Injector.java b/src/com/android/documentsui/Injector.java
index ea4dd90a7..0fc3670f0 100644
--- a/src/com/android/documentsui/Injector.java
+++ b/src/com/android/documentsui/Injector.java
@@ -18,9 +18,11 @@ package com.android.documentsui;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.SOURCE;
+import android.view.MenuItem;
+
import androidx.annotation.Nullable;
+import androidx.recyclerview.selection.SelectionTracker;
import androidx.recyclerview.widget.RecyclerView;
-import android.view.MenuItem;
import com.android.documentsui.MenuManager.SelectionDetails;
import com.android.documentsui.base.DebugHelper;
@@ -28,12 +30,8 @@ import com.android.documentsui.base.EventHandler;
import com.android.documentsui.base.Features;
import com.android.documentsui.base.Lookup;
import com.android.documentsui.base.RootInfo;
-import com.android.documentsui.dirlist.DocsStableIdProvider;
-import com.android.documentsui.dirlist.DocumentsAdapter;
import com.android.documentsui.prefs.ScopedPreferences;
import com.android.documentsui.queries.SearchViewManager;
-import com.android.documentsui.selection.ContentLock;
-import com.android.documentsui.selection.SelectionHelper;
import com.android.documentsui.ui.DialogController;
import com.android.documentsui.ui.MessageBuilder;
import androidx.annotation.VisibleForTesting;
@@ -120,9 +118,8 @@ public class Injector<T extends ActionHandler> {
return focusManager.reset(view, model);
}
- public SelectionHelper getSelectionManager(
- DocumentsAdapter adapter, SelectionHelper.SelectionPredicate canSetState) {
- return selectionMgr.reset(adapter, new DocsStableIdProvider(adapter), canSetState);
+ public void updateSharedSelectionTracker(SelectionTracker<String> selectionTracker) {
+ selectionMgr.reset(selectionTracker);
}
public final ActionModeController getActionModeController(
diff --git a/src/com/android/documentsui/Model.java b/src/com/android/documentsui/Model.java
index f02c324a1..7141ab90e 100644
--- a/src/com/android/documentsui/Model.java
+++ b/src/com/android/documentsui/Model.java
@@ -28,16 +28,17 @@ import android.net.Uri;
import android.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
+import android.util.Log;
+
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import android.util.Log;
+import androidx.recyclerview.selection.Selection;
import com.android.documentsui.base.DocumentFilters;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.EventListener;
import com.android.documentsui.base.Features;
import com.android.documentsui.roots.RootCursorWrapper;
-import com.android.documentsui.selection.Selection;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -73,7 +74,7 @@ public class Model {
private @Nullable Cursor mCursor;
private int mCursorCount;
private String mIds[] = new String[0];
- private Set<Selection> mDocumentsToBeDeleted = new HashSet<>();
+ private Set<Selection<String>> mDocumentsToBeDeleted = new HashSet<>();
public Model(Features features) {
mFeatures = features;
@@ -142,7 +143,7 @@ public class Model {
notifyUpdateListeners();
}
- public void markDocumentsToBeDeleted(Selection selection) {
+ public void markDocumentsToBeDeleted(Selection<String> selection) {
if (mDocumentsToBeDeleted.contains(selection)) {
return;
}
@@ -151,7 +152,7 @@ public class Model {
notifyUpdateListeners();
}
- public void restoreDocumentsToBeDeleted(Selection selection) {
+ public void restoreDocumentsToBeDeleted(Selection<String> selection) {
if (!mDocumentsToBeDeleted.contains(selection)) {
return;
}
@@ -161,7 +162,7 @@ public class Model {
}
private boolean isDocumentToBeDeleted(String id) {
- for (Selection s : mDocumentsToBeDeleted) {
+ for (Selection<String> s : mDocumentsToBeDeleted) {
if (s.contains(id)) {
return true;
}
@@ -170,8 +171,8 @@ public class Model {
}
private void updateDocumentsToBeDeleted() {
- for (Iterator<Selection> i = mDocumentsToBeDeleted.iterator(); i.hasNext();) {
- Selection selection = i.next();
+ for (Iterator<Selection<String>> i = mDocumentsToBeDeleted.iterator(); i.hasNext();) {
+ Selection<String> selection = i.next();
for (String id : selection) {
if (!mPositions.containsKey(id)) {
i.remove();
@@ -183,7 +184,7 @@ public class Model {
private int getDocumentsToBeDeletedCount() {
int count = 0;
- for (Selection s : mDocumentsToBeDeleted) {
+ for (Selection<String> s : mDocumentsToBeDeleted) {
count += s.size();
}
return count;
@@ -258,7 +259,7 @@ public class Model {
return mIsLoading;
}
- public List<DocumentInfo> getDocuments(Selection selection) {
+ public List<DocumentInfo> getDocuments(Selection<String> selection) {
return loadDocuments(selection, DocumentFilters.ANY);
}
@@ -269,7 +270,7 @@ public class Model {
: DocumentInfo.fromDirectoryCursor(cursor);
}
- public List<DocumentInfo> loadDocuments(Selection selection, Predicate<Cursor> filter) {
+ public List<DocumentInfo> loadDocuments(Selection<String> selection, Predicate<Cursor> filter) {
final int size = (selection != null) ? selection.size() : 0;
final List<DocumentInfo> docs = new ArrayList<>(size);
@@ -283,7 +284,7 @@ public class Model {
return docs;
}
- public boolean hasDocuments(Selection selection, Predicate<Cursor> filter) {
+ public boolean hasDocuments(Selection<String> selection, Predicate<Cursor> filter) {
for (String modelId: selection) {
if (loadDocument(modelId, filter) != null) {
return true;
diff --git a/src/com/android/documentsui/SharedInputHandler.java b/src/com/android/documentsui/SharedInputHandler.java
index 8d39204cd..b9a5b92c3 100644
--- a/src/com/android/documentsui/SharedInputHandler.java
+++ b/src/com/android/documentsui/SharedInputHandler.java
@@ -20,12 +20,16 @@ import static com.android.documentsui.base.SharedMinimal.DEBUG;
import android.util.Log;
import android.view.KeyEvent;
+import androidx.recyclerview.selection.SelectionTracker;
+
import com.android.documentsui.base.Events;
import com.android.documentsui.base.Features;
import com.android.documentsui.base.Procedure;
import com.android.documentsui.dirlist.FocusHandler;
-import com.android.documentsui.selection.SelectionHelper;
+/**
+ * Handle common input events.
+ */
public class SharedInputHandler {
private static final String TAG = "SharedInputHandler";
@@ -34,12 +38,12 @@ public class SharedInputHandler {
private final Procedure mSearchCanceler;
private final Procedure mDirPopper;
private final Features mFeatures;
- private final SelectionHelper mSelectionMgr;
+ private final SelectionTracker<String> mSelectionMgr;
private final DrawerController mDrawer;
public SharedInputHandler(
FocusHandler focusHandler,
- SelectionHelper selectionMgr,
+ SelectionTracker<String> selectionMgr,
Procedure searchCanceler,
Procedure dirPopper,
Features features,
diff --git a/src/com/android/documentsui/selection/ViewAutoScroller.java b/src/com/android/documentsui/ViewAutoScroller.java
index b77176c01..f7b062e18 100644
--- a/src/com/android/documentsui/selection/ViewAutoScroller.java
+++ b/src/com/android/documentsui/ViewAutoScroller.java
@@ -14,16 +14,15 @@
* limitations under the License.
*/
-package com.android.documentsui.selection;
+package com.android.documentsui;
import android.graphics.Point;
/**
* Provides auto-scrolling upon request when user's interaction with the application
- * introduces a natural intent to scroll. Used by BandController, GestureSelector,
- * and DragHoverListener to allow auto scrolling when user either does band selection,
- * attempting to drag and drop files to somewhere off the current screen, or trying to motion select
- * past top/bottom of the screen.
+ * introduces a natural intent to scroll. Used by DragHoverListener to allow auto scrolling
+ * when user either does band selection, attempting to drag and drop files to somewhere off
+ * the current screen, or trying to motion select past top/bottom of the screen.
*/
public final class ViewAutoScroller implements Runnable {
diff --git a/src/com/android/documentsui/base/Events.java b/src/com/android/documentsui/base/Events.java
index c38f1a4c6..1e6be6c3c 100644
--- a/src/com/android/documentsui/base/Events.java
+++ b/src/com/android/documentsui/base/Events.java
@@ -16,7 +16,6 @@
package com.android.documentsui.base;
-import android.graphics.Point;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -29,10 +28,6 @@ public final class Events {
return e.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE;
}
- public static boolean isActionMove(MotionEvent e) {
- return e.getActionMasked() == MotionEvent.ACTION_MOVE;
- }
-
public static boolean isActionDown(MotionEvent e) {
return e.getActionMasked() == MotionEvent.ACTION_DOWN;
}
@@ -49,22 +44,6 @@ public final class Events {
return e.getActionMasked() == MotionEvent.ACTION_POINTER_UP;
}
- public static boolean isActionCancel(MotionEvent e) {
- return e.getActionMasked() == MotionEvent.ACTION_CANCEL;
- }
-
- public static boolean isPrimaryButtonPressed(MotionEvent e) {
- return e.isButtonPressed(MotionEvent.BUTTON_PRIMARY);
- }
-
- public static boolean isSecondaryButtonPressed(MotionEvent e) {
- return e.isButtonPressed(MotionEvent.BUTTON_SECONDARY);
- }
-
- public static boolean isTertiaryButtonPressed(MotionEvent e) {
- return e.isButtonPressed(MotionEvent.BUTTON_TERTIARY);
- }
-
public static boolean isCtrlKeyPressed(MotionEvent e) {
return hasBit(e.getMetaState(), KeyEvent.META_CTRL_ON);
}
@@ -77,20 +56,10 @@ public final class Events {
return hasBit(e.getMetaState(), KeyEvent.META_SHIFT_ON);
}
- public static boolean isTouchpadScroll(MotionEvent e) {
- // Touchpad inputs are treated as mouse inputs, and when scrolling, there are no buttons
- // returned.
- return isMouseEvent(e) && isActionMove(e) && e.getButtonState() == 0;
- }
-
private static boolean hasBit(int metaState, int bit) {
return (metaState & bit) != 0;
}
- public static Point getOrigin(MotionEvent e) {
- return new Point((int) e.getX(), (int) e.getY());
- }
-
/**
* @return true if keyCode is a known navigation code (e.g. up, down, home).
*/
@@ -109,15 +78,4 @@ public final class Events {
return false;
}
}
-
- /**
- * Returns true if the event is a mouse drag event.
- * @param e
- * @return
- */
- public static boolean isMouseDragEvent(MotionEvent e) {
- return isMouseEvent(e)
- && isActionMove(e)
- && isPrimaryButtonPressed(e);
- }
}
diff --git a/src/com/android/documentsui/clipping/DocumentClipper.java b/src/com/android/documentsui/clipping/DocumentClipper.java
index dbb84fca3..fe85e27e3 100644
--- a/src/com/android/documentsui/clipping/DocumentClipper.java
+++ b/src/com/android/documentsui/clipping/DocumentClipper.java
@@ -20,12 +20,11 @@ import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.net.Uri;
-import androidx.annotation.Nullable;
+
+import androidx.recyclerview.selection.Selection;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.DocumentStack;
-import com.android.documentsui.base.RootInfo;
-import com.android.documentsui.selection.Selection;
import com.android.documentsui.services.FileOperationService.OpType;
import com.android.documentsui.services.FileOperations;
@@ -47,7 +46,7 @@ public interface DocumentClipper {
* Returns {@link ClipData} representing the selection, or null if selection is empty,
* or cannot be converted.
*/
- ClipData getClipDataForDocuments(Function<String, Uri> uriBuilder, Selection selection,
+ ClipData getClipDataForDocuments(Function<String, Uri> uriBuilder, Selection<String> selection,
@OpType int opType);
/**
@@ -63,13 +62,13 @@ public interface DocumentClipper {
/**
* Puts {@code ClipData} in a primary clipboard, describing a copy operation
*/
- void clipDocumentsForCopy(Function<String, Uri> uriBuilder, Selection selection);
+ void clipDocumentsForCopy(Function<String, Uri> uriBuilder, Selection<String> selection);
/**
* Puts {@Code ClipData} in a primary clipboard, describing a cut operation
*/
void clipDocumentsForCut(
- Function<String, Uri> uriBuilder, Selection selection, DocumentInfo parent);
+ Function<String, Uri> uriBuilder, Selection<String> selection, DocumentInfo parent);
/**
* Copies documents from clipboard. It's the same as {@link #copyFromClipData} with clipData
diff --git a/src/com/android/documentsui/clipping/RuntimeDocumentClipper.java b/src/com/android/documentsui/clipping/RuntimeDocumentClipper.java
index 64311f349..1c5804c57 100644
--- a/src/com/android/documentsui/clipping/RuntimeDocumentClipper.java
+++ b/src/com/android/documentsui/clipping/RuntimeDocumentClipper.java
@@ -24,15 +24,15 @@ import android.content.Context;
import android.net.Uri;
import android.os.PersistableBundle;
import android.provider.DocumentsContract;
-import androidx.annotation.Nullable;
import android.util.Log;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.selection.Selection;
+
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.DocumentStack;
import com.android.documentsui.base.Features;
-import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.Shared;
-import com.android.documentsui.selection.Selection;
import com.android.documentsui.services.FileOperation;
import com.android.documentsui.services.FileOperationService;
import com.android.documentsui.services.FileOperationService.OpType;
@@ -90,7 +90,7 @@ final class RuntimeDocumentClipper implements DocumentClipper {
@Override
public ClipData getClipDataForDocuments(
- Function<String, Uri> uriBuilder, Selection selection, @OpType int opType) {
+ Function<String, Uri> uriBuilder, Selection<String> selection, @OpType int opType) {
assert(selection != null);
@@ -190,7 +190,8 @@ final class RuntimeDocumentClipper implements DocumentClipper {
}
@Override
- public void clipDocumentsForCopy(Function<String, Uri> uriBuilder, Selection selection) {
+ public void clipDocumentsForCopy(
+ Function<String, Uri> uriBuilder, Selection<String> selection) {
ClipData data =
getClipDataForDocuments(uriBuilder, selection, FileOperationService.OPERATION_COPY);
assert(data != null);
@@ -200,7 +201,7 @@ final class RuntimeDocumentClipper implements DocumentClipper {
@Override
public void clipDocumentsForCut(
- Function<String, Uri> uriBuilder, Selection selection, DocumentInfo parent) {
+ Function<String, Uri> uriBuilder, Selection<String> selection, DocumentInfo parent) {
assert(!selection.isEmpty());
assert(parent.derivedUri != null);
diff --git a/src/com/android/documentsui/clipping/UrisSupplier.java b/src/com/android/documentsui/clipping/UrisSupplier.java
index fd4d0e653..6679347d6 100644
--- a/src/com/android/documentsui/clipping/UrisSupplier.java
+++ b/src/com/android/documentsui/clipping/UrisSupplier.java
@@ -25,12 +25,13 @@ import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
-import androidx.annotation.VisibleForTesting;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+import androidx.recyclerview.selection.Selection;
+
import com.android.documentsui.DocumentsApplication;
import com.android.documentsui.base.Shared;
-import com.android.documentsui.selection.Selection;
import com.android.documentsui.services.FileOperation;
import java.io.File;
@@ -82,7 +83,7 @@ public abstract class UrisSupplier implements Parcelable {
}
public static UrisSupplier create(
- Selection selection, Function<String, Uri> uriBuilder, ClipStore storage)
+ Selection<String> selection, Function<String, Uri> uriBuilder, ClipStore storage)
throws IOException {
List<Uri> uris = new ArrayList<>(selection.size());
diff --git a/src/com/android/documentsui/dirlist/DirectoryFragment.java b/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 2cd150c37..e3b429b09 100644
--- a/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -34,23 +34,14 @@ import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
-import androidx.annotation.Nullable;
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.RecyclerListener;
-import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import android.util.Log;
import android.util.SparseArray;
import android.view.ContextMenu;
-import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -59,10 +50,25 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
+import androidx.recyclerview.selection.MutableSelection;
+import androidx.recyclerview.selection.Selection;
+import androidx.recyclerview.selection.SelectionTracker;
+import androidx.recyclerview.selection.StorageStrategy;
+import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.RecyclerListener;
+import androidx.recyclerview.widget.RecyclerView.ViewHolder;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
import com.android.documentsui.ActionHandler;
import com.android.documentsui.ActionModeController;
import com.android.documentsui.BaseActivity;
-import com.android.documentsui.BaseActivity.RetainedState;
+import com.android.documentsui.ContentLock;
+import com.android.documentsui.DocsSelectionHelper.DocDetailsLookup;
import com.android.documentsui.DocumentsApplication;
import com.android.documentsui.DragHoverListener;
import com.android.documentsui.FocusManager;
@@ -87,20 +93,6 @@ import com.android.documentsui.clipping.DocumentClipper;
import com.android.documentsui.clipping.UrisSupplier;
import com.android.documentsui.dirlist.AnimationView.AnimationType;
import com.android.documentsui.picker.PickActivity;
-import com.android.documentsui.selection.BandSelectionHelper;
-import com.android.documentsui.selection.ContentLock;
-import com.android.documentsui.selection.DefaultBandHost;
-import com.android.documentsui.selection.DefaultBandPredicate;
-import com.android.documentsui.selection.GestureRouter;
-import com.android.documentsui.selection.GestureSelectionHelper;
-import com.android.documentsui.selection.ItemDetailsLookup;
-import com.android.documentsui.selection.MotionInputHandler;
-import com.android.documentsui.selection.MouseInputHandler;
-import com.android.documentsui.selection.Selection;
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
-import com.android.documentsui.selection.TouchEventRouter;
-import com.android.documentsui.selection.TouchInputHandler;
import com.android.documentsui.services.FileOperation;
import com.android.documentsui.services.FileOperationService;
import com.android.documentsui.services.FileOperationService.OpType;
@@ -129,7 +121,6 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
public static final int REQUEST_COPY_DESTINATION = 1;
static final String TAG = "DirectoryFragment";
- private static final int LOADER_ID = 42;
private static final int CACHE_EVICT_LIMIT = 100;
private static final int REFRESH_SPINNER_TIMEOUT = 500;
@@ -147,7 +138,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
@Injected
@ContentScoped
- private SelectionHelper mSelectionMgr;
+ private SelectionTracker<String> mSelectionMgr;
@Injected
@ContentScoped
@@ -161,10 +152,9 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
@ContentScoped
private ActionModeController mActionModeController;
- private ItemDetailsLookup mDetailsLookup;
+ private DocDetailsLookup mDetailsLookup;
private SelectionMetadata mSelectionMetadata;
private KeyInputHandler mKeyListener;
- private @Nullable BandSelectionHelper mBandSelector;
private @Nullable DragHoverListener mDragHoverListener;
private IconHelper mIconHelper;
private SwipeRefreshLayout mRefreshLayout;
@@ -181,14 +171,12 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
private DirectoryState mLocalState;
- // Blocks loading/reloading of content while user is actively making selection.
- private ContentLock mContentLock = new ContentLock();
-
- private Runnable mBandSelectStartedCallback;
-
// Note, we use !null to indicate that selection was restored (from rotation).
// So don't fiddle with this field unless you've got the bigger picture in mind.
- private @Nullable Selection mRestoredSelection = null;
+ private @Nullable Bundle mRestoredState;
+
+ // Blocks loading/reloading of content while user is actively making selection.
+ private ContentLock mContentLock = new ContentLock();
private SortModel.UpdateListener mSortListener = (model, updateType) -> {
// Only when sort order has changed do we need to trigger another loading.
@@ -223,6 +211,9 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
mRecView.setItemAnimator(new DirectoryItemAnimator(mActivity));
mInjector = mActivity.getInjector();
+ // Initially, this selection tracker (delegator) uses a dummy implementation, so it must be
+ // updated (reset) when necessary things are ready.
+ mSelectionMgr = mInjector.selectionMgr;
mModel = mInjector.getModel();
mModel.reset();
@@ -234,7 +225,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
new DragHost<>(
mActivity,
DocumentsApplication.getDragAndDropManager(mActivity),
- mInjector.selectionMgr,
+ mSelectionMgr,
mInjector.actions,
mActivity.getDisplayState(),
mInjector.dialogs,
@@ -267,10 +258,6 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
mModel.removeUpdateListener(mModelUpdateListener);
mModel.removeUpdateListener(mAdapter.getModelUpdateListener());
- if (mBandSelector != null) {
- mBandSelector.removeOnBandStartedListener(mBandSelectStartedCallback);
- }
-
super.onDestroyView();
}
@@ -283,17 +270,12 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
// Read arguments when object created for the first time.
// Restore state if fragment recreated.
Bundle args = savedInstanceState == null ? getArguments() : savedInstanceState;
+ mRestoredState = args;
mLocalState = new DirectoryState();
mLocalState.restore(args);
-
- // Restore any selection we may have squirreled away in retained state.
- @Nullable RetainedState retained = mActivity.getRetainedState();
- if (retained != null && retained.hasSelection()) {
- // We claim the selection for ourselves and null it out once used
- // so we don't have a rando selection hanging around in RetainedState.
- mRestoredSelection = retained.selection;
- retained.selection = null;
+ if (mLocalState.mSelectionId == null) {
+ mLocalState.mSelectionId = Integer.toHexString(System.identityHashCode(mRecView));
}
mIconHelper = new IconHelper(mActivity, MODE_GRID);
@@ -322,10 +304,9 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
mModel.addUpdateListener(mAdapter.getModelUpdateListener());
mModel.addUpdateListener(mModelUpdateListener);
- SelectionPredicate selectionPredicate =
+ SelectionPredicate<String> selectionPredicate =
new DocsSelectionPredicate(mInjector.config, mState, mModel, mRecView);
- mSelectionMgr = mInjector.getSelectionManager(mAdapter, selectionPredicate);
mFocusManager = mInjector.getFocusManager(mRecView, mModel);
mActions = mInjector.getActionHandler(mContentLock);
@@ -333,26 +314,8 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
new AccessibilityEventRouter(mRecView,
(View child) -> onAccessibilityClick(child)));
mSelectionMetadata = new SelectionMetadata(mModel::getItem);
- mSelectionMgr.addObserver(mSelectionMetadata);
mDetailsLookup = new DocsItemDetailsLookup(mRecView);
- GestureSelectionHelper gestureHelper = GestureSelectionHelper.create(
- mSelectionMgr, mRecView, mContentLock, mDetailsLookup);
-
- if (mState.allowMultiple) {
- mBandSelector = new BandSelectionHelper(
- new DefaultBandHost(mRecView, R.drawable.band_select_overlay),
- mAdapter,
- new DocsStableIdProvider(mAdapter),
- mSelectionMgr,
- selectionPredicate,
- new DefaultBandPredicate(mDetailsLookup),
- mContentLock);
-
- mBandSelectStartedCallback = mFocusManager::clearFocus;
- mBandSelector.addOnBandStartedListener(mBandSelectStartedCallback);
- }
-
DragStartListener dragStartListener = mInjector.config.dragAndDropEnabled()
? DragStartListener.create(
mIconHelper,
@@ -360,12 +323,33 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
mSelectionMgr,
mSelectionMetadata,
mState,
- mDetailsLookup,
this::getModelId,
mRecView::findChildViewUnder,
DocumentsApplication.getDragAndDropManager(mActivity))
: DragStartListener.DUMMY;
+ {
+ // Limiting the scope of the localTracker so nobody uses it.
+ // This block initializes/updates the global SelectionTracker held in mSelectionMgr.
+ SelectionTracker<String> localTracker = new SelectionTracker.Builder<>(
+ mLocalState.mSelectionId,
+ mRecView,
+ new DocsStableIdProvider(mAdapter),
+ mDetailsLookup,
+ StorageStrategy.createStringStorage())
+ .withBandOverlay(R.drawable.band_select_overlay)
+ .withFocusDelegate(mFocusManager)
+ .withOnDragInitiatedListener(dragStartListener::onDragEvent)
+ .withOnContextClickListener(this::onContextMenuClick)
+ .withOnItemActivatedListener(this::onItemActivated)
+ .withOperationMonitor(mContentLock.getMonitor())
+ .withSelectionPredicate(selectionPredicate)
+ .build();
+ mInjector.updateSharedSelectionTracker(localTracker);
+ }
+
+ mSelectionMgr.addObserver(mSelectionMetadata);
+
// Construction of the input handlers is non trivial, so to keep logic clear,
// and code flexible, and DirectoryFragment small, the construction has been
// moved off into a separate class.
@@ -373,19 +357,8 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
mActions,
mSelectionMgr,
selectionPredicate,
- mDetailsLookup,
mFocusManager,
- mRecView,
- mState);
-
- MouseInputHandler mouseHandler =
- handlers.createMouseHandler(this::onContextMenuClick);
-
- TouchInputHandler touchHandler =
- handlers.createTouchHandler(gestureHelper, dragStartListener);
-
- GestureRouter<MotionInputHandler> gestureRouter = new GestureRouter<>(touchHandler);
- gestureRouter.register(MotionEvent.TOOL_TYPE_MOUSE, mouseHandler);
+ mRecView);
// This little guy gets added to each Holder, so that we can be notified of key events
// on RecyclerView items.
@@ -399,17 +372,6 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
new RefreshHelper(mRefreshLayout::setEnabled)
.attach(mRecView);
- GestureDetector gestureDetector = new GestureDetector(getContext(), gestureRouter);
-
- TouchEventRouter eventRouter = new TouchEventRouter(gestureDetector, gestureHelper);
-
- eventRouter.register(
- MotionEvent.TOOL_TYPE_MOUSE,
- new MouseDragEventInterceptor(
- mDetailsLookup, dragStartListener::onMouseDragEvent, mBandSelector));
-
- mRecView.addOnItemTouchListener(eventRouter);
-
mActionModeController = mInjector.getActionModeController(
mSelectionMetadata,
this::handleMenuItemClick);
@@ -455,16 +417,12 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
mState.dirConfigs.put(mLocalState.getConfigKey(), container);
}
- public void retainState(RetainedState state) {
- state.selection = new Selection();
- mSelectionMgr.copySelection(state.selection);
- }
-
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mLocalState.save(outState);
+ mSelectionMgr.onSaveInstanceState(outState);
}
@Override
@@ -515,7 +473,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
// TODO: Move to UserInputHander.
protected boolean onContextMenuClick(MotionEvent e) {
- if (mDetailsLookup.overStableItem(e)) {
+ if (mDetailsLookup.overItemWithSelectionKey(e)) {
View childView = mRecView.findChildViewUnder(e.getX(), e.getY());
ViewHolder holder = mRecView.getChildViewHolder(childView);
@@ -530,6 +488,13 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
return true;
}
+ private boolean onItemActivated(ItemDetails<String> item, MotionEvent e) {
+ return mActions.openItem(
+ item,
+ ActionHandler.VIEW_TYPE_PREVIEW,
+ ActionHandler.VIEW_TYPE_REGULAR);
+ }
+
public void onViewModeChanged() {
// Mode change is just visual change; no need to kick loader.
onDisplayStateChanged();
@@ -554,9 +519,6 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
int pad = getDirectoryPadding(mode);
mRecView.setPadding(pad, pad, pad, pad);
mRecView.requestLayout();
- if (mBandSelector != null) {
- mBandSelector.reset();
- }
mIconHelper.setViewMode(mode);
}
@@ -635,7 +597,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
}
private boolean handleMenuItemClick(MenuItem item) {
- Selection selection = new Selection();
+ MutableSelection<String> selection = new MutableSelection<>();
mSelectionMgr.copySelection(selection);
switch (item.getItemId()) {
@@ -780,7 +742,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
}
}
- private void showChooserForDoc(final Selection selected) {
+ private void showChooserForDoc(final Selection<String> selected) {
Metrics.logUserAction(getContext(), Metrics.USER_ACTION_OPEN);
assert selected.size() == 1;
@@ -789,7 +751,8 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
mActions.showChooserForDoc(doc);
}
- private void transferDocuments(final Selection selected, @Nullable DocumentStack destination,
+ private void transferDocuments(
+ final Selection<String> selected, @Nullable DocumentStack destination,
final @OpType int mode) {
switch (mode) {
case FileOperationService.OPERATION_COPY:
@@ -1025,7 +988,6 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
final Bundle args = new Bundle();
args.putParcelable(Shared.EXTRA_ROOT, root);
args.putParcelable(Shared.EXTRA_DOC, doc);
- args.putParcelable(Shared.EXTRA_SELECTION, new Selection());
final FragmentTransaction ft = fm.beginTransaction();
AnimationView.setupAnimations(ft, anim, args);
@@ -1084,9 +1046,9 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
mAdapter.notifyDataSetChanged();
- if (mRestoredSelection != null) {
- mSelectionMgr.restoreSelection(mRestoredSelection);
- mRestoredSelection = null;
+ if (mRestoredState != null) {
+ mSelectionMgr.onRestoreInstanceState(mRestoredState);
+ mRestoredState = null;
}
// Restore any previous instance state
diff --git a/src/com/android/documentsui/dirlist/DirectoryState.java b/src/com/android/documentsui/dirlist/DirectoryState.java
index b27a4b8f4..30d570c2f 100644
--- a/src/com/android/documentsui/dirlist/DirectoryState.java
+++ b/src/com/android/documentsui/dirlist/DirectoryState.java
@@ -22,8 +22,8 @@ import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.Shared;
import com.android.documentsui.services.FileOperation;
import com.android.documentsui.services.FileOperationService;
-import com.android.documentsui.sorting.SortModel;
import com.android.documentsui.sorting.SortDimension.SortDirection;
+import com.android.documentsui.sorting.SortModel;
import javax.annotation.Nullable;
@@ -31,6 +31,7 @@ final class DirectoryState {
private static final String EXTRA_SORT_DIMENSION_ID = "sortDimensionId";
private static final String EXTRA_SORT_DIRECTION = "sortDirection";
+ private static final String EXTRA_SELECTION_ID = "selectionId";
// Null when viewing Recents directory.
@Nullable DocumentInfo mDocument;
@@ -40,6 +41,10 @@ final class DirectoryState {
int mLastSortDimensionId = SortModel.SORT_DIMENSION_ID_UNKNOWN;
@SortDirection int mLastSortDirection;
+ // The unique id to identify the selection. It is null when the corresponding
+ // container (fragment/activity) is the first launch.
+ @Nullable String mSelectionId;
+
private RootInfo mRoot;
private String mConfigKey;
@@ -49,6 +54,7 @@ final class DirectoryState {
mPendingOperation = bundle.getParcelable(FileOperationService.EXTRA_OPERATION);
mLastSortDimensionId = bundle.getInt(EXTRA_SORT_DIMENSION_ID);
mLastSortDirection = bundle.getInt(EXTRA_SORT_DIRECTION);
+ mSelectionId = bundle.getString(EXTRA_SELECTION_ID);
}
public void save(Bundle bundle) {
@@ -57,6 +63,7 @@ final class DirectoryState {
bundle.putParcelable(FileOperationService.EXTRA_OPERATION, mPendingOperation);
bundle.putInt(EXTRA_SORT_DIMENSION_ID, mLastSortDimensionId);
bundle.putInt(EXTRA_SORT_DIRECTION, mLastSortDirection);
+ bundle.putString(EXTRA_SELECTION_ID, mSelectionId);
}
public FileOperation claimPendingOperation() {
@@ -65,11 +72,6 @@ final class DirectoryState {
return op;
}
- public void update(RootInfo root, DocumentInfo doc) {
- mRoot = root;
- mDocument = doc;
- }
-
String getConfigKey() {
if (mConfigKey == null) {
final StringBuilder builder = new StringBuilder();
diff --git a/src/com/android/documentsui/dirlist/DocsItemDetailsLookup.java b/src/com/android/documentsui/dirlist/DocsItemDetailsLookup.java
index bc4494cf8..6f16b7632 100644
--- a/src/com/android/documentsui/dirlist/DocsItemDetailsLookup.java
+++ b/src/com/android/documentsui/dirlist/DocsItemDetailsLookup.java
@@ -15,18 +15,19 @@
*/
package com.android.documentsui.dirlist;
+import android.view.MotionEvent;
+import android.view.View;
+
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
-import android.view.MotionEvent;
-import android.view.View;
-import com.android.documentsui.selection.ItemDetailsLookup;
+import com.android.documentsui.DocsSelectionHelper.DocDetailsLookup;
/**
* Access to details of an item associated with a {@link MotionEvent} instance.
*/
-final class DocsItemDetailsLookup extends ItemDetailsLookup {
+final class DocsItemDetailsLookup extends DocDetailsLookup {
private final RecyclerView mRecView;
@@ -35,47 +36,7 @@ final class DocsItemDetailsLookup extends ItemDetailsLookup {
}
@Override
- public boolean overItem(MotionEvent e) {
- return getItemPosition(e) != RecyclerView.NO_POSITION;
- }
-
- @Override
- public boolean overStableItem(MotionEvent e) {
- if (!overItem(e)) {
- return false;
- }
- ItemDetails details = getItemDetails(e);
- return details != null && details.hasStableId();
- }
-
- @Override
- public boolean inItemDragRegion(MotionEvent e) {
- if (!overItem(e)) {
- return false;
- }
- ItemDetails details = getItemDetails(e);
- return details != null && details.inDragRegion(e);
- }
-
- @Override
- public boolean inItemSelectRegion(MotionEvent e) {
- if (!overItem(e)) {
- return false;
- }
- ItemDetails details = getItemDetails(e);
- return details != null && details.inSelectionHotspot(e);
- }
-
- @Override
- public int getItemPosition(MotionEvent e) {
- View child = mRecView.findChildViewUnder(e.getX(), e.getY());
- return (child != null)
- ? mRecView.getChildAdapterPosition(child)
- : RecyclerView.NO_POSITION;
- }
-
- @Override
- public ItemDetails getItemDetails(MotionEvent e) {
+ public DocumentItemDetails getItemDetails(MotionEvent e) {
@Nullable DocumentHolder holder = getDocumentHolder(e);
return holder == null ? null : holder.getItemDetails();
}
diff --git a/src/com/android/documentsui/dirlist/DocsSelectionPredicate.java b/src/com/android/documentsui/dirlist/DocsSelectionPredicate.java
index 5ceb4617a..167cf1dbc 100644
--- a/src/com/android/documentsui/dirlist/DocsSelectionPredicate.java
+++ b/src/com/android/documentsui/dirlist/DocsSelectionPredicate.java
@@ -21,19 +21,20 @@ import static com.android.documentsui.base.DocumentInfo.getCursorString;
import android.database.Cursor;
import android.provider.DocumentsContract.Document;
+
+import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
import com.android.documentsui.ActivityConfig;
import com.android.documentsui.Model;
import com.android.documentsui.base.State;
-import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
/**
* Class embodying the logic as to whether an item (specified by id or position)
* can be selected (or not).
*/
-final class DocsSelectionPredicate extends SelectionPredicate {
+final class DocsSelectionPredicate extends SelectionPredicate<String> {
private ActivityConfig mConfig;
private Model mModel;
@@ -56,7 +57,7 @@ final class DocsSelectionPredicate extends SelectionPredicate {
}
@Override
- public boolean canSetStateForId(String id, boolean nextState) {
+ public boolean canSetStateForKey(String id, boolean nextState) {
if (nextState) {
// Check if an item can be selected
final Cursor cursor = mModel.getItem(id);
diff --git a/src/com/android/documentsui/dirlist/DocsStableIdProvider.java b/src/com/android/documentsui/dirlist/DocsStableIdProvider.java
index 96390df59..6ff73f279 100644
--- a/src/com/android/documentsui/dirlist/DocsStableIdProvider.java
+++ b/src/com/android/documentsui/dirlist/DocsStableIdProvider.java
@@ -17,9 +17,7 @@ package com.android.documentsui.dirlist;
import static androidx.core.util.Preconditions.checkArgument;
-import com.android.documentsui.selection.SelectionHelper.StableIdProvider;
-
-import java.util.List;
+import com.android.documentsui.DocsSelectionHelper.StableIdProvider;
/**
* Provides RecyclerView selection code access to stable ids backed
@@ -35,7 +33,7 @@ public final class DocsStableIdProvider extends StableIdProvider {
}
@Override
- public String getStableId(int position) {
+ public String getKey(int position) {
return mAdapter.getStableId(position);
}
@@ -43,9 +41,4 @@ public final class DocsStableIdProvider extends StableIdProvider {
public int getPosition(String id) {
return mAdapter.getPosition(id);
}
-
- @Override
- public List<String> getStableIds() {
- return mAdapter.getStableIds();
- }
}
diff --git a/src/com/android/documentsui/dirlist/DocumentHolder.java b/src/com/android/documentsui/dirlist/DocumentHolder.java
index 7854dc452..c1c5c1ee3 100644
--- a/src/com/android/documentsui/dirlist/DocumentHolder.java
+++ b/src/com/android/documentsui/dirlist/DocumentHolder.java
@@ -18,7 +18,6 @@ package com.android.documentsui.dirlist;
import android.content.Context;
import android.database.Cursor;
-import androidx.recyclerview.widget.RecyclerView;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -27,11 +26,15 @@ import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.widget.ImageView;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.android.documentsui.base.Shared;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
import javax.annotation.Nullable;
+/**
+ * ViewHolder of a document item within a RecyclerView.
+ */
public abstract class DocumentHolder
extends RecyclerView.ViewHolder implements View.OnKeyListener {
@@ -42,7 +45,7 @@ public abstract class DocumentHolder
protected @Nullable String mModelId;
// See #addKeyEventListener for details on the need for this field.
- private KeyboardEventListener mKeyEventListener;
+ private KeyboardEventListener<DocumentItemDetails> mKeyEventListener;
private final DocumentItemDetails mDetails;
@@ -56,7 +59,7 @@ public abstract class DocumentHolder
itemView.setOnKeyListener(this);
mContext = context;
- mDetails = new DocumentItemDetails();
+ mDetails = new DocumentItemDetails(this);
}
/**
@@ -94,10 +97,10 @@ public abstract class DocumentHolder
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
assert(mKeyEventListener != null);
- ItemDetails details = getItemDetails();
+ DocumentItemDetails details = getItemDetails();
return (details == null)
- ? false
- : mKeyEventListener.onKey(getItemDetails(), keyCode, event);
+ ? false
+ : mKeyEventListener.onKey(details, keyCode, event);
}
/**
@@ -108,7 +111,7 @@ public abstract class DocumentHolder
*
* <p>Ideally we'd not involve DocumentHolder in propagation of events like this.
*/
- public void addKeyEventListener(KeyboardEventListener listener) {
+ public void addKeyEventListener(KeyboardEventListener<DocumentItemDetails> listener) {
assert(mKeyEventListener == null);
mKeyEventListener = listener;
}
@@ -121,7 +124,7 @@ public abstract class DocumentHolder
return false;
}
- public ItemDetails getItemDetails() {
+ public DocumentItemDetails getItemDetails() {
return mDetails;
}
@@ -148,32 +151,4 @@ public abstract class DocumentHolder
static ViewPropertyAnimator fade(ImageView view, float alpha) {
return view.animate().setDuration(Shared.CHECK_ANIMATION_DURATION).alpha(alpha);
}
-
- private final class DocumentItemDetails extends ItemDetails {
-
- @Override
- public int getPosition() {
- return DocumentHolder.this.getAdapterPosition();
- }
-
- @Override
- public String getStableId() {
- return DocumentHolder.this.getModelId();
- }
-
- @Override
- public int getItemViewType() {
- return DocumentHolder.this.getItemViewType();
- }
-
- @Override
- public boolean inDragRegion(MotionEvent e) {
- return DocumentHolder.this.inDragRegion(e);
- }
-
- @Override
- public boolean inSelectionHotspot(MotionEvent e) {
- return DocumentHolder.this.inSelectRegion(e);
- }
- }
}
diff --git a/src/com/android/documentsui/dirlist/DocumentItemDetails.java b/src/com/android/documentsui/dirlist/DocumentItemDetails.java
new file mode 100644
index 000000000..bf6d7ddd5
--- /dev/null
+++ b/src/com/android/documentsui/dirlist/DocumentItemDetails.java
@@ -0,0 +1,59 @@
+/*
+ * 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.documentsui.dirlist;
+
+import android.view.MotionEvent;
+
+import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
+
+/**
+ * Provide information of a specific RecyclerView item for selection.
+ */
+public final class DocumentItemDetails extends ItemDetails<String> {
+ private final DocumentHolder mDocumentHolder;
+
+ DocumentItemDetails(DocumentHolder holder) {
+ mDocumentHolder = holder;
+ }
+
+ /**
+ * @return The view type of this ViewHolder.
+ */
+ public int getItemViewType() {
+ return mDocumentHolder.getItemViewType();
+ }
+
+ @Override
+ public int getPosition() {
+ return mDocumentHolder.getAdapterPosition();
+ }
+
+ @Override
+ public String getSelectionKey() {
+ return mDocumentHolder.getModelId();
+ }
+
+ @Override
+ public boolean inDragRegion(MotionEvent e) {
+ return mDocumentHolder.inDragRegion(e);
+ }
+
+ @Override
+ public boolean inSelectionHotspot(MotionEvent e) {
+ return mDocumentHolder.inSelectRegion(e);
+ }
+}
diff --git a/src/com/android/documentsui/dirlist/DragHost.java b/src/com/android/documentsui/dirlist/DragHost.java
index 770097d32..c1f9c8cb0 100644
--- a/src/com/android/documentsui/dirlist/DragHost.java
+++ b/src/com/android/documentsui/dirlist/DragHost.java
@@ -20,9 +20,11 @@ import static com.android.documentsui.base.SharedMinimal.DEBUG;
import android.app.Activity;
import android.content.ClipData;
+import android.util.Log;
import android.view.DragEvent;
import android.view.View;
-import android.util.Log;
+
+import androidx.recyclerview.selection.SelectionTracker;
import com.android.documentsui.AbstractActionHandler;
import com.android.documentsui.AbstractDragHost;
@@ -32,7 +34,6 @@ import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.DocumentStack;
import com.android.documentsui.base.Lookup;
import com.android.documentsui.base.State;
-import com.android.documentsui.selection.SelectionHelper;
import com.android.documentsui.ui.DialogController;
import java.util.function.Predicate;
@@ -45,7 +46,7 @@ class DragHost<T extends Activity & AbstractActionHandler.CommonAddons> extends
private static final String TAG = "dirlist.DragHost";
private final T mActivity;
- private final SelectionHelper mSelectionMgr;
+ private final SelectionTracker<String> mSelectionMgr;
private final ActionHandler mActions;
private final State mState;
private final DialogController mDialogs;
@@ -56,7 +57,7 @@ class DragHost<T extends Activity & AbstractActionHandler.CommonAddons> extends
DragHost(
T activity,
DragAndDropManager dragAndDropManager,
- SelectionHelper selectionMgr,
+ SelectionTracker<String> selectionMgr,
ActionHandler actions,
State state,
DialogController dialogs,
diff --git a/src/com/android/documentsui/dirlist/DragStartListener.java b/src/com/android/documentsui/dirlist/DragStartListener.java
index e3fa088a6..e88967573 100644
--- a/src/com/android/documentsui/dirlist/DragStartListener.java
+++ b/src/com/android/documentsui/dirlist/DragStartListener.java
@@ -17,24 +17,23 @@
package com.android.documentsui.dirlist;
import static com.android.documentsui.base.SharedMinimal.DEBUG;
-import static androidx.core.util.Preconditions.checkArgument;
import android.net.Uri;
-import androidx.annotation.VisibleForTesting;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
+import androidx.annotation.VisibleForTesting;
+import androidx.recyclerview.selection.MutableSelection;
+import androidx.recyclerview.selection.Selection;
+import androidx.recyclerview.selection.SelectionTracker;
+
import com.android.documentsui.DragAndDropManager;
import com.android.documentsui.MenuManager.SelectionDetails;
import com.android.documentsui.Model;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.Events;
import com.android.documentsui.base.State;
-import com.android.documentsui.selection.ItemDetailsLookup;
-import com.android.documentsui.selection.MutableSelection;
-import com.android.documentsui.selection.Selection;
-import com.android.documentsui.selection.SelectionHelper;
import java.util.ArrayList;
import java.util.List;
@@ -51,17 +50,12 @@ interface DragStartListener {
static final DragStartListener DUMMY = new DragStartListener() {
@Override
- public boolean onMouseDragEvent(MotionEvent event) {
- return false;
- }
- @Override
- public boolean onTouchDragEvent(MotionEvent event) {
+ public boolean onDragEvent(MotionEvent event) {
return false;
}
};
- boolean onMouseDragEvent(MotionEvent event);
- boolean onTouchDragEvent(MotionEvent event);
+ boolean onDragEvent(MotionEvent event);
@VisibleForTesting
class RuntimeDragStartListener implements DragStartListener {
@@ -70,12 +64,11 @@ interface DragStartListener {
private final IconHelper mIconHelper;
private final State mState;
- private final ItemDetailsLookup mDetailsLookup;
- private final SelectionHelper mSelectionMgr;
+ private final SelectionTracker<String> mSelectionMgr;
private final SelectionDetails mSelectionDetails;
private final ViewFinder mViewFinder;
private final Function<View, String> mIdFinder;
- private final Function<Selection, List<DocumentInfo>> mDocsConverter;
+ private final Function<Selection<String>, List<DocumentInfo>> mDocsConverter;
private final DragAndDropManager mDragAndDropManager;
@@ -84,17 +77,15 @@ interface DragStartListener {
public RuntimeDragStartListener(
IconHelper iconHelper,
State state,
- ItemDetailsLookup detailsLookup,
- SelectionHelper selectionMgr,
+ SelectionTracker<String> selectionMgr,
SelectionDetails selectionDetails,
ViewFinder viewFinder,
Function<View, String> idFinder,
- Function<Selection, List<DocumentInfo>> docsConverter,
+ Function<Selection<String>, List<DocumentInfo>> docsConverter,
DragAndDropManager dragAndDropManager) {
mIconHelper = iconHelper;
mState = state;
- mDetailsLookup = detailsLookup;
mSelectionMgr = selectionMgr;
mSelectionDetails = selectionDetails;
mViewFinder = viewFinder;
@@ -104,15 +95,7 @@ interface DragStartListener {
}
@Override
- public final boolean onMouseDragEvent(MotionEvent event) {
- checkArgument(Events.isMouseDragEvent(event));
- checkArgument(mDetailsLookup.inItemDragRegion(event));
-
- return startDrag(mViewFinder.findView(event.getX(), event.getY()), event);
- }
-
- @Override
- public final boolean onTouchDragEvent(MotionEvent event) {
+ public final boolean onDragEvent(MotionEvent event) {
return startDrag(mViewFinder.findView(event.getX(), event.getY()), event);
}
@@ -132,7 +115,7 @@ interface DragStartListener {
return false;
}
- Selection selection = getSelectionToBeCopied(modelId, event);
+ Selection<String> selection = getSelectionToBeCopied(modelId, event);
final List<DocumentInfo> srcs = mDocsConverter.apply(selection);
@@ -158,8 +141,8 @@ interface DragStartListener {
* coordinates of the event, return a valid selection for drag and drop operation
*/
@VisibleForTesting
- MutableSelection getSelectionToBeCopied(String modelId, MotionEvent event) {
- MutableSelection selection = new MutableSelection();
+ MutableSelection<String> getSelectionToBeCopied(String modelId, MotionEvent event) {
+ MutableSelection<String> selection = new MutableSelection<>();
// If CTRL-key is held down and there's other existing selection, add item to
// selection (if not already selected)
if (Events.isCtrlKeyPressed(event)
@@ -181,10 +164,9 @@ interface DragStartListener {
static DragStartListener create(
IconHelper iconHelper,
Model model,
- SelectionHelper selectionMgr,
+ SelectionTracker<String> selectionMgr,
SelectionDetails selectionDetails,
State state,
- ItemDetailsLookup detailsLookup,
Function<View, String> idFinder,
ViewFinder viewFinder,
DragAndDropManager dragAndDropManager) {
@@ -192,7 +174,6 @@ interface DragStartListener {
return new RuntimeDragStartListener(
iconHelper,
state,
- detailsLookup,
selectionMgr,
selectionDetails,
viewFinder,
diff --git a/src/com/android/documentsui/dirlist/FocusHandler.java b/src/com/android/documentsui/dirlist/FocusHandler.java
index 03cf23380..2c7f8e672 100644
--- a/src/com/android/documentsui/dirlist/FocusHandler.java
+++ b/src/com/android/documentsui/dirlist/FocusHandler.java
@@ -62,7 +62,7 @@ public interface FocusHandler extends View.OnFocusChangeListener {
/**
* @return The adapter position of the last focused item.
*/
- int getFocusPosition();
+ int getFocusedPosition();
/**
* @return True if there is currently an item in focus, false otherwise.
diff --git a/src/com/android/documentsui/dirlist/InputHandlers.java b/src/com/android/documentsui/dirlist/InputHandlers.java
index 2943c80a2..8cc2bfb74 100644
--- a/src/com/android/documentsui/dirlist/InputHandlers.java
+++ b/src/com/android/documentsui/dirlist/InputHandlers.java
@@ -17,22 +17,14 @@ package com.android.documentsui.dirlist;
import static androidx.core.util.Preconditions.checkArgument;
+import android.view.KeyEvent;
+
+import androidx.recyclerview.selection.SelectionTracker;
+import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
-import android.view.HapticFeedbackConstants;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
import com.android.documentsui.ActionHandler;
-import com.android.documentsui.base.EventHandler;
-import com.android.documentsui.base.State;
-import com.android.documentsui.selection.GestureSelectionHelper;
-import com.android.documentsui.selection.ItemDetailsLookup;
-import com.android.documentsui.selection.MouseInputHandler;
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.selection.TouchInputHandler;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
-import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
/**
* Helper class dedicated to building gesture input handlers. The construction
@@ -43,43 +35,36 @@ import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
final class InputHandlers {
private ActionHandler mActions;
- private SelectionHelper mSelectionHelper;
- private SelectionPredicate mSelectionPredicate;
- private ItemDetailsLookup mDetailsLookup;
+ private SelectionTracker<String> mSelectionHelper;
+ private SelectionPredicate<String> mSelectionPredicate;
private FocusHandler mFocusHandler;
private RecyclerView mRecView;
- private State mState;
InputHandlers(
ActionHandler actions,
- SelectionHelper selectionHelper,
- SelectionPredicate selectionPredicate,
- ItemDetailsLookup detailsLookup,
+ SelectionTracker<String> selectionHelper,
+ SelectionPredicate<String> selectionPredicate,
FocusHandler focusHandler,
- RecyclerView recView,
- State state) {
+ RecyclerView recView) {
checkArgument(actions != null);
checkArgument(selectionHelper != null);
checkArgument(selectionPredicate != null);
- checkArgument(detailsLookup != null);
checkArgument(focusHandler != null);
checkArgument(recView != null);
- checkArgument(state != null);
mActions = actions;
mSelectionHelper = selectionHelper;
mSelectionPredicate = selectionPredicate;
- mDetailsLookup = detailsLookup;
mFocusHandler = focusHandler;
mRecView = recView;
- mState = state;
}
KeyInputHandler createKeyHandler() {
- KeyInputHandler.Callbacks callbacks = new KeyInputHandler.Callbacks() {
+ KeyInputHandler.Callbacks<DocumentItemDetails> callbacks =
+ new KeyInputHandler.Callbacks<DocumentItemDetails>() {
@Override
- public boolean isInteractiveItem(ItemDetails item, KeyEvent e) {
+ public boolean isInteractiveItem(DocumentItemDetails item, KeyEvent e) {
switch (item.getItemViewType()) {
case DocumentsAdapter.ITEM_TYPE_HEADER_MESSAGE:
case DocumentsAdapter.ITEM_TYPE_INFLATED_MESSAGE:
@@ -95,7 +80,7 @@ final class InputHandlers {
}
@Override
- public boolean onItemActivated(ItemDetails item, KeyEvent e) {
+ public boolean onItemActivated(DocumentItemDetails item, KeyEvent e) {
// Handle enter key events
switch (e.getKeyCode()) {
case KeyEvent.KEYCODE_ENTER:
@@ -116,7 +101,7 @@ final class InputHandlers {
}
@Override
- public boolean onFocusItem(ItemDetails details, int keyCode, KeyEvent event) {
+ public boolean onFocusItem(DocumentItemDetails details, int keyCode, KeyEvent event) {
ViewHolder holder =
mRecView.findViewHolderForAdapterPosition(details.getPosition());
if (holder instanceof DocumentHolder) {
@@ -124,104 +109,8 @@ final class InputHandlers {
}
return false;
}
-
- @Override
- public void onPerformHapticFeedback() {
- mRecView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- }
};
return new KeyInputHandler(mSelectionHelper, mSelectionPredicate, callbacks);
}
-
- MouseInputHandler createMouseHandler(
- EventHandler<MotionEvent> showContextMenuCallback) {
-
- checkArgument(showContextMenuCallback != null);
-
- MouseInputHandler.Callbacks callbacks = new MouseInputHandler.Callbacks() {
- @Override
- public boolean onItemActivated(ItemDetails item, MotionEvent e) {
- return mActions.openItem(
- item,
- ActionHandler.VIEW_TYPE_REGULAR,
- ActionHandler.VIEW_TYPE_PREVIEW);
- }
-
- @Override
- public boolean onContextClick(MotionEvent e) {
- return showContextMenuCallback.accept(e);
- }
-
- @Override
- public void onPerformHapticFeedback() {
- mRecView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- }
-
- @Override
- public void focusItem(ItemDetails item) {
- mFocusHandler.focusDocument(item.getStableId());
- }
-
- @Override
- public void clearFocus() {
- mFocusHandler.clearFocus();
- }
-
- @Override
- public boolean hasFocusedItem() {
- return mFocusHandler.hasFocusedItem();
- }
-
- @Override
- public int getFocusedPosition() {
- return mFocusHandler.getFocusPosition();
- }
- };
-
- return new MouseInputHandler(mSelectionHelper, mDetailsLookup, callbacks);
- }
-
- /**
- * Factory method for input touch delegate. Exists to reduce complexity in the
- * calling scope.
- * @param gestureHelper
- */
- TouchInputHandler createTouchHandler(
- GestureSelectionHelper gestureHelper, DragStartListener dragStartListener) {
- checkArgument(dragStartListener != null);
-
- TouchInputHandler.Callbacks callbacks = new TouchInputHandler.Callbacks() {
- @Override
- public boolean onItemActivated(ItemDetails item, MotionEvent e) {
- return mActions.openItem(
- item,
- ActionHandler.VIEW_TYPE_PREVIEW,
- ActionHandler.VIEW_TYPE_REGULAR);
- }
-
- @Override
- public boolean onDragInitiated(MotionEvent e) {
- return dragStartListener.onTouchDragEvent(e);
- }
-
- @Override
- public void onPerformHapticFeedback() {
- mRecView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- }
-
- @Override
- public void focusItem(ItemDetails item) {
- mFocusHandler.focusDocument(item.getStableId());
- }
-
- @Override
- public void clearFocus() {
- mFocusHandler.clearFocus();
- }
- };
-
- return new TouchInputHandler(
- mSelectionHelper, mDetailsLookup, mSelectionPredicate, gestureHelper, callbacks);
- }
}
diff --git a/src/com/android/documentsui/dirlist/KeyInputHandler.java b/src/com/android/documentsui/dirlist/KeyInputHandler.java
index 6e82c3e0e..826270ea1 100644
--- a/src/com/android/documentsui/dirlist/KeyInputHandler.java
+++ b/src/com/android/documentsui/dirlist/KeyInputHandler.java
@@ -17,31 +17,30 @@ package com.android.documentsui.dirlist;
import android.view.KeyEvent;
+import androidx.recyclerview.selection.SelectionTracker;
+import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
+import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
+
import com.android.documentsui.base.Events;
-import com.android.documentsui.selection.ItemDetailsLookup;
-import com.android.documentsui.selection.MotionInputHandler;
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
-import com.android.documentsui.selection.MotionInputHandler.Callbacks;
-import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
import javax.annotation.Nullable;
+// TODO(b/69058726): Migrate to RecyclerView-Selection
/**
* Class that handles keyboard events on RecyclerView items. The input handler
* must be attached directly to a RecyclerView item since, unlike DOM, events
* don't appear bubble up.
*/
-public final class KeyInputHandler extends KeyboardEventListener {
+public final class KeyInputHandler extends KeyboardEventListener<DocumentItemDetails> {
- private final SelectionHelper mSelectionHelper;
- private final SelectionPredicate mSelectionPredicate;
- private final Callbacks mCallbacks;
+ private final SelectionTracker<String> mSelectionHelper;
+ private final SelectionPredicate<String> mSelectionPredicate;
+ private final Callbacks<DocumentItemDetails> mCallbacks;
public KeyInputHandler(
- SelectionHelper selectionHelper,
- SelectionPredicate selectionPredicate,
- Callbacks callbacks) {
+ SelectionTracker<String> selectionHelper,
+ SelectionPredicate<String> selectionPredicate,
+ Callbacks<DocumentItemDetails> callbacks) {
mSelectionHelper = selectionHelper;
mSelectionPredicate = selectionPredicate;
@@ -49,7 +48,7 @@ public final class KeyInputHandler extends KeyboardEventListener {
}
@Override
- public boolean onKey(@Nullable ItemDetails details, int keyCode, KeyEvent event) {
+ public boolean onKey(@Nullable DocumentItemDetails details, int keyCode, KeyEvent event) {
// Only handle key-down events. This is simpler, consistent with most other UIs, and
// enables the handling of repeated key events from holding down a key.
if (event.getAction() != KeyEvent.ACTION_DOWN) {
@@ -96,17 +95,17 @@ public final class KeyInputHandler extends KeyboardEventListener {
return mCallbacks.onItemActivated(details, event);
}
- private boolean shouldExtendSelection(ItemDetails item, KeyEvent event) {
+ private boolean shouldExtendSelection(DocumentItemDetails item, KeyEvent event) {
if (!Events.isNavigationKeyCode(event.getKeyCode()) || !event.isShiftPressed()) {
return false;
}
- return mSelectionPredicate.canSetStateForId(item.getStableId(), true);
+ return mSelectionPredicate.canSetStateForKey(item.getSelectionKey(), true);
}
- public static abstract class Callbacks extends MotionInputHandler.Callbacks {
- public abstract boolean isInteractiveItem(ItemDetails item, KeyEvent e);
- public abstract boolean onItemActivated(ItemDetails item, KeyEvent e);
- public abstract boolean onFocusItem(ItemDetails details, int keyCode, KeyEvent event);
+ public static abstract class Callbacks<T extends ItemDetails<?>> {
+ public abstract boolean isInteractiveItem(T item, KeyEvent e);
+ public abstract boolean onItemActivated(T item, KeyEvent e);
+ public abstract boolean onFocusItem(T details, int keyCode, KeyEvent event);
}
}
diff --git a/src/com/android/documentsui/dirlist/KeyboardEventListener.java b/src/com/android/documentsui/dirlist/KeyboardEventListener.java
index fb1fc0a6b..d45885de6 100644
--- a/src/com/android/documentsui/dirlist/KeyboardEventListener.java
+++ b/src/com/android/documentsui/dirlist/KeyboardEventListener.java
@@ -17,14 +17,13 @@ package com.android.documentsui.dirlist;
import android.view.KeyEvent;
-import com.android.documentsui.selection.ItemDetailsLookup;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
/**
* KeyboardListener is implemented by {@link KeyInputHandler}. The handler
* must be called from RecyclerView.Holders in response to keyboard events.
*/
-public abstract class KeyboardEventListener {
+public abstract class KeyboardEventListener<T extends ItemDetails<?>> {
/**
* Handles key events on the view holder.
@@ -35,5 +34,5 @@ public abstract class KeyboardEventListener {
*
* @return Whether the event was handled.
*/
- public abstract boolean onKey(ItemDetails details, int keyCode, KeyEvent event);
+ public abstract boolean onKey(T details, int keyCode, KeyEvent event);
}
diff --git a/src/com/android/documentsui/dirlist/MessageHolder.java b/src/com/android/documentsui/dirlist/MessageHolder.java
index 92686025b..1d8d7d61c 100644
--- a/src/com/android/documentsui/dirlist/MessageHolder.java
+++ b/src/com/android/documentsui/dirlist/MessageHolder.java
@@ -16,10 +16,7 @@
package com.android.documentsui.dirlist;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
-
import android.content.Context;
-import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.Space;
@@ -36,7 +33,7 @@ abstract class MessageHolder extends DocumentHolder {
}
@Override
- public ItemDetails getItemDetails() {
+ public DocumentItemDetails getItemDetails() {
return null;
}
}
diff --git a/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
index 85be6a692..604badf4f 100644
--- a/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
+++ b/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
@@ -23,16 +23,17 @@ import static com.android.documentsui.base.State.MODE_LIST;
import android.database.Cursor;
import android.provider.DocumentsContract.Document;
-import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
import android.view.ViewGroup;
+import androidx.recyclerview.selection.SelectionTracker;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.android.documentsui.Model;
import com.android.documentsui.Model.Update;
import com.android.documentsui.base.EventListener;
import com.android.documentsui.base.Lookup;
import com.android.documentsui.base.State;
-import com.android.documentsui.selection.SelectionHelper;
import java.util.ArrayList;
import java.util.List;
@@ -111,7 +112,7 @@ final class ModelBackedDocumentsAdapter extends DocumentsAdapter {
@Override
public void onBindViewHolder(DocumentHolder holder, int position, List<Object> payload) {
- if (payload.contains(SelectionHelper.SELECTION_CHANGED_MARKER)) {
+ if (payload.contains(SelectionTracker.SELECTION_CHANGED_MARKER)) {
final boolean selected = mEnv.isSelected(mModelIds.get(position));
holder.setSelected(selected, true);
} else {
diff --git a/src/com/android/documentsui/dirlist/MouseDragEventInterceptor.java b/src/com/android/documentsui/dirlist/MouseDragEventInterceptor.java
deleted file mode 100644
index 2aba9277c..000000000
--- a/src/com/android/documentsui/dirlist/MouseDragEventInterceptor.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.dirlist;
-
-import static androidx.core.util.Preconditions.checkArgument;
-
-import androidx.annotation.Nullable;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
-import android.view.MotionEvent;
-
-import com.android.documentsui.base.EventHandler;
-import com.android.documentsui.base.Events;
-import com.android.documentsui.selection.BandSelectionHelper;
-import com.android.documentsui.selection.ItemDetailsLookup;
-import com.android.documentsui.selection.TouchEventRouter;
-
-/**
- * OnItemTouchListener that helps enable support for drag/drop functionality
- * in DirectoryFragment.
- *
- * <p>This class takes an OnItemTouchListener that is presumably the
- * one provided by {@link BandSelectionHelper#getListener()}, and
- * is used in conjunction with the {@link TouchEventRouter}.
- *
- * <p>See DirectoryFragment for more details on how this is glued
- * into DocumetnsUI event handling to make the magic happen.
- */
-class MouseDragEventInterceptor implements OnItemTouchListener {
-
- private final ItemDetailsLookup mEventDetailsLookup;
- private final EventHandler<MotionEvent> mMouseDragListener;
- private final @Nullable OnItemTouchListener mDelegate;
-
- public MouseDragEventInterceptor(
- ItemDetailsLookup eventDetailsLookup,
- EventHandler<MotionEvent> mouseDragListener,
- @Nullable OnItemTouchListener delegate) {
-
- checkArgument(eventDetailsLookup != null);
- checkArgument(mouseDragListener != null);
-
- mEventDetailsLookup = eventDetailsLookup;
- mMouseDragListener = mouseDragListener;
- mDelegate = delegate;
- }
-
- @Override
- public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
- if (Events.isMouseDragEvent(e) && mEventDetailsLookup.inItemDragRegion(e)) {
- return mMouseDragListener.accept(e);
- } else if (mDelegate != null) {
- return mDelegate.onInterceptTouchEvent(rv, e);
- }
- return false;
- }
-
- @Override
- public void onTouchEvent(RecyclerView rv, MotionEvent e) {
- if (mDelegate != null) {
- mDelegate.onTouchEvent(rv, e);
- }
- }
-
- @Override
- public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
-}
diff --git a/src/com/android/documentsui/dirlist/SelectionMetadata.java b/src/com/android/documentsui/dirlist/SelectionMetadata.java
index 3ac3a0741..3abc3e190 100644
--- a/src/com/android/documentsui/dirlist/SelectionMetadata.java
+++ b/src/com/android/documentsui/dirlist/SelectionMetadata.java
@@ -23,11 +23,12 @@ import android.database.Cursor;
import android.provider.DocumentsContract.Document;
import android.util.Log;
+import androidx.recyclerview.selection.SelectionTracker.SelectionObserver;
+
import com.android.documentsui.MenuManager;
import com.android.documentsui.archives.ArchivesProvider;
import com.android.documentsui.base.MimeTypes;
import com.android.documentsui.roots.RootCursorWrapper;
-import com.android.documentsui.selection.SelectionHelper.SelectionObserver;
import java.util.function.Function;
@@ -38,7 +39,7 @@ import java.util.function.Function;
* <p>By collecting information in real-time as the selection changes the need to
* traverse the entire selection in order to answer questions is eliminated.
*/
-public class SelectionMetadata extends SelectionObserver
+public class SelectionMetadata extends SelectionObserver<String>
implements MenuManager.SelectionDetails {
private static final String TAG = "SelectionMetadata";
@@ -107,7 +108,7 @@ public class SelectionMetadata extends SelectionObserver
}
@Override
- public void onSelectionReset() {
+ public void onSelectionRefresh() {
mFileCount = 0;
mDirectoryCount = 0;
mPartialCount = 0;
diff --git a/src/com/android/documentsui/files/ActionHandler.java b/src/com/android/documentsui/files/ActionHandler.java
index 19c812ffd..62ae87807 100644
--- a/src/com/android/documentsui/files/ActionHandler.java
+++ b/src/com/android/documentsui/files/ActionHandler.java
@@ -31,6 +31,10 @@ import android.util.Log;
import android.view.DragEvent;
import android.view.View;
+import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
+import androidx.recyclerview.selection.MutableSelection;
+import androidx.recyclerview.selection.Selection;
+
import com.android.documentsui.AbstractActionHandler;
import com.android.documentsui.ActionModeAddons;
import com.android.documentsui.ActivityConfig;
@@ -60,9 +64,6 @@ import com.android.documentsui.files.ActionHandler.Addons;
import com.android.documentsui.inspector.InspectorActivity;
import com.android.documentsui.queries.SearchViewManager;
import com.android.documentsui.roots.ProvidersAccess;
-import com.android.documentsui.selection.MutableSelection;
-import com.android.documentsui.selection.Selection;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
import com.android.documentsui.services.FileOperation;
import com.android.documentsui.services.FileOperationService;
import com.android.documentsui.services.FileOperations;
@@ -140,7 +141,7 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
@Override
public void openSelectedInNewWindow() {
- Selection selection = getStableSelection();
+ Selection<String> selection = getStableSelection();
assert(selection.size() == 1);
DocumentInfo doc = mModel.getDocument(selection.iterator().next());
assert(doc != null);
@@ -194,12 +195,12 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
}
@Override
- public boolean openItem(ItemDetails details, @ViewType int type,
+ public boolean openItem(ItemDetails<String> details, @ViewType int type,
@ViewType int fallback) {
- DocumentInfo doc = mModel.getDocument(details.getStableId());
+ DocumentInfo doc = mModel.getDocument(details.getSelectionKey());
if (doc == null) {
- Log.w(TAG,
- "Can't view item. No Document available for modeId: " + details.getStableId());
+ Log.w(TAG, "Can't view item. No Document available for modeId: "
+ + details.getSelectionKey());
return false;
}
@@ -224,8 +225,8 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
openContainerDocument(doc);
}
- private Selection getSelectedOrFocused() {
- final MutableSelection selection = this.getStableSelection();
+ private Selection<String> getSelectedOrFocused() {
+ final MutableSelection<String> selection = this.getStableSelection();
if (selection.isEmpty()) {
String focusModelId = mFocusHandler.getFocusModelId();
if (focusModelId != null) {
@@ -239,7 +240,7 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
@Override
public void cutToClipboard() {
Metrics.logUserAction(mActivity, Metrics.USER_ACTION_CUT_CLIPBOARD);
- Selection selection = getSelectedOrFocused();
+ Selection<String> selection = getSelectedOrFocused();
if (selection.isEmpty()) {
return;
@@ -260,7 +261,7 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
@Override
public void copyToClipboard() {
Metrics.logUserAction(mActivity, Metrics.USER_ACTION_COPY_CLIPBOARD);
- Selection selection = getSelectedOrFocused();
+ Selection<String> selection = getSelectedOrFocused();
if (selection.isEmpty()) {
return;
@@ -275,7 +276,7 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
@Override
public void viewInOwner() {
Metrics.logUserAction(mActivity, Metrics.USER_ACTION_VIEW_IN_APPLICATION);
- Selection selection = getSelectedOrFocused();
+ Selection<String> selection = getSelectedOrFocused();
if (selection.isEmpty() || selection.size() > 1) {
return;
@@ -297,7 +298,7 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
@Override
public void deleteSelectedDocuments() {
Metrics.logUserAction(mActivity, Metrics.USER_ACTION_DELETE);
- Selection selection = getSelectedOrFocused();
+ Selection<String> selection = getSelectedOrFocused();
if (selection.isEmpty()) {
return;
@@ -362,7 +363,7 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
public void shareSelectedDocuments() {
Metrics.logUserAction(mActivity, Metrics.USER_ACTION_SHARE);
- Selection selection = getStableSelection();
+ Selection<String> selection = getStableSelection();
assert(!selection.isEmpty());
diff --git a/src/com/android/documentsui/files/FilesActivity.java b/src/com/android/documentsui/files/FilesActivity.java
index e8cdc642f..c07deb6ed 100644
--- a/src/com/android/documentsui/files/FilesActivity.java
+++ b/src/com/android/documentsui/files/FilesActivity.java
@@ -98,7 +98,7 @@ public class FilesActivity extends BaseActivity implements ActionHandler.Addons
super.onCreate(icicle);
DocumentClipper clipper = DocumentsApplication.getDocumentClipper(this);
- mInjector.selectionMgr = DocsSelectionHelper.createMultiSelect();
+ mInjector.selectionMgr = DocsSelectionHelper.create();
mInjector.focusManager = new FocusManager(
mInjector.features,
diff --git a/src/com/android/documentsui/files/MenuManager.java b/src/com/android/documentsui/files/MenuManager.java
index bc21a2d49..9bb102c83 100644
--- a/src/com/android/documentsui/files/MenuManager.java
+++ b/src/com/android/documentsui/files/MenuManager.java
@@ -28,15 +28,15 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+import androidx.recyclerview.selection.SelectionTracker;
+
import com.android.documentsui.R;
-import com.android.documentsui.MenuManager.SelectionDetails;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.Features;
import com.android.documentsui.base.Lookup;
import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.State;
import com.android.documentsui.queries.SearchViewManager;
-import com.android.documentsui.selection.SelectionHelper;
import java.util.List;
import java.util.function.IntFunction;
@@ -45,7 +45,7 @@ public final class MenuManager extends com.android.documentsui.MenuManager {
private final Features mFeatures;
private final Context mContext;
- private final SelectionHelper mSelectionManager;
+ private final SelectionTracker<String> mSelectionManager;
private final Lookup<String, Uri> mUriLookup;
private final Lookup<String, String> mAppNameLookup;
@@ -55,7 +55,7 @@ public final class MenuManager extends com.android.documentsui.MenuManager {
State displayState,
DirectoryDetails dirDetails,
Context context,
- SelectionHelper selectionManager,
+ SelectionTracker<String> selectionManager,
Lookup<String, String> appNameLookup,
Lookup<String, Uri> uriLookup) {
diff --git a/src/com/android/documentsui/picker/ActionHandler.java b/src/com/android/documentsui/picker/ActionHandler.java
index f18a7fe6f..ff8a2dd71 100644
--- a/src/com/android/documentsui/picker/ActionHandler.java
+++ b/src/com/android/documentsui/picker/ActionHandler.java
@@ -36,6 +36,8 @@ import android.provider.DocumentsContract;
import android.provider.Settings;
import android.util.Log;
+import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
+
import com.android.documentsui.AbstractActionHandler;
import com.android.documentsui.ActivityConfig;
import com.android.documentsui.DocumentsAccess;
@@ -54,7 +56,6 @@ import com.android.documentsui.dirlist.AnimationView;
import com.android.documentsui.picker.ActionHandler.Addons;
import com.android.documentsui.queries.SearchViewManager;
import com.android.documentsui.roots.ProvidersAccess;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
import com.android.documentsui.services.FileOperationService;
import androidx.annotation.VisibleForTesting;
@@ -246,12 +247,12 @@ class ActionHandler<T extends Activity & Addons> extends AbstractActionHandler<T
}
@Override
- public boolean openItem(ItemDetails details, @ViewType int type,
+ public boolean openItem(ItemDetails<String> details, @ViewType int type,
@ViewType int fallback) {
- DocumentInfo doc = mModel.getDocument(details.getStableId());
+ DocumentInfo doc = mModel.getDocument(details.getSelectionKey());
if (doc == null) {
- Log.w(TAG,
- "Can't view item. No Document available for modeId: " + details.getStableId());
+ Log.w(TAG, "Can't view item. No Document available for modeId: "
+ + details.getSelectionKey());
return false;
}
diff --git a/src/com/android/documentsui/picker/PickActivity.java b/src/com/android/documentsui/picker/PickActivity.java
index dc9690e1b..4e1556275 100644
--- a/src/com/android/documentsui/picker/PickActivity.java
+++ b/src/com/android/documentsui/picker/PickActivity.java
@@ -94,9 +94,7 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons {
super.onCreate(icicle);
- mInjector.selectionMgr = mState.allowMultiple
- ? DocsSelectionHelper.createMultiSelect()
- : DocsSelectionHelper.createSingleSelect();
+ mInjector.selectionMgr = DocsSelectionHelper.create();
mInjector.focusManager = new FocusManager(
mInjector.features,
diff --git a/src/com/android/documentsui/selection/BandPredicate.java b/src/com/android/documentsui/selection/BandPredicate.java
deleted file mode 100644
index 08d64a81b..000000000
--- a/src/com/android/documentsui/selection/BandPredicate.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-import static androidx.core.util.Preconditions.checkArgument;
-
-import androidx.recyclerview.widget.RecyclerView;
-import android.view.MotionEvent;
-import android.view.View;
-
-/**
- * Provides a means of controlling when and where band selection is initiated.
- * This can be used to permit band initiation in non-empty areas, like in the whitespace of
- * a bound view. This is especially useful when there is no empty space between items.
- */
-public abstract class BandPredicate {
-
- /** @return true if band selection can be initiated in response to the {@link MotionEvent}. */
- public abstract boolean canInitiate(MotionEvent e);
-
- /**
- * A BandPredicate that allows initiation of band selection only in areas of RecyclerView
- * that have {@link RecyclerView#NO_POSITION}. In most cases, this will be the empty areas
- * between views.
- */
- public static final class NoPositionBandPredicate extends BandPredicate {
-
- private final RecyclerView mRecView;
-
- public NoPositionBandPredicate(RecyclerView recView) {
- checkArgument(recView != null);
-
- mRecView = recView;
- }
-
- @Override
- public boolean canInitiate(MotionEvent e) {
- View itemView = mRecView.findChildViewUnder(e.getX(), e.getY());
- int position = itemView != null
- ? mRecView.getChildAdapterPosition(itemView)
- : RecyclerView.NO_POSITION;
-
- return position == RecyclerView.NO_POSITION;
- }
- };
-}
diff --git a/src/com/android/documentsui/selection/BandSelectionHelper.java b/src/com/android/documentsui/selection/BandSelectionHelper.java
deleted file mode 100644
index f5aa4665d..000000000
--- a/src/com/android/documentsui/selection/BandSelectionHelper.java
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- * Copyright (C) 2015 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.documentsui.selection;
-
-import static androidx.core.util.Preconditions.checkArgument;
-import static androidx.core.util.Preconditions.checkState;
-import static com.android.documentsui.base.SharedMinimal.DEBUG;
-
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.Build;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
-import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
-import android.util.Log;
-import android.view.MotionEvent;
-
-import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
-import com.android.documentsui.selection.SelectionHelper.StableIdProvider;
-import com.android.documentsui.selection.ViewAutoScroller.ScrollHost;
-import com.android.documentsui.selection.ViewAutoScroller.ScrollerCallbacks;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Provides mouse driven band-selection support when used in conjunction with a {@link RecyclerView}
- * instance. This class is responsible for rendering a band overlay and manipulating selection
- * status of the items it intersects with.
- *
- * <p> Given the recycling nature of RecyclerView items that have scrolled off-screen would not
- * be selectable with a band that itself was partially rendered off-screen. To address this,
- * BandSelectionController builds a model of the list/grid information presented by RecyclerView as
- * the user interacts with items using their pointer (and the band). Selectable items that intersect
- * with the band, both on and off screen, are selected on pointer up.
- */
-public class BandSelectionHelper implements OnItemTouchListener {
-
- static final String TAG = "BandController";
-
- private final BandHost mHost;
- private final StableIdProvider mStableIds;
- private final RecyclerView.Adapter<?> mAdapter;
- private final SelectionHelper mSelectionHelper;
- private final SelectionPredicate mSelectionPredicate;
- private final BandPredicate mBandPredicate;
- private final ContentLock mLock;
- private final Runnable mViewScroller;
- private final GridModel.SelectionObserver mGridObserver;
- private final List<Runnable> mBandStartedListeners = new ArrayList<>();
-
- @Nullable private Rect mBounds;
- @Nullable private Point mCurrentPosition;
- @Nullable private Point mOrigin;
- @Nullable private GridModel mModel;
-
- public BandSelectionHelper(
- BandHost host,
- RecyclerView.Adapter<?> adapter,
- StableIdProvider stableIds,
- SelectionHelper selectionHelper,
- SelectionPredicate selectionPredicate,
- BandPredicate bandPredicate,
- ContentLock lock) {
-
- checkArgument(host != null);
- checkArgument(adapter != null);
- checkArgument(stableIds != null);
- checkArgument(selectionHelper != null);
- checkArgument(selectionPredicate != null);
- checkArgument(bandPredicate != null);
- checkArgument(lock != null);
-
- mHost = host;
- mStableIds = stableIds;
- mAdapter = adapter;
- mSelectionHelper = selectionHelper;
- mSelectionPredicate = selectionPredicate;
- mBandPredicate = bandPredicate;
- mLock = lock;
-
- mHost.addOnScrollListener(
- new OnScrollListener() {
- @Override
- public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
- BandSelectionHelper.this.onScrolled(recyclerView, dx, dy);
- }
- });
-
- mViewScroller = new ViewAutoScroller(
- new ScrollHost() {
- @Override
- public Point getCurrentPosition() {
- return mCurrentPosition;
- }
-
- @Override
- public int getViewHeight() {
- return mHost.getHeight();
- }
-
- @Override
- public boolean isActive() {
- return BandSelectionHelper.this.isActive();
- }
- },
- host);
-
- mAdapter.registerAdapterDataObserver(
- new RecyclerView.AdapterDataObserver() {
- @Override
- public void onChanged() {
- if (isActive()) {
- endBandSelect();
- }
- }
-
- @Override
- public void onItemRangeChanged(
- int startPosition, int itemCount, Object payload) {
- // No change in position. Ignoring.
- }
-
- @Override
- public void onItemRangeInserted(int startPosition, int itemCount) {
- if (isActive()) {
- endBandSelect();
- }
- }
-
- @Override
- public void onItemRangeRemoved(int startPosition, int itemCount) {
- assert(startPosition >= 0);
- assert(itemCount > 0);
-
- // TODO: Should update grid model.
- }
-
- @Override
- public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
- throw new UnsupportedOperationException();
- }
- });
-
- mGridObserver = new GridModel.SelectionObserver() {
- @Override
- public void onSelectionChanged(Set<String> updatedSelection) {
- mSelectionHelper.setProvisionalSelection(updatedSelection);
- }
- };
- }
-
- @VisibleForTesting
- boolean isActive() {
- boolean active = mModel != null;
- if (DEBUG && active) {
- mLock.checkLocked();
- }
- return active;
- }
-
- /**
- * Adds a new listener to be notified when band is created.
- */
- public void addOnBandStartedListener(Runnable listener) {
- checkArgument(listener != null);
-
- mBandStartedListeners.add(listener);
- }
-
- /**
- * Removes listener. No-op if listener was not previously installed.
- */
- public void removeOnBandStartedListener(Runnable listener) {
- mBandStartedListeners.remove(listener);
- }
-
- /**
- * Clients must call reset when there are any material changes to the layout of items
- * in RecyclerView.
- */
- public void reset() {
- if (!isActive()) {
- return;
- }
-
- mHost.hideBand();
- mModel.stopCapturing();
- mModel.onDestroy();
- mModel = null;
- mOrigin = null;
- mLock.unblock();
- }
-
- boolean shouldStart(MotionEvent e) {
- // Don't start, or extend bands on non-left clicks.
- if (!MotionEvents.isPrimaryButtonPressed(e)) {
- return false;
- }
-
- // TODO: Refactor to NOT have side-effects on this "should" method.
- // Weird things happen if we keep up band select
- // when touch events happen.
- if (isActive() && !MotionEvents.isMouseEvent(e)) {
- endBandSelect();
- return false;
- }
-
- // b/30146357 && b/23793622. onInterceptTouchEvent does not dispatch events to onTouchEvent
- // unless the event is != ACTION_DOWN. Thus, we need to actually start band selection when
- // mouse moves, or else starting band selection on mouse down can cause problems as events
- // don't get routed correctly to onTouchEvent.
- return !isActive()
- && MotionEvents.isActionMove(e)
- // the initial button move via mouse-touch (ie. down press)
- // The adapter inserts items for UI layout purposes that aren't
- // associated with files. Checking against actual modelIds count
- // effectively ignores those UI layout items.
- && !mStableIds.getStableIds().isEmpty()
- && mBandPredicate.canInitiate(e);
- }
-
- public boolean shouldStop(MotionEvent e) {
- return isActive()
- && MotionEvents.isMouseEvent(e)
- && (MotionEvents.isActionUp(e)
- || MotionEvents.isActionPointerUp(e)
- || MotionEvents.isActionCancel(e));
- }
-
- @Override
- public boolean onInterceptTouchEvent(RecyclerView unused, MotionEvent e) {
- if (shouldStart(e)) {
- if (!MotionEvents.isCtrlKeyPressed(e)) {
- mSelectionHelper.clearSelection();
- }
-
- startBandSelect(MotionEvents.getOrigin(e));
- return isActive();
- }
-
- if (shouldStop(e)) {
- endBandSelect();
- checkState(mModel == null);
- // fall through to return false, because the band eeess done!
- }
-
- return false;
- }
-
- /**
- * Processes a MotionEvent by starting, ending, or resizing the band select overlay.
- * @param input
- */
- @Override
- public void onTouchEvent(RecyclerView unused, MotionEvent e) {
- if (shouldStop(e)) {
- endBandSelect();
- return;
- }
-
- // We shouldn't get any events in this method when band select is not active,
- // but it turns some guests show up late to the party.
- // Probably happening when a re-layout is happening to the ReyclerView (ie. Pull-To-Refresh)
- if (!isActive()) {
- return;
- }
-
- assert MotionEvents.isActionMove(e);
-
- mCurrentPosition = MotionEvents.getOrigin(e);
- mModel.resizeSelection(mCurrentPosition);
-
- scrollViewIfNecessary();
- resizeBand();
- }
-
- @Override
- public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
-
- /**
- * Starts band select by adding the drawable to the RecyclerView's overlay.
- */
- private void startBandSelect(Point origin) {
- if (DEBUG) Log.d(TAG, "Starting band select @ " + origin);
-
- reset();
- mModel = new GridModel(mHost, mStableIds, mSelectionPredicate);
- mModel.addOnSelectionChangedListener(mGridObserver);
-
- mLock.block();
- notifyBandStarted();
- mOrigin = origin;
- mModel.startCapturing(mOrigin);
- }
-
- private void notifyBandStarted() {
- for (Runnable listener : mBandStartedListeners) {
- listener.run();
- }
- }
-
- private void scrollViewIfNecessary() {
- mHost.removeCallback(mViewScroller);
- mViewScroller.run();
- mHost.invalidateView();
- }
-
- /**
- * Resizes the band select rectangle by using the origin and the current pointer position as
- * two opposite corners of the selection.
- */
- private void resizeBand() {
- mBounds = new Rect(Math.min(mOrigin.x, mCurrentPosition.x),
- Math.min(mOrigin.y, mCurrentPosition.y),
- Math.max(mOrigin.x, mCurrentPosition.x),
- Math.max(mOrigin.y, mCurrentPosition.y));
-
- mHost.showBand(mBounds);
- }
-
- /**
- * Ends band select by removing the overlay.
- */
- private void endBandSelect() {
- if (DEBUG) Log.d(TAG, "Ending band select.");
-
- // TODO: Currently when a band select operation ends outside
- // of an item (e.g. in the empty area between items),
- // getPositionNearestOrigin may return an unselected item.
- // Since the point of this code is to establish the
- // anchor point for subsequent range operations (SHIFT+CLICK)
- // we really want to do a better job figuring out the last
- // item selected (and nearest to the cursor).
- int firstSelected = mModel.getPositionNearestOrigin();
- if (firstSelected != GridModel.NOT_SET
- && mSelectionHelper.isSelected(mStableIds.getStableId(firstSelected))) {
- // Establish the band selection point as range anchor. This
- // allows touch and keyboard based selection activities
- // to be based on the band selection anchor point.
- mSelectionHelper.anchorRange(firstSelected);
- }
-
- mSelectionHelper.mergeProvisionalSelection();
- reset();
- }
-
- /**
- * @see RecyclerView.OnScrollListener
- */
- private void onScrolled(RecyclerView recyclerView, int dx, int dy) {
- if (!isActive()) {
- return;
- }
-
- // Adjust the y-coordinate of the origin the opposite number of pixels so that the
- // origin remains in the same place relative to the view's items.
- mOrigin.y -= dy;
- resizeBand();
- }
-
- /**
- * Provides functionality for BandController. Exists primarily to tests that are
- * fully isolated from RecyclerView.
- */
- public static abstract class BandHost extends ScrollerCallbacks {
- public abstract void showBand(Rect rect);
- public abstract void hideBand();
- public abstract void addOnScrollListener(RecyclerView.OnScrollListener listener);
- public abstract void removeOnScrollListener(RecyclerView.OnScrollListener listener);
- public abstract int getHeight();
- public abstract void invalidateView();
- public abstract Point createAbsolutePoint(Point relativePoint);
- public abstract Rect getAbsoluteRectForChildViewAt(int index);
- public abstract int getAdapterPositionAt(int index);
- public abstract int getColumnCount();
- public abstract int getChildCount();
- public abstract int getVisibleChildCount();
- /**
- * @return true if the item at adapter position is attached to a view.
- */
- public abstract boolean hasView(int adapterPosition);
- }
-}
diff --git a/src/com/android/documentsui/selection/ContentLock.java b/src/com/android/documentsui/selection/ContentLock.java
deleted file mode 100644
index 387e70ccc..000000000
--- a/src/com/android/documentsui/selection/ContentLock.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-import static androidx.core.util.Preconditions.checkState;
-import static com.android.documentsui.selection.Shared.DEBUG;
-import static com.android.documentsui.selection.Shared.TAG;
-
-import androidx.annotation.MainThread;
-import androidx.annotation.Nullable;
-import android.content.Loader;
-import android.util.Log;
-
-/**
- * ContentLock provides a mechanism to block content from reloading while selection
- * activities like gesture and band selection are active. Clients using live data
- * (data loaded, for example by a {@link Loader}), should route calls to load
- * content through this lock using {@link ContentLock#runWhenUnlocked(Runnable)}.
- */
-public final class ContentLock {
-
- private int mLocks = 0;
- private @Nullable Runnable mCallback;
-
- /**
- * Increment the block count by 1
- */
- @MainThread
- public synchronized void block() {
- mLocks++;
- if (DEBUG) Log.v(TAG, "Incremented content lock count to " + mLocks + ".");
- }
-
- /**
- * Decrement the block count by 1; If no other object is trying to block and there exists some
- * callback, that callback will be run
- */
- @MainThread
- public synchronized void unblock() {
- checkState(mLocks > 0);
-
- mLocks--;
- if (DEBUG) Log.v(TAG, "Decremented content lock count to " + mLocks + ".");
-
- if (mLocks == 0 && mCallback != null) {
- mCallback.run();
- mCallback = null;
- }
- }
-
- /**
- * Attempts to run the given Runnable if not-locked, or else the Runnable is set to be ran next
- * (replacing any previous set Runnables).
- */
- public synchronized void runWhenUnlocked(Runnable runnable) {
- if (mLocks == 0) {
- runnable.run();
- } else {
- mCallback = runnable;
- }
- }
-
- /**
- * Returns true if locked.
- */
- synchronized boolean isLocked() {
- return mLocks > 0;
- }
-
- /**
- * Allows other selection code to perform a precondition check asserting the state is locked.
- */
- final void checkLocked() {
- checkState(isLocked());
- }
-
- /**
- * Allows other selection code to perform a precondition check asserting the state is unlocked.
- */
- final void checkUnlocked() {
- checkState(!isLocked());
- }
-}
diff --git a/src/com/android/documentsui/selection/DefaultBandHost.java b/src/com/android/documentsui/selection/DefaultBandHost.java
deleted file mode 100644
index 5b24e8e92..000000000
--- a/src/com/android/documentsui/selection/DefaultBandHost.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-import static androidx.core.util.Preconditions.checkArgument;
-
-import androidx.annotation.DrawableRes;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-import android.view.View;
-
-import com.android.documentsui.selection.BandSelectionHelper.BandHost;
-
-/**
- * RecyclerView backed {@link BandHost}.
- */
-public final class DefaultBandHost extends BandHost {
-
- private final RecyclerView mRecView;
- private final Drawable mBand;
-
- private boolean mIsOverlayShown;
-
- public DefaultBandHost(RecyclerView recView, @DrawableRes int bandOverlayId) {
-
- checkArgument(recView != null);
-
- mRecView = recView;
- mBand = mRecView.getContext().getTheme().getDrawable(bandOverlayId);
-
- checkArgument(mBand != null);
- }
-
- @Override
- public int getAdapterPositionAt(int index) {
- return mRecView.getChildAdapterPosition(mRecView.getChildAt(index));
- }
-
- @Override
- public void addOnScrollListener(RecyclerView.OnScrollListener listener) {
- mRecView.addOnScrollListener(listener);
- }
-
- @Override
- public void removeOnScrollListener(RecyclerView.OnScrollListener listener) {
- mRecView.removeOnScrollListener(listener);
- }
-
- @Override
- public Point createAbsolutePoint(Point relativePoint) {
- return new Point(relativePoint.x + mRecView.computeHorizontalScrollOffset(),
- relativePoint.y + mRecView.computeVerticalScrollOffset());
- }
-
- @Override
- public Rect getAbsoluteRectForChildViewAt(int index) {
- final View child = mRecView.getChildAt(index);
- final Rect childRect = new Rect();
- child.getHitRect(childRect);
- childRect.left += mRecView.computeHorizontalScrollOffset();
- childRect.right += mRecView.computeHorizontalScrollOffset();
- childRect.top += mRecView.computeVerticalScrollOffset();
- childRect.bottom += mRecView.computeVerticalScrollOffset();
- return childRect;
- }
-
- @Override
- public int getChildCount() {
- return mRecView.getAdapter().getItemCount();
- }
-
- @Override
- public int getVisibleChildCount() {
- return mRecView.getChildCount();
- }
-
- @Override
- public int getColumnCount() {
- RecyclerView.LayoutManager layoutManager = mRecView.getLayoutManager();
- if (layoutManager instanceof GridLayoutManager) {
- return ((GridLayoutManager) layoutManager).getSpanCount();
- }
-
- // Otherwise, it is a list with 1 column.
- return 1;
- }
-
- @Override
- public int getHeight() {
- return mRecView.getHeight();
- }
-
- @Override
- public void invalidateView() {
- mRecView.invalidate();
- }
-
- @Override
- public void runAtNextFrame(Runnable r) {
- mRecView.postOnAnimation(r);
- }
-
- @Override
- public void removeCallback(Runnable r) {
- mRecView.removeCallbacks(r);
- }
-
- @Override
- public void scrollBy(int dy) {
- mRecView.scrollBy(0, dy);
- }
-
- @Override
- public void showBand(Rect rect) {
- mBand.setBounds(rect);
-
- if (!mIsOverlayShown) {
- mRecView.getOverlay().add(mBand);
- }
- }
-
- @Override
- public void hideBand() {
- mRecView.getOverlay().remove(mBand);
- }
-
- @Override
- public boolean hasView(int pos) {
- return mRecView.findViewHolderForAdapterPosition(pos) != null;
- }
-} \ No newline at end of file
diff --git a/src/com/android/documentsui/selection/DefaultBandPredicate.java b/src/com/android/documentsui/selection/DefaultBandPredicate.java
deleted file mode 100644
index afbaa3361..000000000
--- a/src/com/android/documentsui/selection/DefaultBandPredicate.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-import static androidx.core.util.Preconditions.checkArgument;
-
-import androidx.annotation.Nullable;
-import android.view.MotionEvent;
-
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
-
-/**
- * BandPredicate that consults ItemDetails, premitting band selection to start
- * when the event is not in the drag region of the item.
- */
-public final class DefaultBandPredicate extends BandPredicate {
-
- private final ItemDetailsLookup mDetailsLookup;
-
- public DefaultBandPredicate(ItemDetailsLookup detailsLookup) {
- checkArgument(detailsLookup != null);
-
- mDetailsLookup = detailsLookup;
- }
-
- @Override
- public boolean canInitiate(MotionEvent e) {
- @Nullable ItemDetails details = mDetailsLookup.getItemDetails(e);
- return (details != null)
- ? !details.inDragRegion(e)
- : true;
- }
-}
diff --git a/src/com/android/documentsui/selection/DefaultSelectionHelper.java b/src/com/android/documentsui/selection/DefaultSelectionHelper.java
deleted file mode 100644
index 0bd45a46e..000000000
--- a/src/com/android/documentsui/selection/DefaultSelectionHelper.java
+++ /dev/null
@@ -1,554 +0,0 @@
-/*
- * Copyright (C) 2015 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.documentsui.selection;
-
-import static androidx.core.util.Preconditions.checkArgument;
-import static androidx.core.util.Preconditions.checkState;
-import static com.android.documentsui.selection.Shared.DEBUG;
-import static com.android.documentsui.selection.Shared.TAG;
-
-import androidx.annotation.IntDef;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.Adapter;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-/**
- * {@link SelectionHelper} providing support traditional multi-item selection on top
- * of {@link RecyclerView}.
- *
- * <p>The class supports running in a single-select mode, which can be enabled
- * by passing {@colde #MODE_SINGLE} to the constructor.
- */
-public final class DefaultSelectionHelper extends SelectionHelper {
-
- public static final int MODE_MULTIPLE = 0;
- public static final int MODE_SINGLE = 1;
-
- @IntDef(flag = true, value = {
- MODE_MULTIPLE,
- MODE_SINGLE
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface SelectionMode {}
-
- private static final int RANGE_REGULAR = 0;
-
- /**
- * "Provisional" selection represents a overlay on the primary selection. A provisional
- * selection maybe be eventually added to the primary selection, or it may be abandoned.
- *
- * <p>E.g. BandController creates a provisional selection while a user is actively selecting
- * items with the band. Provisionally selected items are considered to be selected in
- * {@link Selection#contains(String)} and related methods. A provisional may be abandoned or
- * applied by selection components (like
- * {@link com.android.documentsui.selection.BandSelectionHelper}).
- *
- * <p>A provisional selection may intersect the primary selection, however clearing the
- * provisional selection will not affect the primary selection where the two may intersect.
- */
- private static final int RANGE_PROVISIONAL = 1;
- @IntDef({
- RANGE_REGULAR,
- RANGE_PROVISIONAL
- })
- @Retention(RetentionPolicy.SOURCE)
- @interface RangeType {}
-
- private final Selection mSelection = new Selection();
- private final List<SelectionObserver> mObservers = new ArrayList<>(1);
- private final RecyclerView.Adapter<?> mAdapter;
- private final StableIdProvider mStableIds;
- private final SelectionPredicate mSelectionPredicate;
- private final RecyclerView.AdapterDataObserver mAdapterObserver;
- private final RangeCallbacks mRangeCallbacks;
- private final boolean mSingleSelect;
-
- private @Nullable Range mRange;
-
- /**
- * Creates a new instance.
- *
- * @param mode single or multiple selection mode. In single selection mode
- * users can only select a single item.
- * @param adapter {@link Adapter} for the RecyclerView this instance is coupled with.
- * @param stableIds client supplied class providing access to stable ids.
- * @param selectionPredicate A predicate allowing the client to disallow selection
- * of individual elements.
- */
- public DefaultSelectionHelper(
- @SelectionMode int mode,
- RecyclerView.Adapter<?> adapter,
- StableIdProvider stableIds,
- SelectionPredicate selectionPredicate) {
-
- checkArgument(mode == MODE_SINGLE || mode == MODE_MULTIPLE);
- checkArgument(adapter != null);
- checkArgument(stableIds != null);
- checkArgument(selectionPredicate != null);
-
- mAdapter = adapter;
- mStableIds = stableIds;
- mSelectionPredicate = selectionPredicate;
- mAdapterObserver = new AdapterObserver();
- mRangeCallbacks = new RangeCallbacks();
-
- mSingleSelect = mode == MODE_SINGLE;
-
- mAdapter.registerAdapterDataObserver(mAdapterObserver);
- }
-
- @Override
- public void addObserver(SelectionObserver callback) {
- checkArgument(callback != null);
- mObservers.add(callback);
- }
-
- @Override
- public boolean hasSelection() {
- return !mSelection.isEmpty();
- }
-
- @Override
- public Selection getSelection() {
- return mSelection;
- }
-
- @Override
- public void copySelection(Selection dest) {
- dest.copyFrom(mSelection);
- }
-
- @Override
- public boolean isSelected(String id) {
- return mSelection.contains(id);
- }
-
- @Override
- public void restoreSelection(Selection other) {
- setItemsSelectedQuietly(other.mSelection, true);
- // NOTE: We intentionally don't restore provisional selection. It's provisional.
- notifySelectionRestored();
- }
-
- @Override
- public boolean setItemsSelected(Iterable<String> ids, boolean selected) {
- boolean changed = setItemsSelectedQuietly(ids, selected);
- notifySelectionChanged();
- return changed;
- }
-
- private boolean setItemsSelectedQuietly(Iterable<String> ids, boolean selected) {
- boolean changed = false;
- for (String id: ids) {
- boolean itemChanged = selected
- ? canSetState(id, true) && mSelection.add(id)
- : canSetState(id, false) && mSelection.remove(id);
- if (itemChanged) {
- notifyItemStateChanged(id, selected);
- }
- changed |= itemChanged;
- }
- return changed;
- }
-
- @Override
- public void clearSelection() {
- if (!hasSelection()) {
- return;
- }
-
- Selection prev = clearSelectionQuietly();
- notifySelectionCleared(prev);
- notifySelectionChanged();
- }
-
- /**
- * Clears the selection, without notifying selection listeners.
- * Returns items in previous selection. Callers are responsible for notifying
- * listeners about changes.
- */
- private Selection clearSelectionQuietly() {
- mRange = null;
-
- Selection prevSelection = new Selection();
- if (hasSelection()) {
- copySelection(prevSelection);
- mSelection.clear();
- }
-
- return prevSelection;
- }
-
- @Override
- public boolean select(String id) {
- checkArgument(id != null);
-
- if (!mSelection.contains(id)) {
- if (!canSetState(id, true)) {
- if (DEBUG) Log.d(TAG, "Select cancelled by selection predicate test.");
- return false;
- }
-
- // Enforce single selection policy.
- if (mSingleSelect && hasSelection()) {
- Selection prev = clearSelectionQuietly();
- notifySelectionCleared(prev);
- }
-
- mSelection.add(id);
- notifyItemStateChanged(id, true);
- notifySelectionChanged();
-
- return true;
- }
-
- return false;
- }
-
- @Override
- public boolean deselect(String id) {
- checkArgument(id != null);
-
- if (mSelection.contains(id)) {
- if (!canSetState(id, false)) {
- if (DEBUG) Log.d(TAG, "Deselect cancelled by selection predicate test.");
- return false;
- }
- mSelection.remove(id);
- notifyItemStateChanged(id, false);
- notifySelectionChanged();
- if (mSelection.isEmpty() && isRangeActive()) {
- // if there's nothing in the selection and there is an active ranger it results
- // in unexpected behavior when the user tries to start range selection: the item
- // which the ranger 'thinks' is the already selected anchor becomes unselectable
- endRange();
- }
- return true;
- }
-
- return false;
- }
-
- @Override
- public void startRange(int pos) {
- select(mStableIds.getStableId(pos));
- anchorRange(pos);
- }
-
- @Override
- public void extendRange(int pos) {
- extendRange(pos, RANGE_REGULAR);
- }
-
- @Override
- public void endRange() {
- mRange = null;
- // Clean up in case there was any leftover provisional selection
- clearProvisionalSelection();
- }
-
- @Override
- public void anchorRange(int position) {
- checkArgument(position != RecyclerView.NO_POSITION);
-
- // TODO: I'm not a fan of silently ignoring calls.
- // Determine if there are any cases where method can be called
- // w/o item already being selected. Else, tighten up the ship
- // and make this conditional guard into a proper precondition check.
- if (mSelection.contains(mStableIds.getStableId(position))) {
- mRange = new Range(mRangeCallbacks, position);
- }
- }
-
- @Override
- public void extendProvisionalRange(int pos) {
- extendRange(pos, RANGE_PROVISIONAL);
- }
-
- /**
- * Sets the end point for the current range selection, started by a call to
- * {@link #startRange(int)}. This function should only be called when a range selection
- * is active (see {@link #isRangeActive()}. Items in the range [anchor, end] will be
- * selected or in provisional select, depending on the type supplied. Note that if the type is
- * provisional selection, one should do {@link #mergeProvisionalSelection()} at some
- * point before calling on {@link #endRange()}.
- *
- * @param pos The new end position for the selection range.
- * @param type The type of selection the range should utilize.
- */
- private void extendRange(int pos, @RangeType int type) {
- checkState(isRangeActive(), "Range start point not set.");
-
- mRange.extendSelection(pos, type);
-
- // We're being lazy here notifying even when something might not have changed.
- // To make this more correct, we'd need to update the Ranger class to return
- // information about what has changed.
- notifySelectionChanged();
- }
-
- @Override
- public void setProvisionalSelection(Set<String> newSelection) {
- Map<String, Boolean> delta = mSelection.setProvisionalSelection(newSelection);
- for (Map.Entry<String, Boolean> entry: delta.entrySet()) {
- notifyItemStateChanged(entry.getKey(), entry.getValue());
- }
-
- notifySelectionChanged();
- }
-
- @Override
- public void mergeProvisionalSelection() {
- mSelection.mergeProvisionalSelection();
- }
-
- @Override
- public void clearProvisionalSelection() {
- for (String id : mSelection.mProvisionalSelection) {
- notifyItemStateChanged(id, false);
- }
- mSelection.clearProvisionalSelection();
- }
-
- @Override
- public boolean isRangeActive() {
- return mRange != null;
- }
-
- private boolean canSetState(String id, boolean nextState) {
- return mSelectionPredicate.canSetStateForId(id, nextState);
- }
-
- private void onDataSetChanged() {
- // Update the selection to remove any disappeared IDs.
- mSelection.clearProvisionalSelection();
- mSelection.intersect(mStableIds.getStableIds());
- notifySelectionReset();
-
- for (String id : mSelection) {
- // If the underlying data set has changed, before restoring
- // selection we must re-verify that it can be selected.
- // Why? Because if the dataset has changed, then maybe the
- // selectability of an item has changed.
- if (!canSetState(id, true)) {
- deselect(id);
- } else {
- int lastListener = mObservers.size() - 1;
- for (int i = lastListener; i >= 0; i--) {
- mObservers.get(i).onItemStateChanged(id, true);
- }
- }
- }
- notifySelectionChanged();
- }
-
- private void onDataSetItemRangeInserted(int startPosition, int itemCount) {
- mSelection.clearProvisionalSelection();
- }
-
- private void onDataSetItemRangeRemoved(int startPosition, int itemCount) {
- checkArgument(startPosition >= 0);
- checkArgument(itemCount > 0);
-
- mSelection.clearProvisionalSelection();
-
- // Remove any disappeared IDs from the selection.
- //
- // Ideally there could be a cheaper approach, checking
- // each position individually, but since the source of
- // truth for stable ids (StableIdProvider) probably
- // it-self no-longer knows about the positions in question
- // we fall back to the sledge hammer approach.
- mSelection.intersect(mStableIds.getStableIds());
- }
-
- /**
- * Notifies registered listeners when the selection status of a single item
- * (identified by {@code position}) changes.
- */
- private void notifyItemStateChanged(String id, boolean selected) {
- checkArgument(id != null);
-
- int lastListenerIndex = mObservers.size() - 1;
- for (int i = lastListenerIndex; i >= 0; i--) {
- mObservers.get(i).onItemStateChanged(id, selected);
- }
-
- int position = mStableIds.getPosition(id);
- if (DEBUG) Log.d(TAG, "ITEM " + id + " CHANGED at pos: " + position);
-
- if (position >= 0) {
- mAdapter.notifyItemChanged(position, SelectionHelper.SELECTION_CHANGED_MARKER);
- } else {
- Log.w(TAG, "Item change notification received for unknown item: " + id);
- }
- }
-
- private void notifySelectionCleared(Selection selection) {
- for (String id: selection.mSelection) {
- notifyItemStateChanged(id, false);
- }
- for (String id: selection.mProvisionalSelection) {
- notifyItemStateChanged(id, false);
- }
- }
-
- /**
- * Notifies registered listeners when the selection has changed. This
- * notification should be sent only once a full series of changes
- * is complete, e.g. clearingSelection, or updating the single
- * selection from one item to another.
- */
- private void notifySelectionChanged() {
- int lastListenerIndex = mObservers.size() - 1;
- for (int i = lastListenerIndex; i >= 0; i--) {
- mObservers.get(i).onSelectionChanged();
- }
- }
-
- private void notifySelectionRestored() {
- int lastListenerIndex = mObservers.size() - 1;
- for (int i = lastListenerIndex; i >= 0; i--) {
- mObservers.get(i).onSelectionRestored();
- }
- }
-
- private void notifySelectionReset() {
- int lastListenerIndex = mObservers.size() - 1;
- for (int i = lastListenerIndex; i >= 0; i--) {
- mObservers.get(i).onSelectionReset();
- }
- }
-
- private void updateForRange(int begin, int end, boolean selected, @RangeType int type) {
- switch (type) {
- case RANGE_REGULAR:
- updateForRegularRange(begin, end, selected);
- break;
- case RANGE_PROVISIONAL:
- updateForProvisionalRange(begin, end, selected);
- break;
- default:
- throw new IllegalArgumentException("Invalid range type: " + type);
- }
- }
-
- private void updateForRegularRange(int begin, int end, boolean selected) {
- checkArgument(end >= begin);
-
- for (int i = begin; i <= end; i++) {
- String id = mStableIds.getStableId(i);
- if (id == null) {
- continue;
- }
-
- if (selected) {
- select(id);
- } else {
- deselect(id);
- }
- }
- }
-
- private void updateForProvisionalRange(int begin, int end, boolean selected) {
- checkArgument(end >= begin);
-
- for (int i = begin; i <= end; i++) {
- String id = mStableIds.getStableId(i);
- if (id == null) {
- continue;
- }
-
- boolean changedState = false;
- if (selected) {
- boolean canSelect = canSetState(id, true);
- if (canSelect && !mSelection.mSelection.contains(id)) {
- mSelection.mProvisionalSelection.add(id);
- changedState = true;
- }
- } else {
- mSelection.mProvisionalSelection.remove(id);
- changedState = true;
- }
-
- // Only notify item callbacks when something's state is actually changed in provisional
- // selection.
- if (changedState) {
- notifyItemStateChanged(id, selected);
- }
- }
-
- notifySelectionChanged();
- }
-
- private final class AdapterObserver extends RecyclerView.AdapterDataObserver {
- @Override
- public void onChanged() {
- onDataSetChanged();
- }
-
- @Override
- public void onItemRangeChanged(
- int startPosition, int itemCount, Object payload) {
- // No change in position. Ignore, since we assume
- // selection is a user driven activity. So changes
- // in properties of items shouldn't result in a
- // change of selection.
- }
-
- @Override
- public void onItemRangeInserted(int startPosition, int itemCount) {
- onDataSetItemRangeInserted(startPosition, itemCount);
- }
-
- @Override
- public void onItemRangeRemoved(int startPosition, int itemCount) {
- onDataSetItemRangeRemoved(startPosition, itemCount);
- }
-
- @Override
- public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
- throw new UnsupportedOperationException();
- }
- }
-
- private final class RangeCallbacks extends Range.Callbacks {
- @Override
- void updateForRange(int begin, int end, boolean selected, int type) {
- switch (type) {
- case RANGE_REGULAR:
- updateForRegularRange(begin, end, selected);
- break;
- case RANGE_PROVISIONAL:
- updateForProvisionalRange(begin, end, selected);
- break;
- default:
- throw new IllegalArgumentException(
- "Invalid range type: " + type);
- }
- }
- }
-}
diff --git a/src/com/android/documentsui/selection/GestureRouter.java b/src/com/android/documentsui/selection/GestureRouter.java
deleted file mode 100644
index be143c45b..000000000
--- a/src/com/android/documentsui/selection/GestureRouter.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static androidx.core.util.Preconditions.checkNotNull;
-
-import androidx.annotation.Nullable;
-import android.view.GestureDetector.OnDoubleTapListener;
-import android.view.GestureDetector.OnGestureListener;
-import android.view.GestureDetector.SimpleOnGestureListener;
-import android.view.MotionEvent;
-
-/**
- * GestureRouter is responsible for routing gestures detected by a GestureDetector
- * to registered handlers. The primary function is to divide events by tool-type
- * allowing handlers to cleanly implement tool-type specific policies.
- */
-public final class GestureRouter<T extends OnGestureListener & OnDoubleTapListener>
- implements OnGestureListener, OnDoubleTapListener {
-
- private final ToolHandlerRegistry<T> mDelegates;
-
- public GestureRouter(T defaultDelegate) {
- checkNotNull(defaultDelegate);
- mDelegates = new ToolHandlerRegistry<>(defaultDelegate);
- }
-
- public GestureRouter() {
- this((T) new SimpleOnGestureListener());
- }
-
- /**
- * @param toolType
- * @param delegate the delegate, or null to unregister.
- */
- public void register(int toolType, @Nullable T delegate) {
- mDelegates.set(toolType, delegate);
- }
-
- @Override
- public boolean onSingleTapConfirmed(MotionEvent e) {
- return mDelegates.get(e).onSingleTapConfirmed(e);
- }
-
- @Override
- public boolean onDoubleTap(MotionEvent e) {
- return mDelegates.get(e).onDoubleTap(e);
- }
-
- @Override
- public boolean onDoubleTapEvent(MotionEvent e) {
- return mDelegates.get(e).onDoubleTapEvent(e);
- }
-
- @Override
- public boolean onDown(MotionEvent e) {
- return mDelegates.get(e).onDown(e);
- }
-
- @Override
- public void onShowPress(MotionEvent e) {
- mDelegates.get(e).onShowPress(e);
- }
-
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- return mDelegates.get(e).onSingleTapUp(e);
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- return mDelegates.get(e2).onScroll(e1, e2, distanceX, distanceY);
- }
-
- @Override
- public void onLongPress(MotionEvent e) {
- mDelegates.get(e).onLongPress(e);
- }
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- return mDelegates.get(e2).onFling(e1, e2, velocityX, velocityY);
- }
-}
diff --git a/src/com/android/documentsui/selection/GestureSelectionHelper.java b/src/com/android/documentsui/selection/GestureSelectionHelper.java
deleted file mode 100644
index 21f9b09ef..000000000
--- a/src/com/android/documentsui/selection/GestureSelectionHelper.java
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static androidx.core.util.Preconditions.checkArgument;
-import static androidx.core.util.Preconditions.checkState;
-
-import android.graphics.Point;
-import android.os.Build;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
-
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-
-import com.android.documentsui.selection.ViewAutoScroller.ScrollHost;
-import com.android.documentsui.selection.ViewAutoScroller.ScrollerCallbacks;
-
-/**
- * GestureSelectionHelper provides logic that interprets a combination
- * of motions and gestures in order to provide gesture driven selection support
- * when used in conjunction with RecyclerView and other classes in the ReyclerView
- * selection support package.
- */
-public final class GestureSelectionHelper extends ScrollHost implements OnItemTouchListener {
-
- private static final String TAG = "GestureSelectionHelper";
-
- private final SelectionHelper mSelectionMgr;
- private final Runnable mScroller;
- private final ViewDelegate mView;
- private final ContentLock mLock;
- private final ItemDetailsLookup mItemLookup;
-
- private int mLastTouchedItemPosition = RecyclerView.NO_POSITION;
- private boolean mStarted = false;
- private Point mLastInterceptedPoint;
-
- /**
- * See {@link #create(SelectionHelper, RecyclerView, ContentLock)} for convenience
- * method.
- */
- @VisibleForTesting
- GestureSelectionHelper(
- SelectionHelper selectionHelper,
- ViewDelegate view,
- ContentLock lock,
- ItemDetailsLookup itemLookup) {
-
- checkArgument(selectionHelper != null);
- checkArgument(view != null);
- checkArgument(lock != null);
- checkArgument(itemLookup != null);
-
- mSelectionMgr = selectionHelper;
- mView = view;
- mLock = lock;
- mItemLookup = itemLookup;
-
- mScroller = new ViewAutoScroller(this, mView);
- }
-
- /**
- * Explicitly kicks off a gesture multi-select.
- *
- * @return true if started.
- */
- public 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 (mLastTouchedItemPosition == 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
- // start being called.
- // Verify the truth of that statement here
- // to make the implicit coupling less of a time bomb.
- checkState(mSelectionMgr.isRangeActive());
-
- mLock.checkUnlocked();
-
- mStarted = true;
- mLock.block();
- }
-
- @Override
- public boolean onInterceptTouchEvent(RecyclerView unused, 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 (mItemLookup.getItemDetails(e) != null) {
- mLastTouchedItemPosition = mView.getItemUnder(e);
- }
- }
-
- // See handleTouch(MotionEvent) javadoc for explanation as to why this is correct.
- return handleTouch(e);
- }
-
- @Override
- /** @hide */
- public void onTouchEvent(@NonNull RecyclerView unused, @NonNull MotionEvent e) {
- // See handleTouch(MotionEvent) javadoc for explanation as to why this is correct.
- handleTouch(e);
- }
-
- /**
- * If selection has started, will handle all appropriate types of MotionEvents and will return
- * true if this OnItemTouchListener should start intercepting the rest of the MotionEvents.
- *
- * <p>This code, and the fact that this method is used by both OnInterceptTouchEvent and
- * OnTouchEvent, is correct and valid because:
- * <ol>
- * <li>MotionEvents that aren't ACTION_DOWN are only ever passed to either onInterceptTouchEvent
- * or onTouchEvent; never to both. The MotionEvents we are handling in this method are not
- * ACTION_DOWN, and therefore, its appropriate that both the onInterceptTouchEvent and
- * onTouchEvent code paths cross this method.
- * <li>This method returns true when we want to intercept MotionEvents. OnInterceptTouchEvent
- * uses that information to determine its own return, and OnMotionEvent doesn't have a return
- * so this methods return value is irrelevant to it.
- * </ol>
- */
- private boolean handleTouch(MotionEvent e) {
- if (!mStarted) {
- return false;
- }
-
- switch (e.getActionMasked()) {
- case MotionEvent.ACTION_MOVE:
- handleMoveEvent(e);
- return true;
- case MotionEvent.ACTION_UP:
- handleUpEvent();
- return true;
- case MotionEvent.ACTION_CANCEL:
- handleCancelEvent();
- return true;
- }
-
- return false;
- }
-
- @Override
- public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
- }
-
- // Called when ACTION_UP event is to be handled.
- // Essentially, since this means all gesture movement is over, reset everything and apply
- // provisional selection.
- private void handleUpEvent() {
- mSelectionMgr.mergeProvisionalSelection();
- endSelection();
- if (mLastTouchedItemPosition != RecyclerView.NO_POSITION) {
- mSelectionMgr.startRange(mLastTouchedItemPosition);
- }
- }
-
- // Called when ACTION_CANCEL event is to be handled.
- // This means this gesture selection is aborted, so reset everything and abandon provisional
- // selection.
- private void handleCancelEvent() {
- mSelectionMgr.clearProvisionalSelection();
- endSelection();
- }
-
- private void endSelection() {
- checkState(mStarted);
-
- mLastTouchedItemPosition = RecyclerView.NO_POSITION;
- mStarted = false;
- mLock.unblock();
- }
-
- // 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(MotionEvent e) {
- mLastInterceptedPoint = MotionEvents.getOrigin(e);
-
- int lastGlidedItemPos = mView.getLastGlidedItemPosition(e);
- if (lastGlidedItemPos != RecyclerView.NO_POSITION) {
- doGestureMultiSelect(lastGlidedItemPos);
- }
- scrollIfNecessary();
- }
-
- // It's possible for events to go over the top/bottom of the RecyclerView.
- // We want to get a Y-coordinate within the RecyclerView so we can find the childView underneath
- // correctly.
- private static float getInboundY(float max, float y) {
- if (y < 0f) {
- return 0f;
- } else if (y > max) {
- return max;
- }
- return y;
- }
-
- /* Given the end position, select everything in-between.
- * @param endPos The adapter position of the end item.
- */
- private void doGestureMultiSelect(int endPos) {
- mSelectionMgr.extendProvisionalRange(endPos);
- }
-
- private void scrollIfNecessary() {
- mScroller.run();
- }
-
- @Override
- public Point getCurrentPosition() {
- return mLastInterceptedPoint;
- }
-
- @Override
- public int getViewHeight() {
- return mView.getHeight();
- }
-
- @Override
- public boolean isActive() {
- return mStarted && mSelectionMgr.hasSelection();
- }
-
- /**
- * Returns a new instance of GestureSelectionHelper, wrapping the
- * RecyclerView in a test friendly wrapper.
- */
- public static GestureSelectionHelper create(
- SelectionHelper selectionMgr,
- RecyclerView recycler,
- ContentLock lock,
- ItemDetailsLookup itemLookup) {
-
- return new GestureSelectionHelper(
- selectionMgr, new RecyclerViewDelegate(recycler), lock, itemLookup);
- }
-
- @VisibleForTesting
- static abstract class ViewDelegate extends ScrollerCallbacks {
- abstract int getHeight();
-
- abstract int getItemUnder(MotionEvent e);
-
- abstract int getLastGlidedItemPosition(MotionEvent e);
- }
-
- @VisibleForTesting
- static final class RecyclerViewDelegate extends ViewDelegate {
-
- private final RecyclerView mView;
-
- RecyclerViewDelegate(RecyclerView view) {
- checkArgument(view != null);
- mView = view;
- }
-
- @Override
- int getHeight() {
- return mView.getHeight();
- }
-
- @Override
- int getItemUnder(MotionEvent e) {
- View child = mView.findChildViewUnder(e.getX(), e.getY());
- return child != null
- ? mView.getChildAdapterPosition(child)
- : RecyclerView.NO_POSITION;
- }
-
- @Override
- int getLastGlidedItemPosition(MotionEvent e) {
- // If user has moved his pointer to the bottom-right empty pane (ie. to the right of the
- // last item of the recycler view), we would want to set that as the currentItemPos
- View lastItem = mView.getLayoutManager()
- .getChildAt(mView.getLayoutManager().getChildCount() - 1);
- int direction =
- mView.getContext().getResources().getConfiguration().getLayoutDirection();
- final boolean pastLastItem = isPastLastItem(lastItem.getTop(),
- lastItem.getLeft(),
- lastItem.getRight(),
- e,
- direction);
-
- // Since views get attached & detached from RecyclerView,
- // {@link LayoutManager#getChildCount} can return a different number from the actual
- // number
- // of items in the adapter. Using the adapter is the for sure way to get the actual last
- // item position.
- final float inboundY = getInboundY(mView.getHeight(), e.getY());
- return (pastLastItem) ? mView.getAdapter().getItemCount() - 1
- : mView.getChildAdapterPosition(mView.findChildViewUnder(e.getX(), inboundY));
- }
-
- /*
- * Check to see if MotionEvent if past a particular item, i.e. to the right or to the bottom
- * of the item.
- * For RTL, it would to be to the left or to the bottom of the item.
- */
- @VisibleForTesting
- static boolean isPastLastItem(int top, int left, int right, MotionEvent e, int direction) {
- if (direction == View.LAYOUT_DIRECTION_LTR) {
- return e.getX() > right && e.getY() > top;
- } else {
- return e.getX() < left && e.getY() > top;
- }
- }
-
- @Override
- public void scrollBy(int dy) {
- mView.scrollBy(0, dy);
- }
-
- @Override
- public void runAtNextFrame(Runnable r) {
- mView.postOnAnimation(r);
- }
-
- @Override
- public void removeCallback(Runnable r) {
- mView.removeCallbacks(r);
- }
- }
-}
diff --git a/src/com/android/documentsui/selection/GridModel.java b/src/com/android/documentsui/selection/GridModel.java
deleted file mode 100644
index feca271ab..000000000
--- a/src/com/android/documentsui/selection/GridModel.java
+++ /dev/null
@@ -1,728 +0,0 @@
-/*
- * Copyright (C) 2015 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.documentsui.selection;
-
-import static androidx.core.util.Preconditions.checkArgument;
-import static com.android.documentsui.base.SharedMinimal.DEBUG;
-
-import android.graphics.Point;
-import android.graphics.Rect;
-import androidx.annotation.VisibleForTesting;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
-
-import com.android.documentsui.selection.BandSelectionHelper.BandHost;
-import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
-import com.android.documentsui.selection.SelectionHelper.StableIdProvider;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Provides a band selection item model for views within a RecyclerView. This class queries the
- * RecyclerView to determine where its items are placed; then, once band selection is underway,
- * it alerts listeners of which items are covered by the selections.
- */
-final class GridModel {
-
- // Magical value indicating that a value has not been previously set. primitive null :)
- static final int NOT_SET = -1;
-
- // Enum values used to determine the corner at which the origin is located within the
- private static final int UPPER = 0x00;
- private static final int LOWER = 0x01;
- private static final int LEFT = 0x00;
- private static final int RIGHT = 0x02;
- private static final int UPPER_LEFT = UPPER | LEFT;
- private static final int UPPER_RIGHT = UPPER | RIGHT;
- private static final int LOWER_LEFT = LOWER | LEFT;
- private static final int LOWER_RIGHT = LOWER | RIGHT;
-
- private final BandHost mHost;
- private final StableIdProvider mStableIds;
- private final SelectionPredicate mSelectionPredicate;
-
- private final List<SelectionObserver> mOnSelectionChangedListeners =
- new ArrayList<>();
-
- // Map from the x-value of the left side of a SparseBooleanArray of adapter positions, keyed
- // by their y-offset. For example, if the first column of the view starts at an x-value of 5,
- // mColumns.get(5) would return an array of positions in that column. Within that array, the
- // value for key y is the adapter position for the item whose y-offset is y.
- private final SparseArray<SparseIntArray> mColumns = new SparseArray<>();
-
- // List of limits along the x-axis (columns).
- // This list is sorted from furthest left to furthest right.
- private final List<Limits> mColumnBounds = new ArrayList<>();
-
- // List of limits along the y-axis (rows). Note that this list only contains items which
- // have been in the viewport.
- private final List<Limits> mRowBounds = new ArrayList<>();
-
- // The adapter positions which have been recorded so far.
- private final SparseBooleanArray mKnownPositions = new SparseBooleanArray();
-
- // Array passed to registered OnSelectionChangedListeners. One array is created and reused
- // throughout the lifetime of the object.
- private final Set<String> mSelection = new HashSet<>();
-
- // The current pointer (in absolute positioning from the top of the view).
- private Point mPointer = null;
-
- // The bounds of the band selection.
- private RelativePoint mRelativeOrigin;
- private RelativePoint mRelativePointer;
-
- private boolean mIsActive;
-
- // Tracks where the band select originated from. This is used to determine where selections
- // should expand from when Shift+click is used.
- private int mPositionNearestOrigin = NOT_SET;
-
- private final OnScrollListener mScrollListener;
-
- GridModel(
- BandHost host,
- StableIdProvider stableIds,
- SelectionPredicate selectionPredicate) {
-
- mHost = host;
- mStableIds = stableIds;
- mSelectionPredicate = selectionPredicate;
-
- mScrollListener = new OnScrollListener() {
- @Override
- public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
- GridModel.this.onScrolled(recyclerView, dx, dy);
- }
- };
-
- mHost.addOnScrollListener(mScrollListener);
- }
-
- /**
- * Stops listening to the view's scrolls. Call this function before discarding a
- * GridModel object to prevent memory leaks.
- */
- void stopListening() {
- mHost.removeOnScrollListener(mScrollListener);
- }
-
- /**
- * Start a band select operation at the given point.
- * @param relativeOrigin The origin of the band select operation, relative to the viewport.
- * For example, if the view is scrolled to the bottom, the top-left of the viewport
- * would have a relative origin of (0, 0), even though its absolute point has a higher
- * y-value.
- */
- void startCapturing(Point relativeOrigin) {
- recordVisibleChildren();
- if (isEmpty()) {
- // The selection band logic works only if there is at least one visible child.
- return;
- }
-
- mIsActive = true;
- mPointer = mHost.createAbsolutePoint(relativeOrigin);
- mRelativeOrigin = new RelativePoint(mPointer);
- mRelativePointer = new RelativePoint(mPointer);
- computeCurrentSelection();
- notifySelectionChanged();
- }
-
- /**
- * Ends the band selection.
- */
- void stopCapturing() {
- mIsActive = false;
- }
-
- /**
- * Resizes the selection by adjusting the pointer (i.e., the corner of the selection
- * opposite the origin.
- * @param relativePointer The pointer (opposite of the origin) of the band select operation,
- * relative to the viewport. For example, if the view is scrolled to the bottom, the
- * top-left of the viewport would have a relative origin of (0, 0), even though its
- * absolute point has a higher y-value.
- */
- @VisibleForTesting
- void resizeSelection(Point relativePointer) {
- mPointer = mHost.createAbsolutePoint(relativePointer);
- updateModel();
- }
-
- /**
- * @return The adapter position for the item nearest the origin corresponding to the latest
- * band select operation, or NOT_SET if the selection did not cover any items.
- */
- int getPositionNearestOrigin() {
- return mPositionNearestOrigin;
- }
-
- private void onScrolled(RecyclerView recyclerView, int dx, int dy) {
- if (!mIsActive) {
- return;
- }
-
- mPointer.x += dx;
- mPointer.y += dy;
- recordVisibleChildren();
- updateModel();
- }
-
- /**
- * Queries the view for all children and records their location metadata.
- */
- private void recordVisibleChildren() {
- for (int i = 0; i < mHost.getVisibleChildCount(); i++) {
- int adapterPosition = mHost.getAdapterPositionAt(i);
- // Sometimes the view is not attached, as we notify the multi selection manager
- // synchronously, while views are attached asynchronously. As a result items which
- // are in the adapter may not actually have a corresponding view (yet).
- if (mHost.hasView(adapterPosition) &&
- mSelectionPredicate.canSetStateAtPosition(adapterPosition, true) &&
- !mKnownPositions.get(adapterPosition)) {
- mKnownPositions.put(adapterPosition, true);
- recordItemData(mHost.getAbsoluteRectForChildViewAt(i), adapterPosition);
- }
- }
- }
-
- /**
- * Checks if there are any recorded children.
- */
- private boolean isEmpty() {
- return mColumnBounds.size() == 0 || mRowBounds.size() == 0;
- }
-
- /**
- * Updates the limits lists and column map with the given item metadata.
- * @param absoluteChildRect The absolute rectangle for the child view being processed.
- * @param adapterPosition The position of the child view being processed.
- */
- private void recordItemData(Rect absoluteChildRect, int adapterPosition) {
- if (mColumnBounds.size() != mHost.getColumnCount()) {
- // If not all x-limits have been recorded, record this one.
- recordLimits(
- mColumnBounds, new Limits(absoluteChildRect.left, absoluteChildRect.right));
- }
-
- recordLimits(mRowBounds, new Limits(absoluteChildRect.top, absoluteChildRect.bottom));
-
- SparseIntArray columnList = mColumns.get(absoluteChildRect.left);
- if (columnList == null) {
- columnList = new SparseIntArray();
- mColumns.put(absoluteChildRect.left, columnList);
- }
- columnList.put(absoluteChildRect.top, adapterPosition);
- }
-
- /**
- * Ensures limits exists within the sorted list limitsList, and adds it to the list if it
- * does not exist.
- */
- private void recordLimits(List<Limits> limitsList, Limits limits) {
- int index = Collections.binarySearch(limitsList, limits);
- if (index < 0) {
- limitsList.add(~index, limits);
- }
- }
-
- /**
- * Handles a moved pointer; this function determines whether the pointer movement resulted
- * in a selection change and, if it has, notifies listeners of this change.
- */
- private void updateModel() {
- RelativePoint old = mRelativePointer;
- mRelativePointer = new RelativePoint(mPointer);
- if (old != null && mRelativePointer.equals(old)) {
- return;
- }
-
- computeCurrentSelection();
- notifySelectionChanged();
- }
-
- /**
- * Computes the currently-selected items.
- */
- private void computeCurrentSelection() {
- if (areItemsCoveredByBand(mRelativePointer, mRelativeOrigin)) {
- updateSelection(computeBounds());
- } else {
- mSelection.clear();
- mPositionNearestOrigin = NOT_SET;
- }
- }
-
- /**
- * Notifies all listeners of a selection change. Note that this function simply passes
- * mSelection, so computeCurrentSelection() should be called before this
- * function.
- */
- private void notifySelectionChanged() {
- for (SelectionObserver listener : mOnSelectionChangedListeners) {
- listener.onSelectionChanged(mSelection);
- }
- }
-
- /**
- * @param rect Rectangle including all covered items.
- */
- private void updateSelection(Rect rect) {
- int columnStart =
- Collections.binarySearch(mColumnBounds, new Limits(rect.left, rect.left));
-
- checkArgument(columnStart >= 0, "Rect doesn't intesect any known column.");
-
- int columnEnd = columnStart;
-
- for (int i = columnStart; i < mColumnBounds.size()
- && mColumnBounds.get(i).lowerLimit <= rect.right; i++) {
- columnEnd = i;
- }
-
- int rowStart = Collections.binarySearch(mRowBounds, new Limits(rect.top, rect.top));
- if (rowStart < 0) {
- mPositionNearestOrigin = NOT_SET;
- return;
- }
-
- int rowEnd = rowStart;
- for (int i = rowStart; i < mRowBounds.size()
- && mRowBounds.get(i).lowerLimit <= rect.bottom; i++) {
- rowEnd = i;
- }
-
- updateSelection(columnStart, columnEnd, rowStart, rowEnd);
- }
-
- /**
- * Computes the selection given the previously-computed start- and end-indices for each
- * row and column.
- */
- private void updateSelection(
- int columnStartIndex, int columnEndIndex, int rowStartIndex, int rowEndIndex) {
-
- if (DEBUG) {
- Log.d(BandSelectionHelper.TAG, String.format(
- "updateSelection: %d, %d, %d, %d",
- columnStartIndex, columnEndIndex, rowStartIndex, rowEndIndex));
- }
-
- mSelection.clear();
- for (int column = columnStartIndex; column <= columnEndIndex; column++) {
- SparseIntArray items = mColumns.get(mColumnBounds.get(column).lowerLimit);
- for (int row = rowStartIndex; row <= rowEndIndex; row++) {
- // The default return value for SparseIntArray.get is 0, which is a valid
- // position. Use a sentry value to prevent erroneously selecting item 0.
- final int rowKey = mRowBounds.get(row).lowerLimit;
- int position = items.get(rowKey, NOT_SET);
- if (position != NOT_SET) {
- String id = mStableIds.getStableId(position);
- if (id != null) {
- // The adapter inserts items for UI layout purposes that aren't
- // associated with files. Those will have a null model ID.
- // Don't select them.
- if (canSelect(id)) {
- mSelection.add(id);
- }
- }
- if (isPossiblePositionNearestOrigin(column, columnStartIndex, columnEndIndex,
- row, rowStartIndex, rowEndIndex)) {
- // If this is the position nearest the origin, record it now so that it
- // can be returned by endSelection() later.
- mPositionNearestOrigin = position;
- }
- }
- }
- }
- }
-
- private boolean canSelect(String id) {
- return mSelectionPredicate.canSetStateForId(id, true);
- }
-
- /**
- * @return Returns true if the position is the nearest to the origin, or, in the case of the
- * lower-right corner, whether it is possible that the position is the nearest to the
- * origin. See comment below for reasoning for this special case.
- */
- private boolean isPossiblePositionNearestOrigin(int columnIndex, int columnStartIndex,
- int columnEndIndex, int rowIndex, int rowStartIndex, int rowEndIndex) {
- int corner = computeCornerNearestOrigin();
- switch (corner) {
- case UPPER_LEFT:
- return columnIndex == columnStartIndex && rowIndex == rowStartIndex;
- case UPPER_RIGHT:
- return columnIndex == columnEndIndex && rowIndex == rowStartIndex;
- case LOWER_LEFT:
- return columnIndex == columnStartIndex && rowIndex == rowEndIndex;
- case LOWER_RIGHT:
- // Note that in some cases, the last row will not have as many items as there
- // are columns (e.g., if there are 4 items and 3 columns, the second row will
- // only have one item in the first column). This function is invoked for each
- // position from left to right, so return true for any position in the bottom
- // row and only the right-most position in the bottom row will be recorded.
- return rowIndex == rowEndIndex;
- default:
- throw new RuntimeException("Invalid corner type.");
- }
- }
-
- /**
- * Listener for changes in which items have been band selected.
- */
- public static abstract class SelectionObserver {
- abstract void onSelectionChanged(Set<String> updatedSelection);
- }
-
- void addOnSelectionChangedListener(SelectionObserver listener) {
- mOnSelectionChangedListeners.add(listener);
- }
-
- /**
- * Called when {@link BandSelectionHelper} is finished with a GridModel.
- */
- void onDestroy() {
- mOnSelectionChangedListeners.clear();
- stopListening();
- }
-
- /**
- * Limits of a view item. For example, if an item's left side is at x-value 5 and its right side
- * is at x-value 10, the limits would be from 5 to 10. Used to record the left- and right sides
- * of item columns and the top- and bottom sides of item rows so that it can be determined
- * whether the pointer is located within the bounds of an item.
- */
- private static class Limits implements Comparable<Limits> {
- int lowerLimit;
- int upperLimit;
-
- Limits(int lowerLimit, int upperLimit) {
- this.lowerLimit = lowerLimit;
- this.upperLimit = upperLimit;
- }
-
- @Override
- public int compareTo(Limits other) {
- return lowerLimit - other.lowerLimit;
- }
-
- @Override
- public int hashCode() {
- return lowerLimit ^ upperLimit;
- }
-
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof Limits)) {
- return false;
- }
-
- return ((Limits) other).lowerLimit == lowerLimit &&
- ((Limits) other).upperLimit == upperLimit;
- }
-
- @Override
- public String toString() {
- return "(" + lowerLimit + ", " + upperLimit + ")";
- }
- }
-
- /**
- * The location of a coordinate relative to items. This class represents a general area of the
- * view as it relates to band selection rather than an explicit point. For example, two
- * different points within an item are considered to have the same "location" because band
- * selection originating within the item would select the same items no matter which point
- * was used. Same goes for points between items as well as those at the very beginning or end
- * of the view.
- *
- * Tracking a coordinate (e.g., an x-value) as a CoordinateLocation instead of as an int has the
- * advantage of tying the value to the Limits of items along that axis. This allows easy
- * selection of items within those Limits as opposed to a search through every item to see if a
- * given coordinate value falls within those Limits.
- */
- private static class RelativeCoordinate
- implements Comparable<RelativeCoordinate> {
- /**
- * Location describing points after the last known item.
- */
- static final int AFTER_LAST_ITEM = 0;
-
- /**
- * Location describing points before the first known item.
- */
- static final int BEFORE_FIRST_ITEM = 1;
-
- /**
- * Location describing points between two items.
- */
- static final int BETWEEN_TWO_ITEMS = 2;
-
- /**
- * Location describing points within the limits of one item.
- */
- static final int WITHIN_LIMITS = 3;
-
- /**
- * The type of this coordinate, which is one of AFTER_LAST_ITEM, BEFORE_FIRST_ITEM,
- * BETWEEN_TWO_ITEMS, or WITHIN_LIMITS.
- */
- final int type;
-
- /**
- * The limits before the coordinate; only populated when type == WITHIN_LIMITS or type ==
- * BETWEEN_TWO_ITEMS.
- */
- Limits limitsBeforeCoordinate;
-
- /**
- * The limits after the coordinate; only populated when type == BETWEEN_TWO_ITEMS.
- */
- Limits limitsAfterCoordinate;
-
- // Limits of the first known item; only populated when type == BEFORE_FIRST_ITEM.
- Limits mFirstKnownItem;
- // Limits of the last known item; only populated when type == AFTER_LAST_ITEM.
- Limits mLastKnownItem;
-
- /**
- * @param limitsList The sorted limits list for the coordinate type. If this
- * CoordinateLocation is an x-value, mXLimitsList should be passed; otherwise,
- * mYLimitsList should be pased.
- * @param value The coordinate value.
- */
- RelativeCoordinate(List<Limits> limitsList, int value) {
- int index = Collections.binarySearch(limitsList, new Limits(value, value));
-
- if (index >= 0) {
- this.type = WITHIN_LIMITS;
- this.limitsBeforeCoordinate = limitsList.get(index);
- } else if (~index == 0) {
- this.type = BEFORE_FIRST_ITEM;
- this.mFirstKnownItem = limitsList.get(0);
- } else if (~index == limitsList.size()) {
- Limits lastLimits = limitsList.get(limitsList.size() - 1);
- if (lastLimits.lowerLimit <= value && value <= lastLimits.upperLimit) {
- this.type = WITHIN_LIMITS;
- this.limitsBeforeCoordinate = lastLimits;
- } else {
- this.type = AFTER_LAST_ITEM;
- this.mLastKnownItem = lastLimits;
- }
- } else {
- Limits limitsBeforeIndex = limitsList.get(~index - 1);
- if (limitsBeforeIndex.lowerLimit <= value
- && value <= limitsBeforeIndex.upperLimit) {
- this.type = WITHIN_LIMITS;
- this.limitsBeforeCoordinate = limitsList.get(~index - 1);
- } else {
- this.type = BETWEEN_TWO_ITEMS;
- this.limitsBeforeCoordinate = limitsList.get(~index - 1);
- this.limitsAfterCoordinate = limitsList.get(~index);
- }
- }
- }
-
- int toComparisonValue() {
- if (type == BEFORE_FIRST_ITEM) {
- return mFirstKnownItem.lowerLimit - 1;
- } else if (type == AFTER_LAST_ITEM) {
- return mLastKnownItem.upperLimit + 1;
- } else if (type == BETWEEN_TWO_ITEMS) {
- return limitsBeforeCoordinate.upperLimit + 1;
- } else {
- return limitsBeforeCoordinate.lowerLimit;
- }
- }
-
- @Override
- public int hashCode() {
- return mFirstKnownItem.lowerLimit
- ^ mLastKnownItem.upperLimit
- ^ limitsBeforeCoordinate.upperLimit
- ^ limitsBeforeCoordinate.lowerLimit;
- }
-
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof RelativeCoordinate)) {
- return false;
- }
-
- RelativeCoordinate otherCoordinate = (RelativeCoordinate) other;
- return toComparisonValue() == otherCoordinate.toComparisonValue();
- }
-
- @Override
- public int compareTo(RelativeCoordinate other) {
- return toComparisonValue() - other.toComparisonValue();
- }
- }
-
- /**
- * The location of a point relative to the Limits of nearby items; consists of both an x- and
- * y-RelativeCoordinateLocation.
- */
- private class RelativePoint {
- final RelativeCoordinate xLocation;
- final RelativeCoordinate yLocation;
-
- RelativePoint(Point point) {
- this.xLocation = new RelativeCoordinate(mColumnBounds, point.x);
- this.yLocation = new RelativeCoordinate(mRowBounds, point.y);
- }
-
- @Override
- public int hashCode() {
- return xLocation.toComparisonValue()
- ^ yLocation.toComparisonValue();
- }
-
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof RelativePoint)) {
- return false;
- }
-
- RelativePoint otherPoint = (RelativePoint) other;
- return xLocation.equals(otherPoint.xLocation) && yLocation.equals(otherPoint.yLocation);
- }
- }
-
- /**
- * Generates a rectangle which contains the items selected by the pointer and origin.
- * @return The rectangle, or null if no items were selected.
- */
- private Rect computeBounds() {
- Rect rect = new Rect();
- rect.left = getCoordinateValue(
- min(mRelativeOrigin.xLocation, mRelativePointer.xLocation),
- mColumnBounds,
- true);
- rect.right = getCoordinateValue(
- max(mRelativeOrigin.xLocation, mRelativePointer.xLocation),
- mColumnBounds,
- false);
- rect.top = getCoordinateValue(
- min(mRelativeOrigin.yLocation, mRelativePointer.yLocation),
- mRowBounds,
- true);
- rect.bottom = getCoordinateValue(
- max(mRelativeOrigin.yLocation, mRelativePointer.yLocation),
- mRowBounds,
- false);
- return rect;
- }
-
- /**
- * Computes the corner of the selection nearest the origin.
- * @return
- */
- private int computeCornerNearestOrigin() {
- int cornerValue = 0;
-
- if (mRelativeOrigin.yLocation ==
- min(mRelativeOrigin.yLocation, mRelativePointer.yLocation)) {
- cornerValue |= UPPER;
- } else {
- cornerValue |= LOWER;
- }
-
- if (mRelativeOrigin.xLocation ==
- min(mRelativeOrigin.xLocation, mRelativePointer.xLocation)) {
- cornerValue |= LEFT;
- } else {
- cornerValue |= RIGHT;
- }
-
- return cornerValue;
- }
-
- private RelativeCoordinate min(RelativeCoordinate first, RelativeCoordinate second) {
- return first.compareTo(second) < 0 ? first : second;
- }
-
- private RelativeCoordinate max(RelativeCoordinate first, RelativeCoordinate second) {
- return first.compareTo(second) > 0 ? first : second;
- }
-
- /**
- * @return The absolute coordinate (i.e., the x- or y-value) of the given relative
- * coordinate.
- */
- private int getCoordinateValue(
- RelativeCoordinate coordinate, List<Limits> limitsList, boolean isStartOfRange) {
-
- switch (coordinate.type) {
- case RelativeCoordinate.BEFORE_FIRST_ITEM:
- return limitsList.get(0).lowerLimit;
- case RelativeCoordinate.AFTER_LAST_ITEM:
- return limitsList.get(limitsList.size() - 1).upperLimit;
- case RelativeCoordinate.BETWEEN_TWO_ITEMS:
- if (isStartOfRange) {
- return coordinate.limitsAfterCoordinate.lowerLimit;
- } else {
- return coordinate.limitsBeforeCoordinate.upperLimit;
- }
- case RelativeCoordinate.WITHIN_LIMITS:
- return coordinate.limitsBeforeCoordinate.lowerLimit;
- }
-
- throw new RuntimeException("Invalid coordinate value.");
- }
-
- private boolean areItemsCoveredByBand(
- RelativePoint first, RelativePoint second) {
-
- return doesCoordinateLocationCoverItems(first.xLocation, second.xLocation) &&
- doesCoordinateLocationCoverItems(first.yLocation, second.yLocation);
- }
-
- private boolean doesCoordinateLocationCoverItems(
- RelativeCoordinate pointerCoordinate, RelativeCoordinate originCoordinate) {
-
- if (pointerCoordinate.type == RelativeCoordinate.BEFORE_FIRST_ITEM &&
- originCoordinate.type == RelativeCoordinate.BEFORE_FIRST_ITEM) {
- return false;
- }
-
- if (pointerCoordinate.type == RelativeCoordinate.AFTER_LAST_ITEM &&
- originCoordinate.type == RelativeCoordinate.AFTER_LAST_ITEM) {
- return false;
- }
-
- if (pointerCoordinate.type == RelativeCoordinate.BETWEEN_TWO_ITEMS &&
- originCoordinate.type == RelativeCoordinate.BETWEEN_TWO_ITEMS &&
- pointerCoordinate.limitsBeforeCoordinate.equals(
- originCoordinate.limitsBeforeCoordinate) &&
- pointerCoordinate.limitsAfterCoordinate.equals(
- originCoordinate.limitsAfterCoordinate)) {
- return false;
- }
-
- return true;
- }
-} \ No newline at end of file
diff --git a/src/com/android/documentsui/selection/ItemDetailsLookup.java b/src/com/android/documentsui/selection/ItemDetailsLookup.java
deleted file mode 100644
index 8c0490192..000000000
--- a/src/com/android/documentsui/selection/ItemDetailsLookup.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-import androidx.recyclerview.widget.RecyclerView;
-import android.view.MotionEvent;
-
-import javax.annotation.Nullable;
-
-/**
- * Provides event handlers w/ access to details about documents details
- * view items Documents in the UI (RecyclerView).
- */
-public abstract class ItemDetailsLookup {
-
- /** @return true if there is an item under the finger/cursor. */
- public abstract boolean overItem(MotionEvent e);
-
- /** @return true if there is an item w/ a stable ID under the finger/cursor. */
- public abstract boolean overStableItem(MotionEvent e);
-
- /**
- * @return true if the event is over an area that can be dragged via touch
- * or via mouse. List items have a white area that is not draggable.
- */
- public abstract boolean inItemDragRegion(MotionEvent e);
-
- /**
- * @return true if the event is in the "selection hot spot" region.
- * The hot spot region instantly selects in touch mode, vs launches.
- */
- public abstract boolean inItemSelectRegion(MotionEvent e);
-
- /**
- * @return the adapter position of the item under the finger/cursor.
- */
- public abstract int getItemPosition(MotionEvent e);
-
- /**
- * @return the DocumentDetails for the item under the event, or null.
- */
- public abstract @Nullable ItemDetails getItemDetails(MotionEvent e);
-
- /**
- * Abstract class providing helper classes with access to information about
- * RecyclerView item associated with a MotionEvent.
- */
- public static abstract class ItemDetails {
-
- public boolean hasPosition() {
- return getPosition() > RecyclerView.NO_POSITION;
- }
-
- public abstract int getPosition();
-
- public boolean hasStableId() {
- return getStableId() != null;
- }
-
- public abstract @Nullable String getStableId();
-
- /**
- * @return The view type of this ViewHolder.
- */
- public abstract int getItemViewType();
-
- /**
- * @return true if the event is in an area of the item that should be
- * directly interpreted as a user wishing to select the item. This
- * is useful for checkboxes and other UI affordances focused on enabling
- * selection.
- */
- public boolean inSelectionHotspot(MotionEvent e) {
- return false;
- }
-
- /**
- * Events in the drag region will not be processed as selection events. This
- * allows the client to implement custom handling for events related to drag
- * and drop.
- */
- public boolean inDragRegion(MotionEvent e) {
- return false;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof ItemDetails) {
- return equals((ItemDetails) obj);
- }
- return false;
- }
-
- private boolean equals(ItemDetails other) {
- return this.getPosition() == other.getPosition()
- && this.getStableId() == other.getStableId();
- }
-
- @Override
- public int hashCode() {
- return getPosition() >>> 8;
- }
- }
-}
diff --git a/src/com/android/documentsui/selection/MotionEvents.java b/src/com/android/documentsui/selection/MotionEvents.java
deleted file mode 100644
index 1915c5ab6..000000000
--- a/src/com/android/documentsui/selection/MotionEvents.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-import android.graphics.Point;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-/**
- * Utility methods for working with {@link MotionEvent} instances.
- */
-final class MotionEvents {
-
- private MotionEvents() {}
-
- static boolean isMouseEvent(MotionEvent e) {
- return e.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE;
- }
-
- static boolean isTouchEvent(MotionEvent e) {
- return e.getToolType(0) == MotionEvent.TOOL_TYPE_FINGER;
- }
-
- static boolean isActionMove(MotionEvent e) {
- return e.getActionMasked() == MotionEvent.ACTION_MOVE;
- }
-
- static boolean isActionDown(MotionEvent e) {
- return e.getActionMasked() == MotionEvent.ACTION_DOWN;
- }
-
- static boolean isActionUp(MotionEvent e) {
- return e.getActionMasked() == MotionEvent.ACTION_UP;
- }
-
- static boolean isActionPointerUp(MotionEvent e) {
- return e.getActionMasked() == MotionEvent.ACTION_POINTER_UP;
- }
-
- static boolean isActionPointerDown(MotionEvent e) {
- return e.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN;
- }
-
- static boolean isActionCancel(MotionEvent e) {
- return e.getActionMasked() == MotionEvent.ACTION_CANCEL;
- }
-
- static Point getOrigin(MotionEvent e) {
- return new Point((int) e.getX(), (int) e.getY());
- }
-
- static boolean isPrimaryButtonPressed(MotionEvent e) {
- return e.isButtonPressed(MotionEvent.BUTTON_PRIMARY);
- }
-
- public static boolean isSecondaryButtonPressed(MotionEvent e) {
- return e.isButtonPressed(MotionEvent.BUTTON_SECONDARY);
- }
-
- public static boolean isTertiaryButtonPressed(MotionEvent e) {
- return e.isButtonPressed(MotionEvent.BUTTON_TERTIARY);
- }
-
- static boolean isShiftKeyPressed(MotionEvent e) {
- return hasBit(e.getMetaState(), KeyEvent.META_SHIFT_ON);
- }
-
- static boolean isCtrlKeyPressed(MotionEvent e) {
- return hasBit(e.getMetaState(), KeyEvent.META_CTRL_ON);
- }
-
- static boolean isAltKeyPressed(MotionEvent e) {
- return hasBit(e.getMetaState(), KeyEvent.META_ALT_ON);
- }
-
- public static boolean isTouchpadScroll(MotionEvent e) {
- // Touchpad inputs are treated as mouse inputs, and when scrolling, there are no buttons
- // returned.
- return isMouseEvent(e) && isActionMove(e) && e.getButtonState() == 0;
- }
-
- private static boolean hasBit(int metaState, int bit) {
- return (metaState & bit) != 0;
- }
-}
diff --git a/src/com/android/documentsui/selection/MotionInputHandler.java b/src/com/android/documentsui/selection/MotionInputHandler.java
deleted file mode 100644
index f52a637e0..000000000
--- a/src/com/android/documentsui/selection/MotionInputHandler.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-import static androidx.core.util.Preconditions.checkArgument;
-
-import android.view.GestureDetector.SimpleOnGestureListener;
-import android.view.MotionEvent;
-
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
-
-/**
- * Base class for handlers that can be registered w/ {@link GestureRouter}.
- */
-public abstract class MotionInputHandler extends SimpleOnGestureListener {
-
- protected final SelectionHelper mSelectionHelper;
- protected final ItemDetailsLookup mDetailsLookup;
-
- private final Callbacks mCallbacks;
-
- public MotionInputHandler(
- SelectionHelper selectionHelper,
- ItemDetailsLookup detailsLookup,
- Callbacks callbacks) {
-
- checkArgument(selectionHelper != null);
- checkArgument(detailsLookup != null);
- checkArgument(callbacks != null);
-
- mSelectionHelper = selectionHelper;
- mDetailsLookup = detailsLookup;
- mCallbacks = callbacks;
- }
-
- protected final boolean selectItem(ItemDetails details) {
- checkArgument(details != null);
- checkArgument(details.hasPosition());
- checkArgument(details.hasStableId());
-
- if (mSelectionHelper.select(details.getStableId())) {
- mSelectionHelper.anchorRange(details.getPosition());
- }
-
- // we set the focus on this doc so it will be the origin for keyboard events or shift+clicks
- // if there is only a single item selected, otherwise clear focus
- if (mSelectionHelper.getSelection().size() == 1) {
- mCallbacks.focusItem(details);
- } else {
- mCallbacks.clearFocus();
- }
- return true;
- }
-
- protected final boolean focusItem(ItemDetails details) {
- checkArgument(details != null);
- checkArgument(details.hasStableId());
-
- mSelectionHelper.clearSelection();
- mCallbacks.focusItem(details);
- return true;
- }
-
- protected final void extendSelectionRange(ItemDetails details) {
- checkArgument(details.hasPosition());
- checkArgument(details.hasStableId());
-
- mSelectionHelper.extendRange(details.getPosition());
- mCallbacks.focusItem(details);
- }
-
- protected final boolean isRangeExtension(MotionEvent e) {
- return MotionEvents.isShiftKeyPressed(e) && mSelectionHelper.isRangeActive();
- }
-
- protected boolean shouldClearSelection(MotionEvent e, ItemDetails item) {
- return !MotionEvents.isCtrlKeyPressed(e)
- && !item.inSelectionHotspot(e)
- && !mSelectionHelper.isSelected(item.getStableId());
- }
-
- public static abstract class Callbacks {
- public abstract void onPerformHapticFeedback();
- public void focusItem(ItemDetails item) {}
- public void clearFocus() {}
- }
-}
diff --git a/src/com/android/documentsui/selection/MouseInputHandler.java b/src/com/android/documentsui/selection/MouseInputHandler.java
deleted file mode 100644
index 7ceb0f5fa..000000000
--- a/src/com/android/documentsui/selection/MouseInputHandler.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-import static com.android.documentsui.selection.Shared.DEBUG;
-import static com.android.documentsui.selection.Shared.VERBOSE;
-
-import android.util.Log;
-import android.view.MotionEvent;
-
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
-import com.android.internal.widget.RecyclerView;
-
-import javax.annotation.Nullable;
-
-/**
- * A MotionInputHandler that provides the high-level glue for mouse/stylus driven selection. This
- * class works with {@link RecyclerView}, {@link GestureRouter}, and {@link GestureSelectionHelper}
- * to provide robust user drive selection support.
- */
-public final class MouseInputHandler extends MotionInputHandler {
-
- private static final String TAG = "MouseInputDelegate";
-
- private final Callbacks mCallbacks;
-
- // The event has been handled in onSingleTapUp
- private boolean mHandledTapUp;
- // true when the previous event has consumed a right click motion event
- private boolean mHandledOnDown;
-
- public MouseInputHandler(
- SelectionHelper selectionHelper,
- ItemDetailsLookup detailsLookup,
- Callbacks callbacks) {
-
- super(selectionHelper, detailsLookup, callbacks);
-
- mCallbacks = callbacks;
- }
-
- @Override
- public boolean onDown(MotionEvent e) {
- if (VERBOSE) Log.v(TAG, "Delegated onDown event.");
- if ((MotionEvents.isAltKeyPressed(e) && MotionEvents.isPrimaryButtonPressed(e))
- || MotionEvents.isSecondaryButtonPressed(e)) {
- mHandledOnDown = true;
- return onRightClick(e);
- }
-
- return false;
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- // Don't scroll content window in response to mouse drag
- // If it's two-finger trackpad scrolling, we want to scroll
- return !MotionEvents.isTouchpadScroll(e2);
- }
-
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- // See b/27377794. Since we don't get a button state back from UP events, we have to
- // explicitly save this state to know whether something was previously handled by
- // DOWN events or not.
- if (mHandledOnDown) {
- if (VERBOSE) Log.v(TAG, "Ignoring onSingleTapUp, previously handled in onDown.");
- mHandledOnDown = false;
- return false;
- }
-
- if (!mDetailsLookup.overStableItem(e)) {
- if (DEBUG) Log.d(TAG, "Tap not associated w/ model item. Clearing selection.");
- mSelectionHelper.clearSelection();
- mCallbacks.clearFocus();
- return false;
- }
-
- if (MotionEvents.isTertiaryButtonPressed(e)) {
- if (DEBUG) Log.d(TAG, "Ignoring middle click");
- return false;
- }
-
- ItemDetails item = mDetailsLookup.getItemDetails(e);
- if (mSelectionHelper.hasSelection()) {
- if (isRangeExtension(e)) {
- extendSelectionRange(item);
- } else {
- if (shouldClearSelection(e, item)) {
- mSelectionHelper.clearSelection();
- }
- if (mSelectionHelper.isSelected(item.getStableId())) {
- if (mSelectionHelper.deselect(item.getStableId())) {
- mCallbacks.clearFocus();
- }
- } else {
- selectOrFocusItem(item, e);
- }
- }
- mHandledTapUp = true;
- return true;
- }
-
- return false;
- }
-
- @Override
- public boolean onSingleTapConfirmed(MotionEvent e) {
- if (mHandledTapUp) {
- if (VERBOSE) Log.v(TAG,
- "Ignoring onSingleTapConfirmed, previously handled in onSingleTapUp.");
- mHandledTapUp = false;
- return false;
- }
-
- if (mSelectionHelper.hasSelection()) {
- return false; // should have been handled by onSingleTapUp.
- }
-
- if (!mDetailsLookup.overItem(e)) {
- if (DEBUG) Log.d(TAG, "Ignoring Confirmed Tap on non-item.");
- return false;
- }
-
- if (MotionEvents.isTertiaryButtonPressed(e)) {
- if (DEBUG) Log.d(TAG, "Ignoring middle click");
- return false;
- }
-
- @Nullable ItemDetails item = mDetailsLookup.getItemDetails(e);
- if (item == null || !item.hasStableId()) {
- Log.w(TAG, "Ignoring Confirmed Tap. No document details associated w/ event.");
- return false;
- }
-
- if (mCallbacks.hasFocusedItem() && MotionEvents.isShiftKeyPressed(e)) {
- mSelectionHelper.startRange(mCallbacks.getFocusedPosition());
- mSelectionHelper.extendRange(item.getPosition());
- } else {
- selectOrFocusItem(item, e);
- }
- return true;
- }
-
- @Override
- public boolean onDoubleTap(MotionEvent e) {
- mHandledTapUp = false;
-
- if (!mDetailsLookup.overStableItem(e)) {
- if (DEBUG) Log.d(TAG, "Ignoring DoubleTap on non-model-backed item.");
- return false;
- }
-
- if (MotionEvents.isTertiaryButtonPressed(e)) {
- if (DEBUG) Log.d(TAG, "Ignoring middle click");
- return false;
- }
-
- @Nullable ItemDetails item = mDetailsLookup.getItemDetails(e);
- if (item != null) {
- return mCallbacks.onItemActivated(item, e);
- }
-
- return false;
- }
-
- private boolean onRightClick(MotionEvent e) {
- if (mDetailsLookup.overStableItem(e)) {
- @Nullable ItemDetails item = mDetailsLookup.getItemDetails(e);
- if (item != null && !mSelectionHelper.isSelected(item.getStableId())) {
- mSelectionHelper.clearSelection();
- selectItem(item);
- }
- }
-
- // We always delegate final handling of the event,
- // since the handler might want to show a context menu
- // in an empty area or some other weirdo view.
- return mCallbacks.onContextClick(e);
- }
-
- private void selectOrFocusItem(ItemDetails item, MotionEvent e) {
- if (item.inSelectionHotspot(e) || MotionEvents.isCtrlKeyPressed(e)) {
- selectItem(item);
- } else {
- focusItem(item);
- }
- }
-
- public static abstract class Callbacks extends MotionInputHandler.Callbacks {
- public abstract boolean onItemActivated(ItemDetails item, MotionEvent e);
- public boolean onContextClick(MotionEvent e) {
- return false;
- }
- public boolean hasFocusedItem() {
- return false;
- }
- public int getFocusedPosition() {
- return RecyclerView.NO_POSITION;
- }
- }
- } \ No newline at end of file
diff --git a/src/com/android/documentsui/selection/MutableSelection.java b/src/com/android/documentsui/selection/MutableSelection.java
deleted file mode 100644
index 7939e14ef..000000000
--- a/src/com/android/documentsui/selection/MutableSelection.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-/**
- * Subclass of Selection exposing public support for mutating the underlying selection data.
- * This is useful for clients of {@link SelectionHelper} that wish to manipulate
- * a copy of selection data obtained via {@link SelectionHelper#copySelection(Selection)}.
- */
-public final class MutableSelection extends Selection {
-
- @Override
- public boolean add(String id) {
- return super.add(id);
- }
-
- @Override
- public boolean remove(String id) {
- return super.remove(id);
- }
-
- @Override
- public void clear() {
- super.clear();
- }
-}
diff --git a/src/com/android/documentsui/selection/Range.java b/src/com/android/documentsui/selection/Range.java
deleted file mode 100644
index 001e92d28..000000000
--- a/src/com/android/documentsui/selection/Range.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static androidx.core.util.Preconditions.checkArgument;
-import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
-import static com.android.documentsui.selection.Shared.DEBUG;
-import static com.android.documentsui.selection.Shared.TAG;
-
-import android.util.Log;
-
-import com.android.documentsui.selection.DefaultSelectionHelper.RangeType;
-
-/**
- * Class providing support for managing range selections.
- */
-final class Range {
-
- private final Callbacks mCallbacks;
- private final int mBegin;
- private int mEnd = NO_POSITION;
-
- public Range(Callbacks callbacks, int begin) {
- if (DEBUG) Log.d(TAG, "New Ranger created beginning @ " + begin);
- mCallbacks = callbacks;
- mBegin = begin;
- }
-
- void extendSelection(int position, @RangeType int type) {
- checkArgument(position != NO_POSITION, "Position cannot be NO_POSITION.");
-
- if (mEnd == NO_POSITION || mEnd == mBegin) {
- // Reset mEnd so it can be established in establishRange.
- mEnd = NO_POSITION;
- establishRange(position, type);
- } else {
- reviseRange(position, type);
- }
- }
-
- private void establishRange(int position, @RangeType int type) {
- checkArgument(mEnd == NO_POSITION, "End has already been set.");
-
- if (position == mBegin) {
- mEnd = position;
- }
-
- if (position > mBegin) {
- updateRange(mBegin + 1, position, true, type);
- } else if (position < mBegin) {
- updateRange(position, mBegin - 1, true, type);
- }
-
- mEnd = position;
- }
-
- private void reviseRange(int position, @RangeType int type) {
- checkArgument(mEnd != NO_POSITION, "End must already be set.");
- checkArgument(mBegin != mEnd, "Beging and end point to same position.");
-
- if (position == mEnd) {
- if (DEBUG) Log.v(TAG, "Ignoring no-op revision for range: " + this);
- }
-
- if (mEnd > mBegin) {
- reviseAscendingRange(position, type);
- } else if (mEnd < mBegin) {
- reviseDescendingRange(position, type);
- }
- // the "else" case is covered by checkState at beginning of method.
-
- mEnd = position;
- }
-
- /**
- * Updates an existing ascending selection.
- * @param position
- */
- private void reviseAscendingRange(int position, @RangeType int type) {
- // Reducing or reversing the range....
- if (position < mEnd) {
- if (position < mBegin) {
- updateRange(mBegin + 1, mEnd, false, type);
- updateRange(position, mBegin -1, true, type);
- } else {
- updateRange(position + 1, mEnd, false, type);
- }
- }
-
- // Extending the range...
- else if (position > mEnd) {
- updateRange(mEnd + 1, position, true, type);
- }
- }
-
- private void reviseDescendingRange(int position, @RangeType int type) {
- // Reducing or reversing the range....
- if (position > mEnd) {
- if (position > mBegin) {
- updateRange(mEnd, mBegin - 1, false, type);
- updateRange(mBegin + 1, position, true, type);
- } else {
- updateRange(mEnd, position - 1, false, type);
- }
- }
-
- // Extending the range...
- else if (position < mEnd) {
- updateRange(position, mEnd - 1, true, type);
- }
- }
-
- /**
- * Try to set selection state for all elements in range. Not that callbacks can cancel
- * selection of specific items, so some or even all items may not reflect the desired state
- * after the update is complete.
- *
- * @param begin Adapter position for range start (inclusive).
- * @param end Adapter position for range end (inclusive).
- * @param selected New selection state.
- */
- private void updateRange(int begin, int end, boolean selected, @RangeType int type) {
- mCallbacks.updateForRange(begin, end, selected, type);
- }
-
- @Override
- public String toString() {
- return "Range{begin=" + mBegin + ", end=" + mEnd + "}";
- }
-
- /*
- * @see {@link DefaultSelectionHelper#updateForRange(int, int , boolean, int)}.
- */
- static abstract class Callbacks {
- abstract void updateForRange(
- int begin, int end, boolean selected, @RangeType int type);
- }
-}
diff --git a/src/com/android/documentsui/selection/Selection.java b/src/com/android/documentsui/selection/Selection.java
deleted file mode 100644
index d929bd013..000000000
--- a/src/com/android/documentsui/selection/Selection.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static androidx.core.util.Preconditions.checkArgument;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import androidx.annotation.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-/**
- * Object representing the current selection and provisional selection. Provides read only public
- * access, and private write access.
- * <p>
- * This class tracks selected items by managing two sets:
- *
- * <li>primary selection
- *
- * Primary selection consists of items tapped by a user or by lassoed by band select operation.
- *
- * <li>provisional selection
- *
- * Provisional selections are selections which have been temporarily created
- * by an in-progress band select or gesture selection. Once the user releases the mouse button
- * or lifts their finger the corresponding provisional selection should be converted into
- * primary selection.
- *
- * <p>The total selection is the combination of
- * both the core selection and the provisional selection. Tracking both separately is necessary to
- * ensure that items in the core selection are not "erased" from the core selection when they
- * are temporarily included in a secondary selection (like band selection).
- */
-public class Selection implements Iterable<String>, Parcelable {
-
- final Set<String> mSelection;
- final Set<String> mProvisionalSelection;
-
- public Selection() {
- mSelection = new HashSet<>();
- mProvisionalSelection = new HashSet<>();
- }
-
- /**
- * Used by CREATOR.
- */
- private Selection(Set<String> selection) {
- mSelection = selection;
- mProvisionalSelection = new HashSet<>();
- }
-
- /**
- * @param id
- * @return true if the position is currently selected.
- */
- public boolean contains(@Nullable String id) {
- return mSelection.contains(id) || mProvisionalSelection.contains(id);
- }
-
- /**
- * Returns an {@link Iterator} that iterators over the selection, *excluding*
- * any provisional selection.
- *
- * {@inheritDoc}
- */
- @Override
- public Iterator<String> iterator() {
- return mSelection.iterator();
- }
-
- /**
- * @return size of the selection including both final and provisional selected items.
- */
- public int size() {
- return mSelection.size() + mProvisionalSelection.size();
- }
-
- /**
- * @return true if the selection is empty.
- */
- public boolean isEmpty() {
- return mSelection.isEmpty() && mProvisionalSelection.isEmpty();
- }
-
- /**
- * Sets the provisional selection, which is a temporary selection that can be saved,
- * canceled, or adjusted at a later time. When a new provision selection is applied, the old
- * one (if it exists) is abandoned.
- * @return Map of ids added or removed. Added ids have a value of true, removed are false.
- */
- Map<String, Boolean> setProvisionalSelection(Set<String> newSelection) {
- Map<String, Boolean> delta = new HashMap<>();
-
- for (String id: mProvisionalSelection) {
- // Mark each item that used to be in the provisional selection
- // but is not in the new provisional selection.
- if (!newSelection.contains(id) && !mSelection.contains(id)) {
- delta.put(id, false);
- }
- }
-
- for (String id: mSelection) {
- // Mark each item that used to be in the selection but is unsaved and not in the new
- // provisional selection.
- if (!newSelection.contains(id)) {
- delta.put(id, false);
- }
- }
-
- for (String id: newSelection) {
- // Mark each item that was not previously in the selection but is in the new
- // provisional selection.
- if (!mSelection.contains(id) && !mProvisionalSelection.contains(id)) {
- delta.put(id, true);
- }
- }
-
- // Now, iterate through the changes and actually add/remove them to/from the current
- // selection. This could not be done in the previous loops because changing the size of
- // the selection mid-iteration changes iteration order erroneously.
- for (Map.Entry<String, Boolean> entry: delta.entrySet()) {
- String id = entry.getKey();
- if (entry.getValue()) {
- mProvisionalSelection.add(id);
- } else {
- mProvisionalSelection.remove(id);
- }
- }
-
- return delta;
- }
-
- /**
- * Saves the existing provisional selection. Once the provisional selection is saved,
- * subsequent provisional selections which are different from this existing one cannot
- * cause items in this existing provisional selection to become deselected.
- */
- @VisibleForTesting
- protected void mergeProvisionalSelection() {
- mSelection.addAll(mProvisionalSelection);
- mProvisionalSelection.clear();
- }
-
- /**
- * Abandons the existing provisional selection so that all items provisionally selected are
- * now deselected.
- */
- @VisibleForTesting
- void clearProvisionalSelection() {
- mProvisionalSelection.clear();
- }
-
- /**
- * Adds a new item to the primary selection.
- *
- * @return true if the operation resulted in a modification to the selection.
- */
- boolean add(String id) {
- if (mSelection.contains(id)) {
- return false;
- }
-
- mSelection.add(id);
- return true;
- }
-
- /**
- * Removes an item from the primary selection.
- *
- * @return true if the operation resulted in a modification to the selection.
- */
- boolean remove(String id) {
- if (!mSelection.contains(id)) {
- return false;
- }
-
- mSelection.remove(id);
- return true;
- }
-
- /**
- * Clears the primary selection. The provisional selection, if any, is unaffected.
- */
- void clear() {
- mSelection.clear();
- }
-
- /**
- * Trims this selection to be the intersection of itself and {@code ids}.
- */
- void intersect(Collection<String> ids) {
- checkArgument(ids != null);
-
- mSelection.retainAll(ids);
- mProvisionalSelection.retainAll(ids);
- }
-
- /**
- * Clones primary and provisional selection from supplied {@link Selection}.
- * Does not copy active range data.
- */
- @VisibleForTesting
- void copyFrom(Selection source) {
- mSelection.clear();
- mSelection.addAll(source.mSelection);
-
- mProvisionalSelection.clear();
- mProvisionalSelection.addAll(source.mProvisionalSelection);
- }
-
- @Override
- public String toString() {
- if (size() <= 0) {
- return "size=0, items=[]";
- }
-
- StringBuilder buffer = new StringBuilder(size() * 28);
- buffer.append("Selection{")
- .append("primary{size=" + mSelection.size())
- .append(", entries=" + mSelection)
- .append("}, provisional{size=" + mProvisionalSelection.size())
- .append(", entries=" + mProvisionalSelection)
- .append("}}");
- return buffer.toString();
- }
-
- @Override
- public int hashCode() {
- return mSelection.hashCode() ^ mProvisionalSelection.hashCode();
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- }
-
- return other instanceof Selection
- ? equals((Selection) other)
- : false;
- }
-
- private boolean equals(Selection other) {
- return mSelection.equals(((Selection) other).mSelection) &&
- mProvisionalSelection.equals(((Selection) other).mProvisionalSelection);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeStringList(new ArrayList<>(mSelection));
- // We don't include provisional selection since it is
- // typically coupled to some other runtime state (like a band).
- }
-
- public static final ClassLoaderCreator<Selection> CREATOR =
- new ClassLoaderCreator<Selection>() {
- @Override
- public Selection createFromParcel(Parcel in) {
- return createFromParcel(in, null);
- }
-
- @Override
- public Selection createFromParcel(Parcel in, ClassLoader loader) {
- ArrayList<String> selected = new ArrayList<>();
- in.readStringList(selected);
-
- return new Selection(new HashSet<>(selected));
- }
-
- @Override
- public Selection[] newArray(int size) {
- return new Selection[size];
- }
- };
-} \ No newline at end of file
diff --git a/src/com/android/documentsui/selection/SelectionHelper.java b/src/com/android/documentsui/selection/SelectionHelper.java
deleted file mode 100644
index bd8b34eaa..000000000
--- a/src/com/android/documentsui/selection/SelectionHelper.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * SelectionManager provides support for managing selection within a RecyclerView instance.
- *
- * @see DefaultSelectionHelper for details on instantiation.
- */
-public abstract class SelectionHelper {
-
- /**
- * This value is included in the payload when SelectionHelper implementations
- * notify RecyclerView of changes. Clients can look for this in
- * {@code onBindViewHolder} to know if the bind event is occurring in response
- * to a selection state change.
- */
- public static final String SELECTION_CHANGED_MARKER = "Selection-Changed";
-
- /**
- * Adds {@code observe} to be notified when changes to selection occur.
- *
- * @param observer
- */
- public abstract void addObserver(SelectionObserver observer);
-
- public abstract boolean hasSelection();
-
- /**
- * Returns a Selection object that provides a live view on the current selection.
- *
- * @see #copySelection(Selection) on how to get a snapshot
- * of the selection that will not reflect future changes
- * to selection.
- *
- * @return The current selection.
- */
- public abstract Selection getSelection();
-
- /**
- * Updates {@code dest} to reflect the current selection.
- * @param dest
- */
- public abstract void copySelection(Selection dest);
-
- /**
- * @return true if the item specified by its id is selected. Shorthand for
- * {@code getSelection().contains(String)}.
- */
- public abstract boolean isSelected(String id);
-
- /**
- * Restores the selected state of specified items. Used in cases such as restore the selection
- * after rotation etc. Provisional selection, being provisional 'n all, isn't restored.
- */
- public abstract void restoreSelection(Selection other);
-
- /**
- * Sets the selected state of the specified items. Note that the callback will NOT
- * be consulted to see if an item can be selected.
- *
- * @param ids
- * @param selected
- * @return
- */
- public abstract boolean setItemsSelected(Iterable<String> ids, boolean selected);
-
- /**
- * Clears the selection and notifies (if something changes).
- */
- public abstract void clearSelection();
-
- /**
- * Attempts to select an item.
- *
- * @return true if the item was selected. False if the item was not selected, or was
- * was already selected prior to the method being called.
- */
- public abstract boolean select(String itemId);
-
- /**
- * Attempts to deselect an item.
- *
- * @return true if the item was deselected. False if the item was not deselected, or was
- * was already deselected prior to the method being called.
- */
- public abstract boolean deselect(String itemId);
-
- /**
- * Starts a range selection. If a range selection is already active, this will start a new range
- * selection (which will reset the range anchor).
- *
- * @param pos The anchor position for the selection range.
- */
- public abstract void startRange(int pos);
-
- /**
- * Sets the end point for the active range selection.
- *
- * <p>This function should only be called when a range selection is active
- * (see {@link #isRangeActive()}. Items in the range [anchor, end] will be
- * selected.
- *
- * @param pos The new end position for the selection range.
- * @param type The type of selection the range should utilize.
- *
- * @throws IllegalStateException if a range selection is not active. Range selection
- * must have been started by a call to {@link #startRange(int)}.
- */
- public abstract void extendRange(int pos);
-
- /**
- * Stops an in-progress range selection. All selection done with
- * {@link #extendProvisionalRange(int)} will be lost if
- * {@link Selection#mergeProvisionalSelection()} is not called beforehand.
- */
- public abstract void endRange();
-
- /**
- * @return Whether or not there is a current range selection active.
- */
- public abstract boolean isRangeActive();
-
- /**
- * Sets the magic location at which a selection range begins (the selection anchor). This value
- * is consulted when determining how to extend, and modify selection ranges. Calling this when a
- * range selection is active will reset the range selection.
- */
- public abstract void anchorRange(int position);
-
- /**
- * @param pos
- */
- // TODO: This is smelly. Maybe this type of logic needs to move into range selection,
- // then selection manager can have a startProvisionalRange and startRange. Or
- // maybe ranges always start life as provisional.
- public abstract void extendProvisionalRange(int pos);
-
- /**
- * @param newSelection
- */
- public abstract void setProvisionalSelection(Set<String> newSelection);
-
- /**
- *
- */
- public abstract void clearProvisionalSelection();
-
- public abstract void mergeProvisionalSelection();
-
- /**
- * Observer interface providing access to information about Selection state changes.
- */
- public static abstract class SelectionObserver {
-
- /**
- * Called when state of an item has been changed.
- */
- public void onItemStateChanged(String id, boolean selected) {}
-
- /**
- * Called when the underlying data set has change. After this method is called
- * the selection manager will attempt traverse the existing selection,
- * calling {@link #onItemStateChanged(String, boolean)} for each selected item,
- * and deselecting any items that cannot be selected given the updated dataset.
- */
- public void onSelectionReset() {}
-
- /**
- * Called immediately after completion of any set of changes, excluding
- * those resulting in calls to {@link #onSelectionReset()} and
- * {@link #onSelectionRestored()}.
- */
- public void onSelectionChanged() {}
-
- /**
- * Called immediately after selection is restored.
- * {@link #onItemStateChanged(String, boolean)} will not be called
- * for individual items in the selection.
- */
- public void onSelectionRestored() {}
- }
-
- /**
- * Facilitates the use of stable ids.
- */
- public static abstract class StableIdProvider {
- /**
- * @return The model ID of the item at the given adapter position.
- */
- public abstract String getStableId(int position);
-
- /**
- * @return the position of a stable ID, or RecyclerView.NO_POSITION.
- */
- public abstract int getPosition(String id);
-
- /**
- * @return A list of all known stable IDs.
- */
- public abstract List<String> getStableIds();
- }
-
- /**
- * Implement SelectionPredicate to control when items can be selected or unselected.
- */
- public static abstract class SelectionPredicate {
-
- /** @return true if the item at {@code id} can be set to {@code nextState}. */
- public abstract boolean canSetStateForId(String id, boolean nextState);
-
- /** @return true if the item at {@code id} can be set to {@code nextState}. */
- public abstract boolean canSetStateAtPosition(int position, boolean nextState);
-
- /** @return true if more than a single item can be selected. */
- public boolean canSelectMultiple() {
- return true;
- }
- }
-}
diff --git a/src/com/android/documentsui/selection/Shared.java b/src/com/android/documentsui/selection/Shared.java
deleted file mode 100644
index bf30919dc..000000000
--- a/src/com/android/documentsui/selection/Shared.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-/**
- * Shared constants used in this and descendant packages.
- */
-public final class Shared {
-
- public static final String TAG = "SelectionHelper";
- public static final boolean DEBUG = false;
- public static final boolean VERBOSE = false;
-
- private Shared() {}
-}
diff --git a/src/com/android/documentsui/selection/ToolHandlerRegistry.java b/src/com/android/documentsui/selection/ToolHandlerRegistry.java
deleted file mode 100644
index 4a6aa16a1..000000000
--- a/src/com/android/documentsui/selection/ToolHandlerRegistry.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static androidx.core.util.Preconditions.checkArgument;
-import static androidx.core.util.Preconditions.checkState;
-
-import androidx.annotation.Nullable;
-import android.view.MotionEvent;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Registry for tool specific event handler.
- */
-final class ToolHandlerRegistry<T> {
-
- // Currently there are four known input types. ERASER is the last one, so has the
- // highest value. UNKNOWN is zero, so we add one. This allows delegates to be
- // registered by type, and avoid the auto-boxing that would be necessary were we
- // to store delegates in a Map<Integer, Delegate>.
- private static final int sNumInputTypes = MotionEvent.TOOL_TYPE_ERASER + 1;
-
- private final List<T> mHandlers = Arrays.asList(null, null, null, null, null);
- private final T mDefault;
-
- ToolHandlerRegistry(T defaultDelegate) {
- checkArgument(defaultDelegate != null);
- mDefault = defaultDelegate;
-
- // Initialize all values to null.
- for (int i = 0; i < sNumInputTypes; i++) {
- mHandlers.set(i, null);
- }
- }
-
- /**
- * @param toolType
- * @param delegate the delegate, or null to unregister.
- * @throws IllegalStateException if an tooltype handler is already registered.
- */
- void set(int toolType, @Nullable T delegate) {
- checkArgument(toolType >= 0 && toolType <= MotionEvent.TOOL_TYPE_ERASER);
- checkState(mHandlers.get(toolType) == null);
-
- mHandlers.set(toolType, delegate);
- }
-
- T get(MotionEvent e) {
- T d = mHandlers.get(e.getToolType(0));
- return d != null ? d : mDefault;
- }
-}
diff --git a/src/com/android/documentsui/selection/TouchEventRouter.java b/src/com/android/documentsui/selection/TouchEventRouter.java
deleted file mode 100644
index 232b56067..000000000
--- a/src/com/android/documentsui/selection/TouchEventRouter.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static androidx.core.util.Preconditions.checkArgument;
-
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-
-/**
- * A class responsible for routing MotionEvents to tool-type specific handlers,
- * and if not handled by a handler, on to a {@link GestureDetector} for further
- * processing.
- *
- * <p>TouchEventRouter takes its name from
- * {@link RecyclerView#addOnItemTouchListener(OnItemTouchListener)}. Despite "Touch"
- * being in the name, it receives MotionEvents for all types of tools.
- */
-public final class TouchEventRouter implements OnItemTouchListener {
-
- private final GestureDetector mDetector;
- private final ToolHandlerRegistry<OnItemTouchListener> mDelegates;
-
- public TouchEventRouter(GestureDetector detector, OnItemTouchListener defaultDelegate) {
- checkArgument(detector != null);
- checkArgument(defaultDelegate != null);
-
- mDetector = detector;
- mDelegates = new ToolHandlerRegistry<>(defaultDelegate);
- }
-
- public TouchEventRouter(GestureDetector detector) {
- this(
- detector,
- // Default listener does nothing.
- new OnItemTouchListener() {
- @Override
- public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
- return false;
- }
-
- @Override
- public void onTouchEvent(RecyclerView rv, MotionEvent e) {
- }
-
- @Override
- public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
- }
- });
- }
-
- /**
- * @param toolType See MotionEvent for details on available types.
- * @param delegate An {@link OnItemTouchListener} to receive events
- * of {@code toolType}.
- */
- public void register(int toolType, OnItemTouchListener delegate) {
- checkArgument(delegate != null);
- mDelegates.set(toolType, delegate);
- }
-
- @Override
- public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
- boolean handled = mDelegates.get(e).onInterceptTouchEvent(rv, e);
-
- // Forward all events to UserInputHandler.
- // This is necessary since UserInputHandler needs to always see the first DOWN event. Or
- // else all future UP events will be tossed.
- handled |= mDetector.onTouchEvent(e);
-
- return handled;
- }
-
- @Override
- public void onTouchEvent(RecyclerView rv, MotionEvent e) {
- mDelegates.get(e).onTouchEvent(rv, e);
-
- // Note: even though this event is being handled as part of gestures such as drag and band,
- // continue forwarding to the GestureDetector. The detector needs to see the entire cluster
- // of events in order to properly interpret other gestures, such as long press.
- mDetector.onTouchEvent(e);
- }
-
- @Override
- public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
-}
diff --git a/src/com/android/documentsui/selection/TouchInputHandler.java b/src/com/android/documentsui/selection/TouchInputHandler.java
deleted file mode 100644
index ffb6bce8d..000000000
--- a/src/com/android/documentsui/selection/TouchInputHandler.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-import static com.android.documentsui.base.SharedMinimal.DEBUG;
-
-import androidx.recyclerview.widget.RecyclerView;
-import android.util.Log;
-import android.view.MotionEvent;
-
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
-import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
-
-/**
- * A MotionInputHandler that provides the high-level glue for touch driven selection. This class
- * works with {@link RecyclerView}, {@link GestureRouter}, and {@link GestureSelectionHelper} to
- * provide robust user drive selection support.
- */
-public final class TouchInputHandler extends MotionInputHandler {
- private static final String TAG = "TouchInputDelegate";
-
- private final SelectionPredicate mSelectionPredicate;
- private final Callbacks mCallbacks;
- private final Runnable mGestureKicker;
-
- public TouchInputHandler(
- SelectionHelper selectionHelper,
- ItemDetailsLookup detailsLookup,
- SelectionPredicate selectionPredicate,
- Runnable gestureKicker,
- Callbacks callbacks) {
-
- super(selectionHelper, detailsLookup, callbacks);
-
- mSelectionPredicate = selectionPredicate;
- mGestureKicker = gestureKicker;
- mCallbacks = callbacks;
- }
-
- public TouchInputHandler(
- SelectionHelper selectionHelper,
- ItemDetailsLookup detailsLookup,
- SelectionPredicate selectionPredicate,
- GestureSelectionHelper gestureHelper,
- Callbacks callbacks) {
-
- this(
- selectionHelper,
- detailsLookup,
- selectionPredicate,
- new Runnable() {
- @Override
- public void run() {
- gestureHelper.start();
- }
- },
- callbacks);
- }
-
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- if (!mDetailsLookup.overStableItem(e)) {
- if (DEBUG) Log.d(TAG, "Tap not associated w/ model item. Clearing selection.");
- mSelectionHelper.clearSelection();
- return false;
- }
-
- ItemDetails item = mDetailsLookup.getItemDetails(e);
- if (mSelectionHelper.hasSelection()) {
- if (isRangeExtension(e)) {
- extendSelectionRange(item);
- } else if (mSelectionHelper.isSelected(item.getStableId())) {
- mSelectionHelper.deselect(item.getStableId());
- } else {
- selectItem(item);
- }
-
- return true;
- }
-
- // Touch events select if they occur in the selection hotspot,
- // otherwise they activate.
- return item.inSelectionHotspot(e)
- ? selectItem(item)
- : mCallbacks.onItemActivated(item, e);
- }
-
- @Override
- public final void onLongPress(MotionEvent e) {
- if (!mDetailsLookup.overStableItem(e)) {
- if (DEBUG) Log.d(TAG, "Ignoring LongPress on non-model-backed item.");
- return;
- }
-
- ItemDetails item = mDetailsLookup.getItemDetails(e);
- boolean handled = false;
-
- if (isRangeExtension(e)) {
- extendSelectionRange(item);
- handled = true;
- } else {
- if (!mSelectionHelper.isSelected(item.getStableId())
- && mSelectionPredicate.canSetStateForId(item.getStableId(), 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()) {
- mGestureKicker.run();
- }
- handled = true;
- }
- } else {
- // We only initiate drag and drop on long press for touch to allow regular
- // touch-based scrolling
- // mTouchDragListener.accept(e);
- mCallbacks.onDragInitiated(e);
- handled = true;
- }
- }
-
- if (handled) {
- mCallbacks.onPerformHapticFeedback();
- }
- }
-
- public static abstract class Callbacks extends MotionInputHandler.Callbacks {
- public abstract boolean onItemActivated(ItemDetails item, MotionEvent e);
- public boolean onDragInitiated(MotionEvent e) {
- return false;
- }
- }
-}
diff --git a/src/com/android/documentsui/selection/demo/DemoDetailsLookup.java b/src/com/android/documentsui/selection/demo/DemoDetailsLookup.java
deleted file mode 100644
index c49014e8a..000000000
--- a/src/com/android/documentsui/selection/demo/DemoDetailsLookup.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection.demo;
-
-import androidx.annotation.Nullable;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.ViewHolder;
-import android.view.MotionEvent;
-import android.view.View;
-
-import com.android.documentsui.selection.ItemDetailsLookup;
-
-/**
- * Access to details of an item associated with a {@link MotionEvent} instance.
- */
-final class DemoDetailsLookup extends ItemDetailsLookup {
-
- private final RecyclerView mRecView;
-
- public DemoDetailsLookup(RecyclerView view) {
- mRecView = view;
- }
-
- @Override
- public boolean overItem(MotionEvent e) {
- return getItemPosition(e) != RecyclerView.NO_POSITION;
- }
-
- @Override
- public boolean overStableItem(MotionEvent e) {
- return overItem(e) && getItemDetails(e).hasStableId();
- }
-
- @Override
- public boolean inItemDragRegion(MotionEvent e) {
- return overItem(e) && getItemDetails(e).inDragRegion(e);
- }
-
- @Override
- public boolean inItemSelectRegion(MotionEvent e) {
- return overItem(e) && getItemDetails(e).inSelectionHotspot(e);
- }
-
- @Override
- public int getItemPosition(MotionEvent e) {
- View child = mRecView.findChildViewUnder(e.getX(), e.getY());
- return (child != null)
- ? mRecView.getChildAdapterPosition(child)
- : RecyclerView.NO_POSITION;
- }
-
- @Override
- public ItemDetails getItemDetails(MotionEvent e) {
- @Nullable DemoHolder holder = getDemoHolder(e);
- return holder == null ? null : holder.getItemDetails();
- }
-
- private @Nullable DemoHolder getDemoHolder(MotionEvent e) {
- View childView = mRecView.findChildViewUnder(e.getX(), e.getY());
- if (childView != null) {
- ViewHolder holder = mRecView.getChildViewHolder(childView);
- if (holder instanceof DemoHolder) {
- return (DemoHolder) holder;
- }
- }
- return null;
- }
-}
diff --git a/src/com/android/documentsui/selection/demo/DemoHolder.java b/src/com/android/documentsui/selection/demo/DemoHolder.java
deleted file mode 100644
index ade72c7dd..000000000
--- a/src/com/android/documentsui/selection/demo/DemoHolder.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection.demo;
-
-import android.graphics.Rect;
-import androidx.recyclerview.widget.RecyclerView;
-import android.view.MotionEvent;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.documentsui.R;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
-
-public final class DemoHolder extends RecyclerView.ViewHolder {
-
- private final LinearLayout mContainer;
- public final TextView mSelector;
- public final TextView mLabel;
- private final Details mDetails;
- private DemoItem mItem;
-
- DemoHolder(LinearLayout layout) {
- super(layout);
- mContainer = layout.findViewById(R.id.container);
- mSelector = layout.findViewById(R.id.selector);
- mLabel = layout.findViewById(R.id.label);
- mDetails = new Details(this);
- }
-
- public void update(DemoItem demoItem) {
- mItem = demoItem;
- mLabel.setText(mItem.getName());
- }
-
- void setSelected(boolean selected) {
- mContainer.setActivated(selected);
- mSelector.setActivated(selected);
- }
-
- public String getStableId() {
- return mItem != null ? mItem.getId() : null;
- }
-
- public boolean inDragRegion(MotionEvent e) {
- // If itemView is activated = selected, then whole region is interactive
- if (mContainer.isActivated()) {
- return true;
- }
-
- if (inSelectRegion(e)) {
- return true;
- }
-
- Rect rect = new Rect();
- mLabel.getPaint().getTextBounds(
- mLabel.getText().toString(), 0, mLabel.getText().length(), rect);
-
- // If the tap occurred inside the text, these are interactive spots.
- return rect.contains((int) e.getRawX(), (int) e.getRawY());
- }
-
- public boolean inSelectRegion(MotionEvent e) {
- Rect iconRect = new Rect();
- mSelector.getGlobalVisibleRect(iconRect);
- return iconRect.contains((int) e.getRawX(), (int) e.getRawY());
- }
-
- Details getItemDetails() {
- return mDetails;
- }
-
- private static final class Details extends ItemDetails {
-
- private final DemoHolder mHolder;
-
- Details(DemoHolder holder) {
- mHolder = holder;
- }
-
- @Override
- public int getPosition() {
- return mHolder.getAdapterPosition();
- }
-
- @Override
- public String getStableId() {
- return mHolder.getStableId();
- }
-
- @Override
- public int getItemViewType() {
- return mHolder.getItemViewType();
- }
-
- @Override
- public boolean inDragRegion(MotionEvent e) {
- return mHolder.inDragRegion(e);
- }
-
- @Override
- public boolean inSelectionHotspot(MotionEvent e) {
- return mHolder.inSelectRegion(e);
- }
- }
- } \ No newline at end of file
diff --git a/src/com/android/documentsui/selection/demo/DemoItem.java b/src/com/android/documentsui/selection/demo/DemoItem.java
deleted file mode 100644
index 15755a0e9..000000000
--- a/src/com/android/documentsui/selection/demo/DemoItem.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection.demo;
-
-public class DemoItem {
-
- private final String mId;
- private final String mName;
-
- DemoItem(String id, String name) {
- mId = id;
- mName = name;
- }
-
- public String getId() {
- return mId;
- }
-
- public String getName() {
- return mName;
- }
-}
diff --git a/src/com/android/documentsui/selection/demo/DemoStableIdProvider.java b/src/com/android/documentsui/selection/demo/DemoStableIdProvider.java
deleted file mode 100644
index 5b5332ec8..000000000
--- a/src/com/android/documentsui/selection/demo/DemoStableIdProvider.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection.demo;
-
-import static androidx.core.util.Preconditions.checkArgument;
-
-import com.android.documentsui.selection.SelectionHelper.StableIdProvider;
-
-import java.util.List;
-
-/**
- * Provides RecyclerView selection code access to stable ids backed
- * by DocumentsAdapter.
- */
-final class DemoStableIdProvider extends StableIdProvider {
-
- private final SelectionDemoAdapter mAdapter;
-
- public DemoStableIdProvider(SelectionDemoAdapter adapter) {
- checkArgument(adapter != null);
- mAdapter = adapter;
- }
-
- @Override
- public String getStableId(int position) {
- return mAdapter.getStableId(position);
- }
-
- @Override
- public int getPosition(String id) {
- return mAdapter.getPosition(id);
- }
-
- @Override
- public List<String> getStableIds() {
- return mAdapter.getStableIds();
- }
-}
diff --git a/src/com/android/documentsui/selection/demo/SelectionDemoActivity.java b/src/com/android/documentsui/selection/demo/SelectionDemoActivity.java
deleted file mode 100644
index 90857745c..000000000
--- a/src/com/android/documentsui/selection/demo/SelectionDemoActivity.java
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection.demo;
-
-import android.content.Context;
-import android.os.Bundle;
-import androidx.annotation.CallSuper;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.appcompat.widget.Toolbar;
-import android.view.GestureDetector;
-import android.view.HapticFeedbackConstants;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.widget.Toast;
-
-import com.android.documentsui.R;
-import com.android.documentsui.selection.BandSelectionHelper;
-import com.android.documentsui.selection.ContentLock;
-import com.android.documentsui.selection.DefaultBandHost;
-import com.android.documentsui.selection.DefaultBandPredicate;
-import com.android.documentsui.selection.DefaultSelectionHelper;
-import com.android.documentsui.selection.GestureRouter;
-import com.android.documentsui.selection.GestureSelectionHelper;
-import com.android.documentsui.selection.ItemDetailsLookup;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
-import com.android.documentsui.selection.MotionInputHandler;
-import com.android.documentsui.selection.MouseInputHandler;
-import com.android.documentsui.selection.MutableSelection;
-import com.android.documentsui.selection.Selection;
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
-import com.android.documentsui.selection.SelectionHelper.StableIdProvider;
-import com.android.documentsui.selection.TouchEventRouter;
-import com.android.documentsui.selection.TouchInputHandler;
-import com.android.documentsui.selection.demo.SelectionDemoAdapter.OnBindCallback;
-
-/**
- * ContentPager demo activity.
- */
-public class SelectionDemoActivity extends AppCompatActivity {
-
- private static final String EXTRA_SAVED_SELECTION = "demo-saved-selection";
- private static final String EXTRA_COLUMN_COUNT = "demo-column-count";
-
- private Toolbar mToolbar;
- private SelectionDemoAdapter mAdapter;
- private SelectionHelper mSelectionHelper;
-
- private RecyclerView mRecView;
- private GridLayoutManager mLayout;
- private int mColumnCount = 1; // This will get updated when layout changes.
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.selection_demo_layout);
- mToolbar = findViewById(R.id.toolbar);
- setSupportActionBar(mToolbar);
- mRecView = (RecyclerView) findViewById(R.id.list);
-
- mLayout = new GridLayoutManager(this, mColumnCount);
- mRecView.setLayoutManager(mLayout);
-
- mAdapter = new SelectionDemoAdapter(this);
- mRecView.setAdapter(mAdapter);
-
- StableIdProvider stableIds = new DemoStableIdProvider(mAdapter);
-
- // SelectionPredicate permits client control of which items can be selected.
- SelectionPredicate canSelectAnything = new SelectionPredicate() {
- @Override
- public boolean canSetStateForId(String id, boolean nextState) {
- return true;
- }
-
- @Override
- public boolean canSetStateAtPosition(int position, boolean nextState) {
- return true;
- }
- };
-
- // TODO: Reload content when it changes. Could use CursorLoader.
- // TODO: Retain selection. Restore when content changes.
-
- mSelectionHelper = new DefaultSelectionHelper(
- DefaultSelectionHelper.MODE_MULTIPLE,
- mAdapter,
- stableIds,
- canSelectAnything);
-
- // onBind event callback that allows items to be updated to reflect
- // selection status when bound by recycler view.
- // This allows us to defer initialization of the SelectionHelper dependency
- // which itself depends on the Adapter.
- mAdapter.addOnBindCallback(
- new OnBindCallback() {
- @Override
- void onBound(DemoHolder holder, int position) {
- String id = mAdapter.getStableId(position);
- holder.setSelected(mSelectionHelper.isSelected(id));
- }
- });
-
- ItemDetailsLookup detailsLookup = new DemoDetailsLookup(mRecView);
-
- // Setup basic input handling, with the touch handler as the default consumer
- // of events. If mouse handling is configured as well, the mouse input
- // related handlers will intercept mouse input events.
-
- // GestureRouter is responsible for routing GestureDetector events
- // to tool-type specific handlers.
- GestureRouter<MotionInputHandler> gestureRouter = new GestureRouter<>();
- GestureDetector gestureDetector = new GestureDetector(this, gestureRouter);
-
- // TouchEventRouter takes its name from RecyclerView#OnItemTouchListener.
- // Despite "Touch" being in the name, it receives events for all types of tools.
- // This class is responsible for routing events to tool-type specific handlers,
- // and if not handled by a handler, on to a GestureDetector for analysis.
- TouchEventRouter eventRouter = new TouchEventRouter(gestureDetector);
-
- // Content lock provides a mechanism to block content reload while selection
- // activities are active. If using a loader to load content, route
- // the call through the content lock using ContentLock#runWhenUnlocked.
- // This is especially useful when listening on content change notification.
- ContentLock contentLock = new ContentLock();
-
- // GestureSelectionHelper provides logic that interprets a combination
- // of motions and gestures in order to provide gesture driven selection support
- // when used in conjunction with RecyclerView.
- GestureSelectionHelper gestureHelper = GestureSelectionHelper.create(
- mSelectionHelper, mRecView, contentLock, detailsLookup);
-
- // Finally hook the framework up to listening to recycle view events.
- mRecView.addOnItemTouchListener(eventRouter);
-
- // But before you move on, there's more work to do. Event plumbing has been
- // installed, but we haven't registered any of our helpers or callbacks.
- // Helpers contain predefined logic converting events into selection related events.
- // Callbacks provide authors the ability to reponspond to other types of
- // events (like "active" a tapped item). This is broken up into two main
- // suites, one for "touch" and one for "mouse", though both can and should (usually)
- // be configued to handle other types of input (to satisfy user expectation).
-
- // TOUCH (+ UNKNOWN) handeling provides gesture based selection allowing
- // the user to long press on an item, then drag her finger over other
- // items in order to extend the selection.
- TouchCallbacks touchCallbacks = new TouchCallbacks(this, mRecView);
-
- // Provides high level glue for binding touch events and gestures to selection framework.
- TouchInputHandler touchHandler = new TouchInputHandler(
- mSelectionHelper, detailsLookup, canSelectAnything, gestureHelper, touchCallbacks);
-
- eventRouter.register(MotionEvent.TOOL_TYPE_FINGER, gestureHelper);
- eventRouter.register(MotionEvent.TOOL_TYPE_UNKNOWN, gestureHelper);
-
- gestureRouter.register(MotionEvent.TOOL_TYPE_FINGER, touchHandler);
- gestureRouter.register(MotionEvent.TOOL_TYPE_UNKNOWN, touchHandler);
-
- // MOUSE (+ STYLUS) handeling provides band based selection allowing
- // the user to click down in an empty area, then drag her mouse
- // to create a band that covers the items she wants selected.
- //
- // PRO TIP: Don't skip installing mouse/stylus support. It provides
- // improved productivity and demonstrates feature maturity that users
- // will appreciate. See InputManager for details on more sophisticated
- // strategies on detecting the presence of input tools.
-
- // Provides high level glue for binding mouse/stylus events and gestures
- // to selection framework.
- MouseInputHandler mouseHandler = new MouseInputHandler(
- mSelectionHelper, detailsLookup, new MouseCallbacks(this, mRecView));
-
- DefaultBandHost host = new DefaultBandHost(
- mRecView, R.drawable.selection_demo_band_overlay);
-
- // BandSelectionHelper provides support for band selection on-top of a RecyclerView
- // instance. Given the recycling nature of RecyclerView BandSelectionController
- // necessarily models and caches list/grid information as the user's pointer
- // interacts with the item in the RecyclerView. Selectable items that intersect
- // with the band, both on and off screen, are selected.
- BandSelectionHelper bandHelper = new BandSelectionHelper(
- host,
- mAdapter,
- stableIds,
- mSelectionHelper,
- canSelectAnything,
- new DefaultBandPredicate(detailsLookup),
- contentLock);
-
-
- eventRouter.register(MotionEvent.TOOL_TYPE_MOUSE, bandHelper);
- eventRouter.register(MotionEvent.TOOL_TYPE_STYLUS, bandHelper);
-
- gestureRouter.register(MotionEvent.TOOL_TYPE_MOUSE, mouseHandler);
- gestureRouter.register(MotionEvent.TOOL_TYPE_STYLUS, mouseHandler);
-
- // Aaaaan, all done with mouse/stylus selection setup!
-
- updateFromSavedState(savedInstanceState);
- }
-
- @Override
- protected void onSaveInstanceState(Bundle state) {
- super.onSaveInstanceState(state);
- MutableSelection selection = new MutableSelection();
- mSelectionHelper.copySelection(selection);
- state.putParcelable(EXTRA_SAVED_SELECTION, selection);
- state.putInt(EXTRA_COLUMN_COUNT, mColumnCount);
- }
-
- private void updateFromSavedState(Bundle state) {
- // In order to preserve selection across various lifecycle events be sure to save
- // the selection in onSaveInstanceState, and to restore it when present in the Bundle
- // pass in via onCreate(Bundle).
- if (state != null) {
- if (state.containsKey(EXTRA_SAVED_SELECTION)) {
- Selection savedSelection = state.getParcelable(EXTRA_SAVED_SELECTION);
- if (!savedSelection.isEmpty()) {
- mSelectionHelper.restoreSelection(savedSelection);
- CharSequence text = "Selection restored.";
- Toast.makeText(this, "Selection restored.", Toast.LENGTH_SHORT).show();
- }
- }
- if (state.containsKey(EXTRA_COLUMN_COUNT)) {
- mColumnCount = state.getInt(EXTRA_COLUMN_COUNT);
- mLayout.setSpanCount(mColumnCount);
- }
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- boolean showMenu = super.onCreateOptionsMenu(menu);
- getMenuInflater().inflate(R.menu.selection_demo_actions, menu);
- return showMenu;
- }
-
- @Override
- @CallSuper
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- menu.findItem(R.id.option_menu_add_column).setEnabled(mColumnCount <= 3);
- menu.findItem(R.id.option_menu_remove_column).setEnabled(mColumnCount > 1);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.option_menu_add_column:
- // TODO: Add columns
- mLayout.setSpanCount(++mColumnCount);
- return true;
-
- case R.id.option_menu_remove_column:
- mLayout.setSpanCount(--mColumnCount);
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
-
- @Override
- public void onBackPressed () {
- if (mSelectionHelper.hasSelection()) {
- mSelectionHelper.clearSelection();
- mSelectionHelper.clearProvisionalSelection();
- } else {
- super.onBackPressed();
- }
- }
-
- private static void toast(Context context, String msg) {
- Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
- }
-
- @Override
- protected void onDestroy() {
- mSelectionHelper.clearSelection();
- super.onDestroy();
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- mAdapter.loadData();
- }
-
- // Implementation of MouseInputHandler.Callbacks allows handling
- // of higher level events, like onActivated.
- private static final class MouseCallbacks extends MouseInputHandler.Callbacks {
-
- private final Context mContext;
- private final RecyclerView mRecView;
-
- MouseCallbacks(Context context, RecyclerView recView) {
- mContext = context;
- mRecView = recView;
- }
-
- @Override
- public boolean onItemActivated(ItemDetails item, MotionEvent e) {
- toast(mContext, "Activate item: " + item.getStableId());
- return true;
- }
-
- @Override
- public boolean onContextClick(MotionEvent e) {
- toast(mContext, "Context click received.");
- return true;
- }
-
- @Override
- public void onPerformHapticFeedback() {
- mRecView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- }
- };
-
- private static final class TouchCallbacks extends TouchInputHandler.Callbacks {
-
- private final Context mContext;
- private final RecyclerView mRecView;
-
- private TouchCallbacks(Context context, RecyclerView recView) {
-
- mContext = context;
- mRecView = recView;
- }
-
- @Override
- public boolean onItemActivated(ItemDetails item, MotionEvent e) {
- toast(mContext, "Activate item: " + item.getStableId());
- return true;
- }
-
- @Override
- public void onPerformHapticFeedback() {
- mRecView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- }
- }
-} \ No newline at end of file
diff --git a/src/com/android/documentsui/selection/demo/SelectionDemoAdapter.java b/src/com/android/documentsui/selection/demo/SelectionDemoAdapter.java
deleted file mode 100644
index e70b335c5..000000000
--- a/src/com/android/documentsui/selection/demo/SelectionDemoAdapter.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection.demo;
-
-import android.content.Context;
-import androidx.annotation.Nullable;
-import androidx.recyclerview.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-
-import com.android.documentsui.R;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-final class SelectionDemoAdapter extends RecyclerView.Adapter<DemoHolder> {
-
- private static final Map<String, DemoItem> sDemoData = new HashMap<>();
- static {
- for (int i = 0; i < 1000; i++) {
- String id = createId(i);
- sDemoData.put(id, new DemoItem(id, "item" + i));
- }
- }
-
- private final Context mContext;
- private @Nullable OnBindCallback mBindCallback;
-
- SelectionDemoAdapter(Context context) {
- mContext = context;
- }
-
- void addOnBindCallback(OnBindCallback bindCallback) {
- mBindCallback = bindCallback;
- }
-
- void loadData() {
- onDataReady();
- }
-
- private void onDataReady() {
- notifyDataSetChanged();
- }
-
- @Override
- public int getItemCount() {
- return sDemoData.size();
- }
-
- @Override
- public void onBindViewHolder(DemoHolder holder, int position) {
- String id = createId(position);
- holder.update(sDemoData.get(id));
- if (mBindCallback != null) {
- mBindCallback.onBound(holder, position);
- }
- }
-
- private static String createId(int position) {
- return "id" + position;
- }
-
- @Override
- public DemoHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- LinearLayout layout = inflateLayout(mContext, parent, R.layout.selection_demo_list_item);
- return new DemoHolder(layout);
- }
-
- String getStableId(int position) {
- return createId(position);
- }
-
- int getPosition(String id) {
- return Integer.parseInt(id.substring(2));
- }
-
- List<String> getStableIds() {
- return new ArrayList<>(sDemoData.keySet());
- }
-
- @SuppressWarnings("TypeParameterUnusedInFormals") // Convenience to avoid clumsy cast.
- private static <V extends View> V inflateLayout(
- Context context, ViewGroup parent, int layout) {
-
- return (V) LayoutInflater.from(context).inflate(layout, parent, false);
- }
-
- static abstract class OnBindCallback {
- abstract void onBound(DemoHolder holder, int position);
- }
-}
diff --git a/tests/common/com/android/documentsui/SelectionHelpers.java b/tests/common/com/android/documentsui/SelectionHelpers.java
new file mode 100644
index 000000000..2018252cb
--- /dev/null
+++ b/tests/common/com/android/documentsui/SelectionHelpers.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 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.documentsui;
+
+import androidx.recyclerview.selection.DefaultSelectionTracker;
+import androidx.recyclerview.selection.SelectionPredicates;
+import androidx.recyclerview.selection.SelectionTracker;
+import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
+import androidx.recyclerview.selection.StorageStrategy;
+
+import com.android.documentsui.testing.TestStableIdProvider;
+
+import java.util.Collections;
+import java.util.List;
+
+public class SelectionHelpers {
+
+ public static final SelectionPredicate<String> CAN_SET_ANYTHING =
+ SelectionPredicates.createSelectAnything();
+
+ private SelectionHelpers() {}
+
+ public static DocsSelectionHelper createTestInstance() {
+ return createTestInstance(Collections.emptyList());
+ }
+
+ public static DocsSelectionHelper createTestInstance(List<String> docs) {
+ DocsSelectionHelper manager = new DocsSelectionHelper(
+ new DocsSelectionHelper.DelegateFactory() {
+
+ @Override
+ SelectionTracker<String> create(SelectionTracker<String> selectionTracker) {
+ return new DefaultSelectionTracker<String>(
+ Integer.toHexString(System.identityHashCode(docs)),
+ new TestStableIdProvider(docs),
+ CAN_SET_ANYTHING,
+ StorageStrategy.createStringStorage());
+ }
+ });
+
+ manager.reset(null);
+ return manager;
+ }
+}
diff --git a/tests/common/com/android/documentsui/dirlist/TestDocumentsAdapter.java b/tests/common/com/android/documentsui/dirlist/TestDocumentsAdapter.java
index 2427dc0ca..c7ccaf99f 100644
--- a/tests/common/com/android/documentsui/dirlist/TestDocumentsAdapter.java
+++ b/tests/common/com/android/documentsui/dirlist/TestDocumentsAdapter.java
@@ -18,13 +18,13 @@ package com.android.documentsui.dirlist;
import static org.junit.Assert.assertTrue;
+import androidx.recyclerview.selection.SelectionTracker;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
import android.view.ViewGroup;
import com.android.documentsui.Model.Update;
import com.android.documentsui.base.EventListener;
-import com.android.documentsui.selection.SelectionHelper;
import com.android.documentsui.testing.TestEventListener;
import java.util.ArrayList;
@@ -51,7 +51,7 @@ public class TestDocumentsAdapter extends DocumentsAdapter {
@Override
public void onItemRangeChanged(int startPosition, int itemCount, Object payload) {
- if (SelectionHelper.SELECTION_CHANGED_MARKER.equals(payload)) {
+ if (SelectionTracker.SELECTION_CHANGED_MARKER.equals(payload)) {
int last = startPosition + itemCount;
for (int i = startPosition; i < last; i++) {
mSelectionChanged.add(i);
diff --git a/tests/common/com/android/documentsui/dirlist/TestFocusHandler.java b/tests/common/com/android/documentsui/dirlist/TestFocusHandler.java
index 8dfbdeaa5..565665566 100644
--- a/tests/common/com/android/documentsui/dirlist/TestFocusHandler.java
+++ b/tests/common/com/android/documentsui/dirlist/TestFocusHandler.java
@@ -59,7 +59,7 @@ public final class TestFocusHandler implements FocusHandler {
}
@Override
- public int getFocusPosition() {
+ public int getFocusedPosition() {
return focusPos;
}
diff --git a/tests/common/com/android/documentsui/testing/SelectionHelpers.java b/tests/common/com/android/documentsui/testing/SelectionHelpers.java
deleted file mode 100644
index 70bc44d91..000000000
--- a/tests/common/com/android/documentsui/testing/SelectionHelpers.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.testing;
-
-import com.android.documentsui.DocsSelectionHelper;
-import com.android.documentsui.dirlist.DocsStableIdProvider;
-import com.android.documentsui.dirlist.DocumentsAdapter;
-import com.android.documentsui.dirlist.TestDocumentsAdapter;
-import com.android.documentsui.selection.DefaultSelectionHelper;
-import com.android.documentsui.selection.DefaultSelectionHelper.SelectionMode;
-import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
-
-import java.util.Collections;
-import java.util.List;
-
-public class SelectionHelpers {
-
- public static final SelectionPredicate CAN_SET_ANYTHING = new SelectionPredicate() {
- @Override
- public boolean canSetStateForId(String id, boolean nextState) {
- return true;
- }
-
- @Override
- public boolean canSetStateAtPosition(int position, boolean nextState) {
- return true;
- }
- };
-
- private SelectionHelpers() {}
-
- public static DocsSelectionHelper createTestInstance() {
- return createTestInstance(Collections.emptyList());
- }
-
- public static DocsSelectionHelper createTestInstance(List<String> docs) {
- return createTestInstance(docs, DefaultSelectionHelper.MODE_MULTIPLE);
- }
-
- public static DocsSelectionHelper createTestInstance(
- List<String> docs, @SelectionMode int mode) {
- return createTestInstance(new TestDocumentsAdapter(docs), mode, CAN_SET_ANYTHING);
- }
-
- public static DocsSelectionHelper createTestInstance(
- DocumentsAdapter adapter, @SelectionMode int mode, SelectionPredicate canSetState) {
- DocsSelectionHelper manager = mode == DefaultSelectionHelper.MODE_SINGLE
- ? DocsSelectionHelper.createSingleSelect()
- : DocsSelectionHelper.createMultiSelect();
-
- manager.reset(adapter, new DocsStableIdProvider(adapter), canSetState);
-
- return manager;
- }
-}
diff --git a/tests/common/com/android/documentsui/testing/TestActionHandler.java b/tests/common/com/android/documentsui/testing/TestActionHandler.java
index cd3fb1acf..7b11d41f4 100644
--- a/tests/common/com/android/documentsui/testing/TestActionHandler.java
+++ b/tests/common/com/android/documentsui/testing/TestActionHandler.java
@@ -18,11 +18,12 @@ package com.android.documentsui.testing;
import android.content.Intent;
+import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
+
import com.android.documentsui.AbstractActionHandler;
import com.android.documentsui.TestActivity;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.RootInfo;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
import java.util.function.Consumer;
@@ -30,7 +31,7 @@ public class TestActionHandler extends AbstractActionHandler<TestActivity> {
private final TestEnv mEnv;
- public final TestEventHandler<ItemDetails> open = new TestEventHandler<>();
+ public final TestEventHandler<ItemDetails<String>> open = new TestEventHandler<>();
public boolean mDeleteHappened;
public DocumentInfo nextRootDocument;
@@ -53,7 +54,7 @@ public class TestActionHandler extends AbstractActionHandler<TestActivity> {
}
@Override
- public boolean openItem(ItemDetails doc, @ViewType int type, @ViewType int fallback) {
+ public boolean openItem(ItemDetails<String> doc, @ViewType int type, @ViewType int fallback) {
return open.accept(doc);
}
diff --git a/tests/common/com/android/documentsui/testing/TestDocumentClipper.java b/tests/common/com/android/documentsui/testing/TestDocumentClipper.java
index 3d6c9ad38..9fa4f2e55 100644
--- a/tests/common/com/android/documentsui/testing/TestDocumentClipper.java
+++ b/tests/common/com/android/documentsui/testing/TestDocumentClipper.java
@@ -20,10 +20,11 @@ import android.content.ClipData;
import android.net.Uri;
import android.util.Pair;
+import androidx.recyclerview.selection.Selection;
+
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.DocumentStack;
import com.android.documentsui.clipping.DocumentClipper;
-import com.android.documentsui.selection.Selection;
import com.android.documentsui.services.FileOperationService;
import com.android.documentsui.services.FileOperationService.OpType;
import com.android.documentsui.services.FileOperations.Callback;
@@ -49,8 +50,8 @@ public class TestDocumentClipper implements DocumentClipper {
}
@Override
- public ClipData getClipDataForDocuments(Function<String, Uri> uriBuilder, Selection selection,
- int opType) {
+ public ClipData getClipDataForDocuments(
+ Function<String, Uri> uriBuilder, Selection<String> selection, int opType) {
return nextClip;
}
@@ -67,11 +68,11 @@ public class TestDocumentClipper implements DocumentClipper {
}
@Override
- public void clipDocumentsForCopy(Function<String, Uri> uriBuilder, Selection selection) {
+ public void clipDocumentsForCopy(Function<String, Uri> uriBuilder, Selection<String> selection) {
}
@Override
- public void clipDocumentsForCut(Function<String, Uri> uriBuilder, Selection selection,
+ public void clipDocumentsForCut(Function<String, Uri> uriBuilder, Selection<String> selection,
DocumentInfo parent) {
List<Uri> uris = new ArrayList<>(selection.size());
for (String id : selection) {
diff --git a/tests/common/com/android/documentsui/testing/TestEnv.java b/tests/common/com/android/documentsui/testing/TestEnv.java
index 40b5e0aee..93cc032a1 100644
--- a/tests/common/com/android/documentsui/testing/TestEnv.java
+++ b/tests/common/com/android/documentsui/testing/TestEnv.java
@@ -23,6 +23,7 @@ import android.test.mock.MockContentResolver;
import com.android.documentsui.DocsSelectionHelper;
import com.android.documentsui.FocusManager;
import com.android.documentsui.Injector;
+import com.android.documentsui.SelectionHelpers;
import com.android.documentsui.archives.ArchivesProvider;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.Features;
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestSelectionPredicate.java b/tests/common/com/android/documentsui/testing/TestStableIdProvider.java
index 578be3db3..b1acc25dd 100644
--- a/tests/unit/com/android/documentsui/selection/testing/TestSelectionPredicate.java
+++ b/tests/common/com/android/documentsui/testing/TestStableIdProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -13,24 +13,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.documentsui.selection.testing;
-import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+package com.android.documentsui.testing;
-public final class TestSelectionPredicate extends SelectionPredicate {
- private boolean mValue;
+import com.android.documentsui.DocsSelectionHelper.StableIdProvider;
- public void setReturnValue(boolean value) {
- mValue = value;
+import java.util.List;
+
+public class TestStableIdProvider extends StableIdProvider {
+
+ private final List<String> mDocs;
+
+ public TestStableIdProvider(List<String> docs) {
+ mDocs = docs;
}
@Override
- public boolean canSetStateForId(String id, boolean nextState) {
- return mValue;
+ public String getKey(int position) {
+ return mDocs.get(position);
}
@Override
- public boolean canSetStateAtPosition(int position, boolean nextState) {
- return mValue;
+ public int getPosition(String id) {
+ return mDocs.indexOf(id);
}
-} \ No newline at end of file
+}
diff --git a/tests/unit/com/android/documentsui/AbstractActionHandlerTest.java b/tests/unit/com/android/documentsui/AbstractActionHandlerTest.java
index d9c551725..cc267bcc0 100644
--- a/tests/unit/com/android/documentsui/AbstractActionHandlerTest.java
+++ b/tests/unit/com/android/documentsui/AbstractActionHandlerTest.java
@@ -28,11 +28,12 @@ import android.provider.DocumentsContract.Path;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
+import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
+
import com.android.documentsui.base.DocumentStack;
import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.Shared;
import com.android.documentsui.files.LauncherActivity;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
import com.android.documentsui.sorting.SortDimension;
import com.android.documentsui.sorting.SortModel;
import com.android.documentsui.testing.DocumentStackAsserts;
@@ -77,7 +78,8 @@ public class AbstractActionHandlerTest {
}
@Override
- public boolean openItem(ItemDetails doc, @ViewType int type, @ViewType int fallback) {
+ public boolean openItem(
+ ItemDetails<String> doc, @ViewType int type, @ViewType int fallback) {
throw new UnsupportedOperationException();
}
diff --git a/tests/unit/com/android/documentsui/DocsSelectionHelperTest.java b/tests/unit/com/android/documentsui/DocsSelectionHelperTest.java
index f30464788..de536f581 100644
--- a/tests/unit/com/android/documentsui/DocsSelectionHelperTest.java
+++ b/tests/unit/com/android/documentsui/DocsSelectionHelperTest.java
@@ -23,14 +23,11 @@ import static org.junit.Assert.assertTrue;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import androidx.recyclerview.widget.RecyclerView.Adapter;
+
+import androidx.recyclerview.selection.Selection;
+import androidx.recyclerview.selection.SelectionTracker;
import com.android.documentsui.DocsSelectionHelper.DelegateFactory;
-import com.android.documentsui.selection.DefaultSelectionHelper;
-import com.android.documentsui.selection.Selection;
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
-import com.android.documentsui.selection.SelectionHelper.StableIdProvider;
import org.junit.Before;
import org.junit.Test;
@@ -40,7 +37,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* Tests for the specialized behaviors provided by DocsSelectionManager.
@@ -57,20 +53,16 @@ public class DocsSelectionHelperTest {
public void setup() {
mCreated = new ArrayList<>();
mFactory = new DelegateFactory() {
- @Override
- TestSelectionManager create(
- int mode,
- Adapter<?> adapter,
- StableIdProvider stableIds,
- SelectionPredicate canSetState) {
+ @Override
+ TestSelectionManager create(SelectionTracker<String> selectionTracker) {
TestSelectionManager mgr = new TestSelectionManager();
mCreated.add(mgr);
return mgr;
}
};
- mSelectionMgr = new DocsSelectionHelper(mFactory, DefaultSelectionHelper.MODE_MULTIPLE);
+ mSelectionMgr = new DocsSelectionHelper(mFactory);
}
@Test
@@ -82,16 +74,16 @@ public class DocsSelectionHelperTest {
@Test
public void testReset_CreatesNewInstances() {
- mSelectionMgr.reset(null, null, null); // nulls are passed to factory. We ignore.
- mSelectionMgr.reset(null, null, null); // nulls are passed to factory. We ignore.
+ resetSelectionHelper();
+ resetSelectionHelper();
assertCreated(2);
}
@Test
public void testReset_ClearsPreviousSelection() {
- mSelectionMgr.reset(null, null, null); // nulls are passed to factory. We ignore.
- mSelectionMgr.reset(null, null, null); // nulls are passed to factory. We ignore.
+ resetSelectionHelper();
+ resetSelectionHelper();
mCreated.get(0).assertCleared(true);
mCreated.get(1).assertCleared(false);
@@ -99,7 +91,7 @@ public class DocsSelectionHelperTest {
@Test
public void testReplaceSelection() {
- mSelectionMgr.reset(null, null, null); // nulls are passed to factory. We ignore.
+ resetSelectionHelper();
List<String> ids = new ArrayList<>();
ids.add("poodles");
@@ -113,7 +105,11 @@ public class DocsSelectionHelperTest {
assertEquals(count, mCreated.size());
}
- private static final class TestSelectionManager extends SelectionHelper {
+ private void resetSelectionHelper() {
+ mSelectionMgr.reset(null); // nulls are passed to factory. We ignore.
+ }
+
+ private static final class TestSelectionManager extends DummySelectionTracker<String> {
private boolean mCleared;
private Map<String, Boolean> mSelected = new HashMap<>();
@@ -141,12 +137,7 @@ public class DocsSelectionHelperTest {
}
@Override
- public Selection getSelection() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void copySelection(Selection dest) {
+ public Selection<String> getSelection() {
throw new UnsupportedOperationException();
}
@@ -156,7 +147,7 @@ public class DocsSelectionHelperTest {
}
@Override
- public void restoreSelection(Selection other) {
+ public void restoreSelection(Selection<String> other) {
throw new UnsupportedOperationException();
}
@@ -169,8 +160,9 @@ public class DocsSelectionHelperTest {
}
@Override
- public void clearSelection() {
+ public boolean clearSelection() {
mCleared = true;
+ return true;
}
@Override
@@ -182,50 +174,5 @@ public class DocsSelectionHelperTest {
public boolean deselect(String itemId) {
throw new UnsupportedOperationException();
}
-
- @Override
- public void startRange(int pos) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void extendRange(int pos) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void endRange() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isRangeActive() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void anchorRange(int position) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void extendProvisionalRange(int pos) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void clearProvisionalSelection() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void mergeProvisionalSelection() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setProvisionalSelection(Set<String> newSelection) {
- throw new UnsupportedOperationException();
- }
}
}
diff --git a/tests/unit/com/android/documentsui/DragScrollListenerTest.java b/tests/unit/com/android/documentsui/DragScrollListenerTest.java
index dd7db92d1..029228bfa 100644
--- a/tests/unit/com/android/documentsui/DragScrollListenerTest.java
+++ b/tests/unit/com/android/documentsui/DragScrollListenerTest.java
@@ -23,7 +23,7 @@ import android.support.test.runner.AndroidJUnit4;
import android.view.DragEvent;
import android.view.View;
-import com.android.documentsui.selection.ViewAutoScroller.ScrollerCallbacks;
+import com.android.documentsui.ViewAutoScroller.ScrollerCallbacks;
import com.android.documentsui.testing.DragEvents;
import com.android.documentsui.testing.Views;
diff --git a/tests/unit/com/android/documentsui/FocusManagerTest.java b/tests/unit/com/android/documentsui/FocusManagerTest.java
index 16301b729..15f703d54 100644
--- a/tests/unit/com/android/documentsui/FocusManagerTest.java
+++ b/tests/unit/com/android/documentsui/FocusManagerTest.java
@@ -16,17 +16,16 @@
package com.android.documentsui;
-import androidx.recyclerview.widget.RecyclerView;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.documentsui.base.Features;
+import androidx.recyclerview.selection.SelectionTracker;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.android.documentsui.dirlist.TestData;
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.testing.TestModel;
-import com.android.documentsui.testing.SelectionHelpers;
import com.android.documentsui.testing.TestFeatures;
import com.android.documentsui.testing.TestGridLayoutManager;
+import com.android.documentsui.testing.TestModel;
import com.android.documentsui.testing.TestRecyclerView;
import com.android.documentsui.testing.Views;
@@ -43,7 +42,7 @@ public class FocusManagerTest extends AndroidTestCase {
private FocusManager mManager;
private TestRecyclerView mView;
private TestGridLayoutManager mTestGridLayoutManager;
- private SelectionHelper mSelectionMgr;
+ private SelectionTracker<String> mSelectionMgr;
private TestFeatures mFeatures;
@Override
diff --git a/tests/unit/com/android/documentsui/SharedInputHandlerTest.java b/tests/unit/com/android/documentsui/SharedInputHandlerTest.java
index e66c5c05f..4b6151969 100644
--- a/tests/unit/com/android/documentsui/SharedInputHandlerTest.java
+++ b/tests/unit/com/android/documentsui/SharedInputHandlerTest.java
@@ -25,10 +25,10 @@ import android.support.test.runner.AndroidJUnit4;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import androidx.recyclerview.selection.SelectionTracker;
+
import com.android.documentsui.base.Procedure;
import com.android.documentsui.dirlist.TestFocusHandler;
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.testing.SelectionHelpers;
import com.android.documentsui.testing.TestDrawerController;
import com.android.documentsui.testing.TestFeatures;
@@ -41,7 +41,7 @@ import org.junit.runner.RunWith;
public class SharedInputHandlerTest {
private SharedInputHandler mSharedInputHandler;
- private SelectionHelper mSelectionMgr = SelectionHelpers.createTestInstance();
+ private SelectionTracker<String> mSelectionMgr = SelectionHelpers.createTestInstance();
private TestFeatures mFeatures = new TestFeatures();
private TestFocusHandler mFocusHandler = new TestFocusHandler();
private TestDrawerController mDrawer = TestDrawerController.create();
diff --git a/tests/unit/com/android/documentsui/selection/ViewAutoScrollerTest.java b/tests/unit/com/android/documentsui/ViewAutoScrollerTest.java
index b75c3daab..b3426d30d 100644
--- a/tests/unit/com/android/documentsui/selection/ViewAutoScrollerTest.java
+++ b/tests/unit/com/android/documentsui/ViewAutoScrollerTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.documentsui.selection;
+package com.android.documentsui;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -23,8 +23,9 @@ import android.graphics.Point;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import com.android.documentsui.selection.ViewAutoScroller.ScrollHost;
-import com.android.documentsui.selection.ViewAutoScroller.ScrollerCallbacks;
+import com.android.documentsui.ViewAutoScroller;
+import com.android.documentsui.ViewAutoScroller.ScrollHost;
+import com.android.documentsui.ViewAutoScroller.ScrollerCallbacks;
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/unit/com/android/documentsui/dirlist/DocumentHolderTest.java b/tests/unit/com/android/documentsui/dirlist/DocumentHolderTest.java
index f2187e478..d201a54af 100644
--- a/tests/unit/com/android/documentsui/dirlist/DocumentHolderTest.java
+++ b/tests/unit/com/android/documentsui/dirlist/DocumentHolderTest.java
@@ -30,7 +30,6 @@ import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
import com.android.documentsui.R;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
@SmallTest
public class DocumentHolderTest extends AndroidTestCase {
@@ -99,9 +98,9 @@ public class DocumentHolderTest extends AndroidTestCase {
);
}
- private class TestListener extends KeyboardEventListener {
+ private class TestListener extends KeyboardEventListener<DocumentItemDetails> {
@Override
- public boolean onKey(ItemDetails item, int keyCode, KeyEvent event) {
+ public boolean onKey(DocumentItemDetails item, int keyCode, KeyEvent event) {
return false;
}
diff --git a/tests/unit/com/android/documentsui/dirlist/DragHostTest.java b/tests/unit/com/android/documentsui/dirlist/DragHostTest.java
index 7db69dca3..bb760ad25 100644
--- a/tests/unit/com/android/documentsui/dirlist/DragHostTest.java
+++ b/tests/unit/com/android/documentsui/dirlist/DragHostTest.java
@@ -20,18 +20,18 @@ import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import android.content.ClipData;
-import android.database.Cursor;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.DragEvent;
import android.view.View;
+import androidx.recyclerview.selection.SelectionTracker;
+
+import com.android.documentsui.SelectionHelpers;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.files.TestActivity;
-import com.android.documentsui.selection.SelectionHelper;
import com.android.documentsui.testing.ClipDatas;
import com.android.documentsui.testing.DragEvents;
-import com.android.documentsui.testing.SelectionHelpers;
import com.android.documentsui.testing.TestActionHandler;
import com.android.documentsui.testing.TestDragAndDropManager;
import com.android.documentsui.testing.TestEnv;
@@ -55,7 +55,7 @@ public class DragHostTest {
private TestDialogController mDialogs;
private DragHost<?> dragHost;
private TestDragAndDropManager mDragAndDropManager;
- private SelectionHelper mSelectionMgr;
+ private SelectionTracker<String> mSelectionMgr;
private boolean mIsDocumentView;
private DocumentHolder mNextDocumentHolder;
private DocumentInfo mNextDocumentInfo;
diff --git a/tests/unit/com/android/documentsui/dirlist/DragStartListenerTest.java b/tests/unit/com/android/documentsui/dirlist/DragStartListenerTest.java
index faa86a394..b5739763b 100644
--- a/tests/unit/com/android/documentsui/dirlist/DragStartListenerTest.java
+++ b/tests/unit/com/android/documentsui/dirlist/DragStartListenerTest.java
@@ -18,7 +18,6 @@ package com.android.documentsui.dirlist;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
import android.provider.DocumentsContract;
import android.support.test.filters.SmallTest;
@@ -26,22 +25,21 @@ import android.support.test.runner.AndroidJUnit4;
import android.view.MotionEvent;
import android.view.View;
+import androidx.recyclerview.selection.MutableSelection;
+import androidx.recyclerview.selection.Selection;
+
import com.android.documentsui.DocsSelectionHelper;
import com.android.documentsui.MenuManager.SelectionDetails;
+import com.android.documentsui.SelectionHelpers;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.Events;
import com.android.documentsui.base.Providers;
import com.android.documentsui.base.State;
import com.android.documentsui.dirlist.DragStartListener.RuntimeDragStartListener;
-import com.android.documentsui.selection.MutableSelection;
-import com.android.documentsui.selection.Selection;
-import com.android.documentsui.selection.TestItemDetailsLookup;
-import com.android.documentsui.testing.SelectionHelpers;
import com.android.documentsui.testing.TestDragAndDropManager;
import com.android.documentsui.testing.TestEvents;
import com.android.documentsui.testing.TestSelectionDetails;
import com.android.documentsui.testing.Views;
-import com.android.internal.widget.RecyclerView;
import org.junit.Before;
import org.junit.Test;
@@ -79,7 +77,6 @@ public class DragStartListenerTest {
mListener = new DragStartListener.RuntimeDragStartListener(
null, // icon helper
state,
- mDocLookup,
mSelectionMgr,
mSelectionDetails,
// view finder
@@ -91,7 +88,7 @@ public class DragStartListenerTest {
return mViewModelId;
},
// docInfo Converter
- (Selection selection) -> {
+ (Selection<String> selection) -> {
return new ArrayList<>();
},
mManager);
@@ -107,47 +104,29 @@ public class DragStartListenerTest {
@Test
public void testMouseEvent() {
- assertTrue(Events.isMouseDragEvent(mEvent.build()));
+ MotionEvent e = mEvent.build();
+ // Assert it is a mouse drag event.
+ assertTrue(Events.isMouseEvent(e));
+ assertTrue(e.getActionMasked() == MotionEvent.ACTION_MOVE);
+ assertTrue(e.isButtonPressed(MotionEvent.BUTTON_PRIMARY));
}
@Test
public void testDragStarted_OnMouseMove() {
- assertTrue(mListener.onMouseDragEvent(mEvent.build()));
+ assertTrue(mListener.onDragEvent(mEvent.build()));
mManager.startDragHandler.assertCalled();
}
@Test
public void testDragNotStarted_NonModelBackedView() {
mViewModelId = null;
- assertFalse(mListener.onMouseDragEvent(mEvent.build()));
+ assertFalse(mListener.onDragEvent(mEvent.build()));
mManager.startDragHandler.assertNotCalled();
}
@Test
- public void testThrows_OnNonMouseMove() {
- assertThrows(mEvent.touch().build());
- }
-
- @Test
- public void testThrows_OnNonPrimaryMove() {
- mEvent.releaseButton(MotionEvent.BUTTON_PRIMARY);
- assertThrows(mEvent.pressButton(MotionEvent.BUTTON_SECONDARY).build());
- }
-
- @Test
- public void testThrows_OnNonMove() {
- assertThrows(mEvent.action(MotionEvent.ACTION_UP).build());
- }
-
- @Test
- public void testThrows_WhenNotOnItem() {
- mDocLookup.initAt(RecyclerView.NO_POSITION);
- assertThrows(mEvent.build());
- }
-
- @Test
public void testDragStart_nonSelectedItem() {
- Selection selection = mListener.getSelectionToBeCopied("1234",
+ Selection<String> selection = mListener.getSelectionToBeCopied("1234",
mEvent.action(MotionEvent.ACTION_MOVE).build());
assertTrue(selection.size() == 1);
assertTrue(selection.contains("1234"));
@@ -155,7 +134,7 @@ public class DragStartListenerTest {
@Test
public void testDragStart_selectedItem() {
- MutableSelection selection = new MutableSelection();
+ MutableSelection<String> selection = new MutableSelection<>();
selection.add("1234");
selection.add("5678");
mSelectionMgr.replaceSelection(selection);
@@ -169,7 +148,7 @@ public class DragStartListenerTest {
@Test
public void testDragStart_newNonSelectedItem() {
- MutableSelection selection = new MutableSelection();
+ MutableSelection<String> selection = new MutableSelection<>();
selection.add("5678");
mSelectionMgr.replaceSelection(selection);
@@ -183,7 +162,7 @@ public class DragStartListenerTest {
@Test
public void testCtrlDragStart_newNonSelectedItem() {
- MutableSelection selection = new MutableSelection();
+ MutableSelection<String> selection = new MutableSelection<>();
selection.add("5678");
mSelectionMgr.replaceSelection(selection);
@@ -193,11 +172,4 @@ public class DragStartListenerTest {
assertTrue(selection.contains("1234"));
assertTrue(selection.contains("5678"));
}
-
- private void assertThrows(MotionEvent e) {
- try {
- mListener.onMouseDragEvent(e);
- fail();
- } catch (IllegalArgumentException expected) {}
- }
}
diff --git a/tests/unit/com/android/documentsui/dirlist/KeyInputHandlerTest.java b/tests/unit/com/android/documentsui/dirlist/KeyInputHandlerTest.java
index e0313dab2..58ecf8be9 100644
--- a/tests/unit/com/android/documentsui/dirlist/KeyInputHandlerTest.java
+++ b/tests/unit/com/android/documentsui/dirlist/KeyInputHandlerTest.java
@@ -18,17 +18,15 @@ package com.android.documentsui.dirlist;
import static org.junit.Assert.assertEquals;
-import androidx.annotation.Nullable;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.KeyEvent;
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
-import com.android.documentsui.selection.testing.SelectionPredicates;
-import com.android.documentsui.selection.testing.SelectionProbe;
-import com.android.documentsui.selection.testing.TestData;
-import com.android.documentsui.testing.SelectionHelpers;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.selection.Selection;
+import androidx.recyclerview.selection.SelectionTracker;
+
+import com.android.documentsui.SelectionHelpers;
import org.junit.Before;
import org.junit.Test;
@@ -43,21 +41,19 @@ public final class KeyInputHandlerTest {
private static final List<String> ITEMS = TestData.create(100);
private KeyInputHandler mInputHandler;
- private SelectionHelper mSelectionHelper;
+ private SelectionTracker<String> mSelectionHelper;
private TestFocusHandler mFocusHandler;
- private SelectionProbe mSelection;
private TestCallbacks mCallbacks;
@Before
public void setUp() {
mSelectionHelper = SelectionHelpers.createTestInstance(ITEMS);
- mSelection = new SelectionProbe(mSelectionHelper);
mFocusHandler = new TestFocusHandler();
mCallbacks = new TestCallbacks();
mInputHandler = new KeyInputHandler(
mSelectionHelper,
- SelectionPredicates.CAN_SET_ANYTHING,
+ SelectionHelpers.CAN_SET_ANYTHING,
mCallbacks);
}
@@ -69,34 +65,32 @@ public final class KeyInputHandlerTest {
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP);
mInputHandler.onKey(null, event.getKeyCode(), event);
- mSelection.assertNoSelection();
+ Selection<String> selection = mSelectionHelper.getSelection();
+ assertEquals(selection.toString(), 0, selection.size());
}
- private static final class TestCallbacks extends KeyInputHandler.Callbacks {
+ private static final class TestCallbacks
+ extends KeyInputHandler.Callbacks<DocumentItemDetails> {
- private @Nullable ItemDetails mActivated;
+ private @Nullable DocumentItemDetails mActivated;
@Override
- public boolean isInteractiveItem(ItemDetails item, KeyEvent e) {
+ public boolean isInteractiveItem(DocumentItemDetails item, KeyEvent e) {
return true;
}
@Override
- public boolean onItemActivated(ItemDetails item, KeyEvent e) {
+ public boolean onItemActivated(DocumentItemDetails item, KeyEvent e) {
mActivated = item;
return false;
}
- private void assertActivated(ItemDetails expected) {
+ private void assertActivated(DocumentItemDetails expected) {
assertEquals(expected, mActivated);
}
@Override
- public void onPerformHapticFeedback() {
- }
-
- @Override
- public boolean onFocusItem(ItemDetails details, int keyCode, KeyEvent event) {
+ public boolean onFocusItem(DocumentItemDetails details, int keyCode, KeyEvent event) {
return true;
}
}
diff --git a/tests/unit/com/android/documentsui/selection/TestItemDetails.java b/tests/unit/com/android/documentsui/dirlist/TestItemDetails.java
index b943247d5..75e8e2409 100644
--- a/tests/unit/com/android/documentsui/selection/TestItemDetails.java
+++ b/tests/unit/com/android/documentsui/dirlist/TestItemDetails.java
@@ -13,14 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.documentsui.selection;
+package com.android.documentsui.dirlist;
import android.view.MotionEvent;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
+
import com.android.internal.widget.RecyclerView;
-public final class TestItemDetails extends ItemDetails {
+/**
+ * Test implementation of ItemDetails.
+ */
+public final class TestItemDetails extends ItemDetails<String> {
// DocumentsAdapter.ITEM_TYPE_DOCUMENT
private int mViewType = -1;
@@ -60,7 +64,6 @@ public final class TestItemDetails extends ItemDetails {
mInSelectionHotspot = over;
}
- @Override
public int getItemViewType() {
return mViewType;
}
@@ -97,7 +100,7 @@ public final class TestItemDetails extends ItemDetails {
}
@Override
- public String getStableId() {
+ public String getSelectionKey() {
return mStableId;
}
diff --git a/tests/unit/com/android/documentsui/selection/TestItemDetailsLookup.java b/tests/unit/com/android/documentsui/dirlist/TestItemDetailsLookup.java
index 66014ceaa..3ae3e2663 100644
--- a/tests/unit/com/android/documentsui/selection/TestItemDetailsLookup.java
+++ b/tests/unit/com/android/documentsui/dirlist/TestItemDetailsLookup.java
@@ -13,47 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.documentsui.selection;
+package com.android.documentsui.dirlist;
-import androidx.recyclerview.widget.RecyclerView;
import android.view.MotionEvent;
+import com.android.documentsui.DocsSelectionHelper.DocDetailsLookup;
+
import javax.annotation.Nullable;
/**
- * Test impl of ItemDetailsLookup.
+ * Test implementation of ItemDetailsLookup.
*/
-public class TestItemDetailsLookup extends ItemDetailsLookup {
+public class TestItemDetailsLookup extends DocDetailsLookup {
private @Nullable TestItemDetails mDoc;
@Override
- public boolean overItem(MotionEvent e) {
- return getItemPosition(e) != RecyclerView.NO_POSITION;
- }
-
- @Override
- public boolean overStableItem(MotionEvent e) {
- return mDoc.getStableId() != null;
- }
-
- @Override
- public boolean inItemDragRegion(MotionEvent e) {
- return mDoc.inDragRegion(e);
- }
-
- @Override
- public int getItemPosition(MotionEvent e) {
- return mDoc.getPosition();
- }
-
- @Override
- public boolean inItemSelectRegion(MotionEvent e) {
- return mDoc.inSelectionHotspot(e);
- }
-
- @Override
- public @Nullable ItemDetails getItemDetails(MotionEvent e) {
+ public @Nullable ItemDetails<String> getItemDetails(MotionEvent e) {
return mDoc;
}
diff --git a/tests/unit/com/android/documentsui/files/MenuManagerTest.java b/tests/unit/com/android/documentsui/files/MenuManagerTest.java
index 957a7318b..6cb3c5013 100644
--- a/tests/unit/com/android/documentsui/files/MenuManagerTest.java
+++ b/tests/unit/com/android/documentsui/files/MenuManagerTest.java
@@ -24,16 +24,15 @@ import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.test.AndroidTestCase;
+
+import androidx.recyclerview.selection.SelectionTracker;
import com.android.documentsui.R;
+import com.android.documentsui.SelectionHelpers;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.State;
-import com.android.documentsui.dirlist.TestContext;
import com.android.documentsui.dirlist.TestData;
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.testing.SelectionHelpers;
import com.android.documentsui.testing.TestDirectoryDetails;
import com.android.documentsui.testing.TestEnv;
import com.android.documentsui.testing.TestFeatures;
@@ -112,7 +111,7 @@ public final class MenuManagerTest {
private State state = new State();
private MenuManager mgr;
private TestActivity activity = TestActivity.create(TestEnv.create());
- private SelectionHelper selectionManager;
+ private SelectionTracker<String> selectionManager;
@Before
public void setUp() {
diff --git a/tests/unit/com/android/documentsui/selection/BandSelectionHelperTest.java b/tests/unit/com/android/documentsui/selection/BandSelectionHelperTest.java
deleted file mode 100644
index 62c6f769e..000000000
--- a/tests/unit/com/android/documentsui/selection/BandSelectionHelperTest.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
-import android.view.MotionEvent;
-
-import com.android.documentsui.selection.BandSelectionHelper.BandHost;
-import com.android.documentsui.selection.testing.SelectionPredicates;
-import com.android.documentsui.selection.testing.TestAdapter;
-import com.android.documentsui.selection.testing.TestBandPredicate;
-import com.android.documentsui.selection.testing.TestEvents.Builder;
-import com.android.documentsui.selection.testing.TestStableIdProvider;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Collections;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class BandSelectionHelperTest {
-
- private List<String> mItems;
- private BandSelectionHelper mBandController;
- private boolean mIsActive;
- private Builder mStartBuilder;
- private Builder mStopBuilder;
- private MotionEvent mStartEvent;
- private MotionEvent mStopEvent;
- private TestBandHost mBandHost;
- private TestBandPredicate mBandPredicate;
-
- @Before
- public void setup() throws Exception {
- mItems = TestAdapter.createItemList(10);
- mIsActive = false;
- TestAdapter adapter = new TestAdapter();
- adapter.updateTestModelIds(mItems);
- mBandHost = new TestBandHost();
- mBandPredicate = new TestBandPredicate();
-
- SelectionHelper helper = new DefaultSelectionHelper(
- DefaultSelectionHelper.MODE_SINGLE,
- adapter,
- new TestStableIdProvider(adapter),
- SelectionPredicates.CAN_SET_ANYTHING);
-
- mBandController = new BandSelectionHelper(
- mBandHost,
- adapter,
- new TestStableIdProvider(adapter),
- helper,
- SelectionPredicates.CAN_SET_ANYTHING,
- mBandPredicate,
- new ContentLock()) {
- @Override
- public boolean isActive() {
- return mIsActive;
- }
- };
-
- mStartBuilder = new Builder().mouse().primary().action(MotionEvent.ACTION_MOVE);
- mStopBuilder = new Builder().mouse().action(MotionEvent.ACTION_UP);
- mStartEvent = mStartBuilder.build();
- mStopEvent = mStopBuilder.build();
- }
-
- @Test
- public void testGoodStart() {
- assertTrue(mBandController.shouldStart(mStartEvent));
- }
-
- @Test
- public void testBadStart_NoButtons() {
- assertFalse(mBandController.shouldStart(
- mStartBuilder.releaseButton(MotionEvent.BUTTON_PRIMARY).build()));
- }
-
- @Test
- public void testBadStart_SecondaryButton() {
- assertFalse(
- mBandController.shouldStart(mStartBuilder.secondary().build()));
- }
-
- @Test
- public void testBadStart_TertiaryButton() {
- assertFalse(
- mBandController.shouldStart(mStartBuilder.tertiary().build()));
- }
-
- @Test
- public void testBadStart_Touch() {
- assertFalse(mBandController.shouldStart(
- mStartBuilder.touch().releaseButton(MotionEvent.BUTTON_PRIMARY).build()));
- }
-
- @Test
- public void testBadStart_RespectsCanInitiateBand() {
- mBandPredicate.setCanInitiate(false);
- assertFalse(mBandController.shouldStart(mStartEvent));
- }
-
- @Test
- public void testBadStart_ActionDown() {
- assertFalse(mBandController
- .shouldStart(mStartBuilder.action(MotionEvent.ACTION_DOWN).build()));
- }
-
- @Test
- public void testBadStart_ActionUp() {
- assertFalse(mBandController
- .shouldStart(mStartBuilder.action(MotionEvent.ACTION_UP).build()));
- }
-
- @Test
- public void testBadStart_ActionPointerDown() {
- assertFalse(mBandController.shouldStart(
- mStartBuilder.action(MotionEvent.ACTION_POINTER_DOWN).build()));
- }
-
- @Test
- public void testBadStart_ActionPointerUp() {
- assertFalse(mBandController.shouldStart(
- mStartBuilder.action(MotionEvent.ACTION_POINTER_UP).build()));
- }
-
- @Test
- public void testBadStart_NoItems() {
- TestAdapter emptyAdapter = new TestAdapter();
- emptyAdapter.updateTestModelIds(Collections.EMPTY_LIST);
-
- SelectionHelper helper = new DefaultSelectionHelper(
- DefaultSelectionHelper.MODE_SINGLE,
- emptyAdapter,
- new TestStableIdProvider(emptyAdapter),
- SelectionPredicates.CAN_SET_ANYTHING);
-
- mBandController = new BandSelectionHelper(
- new TestBandHost(),
- emptyAdapter,
- new TestStableIdProvider(emptyAdapter),
- helper,
- SelectionPredicates.CAN_SET_ANYTHING,
- mBandPredicate,
- new ContentLock());
-
- assertFalse(mBandController.shouldStart(mStartEvent));
- }
-
- @Test
- public void testBadStart_alreadyActive() {
- mIsActive = true;
- assertFalse(mBandController.shouldStart(mStartEvent));
- }
-
- @Test
- public void testGoodStop() {
- mIsActive = true;
- assertTrue(mBandController.shouldStop(mStopEvent));
- }
-
- @Test
- public void testGoodStop_PointerUp() {
- mIsActive = true;
- assertTrue(mBandController
- .shouldStop(mStopBuilder.action(MotionEvent.ACTION_POINTER_UP).build()));
- }
-
- @Test
- public void testGoodStop_Cancel() {
- mIsActive = true;
- assertTrue(mBandController
- .shouldStop(mStopBuilder.action(MotionEvent.ACTION_CANCEL).build()));
- }
-
- @Test
- public void testBadStop_NotActive() {
- assertFalse(mBandController.shouldStop(mStopEvent));
- }
-
- @Test
- public void testBadStop_NonMouse() {
- mIsActive = true;
- assertFalse(mBandController.shouldStop(mStopBuilder.touch().build()));
- }
-
- @Test
- public void testBadStop_Move() {
- mIsActive = true;
- assertFalse(mBandController.shouldStop(
- mStopBuilder.action(MotionEvent.ACTION_MOVE).touch().build()));
- }
-
- @Test
- public void testBadStop_Down() {
- mIsActive = true;
- assertFalse(mBandController.shouldStop(
- mStopBuilder.action(MotionEvent.ACTION_DOWN).touch().build()));
- }
-
- private final class TestBandHost extends BandHost {
- @Override
- public void scrollBy(int dy) {
- }
-
- @Override
- public void runAtNextFrame(Runnable r) {
- }
-
- @Override
- public void removeCallback(Runnable r) {
- }
-
- @Override
- public void showBand(Rect rect) {
- }
-
- @Override
- public void hideBand() {
- }
-
- @Override
- public void addOnScrollListener(OnScrollListener listener) {
- }
-
- @Override
- public void removeOnScrollListener(OnScrollListener listener) {
- }
-
- @Override
- public int getHeight() {
- return 0;
- }
-
- @Override
- public void invalidateView() {
- }
-
- @Override
- public Point createAbsolutePoint(Point relativePoint) {
- return null;
- }
-
- @Override
- public Rect getAbsoluteRectForChildViewAt(int index) {
- return null;
- }
-
- @Override
- public int getAdapterPositionAt(int index) {
- return 0;
- }
-
- @Override
- public int getColumnCount() {
- return 0;
- }
-
- @Override
- public int getChildCount() {
- return 0;
- }
-
- @Override
- public int getVisibleChildCount() {
- return 0;
- }
-
- @Override
- public boolean hasView(int adapterPosition) {
- return false;
- }
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/ContentLockTest.java b/tests/unit/com/android/documentsui/selection/ContentLockTest.java
deleted file mode 100644
index 71b6b0fb0..000000000
--- a/tests/unit/com/android/documentsui/selection/ContentLockTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ContentLockTest {
-
- private ContentLock mLock = new ContentLock();
- private boolean mCalled;
-
- private Runnable mRunnable = new Runnable() {
- @Override
- public void run() {
- mCalled = true;
- }
- };
-
- @Before
- public void setUp() {
- mCalled = false;
- }
-
- @Test
- public void testNotBlocking_callbackNotBlocked() {
- mLock.runWhenUnlocked(mRunnable);
- assertTrue(mCalled);
- }
-
- @Test
- public void testToggleBlocking_callbackNotBlocked() {
- mLock.block();
- mLock.unblock();
- mLock.runWhenUnlocked(mRunnable);
- assertTrue(mCalled);
- }
-
- @Test
- public void testBlocking_callbackBlocked() {
- mLock.block();
- mLock.runWhenUnlocked(mRunnable);
- assertFalse(mCalled);
- }
-
- @Test
- public void testBlockthenUnblock_callbackNotBlocked() {
- mLock.block();
- mLock.runWhenUnlocked(mRunnable);
- mLock.unblock();
- assertTrue(mCalled);
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/DefaultSelectionHelperTest.java b/tests/unit/com/android/documentsui/selection/DefaultSelectionHelperTest.java
deleted file mode 100644
index 48c0b2af0..000000000
--- a/tests/unit/com/android/documentsui/selection/DefaultSelectionHelperTest.java
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * Copyright (C) 2015 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.documentsui.selection;
-import static org.junit.Assert.assertFalse;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.util.SparseBooleanArray;
-
-import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
-import com.android.documentsui.selection.testing.SelectionProbe;
-import com.android.documentsui.selection.testing.TestAdapter;
-import com.android.documentsui.selection.testing.TestSelectionObserver;
-import com.android.documentsui.selection.testing.TestStableIdProvider;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DefaultSelectionHelperTest {
-
- private List<String> mItems;
- private Set<String> mIgnored;
- private TestAdapter mAdapter;
- private DefaultSelectionHelper mHelper;
- private TestSelectionObserver mListener;
- private SelectionProbe mSelection;
-
- @Before
- public void setUp() throws Exception {
- mIgnored = new HashSet<>();
- mItems = TestAdapter.createItemList(100);
- mListener = new TestSelectionObserver();
- mAdapter = new TestAdapter();
- mAdapter.updateTestModelIds(mItems);
-
- SelectionPredicate canSelect = new SelectionPredicate() {
-
- @Override
- public boolean canSetStateForId(String id, boolean nextState) {
- return !nextState || !mIgnored.contains(id);
- }
-
- @Override
- public boolean canSetStateAtPosition(int position, boolean nextState) {
- throw new UnsupportedOperationException("Not implemented.");
- }
- };
- mHelper = new DefaultSelectionHelper(
- DefaultSelectionHelper.MODE_MULTIPLE,
- mAdapter,
- new TestStableIdProvider(mAdapter),
- canSelect);
-
- mHelper.addObserver(mListener);
-
- mSelection = new SelectionProbe(mHelper, mListener);
-
- mIgnored.clear();
- }
-
- @Test
- public void testSelect() {
- mHelper.select(mItems.get(7));
-
- mSelection.assertSelection(7);
- }
-
- @Test
- public void testDeselect() {
- mHelper.select(mItems.get(7));
- mHelper.deselect(mItems.get(7));
-
- mSelection.assertNoSelection();
- }
-
- @Test
- public void testSelection_DoNothingOnUnselectableItem() {
- mIgnored.add(mItems.get(7));
- boolean selected = mHelper.select(mItems.get(7));
-
- assertFalse(selected);
- mSelection.assertNoSelection();
- }
-
- @Test
- public void testSelect_NotifiesListenersOfChange() {
- mHelper.select(mItems.get(7));
-
- mListener.assertSelectionChanged();
- }
-
- @Test
- public void testSelect_NotifiesAdapterOfSelect() {
- mHelper.select(mItems.get(7));
-
- mAdapter.assertNotifiedOfSelectionChange(7);
- }
-
- @Test
- public void testSelect_NotifiesAdapterOfDeselect() {
- mHelper.select(mItems.get(7));
- mAdapter.resetSelectionNotifications();
- mHelper.deselect(mItems.get(7));
- mAdapter.assertNotifiedOfSelectionChange(7);
- }
-
- @Test
- public void testDeselect_NotifiesSelectionChanged() {
- mHelper.select(mItems.get(7));
- mHelper.deselect(mItems.get(7));
-
- mListener.assertSelectionChanged();
- }
-
- @Test
- public void testSelection_PersistsOnUpdate() {
- mHelper.select(mItems.get(7));
- mAdapter.updateTestModelIds(mItems);
-
- mSelection.assertSelection(7);
- }
-
- @Test
- public void testSelection_IntersectsWithNewDataSet() {
- mHelper.select(mItems.get(99));
- mHelper.select(mItems.get(7));
-
- mAdapter.updateTestModelIds(TestAdapter.createItemList(50));
-
- mSelection.assertSelection(7);
- }
-
- @Test
- public void testSetItemsSelected() {
- mHelper.setItemsSelected(getStringIds(6, 7, 8), true);
-
- mSelection.assertRangeSelected(6, 8);
- }
-
- @Test
- public void testSetItemsSelected_SkipUnselectableItem() {
- mIgnored.add(mItems.get(7));
-
- mHelper.setItemsSelected(getStringIds(6, 7, 8), true);
-
- mSelection.assertSelected(6);
- mSelection.assertNotSelected(7);
- mSelection.assertSelected(8);
- }
-
- @Test
- public void testRangeSelection() {
- mHelper.startRange(15);
- mHelper.extendRange(19);
- mSelection.assertRangeSelection(15, 19);
- }
-
- @Test
- public void testRangeSelection_SkipUnselectableItem() {
- mIgnored.add(mItems.get(17));
-
- mHelper.startRange(15);
- mHelper.extendRange(19);
-
- mSelection.assertRangeSelected(15, 16);
- mSelection.assertNotSelected(17);
- mSelection.assertRangeSelected(18, 19);
- }
-
- @Test
- public void testRangeSelection_snapExpand() {
- mHelper.startRange(15);
- mHelper.extendRange(19);
- mHelper.extendRange(27);
- mSelection.assertRangeSelection(15, 27);
- }
-
- @Test
- public void testRangeSelection_snapContract() {
- mHelper.startRange(15);
- mHelper.extendRange(27);
- mHelper.extendRange(19);
- mSelection.assertRangeSelection(15, 19);
- }
-
- @Test
- public void testRangeSelection_snapInvert() {
- mHelper.startRange(15);
- mHelper.extendRange(27);
- mHelper.extendRange(3);
- mSelection.assertRangeSelection(3, 15);
- }
-
- @Test
- public void testRangeSelection_multiple() {
- mHelper.startRange(15);
- mHelper.extendRange(27);
- mHelper.endRange();
- mHelper.startRange(42);
- mHelper.extendRange(57);
- mSelection.assertSelectionSize(29);
- mSelection.assertRangeSelected(15, 27);
- mSelection.assertRangeSelected(42, 57);
- }
-
- @Test
- public void testProvisionalRangeSelection() {
- mHelper.startRange(13);
- mHelper.extendProvisionalRange(15);
- mSelection.assertRangeSelection(13, 15);
- mHelper.getSelection().mergeProvisionalSelection();
- mHelper.endRange();
- mSelection.assertSelectionSize(3);
- }
-
- @Test
- public void testProvisionalRangeSelection_endEarly() {
- mHelper.startRange(13);
- mHelper.extendProvisionalRange(15);
- mSelection.assertRangeSelection(13, 15);
-
- mHelper.endRange();
- // If we end range selection prematurely for provision selection, nothing should be selected
- // except the first item
- mSelection.assertSelectionSize(1);
- }
-
- @Test
- public void testProvisionalRangeSelection_snapExpand() {
- mHelper.startRange(13);
- mHelper.extendProvisionalRange(15);
- mSelection.assertRangeSelection(13, 15);
- mHelper.getSelection().mergeProvisionalSelection();
- mHelper.extendRange(18);
- mSelection.assertRangeSelection(13, 18);
- }
-
- @Test
- public void testCombinationRangeSelection_IntersectsOldSelection() {
- mHelper.startRange(13);
- mHelper.extendRange(15);
- mSelection.assertRangeSelection(13, 15);
-
- mHelper.startRange(11);
- mHelper.extendProvisionalRange(18);
- mSelection.assertRangeSelected(11, 18);
- mHelper.endRange();
- mSelection.assertRangeSelected(13, 15);
- mSelection.assertRangeSelected(11, 11);
- mSelection.assertSelectionSize(4);
- }
-
- @Test
- public void testProvisionalSelection() {
- Selection s = mHelper.getSelection();
- mSelection.assertNoSelection();
-
- // Mimicking band selection case -- BandController notifies item callback by itself.
- mListener.onItemStateChanged(mItems.get(1), true);
- mListener.onItemStateChanged(mItems.get(2), true);
-
- SparseBooleanArray provisional = new SparseBooleanArray();
- provisional.append(1, true);
- provisional.append(2, true);
- s.setProvisionalSelection(getItemIds(provisional));
- mSelection.assertSelection(1, 2);
- }
-
- @Test
- public void testProvisionalSelection_Replace() {
- Selection s = mHelper.getSelection();
-
- // Mimicking band selection case -- BandController notifies item callback by itself.
- mListener.onItemStateChanged(mItems.get(1), true);
- mListener.onItemStateChanged(mItems.get(2), true);
- SparseBooleanArray provisional = new SparseBooleanArray();
- provisional.append(1, true);
- provisional.append(2, true);
- s.setProvisionalSelection(getItemIds(provisional));
-
- mListener.onItemStateChanged(mItems.get(1), false);
- mListener.onItemStateChanged(mItems.get(2), false);
- provisional.clear();
-
- mListener.onItemStateChanged(mItems.get(3), true);
- mListener.onItemStateChanged(mItems.get(4), true);
- provisional.append(3, true);
- provisional.append(4, true);
- s.setProvisionalSelection(getItemIds(provisional));
- mSelection.assertSelection(3, 4);
- }
-
- @Test
- public void testProvisionalSelection_IntersectsExistingProvisionalSelection() {
- Selection s = mHelper.getSelection();
-
- // Mimicking band selection case -- BandController notifies item callback by itself.
- mListener.onItemStateChanged(mItems.get(1), true);
- mListener.onItemStateChanged(mItems.get(2), true);
- SparseBooleanArray provisional = new SparseBooleanArray();
- provisional.append(1, true);
- provisional.append(2, true);
- s.setProvisionalSelection(getItemIds(provisional));
-
- mListener.onItemStateChanged(mItems.get(1), false);
- mListener.onItemStateChanged(mItems.get(2), false);
- provisional.clear();
-
- mListener.onItemStateChanged(mItems.get(1), true);
- provisional.append(1, true);
- s.setProvisionalSelection(getItemIds(provisional));
- mSelection.assertSelection(1);
- }
-
- @Test
- public void testProvisionalSelection_Apply() {
- Selection s = mHelper.getSelection();
-
- // Mimicking band selection case -- BandController notifies item callback by itself.
- mListener.onItemStateChanged(mItems.get(1), true);
- mListener.onItemStateChanged(mItems.get(2), true);
- SparseBooleanArray provisional = new SparseBooleanArray();
- provisional.append(1, true);
- provisional.append(2, true);
- s.setProvisionalSelection(getItemIds(provisional));
- s.mergeProvisionalSelection();
-
- mSelection.assertSelection(1, 2);
- }
-
- @Test
- public void testProvisionalSelection_Cancel() {
- mHelper.select(mItems.get(1));
- mHelper.select(mItems.get(2));
- Selection s = mHelper.getSelection();
-
- SparseBooleanArray provisional = new SparseBooleanArray();
- provisional.append(3, true);
- provisional.append(4, true);
- s.setProvisionalSelection(getItemIds(provisional));
- s.clearProvisionalSelection();
-
- // Original selection should remain.
- mSelection.assertSelection(1, 2);
- }
-
- @Test
- public void testProvisionalSelection_IntersectsAppliedSelection() {
- mHelper.select(mItems.get(1));
- mHelper.select(mItems.get(2));
- Selection s = mHelper.getSelection();
-
- // Mimicking band selection case -- BandController notifies item callback by itself.
- mListener.onItemStateChanged(mItems.get(3), true);
- SparseBooleanArray provisional = new SparseBooleanArray();
- provisional.append(2, true);
- provisional.append(3, true);
- s.setProvisionalSelection(getItemIds(provisional));
- mSelection.assertSelection(1, 2, 3);
- }
-
- @Test
- public void testObserverOnChanged_NotifiesListenersOfChange() {
- mAdapter.notifyDataSetChanged();
-
- mListener.assertSelectionChanged();
- }
-
- private Set<String> getItemIds(SparseBooleanArray selection) {
- Set<String> ids = new HashSet<>();
-
- int count = selection.size();
- for (int i = 0; i < count; ++i) {
- ids.add(mItems.get(selection.keyAt(i)));
- }
-
- return ids;
- }
-
- private Iterable<String> getStringIds(int... ids) {
- List<String> stringIds = new ArrayList<>(ids.length);
- for (int id : ids) {
- stringIds.add(mItems.get(id));
- }
- return stringIds;
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/DefaultSelectionHelper_SingleSelectTest.java b/tests/unit/com/android/documentsui/selection/DefaultSelectionHelper_SingleSelectTest.java
deleted file mode 100644
index 563ce87df..000000000
--- a/tests/unit/com/android/documentsui/selection/DefaultSelectionHelper_SingleSelectTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2015 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.documentsui.selection;
-
-import static org.junit.Assert.fail;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.android.documentsui.selection.testing.SelectionPredicates;
-import com.android.documentsui.selection.testing.SelectionProbe;
-import com.android.documentsui.selection.testing.TestAdapter;
-import com.android.documentsui.selection.testing.TestSelectionObserver;
-import com.android.documentsui.selection.testing.TestStableIdProvider;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DefaultSelectionHelper_SingleSelectTest {
-
- private List<String> mItems;
- private SelectionHelper mHelper;
- private TestSelectionObserver mListener;
- private SelectionProbe mSelection;
-
- @Before
- public void setUp() throws Exception {
- mItems = TestAdapter.createItemList(100);
- mListener = new TestSelectionObserver();
- TestAdapter adapter = new TestAdapter();
- adapter.updateTestModelIds(mItems);
-
- mHelper = new DefaultSelectionHelper(
- DefaultSelectionHelper.MODE_SINGLE,
- adapter,
- new TestStableIdProvider(adapter),
- SelectionPredicates.CAN_SET_ANYTHING);
-
- mHelper.addObserver(mListener);
-
- mSelection = new SelectionProbe(mHelper);
- }
-
- @Test
- public void testSimpleSelect() {
- mHelper.select(mItems.get(3));
- mHelper.select(mItems.get(4));
- mListener.assertSelectionChanged();
- mSelection.assertSelection(4);
- }
-
- @Test
- public void testRangeSelectionNotEstablished() {
- mHelper.select(mItems.get(3));
- mListener.reset();
-
- try {
- mHelper.extendRange(10);
- fail("Should have thrown.");
- } catch (Exception expected) {}
-
- mListener.assertSelectionUnchanged();
- mSelection.assertSelection(3);
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/GestureRouterTest.java b/tests/unit/com/android/documentsui/selection/GestureRouterTest.java
deleted file mode 100644
index e467f0fd0..000000000
--- a/tests/unit/com/android/documentsui/selection/GestureRouterTest.java
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyFloat;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.view.GestureDetector.OnDoubleTapListener;
-import android.view.GestureDetector.OnGestureListener;
-import android.view.MotionEvent;
-
-import com.android.documentsui.selection.testing.TestEvents.Mouse;
-import com.android.documentsui.selection.testing.TestEvents.Touch;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public final class GestureRouterTest {
-
- private TestHandler mHandler;
- private TestHandler mAlt;
- private GestureRouter<TestHandler> mRouter;
-
- @Before
- public void setUp() {
- mAlt = new TestHandler();
- mHandler = new TestHandler();
- }
-
- @Test
- public void testDelegates() {
- mRouter = new GestureRouter<>();
- mRouter.register(MotionEvent.TOOL_TYPE_MOUSE, mHandler);
- mRouter.register(MotionEvent.TOOL_TYPE_FINGER, mAlt);
-
- mRouter.onDown(Mouse.CLICK);
- mHandler.assertCalled_onDown(Mouse.CLICK);
- mAlt.assertNotCalled_onDown();
-
- mRouter.onShowPress(Mouse.CLICK);
- mHandler.assertCalled_onShowPress(Mouse.CLICK);
- mAlt.assertNotCalled_onShowPress();
-
- mRouter.onSingleTapUp(Mouse.CLICK);
- mHandler.assertCalled_onSingleTapUp(Mouse.CLICK);
- mAlt.assertNotCalled_onSingleTapUp();
-
- mRouter.onScroll(null, Mouse.CLICK, -1, -1);
- mHandler.assertCalled_onScroll(null, Mouse.CLICK, -1, -1);
- mAlt.assertNotCalled_onScroll();
-
- mRouter.onLongPress(Mouse.CLICK);
- mHandler.assertCalled_onLongPress(Mouse.CLICK);
- mAlt.assertNotCalled_onLongPress();
-
- mRouter.onFling(null, Mouse.CLICK, -1, -1);
- mHandler.assertCalled_onFling(null, Mouse.CLICK, -1, -1);
- mAlt.assertNotCalled_onFling();
-
- mRouter.onSingleTapConfirmed(Mouse.CLICK);
- mHandler.assertCalled_onSingleTapConfirmed(Mouse.CLICK);
- mAlt.assertNotCalled_onSingleTapConfirmed();
-
- mRouter.onDoubleTap(Mouse.CLICK);
- mHandler.assertCalled_onDoubleTap(Mouse.CLICK);
- mAlt.assertNotCalled_onDoubleTap();
-
- mRouter.onDoubleTapEvent(Mouse.CLICK);
- mHandler.assertCalled_onDoubleTapEvent(Mouse.CLICK);
- mAlt.assertNotCalled_onDoubleTapEvent();
- }
-
- @Test
- public void testFallsback() {
- mRouter = new GestureRouter<>(mAlt);
- mRouter.register(MotionEvent.TOOL_TYPE_MOUSE, mHandler);
-
- mRouter.onDown(Touch.TAP);
- mAlt.assertCalled_onDown(Touch.TAP);
-
- mRouter.onShowPress(Touch.TAP);
- mAlt.assertCalled_onShowPress(Touch.TAP);
-
- mRouter.onSingleTapUp(Touch.TAP);
- mAlt.assertCalled_onSingleTapUp(Touch.TAP);
-
- mRouter.onScroll(null, Touch.TAP, -1, -1);
- mAlt.assertCalled_onScroll(null, Touch.TAP, -1, -1);
-
- mRouter.onLongPress(Touch.TAP);
- mAlt.assertCalled_onLongPress(Touch.TAP);
-
- mRouter.onFling(null, Touch.TAP, -1, -1);
- mAlt.assertCalled_onFling(null, Touch.TAP, -1, -1);
-
- mRouter.onSingleTapConfirmed(Touch.TAP);
- mAlt.assertCalled_onSingleTapConfirmed(Touch.TAP);
-
- mRouter.onDoubleTap(Touch.TAP);
- mAlt.assertCalled_onDoubleTap(Touch.TAP);
-
- mRouter.onDoubleTapEvent(Touch.TAP);
- mAlt.assertCalled_onDoubleTapEvent(Touch.TAP);
- }
-
- @Test
- public void testEatsEventsWhenNoFallback() {
- mRouter = new GestureRouter<>();
- // Register the the delegate on mouse so touch events don't get handled.
- mRouter.register(MotionEvent.TOOL_TYPE_MOUSE, mHandler);
-
- mRouter.onDown(Touch.TAP);
- mAlt.assertNotCalled_onDown();
-
- mRouter.onShowPress(Touch.TAP);
- mAlt.assertNotCalled_onShowPress();
-
- mRouter.onSingleTapUp(Touch.TAP);
- mAlt.assertNotCalled_onSingleTapUp();
-
- mRouter.onScroll(null, Touch.TAP, -1, -1);
- mAlt.assertNotCalled_onScroll();
-
- mRouter.onLongPress(Touch.TAP);
- mAlt.assertNotCalled_onLongPress();
-
- mRouter.onFling(null, Touch.TAP, -1, -1);
- mAlt.assertNotCalled_onFling();
-
- mRouter.onSingleTapConfirmed(Touch.TAP);
- mAlt.assertNotCalled_onSingleTapConfirmed();
-
- mRouter.onDoubleTap(Touch.TAP);
- mAlt.assertNotCalled_onDoubleTap();
-
- mRouter.onDoubleTapEvent(Touch.TAP);
- mAlt.assertNotCalled_onDoubleTapEvent();
- }
-
- private static final class TestHandler implements OnGestureListener, OnDoubleTapListener {
-
- private final Spy mSpy = Mockito.mock(Spy.class);
-
- @Override
- public boolean onDown(MotionEvent e) {
- return mSpy.onDown(e);
- }
-
- @Override
- public void onShowPress(MotionEvent e) {
- mSpy.onShowPress(e);
- }
-
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- return mSpy.onSingleTapUp(e);
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- return mSpy.onScroll(e1, e2, distanceX, distanceY);
- }
-
- @Override
- public void onLongPress(MotionEvent e) {
- mSpy.onLongPress(e);
- }
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- return mSpy.onFling(e1, e2, velocityX, velocityY);
- }
-
- @Override
- public boolean onSingleTapConfirmed(MotionEvent e) {
- return mSpy.onSingleTapConfirmed(e);
- }
-
- @Override
- public boolean onDoubleTap(MotionEvent e) {
- return mSpy.onDoubleTap(e);
- }
-
- @Override
- public boolean onDoubleTapEvent(MotionEvent e) {
- return mSpy.onDoubleTapEvent(e);
- }
-
- void assertCalled_onDown(MotionEvent e) {
- verify(mSpy).onDown(e);
- }
-
- void assertCalled_onShowPress(MotionEvent e) {
- verify(mSpy).onShowPress(e);
- }
-
- void assertCalled_onSingleTapUp(MotionEvent e) {
- verify(mSpy).onSingleTapUp(e);
- }
-
- void assertCalled_onScroll(MotionEvent e1, MotionEvent e2, float x, float y) {
- verify(mSpy).onScroll(e1, e2, x, y);
- }
-
- void assertCalled_onLongPress(MotionEvent e) {
- verify(mSpy).onLongPress(e);
- }
-
- void assertCalled_onFling(MotionEvent e1, MotionEvent e2, float x, float y) {
- Mockito.verify(mSpy).onFling(e1, e2, x, y);
- }
-
- void assertCalled_onSingleTapConfirmed(MotionEvent e) {
- Mockito.verify(mSpy).onSingleTapConfirmed(e);
- }
-
- void assertCalled_onDoubleTap(MotionEvent e) {
- Mockito.verify(mSpy).onDoubleTap(e);
- }
-
- void assertCalled_onDoubleTapEvent(MotionEvent e) {
- Mockito.verify(mSpy).onDoubleTapEvent(e);
- }
-
- void assertNotCalled_onDown() {
- verify(mSpy, never()).onDown(any());
- }
-
- void assertNotCalled_onShowPress() {
- verify(mSpy, never()).onShowPress(any());
- }
-
- void assertNotCalled_onSingleTapUp() {
- verify(mSpy, never()).onSingleTapUp(any());
- }
-
- void assertNotCalled_onScroll() {
- verify(mSpy, never()).onScroll(any(), any(), anyFloat(), anyFloat());
- }
-
- void assertNotCalled_onLongPress() {
- verify(mSpy, never()).onLongPress(any());
- }
-
- void assertNotCalled_onFling() {
- Mockito.verify(mSpy, never()).onFling(any(), any(), anyFloat(), anyFloat());
- }
-
- void assertNotCalled_onSingleTapConfirmed() {
- Mockito.verify(mSpy, never()).onSingleTapConfirmed(any());
- }
-
- void assertNotCalled_onDoubleTap() {
- Mockito.verify(mSpy, never()).onDoubleTap(any());
- }
-
- void assertNotCalled_onDoubleTapEvent() {
- Mockito.verify(mSpy, never()).onDoubleTapEvent(any());
- }
- }
-
- private static interface Spy extends OnGestureListener, OnDoubleTapListener {}
-}
diff --git a/tests/unit/com/android/documentsui/selection/GestureSelectionHelperTest.java b/tests/unit/com/android/documentsui/selection/GestureSelectionHelperTest.java
deleted file mode 100644
index 144fa7aa6..000000000
--- a/tests/unit/com/android/documentsui/selection/GestureSelectionHelperTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import androidx.recyclerview.widget.RecyclerView;
-
-import android.view.MotionEvent;
-
-import com.android.documentsui.selection.testing.SelectionProbe;
-import com.android.documentsui.selection.testing.TestData;
-import com.android.documentsui.testing.SelectionHelpers;
-import com.android.documentsui.testing.TestEvents;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class GestureSelectionHelperTest {
-
- private static final List<String> ITEMS = TestData.create(100);
- private static final MotionEvent DOWN = TestEvents.builder()
- .action(MotionEvent.ACTION_DOWN)
- .location(1, 1)
- .build();
-
- private static final MotionEvent MOVE = TestEvents.builder()
- .action(MotionEvent.ACTION_MOVE)
- .location(1, 1)
- .build();
-
- private static final MotionEvent UP = TestEvents.builder()
- .action(MotionEvent.ACTION_UP)
- .location(1, 1)
- .build();
-
- private GestureSelectionHelper mHelper;
- private SelectionHelper mSelectionHelper;
- private SelectionProbe mSelection;
- private ContentLock mLock;
- private TestItemDetailsLookup mItemLookup;
- private TestViewDelegate mView;
-
- @Before
- public void setUp() {
- mSelectionHelper = SelectionHelpers.createTestInstance(ITEMS);
- mSelection = new SelectionProbe(mSelectionHelper);
- mLock = new ContentLock();
- mItemLookup = new TestItemDetailsLookup();
- mItemLookup.initAt(3);
- mView = new TestViewDelegate();
- mHelper = new GestureSelectionHelper(mSelectionHelper, mView, mLock, mItemLookup);
- }
-
- @Test
- public void testIgnoresDown_NoPosition() {
- mView.mNextPosition = RecyclerView.NO_POSITION;
- assertFalse(mHelper.onInterceptTouchEvent(null, DOWN));
- }
-
- @Test
- public void testIgnoresDown_NoItemDetails() {
- mItemLookup.reset();
- assertFalse(mHelper.onInterceptTouchEvent(null, DOWN));
- }
-
- @Test
- public void testNoStartOnIllegalPosition() {
- mView.mNextPosition = -1;
- mHelper.onInterceptTouchEvent(null, DOWN);
- mHelper.start();
- assertFalse(mLock.isLocked());
- }
-
- @Test
- public void testDoesNotClaimDownOnItem() {
- mView.mNextPosition = 0;
- assertFalse(mHelper.onInterceptTouchEvent(null, DOWN));
- }
-
- @Test
- public void testClaimsMoveIfStarted() {
- mView.mNextPosition = 0;
- // TODO(b/109808552): This should be removed with that bug is fixed because it will be a
- // no-op at that time.
- mHelper.onInterceptTouchEvent(null, DOWN);
-
- // Normally, this is controller by the TouchSelectionHelper via a a long press gesture.
- mSelectionHelper.select("1");
- mSelectionHelper.anchorRange(1);
- mHelper.start();
- assertTrue(mHelper.onInterceptTouchEvent(null, MOVE));
- }
-
- @Test
- public void testCreatesRangeSelection() {
- mView.mNextPosition = 1;
- mHelper.onInterceptTouchEvent(null, DOWN);
- // Another way we are implicitly coupled to TouchInputHandler, is that we depend on
- // long press to establish the initial anchor point. Without that we'll get an
- // error when we try to extend the range.
-
- mSelectionHelper.select("1");
- mSelectionHelper.anchorRange(1);
- mHelper.start();
-
- mHelper.onTouchEvent(null, MOVE);
-
- mView.mNextPosition = 9;
- mHelper.onTouchEvent(null, MOVE);
- mHelper.onTouchEvent(null, UP);
-
- mSelection.assertRangeSelected(1, 9);
- }
-
- private static final class TestViewDelegate extends GestureSelectionHelper.ViewDelegate {
-
- private int mNextPosition = RecyclerView.NO_POSITION;
-
- @Override
- int getHeight() {
- return 1000;
- }
-
- @Override
- int getItemUnder(MotionEvent e) {
- return mNextPosition;
- }
-
- @Override
- int getLastGlidedItemPosition(MotionEvent e) {
- return mNextPosition;
- }
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/GestureSelectionHelper_RecyclerViewDelegateTest.java b/tests/unit/com/android/documentsui/selection/GestureSelectionHelper_RecyclerViewDelegateTest.java
deleted file mode 100644
index 9e05d0c50..000000000
--- a/tests/unit/com/android/documentsui/selection/GestureSelectionHelper_RecyclerViewDelegateTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.view.MotionEvent;
-import android.view.View;
-
-import com.android.documentsui.selection.GestureSelectionHelper.RecyclerViewDelegate;
-import com.android.documentsui.testing.TestEvents;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class GestureSelectionHelper_RecyclerViewDelegateTest {
-
- // Simulate a (20, 20) box locating at (20, 20)
- static final int LEFT_BORDER = 20;
- static final int RIGHT_BORDER = 40;
- static final int TOP_BORDER = 20;
- static final int BOTTOM_BORDER = 40;
-
- @Test
- public void testLtrPastLastItem() {
- MotionEvent event = createEvent(100, 100);
- assertTrue(RecyclerViewDelegate.isPastLastItem(
- TOP_BORDER, LEFT_BORDER, RIGHT_BORDER, event, View.LAYOUT_DIRECTION_LTR));
- }
-
- @Test
- public void testLtrPastLastItem_Inverse() {
- MotionEvent event = createEvent(10, 10);
- assertFalse(RecyclerViewDelegate.isPastLastItem(
- TOP_BORDER, LEFT_BORDER, RIGHT_BORDER, event, View.LAYOUT_DIRECTION_LTR));
- }
-
- @Test
- public void testRtlPastLastItem() {
- MotionEvent event = createEvent(10, 30);
- assertTrue(RecyclerViewDelegate.isPastLastItem(
- TOP_BORDER, LEFT_BORDER, RIGHT_BORDER, event, View.LAYOUT_DIRECTION_RTL));
- }
-
- @Test
- public void testRtlPastLastItem_Inverse() {
- MotionEvent event = createEvent(100, 100);
- assertFalse(RecyclerViewDelegate.isPastLastItem(
- TOP_BORDER, LEFT_BORDER, RIGHT_BORDER, event, View.LAYOUT_DIRECTION_RTL));
- }
-
- private static MotionEvent createEvent(int x, int y) {
- return TestEvents.builder().action(MotionEvent.ACTION_MOVE).location(x, y).build();
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/GridModelTest.java b/tests/unit/com/android/documentsui/selection/GridModelTest.java
deleted file mode 100644
index 9b1523561..000000000
--- a/tests/unit/com/android/documentsui/selection/GridModelTest.java
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Copyright (C) 2015 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.documentsui.selection;
-
-import static com.android.documentsui.selection.GridModel.NOT_SET;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
-
-import com.android.documentsui.selection.BandSelectionHelper.BandHost;
-import com.android.documentsui.selection.testing.SelectionPredicates;
-import com.android.documentsui.selection.testing.TestAdapter;
-import com.android.documentsui.selection.testing.TestStableIdProvider;
-
-import org.junit.After;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class GridModelTest {
-
- private static final int VIEW_PADDING_PX = 5;
- private static final int CHILD_VIEW_EDGE_PX = 100;
- private static final int VIEWPORT_HEIGHT = 500;
-
- private GridModel mModel;
- private TestHost mHost;
- private TestAdapter mAdapter;
- private Set<String> mLastSelection;
- private int mViewWidth;
-
- // TLDR: Don't call model.{start|resize}Selection; use the local #startSelection and
- // #resizeSelection methods instead.
- //
- // The reason for this is that selection is stateful and involves operations that take the
- // current UI state (e.g scrolling) into account. This test maintains its own copy of the
- // selection bounds as control data for verifying selections. Keep this data in sync by calling
- // #startSelection and
- // #resizeSelection.
- private Point mSelectionOrigin;
- private Point mSelectionPoint;
-
- @After
- public void tearDown() {
- mModel = null;
- mHost = null;
- mLastSelection = null;
- }
-
- @Test
- public void testSelectionLeftOfItems() {
- initData(20, 5);
- startSelection(new Point(0, 10));
- resizeSelection(new Point(1, 11));
- assertNoSelection();
- assertEquals(NOT_SET, mModel.getPositionNearestOrigin());
- }
-
- @Test
- public void testSelectionRightOfItems() {
- initData(20, 4);
- startSelection(new Point(mViewWidth - 1, 10));
- resizeSelection(new Point(mViewWidth - 2, 11));
- assertNoSelection();
- assertEquals(NOT_SET, mModel.getPositionNearestOrigin());
- }
-
- @Test
- public void testSelectionAboveItems() {
- initData(20, 4);
- startSelection(new Point(10, 0));
- resizeSelection(new Point(11, 1));
- assertNoSelection();
- assertEquals(NOT_SET, mModel.getPositionNearestOrigin());
- }
-
- @Test
- public void testSelectionBelowItems() {
- initData(5, 4);
- startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
- resizeSelection(new Point(11, VIEWPORT_HEIGHT - 2));
- assertNoSelection();
- assertEquals(NOT_SET, mModel.getPositionNearestOrigin());
- }
-
- @Test
- public void testVerticalSelectionBetweenItems() {
- initData(20, 4);
- startSelection(new Point(106, 0));
- resizeSelection(new Point(107, 200));
- assertNoSelection();
- assertEquals(NOT_SET, mModel.getPositionNearestOrigin());
- }
-
- @Test
- public void testHorizontalSelectionBetweenItems() {
- initData(20, 4);
- startSelection(new Point(0, 105));
- resizeSelection(new Point(200, 106));
- assertNoSelection();
- assertEquals(NOT_SET, mModel.getPositionNearestOrigin());
- }
-
- @Test
- public void testGrowingAndShrinkingSelection() {
- initData(20, 4);
- startSelection(new Point(0, 0));
-
- resizeSelection(new Point(5, 5));
- verifySelection();
-
- resizeSelection(new Point(109, 109));
- verifySelection();
-
- resizeSelection(new Point(110, 109));
- verifySelection();
-
- resizeSelection(new Point(110, 110));
- verifySelection();
-
- resizeSelection(new Point(214, 214));
- verifySelection();
-
- resizeSelection(new Point(215, 214));
- verifySelection();
-
- resizeSelection(new Point(214, 214));
- verifySelection();
-
- resizeSelection(new Point(110, 110));
- verifySelection();
-
- resizeSelection(new Point(110, 109));
- verifySelection();
-
- resizeSelection(new Point(109, 109));
- verifySelection();
-
- resizeSelection(new Point(5, 5));
- verifySelection();
-
- resizeSelection(new Point(0, 0));
- verifySelection();
-
- assertEquals(NOT_SET, mModel.getPositionNearestOrigin());
- }
-
- @Test
- public void testSelectionMovingAroundOrigin() {
- initData(16, 4);
-
- startSelection(new Point(210, 210));
- resizeSelection(new Point(mViewWidth - 1, 0));
- verifySelection();
-
- resizeSelection(new Point(0, 0));
- verifySelection();
-
- resizeSelection(new Point(0, 420));
- verifySelection();
-
- resizeSelection(new Point(mViewWidth - 1, 420));
- verifySelection();
-
- // This is manually figured and will need to be adjusted if the separator position is
- // changed.
- assertEquals(7, mModel.getPositionNearestOrigin());
- }
-
- @Test
- public void testScrollingBandSelect() {
- initData(40, 4);
-
- startSelection(new Point(0, 0));
- resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
- verifySelection();
-
- scroll(CHILD_VIEW_EDGE_PX);
- verifySelection();
-
- resizeSelection(new Point(200, VIEWPORT_HEIGHT - 1));
- verifySelection();
-
- scroll(CHILD_VIEW_EDGE_PX);
- verifySelection();
-
- scroll(-2 * CHILD_VIEW_EDGE_PX);
- verifySelection();
-
- resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
- verifySelection();
-
- assertEquals(0, mModel.getPositionNearestOrigin());
- }
-
- private void initData(final int numChildren, int numColumns) {
- mHost = new TestHost(numChildren, numColumns);
- mAdapter = new TestAdapter() {
- @Override
- public String getStableId(int position) {
- return Integer.toString(position);
- }
-
- @Override
- public int getItemCount() {
- return numChildren;
- }
- };
-
- mViewWidth = VIEW_PADDING_PX + numColumns * (VIEW_PADDING_PX + CHILD_VIEW_EDGE_PX);
-
- mModel = new GridModel(
- mHost,
- new TestStableIdProvider(mAdapter),
- SelectionPredicates.CAN_SET_ANYTHING);
-
- mModel.addOnSelectionChangedListener(
- new GridModel.SelectionObserver() {
- @Override
- public void onSelectionChanged(Set<String> updatedSelection) {
- mLastSelection = updatedSelection;
- }
- });
- }
-
- /** Returns the current selection area as a Rect. */
- private Rect getSelectionArea() {
- // Construct a rect from the two selection points.
- Rect selectionArea = new Rect(
- mSelectionOrigin.x, mSelectionOrigin.y, mSelectionOrigin.x, mSelectionOrigin.y);
- selectionArea.union(mSelectionPoint.x, mSelectionPoint.y);
- // Rect intersection tests are exclusive of bounds, while the MSM's selection code is
- // inclusive. Expand the rect by 1 pixel in all directions to account for this.
- selectionArea.inset(-1, -1);
-
- return selectionArea;
- }
-
- /** Asserts that the selection is currently empty. */
- private void assertNoSelection() {
- assertEquals("Unexpected items " + mLastSelection + " in selection " + getSelectionArea(),
- 0, mLastSelection.size());
- }
-
- /** Verifies the selection using actual bbox checks. */
- private void verifySelection() {
- Rect selectionArea = getSelectionArea();
- for (TestHost.Item item: mHost.items) {
- if (Rect.intersects(selectionArea, item.rect)) {
- assertTrue("Expected item " + item + " was not in selection " + selectionArea,
- mLastSelection.contains(item.name));
- } else {
- assertFalse("Unexpected item " + item + " in selection" + selectionArea,
- mLastSelection.contains(item.name));
- }
- }
- }
-
- private void startSelection(Point p) {
- mModel.startCapturing(p);
- mSelectionOrigin = mHost.createAbsolutePoint(p);
- }
-
- private void resizeSelection(Point p) {
- mModel.resizeSelection(p);
- mSelectionPoint = mHost.createAbsolutePoint(p);
- }
-
- private void scroll(int dy) {
- assertTrue(mHost.verticalOffset + VIEWPORT_HEIGHT + dy <= mHost.getTotalHeight());
- mHost.verticalOffset += dy;
- // Correct the cached selection point as well.
- mSelectionPoint.y += dy;
- mHost.mScrollListener.onScrolled(null, 0, dy);
- }
-
- private static final class TestHost extends BandHost {
-
- private final int mNumColumns;
- private final int mNumRows;
- private final int mNumChildren;
- private final int mSeparatorPosition;
-
- public int horizontalOffset = 0;
- public int verticalOffset = 0;
- private List<Item> items = new ArrayList<>();
-
- // Installed by GridModel on construction.
- private @Nullable OnScrollListener mScrollListener;
-
- public TestHost(int numChildren, int numColumns) {
- mNumChildren = numChildren;
- mNumColumns = numColumns;
- mSeparatorPosition = mNumColumns + 1;
- mNumRows = setupGrid();
- }
-
- private int setupGrid() {
- // Split the input set into folders and documents. Do this such that there is a
- // partially-populated row in the middle of the grid, to test corner cases in layout
- // code.
- int y = VIEW_PADDING_PX;
- int i = 0;
- int numRows = 0;
- while (i < mNumChildren) {
- int top = y;
- int height = CHILD_VIEW_EDGE_PX;
- int width = CHILD_VIEW_EDGE_PX;
- for (int j = 0; j < mNumColumns && i < mNumChildren; j++) {
- int left = VIEW_PADDING_PX + (j * (width + VIEW_PADDING_PX));
- items.add(new Item(
- Integer.toString(i),
- new Rect(
- left,
- top,
- left + width - 1,
- top + height - 1)));
-
- // Create a partially populated row at the separator position.
- if (++i == mSeparatorPosition) {
- break;
- }
- }
- y += height + VIEW_PADDING_PX;
- numRows++;
- }
-
- return numRows;
- }
-
- private int getTotalHeight() {
- return CHILD_VIEW_EDGE_PX * mNumRows + VIEW_PADDING_PX * (mNumRows + 1);
- }
-
- private int getFirstVisibleRowIndex() {
- return verticalOffset / (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
- }
-
- private int getLastVisibleRowIndex() {
- int lastVisibleRowUncapped =
- (VIEWPORT_HEIGHT + verticalOffset - 1) / (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
- return Math.min(lastVisibleRowUncapped, mNumRows - 1);
- }
-
- private int getNumItemsInRow(int index) {
- assertTrue(index >= 0 && index < mNumRows);
- int mod = mSeparatorPosition % mNumColumns;
- if (index == (mSeparatorPosition / mNumColumns)) {
- // The row containing the separator may be incomplete
- return mod > 0 ? mod : mNumColumns;
- }
- // Account for the partial separator row in the final row tally.
- if (index == mNumRows - 1) {
- // The last row may be incomplete
- int finalRowCount = (mNumChildren - mod) % mNumColumns;
- return finalRowCount > 0 ? finalRowCount : mNumColumns;
- }
-
- return mNumColumns;
- }
-
- @Override
- public void addOnScrollListener(OnScrollListener listener) {
- mScrollListener = listener;
- }
-
- @Override
- public void removeOnScrollListener(OnScrollListener listener) {}
-
- @Override
- public Point createAbsolutePoint(Point relativePoint) {
- return new Point(
- relativePoint.x + horizontalOffset, relativePoint.y + verticalOffset);
- }
-
- @Override
- public int getVisibleChildCount() {
- int childCount = 0;
- for (int i = getFirstVisibleRowIndex(); i <= getLastVisibleRowIndex(); i++) {
- childCount += getNumItemsInRow(i);
- }
- return childCount;
- }
-
- @Override
- public int getAdapterPositionAt(int index) {
- // Account for partial rows by actually tallying up the items in hidden rows.
- int hiddenCount = 0;
- for (int i = 0; i < getFirstVisibleRowIndex(); i++) {
- hiddenCount += getNumItemsInRow(i);
- }
- return index + hiddenCount;
- }
-
- @Override
- public Rect getAbsoluteRectForChildViewAt(int index) {
- int adapterPosition = getAdapterPositionAt(index);
- return items.get(adapterPosition).rect;
- }
-
- @Override
- public int getChildCount() {
- return mNumChildren;
- }
-
- @Override
- public int getColumnCount() {
- return mNumColumns;
- }
-
- @Override
- public void showBand(Rect rect) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void hideBand() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void scrollBy(int dy) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getHeight() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void invalidateView() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void runAtNextFrame(Runnable r) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void removeCallback(Runnable r) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean hasView(int adapterPosition) {
- return true;
- }
-
- public static final class Item {
- public String name;
- public Rect rect;
-
- public Item(String n, Rect r) {
- name = n;
- rect = r;
- }
-
- @Override
- public String toString() {
- return name + ": " + rect;
- }
- }
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/MouseInputHandlerTest.java b/tests/unit/com/android/documentsui/selection/MouseInputHandlerTest.java
deleted file mode 100644
index c4d66d866..000000000
--- a/tests/unit/com/android/documentsui/selection/MouseInputHandlerTest.java
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static com.android.documentsui.testing.TestEvents.Mouse.ALT_CLICK;
-import static com.android.documentsui.testing.TestEvents.Mouse.CLICK;
-import static com.android.documentsui.testing.TestEvents.Mouse.CTRL_CLICK;
-import static com.android.documentsui.testing.TestEvents.Mouse.SECONDARY_CLICK;
-import static com.android.documentsui.testing.TestEvents.Mouse.SHIFT_CLICK;
-import static com.android.documentsui.testing.TestEvents.Mouse.TERTIARY_CLICK;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import androidx.recyclerview.widget.RecyclerView;
-import android.view.MotionEvent;
-
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.selection.testing.SelectionHelpers;
-import com.android.documentsui.selection.testing.SelectionProbe;
-import com.android.documentsui.selection.testing.TestData;
-import com.android.documentsui.selection.testing.TestEvents;
-import com.android.documentsui.selection.testing.TestMouseCallbacks;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public final class MouseInputHandlerTest {
-
- private static final List<String> ITEMS = TestData.create(100);
-
- private MouseInputHandler mInputDelegate;
- private TestMouseCallbacks mCallbacks;
- private TestItemDetailsLookup mDetailsLookup;
- private SelectionProbe mSelection;
- private SelectionHelper mSelectionMgr;
-
- private TestEvents.Builder mEvent;
-
- @Before
- public void setUp() {
-
- mSelectionMgr = SelectionHelpers.createTestInstance(ITEMS);
- mDetailsLookup = new TestItemDetailsLookup();
- mSelection = new SelectionProbe(mSelectionMgr);
-
- mCallbacks = new TestMouseCallbacks();
- mInputDelegate = new MouseInputHandler(mSelectionMgr, mDetailsLookup, mCallbacks);
-
- mEvent = TestEvents.builder().mouse();
- mDetailsLookup.initAt(RecyclerView.NO_POSITION);
- }
-
- @Test
- public void testConfirmedClick_StartsSelection() {
- mDetailsLookup.initAt(11).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mSelection.assertSelection(11);
- }
-
- @Test
- public void testClickOnSelectRegion_AddsToSelection() {
- mDetailsLookup.initAt(11).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(10).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapUp(CLICK);
-
- mSelection.assertSelected(10, 11);
- }
-
- @Test
- public void testClickOnIconOfSelectedItem_RemovesFromSelection() {
- mDetailsLookup.initAt(8).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
- mSelection.assertSelected(8, 9, 10, 11);
-
- mDetailsLookup.initAt(9);
- mInputDelegate.onSingleTapUp(CLICK);
- mSelection.assertSelected(8, 10, 11);
- }
-
- @Test
- public void testRightClickDown_StartsContextMenu() {
- mInputDelegate.onDown(SECONDARY_CLICK);
-
- mCallbacks.assertLastEvent(SECONDARY_CLICK);
- }
-
- @Test
- public void testAltClickDown_StartsContextMenu() {
- mInputDelegate.onDown(ALT_CLICK);
-
- mCallbacks.assertLastEvent(ALT_CLICK);
- }
-
- @Test
- public void testScroll_shouldTrap() {
- mDetailsLookup.initAt(0);
- assertTrue(mInputDelegate.onScroll(
- null,
- mEvent.action(MotionEvent.ACTION_MOVE).primary().build(),
- -1,
- -1));
- }
-
- @Test
- public void testScroll_NoTrapForTwoFinger() {
- mDetailsLookup.initAt(0);
- assertFalse(mInputDelegate.onScroll(
- null,
- mEvent.action(MotionEvent.ACTION_MOVE).build(),
- -1,
- -1));
- }
-
- @Test
- public void testUnconfirmedCtrlClick_AddsToExistingSelection() {
- mDetailsLookup.initAt(7).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapUp(CTRL_CLICK);
-
- mSelection.assertSelection(7, 11);
- }
-
- @Test
- public void testUnconfirmedShiftClick_ExtendsSelection() {
- mDetailsLookup.initAt(7).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- mSelection.assertSelection(7, 8, 9, 10, 11);
- }
-
- @Test
- public void testConfirmedShiftClick_ExtendsSelectionFromOriginFocus() {
- TestItemDetails item = mDetailsLookup.initAt(7);
- mCallbacks.focusItem(item);
-
- // This is a hack-y test, since the real FocusManager would've set range begin itself.
- mSelectionMgr.anchorRange(7);
- mSelection.assertNoSelection();
-
- mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapConfirmed(SHIFT_CLICK);
- mSelection.assertSelection(7, 8, 9, 10, 11);
- }
-
- @Test
- public void testUnconfirmedShiftClick_RotatesAroundOrigin() {
- mDetailsLookup.initAt(7).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
- mSelection.assertSelection(7, 8, 9, 10, 11);
-
- mDetailsLookup.initAt(5);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- mSelection.assertSelection(5, 6, 7);
- mSelection.assertNotSelected(8, 9, 10, 11);
- }
-
- @Test
- public void testUnconfirmedShiftCtrlClick_Combination() {
- mDetailsLookup.initAt(7).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
- mSelection.assertSelection(7, 8, 9, 10, 11);
-
- mDetailsLookup.initAt(5);
- mInputDelegate.onSingleTapUp(CTRL_CLICK);
-
- mSelection.assertSelection(5, 7, 8, 9, 10, 11);
- }
-
- @Test
- public void testUnconfirmedShiftCtrlClick_ShiftTakesPriority() {
- mDetailsLookup.initAt(7).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapUp(mEvent.ctrl().shift().build());
-
- mSelection.assertSelection(7, 8, 9, 10, 11);
- }
-
- // TODO: Add testSpaceBar_Previews, but we need to set a system property
- // to have a deterministic state.
-
- @Test
- public void testDoubleClick_Opens() {
- TestItemDetails doc = mDetailsLookup.initAt(11);
- mInputDelegate.onDoubleTap(CLICK);
-
- mCallbacks.assertActivated(doc);
- }
-
- @Test
- public void testMiddleClick_DoesNothing() {
- mDetailsLookup.initAt(11).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(TERTIARY_CLICK);
-
- mSelection.assertNoSelection();
- }
-
- @Test
- public void testClickOff_ClearsSelection() {
- mDetailsLookup.initAt(11).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(RecyclerView.NO_POSITION);
- mInputDelegate.onSingleTapUp(CLICK);
-
- mSelection.assertNoSelection();
- }
-
- @Test
- public void testClick_Focuses() {
- mDetailsLookup.initAt(11).setInItemSelectRegion(false);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mCallbacks.assertHasFocus(true);
- mCallbacks.assertFocused("11");
- }
-
- @Test
- public void testClickOff_ClearsFocus() {
- mDetailsLookup.initAt(11).setInItemSelectRegion(false);
- mInputDelegate.onSingleTapConfirmed(CLICK);
- mCallbacks.assertHasFocus(true);
-
- mDetailsLookup.initAt(RecyclerView.NO_POSITION);
- mInputDelegate.onSingleTapUp(CLICK);
- mCallbacks.assertHasFocus(false);
- }
-
- @Test
- public void testClickOffSelection_RemovesSelectionAndFocuses() {
- mDetailsLookup.initAt(1).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(5);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- mSelection.assertSelection(1, 2, 3, 4, 5);
-
- mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapUp(CLICK);
-
- mCallbacks.assertFocused("11");
- mSelection.assertNoSelection();
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/MouseInputHandler_RangeTest.java b/tests/unit/com/android/documentsui/selection/MouseInputHandler_RangeTest.java
deleted file mode 100644
index 939e77892..000000000
--- a/tests/unit/com/android/documentsui/selection/MouseInputHandler_RangeTest.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static com.android.documentsui.testing.TestEvents.Mouse.CLICK;
-import static com.android.documentsui.testing.TestEvents.Mouse.SECONDARY_CLICK;
-import static com.android.documentsui.testing.TestEvents.Mouse.SHIFT_CLICK;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.selection.testing.SelectionHelpers;
-import com.android.documentsui.selection.testing.SelectionProbe;
-import com.android.documentsui.selection.testing.TestData;
-import com.android.documentsui.selection.testing.TestMouseCallbacks;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-/**
- * MouseInputDelegate / SelectHelper integration test covering the shared
- * responsibility of range selection.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public final class MouseInputHandler_RangeTest {
-
- private static final List<String> ITEMS = TestData.create(100);
-
- private MouseInputHandler mInputDelegate;
- private SelectionHelper mSelectionMgr;
- private SelectionProbe mSelection;
- private TestMouseCallbacks mCallbacks;
- private TestItemDetailsLookup mDetailsLookup;
-
- @Before
- public void setUp() {
- mSelectionMgr = SelectionHelpers.createTestInstance(ITEMS);
- mDetailsLookup = new TestItemDetailsLookup();
- mSelection = new SelectionProbe(mSelectionMgr);
-
- mCallbacks = new TestMouseCallbacks();
- mInputDelegate = new MouseInputHandler(mSelectionMgr, mDetailsLookup, mCallbacks);
- }
-
- @Test
- public void testExtendRange() {
- // uni-click just focuses.
- mDetailsLookup.initAt(7).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- mSelection.assertRangeSelection(7, 11);
- }
-
- @Test
- public void testExtendRangeContinues() {
- mDetailsLookup.initAt(7).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- mDetailsLookup.initAt(21);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- mSelection.assertRangeSelection(7, 21);
- }
-
- @Test
- public void testMultipleContiguousRanges() {
- mDetailsLookup.initAt(7).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- // click without shift sets a new range start point.
- TestItemDetails item = mDetailsLookup.initAt(20);
- mInputDelegate.onSingleTapUp(CLICK);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mCallbacks.focusItem(item);
-
- mDetailsLookup.initAt(25);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
- mInputDelegate.onSingleTapConfirmed(SHIFT_CLICK);
-
- mSelection.assertRangeNotSelected(7, 11);
- mSelection.assertRangeSelected(20, 25);
- mSelection.assertSelectionSize(6);
- }
-
- @Test
- public void testReducesSelectionRange() {
- mDetailsLookup.initAt(7).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(17);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- mDetailsLookup.initAt(10);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- mSelection.assertRangeSelection(7, 10);
- }
-
- @Test
- public void testReducesSelectionRange_Reverse() {
- mDetailsLookup.initAt(17).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(7);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- mDetailsLookup.initAt(14);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- mSelection.assertRangeSelection(14, 17);
- }
-
- @Test
- public void testExtendsRange_Reverse() {
- mDetailsLookup.initAt(12).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(5);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- mSelection.assertRangeSelection(5, 12);
- }
-
- @Test
- public void testExtendsRange_ReversesAfterForwardClick() {
- mDetailsLookup.initAt(7).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapConfirmed(CLICK);
-
- mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- mDetailsLookup.initAt(0);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- mSelection.assertRangeSelection(0, 7);
- }
-
- @Test
- public void testRightClickEstablishesRange() {
-
- mDetailsLookup.initAt(7).setInItemSelectRegion(true);
- mInputDelegate.onDown(SECONDARY_CLICK);
- // This next method call simulates the behavior of the system event dispatch code.
- // UserInputHandler depends on a specific sequence of events for internal
- // state to remain valid. It's not an awesome arrangement, but it is currently
- // necessary.
- //
- // See: UserInputHandler.MouseDelegate#mHandledOnDown;
- mInputDelegate.onSingleTapUp(SECONDARY_CLICK);
-
- mDetailsLookup.initAt(11);
- // Now we can send a subsequent event that should extend selection.
- mInputDelegate.onDown(SHIFT_CLICK);
- mInputDelegate.onSingleTapUp(SHIFT_CLICK);
-
- mSelection.assertRangeSelection(7, 11);
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/SelectionTest.java b/tests/unit/com/android/documentsui/selection/SelectionTest.java
deleted file mode 100644
index fcf525bba..000000000
--- a/tests/unit/com/android/documentsui/selection/SelectionTest.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2015 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.documentsui.selection;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.google.common.collect.Sets;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.HashSet;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class SelectionTest {
-
- private Selection selection;
-
- private String[] ids = new String[]{
- "foo",
- "43",
- "auth|id=@53di*/f3#d"
- };
-
- @Before
- public void setUp() throws Exception {
- selection = new Selection();
- selection.add(ids[0]);
- selection.add(ids[1]);
- selection.add(ids[2]);
- }
-
- @Test
- public void testAdd() {
- // We added in setUp.
- assertEquals(3, selection.size());
- assertContains(ids[0]);
- assertContains(ids[1]);
- assertContains(ids[2]);
- }
-
- @Test
- public void testRemove() {
- selection.remove(ids[0]);
- selection.remove(ids[2]);
- assertEquals(1, selection.size());
- assertContains(ids[1]);
- }
-
- @Test
- public void testClear() {
- selection.clear();
- assertEquals(0, selection.size());
- }
-
- @Test
- public void testIsEmpty() {
- assertTrue(new Selection().isEmpty());
- selection.clear();
- assertTrue(selection.isEmpty());
- }
-
- @Test
- public void testSize() {
- Selection other = new Selection();
- for (int i = 0; i < selection.size(); i++) {
- other.add(ids[i]);
- }
- assertEquals(selection.size(), other.size());
- }
-
- @Test
- public void testEqualsSelf() {
- assertEquals(selection, selection);
- }
-
- @Test
- public void testEqualsOther() {
- Selection other = new Selection();
- other.add(ids[0]);
- other.add(ids[1]);
- other.add(ids[2]);
- assertEquals(selection, other);
- assertEquals(selection.hashCode(), other.hashCode());
- }
-
- @Test
- public void testEqualsCopy() {
- Selection other = new Selection();
- other.copyFrom(selection);
- assertEquals(selection, other);
- assertEquals(selection.hashCode(), other.hashCode());
- }
-
- @Test
- public void testNotEquals() {
- Selection other = new Selection();
- other.add("foobar");
- assertFalse(selection.equals(other));
- }
-
- @Test
- public void testIntersection_empty0() {
- Selection testSelection = new Selection();
- testSelection.intersect(new HashSet<String>());
- assertTrue(testSelection.isEmpty());
- }
-
- @Test
- public void testIntersection_empty1() {
- Selection testSelection = new Selection();
- testSelection.intersect(Sets.newHashSet("foo"));
- assertTrue(testSelection.isEmpty());
- }
-
- @Test
- public void testIntersection_empty2() {
- assertFalse(selection.isEmpty());
- selection.intersect(new HashSet<String>());
- assertTrue(selection.isEmpty());
- }
-
- @Test
- public void testIntersection_exclusive() {
- String[] ids0 = new String[]{"foo", "bar", "baz"};
- String[] ids1 = new String[]{"0", "1", "2"};
-
- Selection testSelection = new Selection();
- testSelection.add(ids0[0]);
- testSelection.add(ids0[1]);
- testSelection.add(ids0[2]);
-
- Set<String> set = Sets.newHashSet(ids1);
- testSelection.intersect(set);
-
- assertTrue(testSelection.isEmpty());
- }
-
- @Test
- public void testIntersection_subset() {
- String[] ids0 = new String[]{"foo", "bar", "baz"};
- String[] ids1 = new String[]{"0", "baz", "1", "foo", "2"};
-
- Selection testSelection = new Selection();
- testSelection.add(ids0[0]);
- testSelection.add(ids0[1]);
- testSelection.add(ids0[2]);
-
- testSelection.intersect(Sets.newHashSet(ids1));
-
- assertTrue(testSelection.contains("foo"));
- assertFalse(testSelection.contains("bar"));
- assertTrue(testSelection.contains("baz"));
- }
-
- @Test
- public void testIntersection_all() {
- String[] ids0 = new String[]{"foo", "bar", "baz"};
- String[] ids1 = new String[]{"0", "baz", "1", "foo", "2", "bar"};
-
- Selection testSelection = new Selection();
- testSelection.add(ids0[0]);
- testSelection.add(ids0[1]);
- testSelection.add(ids0[2]);
-
- Selection control = new Selection();
- control.copyFrom(testSelection);
-
- testSelection.intersect(Sets.newHashSet(ids1));
-
- assertTrue(testSelection.equals(control));
- }
-
- private void assertContains(String id) {
- String err = String.format("Selection %s does not contain %s", selection, id);
- assertTrue(err, selection.contains(id));
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/TouchInputHandlerTest.java b/tests/unit/com/android/documentsui/selection/TouchInputHandlerTest.java
deleted file mode 100644
index 919f42564..000000000
--- a/tests/unit/com/android/documentsui/selection/TouchInputHandlerTest.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static com.android.documentsui.testing.TestEvents.Touch.TAP;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import androidx.annotation.Nullable;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import androidx.recyclerview.widget.RecyclerView;
-import android.view.MotionEvent;
-
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
-import com.android.documentsui.selection.TouchInputHandler.Callbacks;
-import com.android.documentsui.selection.testing.SelectionHelpers;
-import com.android.documentsui.selection.testing.SelectionProbe;
-import com.android.documentsui.selection.testing.TestData;
-import com.android.documentsui.selection.testing.TestSelectionPredicate;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public final class TouchInputHandlerTest {
-
- private static final List<String> ITEMS = TestData.create(100);
-
- private TouchInputHandler mInputDelegate;
- private SelectionHelper mSelectionMgr;
- private TestSelectionPredicate mSelectionPredicate;
- private TestRunnable mGestureStarted;
- private TestCallbacks mCallbacks;
- private TestItemDetailsLookup mDetailsLookup;
- private SelectionProbe mSelection;
-
- @Before
- public void setUp() {
- mSelectionMgr = SelectionHelpers.createTestInstance(ITEMS);
- mDetailsLookup = new TestItemDetailsLookup();
- mSelectionPredicate = new TestSelectionPredicate();
- mSelection = new SelectionProbe(mSelectionMgr);
- mGestureStarted = new TestRunnable();
- mCallbacks = new TestCallbacks();
-
- mInputDelegate = new TouchInputHandler(
- mSelectionMgr,
- mDetailsLookup,
- mSelectionPredicate,
- mGestureStarted,
- mCallbacks);
- }
-
- @Test
- public void testTap_ActivatesWhenNoExistingSelection() {
- ItemDetails doc = mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapUp(TAP);
-
- mCallbacks.assertActivated(doc);
- }
-
- @Test
- public void testScroll_shouldNotBeTrapped() {
- assertFalse(mInputDelegate.onScroll(null, TAP, -1, -1));
- }
-
- @Test
- public void testLongPress_SelectsItem() {
- mSelectionPredicate.setReturnValue(true);
-
- mDetailsLookup.initAt(7);
- mInputDelegate.onLongPress(TAP);
-
- mSelection.assertSelection(7);
- }
-
- @Test
- public void testLongPress_StartsGestureSelection() {
- mSelectionPredicate.setReturnValue(true);
-
- mDetailsLookup.initAt(7);
- mInputDelegate.onLongPress(TAP);
- mGestureStarted.assertRan();
- }
-
- @Test
- public void testSelectHotspot_StartsSelectionMode() {
- mSelectionPredicate.setReturnValue(true);
-
- mDetailsLookup.initAt(7).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapUp(TAP);
-
- mSelection.assertSelection(7);
- }
-
- @Test
- public void testSelectionHotspot_UnselectsSelectedItem() {
- mSelectionMgr.select("11");
-
- mDetailsLookup.initAt(11).setInItemSelectRegion(true);
- mInputDelegate.onSingleTapUp(TAP);
-
- mSelection.assertNoSelection();
- }
-
- @Test
- public void testStartsSelection_PerformsHapticFeedback() {
- mSelectionPredicate.setReturnValue(true);
-
- mDetailsLookup.initAt(7);
- mInputDelegate.onLongPress(TAP);
-
- mCallbacks.assertVibrated();
- }
-
- @Test
- public void testLongPress_AddsToSelection() {
- mSelectionPredicate.setReturnValue(true);
-
- mDetailsLookup.initAt(7);
- mInputDelegate.onLongPress(TAP);
-
- mDetailsLookup.initAt(99);
- mInputDelegate.onLongPress(TAP);
-
- mDetailsLookup.initAt(13);
- mInputDelegate.onLongPress(TAP);
-
- mSelection.assertSelection(7, 13, 99);
- }
-
- @Test
- public void testTap_UnselectsSelectedItem() {
- mSelectionMgr.select("11");
-
- mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapUp(TAP);
-
- mSelection.assertNoSelection();
- }
-
- @Test
- public void testTapOff_ClearsSelection() {
- mSelectionMgr.select("7");
- mDetailsLookup.initAt(7);
-
- mInputDelegate.onLongPress(TAP);
-
- mSelectionMgr.select("11");
- mDetailsLookup.initAt(11);
- mInputDelegate.onSingleTapUp(TAP);
-
- mDetailsLookup.initAt(RecyclerView.NO_POSITION).setInItemSelectRegion(false);
- mInputDelegate.onSingleTapUp(TAP);
-
- mSelection.assertNoSelection();
- }
-
- private static final class TestCallbacks extends TouchInputHandler.Callbacks {
-
- private @Nullable ItemDetails mActivated;
- private boolean mVibrated;
-
- @Override
- public boolean onItemActivated(ItemDetails item, MotionEvent e) {
- mActivated = item;
- return false;
- }
-
- @Override
- public boolean onDragInitiated(MotionEvent e) {
- return false;
- }
-
- @Override
- public void onPerformHapticFeedback() {
- mVibrated = true;
- }
-
- private void assertActivated(ItemDetails expected) {
- assertEquals(expected, mActivated);
- }
-
- private void assertVibrated() {
- assertTrue(mVibrated);
- }
- }
-
- private static final class TestRunnable implements Runnable {
-
- private boolean mWasRun;
-
- @Override
- public void run() {
- mWasRun = true;
- }
-
- void assertRan() {
- assertTrue(mWasRun);
- }
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/testing/SelectionHelpers.java b/tests/unit/com/android/documentsui/selection/testing/SelectionHelpers.java
deleted file mode 100644
index 6bdd18a2c..000000000
--- a/tests/unit/com/android/documentsui/selection/testing/SelectionHelpers.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection.testing;
-
-import com.android.documentsui.selection.DefaultSelectionHelper;
-import com.android.documentsui.selection.DefaultSelectionHelper.SelectionMode;
-import com.android.documentsui.selection.SelectionHelper;
-import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
-
-import java.util.Collections;
-import java.util.List;
-
-public class SelectionHelpers {
-
- public static final SelectionPredicate CAN_SET_ANYTHING = new SelectionPredicate() {
- @Override
- public boolean canSetStateForId(String id, boolean nextState) {
- return true;
- }
-
- @Override
- public boolean canSetStateAtPosition(int position, boolean nextState) {
- return true;
- }
- };
-
- private SelectionHelpers() {}
-
- public static SelectionHelper createTestInstance() {
- return createTestInstance(Collections.emptyList());
- }
-
- public static SelectionHelper createTestInstance(List<String> docs) {
- return createTestInstance(docs, DefaultSelectionHelper.MODE_MULTIPLE);
- }
-
- public static SelectionHelper createTestInstance(
- List<String> items, @SelectionMode int mode) {
- return createTestInstance(new TestAdapter(items), mode, CAN_SET_ANYTHING);
- }
-
- public static SelectionHelper createTestInstance(
- TestAdapter adapter, @SelectionMode int mode, SelectionPredicate selPredicate) {
- return new DefaultSelectionHelper(
- mode, adapter, new TestStableIdProvider(adapter), selPredicate);
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/testing/SelectionPredicates.java b/tests/unit/com/android/documentsui/selection/testing/SelectionPredicates.java
deleted file mode 100644
index 020091922..000000000
--- a/tests/unit/com/android/documentsui/selection/testing/SelectionPredicates.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection.testing;
-
-import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
-
-/**
- * Test friendly {@link SelectionPredicate} instances.
- */
-public final class SelectionPredicates {
-
- private SelectionPredicates() {}
-
- public static final SelectionPredicate CAN_SET_ANYTHING = new SelectionPredicate() {
- @Override
- public boolean canSetStateForId(String id, boolean nextState) {
- return true;
- }
-
- @Override
- public boolean canSetStateAtPosition(int position, boolean nextState) {
- return true;
- }
- };
-}
diff --git a/tests/unit/com/android/documentsui/selection/testing/SelectionProbe.java b/tests/unit/com/android/documentsui/selection/testing/SelectionProbe.java
deleted file mode 100644
index 4d5790bf0..000000000
--- a/tests/unit/com/android/documentsui/selection/testing/SelectionProbe.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection.testing;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import com.android.documentsui.selection.DefaultSelectionHelper;
-import com.android.documentsui.selection.Selection;
-import com.android.documentsui.selection.SelectionHelper;
-
-/**
- * Helper class for making assertions against the state of a {@link DefaultSelectionHelper} instance
- * and the consistency of states between {@link DefaultSelectionHelper} and
- * {@link DefaultSelectionHelper.ItemEventCallback}.
- */
-public final class SelectionProbe {
-
- private final SelectionHelper mMgr;
- private final TestSelectionObserver mSelectionListener;
-
- public SelectionProbe(SelectionHelper mgr) {
- mMgr = mgr;
- mSelectionListener = new TestSelectionObserver();
- mMgr.addObserver(mSelectionListener);
- }
-
- public SelectionProbe(SelectionHelper mgr, TestSelectionObserver selectionListener) {
- mMgr = mgr;
- mSelectionListener = selectionListener;
- }
-
- public void assertRangeSelected(int begin, int end) {
- for (int i = begin; i <= end; i++) {
- assertSelected(i);
- }
- }
-
- public void assertRangeNotSelected(int begin, int end) {
- for (int i = begin; i <= end; i++) {
- assertNotSelected(i);
- }
- }
-
- public void assertRangeSelection(int begin, int end) {
- assertSelectionSize(end - begin + 1);
- assertRangeSelected(begin, end);
- }
-
- public void assertSelectionSize(int expected) {
- Selection selection = mMgr.getSelection();
- assertEquals(selection.toString(), expected, selection.size());
-
- mSelectionListener.assertSelectionSize(expected);
- }
-
- public void assertNoSelection() {
- assertSelectionSize(0);
-
- mSelectionListener.assertNoSelection();
- }
-
- public void assertSelection(int... ids) {
- assertSelected(ids);
- assertEquals(ids.length, mMgr.getSelection().size());
-
- mSelectionListener.assertSelectionSize(ids.length);
- }
-
- public void assertSelected(int... ids) {
- Selection sel = mMgr.getSelection();
- for (int id : ids) {
- String sid = String.valueOf(id);
- assertTrue(sid + " is not in selection " + sel, sel.contains(sid));
-
- mSelectionListener.assertSelected(sid);
- }
- }
-
- public void assertNotSelected(int... ids) {
- Selection sel = mMgr.getSelection();
- for (int id : ids) {
- String sid = String.valueOf(id);
- assertFalse(sid + " is in selection " + sel, sel.contains(sid));
-
- mSelectionListener.assertNotSelected(sid);
- }
- }
-
- public void select(int...positions) {
- for (int position : positions) {
- mMgr.select(String.valueOf(position));
- }
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestAdapter.java b/tests/unit/com/android/documentsui/selection/testing/TestAdapter.java
deleted file mode 100644
index 4a2d3e542..000000000
--- a/tests/unit/com/android/documentsui/selection/testing/TestAdapter.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection.testing;
-
-import static org.junit.Assert.assertTrue;
-
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.Adapter;
-import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
-import android.view.ViewGroup;
-
-import com.android.documentsui.selection.SelectionHelper;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public class TestAdapter extends Adapter<TestHolder> {
-
- private final List<String> mItems = new ArrayList<>();
- private final List<Integer> mNotifiedOfSelection = new ArrayList<>();
- private final AdapterDataObserver mAdapterObserver;
-
- public TestAdapter() {
- this(Collections.EMPTY_LIST);
- }
-
- public TestAdapter(List<String> items) {
- mItems.addAll(items);
- mAdapterObserver = new RecyclerView.AdapterDataObserver() {
-
- @Override
- public void onChanged() {
- }
-
- @Override
- public void onItemRangeChanged(int startPosition, int itemCount, Object payload) {
- if (SelectionHelper.SELECTION_CHANGED_MARKER.equals(payload)) {
- int last = startPosition + itemCount;
- for (int i = startPosition; i < last; i++) {
- mNotifiedOfSelection.add(i);
- }
- }
- }
-
- @Override
- public void onItemRangeInserted(int startPosition, int itemCount) {
- }
-
- @Override
- public void onItemRangeRemoved(int startPosition, int itemCount) {
- }
-
- @Override
- public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
- throw new UnsupportedOperationException();
- }
- };
-
- registerAdapterDataObserver(mAdapterObserver);
- }
-
- @Override
- public TestHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- return new TestHolder(parent);
- }
-
- @Override
- public void onBindViewHolder(TestHolder holder, int position) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getItemCount() {
- return mItems.size();
- }
-
- public void updateTestModelIds(List<String> items) {
- mItems.clear();
- mItems.addAll(items);
-
- notifyDataSetChanged();
- }
-
- public List<String> getStableIds() {
- return mItems;
- }
-
- public int getPosition(String id) {
- return mItems.indexOf(id);
- }
-
- public String getStableId(int position) {
- return mItems.get(position);
- }
-
-
- public void resetSelectionNotifications() {
- mNotifiedOfSelection.clear();
- }
-
- public void assertNotifiedOfSelectionChange(int position) {
- assertTrue(mNotifiedOfSelection.contains(position));
- }
-
- public static List<String> createItemList(int num) {
- List<String> items = new ArrayList<>(num);
- for (int i = 0; i < num; ++i) {
- items.add(Integer.toString(i));
- }
- return items;
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestBandPredicate.java b/tests/unit/com/android/documentsui/selection/testing/TestBandPredicate.java
deleted file mode 100644
index 2e901a013..000000000
--- a/tests/unit/com/android/documentsui/selection/testing/TestBandPredicate.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection.testing;
-
-import android.view.MotionEvent;
-
-import com.android.documentsui.selection.BandPredicate;
-
-public class TestBandPredicate extends BandPredicate {
-
- private boolean mCanInitiate = true;
-
- public void setCanInitiate(boolean canInitiate) {
- mCanInitiate = canInitiate;
- }
-
- @Override
- public boolean canInitiate(MotionEvent e) {
- return mCanInitiate;
- }
-
-}
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestData.java b/tests/unit/com/android/documentsui/selection/testing/TestData.java
deleted file mode 100644
index 1a0599072..000000000
--- a/tests/unit/com/android/documentsui/selection/testing/TestData.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection.testing;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class TestData {
- public static List<String> create(int num) {
- List<String> items = new ArrayList<String>(num);
- for (int i = 0; i < num; ++i) {
- items.add(Integer.toString(i));
- }
- return items;
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestEvents.java b/tests/unit/com/android/documentsui/selection/testing/TestEvents.java
deleted file mode 100644
index 828704ffc..000000000
--- a/tests/unit/com/android/documentsui/selection/testing/TestEvents.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection.testing;
-
-import androidx.annotation.IntDef;
-import android.graphics.Point;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.MotionEvent.PointerCoords;
-import android.view.MotionEvent.PointerProperties;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Handy-dandy wrapper class to facilitate the creation of MotionEvents.
- */
-public final class TestEvents {
-
- /**
- * Common mouse event types...for your convenience.
- */
- public static final class Mouse {
- public static final MotionEvent CLICK =
- TestEvents.builder().mouse().primary().build();
- public static final MotionEvent CTRL_CLICK =
- TestEvents.builder().mouse().primary().ctrl().build();
- public static final MotionEvent ALT_CLICK =
- TestEvents.builder().mouse().primary().alt().build();
- public static final MotionEvent SHIFT_CLICK =
- TestEvents.builder().mouse().primary().shift().build();
- public static final MotionEvent SECONDARY_CLICK =
- TestEvents.builder().mouse().secondary().build();
- public static final MotionEvent TERTIARY_CLICK =
- TestEvents.builder().mouse().tertiary().build();
- }
-
- /**
- * Common touch event types...for your convenience.
- */
- public static final class Touch {
- public static final MotionEvent TAP =
- TestEvents.builder().touch().build();
- }
-
- static final int ACTION_UNSET = -1;
-
- // Add other actions from MotionEvent.ACTION_ as needed.
- @IntDef(flag = true, value = {
- MotionEvent.ACTION_DOWN,
- MotionEvent.ACTION_MOVE,
- MotionEvent.ACTION_UP
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Action {}
-
- // Add other types from MotionEvent.TOOL_TYPE_ as needed.
- @IntDef(flag = true, value = {
- MotionEvent.TOOL_TYPE_FINGER,
- MotionEvent.TOOL_TYPE_MOUSE,
- MotionEvent.TOOL_TYPE_STYLUS,
- MotionEvent.TOOL_TYPE_UNKNOWN
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ToolType {}
-
- @IntDef(flag = true, value = {
- MotionEvent.BUTTON_PRIMARY,
- MotionEvent.BUTTON_SECONDARY
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Button {}
-
- @IntDef(flag = true, value = {
- KeyEvent.META_SHIFT_ON,
- KeyEvent.META_CTRL_ON
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Key {}
-
- private static final class State {
- private @Action int mAction = ACTION_UNSET;
- private @ToolType int mToolType = MotionEvent.TOOL_TYPE_UNKNOWN;
- private int mPointerCount = 1;
- private Set<Integer> mButtons = new HashSet<>();
- private Set<Integer> mKeys = new HashSet<>();
- private Point mLocation = new Point(0, 0);
- private Point mRawLocation = new Point(0, 0);
- }
-
- public static final Builder builder() {
- return new Builder();
- }
-
- /**
- * Test event builder with convenience methods for common event attrs.
- */
- public static final class Builder {
-
- private State mState = new State();
-
- /**
- * @param action Any action specified in {@link MotionEvent}.
- * @return
- */
- public Builder action(int action) {
- mState.mAction = action;
- return this;
- }
-
- public Builder type(@ToolType int type) {
- mState.mToolType = type;
- return this;
- }
-
- public Builder location(int x, int y) {
- mState.mLocation = new Point(x, y);
- return this;
- }
-
- public Builder rawLocation(int x, int y) {
- mState.mRawLocation = new Point(x, y);
- return this;
- }
-
- public Builder pointerCount(int count) {
- mState.mPointerCount = count;
- return this;
- }
-
- /**
- * Adds one or more button press attributes.
- */
- public Builder pressButton(@Button int... buttons) {
- for (int button : buttons) {
- mState.mButtons.add(button);
- }
- return this;
- }
-
- /**
- * Removes one or more button press attributes.
- */
- public Builder releaseButton(@Button int... buttons) {
- for (int button : buttons) {
- mState.mButtons.remove(button);
- }
- return this;
- }
-
- /**
- * Adds one or more key press attributes.
- */
- public Builder pressKey(@Key int... keys) {
- for (int key : keys) {
- mState.mKeys.add(key);
- }
- return this;
- }
-
- /**
- * Removes one or more key press attributes.
- */
- public Builder releaseKey(@Button int... keys) {
- for (int key : keys) {
- mState.mKeys.remove(key);
- }
- return this;
- }
-
- public Builder touch() {
- type(MotionEvent.TOOL_TYPE_FINGER);
- return this;
- }
-
- public Builder mouse() {
- type(MotionEvent.TOOL_TYPE_MOUSE);
- return this;
- }
-
- public Builder shift() {
- pressKey(KeyEvent.META_SHIFT_ON);
- return this;
- }
-
- /**
- * Use {@link #remove(@Attribute int...)}
- */
- public Builder unshift() {
- releaseKey(KeyEvent.META_SHIFT_ON);
- return this;
- }
-
- public Builder ctrl() {
- pressKey(KeyEvent.META_CTRL_ON);
- return this;
- }
-
- public Builder alt() {
- pressKey(KeyEvent.META_ALT_ON);
- return this;
- }
-
- public Builder primary() {
- pressButton(MotionEvent.BUTTON_PRIMARY);
- releaseButton(MotionEvent.BUTTON_SECONDARY);
- releaseButton(MotionEvent.BUTTON_TERTIARY);
- return this;
- }
-
- public Builder secondary() {
- pressButton(MotionEvent.BUTTON_SECONDARY);
- releaseButton(MotionEvent.BUTTON_PRIMARY);
- releaseButton(MotionEvent.BUTTON_TERTIARY);
- return this;
- }
-
- public Builder tertiary() {
- pressButton(MotionEvent.BUTTON_TERTIARY);
- releaseButton(MotionEvent.BUTTON_PRIMARY);
- releaseButton(MotionEvent.BUTTON_SECONDARY);
- return this;
- }
-
- public MotionEvent build() {
-
- PointerProperties[] pointers = new PointerProperties[1];
- pointers[0] = new PointerProperties();
- pointers[0].id = 0;
- pointers[0].toolType = mState.mToolType;
-
- PointerCoords[] coords = new PointerCoords[1];
- coords[0] = new PointerCoords();
- coords[0].x = mState.mLocation.x;
- coords[0].y = mState.mLocation.y;
-
- int buttons = 0;
- for (Integer button : mState.mButtons) {
- buttons |= button;
- }
-
- int keys = 0;
- for (Integer key : mState.mKeys) {
- keys |= key;
- }
-
- return MotionEvent.obtain(
- 0, // down time
- 1, // event time
- mState.mAction,
- 1, // pointerCount,
- pointers,
- coords,
- keys,
- buttons,
- 1.0f, // x precision
- 1.0f, // y precision
- 0, // device id
- 0, // edge flags
- 0, // int source,
- 0 // int flags
- );
- }
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestHolder.java b/tests/unit/com/android/documentsui/selection/testing/TestHolder.java
deleted file mode 100644
index 071f808a3..000000000
--- a/tests/unit/com/android/documentsui/selection/testing/TestHolder.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection.testing;
-
-import androidx.recyclerview.widget.RecyclerView.ViewHolder;
-import android.view.View;
-
-public class TestHolder extends ViewHolder {
- public TestHolder(View itemView) {
- super(itemView);
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestMouseCallbacks.java b/tests/unit/com/android/documentsui/selection/testing/TestMouseCallbacks.java
deleted file mode 100644
index 32b5bfeef..000000000
--- a/tests/unit/com/android/documentsui/selection/testing/TestMouseCallbacks.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection.testing;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import androidx.recyclerview.widget.RecyclerView;
-import android.view.MotionEvent;
-
-import com.android.documentsui.selection.MouseInputHandler;
-import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
-
-public final class TestMouseCallbacks extends MouseInputHandler.Callbacks {
-
- private String mFocusItemId;
- private int mFocusPosition;
- private MotionEvent mLastContextEvent;
- private ItemDetails mActivated;
-
- @Override
- public boolean onItemActivated(ItemDetails item, MotionEvent e) {
- mActivated = item;
- return true;
- }
-
- @Override
- public boolean onContextClick(MotionEvent e) {
- mLastContextEvent = e;
- return false;
- }
-
- @Override
- public void onPerformHapticFeedback() {
- }
-
- @Override
- public void clearFocus() {
- mFocusPosition = RecyclerView.NO_POSITION;
- mFocusItemId = null;
- }
-
- @Override
- public void focusItem(ItemDetails item) {
- mFocusItemId = item.getStableId();
- mFocusPosition = item.getPosition();
- }
-
- @Override
- public int getFocusedPosition() {
- return mFocusPosition;
- }
-
- @Override
- public boolean hasFocusedItem() {
- return mFocusItemId != null;
- }
-
- public void assertLastEvent(MotionEvent expected) {
- // sadly, MotionEvent doesn't implement equals, so we compare references.
- assertTrue(expected == mLastContextEvent);
- }
-
- public void assertActivated(ItemDetails expected) {
- assertEquals(expected, mActivated);
- }
-
- public void assertHasFocus(boolean focused) {
- assertEquals(focused, hasFocusedItem());
- }
-
- public void assertFocused(String expectedId) {
- assertEquals(expectedId, mFocusItemId);
- }
-} \ No newline at end of file
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestSelectionObserver.java b/tests/unit/com/android/documentsui/selection/testing/TestSelectionObserver.java
deleted file mode 100644
index e75bde3de..000000000
--- a/tests/unit/com/android/documentsui/selection/testing/TestSelectionObserver.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection.testing;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import com.android.documentsui.selection.SelectionHelper.SelectionObserver;
-
-import java.util.HashSet;
-import java.util.Set;
-
-public class TestSelectionObserver extends SelectionObserver {
-
- private final Set<String> mSelected = new HashSet<>();
- private boolean mSelectionChanged = false;
- private boolean mSelectionReset = false;
- private boolean mSelectionRestored = false;
-
- public void reset() {
- mSelected.clear();
- mSelectionChanged = false;
- mSelectionReset = false;
- }
-
- @Override
- public void onItemStateChanged(String id, boolean selected) {
- if (selected) {
- assertNotSelected(id);
- mSelected.add(id);
- } else {
- assertSelected(id);
- mSelected.remove(id);
- }
- }
-
- @Override
- public void onSelectionReset() {
- mSelectionReset = true;
- mSelected.clear();
- }
-
- @Override
- public void onSelectionChanged() {
- mSelectionChanged = true;
- }
-
- @Override
- public void onSelectionRestored() {
- mSelectionRestored = true;
- }
-
- void assertNoSelection() {
- assertTrue(mSelected.isEmpty());
- }
-
- void assertSelectionSize(int expected) {
- assertEquals(expected, mSelected.size());
- }
-
- void assertSelected(String id) {
- assertTrue(id + " is not selected.", mSelected.contains(id));
- }
-
- void assertNotSelected(String id) {
- assertFalse(id + " is already selected", mSelected.contains(id));
- }
-
- public void assertSelectionChanged() {
- assertTrue(mSelectionChanged);
- }
-
- public void assertSelectionUnchanged() {
- assertFalse(mSelectionChanged);
- }
-
- public void assertSelectionReset() {
- assertTrue(mSelectionReset);
- }
-
- public void assertSelectionRestored() {
- assertTrue(mSelectionRestored);
- }
-}
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestStableIdProvider.java b/tests/unit/com/android/documentsui/selection/testing/TestStableIdProvider.java
deleted file mode 100644
index 37c4665c8..000000000
--- a/tests/unit/com/android/documentsui/selection/testing/TestStableIdProvider.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection.testing;
-
-import static androidx.core.util.Preconditions.checkArgument;
-
-import com.android.documentsui.selection.SelectionHelper.StableIdProvider;
-
-import java.util.List;
-
-/**
- * Provides RecyclerView selection code access to stable ids backed
- * by TestAdapter.
- */
-public final class TestStableIdProvider extends StableIdProvider {
-
- private final TestAdapter mAdapter;
-
- public TestStableIdProvider(TestAdapter adapter) {
- checkArgument(adapter != null);
- mAdapter = adapter;
- }
-
- @Override
- public String getStableId(int position) {
- return mAdapter.getStableId(position);
- }
-
- @Override
- public int getPosition(String id) {
- return mAdapter.getPosition(id);
- }
-
- @Override
- public List<String> getStableIds() {
- return mAdapter.getStableIds();
- }
-}