Merge "Disable "New Folder" context menu item in search." into nyc-andromeda-dev
diff --git a/src/com/android/documentsui/AbstractActionHandler.java b/src/com/android/documentsui/AbstractActionHandler.java
index d626b70..5088149 100644
--- a/src/com/android/documentsui/AbstractActionHandler.java
+++ b/src/com/android/documentsui/AbstractActionHandler.java
@@ -25,7 +25,6 @@
 
 import com.android.documentsui.AbstractActionHandler.CommonAddons;
 import com.android.documentsui.base.BooleanConsumer;
-import com.android.documentsui.base.ConfirmationCallback;
 import com.android.documentsui.base.DocumentInfo;
 import com.android.documentsui.base.DocumentStack;
 import com.android.documentsui.base.Lookup;
@@ -34,7 +33,6 @@
 import com.android.documentsui.base.State;
 import com.android.documentsui.dirlist.AnimationView.AnimationType;
 import com.android.documentsui.dirlist.DocumentDetails;
-import com.android.documentsui.dirlist.Model;
 import com.android.documentsui.files.LauncherActivity;
 import com.android.documentsui.files.OpenUriForViewTask;
 import com.android.documentsui.roots.LoadRootTask;
@@ -153,7 +151,7 @@
     }
 
     @Override
-    public void deleteSelectedDocuments(Model model, ConfirmationCallback callback) {
+    public void deleteSelectedDocuments() {
         throw new UnsupportedOperationException("Delete not supported!");
     }
 
diff --git a/src/com/android/documentsui/ActionHandler.java b/src/com/android/documentsui/ActionHandler.java
index 15ee5bc..fe6be0e 100644
--- a/src/com/android/documentsui/ActionHandler.java
+++ b/src/com/android/documentsui/ActionHandler.java
@@ -22,12 +22,10 @@
 import android.net.Uri;
 
 import com.android.documentsui.base.BooleanConsumer;
-import com.android.documentsui.base.ConfirmationCallback;
 import com.android.documentsui.base.DocumentInfo;
 import com.android.documentsui.base.DocumentStack;
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.dirlist.DocumentDetails;
-import com.android.documentsui.dirlist.Model;
 
 public interface ActionHandler {
 
@@ -67,7 +65,7 @@
 
     void showChooserForDoc(DocumentInfo doc);
 
-    void deleteSelectedDocuments(Model model, ConfirmationCallback callback);
+    void deleteSelectedDocuments();
 
     /**
      * Called when initial activity setup is complete. Implementations
diff --git a/src/com/android/documentsui/ActionModeAddons.java b/src/com/android/documentsui/ActionModeAddons.java
new file mode 100644
index 0000000..83eba78
--- /dev/null
+++ b/src/com/android/documentsui/ActionModeAddons.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+/**
+ * Extra ActionMode functionality required by ActionHandlers.
+ */
+public interface ActionModeAddons {
+
+    void finishActionMode();
+
+    void finishOnConfirmed(int code);
+}
diff --git a/src/com/android/documentsui/dirlist/ActionModeController.java b/src/com/android/documentsui/ActionModeController.java
similarity index 86%
rename from src/com/android/documentsui/dirlist/ActionModeController.java
rename to src/com/android/documentsui/ActionModeController.java
index 03582f4..a6fe7f1 100644
--- a/src/com/android/documentsui/dirlist/ActionModeController.java
+++ b/src/com/android/documentsui/ActionModeController.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.documentsui.dirlist;
+package com.android.documentsui;
 
 import static com.android.documentsui.base.Shared.DEBUG;
 
@@ -29,9 +29,7 @@
 import android.view.MenuItem;
 import android.view.View;
 
-import com.android.documentsui.MenuManager;
 import com.android.documentsui.MenuManager.SelectionDetails;
-import com.android.documentsui.R;
 import com.android.documentsui.base.ConfirmationCallback;
 import com.android.documentsui.base.ConfirmationCallback.Result;
 import com.android.documentsui.base.EventHandler;
@@ -46,7 +44,8 @@
 /**
  * A controller that listens to selection changes and manages life cycles of action modes.
  */
-public class ActionModeController implements SelectionManager.Callback, ActionMode.Callback {
+public class ActionModeController
+        implements SelectionManager.Callback, ActionMode.Callback, ActionModeAddons {
 
     private static final String TAG = "ActionModeController";
 
@@ -55,7 +54,7 @@
     private final MenuManager mMenuManager;
     private final MessageBuilder mMessages;
 
-    private final Config mConfig = new Config();
+    private final ContentScope mScope = new ContentScope();
     private final Selection mSelected = new Selection();
 
     private @Nullable ActionMode mActionMode;
@@ -80,7 +79,7 @@
             if (mActionMode == null) {
                 if (DEBUG) Log.d(TAG, "Starting action mode.");
                 mActionMode = mActivity.startActionMode(this);
-                mConfig.hapticPerformer.accept(HapticFeedbackConstants.LONG_PRESS);
+                mScope.hapticPerformer.accept(HapticFeedbackConstants.LONG_PRESS);
             }
             updateActionMenu();
         } else {
@@ -95,7 +94,7 @@
             final String title = mMessages.getQuantityString(
                     R.plurals.elements_selected, mSelected.size());
             mActionMode.setTitle(title);
-            mConfig.accessibilityAnnouncer.accept(title);
+            mScope.accessibilityAnnouncer.accept(title);
         }
     }
 
@@ -120,16 +119,7 @@
             final String title = mMessages.getQuantityString(
                     R.plurals.elements_selected, mSelected.size());
             mActionMode.setTitle(title);
-            mConfig.accessibilityAnnouncer.accept(title);
-        }
-    }
-
-    void finishActionMode() {
-        if (mActionMode != null) {
-            mActionMode.finish();
-            mActionMode = null;
-        } else {
-            Log.w(TAG, "Tried to finish a null action mode.");
+            mScope.accessibilityAnnouncer.accept(title);
         }
     }
 
@@ -151,7 +141,7 @@
         mSelected.clear();
 
         // Re-enable TalkBack for the toolbars, as they are no longer covered by action mode.
-        mConfig.accessibilityImportanceSetter.setAccessibilityImportance(
+        mScope.accessibilityImportanceSetter.setAccessibilityImportance(
                 View.IMPORTANT_FOR_ACCESSIBILITY_AUTO, R.id.toolbar, R.id.roots_toolbar);
     }
 
@@ -165,7 +155,7 @@
 
             // Hide the toolbars if action mode is enabled, so TalkBack doesn't navigate to
             // these controls when using linear navigation.
