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

Commit 5c24368d authored by Garfield Tan's avatar Garfield Tan Committed by android-build-merger
Browse files

Fix crash when dragging documents from Recents.

am: 2e81db6f

Change-Id: I4a5b8f4171b8debb35dbaf067a212e2b4f1dad64
parents 9973a055 2e81db6f
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -500,7 +500,8 @@ public abstract class AbstractActionHandler<T extends Activity & CommonAddons>
            if (mState.stack.isRecents()) {

                if (DEBUG) Log.d(TAG, "Creating new loader recents.");
                return new RecentsLoader(context, mProviders, mState, mInjector.features);
                return new RecentsLoader(
                        context, mProviders, mState, mInjector.features, mExecutors);

            } else {

+15 −11
Original line number Diff line number Diff line
@@ -67,19 +67,19 @@ public interface DragAndDropManager {
     * @param v the view which
     *          {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)} will be
     *          called.
     * @param parent {@link DocumentInfo} of the container of srcs
     * @param srcs documents that are dragged
     * @param root the root in which documents being dragged are
     * @param invalidDest destinations that don't accept this drag and drop
     * @param iconHelper used to load document icons
     * @param parent {@link DocumentInfo} of the container of srcs
     */
    void startDrag(
            View v,
            DocumentInfo parent,
            List<DocumentInfo> srcs,
            RootInfo root,
            List<Uri> invalidDest,
            IconHelper iconHelper);
            IconHelper iconHelper,
            @Nullable DocumentInfo parent);

    /**
     * Checks whether the document can be spring opened.
@@ -167,10 +167,6 @@ public interface DragAndDropManager {
        // type of file operations.
        private boolean mIsCtrlPressed;

        // Boolean flag for current drag and drop operation. Returns true if the files can only
        // be copied (ie. Read-Only files)
        private boolean mMustBeCopied;

        // Drag events info. These are used to derive state and update drag shadow when user changes
        // Ctrl key state.
        private View mView;
@@ -179,6 +175,10 @@ public interface DragAndDropManager {
        private RootInfo mDestRoot;
        private DocumentInfo mDestDoc;

        // Boolean flag for current drag and drop operation. Returns true if the files can only
        // be copied (ie. files that don't support delete or remove).
        private boolean mMustBeCopied;

        private RuntimeDragAndDropManager(Context context, DocumentClipper clipper) {
            this(
                    context.getApplicationContext(),
@@ -223,11 +223,11 @@ public interface DragAndDropManager {
        @Override
        public void startDrag(
                View v,
                DocumentInfo parent,
                List<DocumentInfo> srcs,
                RootInfo root,
                List<Uri> invalidDest,
                IconHelper iconHelper) {
                IconHelper iconHelper,
                @Nullable DocumentInfo parent) {

            mView = v;
            mInvalidDest = invalidDest;
@@ -235,11 +235,15 @@ public interface DragAndDropManager {
            List<Uri> uris = new ArrayList<>(srcs.size());
            for (DocumentInfo doc : srcs) {
                uris.add(doc.derivedUri);
                if (!doc.isRemoveSupported() && !doc.isDeleteSupported()) {
                if (!doc.isRemoveSupported()
                        && !doc.isDeleteSupported()
                        && !doc.isMoveSupported()) {
                    mMustBeCopied = true;
                }
            }
            mClipData = mClipper.getClipDataForDocuments(
            mClipData = (parent == null)
                    ? mClipper.getClipDataForDocuments(uris, FileOperationService.OPERATION_UNKNOWN)
                    : mClipper.getClipDataForDocuments(
                            uris, FileOperationService.OPERATION_UNKNOWN, parent);
            mClipData.getDescription().getExtras()
                    .putString(SRC_ROOT_KEY, root.getUri().toString());
+31 −5
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.AsyncTaskLoader;
import android.content.ContentProviderClient;
import android.content.Context;
import android.database.Cursor;
import android.database.CursorWrapper;
import android.database.MatrixCursor;
import android.database.MergeCursor;
import android.net.Uri;
@@ -35,6 +36,7 @@ import android.util.Log;

import com.android.documentsui.base.Features;
import com.android.documentsui.base.FilteringCursorWrapper;
import com.android.documentsui.base.Lookup;
import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.State;
import com.android.documentsui.roots.ProvidersAccess;
@@ -54,6 +56,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

@@ -84,6 +87,7 @@ public class RecentsLoader extends AsyncTaskLoader<DirectoryResult> {
    private final ProvidersAccess mProviders;
    private final State mState;
    private final Features mFeatures;
    private final Lookup<String, Executor> mExecutors;

    @GuardedBy("mTasks")
    /** A authority -> RecentsTask map */
