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 d8ec6508d77c0..063dadaa31c71 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 @@ -146,6 +146,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(() -> { @@ -159,7 +162,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. @@ -168,7 +171,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 e7d714e60076e..817c746e65965 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(