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

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

Merge "2/ Add support for dragging shortcuts and tasks"

parents 34cba818 8c1fc3ea
Loading
Loading
Loading
Loading
+18 −1
Original line number Diff line number Diff line
@@ -64,11 +64,28 @@ public class ClipDescription implements Parcelable {
    public static final String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent";

    /**
     * The MIME type for an activity.
     * The MIME type for an activity. The ClipData must include intents with required extras
     * {@link #EXTRA_PENDING_INTENT} and {@link Intent#EXTRA_USER}, and an optional
     * {@link #EXTRA_ACTIVITY_OPTIONS}.
     * @hide
     */
    public static final String MIMETYPE_APPLICATION_ACTIVITY = "application/vnd.android.activity";

    /**
     * The MIME type for a shortcut. The ClipData must include intents with required extras
     * {@link #EXTRA_PENDING_INTENT} and {@link Intent#EXTRA_USER}, and an optional
     * {@link #EXTRA_ACTIVITY_OPTIONS}.
     * @hide
     */
    public static final String MIMETYPE_APPLICATION_SHORTCUT = "application/vnd.android.shortcut";

    /**
     * The MIME type for a task. The ClipData must include an intent with a required extra
     * {@link Intent#EXTRA_TASK_ID} of the task to launch.
     * @hide
     */
    public static final String MIMETYPE_APPLICATION_TASK = "application/vnd.android.task";

    /**
     * The MIME type for data whose type is otherwise unknown.
     * <p>
+3 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.content.pm;

import android.app.IApplicationThread;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentSender;
@@ -55,6 +56,8 @@ interface ILauncherApps {
    void startActivityAsUser(in IApplicationThread caller, String callingPackage,
            String callingFeatureId, in ComponentName component, in Rect sourceBounds,
            in Bundle opts, in UserHandle user);
    PendingIntent getActivityLaunchIntent(in ComponentName component, in Bundle opts,
            in UserHandle user);
    void showAppDetailsAsUser(in IApplicationThread caller, String callingPackage,
            String callingFeatureId, in ComponentName component, in Rect sourceBounds,
            in Bundle opts, in UserHandle user);
+24 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.content.pm;

import static android.Manifest.permission;
import static android.app.PendingIntent.FLAG_IMMUTABLE;

import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
@@ -715,6 +716,29 @@ public class LauncherApps {
        }
    }

    /**
     * Returns a PendingIntent that would start the same activity started from
     * {@link #startMainActivity(ComponentName, UserHandle, Rect, Bundle)}.
     *
     * @param component The ComponentName of the activity to launch
     * @param startActivityOptions Options to pass to startActivity
     * @param user The UserHandle of the profile
     * @hide
     */
    @Nullable
    public PendingIntent getMainActivityLaunchIntent(@NonNull ComponentName component,
            @Nullable Bundle startActivityOptions, @NonNull UserHandle user) {
        logErrorForInvalidProfileAccess(user);
        if (DEBUG) {
            Log.i(TAG, "GetMainActivityLaunchIntent " + component + " " + user);
        }
        try {
            return mService.getActivityLaunchIntent(component, startActivityOptions, user);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }

    /**
     * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
     * returns null.
+6 −0
Original line number Diff line number Diff line
@@ -169,6 +169,12 @@
      "group": "WM_SHELL_DRAG_AND_DROP",
      "at": "com\/android\/wm\/shell\/draganddrop\/DragLayout.java"
    },
    "1842752748": {
      "message": "Clip description: handlingDrag=%b mimeTypes=%s",
      "level": "VERBOSE",
      "group": "WM_SHELL_DRAG_AND_DROP",
      "at": "com\/android\/wm\/shell\/draganddrop\/DragAndDropController.java"
    },
    "1862198614": {
      "message": "Drag event: action=%s x=%f y=%f xOffset=%f yOffset=%f",
      "level": "VERBOSE",
+85 −30
Original line number Diff line number Diff line
@@ -16,8 +16,17 @@

package com.android.wm.shell.draganddrop;

import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS;
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_PACKAGE_NAME;
import static android.content.Intent.EXTRA_SHORTCUT_ID;
import static android.content.Intent.EXTRA_TASK_ID;
import static android.content.Intent.EXTRA_USER;
import static android.view.DragEvent.ACTION_DRAG_ENDED;
import static android.view.DragEvent.ACTION_DRAG_ENTERED;
import static android.view.DragEvent.ACTION_DRAG_EXITED;
@@ -33,15 +42,24 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Slog;
import android.util.SparseArray;
import android.view.DragEvent;
@@ -68,6 +86,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange

    private static final String TAG = DragAndDropController.class.getSimpleName();

    private final Context mContext;
    private final DisplayController mDisplayController;
    private SplitScreen mSplitScreen;

@@ -76,7 +95,8 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
    private DragLayout mDragLayout;
    private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();

    public DragAndDropController(DisplayController displayController) {
    public DragAndDropController(Context context, DisplayController displayController) {
        mContext = context;
        mDisplayController = displayController;
        mDisplayController.addDisplayWindowListener(this);
    }
@@ -135,13 +155,16 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
                event.getOffsetX(), event.getOffsetY());
        final int displayId = target.getDisplay().getDisplayId();
        final PerDisplay pd = mDisplayDropTargets.get(displayId);
        final ClipDescription description = event.getClipDescription();

        if (event.getAction() == ACTION_DRAG_STARTED) {
            final ClipDescription description = event.getClipDescription();
            final boolean hasValidClipData = description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY);
            final boolean hasValidClipData = description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)
                    || description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)
                    || description.hasMimeType(MIMETYPE_APPLICATION_TASK);
            mIsHandlingDrag = hasValidClipData;
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Clip description: %s",
                    getMimeTypes(description));
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
                    "Clip description: handlingDrag=%b mimeTypes=%s",
                    mIsHandlingDrag, getMimeTypes(description));
        }

        if (!mIsHandlingDrag) {
@@ -163,31 +186,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
                mDragLayout.update(event);
                break;
            case ACTION_DROP: {
                final SurfaceControl dragSurface = event.getDragSurface();
                final View dragLayout = mDragLayout;
                final ClipData data = event.getClipData();
                return mDragLayout.drop(event, dragSurface, (dropTargetBounds) -> {
                    if (dropTargetBounds != null) {
                        // TODO(b/169894807): Properly handle the drop, for now just launch it
                        if (data.getItemCount() > 0) {
                            Intent intent = data.getItemAt(0).getIntent();
                            PendingIntent pi = intent.getParcelableExtra(
                                    ClipDescription.EXTRA_PENDING_INTENT);
                            try {
                                pi.send();
                            } catch (PendingIntent.CanceledException e) {
                                Slog.e(TAG, "Failed to launch activity", e);
                            }
                        }
                    }

                    setDropTargetWindowVisibility(pd, View.INVISIBLE);
                    pd.dropTarget.removeView(dragLayout);

                    // Clean up the drag surface
                    mTransaction.reparent(dragSurface, null);
                    mTransaction.apply();
                });
                return handleDrop(event, pd);
            }
            case ACTION_DRAG_EXITED: {
                // Either one of DROP or EXITED will happen, and when EXITED we won't consume
@@ -211,6 +210,62 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
        return true;
    }

    /**
     * Handles dropping on the drop target.
     */
    private boolean handleDrop(DragEvent event, PerDisplay pd) {
        final ClipData data = event.getClipData();
        final ClipDescription description = event.getClipDescription();
        final SurfaceControl dragSurface = event.getDragSurface();
        final View dragLayout = mDragLayout;
        final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
        final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
        return mDragLayout.drop(event, dragSurface, (dropTargetBounds) -> {
            if (dropTargetBounds != null && data.getItemCount() > 0) {
                final Intent intent = data.getItemAt(0).getIntent();
                // TODO(b/169894807): Properly handle the drop, for now just launch it
                if (isTask) {
                    int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
                    try {
                        ActivityTaskManager.getService().startActivityFromRecents(
                                taskId, null);
                    } catch (RemoteException e) {
                        Slog.e(TAG, "Failed to launch task", e);
                    }
                } else if (isShortcut) {
                    try {
                        Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS)
                                ? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS)
                                : null;
                        LauncherApps launcherApps =
                                mContext.getSystemService(LauncherApps.class);
                        launcherApps.startShortcut(
                                intent.getStringExtra(EXTRA_PACKAGE_NAME),
                                intent.getStringExtra(EXTRA_SHORTCUT_ID),
                                null /* sourceBounds */, opts,
                                intent.getParcelableExtra(EXTRA_USER));
                    } catch (ActivityNotFoundException e) {
                        Slog.e(TAG, "Failed to launch shortcut", e);
                    }
                } else {
                    PendingIntent pi = intent.getParcelableExtra(EXTRA_PENDING_INTENT);
                    try {
                        pi.send();
                    } catch (PendingIntent.CanceledException e) {
                        Slog.e(TAG, "Failed to launch activity", e);
                    }
                }
            }

            setDropTargetWindowVisibility(pd, View.INVISIBLE);
            pd.dropTarget.removeView(dragLayout);

            // Clean up the drag surface
            mTransaction.reparent(dragSurface, null);
            mTransaction.apply();
        });
    }

    private void setDropTargetWindowVisibility(PerDisplay pd, int visibility) {
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
                "Set drop target window visibility: displayId=%d visibility=%d",
Loading