-            mConfig.accessibilityImportanceSetter.setAccessibilityImportance(
+            mScope.accessibilityImportanceSetter.setAccessibilityImportance(
                     View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
                     R.id.toolbar,
                     R.id.roots_toolbar);
@@ -184,13 +174,13 @@
 
     private void updateActionMenu() {
         assert(mMenu != null);
-        mMenuManager.updateActionMenu(mMenu, mConfig.selectionDetails);
+        mMenuManager.updateActionMenu(mMenu, mScope.selectionDetails);
         Menus.disableHiddenItems(mMenu);
     }
 
     @Override
     public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
-        return mConfig.menuItemClicker.accept(item);
+        return mScope.menuItemClicker.accept(item);
     }
 
     private static void setImportantForAccessibility(
@@ -208,6 +198,17 @@
         void setAccessibilityImportance(int accessibilityImportance, @IdRes int... viewIds);
     }
 
+    @Override
+    public void finishActionMode() {
+        if (mActionMode != null) {
+            mActionMode.finish();
+            mActionMode = null;
+        } else {
+            Log.w(TAG, "Tried to finish a null action mode.");
+        }
+    }
+
+    @Override
     public void finishOnConfirmed(@Result int code) {
         if (code == ConfirmationCallback.CONFIRM) {
             finishActionMode();
@@ -219,11 +220,11 @@
         assert(mActionMode == null);
         assert(mMenu == null);
 
-        mConfig.menuItemClicker = menuItemClicker;
-        mConfig.selectionDetails = selectionDetails;
-        mConfig.hapticPerformer = view::performHapticFeedback;
-        mConfig.accessibilityAnnouncer = view::announceForAccessibility;
-        mConfig.accessibilityImportanceSetter =
+        mScope.menuItemClicker = menuItemClicker;
+        mScope.selectionDetails = selectionDetails;
+        mScope.hapticPerformer = view::performHapticFeedback;
+        mScope.accessibilityAnnouncer = view::announceForAccessibility;
+        mScope.accessibilityImportanceSetter =
                 (int accessibilityImportance, @IdRes int[] viewIds) -> {
                     setImportantForAccessibility(
                             mActivity, accessibilityImportance, viewIds);
@@ -232,7 +233,7 @@
         return this;
     }
 
-    private static final class Config {
+    private static final class ContentScope {
         private EventHandler<MenuItem> menuItemClicker;
         private SelectionDetails selectionDetails;
         private IntConsumer hapticPerformer;
diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java
index 0f285f5..005f887 100644
--- a/src/com/android/documentsui/BaseActivity.java
+++ b/src/com/android/documentsui/BaseActivity.java
@@ -64,7 +64,6 @@
 import com.android.documentsui.base.Shared;
 import com.android.documentsui.base.State;
 import com.android.documentsui.base.State.ViewMode;
-import com.android.documentsui.dirlist.ActionModeController;
 import com.android.documentsui.dirlist.AnimationView;
 import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.dirlist.DocumentsAdapter;
diff --git a/src/com/android/documentsui/MenuManager.java b/src/com/android/documentsui/MenuManager.java
index 39ecbfa..05e7f17 100644
--- a/src/com/android/documentsui/MenuManager.java
+++ b/src/com/android/documentsui/MenuManager.java
@@ -27,7 +27,6 @@
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.base.Shared;
 import com.android.documentsui.base.State;
-import com.android.documentsui.dirlist.ActionModeController;
 import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.sidebar.RootsFragment;
 import com.android.internal.annotations.VisibleForTesting;
diff --git a/src/com/android/documentsui/dirlist/DirectoryFragment.java b/src/com/android/documentsui/dirlist/DirectoryFragment.java
index cb6ffbc..306644d 100644
--- a/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -61,6 +61,7 @@
 import android.widget.TextView;
 
 import com.android.documentsui.ActionHandler;
+import com.android.documentsui.ActionModeController;
 import com.android.documentsui.ActivityConfig;
 import com.android.documentsui.BaseActivity;
 import com.android.documentsui.BaseActivity.RetainedState;
@@ -100,7 +101,6 @@
 import com.android.documentsui.services.FileOperationService.OpType;
 import com.android.documentsui.services.FileOperations;
 import com.android.documentsui.sorting.SortDimension;
-import com.android.documentsui.sorting.SortDimension.SortDirection;
 import com.android.documentsui.sorting.SortModel;
 import com.android.documentsui.ui.DialogController;
 import com.android.documentsui.ui.Snackbars;
@@ -182,7 +182,7 @@
     private MessageBar mMessageBar;
     private View mProgressBar;
 
-    private Config mConfig;
+    private DirectoryState mLocalState;
 
     // 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.
@@ -257,8 +257,8 @@
         // Restore state if fragment recreated.
         Bundle args = savedInstanceState == null ? getArguments() : savedInstanceState;
 
-        mConfig = new Config();
-        mConfig.restore(args);
+        mLocalState = new DirectoryState();
+        mLocalState.restore(args);
 
         // Restore any selection we may have squirreled away in retained state.
         @Nullable RetainedState retained = getBaseActivity().getRetainedState();
@@ -298,7 +298,7 @@
         final BaseActivity activity = getBaseActivity();
         mSelectionMgr = activity.getSelectionManager(mAdapter, this::canSetSelectionState);
         mFocusManager = activity.getFocusManager(mRecView, mModel);
-        mActions = activity.getActionHandler(mModel, mConfig.mSearchMode);
+        mActions = activity.getActionHandler(mModel, mLocalState.mSearchMode);
         mMenuManager = activity.getMenuManager();
         mDialogs = activity.getDialogController();
 
@@ -343,7 +343,6 @@
                 (MotionEvent t) -> MotionInputEvent.obtain(t, mRecView),
                 this::canSelect,
                 this::onRightClick,
-                (DocumentDetails ignored) -> onDeleteSelectedDocuments(), // delete handler
                 mDragStartListener::onTouchDragEvent,
                 gestureHandler);
 
@@ -367,13 +366,13 @@
 
         final ActivityManager am = (ActivityManager) context.getSystemService(
                 Context.ACTIVITY_SERVICE);
-        boolean svelte = am.isLowRamDevice() && (mConfig.mType == TYPE_RECENT_OPEN);
+        boolean svelte = am.isLowRamDevice() && (mLocalState.mType == TYPE_RECENT_OPEN);
         mIconHelper.setThumbnailsEnabled(!svelte);
 
         // If mDocument is null, we sort it by last modified by default because it's in Recents.
         final boolean prefersLastModified =
-                (mConfig.mDocument != null)
-                        ? (mConfig.mDocument.flags & Document.FLAG_DIR_PREFERS_LAST_MODIFIED) != 0
+                (mLocalState.mDocument != null)
+                        ? (mLocalState.mDocument.flags & Document.FLAG_DIR_PREFERS_LAST_MODIFIED) != 0
                         : true;
         // Call this before adding the listener to avoid restarting the loader one more time
         state.sortModel.setDefaultDimension(
@@ -403,7 +402,7 @@
         final SparseArray<Parcelable> container = new SparseArray<>();
         getView().saveHierarchyState(container);
         final State state = getDisplayState();
-        state.dirConfigs.put(mConfig.getConfigKey(), container);
+        state.dirConfigs.put(mLocalState.getConfigKey(), container);
     }
 
     public void retainState(RetainedState state) {
@@ -414,7 +413,7 @@
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
 
-        mConfig.save(outState);
+        mLocalState.save(outState);
     }
 
     @Override
@@ -453,7 +452,7 @@
 
     private void handleCopyResult(int resultCode, Intent data) {
 
-        FileOperation operation = mConfig.claimPendingOperation();
+        FileOperation operation = mLocalState.claimPendingOperation();
 
         if (resultCode == Activity.RESULT_CANCELED || data == null) {
             // User pressed the back button or otherwise cancelled the destination pick. Don't
@@ -585,8 +584,7 @@
             case R.id.menu_delete:
                 // deleteDocuments will end action mode if the documents are deleted.
                 // It won't end action mode if user cancels the delete.
-                mActions.deleteSelectedDocuments(
-                        mModel, mActionModeController::finishOnConfirmed);
+                mActions.deleteSelectedDocuments();
                 return true;
 
             case R.id.menu_copy_to:
@@ -726,15 +724,8 @@
         startActivity(intent);
     }
 
-    private boolean onDeleteSelectedDocuments() {
-        if (mSelectionMgr.hasSelection()) {
-            mActions.deleteSelectedDocuments(mModel, mActionModeController::finishOnConfirmed);
-        }
-        return false;
-    }
-
     private void transferDocuments(final Selection selected, final @OpType int mode) {
-        if(mode == FileOperationService.OPERATION_COPY) {
+        if (mode == FileOperationService.OPERATION_COPY) {
             Metrics.logUserAction(getContext(), Metrics.USER_ACTION_COPY_TO);
         } else if (mode == FileOperationService.OPERATION_MOVE) {
             Metrics.logUserAction(getContext(), Metrics.USER_ACTION_MOVE_TO);
@@ -757,7 +748,7 @@
         }
 
         Uri srcParent = getDisplayState().stack.peek().derivedUri;
-        mConfig.mPendingOperation = new FileOperation.Builder()
+        mLocalState.mPendingOperation = new FileOperation.Builder()
                 .withOpType(mode)
                 .withSrcParent(srcParent)
                 .withSrcs(srcs)
@@ -1146,7 +1137,7 @@
             mProgressBar.setVisibility(mModel.isLoading() ? View.VISIBLE : View.GONE);
 
             if (mModel.isEmpty()) {
-                if (mConfig.mSearchMode) {
+                if (mLocalState.mSearchMode) {
                     showNoResults(getDisplayState().stack.root);
                 } else {
                     showEmptyDirectory();
@@ -1201,7 +1192,7 @@
             String query) {
         DirectoryFragment df = get(fm);
 
-        df.mConfig.update(root, doc, query);
+        df.mLocalState.update(root, doc, query);
         df.getLoaderManager().restartLoader(LOADER_ID, null, df);
     }
 
@@ -1210,7 +1201,7 @@
         if (DEBUG) Log.d(TAG, "Reloading directory: " + DocumentInfo.debugString(doc));
         DirectoryFragment df = get(fm);
 
-        df.mConfig.update(type, root, doc, query);
+        df.mLocalState.update(type, root, doc, query);
         df.getLoaderManager().restartLoader(LOADER_ID, null, df);
     }
 
@@ -1281,39 +1272,39 @@
         State state = getDisplayState();
 
         Uri contentsUri;
-        switch (mConfig.mType) {
+        switch (mLocalState.mType) {
             case TYPE_NORMAL:
-                contentsUri = mConfig.mSearchMode ? DocumentsContract.buildSearchDocumentsUri(
-                        mConfig.mRoot.authority, mConfig.mRoot.rootId, mConfig.mQuery)
+                contentsUri = mLocalState.mSearchMode ? DocumentsContract.buildSearchDocumentsUri(
+                        mLocalState.mRoot.authority, mLocalState.mRoot.rootId, mLocalState.mQuery)
                         : DocumentsContract.buildChildDocumentsUri(
-                                mConfig.mDocument.authority, mConfig.mDocument.documentId);
+                                mLocalState.mDocument.authority, mLocalState.mDocument.documentId);
                 if (mActivityConfig.managedModeEnabled(state.stack)) {
                     contentsUri = DocumentsContract.setManageMode(contentsUri);
                 }
                 if (DEBUG) Log.d(TAG, "Creating new directory loader for: "
-                        + DocumentInfo.debugString(mConfig.mDocument));
+                        + DocumentInfo.debugString(mLocalState.mDocument));
                 return new DirectoryLoader(
-                        context, mConfig.mRoot, mConfig.mDocument, contentsUri, state.sortModel,
-                        mConfig.mSearchMode);
+                        context, mLocalState.mRoot, mLocalState.mDocument, contentsUri, state.sortModel,
+                        mLocalState.mSearchMode);
             case TYPE_RECENT_OPEN:
                 if (DEBUG) Log.d(TAG, "Creating new loader recents.");
                 final RootsAccess roots = DocumentsApplication.getRootsCache(context);
                 return new RecentsLoader(context, roots, state);
 
             default:
-                throw new IllegalStateException("Unknown type " + mConfig.mType);
+                throw new IllegalStateException("Unknown type " + mLocalState.mType);
         }
     }
 
     @Override
     public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
         if (DEBUG) Log.d(TAG, "Loader has finished for: "
-                + DocumentInfo.debugString(mConfig.mDocument));
+                + DocumentInfo.debugString(mLocalState.mDocument));
         assert(result != null);
 
         if (!isAdded()) return;
 
-        if (mConfig.mSearchMode) {
+        if (mLocalState.mSearchMode) {
             Metrics.logUserAction(getContext(), Metrics.USER_ACTION_SEARCH);
         }
 
@@ -1332,22 +1323,22 @@
         }
 
         // Restore any previous instance state
-        final SparseArray<Parcelable> container = state.dirConfigs.remove(mConfig.getConfigKey());
+        final SparseArray<Parcelable> container = state.dirConfigs.remove(mLocalState.getConfigKey());
         final int curSortedDimensionId = state.sortModel.getSortedDimensionId();
 
         final SortDimension curSortedDimension =
                 state.sortModel.getDimensionById(curSortedDimensionId);
         if (container != null && !getArguments().getBoolean(Shared.EXTRA_IGNORE_STATE, false)) {
             getView().restoreHierarchyState(container);
-        } else if (mConfig.mLastSortDimensionId != curSortedDimension.getId()
-                || mConfig.mLastSortDimensionId == SortModel.SORT_DIMENSION_ID_UNKNOWN
-                || mConfig.mLastSortDirection != curSortedDimension.getSortDirection()) {
+        } else if (mLocalState.mLastSortDimensionId != curSortedDimension.getId()
+                || mLocalState.mLastSortDimensionId == SortModel.SORT_DIMENSION_ID_UNKNOWN
+                || mLocalState.mLastSortDirection != curSortedDimension.getSortDirection()) {
             // Scroll to the top if the sort order actually changed.
             mRecView.smoothScrollToPosition(0);
         }
 
-        mConfig.mLastSortDimensionId = curSortedDimension.getId();
-        mConfig.mLastSortDirection = curSortedDimension.getSortDirection();
+        mLocalState.mLastSortDimensionId = curSortedDimension.getId();
+        mLocalState.mLastSortDirection = curSortedDimension.getSortDirection();
 
         if (mRefreshLayout.isRefreshing()) {
             new Handler().postDelayed(
@@ -1359,81 +1350,9 @@
     @Override
     public void onLoaderReset(Loader<DirectoryResult> loader) {
         if (DEBUG) Log.d(TAG, "Resetting loader for: "
-                + DocumentInfo.debugString(mConfig.mDocument));
+                + DocumentInfo.debugString(mLocalState.mDocument));
         mModel.onLoaderReset();
 
         mRefreshLayout.setRefreshing(false);
     }
-
-    private static final class Config {
-
-        private static final String EXTRA_SORT_DIMENSION_ID = "sortDimensionId";
-        private static final String EXTRA_SORT_DIRECTION = "sortDirection";
-
-        // Directory fragment state is defined by: root, document, query, type, selection
-        private @ResultType int mType = TYPE_NORMAL;
-        private RootInfo mRoot;
-        // Null when viewing Recents directory.
-        private @Nullable DocumentInfo mDocument;
-        private String mQuery = null;
-        // Here we save the clip details of moveTo/copyTo actions when picker shows up.
-        // This will be written to saved instance.
-        private @Nullable FileOperation mPendingOperation;
-        private boolean mSearchMode;
-        private int mLastSortDimensionId = SortModel.SORT_DIMENSION_ID_UNKNOWN;
-        private @SortDirection int mLastSortDirection;
-
-        private String mConfigKey;
-
-        public void restore(Bundle bundle) {
-            mRoot = bundle.getParcelable(Shared.EXTRA_ROOT);
-            mDocument = bundle.getParcelable(Shared.EXTRA_DOC);
-            mQuery = bundle.getString(Shared.EXTRA_QUERY);
-            mType = bundle.getInt(Shared.EXTRA_TYPE);
-            mSearchMode = bundle.getBoolean(Shared.EXTRA_SEARCH_MODE);
-            mPendingOperation = bundle.getParcelable(FileOperationService.EXTRA_OPERATION);
-            mLastSortDimensionId = bundle.getInt(EXTRA_SORT_DIMENSION_ID);
-            mLastSortDirection = bundle.getInt(EXTRA_SORT_DIRECTION);
-        }
-
-        public void save(Bundle bundle) {
-            bundle.putInt(Shared.EXTRA_TYPE, mType);
-            bundle.putParcelable(Shared.EXTRA_ROOT, mRoot);
-            bundle.putParcelable(Shared.EXTRA_DOC, mDocument);
-            bundle.putString(Shared.EXTRA_QUERY, mQuery);
-            bundle.putBoolean(Shared.EXTRA_SEARCH_MODE, mSearchMode);
-            bundle.putParcelable(FileOperationService.EXTRA_OPERATION, mPendingOperation);
-            bundle.putInt(EXTRA_SORT_DIMENSION_ID, mLastSortDimensionId);
-            bundle.putInt(EXTRA_SORT_DIRECTION, mLastSortDirection);
-        }
-
-        public FileOperation claimPendingOperation() {
-            FileOperation op = mPendingOperation;
-            mPendingOperation = null;
-            return op;
-        }
-
-        public void update(int type, RootInfo root, DocumentInfo doc, String query) {
-            mType = type;
-            update(root, doc, query);
-        }
-
-        public void update(RootInfo root, DocumentInfo doc, String query) {
-            mQuery = query;
-            mRoot = root;
-            mDocument = doc;
-            mSearchMode =  query != null;
-        }
-
-        private String getConfigKey() {
-            if (mConfigKey == null) {
-                final StringBuilder builder = new StringBuilder();
-                builder.append(mRoot != null ? mRoot.authority : "null").append(';');
-                builder.append(mRoot != null ? mRoot.rootId : "null").append(';');
-                builder.append(mDocument != null ? mDocument.documentId : "null");
-                mConfigKey = builder.toString();
-            }
-            return mConfigKey;
-        }
-    }
 }
diff --git a/src/com/android/documentsui/dirlist/DirectoryState.java b/src/com/android/documentsui/dirlist/DirectoryState.java
new file mode 100644
index 0000000..6b849a2
--- /dev/null
+++ b/src/com/android/documentsui/dirlist/DirectoryState.java
@@ -0,0 +1,101 @@
+/*
+ * 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.dirlist;
+
+import android.os.Bundle;
+
+import com.android.documentsui.base.DocumentInfo;
+import com.android.documentsui.base.RootInfo;
+import com.android.documentsui.base.Shared;
+import com.android.documentsui.dirlist.DirectoryFragment.ResultType;
+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 javax.annotation.Nullable;
+
+final class DirectoryState {
+
+    private static final String EXTRA_SORT_DIMENSION_ID = "sortDimensionId";
+    private static final String EXTRA_SORT_DIRECTION = "sortDirection";
+
+    // Directory fragment state is defined by: root, document, query, type, selection
+    @ResultType int mType = DirectoryFragment.TYPE_NORMAL;
+    RootInfo mRoot;
+    // Null when viewing Recents directory.
+    @Nullable DocumentInfo mDocument;
+    String mQuery = null;
+    // Here we save the clip details of moveTo/copyTo actions when picker shows up.
+    // This will be written to saved instance.
+    @Nullable FileOperation mPendingOperation;
+    boolean mSearchMode;
+    int mLastSortDimensionId = SortModel.SORT_DIMENSION_ID_UNKNOWN;
+    @SortDirection int mLastSortDirection;
+
+    private String mConfigKey;
+
+    public void restore(Bundle bundle) {
+        mRoot = bundle.getParcelable(Shared.EXTRA_ROOT);
+        mDocument = bundle.getParcelable(Shared.EXTRA_DOC);
+        mQuery = bundle.getString(Shared.EXTRA_QUERY);
+        mType = bundle.getInt(Shared.EXTRA_TYPE);
+        mSearchMode = bundle.getBoolean(Shared.EXTRA_SEARCH_MODE);
+        mPendingOperation = bundle.getParcelable(FileOperationService.EXTRA_OPERATION);
+        mLastSortDimensionId = bundle.getInt(EXTRA_SORT_DIMENSION_ID);
+        mLastSortDirection = bundle.getInt(EXTRA_SORT_DIRECTION);
+    }
+
+    public void save(Bundle bundle) {
+        bundle.putInt(Shared.EXTRA_TYPE, mType);
+        bundle.putParcelable(Shared.EXTRA_ROOT, mRoot);
+        bundle.putParcelable(Shared.EXTRA_DOC, mDocument);
+        bundle.putString(Shared.EXTRA_QUERY, mQuery);
+        bundle.putBoolean(Shared.EXTRA_SEARCH_MODE, mSearchMode);
+        bundle.putParcelable(FileOperationService.EXTRA_OPERATION, mPendingOperation);
+        bundle.putInt(EXTRA_SORT_DIMENSION_ID, mLastSortDimensionId);
+        bundle.putInt(EXTRA_SORT_DIRECTION, mLastSortDirection);
+    }
+
+    public FileOperation claimPendingOperation() {
+        FileOperation op = mPendingOperation;
+        mPendingOperation = null;
+        return op;
+    }
+
+    public void update(int type, RootInfo root, DocumentInfo doc, String query) {
+        mType = type;
+        update(root, doc, query);
+    }
+
+    public void update(RootInfo root, DocumentInfo doc, String query) {
+        mQuery = query;
+        mRoot = root;
+        mDocument = doc;
+        mSearchMode =  query != null;
+    }
+
+    String getConfigKey() {
+        if (mConfigKey == null) {
+            final StringBuilder builder = new StringBuilder();
+            builder.append(mRoot != null ? mRoot.authority : "null").append(';');
+            builder.append(mRoot != null ? mRoot.rootId : "null").append(';');
+            builder.append(mDocument != null ? mDocument.documentId : "null");
+            mConfigKey = builder.toString();
+        }
+        return mConfigKey;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/documentsui/dirlist/UserInputHandler.java b/src/com/android/documentsui/dirlist/UserInputHandler.java
index 4af1fcd..03d40fa 100644
--- a/src/com/android/documentsui/dirlist/UserInputHandler.java
+++ b/src/com/android/documentsui/dirlist/UserInputHandler.java
@@ -45,14 +45,13 @@
 
     private static final String TAG = "UserInputHandler";
 
-    private ActionHandler mActionHandler;
+    private ActionHandler mActions;
     private final FocusHandler mFocusHandler;
     private final SelectionManager mSelectionMgr;
     private final Function<MotionEvent, T> mEventConverter;
     private final Predicate<DocumentDetails> mSelectable;
 
     private final EventHandler<InputEvent> mRightClickHandler;
-    private final EventHandler<DocumentDetails> mDeleteHandler;
 
     private final EventHandler<InputEvent> mTouchDragListener;
     private final EventHandler<InputEvent> mGestureSelectHandler;
@@ -62,23 +61,21 @@
     private final KeyInputHandler mKeyListener;
 
     public UserInputHandler(
-            ActionHandler actionHandler,
+            ActionHandler actions,
             FocusHandler focusHandler,
             SelectionManager selectionMgr,
             Function<MotionEvent, T> eventConverter,
             Predicate<DocumentDetails> selectable,
             EventHandler<InputEvent> rightClickHandler,
-            EventHandler<DocumentDetails> deleteHandler,
             EventHandler<InputEvent> touchDragListener,
             EventHandler<InputEvent> gestureSelectHandler) {
 
-        mActionHandler = actionHandler;
+        mActions = actions;
         mFocusHandler = focusHandler;
         mSelectionMgr = selectionMgr;
         mEventConverter = eventConverter;
         mSelectable = selectable;
         mRightClickHandler = rightClickHandler;
-        mDeleteHandler = deleteHandler;
         mTouchDragListener = touchDragListener;
         mGestureSelectHandler = gestureSelectHandler;
 
@@ -246,7 +243,7 @@
             // otherwise they activate.
             return doc.isInSelectionHotspot(event)
                     ? selectDocument(doc)
-                    : mActionHandler.openDocument(doc);
+                    : mActions.openDocument(doc);
         }
 
         boolean onSingleTapConfirmed(T event) {
@@ -380,7 +377,7 @@
             }
 
             DocumentDetails doc = event.getDocumentDetails();
-            return mActionHandler.viewDocument(doc);
+            return mActions.viewDocument(doc);
         }
 
         final void onLongPress(T event) {
@@ -447,14 +444,14 @@
                     // For non-shifted enter keypresses, fall through.
                 case KeyEvent.KEYCODE_DPAD_CENTER:
                 case KeyEvent.KEYCODE_BUTTON_A:
-                    return mActionHandler.viewDocument(doc);
+                    return mActions.viewDocument(doc);
                 case KeyEvent.KEYCODE_SPACE:
-                    return mActionHandler.previewDocument(doc);
+                    return mActions.previewDocument(doc);
                 case KeyEvent.KEYCODE_FORWARD_DEL:
                     // This has to be handled here instead of in a keyboard shortcut, because
                     // keyboard shortcuts all have to be modified with the 'Ctrl' key.
                     if (mSelectionMgr.hasSelection()) {
-                        mDeleteHandler.accept(doc);
+                        mActions.deleteSelectedDocuments();
                     }
                     // Always handle the key, even if there was nothing to delete. This is a
                     // precaution to prevent other handlers from potentially picking up the event
diff --git a/src/com/android/documentsui/files/ActionHandler.java b/src/com/android/documentsui/files/ActionHandler.java
index e31d587..993af36 100644
--- a/src/com/android/documentsui/files/ActionHandler.java
+++ b/src/com/android/documentsui/files/ActionHandler.java
@@ -27,6 +27,7 @@
 import android.util.Log;
 
 import com.android.documentsui.AbstractActionHandler;
+import com.android.documentsui.ActionModeAddons;
 import com.android.documentsui.ActivityConfig;
 import com.android.documentsui.DocumentsAccess;
 import com.android.documentsui.DocumentsApplication;
@@ -69,6 +70,7 @@
 
     private static final String TAG = "ManagerActionHandler";
 
+    private final ActionModeAddons mActionModeAddons;
     private final DialogController mDialogs;
     private final ActivityConfig mActConfig;
     private final DocumentClipper mClipper;
@@ -82,6 +84,7 @@
             DocumentsAccess docs,
             SelectionManager selectionMgr,
             Lookup<String, Executor> executors,
+            ActionModeAddons actionModeAddons,
             DialogController dialogs,
             ActivityConfig tuner,
             DocumentClipper clipper,
@@ -89,6 +92,7 @@
 
         super(activity, state, roots, docs, selectionMgr, executors);
 
+        mActionModeAddons = actionModeAddons;
         mDialogs = dialogs;
         mActConfig = tuner;
         mClipper = clipper;
@@ -181,7 +185,7 @@
     }
 
     @Override
-    public void deleteSelectedDocuments(Model model, ConfirmationCallback callback) {
+    public void deleteSelectedDocuments() {
         assert(mSelectionMgr.hasSelection());
 
         Metrics.logUserAction(mActivity, Metrics.USER_ACTION_DELETE);
@@ -193,11 +197,11 @@
         assert(srcParent != null);
 
         // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
-        List<DocumentInfo> docs = model.getDocuments(selection);
+        List<DocumentInfo> docs = mScope.model.getDocuments(selection);
 
         ConfirmationCallback result = (@Result int code) -> {
             // share the news with our caller, be it good or bad.
-            callback.accept(code);
+            mActionModeAddons.finishOnConfirmed(code);
 
             if (code != ConfirmationCallback.CONFIRM) {
                 return;
@@ -207,7 +211,7 @@
             try {
                 srcs = UrisSupplier.create(
                         selection,
-                        model::getItemUri,
+                        mScope.model::getItemUri,
                         mClipStore);
             } catch (IOException e) {
                 throw new RuntimeException("Failed to create uri supplier.", e);
diff --git a/src/com/android/documentsui/files/FilesActivity.java b/src/com/android/documentsui/files/FilesActivity.java
index 448b7e9..500bcf7 100644
--- a/src/com/android/documentsui/files/FilesActivity.java
+++ b/src/com/android/documentsui/files/FilesActivity.java
@@ -32,6 +32,7 @@
 import android.view.MenuItem;
 import android.view.View;
 
+import com.android.documentsui.ActionModeController;
 import com.android.documentsui.ActivityConfig;
 import com.android.documentsui.BaseActivity;
 import com.android.documentsui.DocumentsAccess;
@@ -49,7 +50,6 @@
 import com.android.documentsui.base.Shared;
 import com.android.documentsui.base.State;
 import com.android.documentsui.clipping.DocumentClipper;
-import com.android.documentsui.dirlist.ActionModeController;
 import com.android.documentsui.dirlist.AnimationView.AnimationType;
 import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.dirlist.DocumentsAdapter;
@@ -100,6 +100,13 @@
                 });
 
         mDialogs = DialogController.create(this, getMessages());
+
+        mActionModeController = new ActionModeController(
+                this,
+                mSelectionMgr,
+                mMenuManager,
+                getMessages());
+
         mActions = new ActionHandler<>(
                 this,
                 mState,
@@ -107,17 +114,12 @@
                 DocumentsAccess.create(this),
                 mSelectionMgr,
                 ProviderExecutor::forAuthority,
+                mActionModeController,
                 mDialogs,
                 mConfig,
                 mClipper,
                 DocumentsApplication.getClipStore(this));
 
-        mActionModeController = new ActionModeController(
-                this,
-                mSelectionMgr,
-                mMenuManager,
-                getMessages());
-
         RootsFragment.show(getFragmentManager(), null);
 
         final Intent intent = getIntent();
diff --git a/src/com/android/documentsui/picker/PickActivity.java b/src/com/android/documentsui/picker/PickActivity.java
index 12dd19b..42d32ae 100644
--- a/src/com/android/documentsui/picker/PickActivity.java
+++ b/src/com/android/documentsui/picker/PickActivity.java
@@ -43,6 +43,7 @@
 import android.view.MenuItem;
 import android.view.View;
 
+import com.android.documentsui.ActionModeController;
 import com.android.documentsui.ActivityConfig;
 import com.android.documentsui.BaseActivity;
 import com.android.documentsui.DocumentsAccess;
@@ -58,7 +59,6 @@
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.base.Shared;
 import com.android.documentsui.base.State;
-import com.android.documentsui.dirlist.ActionModeController;
 import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.dirlist.DocumentsAdapter;
 import com.android.documentsui.dirlist.Model;
diff --git a/tests/common/com/android/documentsui/TestActionModeAddons.java b/tests/common/com/android/documentsui/TestActionModeAddons.java
new file mode 100644
index 0000000..5e7b7d7
--- /dev/null
+++ b/tests/common/com/android/documentsui/TestActionModeAddons.java
@@ -0,0 +1,36 @@
+/*
+ * 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 com.android.documentsui.testing.TestConfirmationCallback;
+
+/**
+ *
+ */
+public class TestActionModeAddons implements ActionModeAddons {
+
+    public final TestConfirmationCallback finishOnConfimed = new TestConfirmationCallback();
+
+    @Override
+    public void finishActionMode() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void finishOnConfirmed(int code) {
+        finishOnConfimed.accept(code);
+    }
+}
diff --git a/tests/common/com/android/documentsui/TestActivity.java b/tests/common/com/android/documentsui/TestActivity.java
index a2a7b55..9fc4fca 100644
--- a/tests/common/com/android/documentsui/TestActivity.java
+++ b/tests/common/com/android/documentsui/TestActivity.java
@@ -29,8 +29,8 @@
 import com.android.documentsui.base.DocumentInfo;
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.testing.TestEventListener;
-import com.android.documentsui.testing.android.TestPackageManager;
-import com.android.documentsui.testing.android.TestResources;
+import com.android.documentsui.testing.TestPackageManager;
+import com.android.documentsui.testing.TestResources;
 
 import org.mockito.Mockito;
 
diff --git a/tests/common/com/android/documentsui/testing/dirlist/SelectionProbe.java b/tests/common/com/android/documentsui/selection/SelectionProbe.java
similarity index 97%
rename from tests/common/com/android/documentsui/testing/dirlist/SelectionProbe.java
rename to tests/common/com/android/documentsui/selection/SelectionProbe.java
index 9cadf71..c0973d6 100644
--- a/tests/common/com/android/documentsui/testing/dirlist/SelectionProbe.java
+++ b/tests/common/com/android/documentsui/selection/SelectionProbe.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.documentsui.testing.dirlist;
+package com.android.documentsui.selection;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
diff --git a/tests/common/com/android/documentsui/testing/dirlist/TestSelectionListener.java b/tests/common/com/android/documentsui/selection/TestSelectionListener.java
similarity index 96%
rename from tests/common/com/android/documentsui/testing/dirlist/TestSelectionListener.java
rename to tests/common/com/android/documentsui/selection/TestSelectionListener.java
index 14eac8f..62a86b0 100644
--- a/tests/common/com/android/documentsui/testing/dirlist/TestSelectionListener.java
+++ b/tests/common/com/android/documentsui/selection/TestSelectionListener.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.documentsui.testing.dirlist;
+package com.android.documentsui.selection;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
diff --git a/tests/common/com/android/documentsui/testing/android/TestPackageManager.java b/tests/common/com/android/documentsui/testing/TestPackageManager.java
similarity index 98%
rename from tests/common/com/android/documentsui/testing/android/TestPackageManager.java
rename to tests/common/com/android/documentsui/testing/TestPackageManager.java
index a5b28b1..7b1d8dc 100644
--- a/tests/common/com/android/documentsui/testing/android/TestPackageManager.java
+++ b/tests/common/com/android/documentsui/testing/TestPackageManager.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.documentsui.testing.android;
+package com.android.documentsui.testing;
 
 import android.annotation.UserIdInt;
 import android.content.Intent;
diff --git a/tests/common/com/android/documentsui/testing/android/TestResources.java b/tests/common/com/android/documentsui/testing/TestResources.java
similarity index 97%
rename from tests/common/com/android/documentsui/testing/android/TestResources.java
rename to tests/common/com/android/documentsui/testing/TestResources.java
index c962e77..206d46b 100644
--- a/tests/common/com/android/documentsui/testing/android/TestResources.java
+++ b/tests/common/com/android/documentsui/testing/TestResources.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.documentsui.testing.android;
+package com.android.documentsui.testing;
 
 import android.annotation.BoolRes;
 import android.annotation.NonNull;
diff --git a/tests/common/com/android/documentsui/testing/TestRootsAccess.java b/tests/common/com/android/documentsui/testing/TestRootsAccess.java
index 734d521..0a2fbd2 100644
--- a/tests/common/com/android/documentsui/testing/TestRootsAccess.java
+++ b/tests/common/com/android/documentsui/testing/TestRootsAccess.java
@@ -18,7 +18,6 @@
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.base.State;
 import com.android.documentsui.roots.RootsAccess;
-import com.android.documentsui.testing.android.TestPackageManager;
 
 import java.util.ArrayList;
 import java.util.Collection;
diff --git a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_KeyboardTest.java b/tests/unit/com/android/documentsui/dirlist/UserInputHandler_KeyboardTest.java
index 0777f2f..98d3cc0 100644
--- a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_KeyboardTest.java
+++ b/tests/unit/com/android/documentsui/dirlist/UserInputHandler_KeyboardTest.java
@@ -23,13 +23,13 @@
 
 import com.android.documentsui.base.Events.InputEvent;
 import com.android.documentsui.selection.SelectionManager;
+import com.android.documentsui.selection.SelectionProbe;
 import com.android.documentsui.testing.SelectionManagers;
 import com.android.documentsui.testing.TestActionHandler;
 import com.android.documentsui.testing.TestEvent;
+import com.android.documentsui.testing.TestEvent.Builder;
 import com.android.documentsui.testing.TestEventHandler;
 import com.android.documentsui.testing.TestPredicate;
-import com.android.documentsui.testing.TestEvent.Builder;
-import com.android.documentsui.testing.dirlist.SelectionProbe;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -50,7 +50,6 @@
 
     private TestPredicate<DocumentDetails> mCanSelect;
     private TestEventHandler<InputEvent> mRightClickHandler;
-    private TestEventHandler<DocumentDetails> mDeleteHandler;
     private TestEventHandler<InputEvent> mDragAndDropHandler;
     private TestEventHandler<InputEvent> mGestureSelectHandler;
 
@@ -65,7 +64,6 @@
         mFocusHandler = new TestFocusHandler();
         mCanSelect = new TestPredicate<>();
         mRightClickHandler = new TestEventHandler<>();
-        mDeleteHandler = new TestEventHandler<>();
         mDragAndDropHandler = new TestEventHandler<>();
         mGestureSelectHandler = new TestEventHandler<>();
 
@@ -78,7 +76,6 @@
                 },
                 mCanSelect,
                 mRightClickHandler::accept,
-                mDeleteHandler::accept,
                 mDragAndDropHandler::accept,
                 mGestureSelectHandler::accept);
 
diff --git a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_MouseTest.java b/tests/unit/com/android/documentsui/dirlist/UserInputHandler_MouseTest.java
index 787652a..8d7ba82 100644
--- a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_MouseTest.java
+++ b/tests/unit/com/android/documentsui/dirlist/UserInputHandler_MouseTest.java
@@ -25,13 +25,13 @@
 
 import com.android.documentsui.base.Events.InputEvent;
 import com.android.documentsui.selection.SelectionManager;
+import com.android.documentsui.selection.SelectionProbe;
 import com.android.documentsui.testing.SelectionManagers;
 import com.android.documentsui.testing.TestActionHandler;
 import com.android.documentsui.testing.TestEvent;
 import com.android.documentsui.testing.TestEvent.Builder;
 import com.android.documentsui.testing.TestEventHandler;
 import com.android.documentsui.testing.TestPredicate;
-import com.android.documentsui.testing.dirlist.SelectionProbe;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -50,7 +50,6 @@
     private SelectionProbe mSelection;
     private TestPredicate<DocumentDetails> mCanSelect;
     private TestEventHandler<InputEvent> mRightClickHandler;
-    private TestEventHandler<DocumentDetails> mDeleteHandler;
     private TestEventHandler<InputEvent> mDragAndDropHandler;
     private TestEventHandler<InputEvent> mGestureSelectHandler;
 
@@ -65,7 +64,6 @@
         mSelection = new SelectionProbe(selectionMgr);
         mCanSelect = new TestPredicate<>();
         mRightClickHandler = new TestEventHandler<>();
-        mDeleteHandler = new TestEventHandler<>();
         mDragAndDropHandler = new TestEventHandler<>();
         mGestureSelectHandler = new TestEventHandler<>();
 
@@ -78,7 +76,6 @@
                 },
                 mCanSelect,
                 mRightClickHandler::accept,
