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

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

Merge "Move openContainerDocument() into ActionHandlers." into nyc-andromeda-dev

parents b24ecf63 63bf8135
Loading
Loading
Loading
Loading
+24 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Parcelable;
import android.support.annotation.VisibleForTesting;

import com.android.documentsui.AbstractActionHandler.CommonAddons;
import com.android.documentsui.base.BooleanConsumer;
@@ -31,6 +32,7 @@ import com.android.documentsui.base.Lookup;
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.AnimationView.AnimationType;
import com.android.documentsui.dirlist.DocumentDetails;
import com.android.documentsui.files.LauncherActivity;
@@ -55,6 +57,7 @@ public abstract class AbstractActionHandler<T extends Activity & CommonAddons>
    protected final RootsAccess mRoots;
    protected final DocumentsAccess mDocs;
    protected final SelectionManager mSelectionMgr;
    protected final SearchViewManager mSearchMgr;
    protected final Lookup<String, Executor> mExecutors;

    public AbstractActionHandler(
@@ -63,6 +66,7 @@ public abstract class AbstractActionHandler<T extends Activity & CommonAddons>
            RootsAccess roots,
            DocumentsAccess docs,
            SelectionManager selectionMgr,
            SearchViewManager searchMgr,
            Lookup<String, Executor> executors) {

        assert(activity != null);
@@ -76,6 +80,7 @@ public abstract class AbstractActionHandler<T extends Activity & CommonAddons>
        mRoots = roots;
        mDocs = docs;
        mSelectionMgr = selectionMgr;
        mSearchMgr = searchMgr;
        mExecutors = executors;
    }

