summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Chris Li <lihongyu@google.com> 2022-10-10 21:21:51 +0800
committer Chris Li <lihongyu@google.com> 2022-10-13 09:02:27 +0800
commit84ec824a330b01c23b62d95963ca901f5fd15234 (patch)
tree2deefe268fc9c34db2aff6a55a77008c734e82a6
parentc5bfa99295e01f7a8e0412ef279bad0f6c38b027 (diff)
Polish ActivityEmbedding enter/exit PiP (1/n)
1. When moveActivityToPinnedRootTask with creating a new Task for PiP, make sure the Task's initial bounds is the same as the activity parent TaskFragment so the animation starts from the correct bounds. 2. When exit PiP to previous Task, make sure we are animating the correct window surface. For the previous implementation. there can also be TRANSIT_CHANGE change for entering ActivityEmbedding split (from PiP) in the same transition. Bug: 207070762 Test: atest WmTests:RootWindowContainerTests Test: atest WmTests:TransitionTests Merged-In: Ifba090ad9ac9fb7033d343eab1c87c1a67bb9c11 Change-Id: Ifba090ad9ac9fb7033d343eab1c87c1a67bb9c11
-rw-r--r--core/java/android/window/TransitionInfo.java23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java11
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java7
-rw-r--r--services/core/java/com/android/server/wm/Task.java12
-rw-r--r--services/core/java/com/android/server/wm/Transition.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java29
7 files changed, 105 insertions, 9 deletions
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index fbdd325e0814..1bc8e6d7ef65 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -407,6 +407,7 @@ public final class TransitionInfo implements Parcelable {
public static final class Change implements Parcelable {
private final WindowContainerToken mContainer;
private WindowContainerToken mParent;
+ private WindowContainerToken mLastParent;
private final SurfaceControl mLeash;
private @TransitionMode int mMode = TRANSIT_NONE;
private @ChangeFlags int mFlags = FLAG_NONE;
@@ -435,6 +436,7 @@ public final class TransitionInfo implements Parcelable {
private Change(Parcel in) {
mContainer = in.readTypedObject(WindowContainerToken.CREATOR);
mParent = in.readTypedObject(WindowContainerToken.CREATOR);
+ mLastParent = in.readTypedObject(WindowContainerToken.CREATOR);
mLeash = new SurfaceControl();
mLeash.readFromParcel(in);
mMode = in.readInt();
@@ -458,6 +460,14 @@ public final class TransitionInfo implements Parcelable {
mParent = parent;
}
+ /**
+ * Sets the parent of this change's container before the transition if this change's
+ * container is reparented in the transition.
+ */
+ public void setLastParent(@Nullable WindowContainerToken lastParent) {
+ mLastParent = lastParent;
+ }
+
/** Sets the transition mode for this change */
public void setMode(@TransitionMode int mode) {
mMode = mode;
@@ -541,6 +551,17 @@ public final class TransitionInfo implements Parcelable {
return mParent;
}
+ /**
+ * @return the parent of the changing container before the transition if it is reparented
+ * in the transition. The parent window may not be collected in the transition as a
+ * participant, and it may have been detached from the display. {@code null} if the changing
+ * container has not been reparented in the transition, or if the parent is not organizable.
+ */
+ @Nullable
+ public WindowContainerToken getLastParent() {
+ return mLastParent;
+ }
+
/** @return which action this change represents. */
public @TransitionMode int getMode() {
return mMode;
@@ -640,6 +661,7 @@ public final class TransitionInfo implements Parcelable {
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeTypedObject(mContainer, flags);
dest.writeTypedObject(mParent, flags);
+ dest.writeTypedObject(mLastParent, flags);
mLeash.writeToParcel(dest, flags);
dest.writeInt(mMode);
dest.writeInt(mFlags);
@@ -685,6 +707,7 @@ public final class TransitionInfo implements Parcelable {
+ mStartRotation + "->" + mEndRotation + ":" + mRotationAnimation
+ " endFixedRotation=" + mEndFixedRotation;
if (mSnapshot != null) out += " snapshot=" + mSnapshot;
+ if (mLastParent != null) out += " lastParent=" + mLastParent;
return out + "}";
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 33761d23379d..2b36b4c0307d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -452,14 +452,17 @@ public class PipTransition extends PipTransitionController {
@NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull TaskInfo taskInfo, @Nullable TransitionInfo.Change pipTaskChange) {
TransitionInfo.Change pipChange = pipTaskChange;
- if (pipChange == null) {
+ if (mCurrentPipTaskToken == null) {
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: There is no existing PiP Task for TRANSIT_EXIT_PIP", TAG);
+ } else if (pipChange == null) {
// The pipTaskChange is null, this can happen if we are reparenting the PIP activity
// back to its original Task. In that case, we should animate the activity leash
- // instead, which should be the only non-task, independent, TRANSIT_CHANGE window.
+ // instead, which should be the change whose last parent is the recorded PiP Task.
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
- if (change.getTaskInfo() == null && change.getMode() == TRANSIT_CHANGE
- && TransitionInfo.isIndependent(change, info)) {
+ if (mCurrentPipTaskToken.equals(change.getLastParent())) {
+ // Find the activity that is exiting PiP.
pipChange = change;
break;
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 7f222423ec1c..2866f423dc07 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2021,7 +2021,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// non-fullscreen bounds. Then when this new PIP task exits PIP, it can restore
// to its previous freeform bounds.
rootTask.setLastNonFullscreenBounds(task.mLastNonFullscreenBounds);
- rootTask.setBounds(task.getBounds());
+ // When creating a new Task for PiP, set its initial bounds as the TaskFragment in
+ // case the activity is embedded, so that it can be animated to PiP window from the
+ // current bounds.
+ // Use Task#setBoundsUnchecked to skip checking windowing mode as the windowing mode
+ // will be updated later after this is collected in transition.
+ rootTask.setBoundsUnchecked(r.getTaskFragment().getBounds());
// Move the last recents animation transaction from original task to the new one.
if (task.mLastRecentsAnimationTransaction != null) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9f45f02277ce..e4a3a4bcb37e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2618,6 +2618,13 @@ class Task extends TaskFragment {
return boundsChange;
}
+ /** Sets the requested bounds regardless of the windowing mode. */
+ int setBoundsUnchecked(@NonNull Rect bounds) {
+ final int boundsChange = super.setBounds(bounds);
+ updateSurfaceBounds();
+ return boundsChange;
+ }
+
@Override
public boolean isCompatible(int windowingMode, int activityType) {
// TODO: Should we just move this to ConfigurationContainer?
@@ -5917,10 +5924,7 @@ class Task extends TaskFragment {
return BOUNDS_CHANGE_NONE;
}
- final int result = super.setBounds(!inMultiWindowMode() ? null : bounds);
-
- updateSurfaceBounds();
- return result;
+ return setBoundsUnchecked(!inMultiWindowMode() ? null : bounds);
}
@Override
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 526a366ded57..b1862b6f274f 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1595,6 +1595,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
if (info.mEndParent != null) {
change.setParent(info.mEndParent.mRemoteToken.toWindowContainerToken());
}
+ if (info.mStartParent != null && info.mStartParent.mRemoteToken != null
+ && target.getParent() != info.mStartParent) {
+ change.setLastParent(info.mStartParent.mRemoteToken.toWindowContainerToken());
+ }
change.setMode(info.getTransitMode(target));
change.setStartAbsBounds(info.mAbsoluteBounds);
change.setFlags(info.getChangeFlags(target));
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 601cf154b3bf..64c1e05da2cd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -72,6 +72,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Rect;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.util.MergedConfiguration;
@@ -377,6 +378,33 @@ public class RootWindowContainerTests extends WindowTestsBase {
assertEquals(WINDOWING_MODE_FULLSCREEN, fullscreenTask.getWindowingMode());
}
+ @Test
+ public void testMovingEmbeddedActivityToPip() {
+ final Rect taskBounds = new Rect(0, 0, 800, 1000);
+ final Rect taskFragmentBounds = new Rect(0, 0, 400, 1000);
+ final Task task = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
+ WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ task.setBounds(taskBounds);
+ assertEquals(taskBounds, task.getBounds());
+ final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .createActivityCount(2)
+ .setBounds(taskFragmentBounds)
+ .build();
+ assertEquals(taskFragmentBounds, taskFragment.getBounds());
+ final ActivityRecord topActivity = taskFragment.getTopMostActivity();
+
+ // Move the top activity to pinned root task.
+ mRootWindowContainer.moveActivityToPinnedRootTask(topActivity,
+ null /* launchIntoPipHostActivity */, "test");
+
+ final Task pinnedRootTask = task.getDisplayArea().getRootPinnedTask();
+
+ // Ensure the initial bounds of the PiP Task is the same as the TaskFragment.
+ ensureTaskPlacement(pinnedRootTask, topActivity);
+ assertEquals(taskFragmentBounds, pinnedRootTask.getBounds());
+ }
+
private static void ensureTaskPlacement(Task task, ActivityRecord... activities) {
final ArrayList<ActivityRecord> taskActivities = new ArrayList<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 7342c49bf28a..9fd085021d66 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -1322,6 +1322,35 @@ public class TransitionTests extends WindowTestsBase {
}
@Test
+ public void testReparentChangeLastParent() {
+ final Transition transition = createTestTransition(TRANSIT_CHANGE);
+ final ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+ final ArraySet<WindowContainer> participants = transition.mParticipants;
+
+ // Reparent activity in transition.
+ final Task lastParent = createTask(mDisplayContent);
+ final Task newParent = createTask(mDisplayContent);
+ final ActivityRecord activity = createActivityRecord(lastParent);
+ activity.mVisibleRequested = true;
+ // Skip manipulate the SurfaceControl.
+ doNothing().when(activity).setDropInputMode(anyInt());
+ changes.put(activity, new Transition.ChangeInfo(activity));
+ activity.reparent(newParent, POSITION_TOP);
+ activity.mVisibleRequested = false;
+
+ participants.add(activity);
+ final ArrayList<WindowContainer> targets = Transition.calculateTargets(
+ participants, changes);
+ final TransitionInfo info = Transition.calculateTransitionInfo(
+ transition.mType, 0 /* flags */, targets, changes, mMockT);
+
+ // Change contains last parent info.
+ assertEquals(1, info.getChanges().size());
+ assertEquals(lastParent.mRemoteToken.toWindowContainerToken(),
+ info.getChanges().get(0).getLastParent());
+ }
+
+ @Test
public void testIncludeEmbeddedActivityReparent() {
final Transition transition = createTestTransition(TRANSIT_OPEN);
final Task task = createTask(mDisplayContent);