-                mDeleteHandler::accept,
                 mDragAndDropHandler::accept,
                 mGestureSelectHandler::accept);
 
diff --git a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_RangeTest.java b/tests/unit/com/android/documentsui/dirlist/UserInputHandler_RangeTest.java
index c34322e..f9ca6f6 100644
--- a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_RangeTest.java
+++ b/tests/unit/com/android/documentsui/dirlist/UserInputHandler_RangeTest.java
@@ -22,13 +22,13 @@
 
 import com.android.documentsui.base.Events.InputEvent;
 import com.android.documentsui.selection.SelectionManager;
+import com.android.documentsui.selection.SelectionProbe;
 import com.android.documentsui.testing.SelectionManagers;
 import com.android.documentsui.testing.TestActionHandler;
 import com.android.documentsui.testing.TestEvent;
 import com.android.documentsui.testing.TestEvent.Builder;
 import com.android.documentsui.testing.TestEventHandler;
 import com.android.documentsui.testing.TestPredicate;
-import com.android.documentsui.testing.dirlist.SelectionProbe;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -52,7 +52,6 @@
     private SelectionProbe mSelection;
     private TestPredicate<DocumentDetails> mCanSelect;
     private TestEventHandler<InputEvent> mRightClickHandler;
-    private TestEventHandler<DocumentDetails> mDeleteHandler;
     private TestEventHandler<InputEvent> mDragAndDropHandler;
     private TestEventHandler<InputEvent> mGestureSelectHandler;
     private Builder mEvent;
