Merge "Directory fragment refactoring. First attempt to to refactor fragments handling, state and app lifecycle." into nyc-dev
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index b67a6915..a34dd55 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -23,9 +23,11 @@
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_SIDE;
import static com.android.internal.util.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
import android.app.Activity;
import android.app.Fragment;
+import android.app.FragmentManager;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -46,7 +48,7 @@
import android.view.MenuItem;
import android.widget.Spinner;
-import com.android.documentsui.SearchManager.SearchManagerListener;
+import com.android.documentsui.SearchViewManager.SearchManagerListener;
import com.android.documentsui.State.ViewMode;
import com.android.documentsui.dirlist.DirectoryFragment;
import com.android.documentsui.dirlist.Model;
@@ -64,14 +66,12 @@
public abstract class BaseActivity extends Activity
implements SearchManagerListener, NavigationView.Environment {
- static final String EXTRA_STATE = "state";
-
// See comments where this const is referenced for details.
private static final int DRAWER_NO_FIDDLE_DELAY = 1500;
State mState;
RootsCache mRoots;
- SearchManager mSearchManager;
+ SearchViewManager mSearchManager;
DrawerController mDrawer;
NavigationView mNavigator;
@@ -121,7 +121,7 @@
}
});
- mSearchManager = new SearchManager(this);
+ mSearchManager = new SearchViewManager(this, icicle);
DocumentsToolbar toolbar = (DocumentsToolbar) findViewById(R.id.toolbar);
setActionBar(toolbar);
@@ -141,6 +141,7 @@
boolean showMenu = super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.activity, menu);
+ mNavigator.update();
mSearchManager.install((DocumentsToolbar) findViewById(R.id.toolbar));
return showMenu;
@@ -188,7 +189,7 @@
private State getState(@Nullable Bundle icicle) {
if (icicle != null) {
- State state = icicle.<State>getParcelable(EXTRA_STATE);
+ State state = icicle.<State>getParcelable(Shared.EXTRA_STATE);
if (DEBUG) Log.d(mTag, "Recovered existing state object: " + state);
return state;
}
@@ -224,6 +225,9 @@
}
void onRootPicked(RootInfo root) {
+ // Clicking on the current root removes search
+ mSearchManager.cancelSearch();
+
// Skip refreshing if root nor directory didn't change
if (root.equals(getCurrentRoot()) && mState.stack.size() == 1) {
return;
@@ -233,7 +237,6 @@
// Clear entire backstack and start in new root
mState.onRootChanged(root);
- mSearchManager.update(root);
// Recents is always in memory, so we just load it directly.
// Otherwise we delegate loading data from disk to a task
@@ -370,18 +373,18 @@
* e.g. The current directory name displayed on the action bar won't get updated.
*/
@Override
- public void onSearchChanged() {
- refreshDirectory(ANIM_NONE);
+ public void onSearchChanged(@Nullable String query) {
+ // We should not get here if root is not searchable
+ checkState(canSearchRoot());
+ reloadSearch(query);
}
- /**
- * Called when search query changed.
- * Updates the state object.
- * @param query - New query
- */
- @Override
- public void onSearchQueryChanged(String query) {
- mState.currentSearch = query;
+ private void reloadSearch(String query) {
+ FragmentManager fm = getFragmentManager();
+ RootInfo root = getCurrentRoot();
+ DocumentInfo cwd = getCurrentDirectory();
+
+ DirectoryFragment.reloadSearch(fm, root, cwd, query);
}
final List<String> getExcludedAuthorities() {
@@ -486,7 +489,8 @@
@Override
protected void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
- state.putParcelable(EXTRA_STATE, mState);
+ state.putParcelable(Shared.EXTRA_STATE, mState);
+ mSearchManager.onSaveInstanceState(state);
}
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index b0542b9..13b7b14 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -53,19 +53,22 @@
private final RootInfo mRoot;
private final Uri mUri;
private final int mUserSortOrder;
+ private final boolean mSearchMode;
private DocumentInfo mDoc;
private CancellationSignal mSignal;
private DirectoryResult mResult;
+
public DirectoryLoader(Context context, int type, RootInfo root, DocumentInfo doc, Uri uri,
- int userSortOrder) {
+ int userSortOrder, boolean inSearchMode) {
super(context, ProviderExecutor.forAuthority(root.authority));
mType = type;
mRoot = root;
mUri = uri;
mUserSortOrder = userSortOrder;
mDoc = doc;
+ mSearchMode = inSearchMode;
}
@Override
@@ -83,7 +86,7 @@
final DirectoryResult result = new DirectoryResult();
// Use default document when searching
- if (mType == DirectoryFragment.TYPE_SEARCH) {
+ if (mSearchMode) {
final Uri docUri = DocumentsContract.buildDocumentUri(
mRoot.authority, mRoot.documentId);
try {
@@ -106,7 +109,7 @@
}
// Search always uses ranking from provider
- if (mType == DirectoryFragment.TYPE_SEARCH) {
+ if (mSearchMode) {
result.sortOrder = State.SORT_ORDER_UNKNOWN;
}
@@ -127,7 +130,7 @@
cursor = new RootCursorWrapper(mUri.getAuthority(), mRoot.rootId, cursor, -1);
- if (mType == DirectoryFragment.TYPE_SEARCH) {
+ if (mSearchMode) {
// Filter directories out of search results, for now
cursor = new FilteringCursorWrapper(cursor, null, SEARCH_REJECT_MIMES);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index ec7dde9..9812495 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -290,13 +290,8 @@
mState.derivedMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
}
} else {
- if (mSearchManager.isSearching()) {
- // Ongoing search
- DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
- } else {
// Normal boring directory
DirectoryFragment.showDirectory(fm, root, cwd, anim);
- }
}
// Forget any replacement target
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
index f7a45e2..9609dee 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
@@ -16,8 +16,10 @@
package com.android.documentsui;
+import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.State.ACTION_MANAGE;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
+import static com.android.internal.util.Preconditions.checkState;
import android.app.Activity;
import android.app.Fragment;
@@ -119,17 +121,14 @@
final RootInfo root = getCurrentRoot();
final DocumentInfo cwd = getCurrentDirectory();
+ if (DEBUG) checkState(!mSearchManager.isSearching());
+
// If started in manage roots mode, there has to be a cwd (i.e. the root dir of the managed
// root).
Preconditions.checkNotNull(cwd);
- if (mState.currentSearch != null) {
- // Ongoing search
- DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
- } else {
- // Normal boring directory
- DirectoryFragment.showDirectory(fm, root, cwd, anim);
- }
+ // Normal boring directory
+ DirectoryFragment.showDirectory(fm, root, cwd, anim);
}
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index c0faba3..b8b50e4 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -82,7 +82,6 @@
if (mState.restored) {
if (DEBUG) Log.d(TAG, "Stack already resolved for uri: " + intent.getData());
- refreshCurrentRootAndDirectory(ANIM_NONE);
} else if (!mState.stack.isEmpty()) {
// If a non-empty stack is present in our state it was read (presumably)
// from EXTRA_STACK intent extra. In this case, we'll skip other means of
@@ -248,16 +247,13 @@
final RootInfo root = getCurrentRoot();
final DocumentInfo cwd = getCurrentDirectory();
+ if (DEBUG) checkState(!mSearchManager.isSearching());
+
if (cwd == null) {
DirectoryFragment.showRecentsOpen(fm, anim);
} else {
- if (mState.currentSearch != null) {
- // Ongoing search
- DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
- } else {
- // Normal boring directory
- DirectoryFragment.showDirectory(fm, root, cwd, anim);
- }
+ // Normal boring directory
+ DirectoryFragment.showDirectory(fm, root, cwd, anim);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SearchManager.java b/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
similarity index 78%
rename from packages/DocumentsUI/src/com/android/documentsui/SearchManager.java
rename to packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
index 69f54c7..0496862 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SearchManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
@@ -16,6 +16,8 @@
package com.android.documentsui;
+import android.annotation.Nullable;
+import android.os.Bundle;
import android.provider.DocumentsContract.Root;
import android.text.TextUtils;
import android.util.Log;
@@ -31,28 +33,27 @@
/**
* Manages searching UI behavior.
*/
-final class SearchManager implements
+final class SearchViewManager implements
SearchView.OnCloseListener, OnQueryTextListener, OnClickListener, OnFocusChangeListener {
public interface SearchManagerListener {
- void onSearchChanged();
-
- void onSearchQueryChanged(String query);
+ void onSearchChanged(@Nullable String query);
}
public static final String TAG = "SearchManger";
private SearchManagerListener mListener;
- private String currentSearch;
private boolean mSearchExpanded;
+ private String mCurrentSearch;
private boolean mIgnoreNextClose;
private DocumentsToolbar mActionBar;
private MenuItem mMenu;
private SearchView mView;
- public SearchManager(SearchManagerListener listener) {
+ public SearchViewManager(SearchManagerListener listener, @Nullable Bundle savedState) {
mListener = listener;
+ mCurrentSearch = savedState != null ? savedState.getString(Shared.EXTRA_QUERY) : null;
}
public void setSearchMangerListener(SearchManagerListener listener) {
@@ -69,6 +70,8 @@
mView.setOnCloseListener(this);
mView.setOnSearchClickListener(this);
mView.setOnQueryTextFocusChangeListener(this);
+
+ restoreSearch();
}
/**
@@ -80,12 +83,12 @@
return;
}
- if (currentSearch != null) {
+ if (mCurrentSearch != null) {
mMenu.expandActionView();
mView.setIconified(false);
mView.clearFocus();
- mView.setQuery(currentSearch, false);
+ mView.setQuery(mCurrentSearch, false);
} else {
mView.clearFocus();
if (!mView.isIconified()) {
@@ -108,13 +111,11 @@
return;
}
- mMenu.setVisible(visible);
if (!visible) {
- currentSearch = null;
- if (mListener != null) {
- mListener.onSearchQueryChanged(currentSearch);
- }
+ mCurrentSearch = null;
}
+
+ mMenu.setVisible(visible);
}
/**
@@ -133,8 +134,23 @@
return false;
}
+ private void restoreSearch() {
+ if (isSearching()) {
+ onSearchExpanded();
+ mView.setIconified(false);
+ mView.setQuery(mCurrentSearch, false);
+ mView.clearFocus();
+ }
+ }
+
+ private void onSearchExpanded() {
+ mSearchExpanded = true;
+ mView.setBackgroundColor(
+ mView.getResources().getColor(R.color.menu_search_background, null));
+ }
+
boolean isSearching() {
- return currentSearch != null;
+ return mCurrentSearch != null;
}
boolean isExpanded() {
@@ -142,6 +158,14 @@
}
/**
+ * Called when owning activity is saving state to be used to restore state during creation.
+ * @param state Bundle to save state too
+ */
+ public void onSaveInstanceState(Bundle state) {
+ state.putString(Shared.EXTRA_QUERY, mCurrentSearch);
+ }
+
+ /**
* Clears the search. Clears the SearchView background color. Triggers refreshing of the
* directory content.
* @return True if the default behavior of clearing/dismissing SearchView should be overridden.
@@ -159,11 +183,10 @@
mView.getResources().getColor(android.R.color.transparent, null));
// Refresh the directory if a search was done
- if (currentSearch != null) {
- currentSearch = null;
+ if (mCurrentSearch != null) {
+ mCurrentSearch = null;
if (mListener != null) {
- mListener.onSearchQueryChanged(currentSearch);
- mListener.onSearchChanged();
+ mListener.onSearchChanged(mCurrentSearch);
}
}
return false;
@@ -176,18 +199,15 @@
*/
@Override
public void onClick(View v) {
- mSearchExpanded = true;
- mView.setBackgroundColor(
- mView.getResources().getColor(R.color.menu_search_background, null));
+ onSearchExpanded();
}
@Override
public boolean onQueryTextSubmit(String query) {
- currentSearch = query;
+ mCurrentSearch = query;
mView.clearFocus();
if (mListener != null) {
- mListener.onSearchQueryChanged(currentSearch);
- mListener.onSearchChanged();
+ mListener.onSearchChanged(mCurrentSearch);
}
return true;
}
@@ -195,7 +215,7 @@
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
- if (currentSearch == null) {
+ if (mCurrentSearch == null) {
mView.setIconified(true);
} else if (TextUtils.isEmpty(mView.getQuery())) {
cancelSearch();
@@ -207,4 +227,9 @@
public boolean onQueryTextChange(String newText) {
return false;
}
+
+ String getCurrentSearch() {
+ return mCurrentSearch;
+ }
+
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index b90a119..a288fe8 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -37,10 +37,50 @@
* specifies if the destination directory needs to create new directory or not.
*/
public static final String EXTRA_DIRECTORY_COPY = "com.android.documentsui.DIRECTORY_COPY";
+ public static final String EXTRA_STACK = "com.android.documentsui.STACK";
+
+ /**
+ * Extra flag used to store query of type String in the bundle.
+ */
+ public static final String EXTRA_QUERY = "query";
+
+ /**
+ * Extra flag used to store state of type State in the bundle.
+ */
+ public static final String EXTRA_STATE = "state";
+
+ /**
+ * Extra flag used to store type of DirectoryFragment's type ResultType type in the bundle.
+ */
+ public static final String EXTRA_TYPE = "type";
+
+ /**
+ * Extra flag used to store root of type RootInfo in the bundle.
+ */
+ public static final String EXTRA_ROOT = "root";
+
+ /**
+ * Extra flag used to store document of DocumentInfo type in the bundle.
+ */
+ public static final String EXTRA_DOC = "document";
+
+ /**
+ * Extra flag used to store DirectoryFragment's selection of Selection type in the bundle.
+ */
+ public static final String EXTRA_SELECTION = "selection";
+
+ /**
+ * Extra flag used to store DirectoryFragment's search mode of boolean type in the bundle.
+ */
+ public static final String EXTRA_SEARCH_MODE = "searchMode";
+
+ /**
+ * Extra flag used to store DirectoryFragment's ignore state of boolean type in the bundle.
+ */
+ public static final String EXTRA_IGNORE_STATE = "ignoreState";
public static final boolean DEBUG = true;
public static final String TAG = "Documents";
- public static final String EXTRA_STACK = "com.android.documentsui.STACK";
/**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index 0948ab1..2ecbdf6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -105,9 +105,6 @@
private boolean mInitialRootChanged;
private boolean mInitialDocChanged;
- /** Currently active search, overriding any stack. */
- public String currentSearch;
-
/** Instance state for every shown directory */
public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
@@ -186,7 +183,6 @@
out.writeInt(showAdvanced ? 1 : 0);
out.writeInt(restored ? 1 : 0);
DurableUtils.writeToParcel(out, stack);
- out.writeString(currentSearch);
out.writeMap(dirState);
out.writeParcelable(selectedDocuments, 0);
out.writeList(selectedDocumentsForCopy);
@@ -217,7 +213,6 @@
state.showAdvanced = in.readInt() != 0;
state.restored = in.readInt() != 0;
DurableUtils.readFromParcel(in, state.stack);
- state.currentSearch = in.readString();
in.readMap(state.dirState, loader);
state.selectedDocuments = in.readParcelable(loader);
in.readList(state.selectedDocumentsForCopy, loader);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 4583dec..669eb71 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -113,19 +113,26 @@
/**
* Display the documents inside a single directory.
*/
-public class DirectoryFragment extends Fragment implements DocumentsAdapter.Environment {
+public class DirectoryFragment extends Fragment
+ implements DocumentsAdapter.Environment, LoaderCallbacks<DirectoryResult> {
@IntDef(flag = true, value = {
TYPE_NORMAL,
- TYPE_SEARCH,
TYPE_RECENT_OPEN
})
@Retention(RetentionPolicy.SOURCE)
public @interface ResultType {}
public static final int TYPE_NORMAL = 1;
- public static final int TYPE_SEARCH = 2;
- public static final int TYPE_RECENT_OPEN = 3;
+ public static final int TYPE_RECENT_OPEN = 2;
+ @IntDef(flag = true, value = {
+ ANIM_NONE,
+ ANIM_SIDE,
+ ANIM_LEAVE,
+ ANIM_ENTER
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AnimationType {}
public static final int ANIM_NONE = 1;
public static final int ANIM_SIDE = 2;
public static final int ANIM_LEAVE = 3;
@@ -146,12 +153,6 @@
private static final int DELETE_JOB_DELAY = 5500;
private static final int EMPTY_REVEAL_DURATION = 250;
- private static final String EXTRA_TYPE = "type";
- private static final String EXTRA_ROOT = "root";
- private static final String EXTRA_DOC = "doc";
- private static final String EXTRA_QUERY = "query";
- private static final String EXTRA_IGNORE_STATE = "ignoreState";
-
private Model mModel;
private MultiSelectManager mSelectionManager;
private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
@@ -164,12 +165,10 @@
private RecyclerView mRecView;
private ListeningGestureDetector mGestureDetector;
- private @ResultType int mType = TYPE_NORMAL;
private String mStateKey;
private int mLastSortOrder = SORT_ORDER_UNKNOWN;
private DocumentsAdapter mAdapter;
- private LoaderCallbacks<DirectoryResult> mCallbacks;
private FragmentTuner mTuner;
private DocumentClipper mClipper;
private GridLayoutManager mLayout;
@@ -178,6 +177,14 @@
private MessageBar mMessageBar;
private View mProgressBar;
+ // Directory fragment state is defined by: root, document, query, type, selection
+ private @ResultType int mType = TYPE_NORMAL;
+ private RootInfo mRoot;
+ private DocumentInfo mDocument;
+ private String mQuery = null;
+ private Selection mSelection = null;
+ private boolean mSearchMode = false;
+
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -226,9 +233,16 @@
final Context context = getActivity();
final State state = getDisplayState();
- final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
- final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
- mStateKey = buildStateKey(root, doc);
+ // Read arguments when object created for the first time.
+ // Restore state if fragment recreated.
+ Bundle args = savedInstanceState == null ? getArguments() : savedInstanceState;
+ mRoot = args.getParcelable(Shared.EXTRA_ROOT);
+ mDocument = args.getParcelable(Shared.EXTRA_DOC);
+ mStateKey = buildStateKey(mRoot, mDocument);
+ mQuery = args.getString(Shared.EXTRA_QUERY);
+ mType = args.getInt(Shared.EXTRA_TYPE);
+ mSelection = args.getParcelable(Shared.EXTRA_SELECTION);
+ mSearchMode = args.getBoolean(Shared.EXTRA_SEARCH_MODE);
mIconHelper = new IconHelper(context, MODE_GRID);
@@ -248,13 +262,6 @@
mRecView.addOnItemTouchListener(mGestureDetector);
- // final here because we'll manually bump the listener iwhen we had an initial selection,
- // but only after the model is fully loaded.
- final SelectionModeListener selectionListener = new SelectionModeListener();
- final Selection initialSelection = state.selectedDocuments.hasDirectoryKey(mStateKey)
- ? state.selectedDocuments
- : null;
-
// TODO: instead of inserting the view into the constructor, extract listener-creation code
// and set the listener on the view after the fact. Then the view doesn't need to be passed
// into the selection manager.
@@ -264,9 +271,9 @@
state.allowMultiple
? MultiSelectManager.MODE_MULTIPLE
: MultiSelectManager.MODE_SINGLE,
- initialSelection);
+ null);
- mSelectionManager.addCallback(selectionListener);
+ mSelectionManager.addCallback(new SelectionModeListener());
mModel = new Model();
mModel.addUpdateListener(mAdapter);
@@ -275,8 +282,6 @@
// Make sure this is done after the RecyclerView is set up.
mFocusManager = new FocusManager(context, mRecView, mModel);
- mType = getArguments().getInt(EXTRA_TYPE);
-
mTuner = FragmentTuner.pick(getContext(), state);
mClipper = new DocumentClipper(context);
@@ -286,7 +291,7 @@
hideGridTitles = MimePredicate.mimeMatches(
MimePredicate.VISUAL_MIMES, state.acceptMimes);
} else {
- hideGridTitles = (doc != null) && doc.isGridTitlesHidden();
+ hideGridTitles = (mDocument != null) && mDocument.isGridTitlesHidden();
}
GridDocumentHolder.setHideTitles(hideGridTitles);
@@ -295,86 +300,20 @@
boolean svelte = am.isLowRamDevice() && (mType == TYPE_RECENT_OPEN);
mIconHelper.setThumbnailsEnabled(!svelte);
- mCallbacks = new LoaderCallbacks<DirectoryResult>() {
- @Override
- public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
- final String query = getArguments().getString(EXTRA_QUERY);
-
- Uri contentsUri;
- switch (mType) {
- case TYPE_NORMAL:
- contentsUri = DocumentsContract.buildChildDocumentsUri(
- doc.authority, doc.documentId);
- if (state.action == ACTION_MANAGE) {
- contentsUri = DocumentsContract.setManageMode(contentsUri);
- }
- return new DirectoryLoader(
- context, mType, root, doc, contentsUri, state.userSortOrder);
- case TYPE_SEARCH:
- contentsUri = DocumentsContract.buildSearchDocumentsUri(
- root.authority, root.rootId, query);
- if (state.action == ACTION_MANAGE) {
- contentsUri = DocumentsContract.setManageMode(contentsUri);
- }
- return new DirectoryLoader(
- context, mType, root, doc, contentsUri, state.userSortOrder);
- case TYPE_RECENT_OPEN:
- final RootsCache roots = DocumentsApplication.getRootsCache(context);
- return new RecentsLoader(context, roots, state);
- default:
- throw new IllegalStateException("Unknown type " + mType);
- }
- }
-
- @Override
- public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
- if (!isAdded()) return;
-
- mModel.update(result);
- state.derivedSortOrder = result.sortOrder;
-
- updateDisplayState();
-
- if (initialSelection != null) {
- selectionListener.onSelectionChanged();
- }
-
- // Restore any previous instance state
- final SparseArray<Parcelable> container = state.dirState.remove(mStateKey);
- if (container != null && !getArguments().getBoolean(EXTRA_IGNORE_STATE, false)) {
- getView().restoreHierarchyState(container);
- } else if (mLastSortOrder != state.derivedSortOrder) {
- // The derived sort order takes the user sort order into account, but applies
- // directory-specific defaults when the user doesn't explicitly set the sort
- // order. Scroll to the top if the sort order actually changed.
- mRecView.smoothScrollToPosition(0);
- }
-
- mLastSortOrder = state.derivedSortOrder;
-
- mTuner.onModelLoaded(mModel, mType);
- }
-
- @Override
- public void onLoaderReset(Loader<DirectoryResult> loader) {
- mModel.update(null);
- }
- };
-
// Kick off loader at least once
- getLoaderManager().restartLoader(LOADER_ID, null, mCallbacks);
+ getLoaderManager().restartLoader(LOADER_ID, null, this);
}
@Override
public void onSaveInstanceState(Bundle outState) {
- State state = getDisplayState();
- if (mSelectionManager.hasSelection()) {
- mSelectionManager.getSelection(state.selectedDocuments);
- state.selectedDocuments.setDirectoryKey(mStateKey);
- if (!state.selectedDocuments.isEmpty()) {
- if (DEBUG) Log.d(TAG, "Persisted selection: " + state.selectedDocuments);
- }
- }
+ super.onSaveInstanceState(outState);
+
+ outState.putInt(Shared.EXTRA_TYPE, mType);
+ outState.putParcelable(Shared.EXTRA_ROOT, mRoot);
+ outState.putParcelable(Shared.EXTRA_DOC, mDocument);
+ outState.putString(Shared.EXTRA_QUERY, mQuery);
+ outState.putParcelable(Shared.EXTRA_SELECTION, mSelectionManager.getSelection());
+ outState.putBoolean(Shared.EXTRA_SEARCH_MODE, mSearchMode);
}
@Override
@@ -449,7 +388,7 @@
public void onSortOrderChanged() {
// Sort order is implemented as a sorting wrapper around directory
// results. So when sort order changes, we force a reload of the directory.
- getLoaderManager().restartLoader(LOADER_ID, null, mCallbacks);
+ getLoaderManager().restartLoader(LOADER_ID, null, this);
}
public void onViewModeChanged() {
@@ -1342,7 +1281,7 @@
mProgressBar.setVisibility(model.isLoading() ? View.VISIBLE : View.GONE);
if (model.isEmpty()) {
- if (getDisplayState().currentSearch != null) {
+ if (mSearchMode) {
showNoResults(getDisplayState().stack.root);
} else {
showEmptyDirectory();
@@ -1468,32 +1407,50 @@
public static void showDirectory(
FragmentManager fm, RootInfo root, DocumentInfo doc, int anim) {
- show(fm, TYPE_NORMAL, root, doc, null, anim);
- }
-
- public static void showSearch(FragmentManager fm, RootInfo root, String query, int anim) {
- show(fm, TYPE_SEARCH, root, null, query, anim);
+ create(fm, TYPE_NORMAL, root, doc, null, anim);
}
public static void showRecentsOpen(FragmentManager fm, int anim) {
- show(fm, TYPE_RECENT_OPEN, null, null, null, anim);
+ create(fm, TYPE_RECENT_OPEN, null, null, null, anim);
}
- private static void show(FragmentManager fm, int type, RootInfo root, DocumentInfo doc,
+ public static void reloadSearch(FragmentManager fm, RootInfo root, DocumentInfo doc,
+ String query) {
+ DirectoryFragment df = get(fm);
+
+ df.mQuery = query;
+ df.mRoot = root;
+ df.mDocument = doc;
+ df.mSearchMode = query != null;
+ df.getLoaderManager().restartLoader(LOADER_ID, null, df);
+ }
+
+ public static void reload(FragmentManager fm, int type, RootInfo root, DocumentInfo doc,
+ String query) {
+ DirectoryFragment df = get(fm);
+ df.mType = type;
+ df.mQuery = query;
+ df.mRoot = root;
+ df.mDocument = doc;
+ df.mSearchMode = query != null;
+ df.getLoaderManager().restartLoader(LOADER_ID, null, df);
+ }
+
+ public static void create(FragmentManager fm, int type, RootInfo root, DocumentInfo doc,
String query, int anim) {
final Bundle args = new Bundle();
- args.putInt(EXTRA_TYPE, type);
- args.putParcelable(EXTRA_ROOT, root);
- args.putParcelable(EXTRA_DOC, doc);
- args.putString(EXTRA_QUERY, query);
+ args.putInt(Shared.EXTRA_TYPE, type);
+ args.putParcelable(Shared.EXTRA_ROOT, root);
+ args.putParcelable(Shared.EXTRA_DOC, doc);
+ args.putString(Shared.EXTRA_QUERY, query);
final FragmentTransaction ft = fm.beginTransaction();
switch (anim) {
case ANIM_SIDE:
- args.putBoolean(EXTRA_IGNORE_STATE, true);
+ args.putBoolean(Shared.EXTRA_IGNORE_STATE, true);
break;
case ANIM_ENTER:
- args.putBoolean(EXTRA_IGNORE_STATE, true);
+ args.putBoolean(Shared.EXTRA_IGNORE_STATE, true);
ft.setCustomAnimations(R.animator.dir_enter, R.animator.dir_frozen);
break;
case ANIM_LEAVE:
@@ -1504,7 +1461,7 @@
final DirectoryFragment fragment = new DirectoryFragment();
fragment.setArguments(args);
- ft.replace(R.id.container_directory, fragment);
+ ft.replace(getFragmentId(), fragment);
ft.commitAllowingStateLoss();
}
@@ -1518,9 +1475,77 @@
public static @Nullable DirectoryFragment get(FragmentManager fm) {
// TODO: deal with multiple directories shown at once
- Fragment fragment = fm.findFragmentById(R.id.container_directory);
+ Fragment fragment = fm.findFragmentById(getFragmentId());
return fragment instanceof DirectoryFragment
? (DirectoryFragment) fragment
: null;
}
-}
+
+ private static int getFragmentId() {
+ return R.id.container_directory;
+ }
+
+ @Override
+ public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
+ Context context = getActivity();
+ State state = getDisplayState();
+
+ Uri contentsUri;
+ switch (mType) {
+ case TYPE_NORMAL:
+ contentsUri = mSearchMode ? DocumentsContract.buildSearchDocumentsUri(
+ mRoot.authority, mRoot.rootId, mQuery)
+ : DocumentsContract.buildChildDocumentsUri(
+ mDocument.authority, mDocument.documentId);
+ if (state.action == ACTION_MANAGE) {
+ contentsUri = DocumentsContract.setManageMode(contentsUri);
+ }
+ return new DirectoryLoader(
+ context, mType, mRoot, mDocument, contentsUri, state.userSortOrder, mSearchMode);
+ case TYPE_RECENT_OPEN:
+ final RootsCache roots = DocumentsApplication.getRootsCache(context);
+ return new RecentsLoader(context, roots, state);
+ default:
+ throw new IllegalStateException("Unknown type " + mType);
+ }
+ }
+
+ @Override
+ public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
+ if (!isAdded()) return;
+
+ State state = getDisplayState();
+
+ mAdapter.notifyDataSetChanged();
+ mModel.update(result);
+
+ state.derivedSortOrder = result.sortOrder;
+
+ updateLayout(state.derivedMode);
+
+ if (mSelection != null) {
+ mSelectionManager.setItemsSelected(mSelection.toList(), true);
+ }
+
+ // Restore any previous instance state
+ final SparseArray<Parcelable> container = state.dirState.remove(mStateKey);
+ if (container != null && !getArguments().getBoolean(Shared.EXTRA_IGNORE_STATE, false)) {
+ getView().restoreHierarchyState(container);
+ } else if (mLastSortOrder != state.derivedSortOrder) {
+ // The derived sort order takes the user sort order into account, but applies
+ // directory-specific defaults when the user doesn't explicitly set the sort
+ // order. Scroll to the top if the sort order actually changed.
+ mRecView.smoothScrollToPosition(0);
+ }
+
+ mLastSortOrder = state.derivedSortOrder;
+
+ mTuner.onModelLoaded(mModel, mType, mSearchMode);
+
+ }
+
+ @Override
+ public void onLoaderReset(Loader<DirectoryResult> loader) {
+ mModel.update(null);
+ }
+ }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index a9b0fd1..914f71e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -84,7 +84,7 @@
return MimePredicate.mimeMatches(mState.acceptMimes, docMimeType);
}
- abstract void onModelLoaded(Model model, @ResultType int resultType);
+ abstract void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch);
/**
* Provides support for Platform specific specializations of DirectoryFragment.
@@ -166,7 +166,7 @@
}
@Override
- void onModelLoaded(Model model, @ResultType int resultType) {
+ void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
// When launched into empty recents, show drawer
if (resultType == DirectoryFragment.TYPE_RECENT_OPEN
&& model.isEmpty()
@@ -211,7 +211,7 @@
}
@Override
- void onModelLoaded(Model model, @ResultType int resultType) {}
+ void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {}
}
/**
@@ -248,11 +248,10 @@
}
@Override
- void onModelLoaded(Model model, @ResultType int resultType) {
+ void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
if (DEBUG) Log.d(TAG, "Handling model loaded. Has Location shcnage: " + mState.initialLocationHasChanged());
// When launched into empty root, open drawer.
- if (model.isEmpty() && !mState.initialLocationHasChanged()
- && resultType != DirectoryFragment.TYPE_SEARCH) {
+ if (model.isEmpty() && !mState.initialLocationHasChanged() && !isSearch) {
if (DEBUG) Log.d(TAG, "Showing roots drawer cuz stuffs empty.");
// This noops on layouts without drawer, so no need to guard.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
index c8b6f85..19268d7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
@@ -687,7 +687,7 @@
* Returns an unordered array of selected positions (including any
* provisional selections current in effect).
*/
- private List<String> toList() {
+ public List<String> toList() {
ArrayList<String> selection = new ArrayList<String>(mSelection);
selection.addAll(mProvisionalSelection);
return selection;