diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index 7d65a08ce7980..1861e48482b87 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -118,15 +118,15 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
*
* @param shortcut the shortcut used to launch the activity.
* @param options options for the activity.
- * @param sourceBounds the rect containing the source bounds of the clicked icon to open
- * this shortcut.
+ * @param launchBounds the bounds (window size and position) that the activity should be
+ * launched in, in pixels and in screen coordinates.
*/
public void startShortcutActivity(@NonNull ShortcutInfo shortcut,
- @NonNull ActivityOptions options, @Nullable Rect sourceBounds) {
- prepareActivityOptions(options);
+ @NonNull ActivityOptions options, @Nullable Rect launchBounds) {
+ prepareActivityOptions(options, launchBounds);
LauncherApps service = mContext.getSystemService(LauncherApps.class);
try {
- service.startShortcut(shortcut, sourceBounds, options.toBundle());
+ service.startShortcut(shortcut, null /* sourceBounds */, options.toBundle());
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -138,10 +138,12 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
* @param pendingIntent Intent used to launch an activity.
* @param fillInIntent Additional Intent data, see {@link Intent#fillIn Intent.fillIn()}
* @param options options for the activity.
+ * @param launchBounds the bounds (window size and position) that the activity should be
+ * launched in, in pixels and in screen coordinates.
*/
public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent,
- @NonNull ActivityOptions options) {
- prepareActivityOptions(options);
+ @NonNull ActivityOptions options, @Nullable Rect launchBounds) {
+ prepareActivityOptions(options, launchBounds);
try {
pendingIntent.send(mContext, 0 /* code */, fillInIntent,
null /* onFinished */, null /* handler */, null /* requiredPermission */,
@@ -151,11 +153,12 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
}
}
- private void prepareActivityOptions(ActivityOptions options) {
+ private void prepareActivityOptions(ActivityOptions options, Rect launchBounds) {
final Binder launchCookie = new Binder();
mShellExecutor.execute(() -> {
mTaskOrganizer.setPendingLaunchCookieListener(launchCookie, this);
});
+ options.setLaunchBounds(launchBounds);
options.setLaunchCookie(launchCookie);
options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
options.setRemoveWithTaskOrganizer(true);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 6a68b06527bea..51964b4031ec8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -153,6 +153,9 @@ public class BubbleExpandedView extends LinearLayout {
ActivityOptions options = ActivityOptions.makeCustomAnimation(getContext(),
0 /* enterResId */, 0 /* exitResId */);
+ Rect launchBounds = new Rect();
+ mTaskView.getBoundsOnScreen(launchBounds);
+
// TODO: I notice inconsistencies in lifecycle
// Post to keep the lifecycle normal
post(() -> {
@@ -166,7 +169,7 @@ public class BubbleExpandedView extends LinearLayout {
if (!mIsOverflow && mBubble.hasMetadataShortcutId()) {
options.setApplyActivityFlagsForBubbles(true);
mTaskView.startShortcutActivity(mBubble.getShortcutInfo(),
- options, null /* sourceBounds */);
+ options, launchBounds);
} else {
Intent fillInIntent = new Intent();
// Apply flags to make behaviour match documentLaunchMode=always.
@@ -175,7 +178,8 @@ public class BubbleExpandedView extends LinearLayout {
if (mBubble != null) {
mBubble.setIntentActive();
}
- mTaskView.startActivity(mPendingIntent, fillInIntent, options);
+ mTaskView.startActivity(mPendingIntent, fillInIntent, options,
+ launchBounds);
}
} catch (RuntimeException e) {
// If there's a runtime exception here then there's something
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
index 4e582c2420949..20ac5bf8fa84d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
@@ -36,6 +36,7 @@ import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.content.Context;
+import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.SurfaceControl;
@@ -125,7 +126,7 @@ public class TaskViewTest extends ShellTestCase {
@Test
public void testStartActivity() {
ActivityOptions options = ActivityOptions.makeBasic();
- mTaskView.startActivity(mock(PendingIntent.class), null, options);
+ mTaskView.startActivity(mock(PendingIntent.class), null, options, new Rect(0, 0, 100, 100));
verify(mOrganizer).setPendingLaunchCookieListener(any(), eq(mTaskView));
assertThat(options.getLaunchWindowingMode()).isEqualTo(WINDOWING_MODE_MULTI_WINDOW);
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b292d7e291711..031e80f58ed93 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1333,6 +1333,7 @@
22sp
14sp
52dp
+ 52dp
100dp
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index 9c788df362de8..06fbf734d1c47 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -24,6 +24,7 @@ import android.app.PendingIntent
import android.content.ComponentName
import android.content.Context
import android.content.Intent
+import android.graphics.Rect
import android.view.View
import android.view.ViewGroup
import android.view.WindowInsets
@@ -83,8 +84,9 @@ class DetailDialog(
taskView.startActivity(
PendingIntent.getActivity(context, 0, launchIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE),
- null,
- options
+ null /* fillInIntent */,
+ options,
+ getTaskViewBounds()
)
}
@@ -159,6 +161,23 @@ class DetailDialog(
taskView.setListener(cvh.uiExecutor, stateCallback)
}
+ fun getTaskViewBounds(): Rect {
+ val wm = context.getSystemService(WindowManager::class.java)
+ val windowMetrics = wm.getCurrentWindowMetrics()
+ val rect = windowMetrics.bounds
+ val metricInsets = windowMetrics.windowInsets
+ val insets = metricInsets.getInsetsIgnoringVisibility(Type.systemBars()
+ or Type.displayCutout())
+ val headerHeight = context.resources.getDimensionPixelSize(
+ R.dimen.controls_detail_dialog_header_height)
+
+ val finalRect = Rect(rect.left - insets.left /* left */,
+ rect.top + insets.top + headerHeight /* top */,
+ rect.right - insets.right /* right */,
+ rect.bottom - insets.bottom /* bottom */)
+ return finalRect
+ }
+
override fun dismiss() {
if (!isShowing()) return
taskView.release()
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index 285145a7fb078..3793e4b500ba2 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -160,8 +160,7 @@ class LaunchParamsController {
return false;
}
- if (task.getRootTask().inFreeformWindowingMode()) {
- // Only set bounds if it's in freeform mode.
+ if (task.getRootTask().inMultiWindowMode()) {
task.setBounds(mTmpParams.mBounds);
return true;
}
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index cc0471c30f5f4..f43cd7a80ede6 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
@@ -195,6 +196,11 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
} else {
if (DEBUG) appendLog("empty-window-layout");
}
+ } else if (launchMode == WINDOWING_MODE_MULTI_WINDOW
+ && options != null && options.getLaunchBounds() != null) {
+ outParams.mBounds.set(options.getLaunchBounds());
+ hasInitialBounds = true;
+ if (DEBUG) appendLog("multiwindow-activity-options-bounds=" + outParams.mBounds);
}
// STEP 2.2: Check if previous modifier or the controller (referred as "callers" below) has
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index a55150dbd6b10..fc298b0d96a15 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.Display.INVALID_DISPLAY;
@@ -371,6 +372,29 @@ public class LaunchParamsControllerTests extends WindowTestsBase {
assertEquals(expected, task.getRequestedOverrideBounds());
}
+ /**
+ * Ensures that {@link LaunchParamsModifier} requests specifying bounds during
+ * layout are honored if window is in multiwindow mode.
+ */
+ @Test
+ public void testLayoutTaskBoundsChangeMultiWindow() {
+ final Rect expected = new Rect(10, 20, 30, 40);
+
+ final LaunchParams params = new LaunchParams();
+ params.mWindowingMode = WINDOWING_MODE_MULTI_WINDOW;
+ params.mBounds.set(expected);
+ final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
+ final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build();
+
+ mController.registerModifier(positioner);
+
+ assertNotEquals(expected, task.getBounds());
+
+ mController.layoutTask(task, null /* windowLayout */);
+
+ assertEquals(expected, task.getRequestedOverrideBounds());
+ }
+
/**
* Ensures that {@link LaunchParamsModifier} requests specifying bounds during
* layout are set to last non-fullscreen bounds.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 7b0643e5ef944..5e4c67ce9e5c0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
@@ -926,6 +927,25 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase {
assertEquals(expected, mResult.mBounds);
}
+ @Test
+ public void testKeepsBoundsForMultiWindowModeInOptions() {
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
+ WINDOWING_MODE_FULLSCREEN);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+
+ final Rect expected = new Rect(0, 0, 100, 100);
+ options.setLaunchBounds(expected);
+
+ mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
+
+ assertEquals(RESULT_CONTINUE,
+ new CalculateRequestBuilder().setOptions(options).calculate());
+
+ assertEquals(expected, mResult.mBounds);
+ }
+
@Test
public void testRespectsLaunchBoundsWithFreeformSourceOnFullscreenDisplay() {
final TestDisplayContent fullscreenDisplay = createNewDisplayContent(