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

Commit 9fea3122 authored by Ben Lin's avatar Ben Lin
Browse files

Adding blocking to DirectoryLoader when Band Selection is active.

Bug: 29538016
Change-Id: Ib297afaf8b28d030ce10337efc7965717d2fa375
parent 340db018
Loading
Loading
Loading
Loading
+26 −2
Original line number Diff line number Diff line
@@ -20,9 +20,11 @@ import android.content.AsyncTaskLoader;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.OperationCanceledException;
import android.os.RemoteException;
import android.provider.DocumentsContract.Document;
@@ -42,8 +44,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {

    private static final String[] SEARCH_REJECT_MIMES = new String[] { Document.MIME_TYPE_DIR };

    private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();

    private final LockingContentObserver mObserver;
    private final RootInfo mRoot;
    private final Uri mUri;
    private final SortModel mModel;
@@ -59,6 +60,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
            DocumentInfo doc,
            Uri uri,
            SortModel model,
            DirectoryReloadLock lock,
            boolean inSearchMode) {

        super(context, ProviderExecutor.forAuthority(root.authority));
@@ -67,6 +69,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
        mModel = model;
        mDoc = doc;
        mSearchMode = inSearchMode;
        mObserver = new LockingContentObserver(lock, this::onContentChanged);
    }

    @Override
@@ -181,4 +184,25 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {

        getContext().getContentResolver().unregisterContentObserver(mObserver);
    }

    private static final class LockingContentObserver extends ContentObserver {
        private final DirectoryReloadLock mLock;
        private final Runnable mContentChangedCallback;

        public LockingContentObserver(DirectoryReloadLock lock, Runnable contentChangedCallback) {
            super(new Handler());
            mLock = lock;
            mContentChangedCallback = contentChangedCallback;
        }

        @Override
        public boolean deliverSelfNotifications() {
            return true;
        }

        @Override
        public void onChange(boolean selfChange) {
            mLock.tryUpdate(mContentChangedCallback);
        }
    }
}
+67 −0
Original line number Diff line number Diff line
/*
 * 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.annotation.MainThread;
import android.annotation.Nullable;

import com.android.documentsui.base.Shared;
import com.android.documentsui.selection.BandController;

/**
 * A lock used by {@link DirectoryLoader} and {@link BandController} to ensure refresh is blocked
 * while Band Selection is active.
 */
public final class DirectoryReloadLock {
    private int mPauseCount = 0;
    private @Nullable Runnable mCallback;

    /**
     * Increment the block count by 1
     */
    @MainThread
    public void block() {
        Shared.checkMainLoop();
        mPauseCount++;
    }

    /**
     * Decrement the block count by 1; If no other object is trying to block and there exists some
     * callback, that callback will be run
     */
    @MainThread
    public void unblock() {
        Shared.checkMainLoop();
        mPauseCount--;
        if (mPauseCount == 0 && mCallback != null) {
            mCallback.run();
            mCallback = null;
        }
    }

    /**
     * Attempts to run the given Runnable if not-blocked, or else the Runnable is set to be ran next
     * (replacing any previous set Runnables).
     */
    public void tryUpdate(Runnable update) {
        if (mPauseCount == 0) {
            update.run();
        } else {
            mCallback = update;
        }
    }
}
 No newline at end of file
+5 −1
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ import com.android.documentsui.BaseActivity;
import com.android.documentsui.BaseActivity.RetainedState;
import com.android.documentsui.DirectoryLoader;
import com.android.documentsui.DirectoryResult;
import com.android.documentsui.DirectoryReloadLock;
import com.android.documentsui.DocumentsApplication;
import com.android.documentsui.FocusManager;
import com.android.documentsui.ItemDragListener;
@@ -186,6 +187,7 @@ public class DirectoryFragment extends Fragment
    private View mProgressBar;

    private DirectoryState mLocalState;
    private DirectoryReloadLock mReloadLock = new DirectoryReloadLock();

    // Note, we use !null to indicate that selection was restored (from rotation).
    // So don't fiddle with this field unless you've got the bigger picture in mind.
