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

Commit 990f76ea authored by Steve McKay's avatar Steve McKay
Browse files

Lifetime of FragmentTuners scoped to activity.

Add support for resetting with new state from directory fragment.
Update Model to use an EventListener.
Eliminate documentPick handling from base activity and directory fragment...
    Plum document picking directly from UserInputHandler to FragmentTuner instances.
Add new EventHandler internface (returns void, more semantic meaning that Consumer<T>).
Replace ModelUpdateListener interface with EventHandler.
Make DocumentAdapters return EventHandler<Model.Update> instead of
    implementing ModelUpdateListener.
Move Activity specific FragmentTuner impls along side respective activities.

Change-Id: Ia6a5ab00ede685f7418773ed865d8c51e4125330
parent 25676037
Loading
Loading
Loading
Loading
+19 −3
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ import com.android.documentsui.dirlist.AnimationView;
import com.android.documentsui.dirlist.DirectoryFragment;
import com.android.documentsui.dirlist.FragmentTuner;
import com.android.documentsui.dirlist.Model;
import com.android.documentsui.dirlist.MultiSelectManager;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.roots.LoadRootTask;
import com.android.documentsui.roots.RootsCache;
@@ -138,13 +139,28 @@ public abstract class BaseActivity extends Activity
    private boolean mNavDrawerHasFocus;
    private long mStartTime;

    /**
     * Provides Activity a means of injection into and specialization of
     * DirectoryFragment.
     */
    public abstract FragmentTuner getFragmentTuner(
            Model model, MultiSelectManager selectionMgr, boolean mSearchMode);

    public abstract void onDocumentPicked(DocumentInfo doc, Model model);
    public abstract void onDocumentsPicked(List<DocumentInfo> docs);
    public abstract FragmentTuner createFragmentTuner();
    /**
     * Provides Activity a means of injection into and specialization of
     * DirectoryFragment hosted menus.
     */
    public abstract MenuManager getMenuManager();

    /**
     * Provides Activity a means of injection into and specialization of
     * DirectoryFragment.
     */
    public abstract DirectoryDetails getDirectoryDetails();

    public abstract void onDocumentPicked(DocumentInfo doc, Model model);
    public abstract void onDocumentsPicked(List<DocumentInfo> docs);

    protected abstract void onTaskFinished(Uri... uris);
    protected abstract void refreshDirectory(int anim);
    /** Allows sub-classes to include information in a newly created State instance. */
+1 −1
Original line number Diff line number Diff line
@@ -22,5 +22,5 @@ package com.android.documentsui.base;
 */
@FunctionalInterface
public interface EventHandler<T> {
    boolean apply(T event);
    boolean accept(T event);
}
 No newline at end of file
+25 −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.base;

/**
 * A functional interface that listens to an event without returning any information.
 */
@FunctionalInterface
public interface EventListener<T> {
    void accept(T event);
}
 No newline at end of file
+1 −1
Original line number Diff line number Diff line
@@ -195,7 +195,7 @@ class ActionModeController implements MultiSelectManager.Callback, ActionMode.Ca

    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        return mMenuItemClicker.apply(item);
        return mMenuItemClicker.accept(item);
    }

    static ActionModeController create(
+30 −43
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ import com.android.documentsui.RecentsLoader;
import com.android.documentsui.Snackbars;
import com.android.documentsui.ThumbnailCache;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.EventListener;
import com.android.documentsui.base.Events.InputEvent;
import com.android.documentsui.base.Events.MotionInputEvent;
import com.android.documentsui.base.RootInfo;
@@ -134,7 +135,7 @@ public class DirectoryFragment extends Fragment
    private static final int REFRESH_SPINNER_DISMISS_DELAY = 500;

    private final Model mModel = new Model();
    private final Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
    private final EventListener<Model.Update> mModelUpdateListener = new ModelUpdateListener();
    private MultiSelectManager mSelectionMgr;
    private ActionModeController mActionModeController;
    private SelectionMetadata mSelectionMetadata;
@@ -298,7 +299,7 @@ public class DirectoryFragment extends Fragment
        mSelectionMetadata = new SelectionMetadata(mModel::getItem);
        mSelectionMgr.addItemCallback(mSelectionMetadata);

        mModel.addUpdateListener(mAdapter);
        mModel.addUpdateListener(mAdapter.getModelUpdateListener());
        mModel.addUpdateListener(mModelUpdateListener);

        // Make sure this is done after the RecyclerView and the Model are set up.
@@ -310,8 +311,9 @@ public class DirectoryFragment extends Fragment
                mSelectionMgr,
                mRecView);

        mTuner = getBaseActivity().createFragmentTuner();
        mMenuManager = getBaseActivity().getMenuManager();
        final BaseActivity activity = getBaseActivity();
        mTuner = activity.getFragmentTuner(mModel, mSelectionMgr, mSearchMode);
        mMenuManager = activity.getMenuManager();

        if (state.allowMultiple) {
            mBandController = new BandController(mRecView, mAdapter, mSelectionMgr);
@@ -336,7 +338,11 @@ public class DirectoryFragment extends Fragment
                (MotionEvent t) -> MotionInputEvent.obtain(t, mRecView),
                this::canSelect,
                this::onRightClick,
                (DocumentDetails doc) -> handleViewItem(doc.getModelId()), // activate handler
                // TODO: consider injecting the tuner directly into the handler for
                // less middle-man action.
                (DocumentDetails details) -> mTuner.onDocumentPicked(details.getModelId()),
                // TODO: replace this with a previewHandler
                (DocumentDetails details) -> mTuner.onDocumentPicked(details.getModelId()),
                (DocumentDetails ignored) -> onDeleteSelectedDocuments(), // delete handler
                mDragStartListener::onTouchDragEvent,
                gestureSel::start);
