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

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

Merge "Allow dragging to launch multiple instances of the same activity"

parents 556e1ae1 f4ed441e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ 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,
    PendingIntent getActivityLaunchIntent(String callingPackage, in ComponentName component,
            in UserHandle user);
    void showAppDetailsAsUser(in IApplicationThread caller, String callingPackage,
            String callingFeatureId, in ComponentName component, in Rect sourceBounds,
+9 −4
Original line number Diff line number Diff line
@@ -749,24 +749,29 @@ public class LauncherApps {
    }

    /**
     * Returns a PendingIntent that would start the same activity started from
     * {@link #startMainActivity(ComponentName, UserHandle, Rect, Bundle)}.
     * Returns a mutable PendingIntent that would start the same activity started from
     * {@link #startMainActivity(ComponentName, UserHandle, Rect, Bundle)}.  The caller needs to
     * take care in ensuring that the mutable intent returned is not passed to untrusted parties.
     *
     * @param component The ComponentName of the activity to launch
     * @param startActivityOptions This parameter is no longer supported
     * @param user The UserHandle of the profile
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS)
    @Nullable
    public PendingIntent getMainActivityLaunchIntent(@NonNull ComponentName component,
            @Nullable Bundle startActivityOptions, @NonNull UserHandle user) {
        if (mContext.checkSelfPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS)
                != PackageManager.PERMISSION_GRANTED) {
            Log.w(TAG, "Only allowed for recents.");
        }
        logErrorForInvalidProfileAccess(user);
        if (DEBUG) {
            Log.i(TAG, "GetMainActivityLaunchIntent " + component + " " + user);
        }
        try {
            // due to b/209607104, startActivityOptions will be ignored
            return mService.getActivityLaunchIntent(component, null /* opts */, user);
            return mService.getActivityLaunchIntent(mContext.getPackageName(), component, user);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
+56 −10
Original line number Diff line number Diff line
@@ -45,10 +45,12 @@ import android.app.WindowConfiguration;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.ResolveInfo;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Bundle;
@@ -62,9 +64,11 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;

import com.android.internal.logging.InstanceId;
import com.android.internal.protolog.common.ProtoLog;
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.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;

import java.lang.annotation.Retention;
@@ -106,11 +110,18 @@ public class DragAndDropPolicy {
     */
    void start(DisplayLayout displayLayout, ClipData data, InstanceId loggerSessionId) {
        mLoggerSessionId = loggerSessionId;
        mSession = new DragSession(mContext, mActivityTaskManager, displayLayout, data);
        mSession = new DragSession(mActivityTaskManager, displayLayout, data);
        // TODO(b/169894807): Also update the session data with task stack changes
        mSession.update();
    }

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

    /**
     * Returns the target's regions based on the current state of the device and display.
     */
@@ -248,32 +259,68 @@ public class DragAndDropPolicy {
            final UserHandle user = intent.getParcelableExtra(EXTRA_USER);
            mStarter.startShortcut(packageName, id, position, opts, user);
        } else {
            mStarter.startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT),
                    null, position, opts);
            final PendingIntent launchIntent = intent.getParcelableExtra(EXTRA_PENDING_INTENT);
            mStarter.startIntent(launchIntent, getStartIntentFillInIntent(launchIntent, position),
                    position, opts);
        }
    }

    /**
     * Returns the fill-in intent to use when starting an app from a drop.
     */
    @VisibleForTesting
    Intent getStartIntentFillInIntent(PendingIntent launchIntent, @SplitPosition int position) {
        // Get the drag app
        final List<ResolveInfo> infos = launchIntent.queryIntentComponents(0 /* flags */);
        final ComponentName dragIntentActivity = !infos.isEmpty()
                ? infos.get(0).activityInfo.getComponentName()
                : null;

        // Get the current app (either fullscreen or the remaining app post-drop if in splitscreen)
        final boolean inSplitScreen = mSplitScreen != null
                && mSplitScreen.isSplitScreenVisible();
        final ComponentName currentActivity;
        if (!inSplitScreen) {
            currentActivity = mSession.runningTaskInfo != null
                    ? mSession.runningTaskInfo.baseActivity
                    : null;
        } else {
            final int nonReplacedSplitPosition = position == SPLIT_POSITION_TOP_OR_LEFT
                    ? SPLIT_POSITION_BOTTOM_OR_RIGHT
                    : SPLIT_POSITION_TOP_OR_LEFT;
            ActivityManager.RunningTaskInfo nonReplacedTaskInfo =
                    mSplitScreen.getTaskInfo(nonReplacedSplitPosition);
            currentActivity = nonReplacedTaskInfo.baseActivity;
        }

        if (currentActivity.equals(dragIntentActivity)) {
            // Only apply MULTIPLE_TASK if we are dragging the same activity
            final Intent fillInIntent = new Intent();
            fillInIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Adding MULTIPLE_TASK");
            return fillInIntent;
        }
        return null;
    }

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

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

        DragSession(Context context, ActivityTaskManager activityTaskManager,
        DragSession(ActivityTaskManager activityTaskManager,
                DisplayLayout dispLayout, ClipData data) {
            mContext = context;
            mActivityTaskManager = activityTaskManager;
            mInitialDragData = data;
            displayLayout = dispLayout;
@@ -287,10 +334,9 @@ public class DragAndDropPolicy {
                    mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
            if (!tasks.isEmpty()) {
                final ActivityManager.RunningTaskInfo task = tasks.get(0);
                runningTaskInfo = task;
                runningTaskWinMode = task.getWindowingMode();
                runningTaskActType = task.getActivityType();
                runningTaskId = task.taskId;
                runningTaskIsResizeable = task.isResizeable;
            }

            final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
+2 −14
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.StatusBarManager;
import android.content.ClipData;
import android.content.Context;
@@ -35,7 +34,6 @@ import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
import android.view.DragEvent;
import android.view.SurfaceControl;
import android.view.WindowInsets;
@@ -51,7 +49,6 @@ import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;

import java.util.ArrayList;
import java.util.List;

/**
 * Coordinates the visible drop targets for the current drag.
@@ -166,17 +163,8 @@ public class DragLayout extends LinearLayout {
        boolean alreadyInSplit = mSplitScreenController != null
                && mSplitScreenController.isSplitScreenVisible();
        if (!alreadyInSplit) {
            List<ActivityManager.RunningTaskInfo> tasks = null;
            // Figure out the splashscreen info for the existing task.
            try {
                tasks = ActivityTaskManager.getService().getTasks(1,
                        false /* filterOnlyVisibleRecents */,
                        false /* keepIntentExtra */);
            } catch (RemoteException e) {
                // don't show an icon / will just use the defaults
            }
            if (tasks != null && !tasks.isEmpty()) {
                ActivityManager.RunningTaskInfo taskInfo1 = tasks.get(0);
            ActivityManager.RunningTaskInfo taskInfo1 = mPolicy.getLatestRunningTask();
            if (taskInfo1 != null) {
                Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo);
                int bgColor1 = getResizingBackgroundColor(taskInfo1);
                mDropZoneView1.setAppInfo(bgColor1, icon1);
+1 −1
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@ import android.content.Context;
import android.hardware.display.DisplayManager;
import android.testing.TestableContext;

import androidx.test.InstrumentationRegistry;
import androidx.test.platform.app.InstrumentationRegistry;

import org.junit.After;
import org.junit.Before;
Loading