Fix transitions in the background when launching something in TaskView
* Allow bounds to be set on launch params for multiwindow activities * Users of TaskView should pass bounds when starting an activity otherwise they will see this animation * Modify bubbles & controls to pass launch bounds Test: atest TaskLaunchParamsModifierTests LaunchParamsControllerTests MultiWindowTests Bug: 182299605 Bug: 182516248 Change-Id: Ie5337593d776309f8aac0c6991cf846463e519a7
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1333,6 +1333,7 @@
|
||||
<dimen name="controls_setup_title">22sp</dimen>
|
||||
<dimen name="controls_setup_subtitle">14sp</dimen>
|
||||
<dimen name="controls_setup_vertical_padding">52dp</dimen>
|
||||
<dimen name="controls_detail_dialog_header_height">52dp</dimen>
|
||||
|
||||
<!-- Home Controls activity view detail panel-->
|
||||
<dimen name="controls_activity_view_top_offset">100dp</dimen>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user