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

Commit 739f94ba authored by Steve McKay's avatar Steve McKay
Browse files

ActionHandler stage 2.

Extract interface, dropping any Activity typed param.
Introduce AbstractActionHandler, depends *only* on concrete Activity.
Make only subclasses know about ManageActivity and PickActivity.
Distribute functionality accordingly.
Pull openInNewWindow into ActivityHandler...
    update different cases to all send a stac....
    and update launching code to handle a stack with just a root.
Add an almost pointless test for openInNewWindow (but the test harness is in place).

Change-Id: I729ee0c06d3de0c05c0bea118533dd1c1f274783
parent 1cad5187
Loading
Loading
Loading
Loading
+104 −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.ClipData;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.os.Parcelable;

import com.android.documentsui.base.BooleanConsumer;
import com.android.documentsui.base.DocumentStack;
import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.Shared;
import com.android.documentsui.dirlist.DocumentDetails;
import com.android.documentsui.manager.LauncherActivity;
import com.android.documentsui.sidebar.EjectRootTask;

/**
 * Provides support for specializing the actions (viewDocument etc.) to the host activity.
 */
public abstract class AbstractActionHandler<T extends Activity> implements ActionHandler {

    protected final T mActivity;

    public AbstractActionHandler(T activity) {
        mActivity = activity;
    }

    @Override
    public void openSettings(RootInfo root) {
        throw new UnsupportedOperationException("Can't open settings.");
    }

    @Override
    public void ejectRoot(RootInfo root, BooleanConsumer listener) {
        new EjectRootTask(
                mActivity.getContentResolver(),
                root.authority,
                root.rootId,
                listener).executeOnExecutor(ProviderExecutor.forAuthority(root.authority));
    }

    @Override
    public void openRoot(ResolveInfo app) {
        throw new UnsupportedOperationException("Can't open an app.");
    }

    @Override
    public void showAppDetails(ResolveInfo info) {
        throw new UnsupportedOperationException("Can't show app details.");
    }

    @Override
    public boolean dropOn(ClipData data, RootInfo root) {
        throw new UnsupportedOperationException("Can't open an app.");
    }

    @Override
    public void openInNewWindow(DocumentStack path) {
        Metrics.logUserAction(mActivity, Metrics.USER_ACTION_NEW_WINDOW);

        Intent intent = LauncherActivity.createLaunchIntent(mActivity);
        intent.putExtra(Shared.EXTRA_STACK, (Parcelable) path);

        // Multi-window necessitates we pick how we are launched.
        // By default we'd be launched in-place above the existing app.
        // By setting launch-to-side ActivityManager will open us to side.
        if (mActivity.isInMultiWindowMode()) {
            intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
        }

        mActivity.startActivity(intent);
    }

    @Override
    public void pasteIntoFolder(RootInfo root) {
        throw new UnsupportedOperationException("Can't paste into folder.");
    }

    @Override
    public boolean viewDocument(DocumentDetails doc) {
        throw new UnsupportedOperationException("Direct view not supported!");
    }

    @Override
    public boolean previewDocument(DocumentDetails doc) {
        throw new UnsupportedOperationException("Preview not supported!");
    }
}
+17 −80
Original line number Diff line number Diff line
@@ -19,102 +19,39 @@ package com.android.documentsui;
import android.content.ClipData;
import android.content.pm.ResolveInfo;

import com.android.documentsui.base.CheckedTask.Check;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.BooleanConsumer;
import com.android.documentsui.base.DocumentStack;
import com.android.documentsui.base.RootInfo;
import com.android.documentsui.clipping.DocumentClipper;
import com.android.documentsui.dirlist.DocumentDetails;
import com.android.documentsui.sidebar.EjectRootTask;

import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
public interface ActionHandler {

/**
 * Provides support for specializing the actions (viewDocument etc.) to the host activity.
 */
public abstract class ActionHandler<T extends BaseActivity> {

    protected T mActivity;

    public ActionHandler(T activity) {
        mActivity = activity;
    }

    public void openSettings(RootInfo root) {
        throw new UnsupportedOperationException("Can't open settings.");
    }
    void openSettings(RootInfo root);