@@ -66,7 +65,6 @@
         mSelection = new SelectionProbe(selectionMgr);
         mCanSelect = new TestPredicate<>();
         mRightClickHandler = new TestEventHandler<>();
-        mDeleteHandler = new TestEventHandler<>();
         mDragAndDropHandler = new TestEventHandler<>();
         mGestureSelectHandler = new TestEventHandler<>();
 
@@ -79,7 +77,6 @@
                 },
                 mCanSelect,
                 mRightClickHandler::accept,
-                mDeleteHandler::accept,
                 mDragAndDropHandler::accept,
                 mGestureSelectHandler::accept);
 
diff --git a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_TouchTest.java b/tests/unit/com/android/documentsui/dirlist/UserInputHandler_TouchTest.java
index f8ad916..797f11d 100644
--- a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_TouchTest.java
+++ b/tests/unit/com/android/documentsui/dirlist/UserInputHandler_TouchTest.java
@@ -25,13 +25,13 @@
 
 import com.android.documentsui.base.Events.InputEvent;
 import com.android.documentsui.selection.SelectionManager;
+import com.android.documentsui.selection.SelectionProbe;
 import com.android.documentsui.testing.SelectionManagers;
 import com.android.documentsui.testing.TestActionHandler;
 import com.android.documentsui.testing.TestEvent;
 import com.android.documentsui.testing.TestEvent.Builder;
 import com.android.documentsui.testing.TestEventHandler;
 import com.android.documentsui.testing.TestPredicate;
