diff options
author | 2016-10-04 14:36:38 -0700 | |
---|---|---|
committer | 2016-10-05 17:23:50 -0700 | |
commit | 208945c4e262868d3ebe0f55f1b895cd5a201cbb (patch) | |
tree | bc88b65a37c5886a21038f070bc805144543a09c | |
parent | e13f6785f7c0aab6fdc2222756d8e17385e409e6 (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
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 |