@@ -350,8 +356,6 @@ public class DirectoryFragment extends Fragment
                mInputHandler,
                mBandController);

        final BaseActivity activity = getBaseActivity();
        mTuner = activity.createFragmentTuner();
        mMenuManager = activity.getMenuManager();

        mActionModeController = ActionModeController.create(
@@ -441,6 +445,9 @@ public class DirectoryFragment extends Fragment

        final String modelId = getModelId(v);
        if (modelId == null) {
            // TODO: inject DirectoryDetails into MenuManager constructor
            // Since both classes are supplied by Activity and created
            // at the same time.
            mMenuManager.inflateContextMenuForContainer(
                    menu, inflater, getBaseActivity().getDirectoryDetails());
        } else {
@@ -493,25 +500,6 @@ public class DirectoryFragment extends Fragment
        return true;
    }

    private boolean handleViewItem(String id) {
        final Cursor cursor = mModel.getItem(id);

        if (cursor == null) {
            Log.w(TAG, "Can't view item. Can't obtain cursor for modeId" + id);
            return false;
        }

        final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
        final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
        if (mTuner.isDocumentEnabled(docMimeType, docFlags)) {
            final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
            getBaseActivity().onDocumentPicked(doc, mModel);
            mSelectionMgr.clearSelection();
            return true;
        }
        return false;
    }

    public void onViewModeChanged() {
        // Mode change is just visual change; no need to kick loader.
        updateDisplayState();
@@ -1254,20 +1242,26 @@ public class DirectoryFragment extends Fragment
        return mSelectionMgr.getSelection().contains(modelId);
    }

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

        @Override
        public void onModelUpdate(Model model) {
            if (DEBUG) Log.d(TAG, "Received model update. Loading=" + model.isLoading());
        public void accept(Model.Update update) {
            if (update.hasError()) {
                showQueryError();
                return;
            }

            if (model.info != null || model.error != null) {
                mMessageBar.setInfo(model.info);
                mMessageBar.setError(model.error);
            if (DEBUG) Log.d(TAG, "Received model update. Loading=" + mModel.isLoading());

            if (mModel.info != null || mModel.error != null) {
                mMessageBar.setInfo(mModel.info);
                mMessageBar.setError(mModel.error);
                mMessageBar.show();
            }

            mProgressBar.setVisibility(model.isLoading() ? View.VISIBLE : View.GONE);
            mProgressBar.setVisibility(mModel.isLoading() ? View.VISIBLE : View.GONE);

            if (model.isEmpty()) {
            if (mModel.isEmpty()) {
                if (mSearchMode) {
                    showNoResults(getDisplayState().stack.root);
                } else {
@@ -1278,15 +1272,10 @@ public class DirectoryFragment extends Fragment
                mAdapter.notifyDataSetChanged();
            }

            if (!model.isLoading()) {
            if (!mModel.isLoading()) {
                getBaseActivity().notifyDirectoryLoaded(
                    model.doc != null ? model.doc.derivedUri : null);
            }
                        mModel.doc != null ? mModel.doc.derivedUri : null);
            }

        @Override
        public void onModelUpdateFailed(Exception e) {
            showQueryError();
        }
    }

@@ -1486,8 +1475,6 @@ public class DirectoryFragment extends Fragment
        mLastSortDimension = curSortedDimension;
        mLastSortDirection = curSortedDimension.getSortDirection();

        mTuner.onModelLoaded(mModel, mType, mSearchMode);

        if (mRefreshLayout.isRefreshing()) {
            new Handler().postDelayed(
                    () -> mRefreshLayout.setRefreshing(false),
Loading