Pass PictureInPictureParams in TaskInfo.
This way TaskOrganizerImplementations can use the parameters from
taskAppeared. We also wire up taskInfoChanged.
Bug: 146594635
Bug: 139371701
Test: TaskOrganizerTests
Change-Id: I5371af16177ebdf6e2187beb7184efd499c8f36d
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index a54f5d4..9b968cb 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -7692,4 +7692,9 @@
}
win.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
}
+
+ void setPictureInPictureParams(PictureInPictureParams p) {
+ pictureInPictureArgs.copyOnlySet(p);
+ getTask().getRootTask().setPictureInPictureParams(p);
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 5f3e3a3..80162fb 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4153,7 +4153,7 @@
return;
}
// Only update the saved args from the args that are set
- r.pictureInPictureArgs.copyOnlySet(params);
+ r.setPictureInPictureParams(params);
final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
// Adjust the source bounds by the insets for the transition down
@@ -4201,7 +4201,7 @@
"setPictureInPictureParams", token, params);
// Only update the saved args from the args that are set
- r.pictureInPictureArgs.copyOnlySet(params);
+ r.setPictureInPictureParams(params);
if (r.inPinnedWindowingMode()) {
// If the activity is already in picture-in-picture, update the pinned stack now
// if it is not already expanding to fullscreen. Otherwise, the arguments will
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b1db9d7..028274a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -99,6 +99,7 @@
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppGlobals;
+import android.app.PictureInPictureParams;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
import android.content.ComponentName;
@@ -461,6 +462,11 @@
*/
ITaskOrganizer mTaskOrganizer;
+ /**
+ * Last Picture-in-Picture params applicable to the task. Updated when the app
+ * enters Picture-in-Picture or when setPictureInPictureParams is called.
+ */
+ PictureInPictureParams mPictureInPictureParams = new PictureInPictureParams.Builder().build();
/**
* Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
@@ -3199,6 +3205,12 @@
// order changes.
final Task top = getTopMostTask();
info.resizeMode = top != null ? top.mResizeMode : mResizeMode;
+
+ if (mPictureInPictureParams.empty()) {
+ info.pictureInPictureParams = null;
+ } else {
+ info.pictureInPictureParams = mPictureInPictureParams;
+ }
}
/**
@@ -3929,4 +3941,10 @@
void onWindowFocusChanged(boolean hasFocus) {
updateShadowsRadius(hasFocus, getPendingTransaction());
}
+
+ void setPictureInPictureParams(PictureInPictureParams p) {
+ mPictureInPictureParams.copyOnlySet(p);
+ mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
+ this, true /* force */);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index f7aa3cc..6e738e90 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -34,14 +34,21 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
+import android.app.PictureInPictureParams;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -49,6 +56,8 @@
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.util.ArrayMap;
+import android.content.pm.ActivityInfo;
+import android.util.Rational;
import android.view.Display;
import android.view.ITaskOrganizer;
import android.view.IWindowContainer;
@@ -483,4 +492,76 @@
verify(transactionListener)
.transactionReady(anyInt(), any());
}
+
+ class StubOrganizer extends ITaskOrganizer.Stub {
+ RunningTaskInfo mInfo;
+
+ @Override
+ public void taskAppeared(RunningTaskInfo info) {
+ mInfo = info;
+ }
+ @Override
+ public void taskVanished(IWindowContainer wc) {
+ }
+ @Override
+ public void transactionReady(int id, SurfaceControl.Transaction t) {
+ }
+ @Override
+ public void onTaskInfoChanged(RunningTaskInfo info) {
+ }
+ };
+
+ private ActivityRecord makePipableActivity() {
+ final ActivityRecord record = createActivityRecord(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ record.info.flags |= ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+ spyOn(record);
+ doReturn(true).when(record).checkEnterPictureInPictureState(any(), anyBoolean());
+ return record;
+ }
+
+ @Test
+ public void testEnterPipParams() {
+ final StubOrganizer o = new StubOrganizer();
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o, WINDOWING_MODE_PINNED);
+ final ActivityRecord record = makePipableActivity();
+
+ final PictureInPictureParams p =
+ new PictureInPictureParams.Builder().setAspectRatio(new Rational(1, 2)).build();
+ assertTrue(mWm.mAtmService.enterPictureInPictureMode(record.token, p));
+ waitUntilHandlersIdle();
+ assertNotNull(o.mInfo);
+ assertNotNull(o.mInfo.pictureInPictureParams);
+ }
+
+ @Test
+ public void testChangePipParams() {
+ class ChangeSavingOrganizer extends StubOrganizer {
+ RunningTaskInfo mChangedInfo;
+ @Override
+ public void onTaskInfoChanged(RunningTaskInfo info) {
+ mChangedInfo = info;
+ }
+ }
+ ChangeSavingOrganizer o = new ChangeSavingOrganizer();
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o, WINDOWING_MODE_PINNED);
+
+ final ActivityRecord record = makePipableActivity();
+ final PictureInPictureParams p =
+ new PictureInPictureParams.Builder().setAspectRatio(new Rational(1, 2)).build();
+ assertTrue(mWm.mAtmService.enterPictureInPictureMode(record.token, p));
+ waitUntilHandlersIdle();
+ assertNotNull(o.mInfo);
+ assertNotNull(o.mInfo.pictureInPictureParams);
+
+ final PictureInPictureParams p2 =
+ new PictureInPictureParams.Builder().setAspectRatio(new Rational(3, 4)).build();
+ mWm.mAtmService.setPictureInPictureParams(record.token, p2);
+ waitUntilHandlersIdle();
+ assertNotNull(o.mChangedInfo);
+ assertNotNull(o.mChangedInfo.pictureInPictureParams);
+ final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatioRational();
+ assertEquals(3, ratio.getNumerator());
+ assertEquals(4, ratio.getDenominator());
+ }
}