-import com.android.documentsui.testing.dirlist.SelectionProbe;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -51,7 +51,6 @@
     private SelectionProbe mSelection;
     private TestPredicate<DocumentDetails> mCanSelect;
     private TestEventHandler<InputEvent> mRightClickHandler;
-    private TestEventHandler<DocumentDetails> mDeleteHandler;
     private TestEventHandler<InputEvent> mDragAndDropHandler;
     private TestEventHandler<InputEvent> mGestureSelectHandler;
 
@@ -66,7 +65,6 @@
         mSelection = new SelectionProbe(selectionMgr);
         mCanSelect = new TestPredicate<>();
         mRightClickHandler = new TestEventHandler<>();
-        mDeleteHandler = new TestEventHandler<>();
         mDragAndDropHandler = new TestEventHandler<>();
         mGestureSelectHandler = new TestEventHandler<>();
 
@@ -79,7 +77,6 @@
                 },
                 mCanSelect,
                 mRightClickHandler::accept,
-                mDeleteHandler::accept,
                 mDragAndDropHandler::accept,
                 mGestureSelectHandler::accept);
 
diff --git a/tests/unit/com/android/documentsui/files/ActionHandlerTest.java b/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
index 1583b41..2620f14 100644
--- a/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
+++ b/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
@@ -27,6 +27,7 @@
 import android.support.test.runner.AndroidJUnit4;
 
 import com.android.documentsui.R;