@@ -150,6 +155,21 @@ public abstract class AbstractActionHandler<T extends Activity & CommonAddons>
        throw new UnsupportedOperationException("Show chooser for doc not supported!");
    }

    @Override
    public void openContainerDocument(DocumentInfo doc) {
        assert(doc.isContainer());

        mActivity.notifyDirectoryNavigated(doc.derivedUri);

        mState.pushDocument(doc);
        // Show an opening animation only if pressing "back" would get us back to the
        // previous directory. Especially after opening a root document, pressing
        // back, wouldn't go to the previous root, but close the activity.
        final int anim = (mState.hasLocationChanged() && mState.stack.size() > 1)
                ? AnimationView.ANIM_ENTER : AnimationView.ANIM_NONE;
        mActivity.refreshCurrentRootAndDirectory(anim);
    }

    @Override
    public void deleteSelectedDocuments() {
        throw new UnsupportedOperationException("Delete not supported!");
@@ -179,6 +199,7 @@ public abstract class AbstractActionHandler<T extends Activity & CommonAddons>
    protected Selection getStableSelection() {
        return mSelectionMgr.getSelection(new Selection());
    }

    /**
     * A class primarily for the support of isolating our tests
     * from our concrete activity implementations.
@@ -189,9 +210,11 @@ public abstract class AbstractActionHandler<T extends Activity & CommonAddons>
        // TODO: Move this to PickAddons as multi-document picking is exclusive to that activity.
        void onDocumentsPicked(List<DocumentInfo> docs);
        void onDocumentPicked(DocumentInfo doc);
        void openContainerDocument(DocumentInfo doc);
        RootInfo getCurrentRoot();
        DocumentInfo getCurrentDirectory();
        void setRootsDrawerOpen(boolean open);

        @VisibleForTesting
        void notifyDirectoryNavigated(Uri docUri);
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -65,6 +65,8 @@ public interface ActionHandler {

    void showChooserForDoc(DocumentInfo doc);

    void openContainerDocument(DocumentInfo doc);

    void deleteSelectedDocuments();

    void shareSelectedDocuments();
+29 −89
Original line number Diff line number Diff line
@@ -32,11 +32,9 @@ import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.MessageQueue.IdleHandler;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
@@ -59,7 +57,6 @@ import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.EventHandler;
import com.android.documentsui.base.Events;
import com.android.documentsui.base.LocalPreferences;
import com.android.documentsui.base.PairedTask;
import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.Shared;
import com.android.documentsui.base.State;
@@ -80,12 +77,11 @@ import com.android.documentsui.ui.DialogController;
import com.android.documentsui.ui.MessageBuilder;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executor;

public abstract class BaseActivity
public abstract class BaseActivity<T extends ActionHandler>
        extends Activity implements CommonAddons, NavigationViewManager.Environment {

    private static final String BENCHMARK_TESTING_PACKAGE = "com.android.documentsui.appperftests";
@@ -95,25 +91,23 @@ public abstract class BaseActivity

    protected @Nullable RetainedState mRetainedState;
    protected RootsCache mRoots;
    protected DocumentsAccess mDocs;
    protected MessageBuilder mMessages;
    protected DrawerController mDrawer;
    protected NavigationViewManager mNavigator;
    protected FocusManager mFocusManager;
    protected SortController mSortController;

    protected T mActions;

    private final List<EventListener> mEventListeners = new ArrayList<>();
    private final String mTag;
    private final ContentObserver mRootsCacheObserver = new ContentObserver(
            new Handler()) {
                @Override
                public void onChange(boolean selfChange) {
                    new HandleRootsChangedTask(BaseActivity.this).execute(getCurrentRoot());
                }
            };

    @LayoutRes
    private int mLayoutId;

    private RootsMonitor<BaseActivity> mRootsMonitor;

    private boolean mNavDrawerHasFocus;
    private long mStartTime;

@@ -202,9 +196,8 @@ public abstract class BaseActivity
        // support to that fragment.
        mRetainedState = (RetainedState) getLastNonConfigurationInstance();
        mRoots = DocumentsApplication.getRootsCache(this);
        mDocs = DocumentsAccess.create(this);
        mMessages = new MessageBuilder(this);
        getContentResolver().registerContentObserver(
                RootsCache.sNotificationUri, false, mRootsCacheObserver);

        DocumentsToolbar toolbar = (DocumentsToolbar) findViewById(R.id.toolbar);
        setActionBar(toolbar);
@@ -245,6 +238,20 @@ public abstract class BaseActivity
        setResult(Activity.RESULT_CANCELED);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);

        mRootsMonitor = new RootsMonitor<>(
                this,
                mActions,
                mRoots,
                mDocs,
                mState,
                mSearchManager);
        mRootsMonitor.start();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        boolean showMenu = super.onCreateOptionsMenu(menu);
@@ -267,7 +274,7 @@ public abstract class BaseActivity

    @Override
    protected void onDestroy() {
        getContentResolver().unregisterContentObserver(mRootsCacheObserver);
        mRootsMonitor.stop();
        super.onDestroy();
    }

@@ -344,7 +351,7 @@ public abstract class BaseActivity
            new GetRootDocumentTask(
                    root,
                    this,
                    this::openContainerDocument)
                    mActions::openContainerDocument)
                    .executeOnExecutor(getExecutorForCurrentDirectory());
        }
    }
@@ -406,22 +413,6 @@ public abstract class BaseActivity
                && !root.isDownloads();
    }

    // TODO: Move to ActionHandler...currently blocked by the notifyDirectory....business.
    @Override
    public void openContainerDocument(DocumentInfo doc) {
        assert(doc.isContainer());

        notifyDirectoryNavigated(doc.derivedUri);

        mState.pushDocument(doc);
        // Show an opening animation only if pressing "back" would get us back to the
        // previous directory. Especially after opening a root document, pressing
        // back, wouldn't go to the previous root, but close the activity.
        final int anim = (mState.hasLocationChanged() && mState.stack.size() > 1)
                ? AnimationView.ANIM_ENTER : AnimationView.ANIM_NONE;
        refreshCurrentRootAndDirectory(anim);
    }

    /**
     * Refreshes the content of the director and the menu/action bar.
     * The current directory name and selection will get updated.
@@ -638,21 +629,26 @@ public abstract class BaseActivity
        return super.onKeyDown(keyCode, event);
    }

    @VisibleForTesting
    public void addEventListener(EventListener listener) {
        mEventListeners.add(listener);
    }

    @VisibleForTesting
    public void removeEventListener(EventListener listener) {
        mEventListeners.remove(listener);
    }

    @VisibleForTesting
    public void notifyDirectoryLoaded(Uri uri) {
        for (EventListener listener : mEventListeners) {
            listener.onDirectoryLoaded(uri);
        }
    }

    void notifyDirectoryNavigated(Uri uri) {
    @VisibleForTesting
    @Override
    public void notifyDirectoryNavigated(Uri uri) {
        for (EventListener listener : mEventListeners) {
            listener.onDirectoryNavigated(uri);
        }
@@ -728,62 +724,6 @@ public abstract class BaseActivity
        });
    }

    private static final class HandleRootsChangedTask
            extends PairedTask<BaseActivity, RootInfo, RootInfo> {
        RootInfo mCurrentRoot;
        DocumentInfo mDefaultRootDocument;

        public HandleRootsChangedTask(BaseActivity activity) {
            super(activity);
        }

        @Override
        protected RootInfo run(RootInfo... roots) {
            assert(roots.length == 1);
            mCurrentRoot = roots[0];
            final Collection<RootInfo> cachedRoots = mOwner.mRoots.getRootsBlocking();
            for (final RootInfo root : cachedRoots) {
                if (root.getUri().equals(mCurrentRoot.getUri())) {
                    // We don't need to change the current root as the current root was not removed.
                    return null;
                }
            }

            // Choose the default root.
            final RootInfo defaultRoot = mOwner.mRoots.getDefaultRootBlocking(mOwner.mState);
            assert(defaultRoot != null);
            if (!defaultRoot.isRecents()) {
                mDefaultRootDocument = defaultRoot.getRootDocumentBlocking(mOwner);
            }
            return defaultRoot;
        }

        @Override
        protected void finish(RootInfo defaultRoot) {
            if (defaultRoot == null) {
                return;
            }

            // If the activity has been launched for the specific root and it is removed, finish the
            // activity.
            final Uri uri = mOwner.getIntent().getData();
            if (uri != null && uri.equals(mCurrentRoot.getUri())) {
                mOwner.finish();
                return;
            }

            // Clear entire backstack and start in new root.
            mOwner.mState.onRootChanged(defaultRoot);
            mOwner.mSearchManager.update(defaultRoot);

            if (defaultRoot.isRecents()) {
                mOwner.refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE);
            } else {
                mOwner.openContainerDocument(mDefaultRootDocument);
            }
        }
    }

    public final class RetainedState {
        public @Nullable Selection selection;

+0 −81
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.net.Uri;

import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.PairedTask;
import com.android.documentsui.base.RootInfo;
import com.android.documentsui.dirlist.AnimationView;

import java.util.Collection;

final class OnRootsChangedTask
        extends PairedTask<BaseActivity, RootInfo, RootInfo> {
    RootInfo mCurrentRoot;
    DocumentInfo mDefaultRootDocument;

    public OnRootsChangedTask(BaseActivity activity) {
        super(activity);
    }

    @Override
    protected RootInfo run(RootInfo... roots) {
        assert(roots.length == 1);
        mCurrentRoot = roots[0];
        final Collection<RootInfo> cachedRoots = mOwner.mRoots.getRootsBlocking();
        for (final RootInfo root : cachedRoots) {
            if (root.getUri().equals(mCurrentRoot.getUri())) {
                // We don't need to change the current root as the current root was not removed.
                return null;
            }
        }

        // Choose the default root.
        final RootInfo defaultRoot = mOwner.mRoots.getDefaultRootBlocking(mOwner.mState);
        assert(defaultRoot != null);
        if (!defaultRoot.isRecents()) {
            mDefaultRootDocument = defaultRoot.getRootDocumentBlocking(mOwner);
        }
        return defaultRoot;
    }

    @Override
    protected void finish(RootInfo defaultRoot) {
        if (defaultRoot == null) {
            return;
        }

        // If the activity has been launched for the specific root and it is removed, finish the
        // activity.
        final Uri uri = mOwner.getIntent().getData();
        if (uri != null && uri.equals(mCurrentRoot.getUri())) {
            mOwner.finish();
            return;
        }

        // Clear entire backstack and start in new root.
        mOwner.mState.onRootChanged(defaultRoot);
        mOwner.mSearchManager.update(defaultRoot);

        if (defaultRoot.isRecents()) {
            mOwner.refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE);
        } else {
            mOwner.openContainerDocument(mDefaultRootDocument);
        }
    }
}
 No newline at end of file
+147 −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.app.Activity;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;

import com.android.documentsui.AbstractActionHandler.CommonAddons;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.PairedTask;
import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.State;
import com.android.documentsui.dirlist.AnimationView;
import com.android.documentsui.roots.RootsAccess;

import java.util.Collection;

/**
 * Monitors roots change and refresh the page when necessary.
 */
final class RootsMonitor<T extends Activity & CommonAddons> {

    private final ContentResolver mResolver;
    private final ContentObserver mObserver;

    RootsMonitor(
            final T activity,
            final ActionHandler actions,
            final RootsAccess roots,
            final DocumentsAccess docs,
            final State state,
            final SearchViewManager searchMgr) {
        mResolver = activity.getContentResolver();

        mObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
            @Override
            public void onChange(boolean selfChange) {
                new HandleRootsChangedTask<T>(
                        activity,
                        actions,
                        roots,
                        docs,
                        state,
                        searchMgr).execute(activity.getCurrentRoot());
            }
        };
    }

    void start() {
        mResolver.registerContentObserver(RootsAccess.NOTIFICATION_URI, false, mObserver);
    }

    void stop() {
        mResolver.unregisterContentObserver(mObserver);
    }

    private static class HandleRootsChangedTask<T extends Activity & CommonAddons>
            extends PairedTask<T, RootInfo, RootInfo> {
        private final ActionHandler mActions;
        private final RootsAccess mRoots;
        private final DocumentsAccess mDocs;
        private final State mState;
        private final SearchViewManager mSearchMgr;

        private RootInfo mCurrentRoot;
        private DocumentInfo mDefaultRootDocument;

        private HandleRootsChangedTask(
                T activity,
                ActionHandler actions,
                RootsAccess roots,
                DocumentsAccess docs,
                State state,
                SearchViewManager searchMgr) {
            super(activity);
            mActions = actions;
            mRoots = roots;
            mDocs = docs;
            mState = state;
            mSearchMgr = searchMgr;
        }

        @Override
        protected RootInfo run(RootInfo... roots) {
            assert (roots.length == 1);
            mCurrentRoot = roots[0];
            final Collection<RootInfo> cachedRoots = mRoots.getRootsBlocking();
            for (final RootInfo root : cachedRoots) {
                if (root.getUri().equals(mCurrentRoot.getUri())) {
                    // We don't need to change the current root as the current root was not removed.
                    return null;
                }
            }

            // Choose the default root.
            final RootInfo defaultRoot = mRoots.getDefaultRootBlocking(mState);
            assert (defaultRoot != null);
            if (!defaultRoot.isRecents()) {
                mDefaultRootDocument = mDocs.getRootDocument(defaultRoot);
            }
            return defaultRoot;
        }

        @Override
        protected void finish(RootInfo defaultRoot) {
            if (defaultRoot == null) {
                return;
            }

            // If the activity has been launched for the specific root and it is removed, finish the
            // activity.
            final Uri uri = mOwner.getIntent().getData();
            if (uri != null && uri.equals(mCurrentRoot.getUri())) {
                mOwner.finish();
                return;
            }

            // Clear entire backstack and start in new root.
            mState.onRootChanged(defaultRoot);
            mSearchMgr.update(defaultRoot);

            if (defaultRoot.isRecents()) {
                mOwner.refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE);
            } else {
                mActions.openContainerDocument(mDefaultRootDocument);
            }
        }
    }
}
Loading