    /**
     * Drops documents on a root.
     * @param check The check to make sure RootsFragment is not detached from activity.
     */
    public boolean dropOn(ClipData data, RootInfo root) {
        new GetRootDocumentTask(
                root,
                mActivity,
                mActivity::isDestroyed,
                (DocumentInfo doc) -> dropOn(data, root, doc)
        ).executeOnExecutor(ProviderExecutor.forAuthority(root.authority));
        return true;
    }

    private void dropOn(ClipData data, RootInfo root, DocumentInfo doc) {
        DocumentClipper clipper
                = DocumentsApplication.getDocumentClipper(mActivity);
        clipper.copyFromClipData(root, doc, data, mActivity.fileOpCallback);
    }

    public void ejectRoot(
            RootInfo root, BooleanSupplier ejectCanceledCheck, Consumer<Boolean> listener) {
        assert(ejectCanceledCheck != null);
        ejectRoot(
                root.authority,
                root.rootId,
                ejectCanceledCheck,
                listener);
    }
    boolean dropOn(ClipData data, RootInfo root);

    private void ejectRoot(
            String authority,
            String rootId,
            BooleanSupplier ejectCanceledCheck,
            Consumer<Boolean> listener) {
        new EjectRootTask(
                mActivity,
                authority,
                rootId,
                ejectCanceledCheck,
                listener).executeOnExecutor(ProviderExecutor.forAuthority(authority));
    }
    /**
     * Attempts to eject the identified root. Returns a boolean answer to listener.
     */
    void ejectRoot(RootInfo root, BooleanConsumer listener);

    public void showAppDetails(ResolveInfo info) {
        throw new UnsupportedOperationException("Can't show app details.");
    }
    void showAppDetails(ResolveInfo info);

    public void openRoot(RootInfo root) {
        Metrics.logRootVisited(mActivity, root);
        mActivity.onRootPicked(root);
    }
    void openRoot(RootInfo root);

    public void openRoot(ResolveInfo app) {
        throw new UnsupportedOperationException("Can't open an app.");
    }
    void openRoot(ResolveInfo app);

    public void openInNewWindow(RootInfo root) {
        throw new UnsupportedOperationException("Can't open in new window");
    }
    void openInNewWindow(DocumentStack path);

    public void pasteIntoFolder(RootInfo root) {
        throw new UnsupportedOperationException("Can't paste into folder.");
    }
    void pasteIntoFolder(RootInfo root);

    public boolean viewDocument(DocumentDetails doc) {
        throw new UnsupportedOperationException("Direct view not supported!");
    }
    boolean viewDocument(DocumentDetails doc);

    public boolean previewDocument(DocumentDetails doc) {
        throw new UnsupportedOperationException("Preview not supported!");
    }
    boolean previewDocument(DocumentDetails doc);

    public abstract boolean openDocument(DocumentDetails doc);
    boolean openDocument(DocumentDetails doc);
}
+2 −3
Original line number Diff line number Diff line
@@ -158,10 +158,9 @@ public abstract class BaseActivity extends Activity implements NavigationViewMan
     * Provides Activity a means of injection into and specialization of
     * fragment actions.
     *
     * Args can be nullable when called from a contact without this information such as
     * RootsFragment.
     * Args can be nullable when called from a context lacking them, such as RootsFragment.
     */
    public abstract ActionHandler<? extends BaseActivity> getActionHandler(
    public abstract ActionHandler getActionHandler(
            @Nullable Model model, @Nullable MultiSelectManager selectionMgr);

    public abstract void onDocumentPicked(DocumentInfo doc, Model model);
+22 −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;

@FunctionalInterface
public interface BooleanConsumer {

    void accept(boolean value);
}
+3 −3
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ public abstract class CheckedTask<Input, Output>
    protected abstract void finish(Output output);

    @Override
    final protected void onPreExecute() {
    protected final void onPreExecute() {
        if (mCheck.stop()) {
            return;
        }
@@ -58,7 +58,7 @@ public abstract class CheckedTask<Input, Output>
    }

    @Override
    final protected Output doInBackground(Input... input) {
    protected final Output doInBackground(Input... input) {
        if (mCheck.stop()) {
            return null;
        }
@@ -66,7 +66,7 @@ public abstract class CheckedTask<Input, Output>
    }

    @Override
    final protected void onPostExecute(Output result) {
    protected final void onPostExecute(Output result) {
        if (mCheck.stop()) {
            return;
        }
Loading