Allow dragging to launch multiple instances of the same activity
- When dragging to launch a new app, apply MULTIPLE_TASK to the launch intent to allow apps that support it to show side-by-side - This requires the pending intent resolved from LauncherAppsService to be mutable (should be ok since we only use this api from SysUI) - Also remove some unused members and duplication of getting the running task when dragging Bug: 207686016 Test: atest WMShellUnitTests Change-Id: Ib233ad754a6c6e3c4e0d0e10ed788ab8e055cccc
This commit is contained in:
@@ -58,7 +58,7 @@ interface ILauncherApps {
|
|||||||
void startActivityAsUser(in IApplicationThread caller, String callingPackage,
|
void startActivityAsUser(in IApplicationThread caller, String callingPackage,
|
||||||
String callingFeatureId, in ComponentName component, in Rect sourceBounds,
|
String callingFeatureId, in ComponentName component, in Rect sourceBounds,
|
||||||
in Bundle opts, in UserHandle user);
|
in Bundle opts, in UserHandle user);
|
||||||
PendingIntent getActivityLaunchIntent(in ComponentName component, in Bundle opts,
|
PendingIntent getActivityLaunchIntent(String callingPackage, in ComponentName component,
|
||||||
in UserHandle user);
|
in UserHandle user);
|
||||||
void showAppDetailsAsUser(in IApplicationThread caller, String callingPackage,
|
void showAppDetailsAsUser(in IApplicationThread caller, String callingPackage,
|
||||||
String callingFeatureId, in ComponentName component, in Rect sourceBounds,
|
String callingFeatureId, in ComponentName component, in Rect sourceBounds,
|
||||||
|
|||||||
@@ -749,24 +749,29 @@ public class LauncherApps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a PendingIntent that would start the same activity started from
|
* Returns a mutable PendingIntent that would start the same activity started from
|
||||||
* {@link #startMainActivity(ComponentName, UserHandle, Rect, Bundle)}.
|
* {@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 component The ComponentName of the activity to launch
|
||||||
* @param startActivityOptions This parameter is no longer supported
|
* @param startActivityOptions This parameter is no longer supported
|
||||||
* @param user The UserHandle of the profile
|
* @param user The UserHandle of the profile
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
|
@RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS)
|
||||||
@Nullable
|
@Nullable
|
||||||
public PendingIntent getMainActivityLaunchIntent(@NonNull ComponentName component,
|
public PendingIntent getMainActivityLaunchIntent(@NonNull ComponentName component,
|
||||||
@Nullable Bundle startActivityOptions, @NonNull UserHandle user) {
|
@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);
|
logErrorForInvalidProfileAccess(user);
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.i(TAG, "GetMainActivityLaunchIntent " + component + " " + user);
|
Log.i(TAG, "GetMainActivityLaunchIntent " + component + " " + user);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// due to b/209607104, startActivityOptions will be ignored
|
return mService.getActivityLaunchIntent(mContext.getPackageName(), component, user);
|
||||||
return mService.getActivityLaunchIntent(component, null /* opts */, user);
|
|
||||||
} catch (RemoteException re) {
|
} catch (RemoteException re) {
|
||||||
throw re.rethrowFromSystemServer();
|
throw re.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,10 +45,12 @@ import android.app.WindowConfiguration;
|
|||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.ClipDescription;
|
import android.content.ClipDescription;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.content.pm.LauncherApps;
|
import android.content.pm.LauncherApps;
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
import android.graphics.Insets;
|
import android.graphics.Insets;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -62,9 +64,11 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.android.internal.logging.InstanceId;
|
import com.android.internal.logging.InstanceId;
|
||||||
|
import com.android.internal.protolog.common.ProtoLog;
|
||||||
import com.android.wm.shell.R;
|
import com.android.wm.shell.R;
|
||||||
import com.android.wm.shell.common.DisplayLayout;
|
import com.android.wm.shell.common.DisplayLayout;
|
||||||
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
|
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
|
||||||
|
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
@@ -106,11 +110,18 @@ public class DragAndDropPolicy {
|
|||||||
*/
|
*/
|
||||||
void start(DisplayLayout displayLayout, ClipData data, InstanceId loggerSessionId) {
|
void start(DisplayLayout displayLayout, ClipData data, InstanceId loggerSessionId) {
|
||||||
mLoggerSessionId = 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
|
// TODO(b/169894807): Also update the session data with task stack changes
|
||||||
mSession.update();
|
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.
|
* 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);
|
final UserHandle user = intent.getParcelableExtra(EXTRA_USER);
|
||||||
mStarter.startShortcut(packageName, id, position, opts, user);
|
mStarter.startShortcut(packageName, id, position, opts, user);
|
||||||
} else {
|
} else {
|
||||||
mStarter.startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT),
|
final PendingIntent launchIntent = intent.getParcelableExtra(EXTRA_PENDING_INTENT);
|
||||||
null, position, opts);
|
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.
|
* Per-drag session data.
|
||||||
*/
|
*/
|
||||||
private static class DragSession {
|
private static class DragSession {
|
||||||
private final Context mContext;
|
|
||||||
private final ActivityTaskManager mActivityTaskManager;
|
private final ActivityTaskManager mActivityTaskManager;
|
||||||
private final ClipData mInitialDragData;
|
private final ClipData mInitialDragData;
|
||||||
|
|
||||||
final DisplayLayout displayLayout;
|
final DisplayLayout displayLayout;
|
||||||
Intent dragData;
|
Intent dragData;
|
||||||
int runningTaskId;
|
ActivityManager.RunningTaskInfo runningTaskInfo;
|
||||||
@WindowConfiguration.WindowingMode
|
@WindowConfiguration.WindowingMode
|
||||||
int runningTaskWinMode = WINDOWING_MODE_UNDEFINED;
|
int runningTaskWinMode = WINDOWING_MODE_UNDEFINED;
|
||||||
@WindowConfiguration.ActivityType
|
@WindowConfiguration.ActivityType
|
||||||
int runningTaskActType = ACTIVITY_TYPE_STANDARD;
|
int runningTaskActType = ACTIVITY_TYPE_STANDARD;
|
||||||
boolean runningTaskIsResizeable;
|
|
||||||
boolean dragItemSupportsSplitscreen;
|
boolean dragItemSupportsSplitscreen;
|
||||||
|
|
||||||
DragSession(Context context, ActivityTaskManager activityTaskManager,
|
DragSession(ActivityTaskManager activityTaskManager,
|
||||||
DisplayLayout dispLayout, ClipData data) {
|
DisplayLayout dispLayout, ClipData data) {
|
||||||
mContext = context;
|
|
||||||
mActivityTaskManager = activityTaskManager;
|
mActivityTaskManager = activityTaskManager;
|
||||||
mInitialDragData = data;
|
mInitialDragData = data;
|
||||||
displayLayout = dispLayout;
|
displayLayout = dispLayout;
|
||||||
@@ -287,10 +334,9 @@ public class DragAndDropPolicy {
|
|||||||
mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
|
mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
|
||||||
if (!tasks.isEmpty()) {
|
if (!tasks.isEmpty()) {
|
||||||
final ActivityManager.RunningTaskInfo task = tasks.get(0);
|
final ActivityManager.RunningTaskInfo task = tasks.get(0);
|
||||||
|
runningTaskInfo = task;
|
||||||
runningTaskWinMode = task.getWindowingMode();
|
runningTaskWinMode = task.getWindowingMode();
|
||||||
runningTaskActType = task.getActivityType();
|
runningTaskActType = task.getActivityType();
|
||||||
runningTaskId = task.taskId;
|
|
||||||
runningTaskIsResizeable = task.isResizeable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
|
final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import android.animation.Animator;
|
|||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.ActivityTaskManager;
|
|
||||||
import android.app.StatusBarManager;
|
import android.app.StatusBarManager;
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -35,7 +34,6 @@ import android.graphics.Color;
|
|||||||
import android.graphics.Insets;
|
import android.graphics.Insets;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.view.DragEvent;
|
import android.view.DragEvent;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
@@ -51,7 +49,6 @@ import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
|||||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Coordinates the visible drop targets for the current drag.
|
* Coordinates the visible drop targets for the current drag.
|
||||||
@@ -166,17 +163,8 @@ public class DragLayout extends LinearLayout {
|
|||||||
boolean alreadyInSplit = mSplitScreenController != null
|
boolean alreadyInSplit = mSplitScreenController != null
|
||||||
&& mSplitScreenController.isSplitScreenVisible();
|
&& mSplitScreenController.isSplitScreenVisible();
|
||||||
if (!alreadyInSplit) {
|
if (!alreadyInSplit) {
|
||||||
List<ActivityManager.RunningTaskInfo> tasks = null;
|
ActivityManager.RunningTaskInfo taskInfo1 = mPolicy.getLatestRunningTask();
|
||||||
// Figure out the splashscreen info for the existing task.
|
if (taskInfo1 != null) {
|
||||||
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);
|
|
||||||
Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo);
|
Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo);
|
||||||
int bgColor1 = getResizingBackgroundColor(taskInfo1);
|
int bgColor1 = getResizingBackgroundColor(taskInfo1);
|
||||||
mDropZoneView1.setAppInfo(bgColor1, icon1);
|
mDropZoneView1.setAppInfo(bgColor1, icon1);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import android.content.Context;
|
|||||||
import android.hardware.display.DisplayManager;
|
import android.hardware.display.DisplayManager;
|
||||||
import android.testing.TestableContext;
|
import android.testing.TestableContext;
|
||||||
|
|
||||||
import androidx.test.InstrumentationRegistry;
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
|
|||||||
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
|
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
|
||||||
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
|
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
|
||||||
|
|
||||||
|
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||||
|
|
||||||
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
|
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
|
||||||
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
|
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
|
||||||
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
|
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
|
||||||
@@ -32,6 +34,7 @@ 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_RIGHT;
|
||||||
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
|
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertNull;
|
||||||
import static junit.framework.Assert.assertTrue;
|
import static junit.framework.Assert.assertTrue;
|
||||||
import static junit.framework.Assert.fail;
|
import static junit.framework.Assert.fail;
|
||||||
|
|
||||||
@@ -50,9 +53,11 @@ import android.app.ActivityTaskManager;
|
|||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.ClipDescription;
|
import android.content.ClipDescription;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Insets;
|
import android.graphics.Insets;
|
||||||
@@ -177,6 +182,12 @@ public class DragAndDropPolicyTest {
|
|||||||
info.configuration.windowConfiguration.setActivityType(actType);
|
info.configuration.windowConfiguration.setActivityType(actType);
|
||||||
info.configuration.windowConfiguration.setWindowingMode(winMode);
|
info.configuration.windowConfiguration.setWindowingMode(winMode);
|
||||||
info.isResizeable = true;
|
info.isResizeable = true;
|
||||||
|
info.baseActivity = new ComponentName(getInstrumentation().getContext().getPackageName(),
|
||||||
|
".ActivityWithMode" + winMode);
|
||||||
|
ActivityInfo activityInfo = new ActivityInfo();
|
||||||
|
activityInfo.packageName = info.baseActivity.getPackageName();
|
||||||
|
activityInfo.name = info.baseActivity.getClassName();
|
||||||
|
info.topActivityInfo = activityInfo;
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,6 +263,62 @@ public class DragAndDropPolicyTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLaunchMultipleTask_differentActivity() {
|
||||||
|
setRunningTask(mFullscreenAppTask);
|
||||||
|
mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
|
||||||
|
Intent fillInIntent = mPolicy.getStartIntentFillInIntent(mock(PendingIntent.class), 0);
|
||||||
|
assertNull(fillInIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLaunchMultipleTask_differentActivity_inSplitscreen() {
|
||||||
|
setRunningTask(mFullscreenAppTask);
|
||||||
|
doReturn(true).when(mSplitScreenStarter).isSplitScreenVisible();
|
||||||
|
doReturn(mFullscreenAppTask).when(mSplitScreenStarter).getTaskInfo(anyInt());
|
||||||
|
mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
|
||||||
|
Intent fillInIntent = mPolicy.getStartIntentFillInIntent(mock(PendingIntent.class), 0);
|
||||||
|
assertNull(fillInIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLaunchMultipleTask_sameActivity() {
|
||||||
|
setRunningTask(mFullscreenAppTask);
|
||||||
|
|
||||||
|
// Replace the mocked drag pending intent and ensure it resolves to the same activity
|
||||||
|
PendingIntent launchIntent = mock(PendingIntent.class);
|
||||||
|
ResolveInfo launchInfo = new ResolveInfo();
|
||||||
|
launchInfo.activityInfo = mFullscreenAppTask.topActivityInfo;
|
||||||
|
doReturn(Collections.singletonList(launchInfo))
|
||||||
|
.when(launchIntent).queryIntentComponents(anyInt());
|
||||||
|
mActivityClipData.getItemAt(0).getIntent().putExtra(ClipDescription.EXTRA_PENDING_INTENT,
|
||||||
|
launchIntent);
|
||||||
|
|
||||||
|
mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
|
||||||
|
Intent fillInIntent = mPolicy.getStartIntentFillInIntent(launchIntent, 0);
|
||||||
|
assertTrue((fillInIntent.getFlags() & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLaunchMultipleTask_sameActivity_inSplitScreen() {
|
||||||
|
setRunningTask(mFullscreenAppTask);
|
||||||
|
|
||||||
|
// Replace the mocked drag pending intent and ensure it resolves to the same activity
|
||||||
|
PendingIntent launchIntent = mock(PendingIntent.class);
|
||||||
|
ResolveInfo launchInfo = new ResolveInfo();
|
||||||
|
launchInfo.activityInfo = mFullscreenAppTask.topActivityInfo;
|
||||||
|
doReturn(Collections.singletonList(launchInfo))
|
||||||
|
.when(launchIntent).queryIntentComponents(anyInt());
|
||||||
|
mActivityClipData.getItemAt(0).getIntent().putExtra(ClipDescription.EXTRA_PENDING_INTENT,
|
||||||
|
launchIntent);
|
||||||
|
|
||||||
|
doReturn(true).when(mSplitScreenStarter).isSplitScreenVisible();
|
||||||
|
doReturn(mFullscreenAppTask).when(mSplitScreenStarter).getTaskInfo(anyInt());
|
||||||
|
mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
|
||||||
|
Intent fillInIntent = mPolicy.getStartIntentFillInIntent(launchIntent, 0);
|
||||||
|
assertTrue((fillInIntent.getFlags() & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
private Target filterTargetByType(ArrayList<Target> targets, int type) {
|
private Target filterTargetByType(ArrayList<Target> targets, int type) {
|
||||||
for (Target t : targets) {
|
for (Target t : targets) {
|
||||||
if (type == t.type) {
|
if (type == t.type) {
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ import android.testing.AndroidTestingRunner;
|
|||||||
import android.testing.TestableContext;
|
import android.testing.TestableContext;
|
||||||
import android.testing.TestableLooper;
|
import android.testing.TestableLooper;
|
||||||
|
|
||||||
import androidx.test.InstrumentationRegistry;
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
|
|
||||||
import com.android.wm.shell.common.ShellExecutor;
|
import com.android.wm.shell.common.ShellExecutor;
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ import android.window.DisplayAreaOrganizer;
|
|||||||
import android.window.IWindowContainerToken;
|
import android.window.IWindowContainerToken;
|
||||||
import android.window.WindowContainerToken;
|
import android.window.WindowContainerToken;
|
||||||
|
|
||||||
import androidx.test.InstrumentationRegistry;
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
|
|
||||||
import com.android.wm.shell.common.DisplayController;
|
import com.android.wm.shell.common.DisplayController;
|
||||||
import com.android.wm.shell.common.DisplayLayout;
|
import com.android.wm.shell.common.DisplayLayout;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.server.pm;
|
|||||||
|
|
||||||
import static android.app.ActivityOptions.KEY_SPLASH_SCREEN_THEME;
|
import static android.app.ActivityOptions.KEY_SPLASH_SCREEN_THEME;
|
||||||
import static android.app.PendingIntent.FLAG_IMMUTABLE;
|
import static android.app.PendingIntent.FLAG_IMMUTABLE;
|
||||||
|
import static android.app.PendingIntent.FLAG_MUTABLE;
|
||||||
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
|
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
|
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
|
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
|
||||||
@@ -1218,8 +1219,9 @@ public class LauncherAppsService extends SystemService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PendingIntent getActivityLaunchIntent(ComponentName component, Bundle opts,
|
public PendingIntent getActivityLaunchIntent(String callingPackage, ComponentName component,
|
||||||
UserHandle user) {
|
UserHandle user) {
|
||||||
|
ensureShortcutPermission(callingPackage);
|
||||||
if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) {
|
if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) {
|
||||||
throw new ActivityNotFoundException("Activity could not be found");
|
throw new ActivityNotFoundException("Activity could not be found");
|
||||||
}
|
}
|
||||||
@@ -1237,7 +1239,7 @@ public class LauncherAppsService extends SystemService {
|
|||||||
// calling identity to mirror the startActivityAsUser() call which does not validate
|
// calling identity to mirror the startActivityAsUser() call which does not validate
|
||||||
// the calling user
|
// the calling user
|
||||||
return PendingIntent.getActivityAsUser(mContext, 0 /* requestCode */, launchIntent,
|
return PendingIntent.getActivityAsUser(mContext, 0 /* requestCode */, launchIntent,
|
||||||
FLAG_IMMUTABLE, null /* options */, user);
|
FLAG_MUTABLE, null /* opts */, user);
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(ident);
|
Binder.restoreCallingIdentity(ident);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user