diff options
author | Steve McKay <smckay@google.com> | 2015-04-22 18:13:17 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-04-22 18:13:21 +0000 |
commit | a56104d74dbbd35b785ec542d8804cf05f70bf21 (patch) | |
tree | ca669b8b629166416ca7aa479aea5112fa94aecd /packages/DocumentsUI | |
parent | 4ff2617265500ecf6ccd48ded034fdc7e4c90e35 (diff) | |
parent | ef3e2cf35fbede340d5ff830b410baea8e461a94 (diff) | |
download | frameworks_base-a56104d74dbbd35b785ec542d8804cf05f70bf21.zip frameworks_base-a56104d74dbbd35b785ec542d8804cf05f70bf21.tar.gz frameworks_base-a56104d74dbbd35b785ec542d8804cf05f70bf21.tar.bz2 |
Merge "Reduce code duplication between DocumentsActivity and StandaloneActivity."
Diffstat (limited to 'packages/DocumentsUI')
8 files changed, 753 insertions, 1242 deletions
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java index 8039b71..efe71d4 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java @@ -16,17 +16,47 @@ package com.android.documentsui; +import static com.android.documentsui.DirectoryFragment.ANIM_NONE; +import static com.android.documentsui.DirectoryFragment.ANIM_SIDE; +import static com.android.documentsui.DirectoryFragment.ANIM_UP; + +import java.io.FileNotFoundException; +import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; +import java.util.concurrent.Executor; +import libcore.io.IoUtils; import android.app.Activity; import android.app.Fragment; -import android.content.pm.ResolveInfo; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.provider.DocumentsContract; +import android.provider.DocumentsContract.Root; +import android.util.Log; import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MenuItem.OnActionExpandListener; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.SearchView; +import android.widget.SearchView.OnQueryTextListener; +import android.widget.TextView; +import com.android.documentsui.RecentsProvider.ResumeColumns; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.DurableUtils; @@ -34,20 +64,125 @@ import com.android.documentsui.model.RootInfo; import com.google.common.collect.Maps; abstract class BaseActivity extends Activity { + + static final String EXTRA_STATE = "state"; + + private final String mTag; + RootsCache mRoots; + public abstract State getDisplayState(); - public abstract RootInfo getCurrentRoot(); - public abstract void onStateChanged(); - public abstract void setRootsDrawerOpen(boolean open); public abstract void onDocumentPicked(DocumentInfo doc); public abstract void onDocumentsPicked(List<DocumentInfo> docs); - public abstract DocumentInfo getCurrentDirectory(); - public abstract void setPending(boolean pending); - public abstract void onStackPicked(DocumentStack stack); - public abstract void onPickRequested(DocumentInfo pickTarget); - public abstract void onAppPicked(ResolveInfo info); - public abstract void onRootPicked(RootInfo root, boolean closeDrawer); - public abstract void onSaveRequested(DocumentInfo replaceTarget); - public abstract void onSaveRequested(String mimeType, String displayName); + abstract void onTaskFinished(Uri... uris); + abstract void onDirectoryChanged(int anim); + abstract void updateActionBar(); + abstract void saveStackBlocking(); + + public BaseActivity(String tag) { + mTag = tag; + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + mRoots = DocumentsApplication.getRootsCache(this); + } + + void onStackRestored(boolean restored, boolean external) {} + + void onRootPicked(RootInfo root) { + State state = getDisplayState(); + + // Clear entire backstack and start in new root + state.stack.root = root; + state.stack.clear(); + state.stackTouched = true; + + if (!mRoots.isRecentsRoot(root)) { + new PickRootTask(root).executeOnExecutor(getCurrentExecutor()); + } else { + onCurrentDirectoryChanged(ANIM_SIDE); + } + } + + void expandMenus(Menu menu) { + for (int i = 0; i < menu.size(); i++) { + final MenuItem item = menu.getItem(i); + switch (item.getItemId()) { + case R.id.menu_advanced: + case R.id.menu_file_size: + break; + default: + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + } + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + final int id = item.getItemId(); + if (id == android.R.id.home) { + onBackPressed(); + return true; + } else if (id == R.id.menu_create_dir) { + CreateDirectoryFragment.show(getFragmentManager()); + return true; + } else if (id == R.id.menu_search) { + return false; + } else if (id == R.id.menu_sort_name) { + setUserSortOrder(State.SORT_ORDER_DISPLAY_NAME); + return true; + } else if (id == R.id.menu_sort_date) { + setUserSortOrder(State.SORT_ORDER_LAST_MODIFIED); + return true; + } else if (id == R.id.menu_sort_size) { + setUserSortOrder(State.SORT_ORDER_SIZE); + return true; + } else if (id == R.id.menu_grid) { + setUserMode(State.MODE_GRID); + return true; + } else if (id == R.id.menu_list) { + setUserMode(State.MODE_LIST); + return true; + } else if (id == R.id.menu_advanced) { + setDisplayAdvancedDevices(!LocalPreferences.getDisplayAdvancedDevices(this)); + return true; + } else if (id == R.id.menu_file_size) { + setDisplayFileSize(!LocalPreferences.getDisplayFileSize(this)); + return true; + } else if (id == R.id.menu_settings) { + final RootInfo root = getCurrentRoot(); + final Intent intent = new Intent(DocumentsContract.ACTION_DOCUMENT_ROOT_SETTINGS); + intent.setDataAndType(DocumentsContract.buildRootUri(root.authority, root.rootId), + DocumentsContract.Root.MIME_TYPE_ITEM); + startActivity(intent); + return true; + } + + return super.onOptionsItemSelected(item); + } + + /** + * Call this when directory changes. Prior to root fragment update + * the (abstract) directoryChanged method will be called. + * @param anim + */ + final void onCurrentDirectoryChanged(int anim) { + onDirectoryChanged(anim); + + final RootsFragment roots = RootsFragment.get(getFragmentManager()); + if (roots != null) { + roots.onCurrentRootChanged(); + } + + updateActionBar(); + invalidateOptionsMenu(); + } + + final String getCallingPackageMaybeExtra() { + final String extra = getIntent().getStringExtra(DocumentsContract.EXTRA_PACKAGE_NAME); + return (extra != null) ? extra : getCallingPackage(); + } public static BaseActivity get(Fragment fragment) { return (BaseActivity) fragment.getActivity(); @@ -169,4 +304,382 @@ abstract class BaseActivity extends Activity { } }; } + + void setDisplayAdvancedDevices(boolean display) { + State state = getDisplayState(); + LocalPreferences.setDisplayAdvancedDevices(this, display); + state.showAdvanced = state.forceAdvanced | display; + RootsFragment.get(getFragmentManager()).onDisplayStateChanged(); + invalidateOptionsMenu(); + } + + void setDisplayFileSize(boolean display) { + LocalPreferences.setDisplayFileSize(this, display); + getDisplayState().showSize = display; + DirectoryFragment.get(getFragmentManager()).onDisplayStateChanged(); + invalidateOptionsMenu(); + } + + void onStateChanged() { + invalidateOptionsMenu(); + } + + /** + * Set state sort order based on explicit user action. + */ + void setUserSortOrder(int sortOrder) { + getDisplayState().userSortOrder = sortOrder; + DirectoryFragment.get(getFragmentManager()).onUserSortOrderChanged(); + } + + /** + * Set state mode based on explicit user action. + */ + void setUserMode(int mode) { + getDisplayState().userMode = mode; + DirectoryFragment.get(getFragmentManager()).onUserModeChanged(); + } + + void setPending(boolean pending) { + final SaveFragment save = SaveFragment.get(getFragmentManager()); + if (save != null) { + save.setPending(pending); + } + } + + @Override + protected void onSaveInstanceState(Bundle state) { + super.onSaveInstanceState(state); + state.putParcelable(EXTRA_STATE, getDisplayState()); + } + + @Override + protected void onRestoreInstanceState(Bundle state) { + super.onRestoreInstanceState(state); + } + + RootInfo getCurrentRoot() { + State state = getDisplayState(); + if (state.stack.root != null) { + return state.stack.root; + } else { + return mRoots.getRecentsRoot(); + } + } + + public DocumentInfo getCurrentDirectory() { + return getDisplayState().stack.peek(); + } + + public Executor getCurrentExecutor() { + final DocumentInfo cwd = getCurrentDirectory(); + if (cwd != null && cwd.authority != null) { + return ProviderExecutor.forAuthority(cwd.authority); + } else { + return AsyncTask.THREAD_POOL_EXECUTOR; + } + } + + public void onStackPicked(DocumentStack stack) { + try { + // Update the restored stack to ensure we have freshest data + stack.updateDocuments(getContentResolver()); + + State state = getDisplayState(); + state.stack = stack; + state.stackTouched = true; + onCurrentDirectoryChanged(ANIM_SIDE); + + } catch (FileNotFoundException e) { + Log.w(mTag, "Failed to restore stack: " + e); + } + } + + final class PickRootTask extends AsyncTask<Void, Void, DocumentInfo> { + private RootInfo mRoot; + + public PickRootTask(RootInfo root) { + mRoot = root; + } + + @Override + protected DocumentInfo doInBackground(Void... params) { + try { + final Uri uri = DocumentsContract.buildDocumentUri( + mRoot.authority, mRoot.documentId); + return DocumentInfo.fromUri(getContentResolver(), uri); + } catch (FileNotFoundException e) { + Log.w(mTag, "Failed to find root", e); + return null; + } + } + + @Override + protected void onPostExecute(DocumentInfo result) { + if (result != null) { + State state = getDisplayState(); + state.stack.push(result); + state.stackTouched = true; + onCurrentDirectoryChanged(ANIM_SIDE); + } + } + } + + final class RestoreStackTask extends AsyncTask<Void, Void, Void> { + private volatile boolean mRestoredStack; + private volatile boolean mExternal; + + @Override + protected Void doInBackground(Void... params) { + State state = getDisplayState(); + RootsCache roots = DocumentsApplication.getRootsCache(BaseActivity.this); + + // Restore last stack for calling package + final String packageName = getCallingPackageMaybeExtra(); + final Cursor cursor = getContentResolver() + .query(RecentsProvider.buildResume(packageName), null, null, null, null); + try { + if (cursor.moveToFirst()) { + mExternal = cursor.getInt(cursor.getColumnIndex(ResumeColumns.EXTERNAL)) != 0; + final byte[] rawStack = cursor.getBlob( + cursor.getColumnIndex(ResumeColumns.STACK)); + DurableUtils.readFromArray(rawStack, state.stack); + mRestoredStack = true; + } + } catch (IOException e) { + Log.w(mTag, "Failed to resume: " + e); + } finally { + IoUtils.closeQuietly(cursor); + } + + if (mRestoredStack) { + // Update the restored stack to ensure we have freshest data + final Collection<RootInfo> matchingRoots = roots.getMatchingRootsBlocking(state); + try { + state.stack.updateRoot(matchingRoots); + state.stack.updateDocuments(getContentResolver()); + } catch (FileNotFoundException e) { + Log.w(mTag, "Failed to restore stack: " + e); + state.stack.reset(); + mRestoredStack = false; + } + } + + return null; + } + + @Override + protected void onPostExecute(Void result) { + if (isDestroyed()) return; + getDisplayState().restored = true; + onCurrentDirectoryChanged(ANIM_NONE); + + onStackRestored(mRestoredStack, mExternal); + + getDisplayState().restored = true; + onCurrentDirectoryChanged(ANIM_NONE); + } + } + + final class ItemSelectedListener implements OnItemSelectedListener { + + boolean mIgnoreNextNavigation; + + @Override + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + if (mIgnoreNextNavigation) { + mIgnoreNextNavigation = false; + return; + } + + State state = getDisplayState(); + while (state.stack.size() > position + 1) { + state.stackTouched = true; + state.stack.pop(); + } + onCurrentDirectoryChanged(ANIM_UP); + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + // Ignored + } + } + + /** + * Class providing toolbar with runtime access to useful activity data. + */ + final class StackAdapter extends BaseAdapter { + @Override + public int getCount() { + return getDisplayState().stack.size(); + } + + @Override + public DocumentInfo getItem(int position) { + State state = getDisplayState(); + return state.stack.get(state.stack.size() - position - 1); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_subdir_title, parent, false); + } + + final TextView title = (TextView) convertView.findViewById(android.R.id.title); + final DocumentInfo doc = getItem(position); + + if (position == 0) { + final RootInfo root = getCurrentRoot(); + title.setText(root.title); + } else { + title.setText(doc.displayName); + } + + return convertView; + } + + @Override + public View getDropDownView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_subdir, parent, false); + } + + final ImageView subdir = (ImageView) convertView.findViewById(R.id.subdir); + final TextView title = (TextView) convertView.findViewById(android.R.id.title); + final DocumentInfo doc = getItem(position); + + if (position == 0) { + final RootInfo root = getCurrentRoot(); + title.setText(root.title); + subdir.setVisibility(View.GONE); + } else { + title.setText(doc.displayName); + subdir.setVisibility(View.VISIBLE); + } + + return convertView; + } + } + + /** + * Facade over the various search parts in the menu. + */ + final class SearchManager implements + SearchView.OnCloseListener, OnActionExpandListener, OnQueryTextListener { + + protected boolean mSearchExpanded; + protected boolean mIgnoreNextClose; + protected boolean mIgnoreNextCollapse; + + private MenuItem mMenu; + private SearchView mView; + + public void install(MenuItem menu) { + assert(mMenu == null); + mMenu = menu; + mView = (SearchView) menu.getActionView(); + + mMenu.setOnActionExpandListener(this); + mView.setOnQueryTextListener(this); + mView.setOnCloseListener(this); + } + + /** + * @param root Info about the current directory. + */ + void update(RootInfo root) { + if (mMenu == null) { + Log.d(mTag, "showMenu called before Search MenuItem installed."); + return; + } + State state = getDisplayState(); + if (state.currentSearch != null) { + mMenu.expandActionView(); + + mView.setIconified(false); + mView.clearFocus(); + mView.setQuery(state.currentSearch, false); + } else { + mIgnoreNextClose = true; + mView.setIconified(true); + mView.clearFocus(); + + mIgnoreNextCollapse = true; + mMenu.collapseActionView(); + } + + showMenu(root != null + && ((root.flags & Root.FLAG_SUPPORTS_SEARCH) != 0)); + } + + void showMenu(boolean visible) { + if (mMenu == null) { + Log.d(mTag, "showMenu called before Search MenuItem installed."); + return; + } + mMenu.setVisible(visible); + } + + boolean isSearching() { + return getDisplayState().currentSearch != null; + } + + boolean isExpanded() { + return mSearchExpanded; + } + + @Override + public boolean onClose() { + mSearchExpanded = false; + if (mIgnoreNextClose) { + mIgnoreNextClose = false; + return false; + } + + getDisplayState().currentSearch = null; + onCurrentDirectoryChanged(ANIM_NONE); + return false; + } + @Override + public boolean onMenuItemActionExpand(MenuItem item) { + mSearchExpanded = true; + updateActionBar(); + return true; + } + + @Override + public boolean onMenuItemActionCollapse(MenuItem item) { + mSearchExpanded = false; + if (mIgnoreNextCollapse) { + mIgnoreNextCollapse = false; + return true; + } + + getDisplayState().currentSearch = null; + onCurrentDirectoryChanged(ANIM_NONE); + return true; + } + @Override + public boolean onQueryTextSubmit(String query) { + mSearchExpanded = true; + getDisplayState().currentSearch = query; + mView.clearFocus(); + onCurrentDirectoryChanged(ANIM_NONE); + return true; + } + + @Override + public boolean onQueryTextChange(String newText) { + return false; + } + } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index ef644f4..7cf58cc 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -28,7 +28,6 @@ import static com.android.documentsui.DocumentsActivity.TAG; import static com.android.documentsui.model.DocumentInfo.getCursorInt; import static com.android.documentsui.model.DocumentInfo.getCursorLong; import static com.android.documentsui.model.DocumentInfo.getCursorString; - import android.app.Activity; import android.app.ActivityManager; import android.app.Fragment; @@ -311,8 +310,9 @@ public class DirectoryFragment extends Fragment { updateDisplayState(); // When launched into empty recents, show drawer - if (mType == TYPE_RECENT_OPEN && mAdapter.isEmpty() && !state.stackTouched) { - ((BaseActivity) context).setRootsDrawerOpen(true); + if (mType == TYPE_RECENT_OPEN && mAdapter.isEmpty() && !state.stackTouched && + context instanceof DocumentsActivity) { + ((DocumentsActivity) context).setRootsDrawerOpen(true); } // Restore any previous instance state diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index a2a789f..9d828de 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -21,16 +21,17 @@ import static com.android.documentsui.BaseActivity.State.ACTION_CREATE; import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT; import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE; import static com.android.documentsui.BaseActivity.State.ACTION_OPEN; -import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE; import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_COPY_DESTINATION; -import static com.android.documentsui.BaseActivity.State.MODE_GRID; -import static com.android.documentsui.BaseActivity.State.MODE_LIST; +import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE; import static com.android.documentsui.DirectoryFragment.ANIM_DOWN; import static com.android.documentsui.DirectoryFragment.ANIM_NONE; -import static com.android.documentsui.DirectoryFragment.ANIM_SIDE; import static com.android.documentsui.DirectoryFragment.ANIM_UP; +import java.util.Arrays; +import java.util.List; + import android.app.Activity; +import android.app.Fragment; import android.app.FragmentManager; import android.content.ActivityNotFoundException; import android.content.ClipData; @@ -42,7 +43,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; import android.content.res.Resources; -import android.database.Cursor; import android.graphics.Point; import android.net.Uri; import android.os.AsyncTask; @@ -54,51 +54,27 @@ import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout.DrawerListener; import android.util.Log; -import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; -import android.view.MenuItem.OnActionExpandListener; import android.view.View; -import android.view.ViewGroup; import android.view.WindowManager; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; import android.widget.BaseAdapter; -import android.widget.ImageView; -import android.widget.SearchView; -import android.widget.SearchView.OnQueryTextListener; import android.widget.Spinner; -import android.widget.TextView; import android.widget.Toast; import android.widget.Toolbar; -import libcore.io.IoUtils; - import com.android.documentsui.RecentsProvider.RecentColumns; import com.android.documentsui.RecentsProvider.ResumeColumns; import com.android.documentsui.model.DocumentInfo; -import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.DurableUtils; import com.android.documentsui.model.RootInfo; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.Executor; - public class DocumentsActivity extends BaseActivity { - public static final String TAG = "Documents"; - - private static final String EXTRA_STATE = "state"; - private static final int CODE_FORWARD = 42; + public static final String TAG = "Documents"; private boolean mShowAsDialog; - private SearchView mSearchView; - private Toolbar mToolbar; private Spinner mToolbarStack; @@ -110,21 +86,20 @@ public class DocumentsActivity extends BaseActivity { private DirectoryContainerView mDirectoryContainer; - private boolean mIgnoreNextNavigation; - private boolean mIgnoreNextClose; - private boolean mIgnoreNextCollapse; + private State mState; - private boolean mSearchExpanded; + private SearchManager mSearchManager; + private ItemSelectedListener mStackListener; + private BaseAdapter mStackAdapter; - private RootsCache mRoots; - private State mState; + public DocumentsActivity() { + super(TAG); + } @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - mRoots = DocumentsApplication.getRootsCache(this); - setResult(Activity.RESULT_CANCELED); setContentView(R.layout.activity); @@ -157,16 +132,16 @@ public class DocumentsActivity extends BaseActivity { mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory); - if (icicle != null) { - mState = icicle.getParcelable(EXTRA_STATE); - } else { - buildDefaultState(); - } + mState = (icicle != null) + ? icicle.<State>getParcelable(EXTRA_STATE) + : buildDefaultState(); mToolbar = (Toolbar) findViewById(R.id.toolbar); mToolbar.setTitleTextAppearance(context, android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title); + mStackAdapter = new StackAdapter(); + mStackListener = new ItemSelectedListener(); mToolbarStack = (Spinner) findViewById(R.id.stack); mToolbarStack.setOnItemSelectedListener(mStackListener); @@ -176,6 +151,7 @@ public class DocumentsActivity extends BaseActivity { android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title); } + mSearchManager = new SearchManager(); setActionBar(mToolbar); // Hide roots when we're managing a specific root @@ -220,55 +196,57 @@ public class DocumentsActivity extends BaseActivity { } } - private void buildDefaultState() { - mState = new State(); + private State buildDefaultState() { + State state = new State(); final Intent intent = getIntent(); final String action = intent.getAction(); if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) { - mState.action = ACTION_OPEN; + state.action = ACTION_OPEN; } else if (Intent.ACTION_CREATE_DOCUMENT.equals(action)) { - mState.action = ACTION_CREATE; + state.action = ACTION_CREATE; } else if (Intent.ACTION_GET_CONTENT.equals(action)) { - mState.action = ACTION_GET_CONTENT; + state.action = ACTION_GET_CONTENT; } else if (Intent.ACTION_OPEN_DOCUMENT_TREE.equals(action)) { - mState.action = ACTION_OPEN_TREE; + state.action = ACTION_OPEN_TREE; } else if (DocumentsContract.ACTION_MANAGE_ROOT.equals(action)) { - mState.action = ACTION_MANAGE; + state.action = ACTION_MANAGE; } else if (DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT.equals(action)) { - mState.action = ACTION_BROWSE; + state.action = ACTION_BROWSE; } else if (DocumentsIntent.ACTION_OPEN_COPY_DESTINATION.equals(action)) { - mState.action = ACTION_OPEN_COPY_DESTINATION; + state.action = ACTION_OPEN_COPY_DESTINATION; } - if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) { - mState.allowMultiple = intent.getBooleanExtra( + if (state.action == ACTION_OPEN || state.action == ACTION_GET_CONTENT) { + state.allowMultiple = intent.getBooleanExtra( Intent.EXTRA_ALLOW_MULTIPLE, false); } - if (mState.action == ACTION_MANAGE || mState.action == ACTION_BROWSE) { - mState.acceptMimes = new String[] { "*/*" }; - mState.allowMultiple = true; + if (state.action == ACTION_MANAGE || state.action == ACTION_BROWSE) { + state.acceptMimes = new String[] { "*/*" }; + state.allowMultiple = true; } else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) { - mState.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES); + state.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES); } else { - mState.acceptMimes = new String[] { intent.getType() }; + state.acceptMimes = new String[] { intent.getType() }; } - mState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false); - mState.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false); - mState.showAdvanced = mState.forceAdvanced + state.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false); + state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false); + state.showAdvanced = state.forceAdvanced | LocalPreferences.getDisplayAdvancedDevices(this); - if (mState.action == ACTION_MANAGE || mState.action == ACTION_BROWSE) { - mState.showSize = true; + if (state.action == ACTION_MANAGE || state.action == ACTION_BROWSE) { + state.showSize = true; } else { - mState.showSize = LocalPreferences.getDisplayFileSize(this); + state.showSize = LocalPreferences.getDisplayFileSize(this); } - if (mState.action == ACTION_OPEN_COPY_DESTINATION) { - mState.directoryCopy = intent.getBooleanExtra( + if (state.action == ACTION_OPEN_COPY_DESTINATION) { + state.directoryCopy = intent.getBooleanExtra( BaseActivity.DocumentsIntent.EXTRA_DIRECTORY_COPY, false); } + + return state; } private class RestoreRootTask extends AsyncTask<Void, Void, RootInfo> { @@ -290,7 +268,7 @@ public class DocumentsActivity extends BaseActivity { mState.restored = true; if (root != null) { - onRootPicked(root, true); + onRootPicked(root); } else { Log.w(TAG, "Failed to find root: " + mRootUri); finish(); @@ -298,71 +276,55 @@ public class DocumentsActivity extends BaseActivity { } } - private class RestoreStackTask extends AsyncTask<Void, Void, Void> { - private volatile boolean mRestoredStack; - private volatile boolean mExternal; - - @Override - protected Void doInBackground(Void... params) { - // Restore last stack for calling package - final String packageName = getCallingPackageMaybeExtra(); - final Cursor cursor = getContentResolver() - .query(RecentsProvider.buildResume(packageName), null, null, null, null); - try { - if (cursor.moveToFirst()) { - mExternal = cursor.getInt(cursor.getColumnIndex(ResumeColumns.EXTERNAL)) != 0; - final byte[] rawStack = cursor.getBlob( - cursor.getColumnIndex(ResumeColumns.STACK)); - DurableUtils.readFromArray(rawStack, mState.stack); - mRestoredStack = true; - } - } catch (IOException e) { - Log.w(TAG, "Failed to resume: " + e); - } finally { - IoUtils.closeQuietly(cursor); - } + @Override + void onStackRestored(boolean restored, boolean external) { + // Show drawer when no stack restored, but only when requesting + // non-visual content. However, if we last used an external app, + // drawer is always shown. - if (mRestoredStack) { - // Update the restored stack to ensure we have freshest data - final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState); - try { - mState.stack.updateRoot(matchingRoots); - mState.stack.updateDocuments(getContentResolver()); - } catch (FileNotFoundException e) { - Log.w(TAG, "Failed to restore stack: " + e); - mState.stack.reset(); - mRestoredStack = false; - } - } + boolean showDrawer = false; + if (!restored) { + showDrawer = true; + } + if (MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) { + showDrawer = false; + } + if (external && mState.action == ACTION_GET_CONTENT) { + showDrawer = true; + } - return null; + if (showDrawer) { + setRootsDrawerOpen(true); } + } - @Override - protected void onPostExecute(Void result) { - if (isDestroyed()) return; - mState.restored = true; + public void onAppPicked(ResolveInfo info) { + final Intent intent = new Intent(getIntent()); + intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT); + intent.setComponent(new ComponentName( + info.activityInfo.applicationInfo.packageName, info.activityInfo.name)); + startActivityForResult(intent, CODE_FORWARD); + } - // Show drawer when no stack restored, but only when requesting - // non-visual content. However, if we last used an external app, - // drawer is always shown. + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + Log.d(TAG, "onActivityResult() code=" + resultCode); - boolean showDrawer = false; - if (!mRestoredStack) { - showDrawer = true; - } - if (MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) { - showDrawer = false; - } - if (mExternal && mState.action == ACTION_GET_CONTENT) { - showDrawer = true; - } + // Only relay back results when not canceled; otherwise stick around to + // let the user pick another app/backend. + if (requestCode == CODE_FORWARD && resultCode != RESULT_CANCELED) { - if (showDrawer) { - setRootsDrawerOpen(true); - } + // Remember that we last picked via external app + final String packageName = getCallingPackageMaybeExtra(); + final ContentValues values = new ContentValues(); + values.put(ResumeColumns.EXTERNAL, 1); + getContentResolver().insert(RecentsProvider.buildResume(packageName), values); - onCurrentDirectoryChanged(ANIM_NONE); + // Pass back result to original caller + setResult(resultCode, data); + finish(); + } else { + super.onActivityResult(requestCode, resultCode, data); } } @@ -397,7 +359,6 @@ public class DocumentsActivity extends BaseActivity { updateActionBar(); } - @Override public void setRootsDrawerOpen(boolean open) { if (!mShowAsDialog) { if (open) { @@ -416,6 +377,7 @@ public class DocumentsActivity extends BaseActivity { } } + @Override public void updateActionBar() { if (mRootsToolbar != null) { if (mState.action == ACTION_OPEN || @@ -447,7 +409,7 @@ public class DocumentsActivity extends BaseActivity { }); } - if (mSearchExpanded) { + if (mSearchManager.isExpanded()) { mToolbar.setTitle(null); mToolbarStack.setVisibility(View.GONE); mToolbarStack.setAdapter(null); @@ -461,7 +423,7 @@ public class DocumentsActivity extends BaseActivity { mToolbarStack.setVisibility(View.VISIBLE); mToolbarStack.setAdapter(mStackAdapter); - mIgnoreNextNavigation = true; + mStackListener.mIgnoreNextNavigation = true; mToolbarStack.setSelection(mStackAdapter.getCount() - 1); } } @@ -469,79 +431,18 @@ public class DocumentsActivity extends BaseActivity { @Override public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); + boolean showMenu = super.onCreateOptionsMenu(menu); + getMenuInflater().inflate(R.menu.activity, menu); // Most actions are visible when showing as dialog if (mShowAsDialog) { - for (int i = 0; i < menu.size(); i++) { - final MenuItem item = menu.getItem(i); - switch (item.getItemId()) { - case R.id.menu_advanced: - case R.id.menu_file_size: - break; - default: - item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - } - } + expandMenus(menu); } - final MenuItem searchMenu = menu.findItem(R.id.menu_search); - mSearchView = (SearchView) searchMenu.getActionView(); - mSearchView.setOnQueryTextListener(new OnQueryTextListener() { - @Override - public boolean onQueryTextSubmit(String query) { - mSearchExpanded = true; - mState.currentSearch = query; - mSearchView.clearFocus(); - onCurrentDirectoryChanged(ANIM_NONE); - return true; - } - - @Override - public boolean onQueryTextChange(String newText) { - return false; - } - }); - - searchMenu.setOnActionExpandListener(new OnActionExpandListener() { - @Override - public boolean onMenuItemActionExpand(MenuItem item) { - mSearchExpanded = true; - updateActionBar(); - return true; - } - - @Override - public boolean onMenuItemActionCollapse(MenuItem item) { - mSearchExpanded = false; - if (mIgnoreNextCollapse) { - mIgnoreNextCollapse = false; - return true; - } + this.mSearchManager.install(menu.findItem(R.id.menu_search)); - mState.currentSearch = null; - onCurrentDirectoryChanged(ANIM_NONE); - return true; - } - }); - - mSearchView.setOnCloseListener(new SearchView.OnCloseListener() { - @Override - public boolean onClose() { - mSearchExpanded = false; - if (mIgnoreNextClose) { - mIgnoreNextClose = false; - return false; - } - - mState.currentSearch = null; - onCurrentDirectoryChanged(ANIM_NONE); - return false; - } - }); - - return true; + return showMenu; } @Override @@ -554,7 +455,6 @@ public class DocumentsActivity extends BaseActivity { final DocumentInfo cwd = getCurrentDirectory(); final MenuItem createDir = menu.findItem(R.id.menu_create_dir); - final MenuItem search = menu.findItem(R.id.menu_search); final MenuItem sort = menu.findItem(R.id.menu_sort); final MenuItem sortSize = menu.findItem(R.id.menu_sort_size); final MenuItem grid = menu.findItem(R.id.menu_grid); @@ -564,36 +464,23 @@ public class DocumentsActivity extends BaseActivity { final MenuItem settings = menu.findItem(R.id.menu_settings); sort.setVisible(cwd != null); - grid.setVisible(mState.derivedMode != MODE_GRID); - list.setVisible(mState.derivedMode != MODE_LIST); + grid.setVisible(mState.derivedMode != State.MODE_GRID); + list.setVisible(mState.derivedMode != State.MODE_LIST); - if (mState.currentSearch != null) { - // Search uses backend ranking; no sorting - sort.setVisible(false); - search.expandActionView(); + mSearchManager.update(root); - mSearchView.setIconified(false); - mSearchView.clearFocus(); - mSearchView.setQuery(mState.currentSearch, false); - } else { - mIgnoreNextClose = true; - mSearchView.setIconified(true); - mSearchView.clearFocus(); - - mIgnoreNextCollapse = true; - search.collapseActionView(); - } + // Search uses backend ranking; no sorting + sort.setVisible(mSearchManager.isSearching()); // Only sort by size when visible sortSize.setVisible(mState.showSize); - boolean searchVisible; boolean fileSizeVisible = !(mState.action == ACTION_MANAGE || mState.action == ACTION_BROWSE); if (mState.action == ACTION_CREATE || mState.action == ACTION_OPEN_TREE) { createDir.setVisible(cwd != null && cwd.isCreateSupported()); - searchVisible = false; + mSearchManager.showMenu(false); // No display options in recent directories if (cwd == null) { @@ -607,14 +494,8 @@ public class DocumentsActivity extends BaseActivity { } } else { createDir.setVisible(false); - - searchVisible = root != null - && ((root.flags & Root.FLAG_SUPPORTS_SEARCH) != 0); } - // TODO: close any search in-progress when hiding - search.setVisible(searchVisible); - advanced.setTitle(LocalPreferences.getDisplayAdvancedDevices(this) ? R.string.menu_advanced_hide : R.string.menu_advanced_show); fileSize.setTitle(LocalPreferences.getDisplayFileSize(this) @@ -634,90 +515,7 @@ public class DocumentsActivity extends BaseActivity { if (mDrawerToggle != null && mDrawerToggle.onOptionsItemSelected(item)) { return true; } - - final int id = item.getItemId(); - if (id == android.R.id.home) { - onBackPressed(); - return true; - } else if (id == R.id.menu_create_dir) { - CreateDirectoryFragment.show(getFragmentManager()); - return true; - } else if (id == R.id.menu_search) { - return false; - } else if (id == R.id.menu_sort_name) { - setUserSortOrder(State.SORT_ORDER_DISPLAY_NAME); - return true; - } else if (id == R.id.menu_sort_date) { - setUserSortOrder(State.SORT_ORDER_LAST_MODIFIED); - return true; - } else if (id == R.id.menu_sort_size) { - setUserSortOrder(State.SORT_ORDER_SIZE); - return true; - } else if (id == R.id.menu_grid) { - setUserMode(State.MODE_GRID); - return true; - } else if (id == R.id.menu_list) { - setUserMode(State.MODE_LIST); - return true; - } else if (id == R.id.menu_advanced) { - setDisplayAdvancedDevices(!LocalPreferences.getDisplayAdvancedDevices(this)); - return true; - } else if (id == R.id.menu_file_size) { - setDisplayFileSize(!LocalPreferences.getDisplayFileSize(this)); - return true; - } else if (id == R.id.menu_settings) { - final RootInfo root = getCurrentRoot(); - final Intent intent = new Intent(DocumentsContract.ACTION_DOCUMENT_ROOT_SETTINGS); - intent.setDataAndType(DocumentsContract.buildRootUri(root.authority, root.rootId), - DocumentsContract.Root.MIME_TYPE_ITEM); - startActivity(intent); - return true; - } else { - return super.onOptionsItemSelected(item); - } - } - - private void setDisplayAdvancedDevices(boolean display) { - LocalPreferences.setDisplayAdvancedDevices(this, display); - mState.showAdvanced = mState.forceAdvanced | display; - RootsFragment.get(getFragmentManager()).onDisplayStateChanged(); - invalidateOptionsMenu(); - } - - private void setDisplayFileSize(boolean display) { - LocalPreferences.setDisplayFileSize(this, display); - mState.showSize = display; - DirectoryFragment.get(getFragmentManager()).onDisplayStateChanged(); - invalidateOptionsMenu(); - } - - @Override - public void onStateChanged() { - invalidateOptionsMenu(); - } - - /** - * Set state sort order based on explicit user action. - */ - private void setUserSortOrder(int sortOrder) { - mState.userSortOrder = sortOrder; - DirectoryFragment.get(getFragmentManager()).onUserSortOrderChanged(); - } - - /** - * Set state mode based on explicit user action. - */ - private void setUserMode(int mode) { - mState.userMode = mode; - DirectoryFragment.get(getFragmentManager()).onUserModeChanged(); - } - - @Override - public void setPending(boolean pending) { - final SaveFragment save = SaveFragment.get(getFragmentManager()); - if (save != null) { - save.setPending(pending); - } + return super.onOptionsItemSelected(item); } @Override @@ -740,131 +538,12 @@ public class DocumentsActivity extends BaseActivity { } @Override - protected void onSaveInstanceState(Bundle state) { - super.onSaveInstanceState(state); - state.putParcelable(EXTRA_STATE, mState); - } - - @Override - protected void onRestoreInstanceState(Bundle state) { - super.onRestoreInstanceState(state); - } - - private BaseAdapter mStackAdapter = new BaseAdapter() { - @Override - public int getCount() { - return mState.stack.size(); - } - - @Override - public DocumentInfo getItem(int position) { - return mState.stack.get(mState.stack.size() - position - 1); - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.item_subdir_title, parent, false); - } - - final TextView title = (TextView) convertView.findViewById(android.R.id.title); - final DocumentInfo doc = getItem(position); - - if (position == 0) { - final RootInfo root = getCurrentRoot(); - title.setText(root.title); - } else { - title.setText(doc.displayName); - } - - return convertView; - } - - @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.item_subdir, parent, false); - } - - final ImageView subdir = (ImageView) convertView.findViewById(R.id.subdir); - final TextView title = (TextView) convertView.findViewById(android.R.id.title); - final DocumentInfo doc = getItem(position); - - if (position == 0) { - final RootInfo root = getCurrentRoot(); - title.setText(root.title); - subdir.setVisibility(View.GONE); - } else { - title.setText(doc.displayName); - subdir.setVisibility(View.VISIBLE); - } - - return convertView; - } - }; - - private OnItemSelectedListener mStackListener = new OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - if (mIgnoreNextNavigation) { - mIgnoreNextNavigation = false; - return; - } - - while (mState.stack.size() > position + 1) { - mState.stackTouched = true; - mState.stack.pop(); - } - onCurrentDirectoryChanged(ANIM_UP); - } - - @Override - public void onNothingSelected(AdapterView<?> parent) { - // Ignored - } - }; - - @Override - public RootInfo getCurrentRoot() { - if (mState.stack.root != null) { - return mState.stack.root; - } else { - return mRoots.getRecentsRoot(); - } - } - - @Override - public DocumentInfo getCurrentDirectory() { - return mState.stack.peek(); - } - - private String getCallingPackageMaybeExtra() { - final String extra = getIntent().getStringExtra(DocumentsContract.EXTRA_PACKAGE_NAME); - return (extra != null) ? extra : getCallingPackage(); - } - - public Executor getCurrentExecutor() { - final DocumentInfo cwd = getCurrentDirectory(); - if (cwd != null && cwd.authority != null) { - return ProviderExecutor.forAuthority(cwd.authority); - } else { - return AsyncTask.THREAD_POOL_EXECUTOR; - } - } - - @Override public State getDisplayState() { return mState; } - private void onCurrentDirectoryChanged(int anim) { + @Override + void onDirectoryChanged(int anim) { final FragmentManager fm = getFragmentManager(); final RootInfo root = getCurrentRoot(); final DocumentInfo cwd = getCurrentDirectory(); @@ -883,7 +562,7 @@ public class DocumentsActivity extends BaseActivity { // Start recents in grid when requesting visual things final boolean visualMimes = MimePredicate.mimeMatches( MimePredicate.VISUAL_MIMES, mState.acceptMimes); - mState.userMode = visualMimes ? MODE_GRID : MODE_LIST; + mState.userMode = visualMimes ? State.MODE_GRID : State.MODE_LIST; mState.derivedMode = mState.userMode; } } else { @@ -913,108 +592,20 @@ public class DocumentsActivity extends BaseActivity { pick.setPickTarget(mState.action, cwd, displayName); } } - - final RootsFragment roots = RootsFragment.get(fm); - if (roots != null) { - roots.onCurrentRootChanged(); - } - - updateActionBar(); - invalidateOptionsMenu(); - dumpStack(); } - @Override - public void onStackPicked(DocumentStack stack) { - try { - // Update the restored stack to ensure we have freshest data - stack.updateDocuments(getContentResolver()); - - mState.stack = stack; - mState.stackTouched = true; - onCurrentDirectoryChanged(ANIM_SIDE); - - } catch (FileNotFoundException e) { - Log.w(TAG, "Failed to restore stack: " + e); - } - } - - @Override - public void onRootPicked(RootInfo root, boolean closeDrawer) { - // Clear entire backstack and start in new root - mState.stack.root = root; - mState.stack.clear(); - mState.stackTouched = true; - - if (!mRoots.isRecentsRoot(root)) { - new PickRootTask(root).executeOnExecutor(getCurrentExecutor()); - } else { - onCurrentDirectoryChanged(ANIM_SIDE); - } - - if (closeDrawer) { - setRootsDrawerOpen(false); - } - } - - private class PickRootTask extends AsyncTask<Void, Void, DocumentInfo> { - private RootInfo mRoot; - - public PickRootTask(RootInfo root) { - mRoot = root; - } - - @Override - protected DocumentInfo doInBackground(Void... params) { - try { - final Uri uri = DocumentsContract.buildDocumentUri( - mRoot.authority, mRoot.documentId); - return DocumentInfo.fromUri(getContentResolver(), uri); - } catch (FileNotFoundException e) { - Log.w(TAG, "Failed to find root", e); - return null; - } - } - - @Override - protected void onPostExecute(DocumentInfo result) { - if (result != null) { - mState.stack.push(result); - mState.stackTouched = true; - onCurrentDirectoryChanged(ANIM_SIDE); - } - } + void onSaveRequested(DocumentInfo replaceTarget) { + new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor()); } - @Override - public void onAppPicked(ResolveInfo info) { - final Intent intent = new Intent(getIntent()); - intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT); - intent.setComponent(new ComponentName( - info.activityInfo.applicationInfo.packageName, info.activityInfo.name)); - startActivityForResult(intent, CODE_FORWARD); + void onSaveRequested(String mimeType, String displayName) { + new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor()); } @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - Log.d(TAG, "onActivityResult() code=" + resultCode); - - // Only relay back results when not canceled; otherwise stick around to - // let the user pick another app/backend. - if (requestCode == CODE_FORWARD && resultCode != RESULT_CANCELED) { - - // Remember that we last picked via external app - final String packageName = getCallingPackageMaybeExtra(); - final ContentValues values = new ContentValues(); - values.put(ResumeColumns.EXTERNAL, 1); - getContentResolver().insert(RecentsProvider.buildResume(packageName), values); - - // Pass back result to original caller - setResult(resultCode, data); - finish(); - } else { - super.onActivityResult(requestCode, resultCode, data); - } + void onRootPicked(RootInfo root) { + super.onRootPicked(root); + setRootsDrawerOpen(false); } @Override @@ -1076,17 +667,6 @@ public class DocumentsActivity extends BaseActivity { } } - @Override - public void onSaveRequested(DocumentInfo replaceTarget) { - new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor()); - } - - @Override - public void onSaveRequested(String mimeType, String displayName) { - new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor()); - } - - @Override public void onPickRequested(DocumentInfo pickTarget) { Uri result; if (mState.action == ACTION_OPEN_TREE) { @@ -1101,7 +681,8 @@ public class DocumentsActivity extends BaseActivity { new PickFinishTask(result).executeOnExecutor(getCurrentExecutor()); } - private void saveStackBlocking() { + @Override + void saveStackBlocking() { final ContentResolver resolver = getContentResolver(); final ContentValues values = new ContentValues(); @@ -1124,7 +705,8 @@ public class DocumentsActivity extends BaseActivity { resolver.insert(RecentsProvider.buildResume(packageName), values); } - private void onFinished(Uri... uris) { + @Override + void onTaskFinished(Uri... uris) { Log.d(TAG, "onFinished() " + Arrays.toString(uris)); final Intent intent = new Intent(); @@ -1159,7 +741,52 @@ public class DocumentsActivity extends BaseActivity { finish(); } - private class CreateFinishTask extends AsyncTask<Void, Void, Uri> { + public static DocumentsActivity get(Fragment fragment) { + return (DocumentsActivity) fragment.getActivity(); + } + + private final class PickFinishTask extends AsyncTask<Void, Void, Void> { + private final Uri mUri; + + public PickFinishTask(Uri uri) { + mUri = uri; + } + + @Override + protected Void doInBackground(Void... params) { + saveStackBlocking(); + return null; + } + + @Override + protected void onPostExecute(Void result) { + onTaskFinished(mUri); + } + } + + final class ExistingFinishTask extends AsyncTask<Void, Void, Void> { + private final Uri[] mUris; + + public ExistingFinishTask(Uri... uris) { + mUris = uris; + } + + @Override + protected Void doInBackground(Void... params) { + saveStackBlocking(); + return null; + } + + @Override + protected void onPostExecute(Void result) { + onTaskFinished(mUris); + } + } + + /** + * Task that creates a new document in the background. + */ + final class CreateFinishTask extends AsyncTask<Void, Void, Uri> { private final String mMimeType; private final String mDisplayName; @@ -1201,7 +828,7 @@ public class DocumentsActivity extends BaseActivity { @Override protected void onPostExecute(Uri result) { if (result != null) { - onFinished(result); + onTaskFinished(result); } else { Toast.makeText(DocumentsActivity.this, R.string.save_error, Toast.LENGTH_SHORT) .show(); @@ -1210,50 +837,4 @@ public class DocumentsActivity extends BaseActivity { setPending(false); } } - - private class ExistingFinishTask extends AsyncTask<Void, Void, Void> { - private final Uri[] mUris; - - public ExistingFinishTask(Uri... uris) { - mUris = uris; - } - - @Override - protected Void doInBackground(Void... params) { - saveStackBlocking(); - return null; - } - - @Override - protected void onPostExecute(Void result) { - onFinished(mUris); - } - } - - private class PickFinishTask extends AsyncTask<Void, Void, Void> { - private final Uri mUri; - - public PickFinishTask(Uri uri) { - mUri = uri; - } - - @Override - protected Void doInBackground(Void... params) { - saveStackBlocking(); - return null; - } - - @Override - protected void onPostExecute(Void result) { - onFinished(mUri); - } - } - - private void dumpStack() { - Log.d(TAG, "Current stack: "); - Log.d(TAG, " * " + mState.stack.root); - for (DocumentInfo doc : mState.stack) { - Log.d(TAG, " +-- " + doc); - } - } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java index 7ea51b9..e899379 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java @@ -75,7 +75,7 @@ public class PickFragment extends Fragment { private View.OnClickListener mPickListener = new View.OnClickListener() { @Override public void onClick(View v) { - final BaseActivity activity = BaseActivity.get(PickFragment.this); + final DocumentsActivity activity = DocumentsActivity.get(PickFragment.this); activity.onPickRequested(mPickTarget); } }; diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java index 26aecc5..e11d7d9 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java @@ -109,8 +109,9 @@ public class RecentsCreateFragment extends Fragment { mAdapter.swapStacks(data); // When launched into empty recents, show drawer - if (mAdapter.isEmpty() && !state.stackTouched) { - ((BaseActivity) context).setRootsDrawerOpen(true); + if (mAdapter.isEmpty() && !state.stackTouched && + context instanceof DocumentsActivity) { + ((DocumentsActivity) context).setRootsDrawerOpen(true); } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java index ed5e123..fd67a77 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java @@ -174,11 +174,12 @@ public class RootsFragment extends Fragment { private OnItemClickListener mItemListener = new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - final BaseActivity activity = BaseActivity.get(RootsFragment.this); - final Item item = mAdapter.getItem(position); + Item item = mAdapter.getItem(position); if (item instanceof RootItem) { - activity.onRootPicked(((RootItem) item).root, true); + BaseActivity activity = BaseActivity.get(RootsFragment.this); + activity.onRootPicked(((RootItem) item).root); } else if (item instanceof AppItem) { + DocumentsActivity activity = DocumentsActivity.get(RootsFragment.this); activity.onAppPicked(((AppItem) item).info); } else { throw new IllegalStateException("Unknown root: " + item); diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java index a13fccc..ce98db2 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java @@ -113,7 +113,7 @@ public class SaveFragment extends Fragment { private View.OnClickListener mSaveListener = new View.OnClickListener() { @Override public void onClick(View v) { - final BaseActivity activity = BaseActivity.get(SaveFragment.this); + final DocumentsActivity activity = DocumentsActivity.get(SaveFragment.this); if (mReplaceTarget != null) { activity.onSaveRequested(mReplaceTarget); } else { diff --git a/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java b/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java index 976f21d..f89b182 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java @@ -16,50 +16,29 @@ package com.android.documentsui; - import static com.android.documentsui.DirectoryFragment.ANIM_DOWN; import static com.android.documentsui.DirectoryFragment.ANIM_NONE; -import static com.android.documentsui.DirectoryFragment.ANIM_SIDE; import static com.android.documentsui.DirectoryFragment.ANIM_UP; import android.app.Activity; -import android.app.Fragment; import android.app.FragmentManager; import android.content.ActivityNotFoundException; import android.content.ClipData; -import android.content.ComponentName; -import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; -import android.content.pm.ResolveInfo; -import android.content.res.Resources; -import android.database.Cursor; import android.graphics.Point; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; -import android.os.Debug; import android.provider.DocumentsContract; -import android.support.v4.app.ActionBarDrawerToggle; -import android.support.v4.widget.DrawerLayout; -import android.support.v4.widget.DrawerLayout.DrawerListener; +import android.provider.DocumentsContract.Root; import android.util.Log; -import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; -import android.view.MenuItem.OnActionExpandListener; import android.view.View; -import android.view.ViewGroup; import android.view.WindowManager; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; import android.widget.BaseAdapter; -import android.widget.ImageView; -import android.widget.SearchView; -import android.widget.SearchView.OnQueryTextListener; import android.widget.Spinner; -import android.widget.TextView; import android.widget.Toast; import android.widget.Toolbar; @@ -70,55 +49,37 @@ import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.DurableUtils; import com.android.documentsui.model.RootInfo; -import libcore.io.IoUtils; - -import java.io.FileNotFoundException; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.List; -import java.util.concurrent.Executor; +/** + * Activity providing a directly launchable file management activity. + */ public class StandaloneActivity extends BaseActivity { public static final String TAG = "StandaloneFileManagement"; - private static final String EXTRA_STATE = "state"; - - private static final int CODE_FORWARD = 42; - - private SearchView mSearchView; - private Toolbar mToolbar; private Spinner mToolbarStack; - private Toolbar mRootsToolbar; - - private ActionBarDrawerToggle mDrawerToggle; - private DirectoryContainerView mDirectoryContainer; - - private boolean mIgnoreNextNavigation; - private boolean mIgnoreNextClose; - private boolean mIgnoreNextCollapse; - - private boolean mSearchExpanded; - - private RootsCache mRoots; + private SearchManager mSearchManager; private State mState; + private ItemSelectedListener mStackListener; + private BaseAdapter mStackAdapter; + + public StandaloneActivity() { + super(TAG); + } @Override public void onCreate(Bundle icicle) { - // Debug.waitForDebugger(); super.onCreate(icicle); - mRoots = DocumentsApplication.getRootsCache(this); - setResult(Activity.RESULT_CANCELED); setContentView(R.layout.activity); final Context context = this; - final Resources res = getResources(); // Strongly define our horizontal dimension; we leave vertical as final WindowManager.LayoutParams a = getWindow().getAttributes(); @@ -131,16 +92,17 @@ public class StandaloneActivity extends BaseActivity { mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory); - if (icicle != null) { - mState = icicle.getParcelable(EXTRA_STATE); - } else { - buildDefaultState(); - } + mState = (icicle != null) + ? icicle.<State>getParcelable(EXTRA_STATE) + : buildDefaultState(); + mSearchManager = new SearchManager(); mToolbar = (Toolbar) findViewById(R.id.toolbar); mToolbar.setTitleTextAppearance(context, android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title); + mStackAdapter = new StackAdapter(); + mStackListener = new ItemSelectedListener(); mToolbarStack = (Spinner) findViewById(R.id.stack); mToolbarStack.setOnItemSelectedListener(mStackListener); @@ -167,87 +129,33 @@ public class StandaloneActivity extends BaseActivity { } } - private void buildDefaultState() { - mState = new State(); + private State buildDefaultState() { + State state = new State(); final Intent intent = getIntent(); - mState.action = State.ACTION_BROWSE_ALL; - mState.acceptMimes = new String[] { "*/*" }; - mState.allowMultiple = true; - mState.acceptMimes = new String[] { intent.getType() }; - mState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false); - mState.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false); - mState.showAdvanced = mState.forceAdvanced + state.action = State.ACTION_BROWSE_ALL; + state.acceptMimes = new String[] { "*/*" }; + state.allowMultiple = true; + state.acceptMimes = new String[] { intent.getType() }; + state.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false); + state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false); + state.showAdvanced = state.forceAdvanced | LocalPreferences.getDisplayAdvancedDevices(this); - mState.showSize = true; + state.showSize = true; final DocumentStack stack = intent.getParcelableExtra(CopyService.EXTRA_STACK); if (stack != null) - mState.stack = stack; - } - - private class RestoreStackTask extends AsyncTask<Void, Void, Void> { - private volatile boolean mRestoredStack; - private volatile boolean mExternal; - - @Override - protected Void doInBackground(Void... params) { - // Restore last stack for calling package - final String packageName = getCallingPackageMaybeExtra(); - final Cursor cursor = getContentResolver() - .query(RecentsProvider.buildResume(packageName), null, null, null, null); - try { - if (cursor.moveToFirst()) { - mExternal = cursor.getInt(cursor.getColumnIndex(ResumeColumns.EXTERNAL)) != 0; - final byte[] rawStack = cursor.getBlob( - cursor.getColumnIndex(ResumeColumns.STACK)); - DurableUtils.readFromArray(rawStack, mState.stack); - mRestoredStack = true; - } - } catch (IOException e) { - Log.w(TAG, "Failed to resume: " + e); - } finally { - IoUtils.closeQuietly(cursor); - } - - if (mRestoredStack) { - // Update the restored stack to ensure we have freshest data - final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState); - try { - mState.stack.updateRoot(matchingRoots); - mState.stack.updateDocuments(getContentResolver()); - } catch (FileNotFoundException e) { - Log.w(TAG, "Failed to restore stack: " + e); - mState.stack.reset(); - mRestoredStack = false; - } - } - - return null; - } + state.stack = stack; - @Override - protected void onPostExecute(Void result) { - if (isDestroyed()) return; - mState.restored = true; - onCurrentDirectoryChanged(ANIM_NONE); - } + return state; } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); - if (mDrawerToggle != null) { - mDrawerToggle.syncState(); - } updateActionBar(); } @Override - public void setRootsDrawerOpen(boolean open) { - Log.w(TAG, "Trying to change state of roots drawer to > " + (open ? "open" : "closed")); - // throw new UnsupportedOperationException(); - } - public void updateActionBar() { final RootInfo root = getCurrentRoot(); mToolbar.setNavigationIcon( @@ -255,7 +163,7 @@ public class StandaloneActivity extends BaseActivity { mToolbar.setNavigationContentDescription(R.string.drawer_open); mToolbar.setNavigationOnClickListener(null); - if (mSearchExpanded) { + if (mSearchManager.isExpanded()) { mToolbar.setTitle(null); mToolbarStack.setVisibility(View.GONE); mToolbarStack.setAdapter(null); @@ -269,7 +177,7 @@ public class StandaloneActivity extends BaseActivity { mToolbarStack.setVisibility(View.VISIBLE); mToolbarStack.setAdapter(mStackAdapter); - mIgnoreNextNavigation = true; + mStackListener.mIgnoreNextNavigation = true; mToolbarStack.setSelection(mStackAdapter.getCount() - 1); } } @@ -277,220 +185,60 @@ public class StandaloneActivity extends BaseActivity { @Override public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); + boolean showMenu = super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.activity, menu); - for (int i = 0; i < menu.size(); i++) { - final MenuItem item = menu.getItem(i); - switch (item.getItemId()) { - case R.id.menu_advanced: - case R.id.menu_file_size: - break; - default: - item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - } - } + expandMenus(menu); - final MenuItem searchMenu = menu.findItem(R.id.menu_search); - mSearchView = (SearchView) searchMenu.getActionView(); - mSearchView.setOnQueryTextListener(new OnQueryTextListener() { - @Override - public boolean onQueryTextSubmit(String query) { - mSearchExpanded = true; - mState.currentSearch = query; - mSearchView.clearFocus(); - onCurrentDirectoryChanged(ANIM_NONE); - return true; - } - - @Override - public boolean onQueryTextChange(String newText) { - return false; - } - }); - - searchMenu.setOnActionExpandListener(new OnActionExpandListener() { - @Override - public boolean onMenuItemActionExpand(MenuItem item) { - mSearchExpanded = true; - updateActionBar(); - return true; - } - - @Override - public boolean onMenuItemActionCollapse(MenuItem item) { - mSearchExpanded = false; - if (mIgnoreNextCollapse) { - mIgnoreNextCollapse = false; - return true; - } - - mState.currentSearch = null; - onCurrentDirectoryChanged(ANIM_NONE); - return true; - } - }); - - mSearchView.setOnCloseListener(new SearchView.OnCloseListener() { - @Override - public boolean onClose() { - mSearchExpanded = false; - if (mIgnoreNextClose) { - mIgnoreNextClose = false; - return false; - } - - mState.currentSearch = null; - onCurrentDirectoryChanged(ANIM_NONE); - return false; - } - }); + this.mSearchManager.install(menu.findItem(R.id.menu_search)); - return true; + return showMenu; } @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); - final FragmentManager fm = getFragmentManager(); - final RootInfo root = getCurrentRoot(); final DocumentInfo cwd = getCurrentDirectory(); final MenuItem createDir = menu.findItem(R.id.menu_create_dir); - final MenuItem search = menu.findItem(R.id.menu_search); final MenuItem sort = menu.findItem(R.id.menu_sort); final MenuItem sortSize = menu.findItem(R.id.menu_sort_size); final MenuItem grid = menu.findItem(R.id.menu_grid); final MenuItem list = menu.findItem(R.id.menu_list); final MenuItem advanced = menu.findItem(R.id.menu_advanced); final MenuItem fileSize = menu.findItem(R.id.menu_file_size); + final MenuItem settings = menu.findItem(R.id.menu_settings); - sort.setVisible(cwd != null); grid.setVisible(mState.derivedMode != State.MODE_GRID); list.setVisible(mState.derivedMode != State.MODE_LIST); - if (mState.currentSearch != null) { - // Search uses backend ranking; no sorting - sort.setVisible(false); - - search.expandActionView(); - - mSearchView.setIconified(false); - mSearchView.clearFocus(); - mSearchView.setQuery(mState.currentSearch, false); - } else { - mIgnoreNextClose = true; - mSearchView.setIconified(true); - mSearchView.clearFocus(); - - mIgnoreNextCollapse = true; - search.collapseActionView(); - } + mSearchManager.update(root); + sort.setVisible(cwd != null && !mSearchManager.isSearching()); // Only sort by size when visible sortSize.setVisible(mState.showSize); - fileSize.setVisible(true); - search.setVisible(true); - createDir.setVisible(true); - advanced.setVisible(true); + createDir.setVisible(cwd != null + && cwd.isCreateSupported() + && !mSearchManager.isSearching() + && !root.isDownloads()); + + fileSize.setVisible(cwd != null); + advanced.setVisible(cwd != null); advanced.setTitle(LocalPreferences.getDisplayAdvancedDevices(this) ? R.string.menu_advanced_hide : R.string.menu_advanced_show); fileSize.setTitle(LocalPreferences.getDisplayFileSize(this) ? R.string.menu_file_size_hide : R.string.menu_file_size_show); + settings.setVisible((root.flags & Root.FLAG_HAS_SETTINGS) != 0); return true; } @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (mDrawerToggle != null && mDrawerToggle.onOptionsItemSelected(item)) { - return true; - } - - final int id = item.getItemId(); - if (id == android.R.id.home) { - onBackPressed(); - return true; - } else if (id == R.id.menu_create_dir) { - CreateDirectoryFragment.show(getFragmentManager()); - return true; - } else if (id == R.id.menu_search) { - return false; - } else if (id == R.id.menu_sort_name) { - setUserSortOrder(State.SORT_ORDER_DISPLAY_NAME); - return true; - } else if (id == R.id.menu_sort_date) { - setUserSortOrder(State.SORT_ORDER_LAST_MODIFIED); - return true; - } else if (id == R.id.menu_sort_size) { - setUserSortOrder(State.SORT_ORDER_SIZE); - return true; - } else if (id == R.id.menu_grid) { - setUserMode(State.MODE_GRID); - return true; - } else if (id == R.id.menu_list) { - setUserMode(State.MODE_LIST); - return true; - } else if (id == R.id.menu_advanced) { - setDisplayAdvancedDevices(!LocalPreferences.getDisplayAdvancedDevices(this)); - return true; - } else if (id == R.id.menu_file_size) { - setDisplayFileSize(!LocalPreferences.getDisplayFileSize(this)); - return true; - } else { - return super.onOptionsItemSelected(item); - } - } - - private void setDisplayAdvancedDevices(boolean display) { - LocalPreferences.setDisplayAdvancedDevices(this, display); - mState.showAdvanced = mState.forceAdvanced | display; - RootsFragment.get(getFragmentManager()).onDisplayStateChanged(); - invalidateOptionsMenu(); - } - - private void setDisplayFileSize(boolean display) { - LocalPreferences.setDisplayFileSize(this, display); - mState.showSize = display; - DirectoryFragment.get(getFragmentManager()).onDisplayStateChanged(); - invalidateOptionsMenu(); - } - - @Override - public void onStateChanged() { - invalidateOptionsMenu(); - } - - /** - * Set state sort order based on explicit user action. - */ - private void setUserSortOrder(int sortOrder) { - mState.userSortOrder = sortOrder; - DirectoryFragment.get(getFragmentManager()).onUserSortOrderChanged(); - } - - /** - * Set state mode based on explicit user action. - */ - private void setUserMode(int mode) { - mState.userMode = mode; - DirectoryFragment.get(getFragmentManager()).onUserModeChanged(); - } - - @Override - public void setPending(boolean pending) { - final SaveFragment save = SaveFragment.get(getFragmentManager()); - if (save != null) { - save.setPending(pending); - } - } - - @Override public void onBackPressed() { if (!mState.stackTouched) { super.onBackPressed(); @@ -507,130 +255,12 @@ public class StandaloneActivity extends BaseActivity { } @Override - protected void onSaveInstanceState(Bundle state) { - super.onSaveInstanceState(state); - state.putParcelable(EXTRA_STATE, mState); - } - - @Override - protected void onRestoreInstanceState(Bundle state) { - super.onRestoreInstanceState(state); - } - - private BaseAdapter mStackAdapter = new BaseAdapter() { - @Override - public int getCount() { - return mState.stack.size(); - } - - @Override - public DocumentInfo getItem(int position) { - return mState.stack.get(mState.stack.size() - position - 1); - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.item_subdir_title, parent, false); - } - - final TextView title = (TextView) convertView.findViewById(android.R.id.title); - final DocumentInfo doc = getItem(position); - - if (position == 0) { - final RootInfo root = getCurrentRoot(); - title.setText(root.title); - } else { - title.setText(doc.displayName); - } - - return convertView; - } - - @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.item_subdir, parent, false); - } - - final ImageView subdir = (ImageView) convertView.findViewById(R.id.subdir); - final TextView title = (TextView) convertView.findViewById(android.R.id.title); - final DocumentInfo doc = getItem(position); - - if (position == 0) { - final RootInfo root = getCurrentRoot(); - title.setText(root.title); - subdir.setVisibility(View.GONE); - } else { - title.setText(doc.displayName); - subdir.setVisibility(View.VISIBLE); - } - - return convertView; - } - }; - - private OnItemSelectedListener mStackListener = new OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - if (mIgnoreNextNavigation) { - mIgnoreNextNavigation = false; - return; - } - - while (mState.stack.size() > position + 1) { - mState.stackTouched = true; - mState.stack.pop(); - } - onCurrentDirectoryChanged(ANIM_UP); - } - - @Override - public void onNothingSelected(AdapterView<?> parent) { - // Ignored - } - }; - - @Override - public RootInfo getCurrentRoot() { - if (mState.stack.root != null) { - return mState.stack.root; - } else { - return mRoots.getRecentsRoot(); - } - } - - public DocumentInfo getCurrentDirectory() { - return mState.stack.peek(); - } - - private String getCallingPackageMaybeExtra() { - final String extra = getIntent().getStringExtra(DocumentsContract.EXTRA_PACKAGE_NAME); - return (extra != null) ? extra : getCallingPackage(); - } - - public Executor getCurrentExecutor() { - final DocumentInfo cwd = getCurrentDirectory(); - if (cwd != null && cwd.authority != null) { - return ProviderExecutor.forAuthority(cwd.authority); - } else { - return AsyncTask.THREAD_POOL_EXECUTOR; - } - } - - @Override public State getDisplayState() { return mState; } - private void onCurrentDirectoryChanged(int anim) { + @Override + void onDirectoryChanged(int anim) { final FragmentManager fm = getFragmentManager(); final RootInfo root = getCurrentRoot(); final DocumentInfo cwd = getCurrentDirectory(); @@ -654,109 +284,10 @@ public class StandaloneActivity extends BaseActivity { DirectoryFragment.showNormal(fm, root, cwd, anim); } } - - final RootsFragment roots = RootsFragment.get(fm); - if (roots != null) { - roots.onCurrentRootChanged(); - } - - updateActionBar(); - invalidateOptionsMenu(); - dumpStack(); - } - - @Override - public void onStackPicked(DocumentStack stack) { - try { - // Update the restored stack to ensure we have freshest data - stack.updateDocuments(getContentResolver()); - - mState.stack = stack; - mState.stackTouched = true; - onCurrentDirectoryChanged(ANIM_SIDE); - - } catch (FileNotFoundException e) { - Log.w(TAG, "Failed to restore stack: " + e); - } - } - - @Override - public void onRootPicked(RootInfo root, boolean closeDrawer) { - // Clear entire backstack and start in new root - mState.stack.root = root; - mState.stack.clear(); - mState.stackTouched = true; - - if (!mRoots.isRecentsRoot(root)) { - new PickRootTask(root).executeOnExecutor(getCurrentExecutor()); - } else { - onCurrentDirectoryChanged(ANIM_SIDE); - } - } - - private class PickRootTask extends AsyncTask<Void, Void, DocumentInfo> { - private RootInfo mRoot; - - public PickRootTask(RootInfo root) { - mRoot = root; - } - - @Override - protected DocumentInfo doInBackground(Void... params) { - try { - final Uri uri = DocumentsContract.buildDocumentUri( - mRoot.authority, mRoot.documentId); - return DocumentInfo.fromUri(getContentResolver(), uri); - } catch (FileNotFoundException e) { - Log.w(TAG, "Failed to find root", e); - return null; - } - } - - @Override - protected void onPostExecute(DocumentInfo result) { - if (result != null) { - mState.stack.push(result); - mState.stackTouched = true; - onCurrentDirectoryChanged(ANIM_SIDE); - } - } - } - - @Override - public void onAppPicked(ResolveInfo info) { - final Intent intent = new Intent(getIntent()); - intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT); - intent.setComponent(new ComponentName( - info.activityInfo.applicationInfo.packageName, info.activityInfo.name)); - startActivityForResult(intent, CODE_FORWARD); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - Log.d(TAG, "onActivityResult() code=" + resultCode); - - // Only relay back results when not canceled; otherwise stick around to - // let the user pick another app/backend. - if (requestCode == CODE_FORWARD && resultCode != RESULT_CANCELED) { - - // Remember that we last picked via external app - final String packageName = getCallingPackageMaybeExtra(); - final ContentValues values = new ContentValues(); - values.put(ResumeColumns.EXTERNAL, 1); - getContentResolver().insert(RecentsProvider.buildResume(packageName), values); - - // Pass back result to original caller - setResult(resultCode, data); - finish(); - } else { - super.onActivityResult(requestCode, resultCode, data); - } } @Override public void onDocumentPicked(DocumentInfo doc) { - final FragmentManager fm = getFragmentManager(); if (doc.isDirectory()) { mState.stack.push(doc); mState.stackTouched = true; @@ -780,27 +311,12 @@ public class StandaloneActivity extends BaseActivity { } @Override - public void onSaveRequested(DocumentInfo replaceTarget) { - new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor()); - } - - @Override - public void onSaveRequested(String mimeType, String displayName) { - new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor()); - } - - @Override - public void onPickRequested(DocumentInfo pickTarget) { - final Uri viaUri = DocumentsContract.buildTreeDocumentUri(pickTarget.authority, - pickTarget.documentId); - new PickFinishTask(viaUri).executeOnExecutor(getCurrentExecutor()); - } - - private void saveStackBlocking() { + void saveStackBlocking() { final ContentResolver resolver = getContentResolver(); final ContentValues values = new ContentValues(); - final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack); + final byte[] rawStack = DurableUtils.writeToArrayOrNull( + getDisplayState().stack); // Remember location for next app launch final String packageName = getCallingPackageMaybeExtra(); @@ -810,7 +326,8 @@ public class StandaloneActivity extends BaseActivity { resolver.insert(RecentsProvider.buildResume(packageName), values); } - private void onFinished(Uri... uris) { + @Override + void onTaskFinished(Uri... uris) { Log.d(TAG, "onFinished() " + Arrays.toString(uris)); final Intent intent = new Intent(); @@ -832,106 +349,4 @@ public class StandaloneActivity extends BaseActivity { setResult(Activity.RESULT_OK, intent); finish(); } - - private class CreateFinishTask extends AsyncTask<Void, Void, Uri> { - private final String mMimeType; - private final String mDisplayName; - - public CreateFinishTask(String mimeType, String displayName) { - mMimeType = mimeType; - mDisplayName = displayName; - } - - @Override - protected void onPreExecute() { - setPending(true); - } - - @Override - protected Uri doInBackground(Void... params) { - final ContentResolver resolver = getContentResolver(); - final DocumentInfo cwd = getCurrentDirectory(); - - ContentProviderClient client = null; - Uri childUri = null; - try { - client = DocumentsApplication.acquireUnstableProviderOrThrow( - resolver, cwd.derivedUri.getAuthority()); - childUri = DocumentsContract.createDocument( - client, cwd.derivedUri, mMimeType, mDisplayName); - } catch (Exception e) { - Log.w(TAG, "Failed to create document", e); - } finally { - ContentProviderClient.releaseQuietly(client); - } - - if (childUri != null) { - saveStackBlocking(); - } - - return childUri; - } - - @Override - protected void onPostExecute(Uri result) { - if (result != null) { - onFinished(result); - } else { - Toast.makeText(StandaloneActivity.this, R.string.save_error, Toast.LENGTH_SHORT) - .show(); - } - - setPending(false); - } - } - - private class ExistingFinishTask extends AsyncTask<Void, Void, Void> { - private final Uri[] mUris; - - public ExistingFinishTask(Uri... uris) { - mUris = uris; - } - - @Override - protected Void doInBackground(Void... params) { - saveStackBlocking(); - return null; - } - - @Override - protected void onPostExecute(Void result) { - onFinished(mUris); - } - } - - private class PickFinishTask extends AsyncTask<Void, Void, Void> { - private final Uri mUri; - - public PickFinishTask(Uri uri) { - mUri = uri; - } - - @Override - protected Void doInBackground(Void... params) { - saveStackBlocking(); - return null; - } - - @Override - protected void onPostExecute(Void result) { - onFinished(mUri); - } - } - - private void dumpStack() { - Log.d(TAG, "Current stack: "); - Log.d(TAG, " * " + mState.stack.root); - for (DocumentInfo doc : mState.stack) { - Log.d(TAG, " +-- " + doc); - } - } - - public static BaseActivity get(Fragment fragment) { - return (BaseActivity) fragment.getActivity(); - } } |