Merge "Fix transitions in the background when launching something in TaskView" into sc-dev

This commit is contained in:
Mady Mellor
2021-05-20 22:55:00 +00:00
committed by Android (Google) Code Review
9 changed files with 92 additions and 15 deletions

View File

@@ -118,15 +118,15 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
* *
* @param shortcut the shortcut used to launch the activity. * @param shortcut the shortcut used to launch the activity.
* @param options options for the activity. * @param options options for the activity.
* @param sourceBounds the rect containing the source bounds of the clicked icon to open * @param launchBounds the bounds (window size and position) that the activity should be
* this shortcut. * launched in, in pixels and in screen coordinates.
*/ */
public void startShortcutActivity(@NonNull ShortcutInfo shortcut, public void startShortcutActivity(@NonNull ShortcutInfo shortcut,
@NonNull ActivityOptions options, @Nullable Rect sourceBounds) { @NonNull ActivityOptions options, @Nullable Rect launchBounds) {
prepareActivityOptions(options); prepareActivityOptions(options, launchBounds);
LauncherApps service = mContext.getSystemService(LauncherApps.class); LauncherApps service = mContext.getSystemService(LauncherApps.class);
try { try {
service.startShortcut(shortcut, sourceBounds, options.toBundle()); service.startShortcut(shortcut, null /* sourceBounds */, options.toBundle());
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(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 pendingIntent Intent used to launch an activity.
* @param fillInIntent Additional Intent data, see {@link Intent#fillIn Intent.fillIn()} * @param fillInIntent Additional Intent data, see {@link Intent#fillIn Intent.fillIn()}
* @param options options for the activity. * @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, public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent,
@NonNull ActivityOptions options) { @NonNull ActivityOptions options, @Nullable Rect launchBounds) {
prepareActivityOptions(options); prepareActivityOptions(options, launchBounds);
try { try {
pendingIntent.send(mContext, 0 /* code */, fillInIntent, pendingIntent.send(mContext, 0 /* code */, fillInIntent,
null /* onFinished */, null /* handler */, null /* requiredPermission */, 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(); final Binder launchCookie = new Binder();
mShellExecutor.execute(() -> { mShellExecutor.execute(() -> {
mTaskOrganizer.setPendingLaunchCookieListener(launchCookie, this); mTaskOrganizer.setPendingLaunchCookieListener(launchCookie, this);
}); });
options.setLaunchBounds(launchBounds);
options.setLaunchCookie(launchCookie); options.setLaunchCookie(launchCookie);
options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW); options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
options.setRemoveWithTaskOrganizer(true); options.setRemoveWithTaskOrganizer(true);

View File

@@ -153,6 +153,9 @@ public class BubbleExpandedView extends LinearLayout {
ActivityOptions options = ActivityOptions.makeCustomAnimation(getContext(), ActivityOptions options = ActivityOptions.makeCustomAnimation(getContext(),
0 /* enterResId */, 0 /* exitResId */); 0 /* enterResId */, 0 /* exitResId */);
Rect launchBounds = new Rect();
mTaskView.getBoundsOnScreen(launchBounds);
// TODO: I notice inconsistencies in lifecycle // TODO: I notice inconsistencies in lifecycle
// Post to keep the lifecycle normal // Post to keep the lifecycle normal
post(() -> { post(() -> {
@@ -166,7 +169,7 @@ public class BubbleExpandedView extends LinearLayout {
if (!mIsOverflow && mBubble.hasMetadataShortcutId()) { if (!mIsOverflow && mBubble.hasMetadataShortcutId()) {
options.setApplyActivityFlagsForBubbles(true); options.setApplyActivityFlagsForBubbles(true);
mTaskView.startShortcutActivity(mBubble.getShortcutInfo(), mTaskView.startShortcutActivity(mBubble.getShortcutInfo(),
options, null /* sourceBounds */); options, launchBounds);
} else { } else {
Intent fillInIntent = new Intent(); Intent fillInIntent = new Intent();
// Apply flags to make behaviour match documentLaunchMode=always. // Apply flags to make behaviour match documentLaunchMode=always.
@@ -175,7 +178,8 @@ public class BubbleExpandedView extends LinearLayout {
if (mBubble != null) { if (mBubble != null) {
mBubble.setIntentActive(); mBubble.setIntentActive();
} }
mTaskView.startActivity(mPendingIntent, fillInIntent, options); mTaskView.startActivity(mPendingIntent, fillInIntent, options,
launchBounds);
} }
} catch (RuntimeException e) { } catch (RuntimeException e) {
// If there's a runtime exception here then there's something // If there's a runtime exception here then there's something

View File

@@ -36,6 +36,7 @@ import android.app.ActivityManager;
import android.app.ActivityOptions; import android.app.ActivityOptions;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper; import android.testing.TestableLooper;
import android.view.SurfaceControl; import android.view.SurfaceControl;
@@ -125,7 +126,7 @@ public class TaskViewTest extends ShellTestCase {
@Test @Test
public void testStartActivity() { public void testStartActivity() {
ActivityOptions options = ActivityOptions.makeBasic(); 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)); verify(mOrganizer).setPendingLaunchCookieListener(any(), eq(mTaskView));
assertThat(options.getLaunchWindowingMode()).isEqualTo(WINDOWING_MODE_MULTI_WINDOW); assertThat(options.getLaunchWindowingMode()).isEqualTo(WINDOWING_MODE_MULTI_WINDOW);

View File

@@ -1333,6 +1333,7 @@
<dimen name="controls_setup_title">22sp</dimen> <dimen name="controls_setup_title">22sp</dimen>
<dimen name="controls_setup_subtitle">14sp</dimen> <dimen name="controls_setup_subtitle">14sp</dimen>
<dimen name="controls_setup_vertical_padding">52dp</dimen> <dimen name="controls_setup_vertical_padding">52dp</dimen>
<dimen name="controls_detail_dialog_header_height">52dp</dimen>
<!-- Home Controls activity view detail panel--> <!-- Home Controls activity view detail panel-->
<dimen name="controls_activity_view_top_offset">100dp</dimen> <dimen name="controls_activity_view_top_offset">100dp</dimen>

View File

@@ -24,6 +24,7 @@ import android.app.PendingIntent
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Rect
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowInsets import android.view.WindowInsets
@@ -83,8 +84,9 @@ class DetailDialog(
taskView.startActivity( taskView.startActivity(
PendingIntent.getActivity(context, 0, launchIntent, PendingIntent.getActivity(context, 0, launchIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE),
null, null /* fillInIntent */,
options options,
getTaskViewBounds()
) )
} }
@@ -159,6 +161,23 @@ class DetailDialog(
taskView.setListener(cvh.uiExecutor, stateCallback) 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() { override fun dismiss() {
if (!isShowing()) return if (!isShowing()) return
taskView.release() taskView.release()

View File

@@ -160,8 +160,7 @@ class LaunchParamsController {
return false; return false;
} }
if (task.getRootTask().inFreeformWindowingMode()) { if (task.getRootTask().inMultiWindowMode()) {
// Only set bounds if it's in freeform mode.
task.setBounds(mTmpParams.mBounds); task.setBounds(mTmpParams.mBounds);
return true; return true;
} }

View File

@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 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_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
@@ -195,6 +196,11 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
} else { } else {
if (DEBUG) appendLog("empty-window-layout"); 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 // STEP 2.2: Check if previous modifier or the controller (referred as "callers" below) has

View File

@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 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_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.INVALID_DISPLAY;
@@ -371,6 +372,29 @@ public class LaunchParamsControllerTests extends WindowTestsBase {
assertEquals(expected, task.getRequestedOverrideBounds()); 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 * Ensures that {@link LaunchParamsModifier} requests specifying bounds during
* layout are set to last non-fullscreen bounds. * layout are set to last non-fullscreen bounds.

View File

@@ -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.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 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_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
@@ -926,6 +927,25 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase {
assertEquals(expected, mResult.mBounds); 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 @Test
public void testRespectsLaunchBoundsWithFreeformSourceOnFullscreenDisplay() { public void testRespectsLaunchBoundsWithFreeformSourceOnFullscreenDisplay() {
final TestDisplayContent fullscreenDisplay = createNewDisplayContent( final TestDisplayContent fullscreenDisplay = createNewDisplayContent(