@@ -308,13 +310,14 @@ public class DirectoryFragment extends Fragment
        mSelectionMetadata = new SelectionMetadata(mModel::getItem);
        mSelectionMgr.addItemCallback(mSelectionMetadata);

        GestureSelector gestureSel = GestureSelector.create(mSelectionMgr, mRecView);
        GestureSelector gestureSel = GestureSelector.create(mSelectionMgr, mRecView, mReloadLock);

        if (mState.allowMultiple) {
            mBandController = new BandController(
                    mRecView,
                    mAdapter,
                    mSelectionMgr,
                    mReloadLock,
                    (int pos) -> {
                        // The band selection model only operates on documents and directories.
                        // Exclude other types of adapter items like whitespace and dividers.
@@ -1233,6 +1236,7 @@ public class DirectoryFragment extends Fragment
                            mLocalState.mDocument,
                            contentsUri,
                            mState.sortModel,
                            mReloadLock,
                            mLocalState.mSearchMode);

                case TYPE_RECENT_OPEN:
+8 −1
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.view.View;

import com.android.documentsui.DirectoryReloadLock;
import com.android.documentsui.R;
import com.android.documentsui.base.Events.InputEvent;
import com.android.documentsui.dirlist.DocumentsAdapter;
@@ -61,6 +62,7 @@ public class BandController extends OnScrollListener {
    private final SelectionEnvironment mEnvironment;
    private final DocumentsAdapter mAdapter;
    private final SelectionManager mSelectionManager;
    private final DirectoryReloadLock mLock;
    private final Runnable mViewScroller;
    private final GridModel.OnSelectionChangedListener mGridListener;

@@ -75,16 +77,19 @@ public class BandController extends OnScrollListener {
            final RecyclerView view,
            DocumentsAdapter adapter,
            SelectionManager selectionManager,
            DirectoryReloadLock lock,
            IntPredicate gridItemTester) {
        this(new RuntimeSelectionEnvironment(view), adapter, selectionManager, gridItemTester);
        this(new RuntimeSelectionEnvironment(view), adapter, selectionManager, lock, gridItemTester);
    }

    private BandController(
            SelectionEnvironment env,
            DocumentsAdapter adapter,
            SelectionManager selectionManager,
            DirectoryReloadLock lock,
            IntPredicate gridItemTester) {

        mLock = lock;
        selectionManager.bindContoller(this);

        mEnvironment = env;
@@ -265,6 +270,7 @@ public class BandController extends OnScrollListener {
    private void startBandSelect(Point origin) {
        if (DEBUG) Log.d(TAG, "Starting band select @ " + origin);

        mLock.block();
        mOrigin = origin;
        mModelBuilder.run();  // Creates a new selection model.
        mModel.startSelection(mOrigin);
@@ -314,6 +320,7 @@ public class BandController extends OnScrollListener {

        mModel = null;
        mOrigin = null;
        mLock.unblock();
    }

    private void onSelectionChanged(Set<String> updatedSelection) {
+12 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.support.annotation.VisibleForTesting;
import android.support.v7.widget.RecyclerView;
import android.view.View;

import com.android.documentsui.DirectoryReloadLock;
import com.android.documentsui.base.Events.InputEvent;
import com.android.documentsui.ui.ViewAutoScroller;
import com.android.documentsui.ui.ViewAutoScroller.ScrollActionDelegate;
@@ -40,6 +41,7 @@ public final class GestureSelector {
    private final Runnable mDragScroller;
    private final IntSupplier mHeight;
    private final ViewFinder mViewFinder;
    private final DirectoryReloadLock mLock;
    private int mLastStartedItemPos = -1;
    private boolean mStarted = false;
    private Point mLastInterceptedPoint;
@@ -48,10 +50,12 @@ public final class GestureSelector {
            SelectionManager selectionMgr,
            IntSupplier heightSupplier,
            ViewFinder viewFinder,
            ScrollActionDelegate actionDelegate) {
            ScrollActionDelegate actionDelegate,
            DirectoryReloadLock lock) {
        mSelectionMgr = selectionMgr;
        mHeight = heightSupplier;
        mViewFinder = viewFinder;
        mLock = lock;

        ScrollDistanceDelegate distanceDelegate = new ScrollDistanceDelegate() {
            @Override
@@ -75,7 +79,8 @@ public final class GestureSelector {

    public static GestureSelector create(
            SelectionManager selectionMgr,
            RecyclerView scrollView) {
            RecyclerView scrollView,
            DirectoryReloadLock lock) {
        ScrollActionDelegate actionDelegate = new ScrollActionDelegate() {
            @Override
            public void scrollBy(int dy) {
@@ -97,7 +102,8 @@ public final class GestureSelector {
                        selectionMgr,
                        scrollView::getHeight,
                        scrollView::findChildViewUnder,
                        actionDelegate);
                        actionDelegate,
                        lock);

        return helper;
    }
@@ -162,6 +168,8 @@ public final class GestureSelector {
        mLastInterceptedPoint = e.getOrigin();
        if (mStarted) {
            mSelectionMgr.startRangeSelection(mLastStartedItemPos);
            // Gesture Selection about to start
            mLock.block();
            return true;
        }
        return false;
@@ -173,6 +181,7 @@ public final class GestureSelector {
        mLastStartedItemPos = -1;
        mStarted = false;
        mSelectionMgr.getSelection().applyProvisionalSelection();
        mLock.unblock();
        return false;
    }

Loading