Initialize the location to recents if we fail to restore stack.

Bug: 36083419
Change-Id: I8da79eb9dd50d69c828472aae725e286d5e1e8a0
(cherry picked from commit bab25161824d80657b11ba6db6e9f0ecfc72dfbc)
diff --git a/src/com/android/documentsui/base/State.java b/src/com/android/documentsui/base/State.java
index b8ccbb6..d50dbdb 100644
--- a/src/com/android/documentsui/base/State.java
+++ b/src/com/android/documentsui/base/State.java
@@ -80,10 +80,6 @@
     public boolean localOnly;
     public boolean showDeviceStorageOption;
     public boolean showAdvanced;
-    /*
-     * Indicates handler was an external app, like photos.
-     */
-    public boolean external;
 
     // Indicates that a copy operation (or move) includes a directory.
     // Why? Directory creation isn't supported by some roots (like Downloads).
@@ -130,7 +126,6 @@
         out.writeInt(localOnly ? 1 : 0);
         out.writeInt(showDeviceStorageOption ? 1 : 0);
         out.writeInt(showAdvanced ? 1 : 0);
-        out.writeInt(external ? 1 : 0);
         DurableUtils.writeToParcel(out, stack);
         out.writeMap(dirConfigs);
         out.writeList(excludedAuthorities);
@@ -153,7 +148,6 @@
             state.localOnly = in.readInt() != 0;
             state.showDeviceStorageOption = in.readInt() != 0;
             state.showAdvanced = in.readInt() != 0;
-            state.external = in.readInt() != 0;
             DurableUtils.readFromParcel(in, state.stack);
             in.readMap(state.dirConfigs, loader);
             in.readList(state.excludedAuthorities, loader);
diff --git a/src/com/android/documentsui/picker/ActionHandler.java b/src/com/android/documentsui/picker/ActionHandler.java
index 444ae67..553cee7 100644
--- a/src/com/android/documentsui/picker/ActionHandler.java
+++ b/src/com/android/documentsui/picker/ActionHandler.java
@@ -38,11 +38,13 @@
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.base.Shared;
 import com.android.documentsui.base.State;
+import com.android.documentsui.dirlist.AnimationView;
 import com.android.documentsui.dirlist.DocumentDetails;
 import com.android.documentsui.Model;
 import com.android.documentsui.picker.ActionHandler.Addons;
 import com.android.documentsui.queries.SearchViewManager;
 import com.android.documentsui.roots.RootsAccess;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.concurrent.Executor;
 
@@ -134,7 +136,19 @@
 
     private void loadLastAccessedStack() {
         if (DEBUG) Log.d(TAG, "Attempting to load last used stack for calling package.");
-        new LoadLastAccessedStackTask<>(mActivity, mState, mRoots).execute();
+        new LoadLastAccessedStackTask<>(mActivity, mState, mRoots, this::onLoadedLastAccessedStack)
+                .execute();
+    }
+
+    @VisibleForTesting
+    void onLoadedLastAccessedStack(@Nullable DocumentStack stack) {
+        if (stack == null) {
+            mState.stack.changeRoot(mRoots.getRecentsRoot());
+        } else {
+            mState.stack.reset(stack);
+        }
+
+        mActivity.refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE);
     }
 
     @Override