+import com.android.documentsui.TestActionModeAddons;
 import com.android.documentsui.base.DocumentInfo;
 import com.android.documentsui.base.DocumentStack;
 import com.android.documentsui.base.RootInfo;
@@ -47,6 +48,7 @@
 
     private TestEnv mEnv;
     private TestActivity mActivity;
+    private TestActionModeAddons mActionModeAddons;
     private TestDialogController mDialogs;
     private TestConfirmationCallback mCallback;
     private ActionHandler<TestActivity> mHandler;
@@ -55,6 +57,7 @@
     public void setUp() {
         mEnv = TestEnv.create();
         mActivity = TestActivity.create();
+        mActionModeAddons = new TestActionModeAddons();
         mDialogs = new TestDialogController();
         mCallback = new TestConfirmationCallback();
         mEnv.roots.configurePm(mActivity.packageMgr);
@@ -66,6 +69,7 @@
                 mEnv.docs,
                 mEnv.selectionMgr,
                 mEnv::lookupExecutor,
+                mActionModeAddons,
                 mDialogs,
                 null,  // tuner, not currently used.
                 null,  // clipper, only used in drag/drop
@@ -106,10 +110,10 @@
     public void testDeleteDocuments() {
         mEnv.populateStack();
 
-        mHandler.deleteSelectedDocuments(mEnv.model, mCallback);
+        mHandler.deleteSelectedDocuments();
         mDialogs.assertNoFileFailures();
         mActivity.startService.assertCalled();
-        mCallback.assertConfirmed();
+        mActionModeAddons.finishOnConfimed.assertConfirmed();
     }
 
     @Test
@@ -117,10 +121,10 @@
         mEnv.populateStack();
 
         mDialogs.rejectNext();
-        mHandler.deleteSelectedDocuments(mEnv.model, mCallback);
+        mHandler.deleteSelectedDocuments();
         mDialogs.assertNoFileFailures();
         mActivity.startService.assertNotCalled();
-        mCallback.assertRejected();
+        mActionModeAddons.finishOnConfimed.assertRejected();
     }
 
     @Test
