summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/pm/ILauncherApps.aidl2
-rw-r--r--core/java/android/content/pm/LauncherApps.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java66
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java16
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java67
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java2
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java6
9 files changed, 142 insertions, 34 deletions
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index cb8988eb5b92..08cfbf76a040 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -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,
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index e35c2f48038d..301d1bbc8e9d 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -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();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 5ebdceba135b..e8bae0f94bf0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -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,12 +110,19 @@ 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.
*/
@NonNull
@@ -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();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index 7307ba30fd67..d395f956a41c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -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);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
index 6080f3ae78e8..403dbf9d9554 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
@@ -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;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index 35e498262707..bb6026c36c97 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -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_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_TOP_OR_LEFT;
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_TOP;
+import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@@ -50,9 +53,11 @@ import android.app.ActivityTaskManager;
import android.app.PendingIntent;
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.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Insets;
@@ -177,6 +182,12 @@ public class DragAndDropPolicyTest {
info.configuration.windowConfiguration.setActivityType(actType);
info.configuration.windowConfiguration.setWindowingMode(winMode);
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;
}
@@ -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) {
for (Target t : targets) {
if (type == t.type) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java
index f10dc16fae5c..b976c1287aca 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java
@@ -24,8 +24,8 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
import android.testing.TestableLooper;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.wm.shell.common.ShellExecutor;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java
index 078e2b6cf574..16e92395c85e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java
@@ -45,8 +45,8 @@ import android.window.DisplayAreaOrganizer;
import android.window.IWindowContainerToken;
import android.window.WindowContainerToken;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index e65783865659..6b3ce773fb63 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -18,6 +18,7 @@ package com.android.server.pm;
import static android.app.ActivityOptions.KEY_SPLASH_SCREEN_THEME;
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.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
@@ -1218,8 +1219,9 @@ public class LauncherAppsService extends SystemService {
}
@Override
- public PendingIntent getActivityLaunchIntent(ComponentName component, Bundle opts,
+ public PendingIntent getActivityLaunchIntent(String callingPackage, ComponentName component,
UserHandle user) {
+ ensureShortcutPermission(callingPackage);
if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) {
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
// the calling user
return PendingIntent.getActivityAsUser(mContext, 0 /* requestCode */, launchIntent,
- FLAG_IMMUTABLE, null /* options */, user);
+ FLAG_MUTABLE, null /* opts */, user);
} finally {
Binder.restoreCallingIdentity(ident);
}