diff --git a/src/com/android/documentsui/picker/LastAccessedProvider.java b/src/com/android/documentsui/picker/LastAccessedProvider.java
index 8428bf8..e911778 100644
--- a/src/com/android/documentsui/picker/LastAccessedProvider.java
+++ b/src/com/android/documentsui/picker/LastAccessedProvider.java
@@ -50,7 +50,6 @@
 public class LastAccessedProvider extends ContentProvider {
     private static final String TAG = "LastAccessedProvider";
 
-
     private static final String AUTHORITY = "com.android.documentsui.lastAccessed";
 
     private static final UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
diff --git a/src/com/android/documentsui/picker/LoadLastAccessedStackTask.java b/src/com/android/documentsui/picker/LoadLastAccessedStackTask.java
index dea7dc4..004bbb4 100644
--- a/src/com/android/documentsui/picker/LoadLastAccessedStackTask.java
+++ b/src/com/android/documentsui/picker/LoadLastAccessedStackTask.java
@@ -24,12 +24,12 @@
 import android.util.Log;
 
 import com.android.documentsui.AbstractActionHandler.CommonAddons;
+import com.android.documentsui.base.DocumentStack;
 import com.android.documentsui.base.DurableUtils;
 import com.android.documentsui.base.PairedTask;
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.base.Shared;
 import com.android.documentsui.base.State;
-import com.android.documentsui.dirlist.AnimationView;
 import com.android.documentsui.picker.LastAccessedProvider.Columns;
 import com.android.documentsui.roots.RootsAccess;
 
@@ -38,6 +38,9 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.Collection;
+import java.util.function.Consumer;
+
+import javax.annotation.Nullable;
 
 /**
  * Loads the last used path (stack) from Recents (history).
@@ -46,54 +49,54 @@
  * for an app like DropBox.
  */
 final class LoadLastAccessedStackTask<T extends Activity & CommonAddons>
-        extends PairedTask<T, Void, Void> {
+        extends PairedTask<T, Void, DocumentStack> {
 
-    private static final String TAG = "LoadLastAccessedStackTask";
-    private volatile boolean mRestoredStack;
-    private volatile boolean mExternal;
+    private static final String TAG = "LoadLastAccessedStackTa";
+
     private final State mState;
-    private RootsAccess mRoots;
+    private final RootsAccess mRoots;
+    private final Consumer<DocumentStack> mCallback;
 
-    public LoadLastAccessedStackTask(T activity, State state, RootsAccess roots) {
+    LoadLastAccessedStackTask(
+            T activity, State state, RootsAccess roots, Consumer<DocumentStack> callback) {
         super(activity);
-        mState = state;
         mRoots = roots;
+        mState = state;
+        mCallback = callback;
     }
 
     @Override
-    protected Void run(Void... params) {
-        if (DEBUG && !mState.stack.isEmpty()) {
-            Log.w(TAG, "Overwriting existing stack.");
-        }
+    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()) {
-                mExternal = cursor.getInt(cursor.getColumnIndex(Columns.EXTERNAL)) != 0;
+                stack = new DocumentStack();
                 final byte[] rawStack = cursor.getBlob(
                         cursor.getColumnIndex(Columns.STACK));
-                DurableUtils.readFromArray(rawStack, mState.stack);
-                mRestoredStack = true;
+                DurableUtils.readFromArray(rawStack, stack);
             }
         } catch (IOException e) {
-            Log.w(TAG, "Failed to resume: " + e);
+            Log.w(TAG, "Failed to resume: ", e);
         } finally {
             IoUtils.closeQuietly(cursor);
         }
 
-        if (mRestoredStack) {
+        if (stack != null) {
             // 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(mOwner.getContentResolver());
+
+                stack.updateRoot(matchingRoots);
+                stack.updateDocuments(mOwner.getContentResolver());
+                return stack;
+
             } catch (FileNotFoundException e) {
-                Log.w(TAG, "Failed to restore stack for package: " + callingPackage
-                        + " because of error: "+ e);
-                mState.stack.reset();
-                mRestoredStack = false;
+                Log.w(TAG, "Failed to restore stack for package: " + callingPackage, e);
             }
         }
 
@@ -101,8 +104,7 @@
     }
 
     @Override
-    protected void finish(Void result) {
-        mState.external = mExternal;
-        mOwner.refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE);
+    protected void finish(@Nullable DocumentStack stack) {
+        mCallback.accept(stack);
     }
 }
diff --git a/src/com/android/documentsui/roots/RootsAccess.java b/src/com/android/documentsui/roots/RootsAccess.java
index 9ddca70..9ea51ab 100644
--- a/src/com/android/documentsui/roots/RootsAccess.java
+++ b/src/com/android/documentsui/roots/RootsAccess.java
@@ -50,6 +50,8 @@
 
     RootInfo getDefaultRootBlocking(State state);
 
+    RootInfo getRecentsRoot();
+
     /**
      * Returns a list of roots for the specified authority. If not found, then
      * an empty list is returned.
diff --git a/src/com/android/documentsui/roots/RootsCache.java b/src/com/android/documentsui/roots/RootsCache.java
index 111a42d..ed29413 100644
--- a/src/com/android/documentsui/roots/RootsCache.java
+++ b/src/com/android/documentsui/roots/RootsCache.java
@@ -322,6 +322,7 @@
         return null;
     }
 
+    @Override
     public RootInfo getRecentsRoot() {
         return mRecentsRoot;
     }
diff --git a/tests/common/com/android/documentsui/testing/TestRootsAccess.java b/tests/common/com/android/documentsui/testing/TestRootsAccess.java
index 45a30c7..6175cd3 100644
--- a/tests/common/com/android/documentsui/testing/TestRootsAccess.java
+++ b/tests/common/com/android/documentsui/testing/TestRootsAccess.java
@@ -125,4 +125,9 @@
     public RootInfo getDefaultRootBlocking(State state) {
         return DOWNLOADS;
     }
+
+    @Override
+    public RootInfo getRecentsRoot() {
+        return RECENTS;
+    }
 }
diff --git a/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java b/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java
index a5bef37..3d5f64b 100644
--- a/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java
+++ b/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java
@@ -28,6 +28,7 @@
 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;
@@ -123,6 +124,16 @@
     }
 
     @Test
+    public void testOnLoadedLastAccessStackCallback_defaultToRecents() throws Exception {
+        mActivity.refreshCurrentRootAndDirectory.assertNotCalled();
+
+        mHandler.onLoadedLastAccessedStack(null);
+
+        assertEquals(TestRootsAccess.RECENTS, mEnv.state.stack.getRoot());
+        mActivity.refreshCurrentRootAndDirectory.assertCalled();
+    }
+
+    @Test
     public void testOpenContainerDocument() {
         mHandler.openContainerDocument(TestEnv.FOLDER_0);