diff options
6 files changed, 309 insertions, 196 deletions
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java index e72343e9a9ba..2eaf76f5ebec 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java @@ -45,22 +45,16 @@ import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.Spinner; -import android.widget.Toolbar; -import com.android.documentsui.RecentsProvider.ResumeColumns; import com.android.documentsui.SearchManager.SearchManagerListener; import com.android.documentsui.State.ViewMode; import com.android.documentsui.dirlist.DirectoryFragment; 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 com.android.internal.util.Preconditions; -import libcore.io.IoUtils; - import java.io.FileNotFoundException; -import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -87,8 +81,8 @@ public abstract class BaseActivity extends Activity abstract void onTaskFinished(Uri... uris); abstract void refreshDirectory(int anim); - abstract void saveStackBlocking(); - abstract State buildState(); + /** Allows sub-classes to include information in a newly created State instance. */ + abstract void includeState(State initialState); public BaseActivity(@LayoutRes int layoutId, String tag) { mLayoutId = layoutId; @@ -103,9 +97,7 @@ public abstract class BaseActivity extends Activity setContentView(mLayoutId); mDrawer = DrawerController.create(this); - mState = (icicle != null) - ? icicle.<State>getParcelable(EXTRA_STATE) - : buildState(); + mState = getState(icicle); Metrics.logActivityLaunch(this, mState, getIntent()); mRoots = DocumentsApplication.getRootsCache(this); @@ -114,7 +106,8 @@ public abstract class BaseActivity extends Activity new RootsCache.OnCacheUpdateListener() { @Override public void onCacheUpdate() { - new HandleRootsChangedTask().execute(getCurrentRoot()); + new HandleRootsChangedTask(BaseActivity.this) + .execute(getCurrentRoot()); } }); @@ -184,7 +177,20 @@ public abstract class BaseActivity extends Activity super.onDestroy(); } - State buildDefaultState() { + private State getState(@Nullable Bundle icicle) { + if (icicle != null) { + State state = icicle.<State>getParcelable(EXTRA_STATE); + if (DEBUG) Log.d(mTag, "Recovered existing state object: " + state); + return state; + } + + State state = createSharedState(); + includeState(state); + if (DEBUG) Log.d(mTag, "Created new state object: " + state); + return state; + } + + private State createSharedState() { State state = new State(); final Intent intent = getIntent(); @@ -224,7 +230,7 @@ public abstract class BaseActivity extends Activity if (mRoots.isRecentsRoot(root)) { refreshCurrentRootAndDirectory(ANIM_NONE); } else { - new PickRootTask(root).executeOnExecutor(getExecutorForCurrentDirectory()); + new PickRootTask(this, root).executeOnExecutor(getExecutorForCurrentDirectory()); } } @@ -574,115 +580,40 @@ public abstract class BaseActivity extends Activity } } - final class PickRootTask extends AsyncTask<Void, Void, DocumentInfo> { + private static final class PickRootTask extends PairedTask<BaseActivity, Void, DocumentInfo> { private RootInfo mRoot; - public PickRootTask(RootInfo root) { + public PickRootTask(BaseActivity activity, RootInfo root) { + super(activity); mRoot = root; } @Override - protected DocumentInfo doInBackground(Void... params) { - return getRootDocumentBlocking(mRoot); - } - - @Override - protected void onPostExecute(DocumentInfo result) { - if (result != null && !isDestroyed()) { - openContainerDocument(result); - } + protected DocumentInfo run(Void... params) { + return mOwner.getRootDocumentBlocking(mRoot); } - } - - final class RestoreStackTask extends AsyncTask<Void, Void, Void> { - private volatile boolean mRestoredStack; - private volatile boolean mExternal; @Override - protected Void doInBackground(Void... params) { - if (DEBUG && !mState.stack.isEmpty()) { - Log.w(mTag, "Overwriting existing stack."); - } - 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, mState.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(mState); - try { - mState.stack.updateRoot(matchingRoots); - mState.stack.updateDocuments(getContentResolver()); - } catch (FileNotFoundException e) { - Log.w(mTag, "Failed to restore stack: " + e); - mState.stack.reset(); - mRestoredStack = false; - } + protected void finish(DocumentInfo result) { + if (result != null) { + mOwner.openContainerDocument(result); } - - return null; - } - - @Override - protected void onPostExecute(Void result) { - if (isDestroyed()) return; - mState.restored = true; - refreshCurrentRootAndDirectory(ANIM_NONE); - onStackRestored(mRestoredStack, mExternal); } } - final class RestoreRootTask extends AsyncTask<Void, Void, RootInfo> { - private Uri mRootUri; - - public RestoreRootTask(Uri rootUri) { - mRootUri = rootUri; - } - - @Override - protected RootInfo doInBackground(Void... params) { - final String rootId = DocumentsContract.getRootId(mRootUri); - return mRoots.getRootOneshot(mRootUri.getAuthority(), rootId); - } + private static final class HandleRootsChangedTask + extends PairedTask<BaseActivity, RootInfo, RootInfo> { + DocumentInfo mHome; - @Override - protected void onPostExecute(RootInfo root) { - if (isDestroyed()) return; - mState.restored = true; - - if (root != null) { - onRootPicked(root); - } else { - Log.w(mTag, "Failed to find root: " + mRootUri); - finish(); - } + public HandleRootsChangedTask(BaseActivity activity) { + super(activity); } - } - - final class HandleRootsChangedTask extends AsyncTask<RootInfo, Void, RootInfo> { - DocumentInfo mHome; @Override - protected RootInfo doInBackground(RootInfo... roots) { + protected RootInfo run(RootInfo... roots) { checkArgument(roots.length == 1); final RootInfo currentRoot = roots[0]; - final Collection<RootInfo> cachedRoots = mRoots.getRootsBlocking(); + final Collection<RootInfo> cachedRoots = mOwner.mRoots.getRootsBlocking(); RootInfo homeRoot = null; for (final RootInfo root : cachedRoots) { if (root.isHome()) { @@ -694,17 +625,17 @@ public abstract class BaseActivity extends Activity } } Preconditions.checkNotNull(homeRoot); - mHome = getRootDocumentBlocking(homeRoot); + mHome = mOwner.getRootDocumentBlocking(homeRoot); return homeRoot; } @Override - protected void onPostExecute(RootInfo homeRoot) { - if (homeRoot != null && mHome != null && !isDestroyed()) { + protected void finish(RootInfo homeRoot) { + if (homeRoot != null && mHome != null) { // Clear entire backstack and start in new root - mState.onRootChanged(homeRoot); - mSearchManager.update(homeRoot); - openContainerDocument(mHome); + mOwner.mState.onRootChanged(homeRoot); + mOwner.mSearchManager.update(homeRoot); + mOwner.openContainerDocument(mHome); } } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index 815ff3db9517..b33b6007ba7e 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -16,6 +16,7 @@ package com.android.documentsui; +import static com.android.documentsui.Shared.DEBUG; import static com.android.documentsui.State.ACTION_CREATE; import static com.android.documentsui.State.ACTION_GET_CONTENT; import static com.android.documentsui.State.ACTION_OPEN; @@ -31,11 +32,12 @@ 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.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; import android.os.Parcelable; import android.provider.DocumentsContract; @@ -52,7 +54,12 @@ import com.android.documentsui.model.DurableUtils; import com.android.documentsui.model.RootInfo; import com.android.documentsui.services.FileOperationService; +import libcore.io.IoUtils; + +import java.io.FileNotFoundException; +import java.io.IOException; import java.util.Arrays; +import java.util.Collection; import java.util.List; public class DocumentsActivity extends BaseActivity { @@ -94,16 +101,14 @@ public class DocumentsActivity extends BaseActivity { // In this case, we set the activity title in AsyncTask.onPostExecute(). To prevent // talkback from reading aloud the default title, we clear it here. setTitle(""); - new RestoreStackTask().execute(); + new RestoreStackTask(this).execute(); } else { refreshCurrentRootAndDirectory(ANIM_NONE); } } @Override - State buildState() { - State state = buildDefaultState(); - + void includeState(State state) { final Intent intent = getIntent(); final String action = intent.getAction(); if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) { @@ -134,8 +139,6 @@ public class DocumentsActivity extends BaseActivity { state.transferMode = intent.getIntExtra(FileOperationService.EXTRA_OPERATION, FileOperationService.OPERATION_COPY); } - - return state; } @Override @@ -319,11 +322,13 @@ public class DocumentsActivity extends BaseActivity { } void onSaveRequested(DocumentInfo replaceTarget) { - new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory()); + new ExistingFinishTask(this, replaceTarget.derivedUri) + .executeOnExecutor(getExecutorForCurrentDirectory()); } void onSaveRequested(String mimeType, String displayName) { - new CreateFinishTask(mimeType, displayName).executeOnExecutor(getExecutorForCurrentDirectory()); + new CreateFinishTask(this, mimeType, displayName) + .executeOnExecutor(getExecutorForCurrentDirectory()); } @Override @@ -343,7 +348,8 @@ public class DocumentsActivity extends BaseActivity { openContainerDocument(doc); } else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) { // Explicit file picked, return - new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory()); + new ExistingFinishTask(this, doc.derivedUri) + .executeOnExecutor(getExecutorForCurrentDirectory()); } else if (mState.action == ACTION_CREATE) { // Replace selected file SaveFragment.get(fm).setReplaceTarget(doc); @@ -358,7 +364,8 @@ public class DocumentsActivity extends BaseActivity { for (int i = 0; i < size; i++) { uris[i] = docs.get(i).derivedUri; } - new ExistingFinishTask(uris).executeOnExecutor(getExecutorForCurrentDirectory()); + new ExistingFinishTask(this, uris) + .executeOnExecutor(getExecutorForCurrentDirectory()); } } @@ -373,11 +380,10 @@ public class DocumentsActivity extends BaseActivity { // Should not be reached. throw new IllegalStateException("Invalid mState.action."); } - new PickFinishTask(result).executeOnExecutor(getExecutorForCurrentDirectory()); + new PickFinishTask(this, result).executeOnExecutor(getExecutorForCurrentDirectory()); } - @Override - void saveStackBlocking() { + void writeStackToRecentsBlocking() { final ContentResolver resolver = getContentResolver(); final ContentValues values = new ContentValues(); @@ -438,69 +444,138 @@ public class DocumentsActivity extends BaseActivity { finish(); } + public static DocumentsActivity get(Fragment fragment) { return (DocumentsActivity) fragment.getActivity(); } - private final class PickFinishTask extends AsyncTask<Void, Void, Void> { + /** + * Restores the stack from Recents for the specified package. + */ + private static final class RestoreStackTask + extends PairedTask<DocumentsActivity, Void, Void> { + + private volatile boolean mRestoredStack; + private volatile boolean mExternal; + private Context mContext; + private State mState; + + public RestoreStackTask(DocumentsActivity activity) { + super(activity); + mState = activity.mState; + } + + @Override + protected Void run(Void... params) { + if (DEBUG && !mState.stack.isEmpty()) { + Log.w(TAG, "Overwriting existing stack."); + } + RootsCache roots = DocumentsApplication.getRootsCache(mContext); + + String packageName = mOwner.getCallingPackageMaybeExtra(); + Uri resumeUri = RecentsProvider.buildResume(packageName); + Cursor cursor = mOwner.getContentResolver().query(resumeUri, 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 = roots.getMatchingRootsBlocking(mState); + try { + mState.stack.updateRoot(matchingRoots); + mState.stack.updateDocuments(mOwner.getContentResolver()); + } catch (FileNotFoundException e) { + Log.w(TAG, "Failed to restore stack for package: " + packageName + + " because of error: "+ e); + mState.stack.reset(); + mRestoredStack = false; + } + } + + return null; + } + + @Override + protected void finish(Void result) { + mState.restored = true; + mOwner.refreshCurrentRootAndDirectory(ANIM_NONE); + mOwner.onStackRestored(mRestoredStack, mExternal); + } + } + + private static final class PickFinishTask extends PairedTask<DocumentsActivity, Void, Void> { private final Uri mUri; - public PickFinishTask(Uri uri) { + public PickFinishTask(DocumentsActivity activity, Uri uri) { + super(activity); mUri = uri; } @Override - protected Void doInBackground(Void... params) { - saveStackBlocking(); + protected Void run(Void... params) { + mOwner.writeStackToRecentsBlocking(); return null; } @Override - protected void onPostExecute(Void result) { - onTaskFinished(mUri); + protected void finish(Void result) { + mOwner.onTaskFinished(mUri); } } - final class ExistingFinishTask extends AsyncTask<Void, Void, Void> { + private static final class ExistingFinishTask extends PairedTask<DocumentsActivity, Void, Void> { private final Uri[] mUris; - public ExistingFinishTask(Uri... uris) { + public ExistingFinishTask(DocumentsActivity activity, Uri... uris) { + super(activity); mUris = uris; } @Override - protected Void doInBackground(Void... params) { - saveStackBlocking(); + protected Void run(Void... params) { + mOwner.writeStackToRecentsBlocking(); return null; } @Override - protected void onPostExecute(Void result) { - onTaskFinished(mUris); + protected void finish(Void result) { + mOwner.onTaskFinished(mUris); } } /** * Task that creates a new document in the background. */ - final class CreateFinishTask extends AsyncTask<Void, Void, Uri> { + private static final class CreateFinishTask extends PairedTask<DocumentsActivity, Void, Uri> { private final String mMimeType; private final String mDisplayName; - public CreateFinishTask(String mimeType, String displayName) { + public CreateFinishTask(DocumentsActivity activity, String mimeType, String displayName) { + super(activity); mMimeType = mimeType; mDisplayName = displayName; } @Override - protected void onPreExecute() { - setPending(true); + protected void prepare() { + mOwner.setPending(true); } @Override - protected Uri doInBackground(Void... params) { - final ContentResolver resolver = getContentResolver(); - final DocumentInfo cwd = getCurrentDirectory(); + protected Uri run(Void... params) { + final ContentResolver resolver = mOwner.getContentResolver(); + final DocumentInfo cwd = mOwner.getCurrentDirectory(); ContentProviderClient client = null; Uri childUri = null; @@ -516,22 +591,22 @@ public class DocumentsActivity extends BaseActivity { } if (childUri != null) { - saveStackBlocking(); + mOwner.writeStackToRecentsBlocking(); } return childUri; } @Override - protected void onPostExecute(Uri result) { + protected void finish(Uri result) { if (result != null) { - onTaskFinished(result); + mOwner.onTaskFinished(result); } else { Snackbars.makeSnackbar( - DocumentsActivity.this, R.string.save_error, Snackbar.LENGTH_SHORT).show(); + mOwner, R.string.save_error, Snackbar.LENGTH_SHORT).show(); } - setPending(false); + mOwner.setPending(false); } } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java index 89be9107e077..dae4bf7418df 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java @@ -24,8 +24,6 @@ import android.app.Fragment; import android.app.FragmentManager; import android.content.ActivityNotFoundException; import android.content.ClipData; -import android.content.ContentResolver; -import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -37,10 +35,8 @@ import android.view.Menu; import android.view.MenuItem; import android.widget.Toolbar; -import com.android.documentsui.RecentsProvider.ResumeColumns; import com.android.documentsui.dirlist.DirectoryFragment; import com.android.documentsui.model.DocumentInfo; -import com.android.documentsui.model.DurableUtils; import com.android.documentsui.model.RootInfo; import com.android.internal.util.Preconditions; @@ -72,23 +68,19 @@ public class DownloadsActivity extends BaseActivity { // talkback from reading aloud the default title, we clear it here. setTitle(""); final Uri rootUri = getIntent().getData(); - new RestoreRootTask(rootUri).executeOnExecutor(getExecutorForCurrentDirectory()); + new RestoreRootTask(this, rootUri).executeOnExecutor(getExecutorForCurrentDirectory()); } else { refreshCurrentRootAndDirectory(ANIM_NONE); } } @Override - State buildState() { - State state = buildDefaultState(); - + void includeState(State state) { state.action = ACTION_MANAGE; state.acceptMimes = new String[] { "*/*" }; state.allowMultiple = true; state.showSize = true; state.excludedAuthorities = getExcludedAuthorities(); - - return state; } @Override @@ -170,21 +162,6 @@ public class DownloadsActivity extends BaseActivity { public void onDocumentsPicked(List<DocumentInfo> docs) {} @Override - void saveStackBlocking() { - final ContentResolver resolver = getContentResolver(); - final ContentValues values = new ContentValues(); - - final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack); - - // Remember location for next app launch - final String packageName = getCallingPackageMaybeExtra(); - values.clear(); - values.put(ResumeColumns.STACK, rawStack); - values.put(ResumeColumns.EXTERNAL, 0); - resolver.insert(RecentsProvider.buildResume(packageName), values); - } - - @Override void onTaskFinished(Uri... uris) { Log.d(TAG, "onFinished() " + Arrays.toString(uris)); diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java index 3aba356793df..c55f814dfef2 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java @@ -30,7 +30,6 @@ import android.content.ContentResolver; import android.content.ContentValues; import android.content.Intent; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; import android.os.Parcelable; import android.provider.DocumentsContract; @@ -98,19 +97,19 @@ public class FilesActivity extends BaseActivity { refreshCurrentRootAndDirectory(ANIM_NONE); } else if (intent.getAction() == Intent.ACTION_VIEW) { checkArgument(uri != null); - new OpenUriForViewTask().executeOnExecutor( + new OpenUriForViewTask(this).executeOnExecutor( ProviderExecutor.forAuthority(uri.getAuthority()), uri); } else if (DocumentsContract.isRootUri(this, uri)) { if (DEBUG) Log.d(TAG, "Launching with root URI."); // If we've got a specific root to display, restore that root using a dedicated // authority. That way a misbehaving provider won't result in an ANR. - new RestoreRootTask(uri).executeOnExecutor( + new RestoreRootTask(this, uri).executeOnExecutor( ProviderExecutor.forAuthority(uri.getAuthority())); } else { if (DEBUG) Log.d(TAG, "Launching into Home directory."); // If all else fails, try to load "Home" directory. final Uri homeUri = DocumentsContract.buildHomeUri(); - new RestoreRootTask(homeUri).executeOnExecutor( + new RestoreRootTask(this, homeUri).executeOnExecutor( ProviderExecutor.forAuthority(homeUri.getAuthority())); } @@ -134,9 +133,7 @@ public class FilesActivity extends BaseActivity { } @Override - State buildState() { - State state = buildDefaultState(); - + void includeState(State state) { final Intent intent = getIntent(); state.action = State.ACTION_BROWSE; @@ -149,8 +146,6 @@ public class FilesActivity extends BaseActivity { if (stack != null) { state.stack = stack; } - - return state; } @Override @@ -363,13 +358,15 @@ public class FilesActivity extends BaseActivity { } } - @Override - void saveStackBlocking() { + // Turns out only DocumentsActivity was ever calling saveStackBlocking. + // There may be a case where we want to contribute entries from + // Behavior here in FilesActivity, but it isn't yet obvious. + // TODO: Contribute to recents, or remove this. + void writeStackToRecentsBlocking() { final ContentResolver resolver = getContentResolver(); final ContentValues values = new ContentValues(); - final byte[] rawStack = DurableUtils.writeToArrayOrNull( - getDisplayState().stack); + final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack); // Remember location for next app launch final String packageName = getCallingPackageMaybeExtra(); @@ -408,12 +405,19 @@ public class FilesActivity extends BaseActivity { * to know which root to select. Also, the stack doesn't contain intermediate directories. * It's primarly used for opening ZIP archives from Downloads app. */ - final class OpenUriForViewTask extends AsyncTask<Uri, Void, Void> { + private static final class OpenUriForViewTask extends PairedTask<FilesActivity, Uri, Void> { + + private final State mState; + public OpenUriForViewTask(FilesActivity activity) { + super(activity); + mState = activity.mState; + } + @Override - protected Void doInBackground(Uri... params) { + protected Void run(Uri... params) { final Uri uri = params[0]; - final RootsCache rootsCache = DocumentsApplication.getRootsCache(FilesActivity.this); + final RootsCache rootsCache = DocumentsApplication.getRootsCache(mOwner); final String authority = uri.getAuthority(); final Collection<RootInfo> roots = @@ -426,20 +430,17 @@ public class FilesActivity extends BaseActivity { final RootInfo root = roots.iterator().next(); mState.stack.root = root; try { - mState.stack.add(DocumentInfo.fromUri(getContentResolver(), uri)); + mState.stack.add(DocumentInfo.fromUri(mOwner.getContentResolver(), uri)); } catch (FileNotFoundException e) { Log.e(TAG, "Failed to resolve DocumentInfo from Uri: " + uri); } - mState.stack.add(getRootDocumentBlocking(root)); + mState.stack.add(mOwner.getRootDocumentBlocking(root)); return null; } @Override - protected void onPostExecute(Void result) { - if (isDestroyed()) { - return; - } - refreshCurrentRootAndDirectory(ANIM_NONE); + protected void finish(Void result) { + mOwner.refreshCurrentRootAndDirectory(ANIM_NONE); } } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/PairedTask.java b/packages/DocumentsUI/src/com/android/documentsui/PairedTask.java new file mode 100644 index 000000000000..b74acb8e38c3 --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/PairedTask.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.documentsui; + +import android.app.Activity; +import android.os.AsyncTask; + +/** + * An {@link AsyncTask} that guards work with checks that a paired {@link Activity} + * is still alive. Instances of this class make no progress. + * + * <p>Use this type of task for greater safety when executing tasks that might complete + * after an Activity is destroyed. + * + * <p>Also useful as tasks can be static, limiting scope, but still have access to + * the owning class (by way the A template and the mActivity field). + * + * @template Owner Activity type. + * @template Input input type + * @template Output output type + */ +abstract class PairedTask<Owner extends Activity, Input, Output> + extends AsyncTask<Input, Void, Output> { + + protected final Owner mOwner; + + public PairedTask(Owner owner) { + mOwner = owner; + } + + /** Called prior to run being executed. Analogous to {@link AsyncTask#onPreExecute} */ + void prepare() {} + + /** Analogous to {@link AsyncTask#doInBackground} */ + abstract Output run(Input... input); + + /** Analogous to {@link AsyncTask#onPostExecute} */ + abstract void finish(Output output); + + @Override + final protected void onPreExecute() { + if (mOwner.isDestroyed()) { + return; + } + prepare(); + } + + @Override + final protected Output doInBackground(Input... input) { + if (mOwner.isDestroyed()) { + return null; + } + return run(input); + } + + @Override + final protected void onPostExecute(Output result) { + if (mOwner.isDestroyed()) { + return; + } + finish(result); + } +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java b/packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java new file mode 100644 index 000000000000..9048b9d45ee7 --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.documentsui; + +import android.net.Uri; +import android.provider.DocumentsContract; +import android.util.Log; + +import com.android.documentsui.model.RootInfo; + +final class RestoreRootTask extends PairedTask<BaseActivity, Void, RootInfo> { + private static final String TAG = "RestoreRootTask"; + + private final Uri mRootUri; + + public RestoreRootTask(BaseActivity activity, Uri rootUri) { + super(activity); + mRootUri = rootUri; + } + + @Override + protected RootInfo run(Void... params) { + String rootId = DocumentsContract.getRootId(mRootUri); + return mOwner.mRoots.getRootOneshot(mRootUri.getAuthority(), rootId); + } + + @Override + protected void finish(RootInfo root) { + mOwner.mState.restored = true; + + if (root != null) { + mOwner.onRootPicked(root); + } else { + Log.w(TAG, "Failed to find root: " + mRootUri); + mOwner.finish(); + } + } +} |