summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Garfield Tan <xutan@google.com> 2016-10-04 14:36:38 -0700
committer Garfield Tan <xutan@google.com> 2016-10-05 17:23:50 -0700
commit208945c4e262868d3ebe0f55f1b895cd5a201cbb (patch)
treebc88b65a37c5886a21038f070bc805144543a09c
parente13f6785f7c0aab6fdc2222756d8e17385e409e6 (diff)
Refactor FragmentTuner to ActivityConfig.
* Move model listener that opens drawer to ActionHandler. * Move showChooserForDoc() to ActionHandler. * Statically initialize ActionHandler. * Isolate OnDragListener to FilesActivity only. Bug: 28315278 Change-Id: I760c8411922fca827fd08c115bd2590ab671c380
-rw-r--r--src/com/android/documentsui/AbstractActionHandler.java6
-rw-r--r--src/com/android/documentsui/ActionHandler.java4
-rw-r--r--src/com/android/documentsui/ActivityConfig.java (renamed from src/com/android/documentsui/dirlist/FragmentTuner.java)23
-rw-r--r--src/com/android/documentsui/BaseActivity.java11
-rw-r--r--src/com/android/documentsui/DrawerController.java18
-rw-r--r--src/com/android/documentsui/dirlist/BandController.java2
-rw-r--r--src/com/android/documentsui/dirlist/DirectoryFragment.java28
-rw-r--r--src/com/android/documentsui/files/ActionHandler.java49
-rw-r--r--src/com/android/documentsui/files/Config.java42
-rw-r--r--src/com/android/documentsui/files/FilesActivity.java15
-rw-r--r--src/com/android/documentsui/files/Tuner.java113
-rw-r--r--src/com/android/documentsui/picker/ActionHandler.java64
-rw-r--r--src/com/android/documentsui/picker/Config.java79
-rw-r--r--src/com/android/documentsui/picker/PickActivity.java15
-rw-r--r--src/com/android/documentsui/picker/Tuner.java159
-rw-r--r--src/com/android/documentsui/sidebar/RootsFragment.java37
-rw-r--r--tests/common/com/android/documentsui/TestActivity.java7
-rw-r--r--tests/common/com/android/documentsui/dirlist/TestModel.java4
-rw-r--r--tests/unit/com/android/documentsui/files/ActionHandlerTest.java12
-rw-r--r--tests/unit/com/android/documentsui/picker/ActionHandlerTest.java34
20 files changed, 360 insertions, 362 deletions
diff --git a/src/com/android/documentsui/AbstractActionHandler.java b/src/com/android/documentsui/AbstractActionHandler.java
index 6b341b8da..6a6d71cd6 100644
--- a/src/com/android/documentsui/AbstractActionHandler.java
+++ b/src/com/android/documentsui/AbstractActionHandler.java
@@ -138,6 +138,11 @@ public abstract class AbstractActionHandler<T extends Activity & CommonAddons>
}
@Override
+ public void showChooserForDoc(DocumentInfo doc) {
+ throw new UnsupportedOperationException("Show chooser for doc not supported!");
+ }
+
+ @Override
public void deleteDocuments(Model model, Selection selection, ConfirmationCallback callback) {
throw new UnsupportedOperationException("Delete not supported!");
}
@@ -171,5 +176,6 @@ public abstract class AbstractActionHandler<T extends Activity & CommonAddons>
void openContainerDocument(DocumentInfo doc);
RootInfo getCurrentRoot();
DocumentInfo getCurrentDirectory();
+ void setRootsDrawerOpen(boolean open);
}
}
diff --git a/src/com/android/documentsui/ActionHandler.java b/src/com/android/documentsui/ActionHandler.java
index 0c33f6c0b..00aaee0a1 100644
--- a/src/com/android/documentsui/ActionHandler.java
+++ b/src/com/android/documentsui/ActionHandler.java
@@ -23,6 +23,7 @@ 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;
@@ -35,7 +36,6 @@ public interface ActionHandler {
/**
* Drops documents on a root.
- * @param check The check to make sure RootsFragment is not detached from activity.
*/
boolean dropOn(ClipData data, RootInfo root);
@@ -64,6 +64,8 @@ public interface ActionHandler {
boolean openDocument(DocumentDetails doc);
+ void showChooserForDoc(DocumentInfo doc);
+
void deleteDocuments(Model model, Selection selection, ConfirmationCallback callback);
/**
diff --git a/src/com/android/documentsui/dirlist/FragmentTuner.java b/src/com/android/documentsui/ActivityConfig.java
index 2451bd2fd..5b70fd5a3 100644
--- a/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/src/com/android/documentsui/ActivityConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,24 +14,25 @@
* limitations under the License.
*/
-package com.android.documentsui.dirlist;
+package com.android.documentsui;
-import com.android.documentsui.base.DocumentInfo;
+import com.android.documentsui.base.DocumentStack;
+import com.android.documentsui.base.State;
/**
* Providers support for specializing the DirectoryFragment to the "host" Activity.
* Feel free to expand the role of this class to handle other specializations.
*/
-public abstract class FragmentTuner {
+public abstract class ActivityConfig {
// Subtly different from isDocumentEnabled. The reason may be illuminated as follows.
// A folder is enabled such that it may be double clicked, even in settings
// when the folder itself cannot be selected. This may also be true of container types.
- public boolean canSelectType(String docMimeType, int docFlags) {
+ public boolean canSelectType(String docMimeType, int docFlags, State state) {
return true;
}
- public boolean isDocumentEnabled(String docMimeType, int docFlags) {
+ public boolean isDocumentEnabled(String docMimeType, int docFlags, State state) {
return true;
}
@@ -39,20 +40,14 @@ public abstract class FragmentTuner {
* When managed mode is enabled, active downloads will be visible in the UI.
* Presumably this should only be true when in the downloads directory.
*/
- protected boolean managedModeEnabled() {
+ public boolean managedModeEnabled(DocumentStack stack) {
return false;
}
/**
* Whether drag n' drop is allowed in this context
*/
- protected boolean dragAndDropEnabled() {
+ public boolean dragAndDropEnabled() {
return false;
}
-
- // TODO: Move to action handler.
- @Deprecated
- protected void showChooserForDoc(DocumentInfo doc) {
- throw new UnsupportedOperationException("Show chooser not supported!");
- }
}
diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java
index 5d1c40c93..e24794a6d 100644
--- a/src/com/android/documentsui/BaseActivity.java
+++ b/src/com/android/documentsui/BaseActivity.java
@@ -64,7 +64,6 @@ import com.android.documentsui.base.State;
import com.android.documentsui.base.State.ViewMode;
import com.android.documentsui.dirlist.AnimationView;
import com.android.documentsui.dirlist.DirectoryFragment;
-import com.android.documentsui.dirlist.FragmentTuner;
import com.android.documentsui.dirlist.Model;
import com.android.documentsui.dirlist.MultiSelectManager;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
@@ -120,7 +119,7 @@ public abstract class BaseActivity
* Provides Activity a means of injection into and specialization of
* DirectoryFragment.
*/
- public abstract FragmentTuner getFragmentTuner(Model model, boolean mSearchMode);
+ public abstract ActivityConfig getActivityConfig();
/**
* Provides Activity a means of injection into and specialization of
@@ -144,10 +143,10 @@ public abstract class BaseActivity
* Provides Activity a means of injection into and specialization of
* fragment actions.
*
- * Args can be nullable when called from a context lacking them, such as RootsFragment.
+ * Args can be null when called from a context lacking fragment, such as RootsFragment.
*/
public abstract ActionHandler getActionHandler(
- @Nullable Model model, @Nullable MultiSelectManager selectionMgr);
+ @Nullable Model model, @Nullable MultiSelectManager selectionMgr, boolean searchMode);
public BaseActivity(@LayoutRes int layoutId, String tag) {
mLayoutId = layoutId;
@@ -168,8 +167,8 @@ public abstract class BaseActivity
setContentView(mLayoutId);
- mDrawer = DrawerController.create(this);
mState = getState(icicle);
+ mDrawer = DrawerController.create(this, getActivityConfig());
Metrics.logActivityLaunch(this, mState, intent);
// we're really interested in retainining state in our very complex
@@ -216,7 +215,6 @@ public abstract class BaseActivity
mSearchManager = new SearchViewManager(searchListener, icicle);
mSortController = SortController.create(this, mState.derivedMode, mState.sortModel);
-
// Base classes must update result in their onCreate.
setResult(Activity.RESULT_CANCELED);
}
@@ -284,6 +282,7 @@ public abstract class BaseActivity
return state;
}
+ @Override
public void setRootsDrawerOpen(boolean open) {
mNavigator.revealRootsDrawer(open);
}
diff --git a/src/com/android/documentsui/DrawerController.java b/src/com/android/documentsui/DrawerController.java
index 2b181f2d1..d5b8f4ff6 100644
--- a/src/com/android/documentsui/DrawerController.java
+++ b/src/com/android/documentsui/DrawerController.java
@@ -20,7 +20,6 @@ import static com.android.documentsui.base.Shared.DEBUG;
import android.annotation.IntDef;
import android.app.Activity;
-import android.support.annotation.ColorRes;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.DrawerLayout.DrawerListener;
@@ -76,7 +75,7 @@ public abstract class DrawerController implements DrawerListener {
/**
* Returns a controller suitable for {@code Layout}.
*/
- static DrawerController create(Activity activity) {
+ public static DrawerController create(Activity activity, ActivityConfig activityConfig) {
DrawerLayout layout = (DrawerLayout) activity.findViewById(R.id.drawer_layout);
@@ -96,7 +95,7 @@ public abstract class DrawerController implements DrawerListener {
R.string.drawer_open,
R.string.drawer_close);
- return new RuntimeDrawerController(layout, drawer, toggle, toolbar);
+ return new RuntimeDrawerController(layout, drawer, toggle, toolbar, activityConfig);
}
/**
@@ -131,8 +130,11 @@ public abstract class DrawerController implements DrawerListener {
private @Trigger int mTrigger = OPENED_OTHER;
public RuntimeDrawerController(
- DrawerLayout layout, View drawer, ActionBarDrawerToggle toggle,
- Toolbar drawerToolbar) {
+ DrawerLayout layout,
+ View drawer,
+ ActionBarDrawerToggle toggle,
+ Toolbar drawerToolbar,
+ ActivityConfig activityConfig) {
mToolbar = drawerToolbar;
assert(layout != null);
@@ -142,8 +144,10 @@ public abstract class DrawerController implements DrawerListener {
mLayout.setDrawerListener(this);
- View edge = layout.findViewById(R.id.drawer_edge);
- edge.setOnDragListener(new ItemDragListener<>(this));
+ if (activityConfig.dragAndDropEnabled()) {
+ View edge = layout.findViewById(R.id.drawer_edge);
+ edge.setOnDragListener(new ItemDragListener<>(this));
+ }
}
@Override
diff --git a/src/com/android/documentsui/dirlist/BandController.java b/src/com/android/documentsui/dirlist/BandController.java
index c938d9391..429b326f1 100644
--- a/src/com/android/documentsui/dirlist/BandController.java
+++ b/src/com/android/documentsui/dirlist/BandController.java
@@ -642,7 +642,7 @@ public class BandController extends OnScrollListener {
*/
private boolean canSelect(String id) {
// TODO: Simplify the logic, so the check whether we can select is done in one place.
- // Consider injecting FragmentTuner, or move the checks from MultiSelectManager to
+ // Consider injecting ActivityConfig, or move the checks from MultiSelectManager to
// Selection.
for (GridModel.OnSelectionChangedListener listener : mOnSelectionChangedListeners) {
if (!listener.onBeforeItemStateChange(id, true)) {
diff --git a/src/com/android/documentsui/dirlist/DirectoryFragment.java b/src/com/android/documentsui/dirlist/DirectoryFragment.java
index a5c2564d6..00c25058a 100644
--- a/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -61,6 +61,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.android.documentsui.ActionHandler;
+import com.android.documentsui.ActivityConfig;
import com.android.documentsui.BaseActivity;
import com.android.documentsui.BaseActivity.RetainedState;
import com.android.documentsui.DirectoryLoader;
@@ -142,7 +143,7 @@ public class DirectoryFragment extends Fragment
private final EventListener<Model.Update> mModelUpdateListener = new ModelUpdateListener();
// This dependency is informally "injected" from the owning Activity in our onCreate method.
- private FragmentTuner mTuner;
+ private ActivityConfig mActivityConfig;
// This dependency is informally "injected" from the owning Activity in our onCreate method.
private FocusManager mFocusManager;
@@ -161,7 +162,7 @@ public class DirectoryFragment extends Fragment
private SelectionMetadata mSelectionMetadata;
private UserInputHandler<InputEvent> mInputHandler;
private @Nullable BandController mBandController;
- private DragHoverListener mDragHoverListener;
+ private @Nullable DragHoverListener mDragHoverListener;
private IconHelper mIconHelper;
private SwipeRefreshLayout mRefreshLayout;
private View mEmptyView;
@@ -173,7 +174,6 @@ public class DirectoryFragment extends Fragment
private GridLayoutManager mLayout;
private int mColumnCount = 1; // This will get updated when layout changes.
- private LayoutInflater mInflater;
private MessageBar mMessageBar;
private View mProgressBar;
@@ -193,7 +193,7 @@ public class DirectoryFragment extends Fragment
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- mInflater = inflater;
+
final View view = inflater.inflate(R.layout.fragment_directory, container, false);
mMessageBar = MessageBar.create(getChildFragmentManager());
@@ -215,9 +215,12 @@ public class DirectoryFragment extends Fragment
mRecView.setItemAnimator(new DirectoryItemAnimator(getActivity()));
mFileList = view.findViewById(R.id.file_list);
- mDragHoverListener = DragHoverListener.create(new DirectoryDragListener(this), mRecView);
+ mActivityConfig = getBaseActivity().getActivityConfig();
+ mDragHoverListener = mActivityConfig.dragAndDropEnabled()
+ ? DragHoverListener.create(new DirectoryDragListener(this), mRecView)
+ : null;
- // Make the recycler and the empty views responsive to drop events.
+ // Make the recycler and the empty views responsive to drop events when allowed.
mRecView.setOnDragListener(mDragHoverListener);
mEmptyView.setOnDragListener(mDragHoverListener);
@@ -301,9 +304,8 @@ public class DirectoryFragment extends Fragment
GestureSelector gestureSel = GestureSelector.create(mSelectionMgr, mRecView);
final BaseActivity activity = getBaseActivity();
- mTuner = activity.getFragmentTuner(mModel, mConfig.mSearchMode);
mFocusManager = activity.getFocusManager(mRecView, mModel);
- mActions = activity.getActionHandler(mModel, mSelectionMgr);
+ mActions = activity.getActionHandler(mModel, mSelectionMgr, mConfig.mSearchMode);
mMenuManager = activity.getMenuManager();
mDialogs = activity.getDialogController();
@@ -311,7 +313,7 @@ public class DirectoryFragment extends Fragment
mBandController = new BandController(mRecView, mAdapter, mSelectionMgr);
}
- DragStartListener mDragStartListener = mTuner.dragAndDropEnabled()
+ DragStartListener mDragStartListener = mActivityConfig.dragAndDropEnabled()
? DragStartListener.create(
mIconHelper,
getContext(),
@@ -669,7 +671,7 @@ public class DirectoryFragment extends Fragment
assert(selected.size() == 1);
DocumentInfo doc =
DocumentInfo.fromDirectoryCursor(mModel.getItem(selected.iterator().next()));
- mTuner.showChooserForDoc(doc);
+ mActions.showChooserForDoc(doc);
}
// TODO: Once selection manager is activity owned, move this logic into
@@ -843,7 +845,7 @@ public class DirectoryFragment extends Fragment
@Override
public boolean isDocumentEnabled(String docMimeType, int docFlags) {
- return mTuner.isDocumentEnabled(docMimeType, docFlags);
+ return mActivityConfig.isDocumentEnabled(docMimeType, docFlags, getDisplayState());
}
private void showEmptyDirectory() {
@@ -1196,7 +1198,7 @@ public class DirectoryFragment extends Fragment
final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
- return mTuner.canSelectType(docMimeType, docFlags);
+ return mActivityConfig.canSelectType(docMimeType, docFlags, getDisplayState());
} else {
// Right now all selected items can be deselected.
return true;
@@ -1303,7 +1305,7 @@ public class DirectoryFragment extends Fragment
mConfig.mRoot.authority, mConfig.mRoot.rootId, mConfig.mQuery)
: DocumentsContract.buildChildDocumentsUri(
mConfig.mDocument.authority, mConfig.mDocument.documentId);
- if (mTuner.managedModeEnabled()) {
+ if (mActivityConfig.managedModeEnabled(state.stack)) {
contentsUri = DocumentsContract.setManageMode(contentsUri);
}
if (DEBUG) Log.d(TAG, "Creating new directory loader for: "
diff --git a/src/com/android/documentsui/files/ActionHandler.java b/src/com/android/documentsui/files/ActionHandler.java
index 121409774..6a1f3adeb 100644
--- a/src/com/android/documentsui/files/ActionHandler.java
+++ b/src/com/android/documentsui/files/ActionHandler.java
@@ -34,16 +34,18 @@ import com.android.documentsui.base.ConfirmationCallback;
import com.android.documentsui.base.ConfirmationCallback.Result;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.DocumentStack;
+import com.android.documentsui.base.EventListener;
import com.android.documentsui.base.Lookup;
import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.State;
import com.android.documentsui.clipping.ClipStore;
import com.android.documentsui.clipping.DocumentClipper;
import com.android.documentsui.clipping.UrisSupplier;
+import com.android.documentsui.ActivityConfig;
import com.android.documentsui.dirlist.AnimationView;
import com.android.documentsui.dirlist.DocumentDetails;
-import com.android.documentsui.dirlist.FragmentTuner;
import com.android.documentsui.dirlist.Model;
+import com.android.documentsui.dirlist.Model.Update;
import com.android.documentsui.dirlist.MultiSelectManager;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.files.ActionHandler.Addons;
@@ -68,7 +70,7 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
private static final String TAG = "ManagerActionHandler";
private final DialogController mDialogs;
- private final FragmentTuner mTuner;
+ private final ActivityConfig mTuner;
private final DocumentClipper mClipper;
private final ClipStore mClipStore;
@@ -81,7 +83,7 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
DocumentsAccess docs,
Lookup<String, Executor> executors,
DialogController dialogs,
- FragmentTuner tuner,
+ ActivityConfig tuner,
DocumentClipper clipper,
ClipStore clipStore) {
@@ -92,7 +94,7 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
mClipper = clipper;
mClipStore = clipStore;
- mConfig = new Config();
+ mConfig = new Config(this::onModelLoaded);
}
@Override
@@ -146,7 +148,7 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
return false;
}
- if (mTuner.isDocumentEnabled(doc.mimeType, doc.flags)) {
+ if (mTuner.isDocumentEnabled(doc.mimeType, doc.flags, mState)) {
onDocumentPicked(doc);
mConfig.selectionMgr.clearSelection();
return true;
@@ -292,6 +294,7 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
return false;
}
+ @Override
public void showChooserForDoc(DocumentInfo doc) {
assert(!doc.isContainer());
@@ -449,8 +452,22 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
return intent;
}
- ActionHandler<T> reset(Model model, MultiSelectManager selectionMgr) {
- mConfig.reset(model, selectionMgr);
+ private void onModelLoaded(Model.Update update) {
+ // When launched into empty root, open drawer.
+ if (mConfig.model.isEmpty()
+ && !mState.hasInitialLocationChanged()
+ && !mConfig.searchMode
+ && !mConfig.modelLoadObserved) {
+ // Opens the drawer *if* an openable drawer is present
+ // else this is a no-op.
+ mActivity.setRootsDrawerOpen(true);
+ }
+
+ mConfig.modelLoadObserved = true;
+ }
+
+ ActionHandler<T> reset(Model model, MultiSelectManager selectionMgr, boolean searchMode) {
+ mConfig.reset(model, selectionMgr, searchMode);
return this;
}
@@ -458,12 +475,28 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
@Nullable Model model;
@Nullable MultiSelectManager selectionMgr;
+ boolean searchMode;
- public void reset(Model model, MultiSelectManager selectionMgr) {
+ private final EventListener<Update> mModelUpdateListener;
+
+ // We use this to keep track of whether a model has been previously loaded or not so we can
+ // open the drawer on empty directories on first launch
+ private boolean modelLoadObserved;
+
+ public Config(EventListener<Update> modelUpdateListener) {
+ mModelUpdateListener = modelUpdateListener;
+ }
+
+ public void reset(Model model, MultiSelectManager selectionMgr, boolean searchMode) {
assert(model != null);
this.model = model;
this.selectionMgr = selectionMgr;
+ this.modelLoadObserved = false;
+ this.searchMode = searchMode;
+
+ model.addUpdateListener(mModelUpdateListener);
+ modelLoadObserved = false;
}
}
diff --git a/src/com/android/documentsui/files/Config.java b/src/com/android/documentsui/files/Config.java
new file mode 100644
index 000000000..69da89e99
--- /dev/null
+++ b/src/com/android/documentsui/files/Config.java
@@ -0,0 +1,42 @@
+/*
+ * 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.files;
+
+import com.android.documentsui.base.DocumentStack;
+import com.android.documentsui.ActivityConfig;
+
+/**
+ * Provides support for Files activity specific specializations.
+ */
+public final class Config extends ActivityConfig {
+
+ @Override
+ public boolean managedModeEnabled(DocumentStack stack) {
+ // When in downloads top level directory, we also show active downloads.
+ // And while we don't allow folders in Downloads, we do allow Zip files in
+ // downloads that themselves can be opened and viewed like directories.
+ // This method helps us understand when to kick in on those special behaviors.
+ return stack.root != null
+ && stack.root.isDownloads()
+ && stack.size() == 1;
+ }
+
+ @Override
+ public boolean dragAndDropEnabled() {
+ return true;
+ }
+}
diff --git a/src/com/android/documentsui/files/FilesActivity.java b/src/com/android/documentsui/files/FilesActivity.java
index f3dfd7751..4feb5f1f2 100644
--- a/src/com/android/documentsui/files/FilesActivity.java
+++ b/src/com/android/documentsui/files/FilesActivity.java
@@ -47,9 +47,9 @@ import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.Shared;
import com.android.documentsui.base.State;
import com.android.documentsui.clipping.DocumentClipper;
+import com.android.documentsui.ActivityConfig;
import com.android.documentsui.dirlist.AnimationView.AnimationType;
import com.android.documentsui.dirlist.DirectoryFragment;
-import com.android.documentsui.dirlist.FragmentTuner;
import com.android.documentsui.dirlist.Model;
import com.android.documentsui.dirlist.MultiSelectManager;
import com.android.documentsui.services.FileOperationService;
@@ -67,7 +67,7 @@ public class FilesActivity extends BaseActivity implements ActionHandler.Addons
public static final String TAG = "FilesActivity";
- private Tuner mTuner;
+ private final Config mConfig = new Config();
private MenuManager mMenuManager;
private FocusManager mFocusManager;
private ActionHandler<FilesActivity> mActions;
@@ -93,7 +93,6 @@ public class FilesActivity extends BaseActivity implements ActionHandler.Addons
}
});
- mTuner = new Tuner(this, mState);
// Make sure this is done after the RecyclerView and the Model are set up.
mFocusManager = new FocusManager(getColor(R.color.accent_dark));
mDialogs = DialogController.create(this);
@@ -104,7 +103,7 @@ public class FilesActivity extends BaseActivity implements ActionHandler.Addons
DocumentsAccess.create(this),
ProviderExecutor::forAuthority,
mDialogs,
- mTuner,
+ mConfig,
mClipper,
DocumentsApplication.getClipStore(this));
@@ -341,8 +340,8 @@ public class FilesActivity extends BaseActivity implements ActionHandler.Addons
}
@Override
- public FragmentTuner getFragmentTuner(Model model, boolean mSearchMode) {
- return mTuner.reset(model, mSearchMode);
+ public ActivityConfig getActivityConfig() {
+ return mConfig;
}
@Override
@@ -357,7 +356,7 @@ public class FilesActivity extends BaseActivity implements ActionHandler.Addons
@Override
public ActionHandler<FilesActivity> getActionHandler(
- Model model, MultiSelectManager selectionMgr) {
+ Model model, MultiSelectManager selectionMgr, boolean searchMode) {
// provide our friend, RootsFragment, early access to this special feature!
if (model == null || selectionMgr == null) {
@@ -365,7 +364,7 @@ public class FilesActivity extends BaseActivity implements ActionHandler.Addons
assert(selectionMgr == null);
return mActions;
}
- return mActions.reset(model, selectionMgr);
+ return mActions.reset(model, selectionMgr, searchMode);
}
@Override
diff --git a/src/com/android/documentsui/files/Tuner.java b/src/com/android/documentsui/files/Tuner.java
deleted file mode 100644
index d8bb224a7..000000000
--- a/src/com/android/documentsui/files/Tuner.java
+++ /dev/null
@@ -1,113 +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.files;
-
-import com.android.documentsui.base.DocumentInfo;
-import com.android.documentsui.base.EventListener;
-import com.android.documentsui.base.State;
-import com.android.documentsui.dirlist.FragmentTuner;
-import com.android.documentsui.dirlist.Model;
-import com.android.documentsui.dirlist.Model.Update;
-
-import javax.annotation.Nullable;
-
-/**
- * Provides support for Files activity specific specializations of DirectoryFragment.
- */
-public final class Tuner extends FragmentTuner {
-
- private final FilesActivity mActivity;
- private final State mState;
-
- private Config mConfig = new Config(this::onModelLoaded);
-
- public Tuner(FilesActivity activity, State state) {
-
- assert(activity != null);
- assert(state != null);
-
- mActivity = activity;
- mState = state;
- }
-
- private void onModelLoaded(Model.Update update) {
- mConfig.modelLoadObserved = true;
-
- // When launched into empty root, open drawer.
- if (mConfig.model.isEmpty()
- && !mState.hasInitialLocationChanged()
- && !mConfig.searchMode
- && !mConfig.modelLoadObserved) {
- // Opens the drawer *if* an openable drawer is present
- // else this is a no-op.
- mActivity.setRootsDrawerOpen(true);
- }
- }
-
- @Override
- public boolean managedModeEnabled() {
- // When in downloads top level directory, we also show active downloads.
- // And while we don't allow folders in Downloads, we do allow Zip files in
- // downloads that themselves can be opened and viewed like directories.
- // This method helps us understand when to kick in on those special behaviors.
- return mState.stack.root != null
- && mState.stack.root.isDownloads()
- && mState.stack.size() == 1;
- }
-
- @Override
- public boolean dragAndDropEnabled() {
- return true;
- }
-
- // TODO: Move to action handler.
- @Override
- public void showChooserForDoc(DocumentInfo doc) {
- mActivity.showChooserForDoc(doc);
- }
-
- Tuner reset(Model model, boolean searchMode) {
- mConfig.reset(model, searchMode);
- return this;
- }
-
- private static final class Config {
-
- @Nullable Model model;
- boolean searchMode;
-
- private final EventListener<Update> mModelUpdateListener;
-
- public Config(EventListener<Update> modelUpdateListener) {
- mModelUpdateListener = modelUpdateListener;
- }
-
- // We use this to keep track of whether a model has been previously loaded or not so we can
- // open the drawer on empty directories on first launch
- private boolean modelLoadObserved;
-
- public void reset(Model model, boolean searchMode) {
- this.searchMode = searchMode;
- assert(model != null);
-
- this.model = model;
-
- model.addUpdateListener(mModelUpdateListener);
- modelLoadObserved = false;
- }
- }
-}
diff --git a/src/com/android/documentsui/picker/ActionHandler.java b/src/com/android/documentsui/picker/ActionHandler.java
index d5f7bbea8..11173633f 100644
--- a/src/com/android/documentsui/picker/ActionHandler.java
+++ b/src/com/android/documentsui/picker/ActionHandler.java
@@ -17,6 +17,8 @@
package com.android.documentsui.picker;
import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.base.State.ACTION_PICK_COPY_DESTINATION;
import android.app.Activity;
import android.content.Intent;
@@ -30,13 +32,16 @@ import com.android.documentsui.DocumentsAccess;
import com.android.documentsui.Metrics;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.DocumentStack;
+import com.android.documentsui.base.EventListener;
import com.android.documentsui.base.Lookup;
+import com.android.documentsui.base.MimePredicate;
import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.Shared;
import com.android.documentsui.base.State;
+import com.android.documentsui.ActivityConfig;
import com.android.documentsui.dirlist.DocumentDetails;
-import com.android.documentsui.dirlist.FragmentTuner;
import com.android.documentsui.dirlist.Model;
+import com.android.documentsui.dirlist.Model.Update;
import com.android.documentsui.dirlist.MultiSelectManager;
import com.android.documentsui.picker.ActionHandler.Addons;
import com.android.documentsui.roots.RootsAccess;
@@ -52,7 +57,7 @@ class ActionHandler<T extends Activity & Addons> extends AbstractActionHandler<T
private static final String TAG = "PickerActionHandler";
- private final FragmentTuner mTuner;
+ private final ActivityConfig mActivityConfig;
private final Config mConfig;
ActionHandler(
@@ -61,12 +66,12 @@ class ActionHandler<T extends Activity & Addons> extends AbstractActionHandler<T
RootsAccess roots,
DocumentsAccess docs,
Lookup<String, Executor> executors,
- FragmentTuner tuner) {
+ ActivityConfig activityConfig) {
super(activity, state, roots, docs, executors);
- mTuner = tuner;
- mConfig = new Config();
+ mActivityConfig = activityConfig;
+ mConfig = new Config(this::onModelLoaded);
}
@Override
@@ -135,7 +140,7 @@ class ActionHandler<T extends Activity & Addons> extends AbstractActionHandler<T
return false;
}
- if (mTuner.isDocumentEnabled(doc.mimeType, doc.flags)) {
+ if (mActivityConfig.isDocumentEnabled(doc.mimeType, doc.flags, mState)) {
mActivity.onDocumentPicked(doc);
mConfig.selectionMgr.clearSelection();
return true;
@@ -143,8 +148,35 @@ class ActionHandler<T extends Activity & Addons> extends AbstractActionHandler<T
return false;
}
- ActionHandler<T> reset(Model model, MultiSelectManager selectionMgr) {
- mConfig.reset(model, selectionMgr);
+ private void onModelLoaded(Model.Update update) {
+ boolean showDrawer = false;
+
+ if (MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) {
+ showDrawer = false;
+ }
+ if (mState.external && mState.action == ACTION_GET_CONTENT) {
+ showDrawer = true;
+ }
+ if (mState.action == ACTION_PICK_COPY_DESTINATION) {
+ showDrawer = true;
+ }
+
+ // When launched into empty root, open drawer.
+ if (mConfig.model.isEmpty()) {
+ showDrawer = true;
+ }
+
+ if (showDrawer && !mState.hasInitialLocationChanged() && !mConfig.searchMode
+ && !mConfig.modelLoadObserved) {
+ // This noops on layouts without drawer, so no need to guard.
+ mActivity.setRootsDrawerOpen(true);
+ }
+
+ mConfig.modelLoadObserved = true;
+ }
+
+ ActionHandler<T> reset(Model model, MultiSelectManager selectionMgr, boolean searchMode) {
+ mConfig.reset(model, selectionMgr, searchMode);
return this;
}
@@ -152,12 +184,26 @@ class ActionHandler<T extends Activity & Addons> extends AbstractActionHandler<T
@Nullable Model model;
@Nullable MultiSelectManager selectionMgr;
+ boolean searchMode;
+
+ // We use this to keep track of whether a model has been previously loaded or not so we can
+ // open the drawer on empty directories on first launch
+ private boolean modelLoadObserved;
- public void reset(Model model, MultiSelectManager selectionMgr) {
+ private final EventListener<Update> mModelUpdateListener;
+
+ public Config(EventListener<Update> modelUpdateListener) {
+ mModelUpdateListener = modelUpdateListener;
+ }
+
+ public void reset(Model model, MultiSelectManager selectionMgr, boolean searchMode) {
assert(model != null);
this.model = model;
this.selectionMgr = selectionMgr;
+ this.searchMode = searchMode;
+
+ model.addUpdateListener(mModelUpdateListener);
}
}
diff --git a/src/com/android/documentsui/picker/Config.java b/src/com/android/documentsui/picker/Config.java
new file mode 100644
index 000000000..2d83ba1cd
--- /dev/null
+++ b/src/com/android/documentsui/picker/Config.java
@@ -0,0 +1,79 @@
+/*
+ * 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.picker;
+
+import static com.android.documentsui.base.State.ACTION_CREATE;
+import static com.android.documentsui.base.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.base.State.ACTION_OPEN;
+import static com.android.documentsui.base.State.ACTION_OPEN_TREE;
+import static com.android.documentsui.base.State.ACTION_PICK_COPY_DESTINATION;
+
+import android.provider.DocumentsContract.Document;
+
+import com.android.documentsui.base.MimePredicate;
+import com.android.documentsui.base.State;
+import com.android.documentsui.ActivityConfig;
+
+/**
+ * Provides support for Platform specific specializations of DirectoryFragment.
+ */
+final class Config extends ActivityConfig {
+
+ @Override
+ public boolean canSelectType(String docMimeType, int docFlags, State state) {
+ if (!isDocumentEnabled(docMimeType, docFlags, state)) {
+ return false;
+ }
+
+ if (MimePredicate.isDirectoryType(docMimeType)) {
+ return false;
+ }
+
+ if (state.action == ACTION_OPEN_TREE || state.action == ACTION_PICK_COPY_DESTINATION) {
+ // In this case nothing *ever* is selectable...the expected user behavior is
+ // they navigate *into* a folder, then click a confirmation button indicating
+ // that the current directory is the directory they are picking.
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean isDocumentEnabled(String mimeType, int docFlags, State state) {
+ // Directories are always enabled.
+ if (MimePredicate.isDirectoryType(mimeType)) {
+ return true;
+ }
+
+ switch (state.action) {
+ case ACTION_CREATE:
+ // Read-only files are disabled when creating.
+ if ((docFlags & Document.FLAG_SUPPORTS_WRITE) == 0) {
+ return false;
+ }
+ case ACTION_OPEN:
+ case ACTION_GET_CONTENT:
+ final boolean isVirtual = (docFlags & Document.FLAG_VIRTUAL_DOCUMENT) != 0;
+ if (isVirtual && state.openableOnly) {
+ return false;
+ }
+ }
+
+ return MimePredicate.mimeMatches(state.acceptMimes, mimeType);
+ }
+}
diff --git a/src/com/android/documentsui/picker/PickActivity.java b/src/com/android/documentsui/picker/PickActivity.java
index 962d3a9bd..da8b97bf9 100644
--- a/src/com/android/documentsui/picker/PickActivity.java
+++ b/src/com/android/documentsui/picker/PickActivity.java
@@ -55,8 +55,8 @@ import com.android.documentsui.base.PairedTask;
import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.Shared;
import com.android.documentsui.base.State;
+import com.android.documentsui.ActivityConfig;
import com.android.documentsui.dirlist.DirectoryFragment;
-import com.android.documentsui.dirlist.FragmentTuner;
import com.android.documentsui.dirlist.Model;
import com.android.documentsui.dirlist.MultiSelectManager;
import com.android.documentsui.picker.LastAccessedProvider.Columns;
@@ -72,7 +72,7 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons {
private static final int CODE_FORWARD = 42;
private static final String TAG = "PickActivity";
- private Tuner mTuner;
+ private final Config mConfig = new Config();
private FocusManager mFocusManager;
private MenuManager mMenuManager;
private ActionHandler<PickActivity> mActionHandler;
@@ -85,7 +85,6 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons {
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- mTuner = new Tuner(this, mState);
mFocusManager = new FocusManager(getColor(R.color.accent_dark));
mMenuManager = new MenuManager(mSearchManager, mState, new DirectoryDetails(this));
mActionHandler = new ActionHandler<>(
@@ -94,7 +93,7 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons {
DocumentsApplication.getRootsCache(this),
DocumentsAccess.create(this),
ProviderExecutor::forAuthority,
- mTuner);
+ mConfig);
Intent intent = getIntent();
@@ -395,8 +394,8 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons {
}
@Override
- public FragmentTuner getFragmentTuner(Model model, boolean mSearchMode) {
- return mTuner.reset(model, mSearchMode);
+ public ActivityConfig getActivityConfig() {
+ return mConfig;
}
@Override
@@ -411,7 +410,7 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons {
@Override
public ActionHandler<PickActivity> getActionHandler(
- Model model, MultiSelectManager selectionMgr) {
+ Model model, MultiSelectManager selectionMgr, boolean searchMode) {
// provide our friend, RootsFragment, early access to this special feature!
if (model == null || selectionMgr == null) {
@@ -419,7 +418,7 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons {
assert(selectionMgr == null);
return mActionHandler;
}
- return mActionHandler.reset(model, selectionMgr);
+ return mActionHandler.reset(model, selectionMgr, searchMode);
}
/* (non-Javadoc)
diff --git a/src/com/android/documentsui/picker/Tuner.java b/src/com/android/documentsui/picker/Tuner.java
deleted file mode 100644
index cccb01f0f..000000000
--- a/src/com/android/documentsui/picker/Tuner.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.picker;
-
-import static com.android.documentsui.base.State.ACTION_CREATE;
-import static com.android.documentsui.base.State.ACTION_GET_CONTENT;
-import static com.android.documentsui.base.State.ACTION_OPEN;
-import static com.android.documentsui.base.State.ACTION_OPEN_TREE;
-import static com.android.documentsui.base.State.ACTION_PICK_COPY_DESTINATION;
-
-import android.provider.DocumentsContract.Document;
-
-import com.android.documentsui.base.EventListener;
-import com.android.documentsui.base.MimePredicate;
-import com.android.documentsui.base.State;
-import com.android.documentsui.dirlist.FragmentTuner;
-import com.android.documentsui.dirlist.Model;
-import com.android.documentsui.dirlist.Model.Update;
-
-import javax.annotation.Nullable;
-
-/**
- * Provides support for Platform specific specializations of DirectoryFragment.
- */
-final class Tuner extends FragmentTuner {
-
- private static final String TAG = "PickTuner";
-
-
- private final PickActivity mActivity;
- private final State mState;
-
- private final Config mConfig = new Config(this::onModelLoaded);
-
- public Tuner(PickActivity activity, State state) {
-
- assert(activity != null);
- assert(state != null);
-
- mActivity = activity;
- mState = state;
- }
-
- @Override
- public boolean canSelectType(String docMimeType, int docFlags) {
- if (!isDocumentEnabled(docMimeType, docFlags)) {
- return false;
- }
-
- if (MimePredicate.isDirectoryType(docMimeType)) {
- return false;
- }
-
- if (mState.action == ACTION_OPEN_TREE
- || mState.action == ACTION_PICK_COPY_DESTINATION) {
- // In this case nothing *ever* is selectable...the expected user behavior is
- // they navigate *into* a folder, then click a confirmation button indicating
- // that the current directory is the directory they are picking.
- return false;
- }
-
- return true;
- }
-
- @Override
- public boolean isDocumentEnabled(String mimeType, int docFlags) {
- // Directories are always enabled.
- if (MimePredicate.isDirectoryType(mimeType)) {
- return true;
- }
-
- switch (mState.action) {
- case ACTION_CREATE:
- // Read-only files are disabled when creating.
- if ((docFlags & Document.FLAG_SUPPORTS_WRITE) == 0) {
- return false;
- }
- case ACTION_OPEN:
- case ACTION_GET_CONTENT:
- final boolean isVirtual = (docFlags & Document.FLAG_VIRTUAL_DOCUMENT) != 0;
- if (isVirtual && mState.openableOnly) {
- return false;
- }
- }
-
- return MimePredicate.mimeMatches(mState.acceptMimes, mimeType);
- }
-
- private void onModelLoaded(Model.Update update) {
- mConfig.modelLoadObserved = true;
- boolean showDrawer = false;
-
- if (MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) {
- showDrawer = false;
- }
- if (mState.external && mState.action == ACTION_GET_CONTENT) {
- showDrawer = true;
- }
- if (mState.action == ACTION_PICK_COPY_DESTINATION) {
- showDrawer = true;
- }
-
- // When launched into empty root, open drawer.
- if (mConfig.model.isEmpty()) {
- showDrawer = true;
- }
-
- if (showDrawer && !mState.hasInitialLocationChanged() && !mConfig.searchMode
- && !mConfig.modelLoadObserved) {
- // This noops on layouts without drawer, so no need to guard.
- mActivity.setRootsDrawerOpen(true);
- }
- }
-
- Tuner reset(Model model, boolean searchMode) {
- mConfig.reset(model, searchMode);
- return this;
- }
-
- private static final class Config {
-
- @Nullable Model model;
- boolean searchMode;
-
- private final EventListener<Update> mModelUpdateListener;
-
- public Config(EventListener<Update> modelUpdateListener) {
- mModelUpdateListener = modelUpdateListener;
- }
-
- // We use this to keep track of whether a model has been previously loaded or not so we can
- // open the drawer on empty directories on first launch
- private boolean modelLoadObserved;
-
- public void reset(Model model, boolean searchMode) {
- assert(model != null);
-
- this.searchMode = searchMode;
- this.model = model;
-
- model.addUpdateListener(mModelUpdateListener);
- modelLoadObserved = false;
- }
- }
-}
diff --git a/src/com/android/documentsui/sidebar/RootsFragment.java b/src/com/android/documentsui/sidebar/RootsFragment.java
index a250a8d68..2a4dca3f3 100644
--- a/src/com/android/documentsui/sidebar/RootsFragment.java
+++ b/src/com/android/documentsui/sidebar/RootsFragment.java
@@ -59,6 +59,7 @@ import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.Shared;
import com.android.documentsui.base.State;
import com.android.documentsui.roots.GetRootDocumentTask;
+import com.android.documentsui.ActivityConfig;
import com.android.documentsui.roots.RootsCache;
import com.android.documentsui.roots.RootsLoader;
@@ -78,18 +79,6 @@ public class RootsFragment extends Fragment implements ItemDragListener.DragHost
private static final String EXTRA_INCLUDE_APPS = "includeApps";
private static final int CONTEXT_MENU_ITEM_TIMEOUT = 500;
- private final OnDragListener mDragListener = new ItemDragListener<RootsFragment>(this) {
- @Override
- public boolean handleDropEventChecked(View v, DragEvent event) {
- final int position = (Integer) v.getTag(R.id.item_position_tag);
- final Item item = mAdapter.getItem(position);
-
- assert(item.isDropTarget());
-
- return item.dropOn(event.getClipData());
- }
- };
-
private final OnItemClickListener mItemListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
@@ -111,8 +100,14 @@ public class RootsFragment extends Fragment implements ItemDragListener.DragHost
private ListView mList;
private RootsAdapter mAdapter;
private LoaderCallbacks<Collection<RootInfo>> mCallbacks;
+ private @Nullable OnDragListener mDragListener;
+
+ // This dependency is informally "injected" from the owning Activity in our onCreate method.
private ActionHandler mActionHandler;
+ // This dependency is informally "injected" from the owning Activity in our onCreate method.
+ private ActivityConfig mActivityConfig;
+
public static RootsFragment show(FragmentManager fm, Intent includeApps) {
final Bundle args = new Bundle();
args.putParcelable(EXTRA_INCLUDE_APPS, includeApps);
@@ -201,7 +196,23 @@ public class RootsFragment extends Fragment implements ItemDragListener.DragHost
final RootsCache roots = DocumentsApplication.getRootsCache(activity);
final State state = activity.getDisplayState();
- mActionHandler = activity.getActionHandler(null, null);
+ mActionHandler = activity.getActionHandler(null, null, false);
+ mActivityConfig = activity.getActivityConfig();
+
+ if (mActivityConfig.dragAndDropEnabled()) {
+ mDragListener = new ItemDragListener<RootsFragment>(this) {
+ @Override
+ public boolean handleDropEventChecked(View v, DragEvent event) {
+ final int position = (Integer) v.getTag(R.id.item_position_tag);
+ final Item item = mAdapter.getItem(position);
+
+ assert (item.isDropTarget());
+
+ return item.dropOn(event.getClipData());
+ }
+ };
+ }
+
mCallbacks = new LoaderCallbacks<Collection<RootInfo>>() {
@Override
diff --git a/tests/common/com/android/documentsui/TestActivity.java b/tests/common/com/android/documentsui/TestActivity.java
index 7d73589f5..a2a7b55d5 100644
--- a/tests/common/com/android/documentsui/TestActivity.java
+++ b/tests/common/com/android/documentsui/TestActivity.java
@@ -50,6 +50,7 @@ public abstract class TestActivity extends AbstractBase {
public TestEventListener<RootInfo> rootPicked;
public TestEventListener<DocumentInfo> openContainer;
public TestEventListener<Integer> refreshCurrentRootAndDirectory;
+ public TestEventListener<Boolean> setRootsDrawerOpen;
public static TestActivity create() {
TestActivity activity = Mockito.mock(TestActivity.class, Mockito.CALLS_REAL_METHODS);
@@ -67,6 +68,7 @@ public abstract class TestActivity extends AbstractBase {
rootPicked = new TestEventListener<>();
openContainer = new TestEventListener<>();
refreshCurrentRootAndDirectory = new TestEventListener<>();
+ setRootsDrawerOpen = new TestEventListener<>();
}
@Override
@@ -132,6 +134,11 @@ public abstract class TestActivity extends AbstractBase {
public final RootInfo getCurrentRoot() {
return currentRoot;
}
+
+ @Override
+ public final void setRootsDrawerOpen(boolean open) {
+ setRootsDrawerOpen.accept(open);
+ }
}
// Trick Mockito into finding our Addons methods correctly. W/o this
diff --git a/tests/common/com/android/documentsui/dirlist/TestModel.java b/tests/common/com/android/documentsui/dirlist/TestModel.java
index abe4d5f53..82849a34f 100644
--- a/tests/common/com/android/documentsui/dirlist/TestModel.java
+++ b/tests/common/com/android/documentsui/dirlist/TestModel.java
@@ -22,10 +22,13 @@ import android.provider.DocumentsContract.Document;
import com.android.documentsui.DirectoryResult;
import com.android.documentsui.base.DocumentInfo;
+import com.android.documentsui.base.EventListener;
import com.android.documentsui.roots.RootCursorWrapper;
import libcore.net.MimeUtils;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Random;
public class TestModel extends Model {
@@ -43,6 +46,7 @@ public class TestModel extends Model {
private int mLastId = 0;
private Random mRand = new Random();
private MatrixCursor mCursor;
+ private List<EventListener<Update>> mUpdateListeners = new ArrayList<>();
public TestModel(String authority) {
super();
diff --git a/tests/unit/com/android/documentsui/files/ActionHandlerTest.java b/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
index 457c2ba08..496fb5109 100644
--- a/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
+++ b/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
@@ -74,7 +74,17 @@ public class ActionHandlerTest {
mSelection = new Selection();
mSelection.add("1");
- mHandler.reset(mEnv.model, null);
+ mHandler.reset(mEnv.model, null, false);
+ }
+
+ @Test
+ public void testOpenDrawerOnLaunchingEmptyRoot() {
+ mEnv.model.reset();
+ // state should not say we've changed our location
+
+ mEnv.model.update();
+
+ mActivity.setRootsDrawerOpen.assertLastArgument(true);
}
@Test
diff --git a/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java b/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java
index c7afff1ea..8a11b084e 100644
--- a/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java
+++ b/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java
@@ -16,6 +16,9 @@
package com.android.documentsui.picker;
+import static com.android.documentsui.base.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.base.State.ACTION_PICK_COPY_DESTINATION;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -67,7 +70,36 @@ public class ActionHandlerTest {
mSelection = new Selection();
mSelection.add("1");
- mHandler.reset(mEnv.model, null);
+ mHandler.reset(mEnv.model, null, false);
+ }
+
+ @Test
+ public void testOpenDrawerOnLaunchingEmptyRoot() {
+ mEnv.model.reset();
+ // state should not say we've changed our location
+
+ mEnv.model.update();
+
+ mActivity.setRootsDrawerOpen.assertLastArgument(true);
+ }
+
+ @Test
+ public void testOpenDrawerOnGettingContent() {
+ mEnv.state.external = true;
+ mEnv.state.action = ACTION_GET_CONTENT;
+
+ mEnv.model.update();
+
+ mActivity.setRootsDrawerOpen.assertLastArgument(true);
+ }
+
+ @Test
+ public void testOpenDrawerOnPickingCopyDestination() {
+ mEnv.state.action = ACTION_PICK_COPY_DESTINATION;
+
+ mEnv.model.update();
+
+ mActivity.setRootsDrawerOpen.assertLastArgument(true);
}
@Test