@@ -94,11 +98,14 @@ public class RecentsLoader extends AsyncTaskLoader<DirectoryResult> {

    private DirectoryResult mResult;

    public RecentsLoader(Context context, ProvidersAccess providers, State state, Features features) {
    public RecentsLoader(Context context, ProvidersAccess providers, State state, Features features,
            Lookup<String, Executor> executors) {

        super(context);
        mProviders = providers;
        mState = state;
        mFeatures = features;
        mExecutors = executors;

        // Keep clients around on high-RAM devices, since we'd be spinning them
        // up moments later to fetch thumbnails anyway.
@@ -127,7 +134,7 @@ public class RecentsLoader extends AsyncTaskLoader<DirectoryResult> {

            mFirstPassLatch = new CountDownLatch(mTasks.size());
            for (RecentsTask task : mTasks.values()) {
                ProviderExecutor.forAuthority(task.authority).execute(task);
                mExecutors.lookup(task.authority).execute(task);
            }

            try {
@@ -196,7 +203,8 @@ public class RecentsLoader extends AsyncTaskLoader<DirectoryResult> {
            merged = new MatrixCursor(new String[0]);
        }

        final Cursor sorted = mState.sortModel.sortCursor(merged);
        final Cursor notMovableMasked = new NotMovableMaskCursor(merged);
        final Cursor sorted = mState.sortModel.sortCursor(notMovableMasked);

        // Tell the UI if this is an in-progress result. When loading is complete, another update is
        // sent with EXTRA_LOADING set to false.
@@ -292,7 +300,7 @@ public class RecentsLoader extends AsyncTaskLoader<DirectoryResult> {
    // TODO: create better transfer of ownership around cursor to ensure its
    // closed in all edge cases.

    public class RecentsTask extends AbstractFuture<Cursor[]> implements Runnable, Closeable {
    private class RecentsTask extends AbstractFuture<Cursor[]> implements Runnable, Closeable {
        public final String authority;
        public final List<String> rootIds;

@@ -321,7 +329,7 @@ public class RecentsLoader extends AsyncTaskLoader<DirectoryResult> {
            }
        }

        public synchronized void runInternal() {
        private synchronized void runInternal() {
            if (mIsClosed) {
                return;
            }
@@ -379,4 +387,22 @@ public class RecentsLoader extends AsyncTaskLoader<DirectoryResult> {
            mIsClosed = true;
        }
    }

    private static class NotMovableMaskCursor extends CursorWrapper {
        private static final int NOT_MOVABLE_MASK =
                ~(Document.FLAG_SUPPORTS_DELETE
                        | Document.FLAG_SUPPORTS_REMOVE
                        | Document.FLAG_SUPPORTS_MOVE);

        private NotMovableMaskCursor(Cursor cursor) {
            super(cursor);
        }

        @Override
        public int getInt(int index) {
            final int flagIndex = getWrappedCursor().getColumnIndex(Document.COLUMN_FLAGS);
            final int value = super.getInt(index);
            return (index == flagIndex) ? (value & NOT_MOVABLE_MASK) : value;
        }
    }
}
+5 −2
Original line number Diff line number Diff line
@@ -32,6 +32,10 @@ import java.util.function.Predicate;
 */
public final class DocumentFilters {

    private static int MOVABLE_MASK = Document.FLAG_SUPPORTS_REMOVE
            | Document.FLAG_SUPPORTS_DELETE
            | Document.FLAG_SUPPORTS_MOVE;

    public static final Predicate<Cursor> ANY = (Cursor c) -> { return true; };
    public static final Predicate<Cursor> VIRTUAL  = DocumentFilters::isVirtual;
    public static final Predicate<Cursor> NOT_MOVABLE = DocumentFilters::isNotMovable;
@@ -77,7 +81,6 @@ public final class DocumentFilters {
     */
    private static final boolean isNotMovable(Cursor c) {
        int flags = getCursorInt(c, Document.COLUMN_FLAGS);
        return (flags & Document.FLAG_SUPPORTS_REMOVE) == 0
                && (flags & Document.FLAG_SUPPORTS_DELETE) == 0;
        return (flags & MOVABLE_MASK) == 0;
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -247,6 +247,10 @@ public class DocumentInfo implements Durable, Parcelable {
        return (flags & Document.FLAG_SUPPORTS_REMOVE) != 0;
    }

    public boolean isMoveSupported() {
        return (flags & Document.FLAG_SUPPORTS_MOVE) != 0;
    }

    public boolean isRenameSupported() {
        return (flags & Document.FLAG_SUPPORTS_RENAME) != 0;
    }
Loading