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

Commit f984c5a6 authored by Winson Chung's avatar Winson Chung Committed by Android (Google) Code Review
Browse files

Merge "Cleanup drag and drop flow/code organization" into udc-qpr-dev

parents 12f1fa63 780008c2
Loading
Loading
Loading
Loading
+11 −25
Original line number Diff line number Diff line
@@ -16,9 +16,6 @@

package com.android.wm.shell.draganddrop;

import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DragEvent.ACTION_DRAG_ENDED;
import static android.view.DragEvent.ACTION_DRAG_ENTERED;
@@ -38,6 +35,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP;

import android.app.ActivityTaskManager;
import android.content.ClipDescription;
import android.content.ComponentCallbacks2;
import android.content.Context;
@@ -205,8 +203,6 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
        final Context context = mDisplayController.getDisplayContext(displayId)
                .createWindowContext(TYPE_APPLICATION_OVERLAY, null);
        final WindowManager wm = context.getSystemService(WindowManager.class);

        // TODO(b/169894807): Figure out the right layer for this, needs to be below the task bar
        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
                TYPE_APPLICATION_OVERLAY,
@@ -279,15 +275,11 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
        }

        if (event.getAction() == ACTION_DRAG_STARTED) {
            final boolean hasValidClipData = event.getClipData().getItemCount() > 0
                    && (description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)
                            || description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)
                            || description.hasMimeType(MIMETYPE_APPLICATION_TASK));
            pd.isHandlingDrag = hasValidClipData;
            pd.isHandlingDrag = DragUtils.canHandleDrag(event);
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
                    "Clip description: handlingDrag=%b itemCount=%d mimeTypes=%s",
                    pd.isHandlingDrag, event.getClipData().getItemCount(),
                    getMimeTypes(description));
                    DragUtils.getMimeTypesConcatenated(description));
        }

        if (!pd.isHandlingDrag) {
@@ -300,10 +292,13 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
                    Slog.w(TAG, "Unexpected drag start during an active drag");
                    return false;
                }
                // TODO(b/290391688): Also update the session data with task stack changes
                InstanceId loggerSessionId = mLogger.logStart(event);
                pd.activeDragCount++;
                pd.dragLayout.prepare(mDisplayController.getDisplayLayout(displayId),
                        event.getClipData(), loggerSessionId);
                pd.dragSession = new DragSession(mContext, ActivityTaskManager.getInstance(),
                        mDisplayController.getDisplayLayout(displayId), event.getClipData());
                pd.dragSession.update();
                pd.dragLayout.prepare(pd.dragSession, loggerSessionId);
                setDropTargetWindowVisibility(pd, View.VISIBLE);
                notifyDragStarted();
                break;
@@ -324,7 +319,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
                break;
            }
            case ACTION_DRAG_ENDED:
                // TODO(b/169894807): Ensure sure it's not possible to get ENDED without DROP
                // TODO(b/290391688): Ensure sure it's not possible to get ENDED without DROP
                // or EXITED
                if (pd.dragLayout.hasDropped()) {
                    mLogger.logDrop();
@@ -362,17 +357,6 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
        pd.setWindowVisibility(visibility);
    }

    private String getMimeTypes(ClipDescription description) {
        String mimeTypes = "";
        for (int i = 0; i < description.getMimeTypeCount(); i++) {
            if (i > 0) {
                mimeTypes += ", ";
            }
            mimeTypes += description.getMimeType(i);
        }
        return mimeTypes;
    }

    /**
     * Returns if any displays are currently ready to handle a drag/drop.
     */
