Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cfd4c79b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Crash fix for accessing DocumentInfo.derivedUri when in Recents." into nyc-andromeda-dev

parents c9f23f04 e9abd2d4
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ import com.android.documentsui.sidebar.EjectRootTask;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;

/**
 * Provides support for specializing the actions (viewDocument etc.) to the host activity.
@@ -58,6 +59,7 @@ public abstract class AbstractActionHandler<T extends Activity & CommonAddons>
        implements ActionHandler {

    private static final String TAG = "AbstractActionHandler";
    private static final int REFRESH_SPINNER_TIMEOUT = 500;

    protected final T mActivity;
    protected final State mState;
@@ -106,6 +108,14 @@ public abstract class AbstractActionHandler<T extends Activity & CommonAddons>
                listener).executeOnExecutor(ProviderExecutor.forAuthority(root.authority));
    }

    @Override
    public void refreshDocument(DocumentInfo doc, BooleanConsumer callback) {
        RefreshTask task = new RefreshTask(mState, doc, REFRESH_SPINNER_TIMEOUT,
                mActivity.getApplicationContext(), mActivity::isDestroyed,
                callback);
        task.executeOnExecutor(mExecutors.lookup(doc == null ? null : doc.authority));
    }

    @Override
    public void openSelectedInNewWindow() {
        throw new UnsupportedOperationException("Can't open in new window.");
+6 −0
Original line number Diff line number Diff line
@@ -42,6 +42,12 @@ public interface ActionHandler {
     */
    void ejectRoot(RootInfo root, BooleanConsumer listener);

    /**
     * Attempts to refresh the given DocumentInfo, which should be at the top of the state stack.
     * Returns a boolean answer to the callback, given by {@link ContentProvider#refresh}.
     */
    void refreshDocument(DocumentInfo doc, BooleanConsumer callback);

    void showAppDetails(ResolveInfo info);

    void openRoot(RootInfo root);
+19 −14
Original line number Diff line number Diff line
@@ -29,12 +29,12 @@ import android.os.CancellationSignal;
import android.util.Log;

import com.android.documentsui.base.ApplicationScope;
import com.android.documentsui.base.BooleanConsumer;
import com.android.documentsui.base.CheckedTask;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.Shared;
import com.android.documentsui.base.State;

import java.util.function.Consumer;

/**
 * A {@link CheckedTask} that calls
 * {@link ContentResolver#refresh(Uri, android.os.Bundle, android.os.CancellationSignal)} on the
@@ -46,14 +46,14 @@ public class RefreshTask extends TimeoutTask<Void, Boolean> {

    private final @ApplicationScope Context mContext;
    private final State mState;
    private final Uri mUri;
    private final Consumer<Boolean> mCallback;
    private final DocumentInfo mDoc;
    private final BooleanConsumer mCallback;
    private final CancellationSignal mSignal;

    public RefreshTask(State state, Uri uri, long timeout, @ApplicationScope Context context, Check check,
            Consumer<Boolean> callback) {
    public RefreshTask(State state, DocumentInfo doc, long timeout,
            @ApplicationScope Context context, Check check, BooleanConsumer callback) {
        super(check);
        mUri = uri;
        mDoc = doc;
        mContext = context;
        mState = state;
        mCallback = callback;
@@ -63,13 +63,18 @@ public class RefreshTask extends TimeoutTask<Void, Boolean> {

    @Override
    public @Nullable Boolean run(Void... params) {
        if (mUri == null) {
            Log.w(TAG, "Attempted to refresh on a null uri. Aborting.");
        if (mDoc == null) {
            Log.w(TAG, "Ignoring attempt to refresh due to null DocumentInfo.");
            return false;
        }

        if (mState.stack.isEmpty()) {
            Log.w(TAG, "Ignoring attempt to refresh due to empty stack.");
            return false;
        }

        if (mUri != mState.stack.peek().derivedUri) {
            Log.w(TAG, "Attempted to refresh on a non-top-level uri. Aborting.");
        if (!mDoc.derivedUri.equals(mState.stack.peek().derivedUri)) {
            Log.w(TAG, "Ignoring attempt to refresh on a non-top-level uri.");
            return false;
        }

@@ -78,17 +83,17 @@ public class RefreshTask extends TimeoutTask<Void, Boolean> {
        // and we will update accordingly. Else, we just tell the callback that Refresh is not
        // supported.
        if (!Shared.ENABLE_OMC_API_FEATURES) {
            Log.w(TAG, "Attempted to call Refresh on an older Android platform. Aborting.");
            Log.w(TAG, "Ignoring attempt to call Refresh on an older Android platform.");
            return false;
        }

        final ContentResolver resolver = mContext.getContentResolver();
        final String authority = mUri.getAuthority();
        final String authority = mDoc.authority;
        boolean refreshSupported = false;
        ContentProviderClient client = null;
        try {
            client = DocumentsApplication.acquireUnstableProviderOrThrow(resolver, authority);
            refreshSupported = client.refresh(mUri, null, mSignal);
            refreshSupported = client.refresh(mDoc.derivedUri, null, mSignal);
        } catch (Exception e) {
            Log.w(TAG, "Failed to refresh", e);
        } finally {
+4 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.documentsui;
import android.annotation.CallSuper;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;

import com.android.documentsui.base.CheckedTask;
import com.android.documentsui.base.DocumentInfo;
@@ -48,7 +49,9 @@ public abstract class TimeoutTask<Input, Output> extends CheckedTask<Input, Outp
            return;
        }

        Handler handler = new Handler();
        // Need to initialize handler to main Looper so it can initialize correctly in test cases
        // Instrumentation threads don't have looper initialized
        Handler handler = new Handler(Looper.getMainLooper());
        handler.postDelayed(() -> {
            if (getStatus() == AsyncTask.Status.RUNNING) {
                onTimeout();
+9 −12
Original line number Diff line number Diff line
@@ -1145,10 +1145,8 @@ public class DirectoryFragment extends Fragment
            cache.removeUri(mModel.getItemUri(ids[i]));
        }

        final Uri uri = mState.stack.peek().derivedUri;
        RefreshTask task = new RefreshTask(mState, uri, REFRESH_SPINNER_TIMEOUT,
                getContext().getApplicationContext(), this::isDetached,
                (Boolean refreshSupported) -> {
        final DocumentInfo doc = mState.stack.peek();
        mActions.refreshDocument(doc, (boolean refreshSupported) -> {
            if (refreshSupported) {
                mRefreshLayout.setRefreshing(false);
            } else {
@@ -1156,7 +1154,6 @@ public class DirectoryFragment extends Fragment
                getLoaderManager().restartLoader(LOADER_ID, null, mLoaderCallbacks);
            }
        });
        task.executeOnExecutor(mActivity.getExecutorForCurrentDirectory());
    }

    private final class ModelUpdateListener implements EventListener<Model.Update> {
Loading