Loading src/com/android/documentsui/base/DocumentStack.java +45 −20 Original line number Diff line number Diff line Loading @@ -19,11 +19,15 @@ package com.android.documentsui.base; import static com.android.documentsui.base.Shared.DEBUG; import android.content.ContentResolver; import android.database.Cursor; import android.os.Parcel; import android.os.Parcelable; import android.provider.DocumentsProvider; import android.util.Log; import com.android.documentsui.picker.LastAccessedProvider; import com.android.documentsui.roots.RootsAccess; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileNotFoundException; Loading Loading @@ -171,26 +175,6 @@ public class DocumentStack implements Durable, Parcelable { return mRoot != null && mRoot.isRecents(); } public void updateRoot(Collection<RootInfo> matchingRoots) throws FileNotFoundException { for (RootInfo root : matchingRoots) { if (root.equals(this.mRoot)) { this.mRoot = root; return; } } throw new FileNotFoundException("Failed to find matching mRoot for " + mRoot); } /** * Update a possibly stale restored stack against a live * {@link DocumentsProvider}. */ public void updateDocuments(ContentResolver resolver) throws FileNotFoundException { for (DocumentInfo info : mList) { info.updateSelf(resolver); } } /** * Resets this stack to the given stack. It takes the reference of {@link #mList} and * {@link #mRoot} instead of making a copy. Loading Loading @@ -218,6 +202,47 @@ public class DocumentStack implements Durable, Parcelable { mRoot = null; } private void updateRoot(Collection<RootInfo> matchingRoots) throws FileNotFoundException { for (RootInfo root : matchingRoots) { // RootInfo's equals() only checks authority and rootId, so this will update RootInfo if // its flag has changed. if (root.equals(this.mRoot)) { this.mRoot = root; return; } } throw new FileNotFoundException("Failed to find matching mRoot for " + mRoot); } /** * Update a possibly stale restored stack against a live * {@link DocumentsProvider}. */ private void updateDocuments(ContentResolver resolver) throws FileNotFoundException { for (DocumentInfo info : mList) { info.updateSelf(resolver); } } public static @Nullable DocumentStack fromLastAccessedCursor( Cursor cursor, Collection<RootInfo> matchingRoots, ContentResolver resolver) throws IOException { if (cursor.moveToFirst()) { DocumentStack stack = new DocumentStack(); final byte[] rawStack = cursor.getBlob( cursor.getColumnIndex(LastAccessedProvider.Columns.STACK)); DurableUtils.readFromArray(rawStack, stack); stack.updateRoot(matchingRoots); stack.updateDocuments(resolver); return stack; } return null; } @Override public void read(DataInputStream in) throws IOException { final int version = in.readInt(); Loading src/com/android/documentsui/picker/ActionHandler.java +20 −4 Original line number Diff line number Diff line Loading @@ -136,19 +136,35 @@ class ActionHandler<T extends Activity & Addons> extends AbstractActionHandler<T private void loadLastAccessedStack() { if (DEBUG) Log.d(TAG, "Attempting to load last used stack for calling package."); new LoadLastAccessedStackTask<>(mActivity, mState, mRoots, this::onLoadedLastAccessedStack) new LoadLastAccessedStackTask<>(mActivity, mState, mRoots, this::onLastAccessedStackLoaded) .execute(); } @VisibleForTesting void onLoadedLastAccessedStack(@Nullable DocumentStack stack) { void onLastAccessedStackLoaded(@Nullable DocumentStack stack) { if (stack == null) { mState.stack.changeRoot(mRoots.getRecentsRoot()); loadDefaultLocation(); } else { mState.stack.reset(stack); mActivity.refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE); } } private void loadDefaultLocation() { switch (mState.action) { case State.ACTION_PICK_COPY_DESTINATION: case State.ACTION_CREATE: loadHomeDir(); break; case State.ACTION_GET_CONTENT: case State.ACTION_OPEN: case State.ACTION_OPEN_TREE: mState.stack.changeRoot(mRoots.getRecentsRoot()); mActivity.refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE); break; default: throw new UnsupportedOperationException("Unexpected action type: " + mState.action); } } @Override Loading src/com/android/documentsui/picker/LoadLastAccessedStackTask.java +2 −22 Original line number Diff line number Diff line Loading @@ -67,39 +67,19 @@ final class LoadLastAccessedStackTask<T extends Activity & CommonAddons> @Override protected DocumentStack run(Void... params) { DocumentStack stack = null; String callingPackage = Shared.getCallingPackageName(mOwner); Uri resumeUri = LastAccessedProvider.buildLastAccessed( callingPackage); Cursor cursor = mOwner.getContentResolver().query(resumeUri, null, null, null, null); try { if (cursor.moveToFirst()) { stack = new DocumentStack(); final byte[] rawStack = cursor.getBlob( cursor.getColumnIndex(Columns.STACK)); DurableUtils.readFromArray(rawStack, stack); } return DocumentStack.fromLastAccessedCursor( cursor, mRoots.getMatchingRootsBlocking(mState), mOwner.getContentResolver()); } catch (IOException e) { Log.w(TAG, "Failed to resume: ", e); } finally { IoUtils.closeQuietly(cursor); } if (stack != null) { // Update the restored stack to ensure we have freshest data final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState); try { stack.updateRoot(matchingRoots); stack.updateDocuments(mOwner.getContentResolver()); return stack; } catch (FileNotFoundException e) { Log.w(TAG, "Failed to restore stack for package: " + callingPackage, e); } } return null; } Loading src/com/android/documentsui/picker/PickActivity.java +9 −14 Original line number Diff line number Diff line Loading @@ -282,10 +282,6 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { final DocumentInfo cwd = getCurrentDirectory(); if (mState.stack.isRecents()) { if (mState.action == ACTION_CREATE || mState.action == ACTION_PICK_COPY_DESTINATION) { mInjector.actions.loadRoot(Shared.getDefaultRootUri(this)); } else { DirectoryFragment.showRecentsOpen(fm, anim); // In recents we pick layout mode based on the mimetype, Loading @@ -295,7 +291,6 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { boolean visualMimes = MimeTypes.mimeMatches( MimeTypes.VISUAL_MIMES, mState.acceptMimes); mState.derivedMode = visualMimes ? State.MODE_GRID : State.MODE_LIST; } } else { // Normal boring directory DirectoryFragment.showDirectory(fm, root, cwd, anim); Loading tests/unit/com/android/documentsui/picker/ActionHandlerTest.java +44 −12 Original line number Diff line number Diff line Loading @@ -16,9 +16,6 @@ package com.android.documentsui.picker; import static com.android.documentsui.base.State.ACTION_GET_CONTENT; import static com.android.documentsui.base.State.ACTION_PICK_COPY_DESTINATION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; Loading @@ -28,13 +25,12 @@ import android.provider.DocumentsContract; import android.provider.DocumentsContract.Path; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; import android.test.mock.MockContentProvider; import com.android.documentsui.R; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.Shared; import com.android.documentsui.base.State; import com.android.documentsui.base.State.ActionType; import com.android.documentsui.testing.DocumentStackAsserts; import com.android.documentsui.testing.TestEnv; import com.android.documentsui.testing.TestRootsAccess; Loading @@ -45,7 +41,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.Arrays; import java.util.List; @RunWith(AndroidJUnit4.class) @MediumTest Loading Loading @@ -124,13 +119,30 @@ public class ActionHandlerTest { } @Test public void testOnLoadedLastAccessStackCallback_defaultToRecents() throws Exception { mActivity.refreshCurrentRootAndDirectory.assertNotCalled(); public void testOnLastAccessedStackLoaded_defaultToRecents_getContent() throws Exception { testOnLastAccessedStackLoaded_defaultToRecentsOnAction(State.ACTION_GET_CONTENT); } mHandler.onLoadedLastAccessedStack(null); @Test public void testOnLastAccessedStackLoaded_defaultToRecents_open() throws Exception { testOnLastAccessedStackLoaded_defaultToRecentsOnAction(State.ACTION_OPEN); } assertEquals(TestRootsAccess.RECENTS, mEnv.state.stack.getRoot()); mActivity.refreshCurrentRootAndDirectory.assertCalled(); @Test public void testOnLastAccessedStackLoaded_defaultToRecents_openTree() throws Exception { testOnLastAccessedStackLoaded_defaultToRecentsOnAction(State.ACTION_OPEN_TREE); } @Test public void testOnLastAccessedStackLoaded_DefaultsToDownloads_create() throws Exception { testOnLastAccessedStackLoaded_defaultToDownloadsOnAction(State.ACTION_CREATE); } @Test public void testOnLastAccessedStackLoaded_DefaultsToDownloads_pickCopyDestination() throws Exception { testOnLastAccessedStackLoaded_defaultToDownloadsOnAction( State.ACTION_PICK_COPY_DESTINATION); } @Test Loading @@ -142,6 +154,26 @@ public class ActionHandlerTest { mActivity.refreshCurrentRootAndDirectory.assertCalled(); } private void testOnLastAccessedStackLoaded_defaultToRecentsOnAction(@ActionType int action) { mEnv.state.action = action; mActivity.refreshCurrentRootAndDirectory.assertNotCalled(); mHandler.onLastAccessedStackLoaded(null); assertEquals(TestRootsAccess.RECENTS, mEnv.state.stack.getRoot()); mActivity.refreshCurrentRootAndDirectory.assertCalled(); } private void testOnLastAccessedStackLoaded_defaultToDownloadsOnAction(@ActionType int action) throws Exception { mEnv.state.action = action; mActivity.refreshCurrentRootAndDirectory.assertNotCalled(); mHandler.onLastAccessedStackLoaded(null); assertRootPicked(TestRootsAccess.DOWNLOADS.getUri()); } private void assertRootPicked(Uri expectedUri) throws Exception { mEnv.beforeAsserts(); Loading Loading
src/com/android/documentsui/base/DocumentStack.java +45 −20 Original line number Diff line number Diff line Loading @@ -19,11 +19,15 @@ package com.android.documentsui.base; import static com.android.documentsui.base.Shared.DEBUG; import android.content.ContentResolver; import android.database.Cursor; import android.os.Parcel; import android.os.Parcelable; import android.provider.DocumentsProvider; import android.util.Log; import com.android.documentsui.picker.LastAccessedProvider; import com.android.documentsui.roots.RootsAccess; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileNotFoundException; Loading Loading @@ -171,26 +175,6 @@ public class DocumentStack implements Durable, Parcelable { return mRoot != null && mRoot.isRecents(); } public void updateRoot(Collection<RootInfo> matchingRoots) throws FileNotFoundException { for (RootInfo root : matchingRoots) { if (root.equals(this.mRoot)) { this.mRoot = root; return; } } throw new FileNotFoundException("Failed to find matching mRoot for " + mRoot); } /** * Update a possibly stale restored stack against a live * {@link DocumentsProvider}. */ public void updateDocuments(ContentResolver resolver) throws FileNotFoundException { for (DocumentInfo info : mList) { info.updateSelf(resolver); } } /** * Resets this stack to the given stack. It takes the reference of {@link #mList} and * {@link #mRoot} instead of making a copy. Loading Loading @@ -218,6 +202,47 @@ public class DocumentStack implements Durable, Parcelable { mRoot = null; } private void updateRoot(Collection<RootInfo> matchingRoots) throws FileNotFoundException { for (RootInfo root : matchingRoots) { // RootInfo's equals() only checks authority and rootId, so this will update RootInfo if // its flag has changed. if (root.equals(this.mRoot)) { this.mRoot = root; return; } } throw new FileNotFoundException("Failed to find matching mRoot for " + mRoot); } /** * Update a possibly stale restored stack against a live * {@link DocumentsProvider}. */ private void updateDocuments(ContentResolver resolver) throws FileNotFoundException { for (DocumentInfo info : mList) { info.updateSelf(resolver); } } public static @Nullable DocumentStack fromLastAccessedCursor( Cursor cursor, Collection<RootInfo> matchingRoots, ContentResolver resolver) throws IOException { if (cursor.moveToFirst()) { DocumentStack stack = new DocumentStack(); final byte[] rawStack = cursor.getBlob( cursor.getColumnIndex(LastAccessedProvider.Columns.STACK)); DurableUtils.readFromArray(rawStack, stack); stack.updateRoot(matchingRoots); stack.updateDocuments(resolver); return stack; } return null; } @Override public void read(DataInputStream in) throws IOException { final int version = in.readInt(); Loading
src/com/android/documentsui/picker/ActionHandler.java +20 −4 Original line number Diff line number Diff line Loading @@ -136,19 +136,35 @@ class ActionHandler<T extends Activity & Addons> extends AbstractActionHandler<T private void loadLastAccessedStack() { if (DEBUG) Log.d(TAG, "Attempting to load last used stack for calling package."); new LoadLastAccessedStackTask<>(mActivity, mState, mRoots, this::onLoadedLastAccessedStack) new LoadLastAccessedStackTask<>(mActivity, mState, mRoots, this::onLastAccessedStackLoaded) .execute(); } @VisibleForTesting void onLoadedLastAccessedStack(@Nullable DocumentStack stack) { void onLastAccessedStackLoaded(@Nullable DocumentStack stack) { if (stack == null) { mState.stack.changeRoot(mRoots.getRecentsRoot()); loadDefaultLocation(); } else { mState.stack.reset(stack); mActivity.refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE); } } private void loadDefaultLocation() { switch (mState.action) { case State.ACTION_PICK_COPY_DESTINATION: case State.ACTION_CREATE: loadHomeDir(); break; case State.ACTION_GET_CONTENT: case State.ACTION_OPEN: case State.ACTION_OPEN_TREE: mState.stack.changeRoot(mRoots.getRecentsRoot()); mActivity.refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE); break; default: throw new UnsupportedOperationException("Unexpected action type: " + mState.action); } } @Override Loading
src/com/android/documentsui/picker/LoadLastAccessedStackTask.java +2 −22 Original line number Diff line number Diff line Loading @@ -67,39 +67,19 @@ final class LoadLastAccessedStackTask<T extends Activity & CommonAddons> @Override protected DocumentStack run(Void... params) { DocumentStack stack = null; String callingPackage = Shared.getCallingPackageName(mOwner); Uri resumeUri = LastAccessedProvider.buildLastAccessed( callingPackage); Cursor cursor = mOwner.getContentResolver().query(resumeUri, null, null, null, null); try { if (cursor.moveToFirst()) { stack = new DocumentStack(); final byte[] rawStack = cursor.getBlob( cursor.getColumnIndex(Columns.STACK)); DurableUtils.readFromArray(rawStack, stack); } return DocumentStack.fromLastAccessedCursor( cursor, mRoots.getMatchingRootsBlocking(mState), mOwner.getContentResolver()); } catch (IOException e) { Log.w(TAG, "Failed to resume: ", e); } finally { IoUtils.closeQuietly(cursor); } if (stack != null) { // Update the restored stack to ensure we have freshest data final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState); try { stack.updateRoot(matchingRoots); stack.updateDocuments(mOwner.getContentResolver()); return stack; } catch (FileNotFoundException e) { Log.w(TAG, "Failed to restore stack for package: " + callingPackage, e); } } return null; } Loading
src/com/android/documentsui/picker/PickActivity.java +9 −14 Original line number Diff line number Diff line Loading @@ -282,10 +282,6 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { final DocumentInfo cwd = getCurrentDirectory(); if (mState.stack.isRecents()) { if (mState.action == ACTION_CREATE || mState.action == ACTION_PICK_COPY_DESTINATION) { mInjector.actions.loadRoot(Shared.getDefaultRootUri(this)); } else { DirectoryFragment.showRecentsOpen(fm, anim); // In recents we pick layout mode based on the mimetype, Loading @@ -295,7 +291,6 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { boolean visualMimes = MimeTypes.mimeMatches( MimeTypes.VISUAL_MIMES, mState.acceptMimes); mState.derivedMode = visualMimes ? State.MODE_GRID : State.MODE_LIST; } } else { // Normal boring directory DirectoryFragment.showDirectory(fm, root, cwd, anim); Loading
tests/unit/com/android/documentsui/picker/ActionHandlerTest.java +44 −12 Original line number Diff line number Diff line Loading @@ -16,9 +16,6 @@ package com.android.documentsui.picker; import static com.android.documentsui.base.State.ACTION_GET_CONTENT; import static com.android.documentsui.base.State.ACTION_PICK_COPY_DESTINATION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; Loading @@ -28,13 +25,12 @@ import android.provider.DocumentsContract; import android.provider.DocumentsContract.Path; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; import android.test.mock.MockContentProvider; import com.android.documentsui.R; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.Shared; import com.android.documentsui.base.State; import com.android.documentsui.base.State.ActionType; import com.android.documentsui.testing.DocumentStackAsserts; import com.android.documentsui.testing.TestEnv; import com.android.documentsui.testing.TestRootsAccess; Loading @@ -45,7 +41,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.Arrays; import java.util.List; @RunWith(AndroidJUnit4.class) @MediumTest Loading Loading @@ -124,13 +119,30 @@ public class ActionHandlerTest { } @Test public void testOnLoadedLastAccessStackCallback_defaultToRecents() throws Exception { mActivity.refreshCurrentRootAndDirectory.assertNotCalled(); public void testOnLastAccessedStackLoaded_defaultToRecents_getContent() throws Exception { testOnLastAccessedStackLoaded_defaultToRecentsOnAction(State.ACTION_GET_CONTENT); } mHandler.onLoadedLastAccessedStack(null); @Test public void testOnLastAccessedStackLoaded_defaultToRecents_open() throws Exception { testOnLastAccessedStackLoaded_defaultToRecentsOnAction(State.ACTION_OPEN); } assertEquals(TestRootsAccess.RECENTS, mEnv.state.stack.getRoot()); mActivity.refreshCurrentRootAndDirectory.assertCalled(); @Test public void testOnLastAccessedStackLoaded_defaultToRecents_openTree() throws Exception { testOnLastAccessedStackLoaded_defaultToRecentsOnAction(State.ACTION_OPEN_TREE); } @Test public void testOnLastAccessedStackLoaded_DefaultsToDownloads_create() throws Exception { testOnLastAccessedStackLoaded_defaultToDownloadsOnAction(State.ACTION_CREATE); } @Test public void testOnLastAccessedStackLoaded_DefaultsToDownloads_pickCopyDestination() throws Exception { testOnLastAccessedStackLoaded_defaultToDownloadsOnAction( State.ACTION_PICK_COPY_DESTINATION); } @Test Loading @@ -142,6 +154,26 @@ public class ActionHandlerTest { mActivity.refreshCurrentRootAndDirectory.assertCalled(); } private void testOnLastAccessedStackLoaded_defaultToRecentsOnAction(@ActionType int action) { mEnv.state.action = action; mActivity.refreshCurrentRootAndDirectory.assertNotCalled(); mHandler.onLastAccessedStackLoaded(null); assertEquals(TestRootsAccess.RECENTS, mEnv.state.stack.getRoot()); mActivity.refreshCurrentRootAndDirectory.assertCalled(); } private void testOnLastAccessedStackLoaded_defaultToDownloadsOnAction(@ActionType int action) throws Exception { mEnv.state.action = action; mActivity.refreshCurrentRootAndDirectory.assertNotCalled(); mHandler.onLastAccessedStackLoaded(null); assertRootPicked(TestRootsAccess.DOWNLOADS.getUri()); } private void assertRootPicked(Uri expectedUri) throws Exception { mEnv.beforeAsserts(); Loading