@@ -462,6 +446,8 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
        // A count of the number of active drags in progress to ensure that we only hide the window
        // when all the drag animations have completed
        int activeDragCount;
        // The active drag session
        DragSession dragSession;

        PerDisplay(int dispId, Context c, WindowManager w, FrameLayout rv, DragLayout dl) {
            displayId = dispId;
+4 −65
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVIT
import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS;
import static android.content.ClipDescription.EXTRA_PENDING_INTENT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
@@ -41,16 +40,13 @@ import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPL
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;

import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.app.WindowConfiguration;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.LauncherApps;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -67,14 +63,12 @@ import androidx.annotation.VisibleForTesting;

import com.android.internal.logging.InstanceId;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreenController;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;

/**
 * The policy for handling drag and drop operations to shell.
@@ -84,7 +78,6 @@ public class DragAndDropPolicy {
    private static final String TAG = DragAndDropPolicy.class.getSimpleName();

    private final Context mContext;
    private final ActivityTaskManager mActivityTaskManager;
    private final Starter mStarter;
    private final SplitScreenController mSplitScreen;
    private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
@@ -94,14 +87,12 @@ public class DragAndDropPolicy {
    private DragSession mSession;

    public DragAndDropPolicy(Context context, SplitScreenController splitScreen) {
        this(context, ActivityTaskManager.getInstance(), splitScreen, new DefaultStarter(context));
        this(context, splitScreen, new DefaultStarter(context));
    }

    @VisibleForTesting
    DragAndDropPolicy(Context context, ActivityTaskManager activityTaskManager,
            SplitScreenController splitScreen, Starter starter) {
    DragAndDropPolicy(Context context, SplitScreenController splitScreen, Starter starter) {
        mContext = context;
        mActivityTaskManager = activityTaskManager;
        mSplitScreen = splitScreen;
        mStarter = mSplitScreen != null ? mSplitScreen : starter;
    }
@@ -109,11 +100,9 @@ public class DragAndDropPolicy {
    /**
     * Starts a new drag session with the given initial drag data.
     */
    void start(DisplayLayout displayLayout, ClipData data, InstanceId loggerSessionId) {
    void start(DragSession session, InstanceId loggerSessionId) {
        mLoggerSessionId = loggerSessionId;
        mSession = new DragSession(mActivityTaskManager, displayLayout, data);
        // TODO(b/169894807): Also update the session data with task stack changes
        mSession.update();
        mSession = session;
        RectF disallowHitRegion = (RectF) mSession.dragData.getExtra(EXTRA_DISALLOW_HIT_REGION);
        if (disallowHitRegion == null) {
            mDisallowHitRegion.setEmpty();
@@ -122,13 +111,6 @@ public class DragAndDropPolicy {
        }
    }

    /**
     * Returns the last running task.
     */
    ActivityManager.RunningTaskInfo getLatestRunningTask() {
        return mSession.runningTaskInfo;
    }

    /**
     * Returns the number of targets.
     */
@@ -285,49 +267,6 @@ public class DragAndDropPolicy {
        }
    }

    /**
     * Per-drag session data.
     */
    private static class DragSession {
        private final ActivityTaskManager mActivityTaskManager;
        private final ClipData mInitialDragData;

        final DisplayLayout displayLayout;
        Intent dragData;
        ActivityManager.RunningTaskInfo runningTaskInfo;
        @WindowConfiguration.WindowingMode
        int runningTaskWinMode = WINDOWING_MODE_UNDEFINED;
        @WindowConfiguration.ActivityType
        int runningTaskActType = ACTIVITY_TYPE_STANDARD;
        boolean dragItemSupportsSplitscreen;

        DragSession(ActivityTaskManager activityTaskManager,
                DisplayLayout dispLayout, ClipData data) {
            mActivityTaskManager = activityTaskManager;
            mInitialDragData = data;
            displayLayout = dispLayout;
        }

        /**
         * Updates the session data based on the current state of the system.
         */
        void update() {
            List<ActivityManager.RunningTaskInfo> tasks =
                    mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
            if (!tasks.isEmpty()) {
                final ActivityManager.RunningTaskInfo task = tasks.get(0);
                runningTaskInfo = task;
                runningTaskWinMode = task.getWindowingMode();
                runningTaskActType = task.getActivityType();
            }

            final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
            dragItemSupportsSplitscreen = info == null
                    || ActivityInfo.isResizeableMode(info.resizeMode);
            dragData = mInitialDragData.getItemAt(0).getIntent();
        }
    }

    /**
     * Interface for actually committing the task launches.
     */
+19 −8
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.StatusBarManager;
import android.content.ClipData;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Color;
@@ -53,14 +52,13 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;

import java.util.ArrayList;

/**
 * Coordinates the visible drop targets for the current drag.
 * Coordinates the visible drop targets for the current drag within a single display.
 */
public class DragLayout extends LinearLayout {

@@ -86,6 +84,7 @@ public class DragLayout extends LinearLayout {

    private boolean mIsShowing;
    private boolean mHasDropped;
    private DragSession mSession;

    @SuppressLint("WrongConstant")
    public DragLayout(Context context, SplitScreenController splitScreenController,
@@ -182,16 +181,19 @@ public class DragLayout extends LinearLayout {
        return mHasDropped;
    }

    public void prepare(DisplayLayout displayLayout, ClipData initialData,
            InstanceId loggerSessionId) {
        mPolicy.start(displayLayout, initialData, loggerSessionId);
    /**
     * Called when a new drag is started.
     */
    public void prepare(DragSession session, InstanceId loggerSessionId) {
        mPolicy.start(session, loggerSessionId);
        mSession = session;
        mHasDropped = false;
        mCurrentTarget = null;

        boolean alreadyInSplit = mSplitScreenController != null
                && mSplitScreenController.isSplitScreenVisible();
        if (!alreadyInSplit) {
            ActivityManager.RunningTaskInfo taskInfo1 = mPolicy.getLatestRunningTask();
            ActivityManager.RunningTaskInfo taskInfo1 = mSession.runningTaskInfo;
            if (taskInfo1 != null) {
                final int activityType = taskInfo1.getActivityType();
                if (activityType == ACTIVITY_TYPE_STANDARD) {
@@ -356,7 +358,16 @@ public class DragLayout extends LinearLayout {
     */
    public void hide(DragEvent event, Runnable hideCompleteCallback) {
        mIsShowing = false;
        animateSplitContainers(false, hideCompleteCallback);
        animateSplitContainers(false, () -> {
            if (hideCompleteCallback != null) {
                hideCompleteCallback.run();
            }
            switch (event.getAction()) {
                case DragEvent.ACTION_DROP:
                case DragEvent.ACTION_DRAG_ENDED:
                    mSession = null;
            }
        });
        // Reset the state if we previously force-ignore the bottom margin
        mDropZoneView1.setForceIgnoreBottomMargin(false);
        mDropZoneView2.setForceIgnoreBottomMargin(false);
+89 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.wm.shell.draganddrop;

import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.ClipDescription.EXTRA_PENDING_INTENT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
import static android.content.Intent.EXTRA_USER;

import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.app.WindowConfiguration;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.net.Uri;
import android.os.UserHandle;

import androidx.annotation.IntDef;
import androidx.annotation.Nullable;

import com.android.wm.shell.common.DisplayLayout;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;

/**
 * Per-drag session data.
 */
public class DragSession {
    private final ActivityTaskManager mActivityTaskManager;
    private final ClipData mInitialDragData;

    final DisplayLayout displayLayout;
    Intent dragData;
    ActivityManager.RunningTaskInfo runningTaskInfo;
    @WindowConfiguration.WindowingMode
    int runningTaskWinMode = WINDOWING_MODE_UNDEFINED;
    @WindowConfiguration.ActivityType
    int runningTaskActType = ACTIVITY_TYPE_STANDARD;
    boolean dragItemSupportsSplitscreen;

    DragSession(Context context, ActivityTaskManager activityTaskManager,
            DisplayLayout dispLayout, ClipData data) {
        mActivityTaskManager = activityTaskManager;
        mInitialDragData = data;
        displayLayout = dispLayout;
    }

    /**
     * Updates the session data based on the current state of the system.
     */
    void update() {
        List<ActivityManager.RunningTaskInfo> tasks =
                mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
        if (!tasks.isEmpty()) {
            final ActivityManager.RunningTaskInfo task = tasks.get(0);
            runningTaskInfo = task;
            runningTaskWinMode = task.getWindowingMode();
            runningTaskActType = task.getActivityType();
        }

        final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
        dragItemSupportsSplitscreen = info == null
                || ActivityInfo.isResizeableMode(info.resizeMode);
        dragData = mInitialDragData.getItemAt(0).getIntent();
    }
}
+60 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.wm.shell.draganddrop;

import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;

import android.content.ClipDescription;
import android.view.DragEvent;

/** Collection of utility classes for handling drag and drop. */
public class DragUtils {
    private static final String TAG = "DragUtils";

    /**
     * Returns whether we can handle this particular drag.
     */
    public static boolean canHandleDrag(DragEvent event) {
        return event.getClipData().getItemCount() > 0
                && (isAppDrag(event.getClipDescription()));
    }

    /**
     * Returns whether this clip data description represents an app drag.
     */
    public static boolean isAppDrag(ClipDescription description) {
        return description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)
                || description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)
                || description.hasMimeType(MIMETYPE_APPLICATION_TASK);
    }

    /**
     * Returns a list of the mime types provided in the clip description.
     */
    public static String getMimeTypesConcatenated(ClipDescription description) {
        String mimeTypes = "";
        for (int i = 0; i < description.getMimeTypeCount(); i++) {
            if (i > 0) {
                mimeTypes += ", ";
            }
            mimeTypes += description.getMimeType(i);
        }
        return mimeTypes;
    }
}
Loading