diff --git a/tests/unit/com/android/documentsui/selection/SelectionManagerTest.java b/tests/unit/com/android/documentsui/selection/SelectionManagerTest.java
index d522efd..d25395a 100644
--- a/tests/unit/com/android/documentsui/selection/SelectionManagerTest.java
+++ b/tests/unit/com/android/documentsui/selection/SelectionManagerTest.java
@@ -24,8 +24,6 @@
 import com.android.documentsui.dirlist.TestData;
 import com.android.documentsui.selection.Selection;
 import com.android.documentsui.testing.SelectionManagers;
-import com.android.documentsui.testing.dirlist.SelectionProbe;
-import com.android.documentsui.testing.dirlist.TestSelectionListener;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/tests/unit/com/android/documentsui/selection/SelectionManager_SingleSelectTest.java b/tests/unit/com/android/documentsui/selection/SelectionManager_SingleSelectTest.java
index d2a546c..b25c1c0 100644
--- a/tests/unit/com/android/documentsui/selection/SelectionManager_SingleSelectTest.java
+++ b/tests/unit/com/android/documentsui/selection/SelectionManager_SingleSelectTest.java
@@ -25,8 +25,6 @@
 import com.android.documentsui.dirlist.TestDocumentsAdapter;
 import com.android.documentsui.selection.SelectionManager;
 import com.android.documentsui.testing.SelectionManagers;
-import com.android.documentsui.testing.dirlist.SelectionProbe;
-import com.android.documentsui.testing.dirlist.TestSelectionListener;
 
 import org.junit.Before;
 import org.junit.Test;