Merge "Fix the transition from Split to PiP" into sc-v2-dev
diff --git a/core/java/android/window/PictureInPictureSurfaceTransaction.java b/core/java/android/window/PictureInPictureSurfaceTransaction.java
index dbf7eb3..2bf2f319 100644
--- a/core/java/android/window/PictureInPictureSurfaceTransaction.java
+++ b/core/java/android/window/PictureInPictureSurfaceTransaction.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Matrix;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
@@ -34,9 +35,10 @@
* @hide
*/
public final class PictureInPictureSurfaceTransaction implements Parcelable {
+ private static final float NOT_SET = -1f;
- public final float mPositionX;
- public final float mPositionY;
+ public final float mAlpha;
+ public final PointF mPosition;
public final float[] mFloat9;
@@ -45,33 +47,37 @@
public final float mCornerRadius;
- private final Rect mWindowCrop = new Rect();
+ private final Rect mWindowCrop;
- public PictureInPictureSurfaceTransaction(Parcel in) {
- mPositionX = in.readFloat();
- mPositionY = in.readFloat();
+ private PictureInPictureSurfaceTransaction(Parcel in) {
+ mAlpha = in.readFloat();
+ mPosition = in.readTypedObject(PointF.CREATOR);
mFloat9 = new float[9];
in.readFloatArray(mFloat9);
mRotation = in.readFloat();
mCornerRadius = in.readFloat();
- mWindowCrop.set(Objects.requireNonNull(in.readTypedObject(Rect.CREATOR)));
+ mWindowCrop = in.readTypedObject(Rect.CREATOR);
}
- public PictureInPictureSurfaceTransaction(float positionX, float positionY,
- float[] float9, float rotation, float cornerRadius,
+ private PictureInPictureSurfaceTransaction(float alpha, @Nullable PointF position,
+ @Nullable float[] float9, float rotation, float cornerRadius,
@Nullable Rect windowCrop) {
- mPositionX = positionX;
- mPositionY = positionY;
- mFloat9 = Arrays.copyOf(float9, 9);
- mRotation = rotation;
- mCornerRadius = cornerRadius;
- if (windowCrop != null) {
- mWindowCrop.set(windowCrop);
+ mAlpha = alpha;
+ mPosition = position;
+ if (float9 == null) {
+ mFloat9 = new float[9];
+ Matrix.IDENTITY_MATRIX.getValues(mFloat9);
+ mRotation = 0;
+ } else {
+ mFloat9 = Arrays.copyOf(float9, 9);
+ mRotation = rotation;
}
+ mCornerRadius = cornerRadius;
+ mWindowCrop = (windowCrop == null) ? null : new Rect(windowCrop);
}
public PictureInPictureSurfaceTransaction(PictureInPictureSurfaceTransaction other) {
- this(other.mPositionX, other.mPositionY,
+ this(other.mAlpha, other.mPosition,
other.mFloat9, other.mRotation, other.mCornerRadius, other.mWindowCrop);
}
@@ -82,13 +88,18 @@
return matrix;
}
+ /** @return {@code true} if this transaction contains setting corner radius. */
+ public boolean hasCornerRadiusSet() {
+ return mCornerRadius > 0;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PictureInPictureSurfaceTransaction)) return false;
PictureInPictureSurfaceTransaction that = (PictureInPictureSurfaceTransaction) o;
- return Objects.equals(mPositionX, that.mPositionX)
- && Objects.equals(mPositionY, that.mPositionY)
+ return Objects.equals(mAlpha, that.mAlpha)
+ && Objects.equals(mPosition, that.mPosition)
&& Arrays.equals(mFloat9, that.mFloat9)
&& Objects.equals(mRotation, that.mRotation)
&& Objects.equals(mCornerRadius, that.mCornerRadius)
@@ -97,7 +108,7 @@
@Override
public int hashCode() {
- return Objects.hash(mPositionX, mPositionY, Arrays.hashCode(mFloat9),
+ return Objects.hash(mAlpha, mPosition, Arrays.hashCode(mFloat9),
mRotation, mCornerRadius, mWindowCrop);
}
@@ -108,8 +119,8 @@
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeFloat(mPositionX);
- out.writeFloat(mPositionY);
+ out.writeFloat(mAlpha);
+ out.writeTypedObject(mPosition, 0 /* flags */);
out.writeFloatArray(mFloat9);
out.writeFloat(mRotation);
out.writeFloat(mCornerRadius);
@@ -120,8 +131,8 @@
public String toString() {
final Matrix matrix = getMatrix();
return "PictureInPictureSurfaceTransaction("
- + " posX=" + mPositionX
- + " posY=" + mPositionY
+ + " alpha=" + mAlpha
+ + " position=" + mPosition
+ " matrix=" + matrix.toShortString()
+ " rotation=" + mRotation
+ " cornerRadius=" + mCornerRadius
@@ -134,11 +145,20 @@
@NonNull SurfaceControl surfaceControl,
@NonNull SurfaceControl.Transaction tx) {
final Matrix matrix = surfaceTransaction.getMatrix();
- tx.setMatrix(surfaceControl, matrix, new float[9])
- .setPosition(surfaceControl,
- surfaceTransaction.mPositionX, surfaceTransaction.mPositionY)
- .setWindowCrop(surfaceControl, surfaceTransaction.mWindowCrop)
- .setCornerRadius(surfaceControl, surfaceTransaction.mCornerRadius);
+ tx.setMatrix(surfaceControl, matrix, new float[9]);
+ if (surfaceTransaction.mPosition != null) {
+ tx.setPosition(surfaceControl,
+ surfaceTransaction.mPosition.x, surfaceTransaction.mPosition.y);
+ }
+ if (surfaceTransaction.mWindowCrop != null) {
+ tx.setWindowCrop(surfaceControl, surfaceTransaction.mWindowCrop);
+ }
+ if (surfaceTransaction.hasCornerRadiusSet()) {
+ tx.setCornerRadius(surfaceControl, surfaceTransaction.mCornerRadius);
+ }
+ if (surfaceTransaction.mAlpha != NOT_SET) {
+ tx.setAlpha(surfaceControl, surfaceTransaction.mAlpha);
+ }
}
public static final @android.annotation.NonNull Creator<PictureInPictureSurfaceTransaction>
@@ -151,4 +171,44 @@
return new PictureInPictureSurfaceTransaction[size];
}
};
+
+ public static class Builder {
+ private float mAlpha = NOT_SET;
+ private PointF mPosition;
+ private float[] mFloat9;
+ private float mRotation;
+ private float mCornerRadius = NOT_SET;
+ private Rect mWindowCrop;
+
+ public Builder setAlpha(float alpha) {
+ mAlpha = alpha;
+ return this;
+ }
+
+ public Builder setPosition(float x, float y) {
+ mPosition = new PointF(x, y);
+ return this;
+ }
+
+ public Builder setTransform(@NonNull float[] float9, float rotation) {
+ mFloat9 = Arrays.copyOf(float9, 9);
+ mRotation = rotation;
+ return this;
+ }
+
+ public Builder setCornerRadius(float cornerRadius) {
+ mCornerRadius = cornerRadius;
+ return this;
+ }
+
+ public Builder setWindowCrop(@NonNull Rect windowCrop) {
+ mWindowCrop = new Rect(windowCrop);
+ return this;
+ }
+
+ public PictureInPictureSurfaceTransaction build() {
+ return new PictureInPictureSurfaceTransaction(mAlpha, mPosition,
+ mFloat9, mRotation, mCornerRadius, mWindowCrop);
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 05552aa..cf4e56e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -102,6 +102,7 @@
static final int EXIT_REASON_ROOT_TASK_VANISHED = 6;
static final int EXIT_REASON_SCREEN_LOCKED = 7;
static final int EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP = 8;
+ static final int EXIT_REASON_CHILD_TASK_ENTER_PIP = 9;
@IntDef(value = {
EXIT_REASON_UNKNOWN,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW,
@@ -112,6 +113,7 @@
EXIT_REASON_ROOT_TASK_VANISHED,
EXIT_REASON_SCREEN_LOCKED,
EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP,
+ EXIT_REASON_CHILD_TASK_ENTER_PIP,
})
@Retention(RetentionPolicy.SOURCE)
@interface ExitReason{}
@@ -406,6 +408,8 @@
return "APP_FINISHED";
case EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW:
return "APP_DOES_NOT_SUPPORT_MULTIWINDOW";
+ case EXIT_REASON_CHILD_TASK_ENTER_PIP:
+ return "CHILD_TASK_ENTER_PIP";
default:
return "unknown reason, reason int = " + exitReason;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index e30e6c5..dd538dc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -35,6 +35,7 @@
import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DEVICE_FOLDED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
@@ -629,8 +630,12 @@
});
mShouldUpdateRecents = false;
- mSideStage.removeAllTasks(wct, childrenToTop == mSideStage);
- mMainStage.deactivate(wct, childrenToTop == mMainStage);
+ // When the exit split-screen is caused by one of the task enters auto pip,
+ // we want the tasks to be put to bottom instead of top, otherwise it will end up
+ // a fullscreen plus a pinned task instead of pinned only at the end of the transition.
+ final boolean fromEnteringPip = exitReason == EXIT_REASON_CHILD_TASK_ENTER_PIP;
+ mSideStage.removeAllTasks(wct, !fromEnteringPip && childrenToTop == mSideStage);
+ mMainStage.deactivate(wct, !fromEnteringPip && childrenToTop == mMainStage);
mTaskOrganizer.applyTransaction(wct);
mSyncQueue.runInSync(t -> t
.setWindowCrop(mMainStage.mRootLeash, null)
@@ -660,6 +665,8 @@
case EXIT_REASON_DRAG_DIVIDER:
// Either of the split apps have finished
case EXIT_REASON_APP_FINISHED:
+ // One of the children enters PiP
+ case EXIT_REASON_CHILD_TASK_ENTER_PIP:
return true;
default:
return false;
@@ -749,6 +756,11 @@
}
}
+ private void onStageChildTaskEnterPip(StageListenerImpl stageListener, int taskId) {
+ exitSplitScreen(stageListener == mMainStageListener ? mMainStage : mSideStage,
+ EXIT_REASON_CHILD_TASK_ENTER_PIP);
+ }
+
private void updateRecentTasksSplitPair() {
if (!mShouldUpdateRecents) {
return;
@@ -1437,6 +1449,11 @@
}
@Override
+ public void onChildTaskEnterPip(int taskId) {
+ StageCoordinator.this.onStageChildTaskEnterPip(this, taskId);
+ }
+
+ @Override
public void onRootTaskVanished() {
reset();
StageCoordinator.this.onStageRootTaskVanished(this);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index cd10b9f..2c853c1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -20,6 +20,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
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 com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -73,6 +74,8 @@
void onChildTaskStatusChanged(int taskId, boolean present, boolean visible);
+ void onChildTaskEnterPip(int taskId);
+
void onRootTaskVanished();
void onNoLongerSupportMultiWindow();
@@ -256,6 +259,9 @@
mChildrenTaskInfo.remove(taskId);
mChildrenLeashes.remove(taskId);
mCallbacks.onChildTaskStatusChanged(taskId, false /* present */, taskInfo.isVisible);
+ if (taskInfo.getWindowingMode() == WINDOWING_MODE_PINNED) {
+ mCallbacks.onChildTaskEnterPip(taskId);
+ }
if (ENABLE_SHELL_TRANSITIONS) {
// Status is managed/synchronized by the transition lifecycle.
return;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
index 7d0fb5d..567e7aa 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
@@ -53,8 +53,8 @@
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setPosition(leash, positionX, positionY)
.setCornerRadius(leash, cornerRadius);
- return new PictureInPictureSurfaceTransaction(
- positionX, positionY, mTmpFloat9, 0 /* rotation */, cornerRadius, sourceBounds);
+ return newPipSurfaceTransaction(positionX, positionY,
+ mTmpFloat9, 0 /* rotation */, cornerRadius, sourceBounds);
}
public PictureInPictureSurfaceTransaction scale(
@@ -70,8 +70,8 @@
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setPosition(leash, positionX, positionY)
.setCornerRadius(leash, cornerRadius);
- return new PictureInPictureSurfaceTransaction(
- positionX, positionY, mTmpFloat9, degree, cornerRadius, sourceBounds);
+ return newPipSurfaceTransaction(positionX, positionY,
+ mTmpFloat9, degree, cornerRadius, sourceBounds);
}
public PictureInPictureSurfaceTransaction scaleAndCrop(
@@ -93,8 +93,8 @@
.setWindowCrop(leash, mTmpDestinationRect)
.setPosition(leash, left, top)
.setCornerRadius(leash, cornerRadius);
- return new PictureInPictureSurfaceTransaction(
- left, top, mTmpFloat9, 0 /* rotation */, cornerRadius, mTmpDestinationRect);
+ return newPipSurfaceTransaction(left, top,
+ mTmpFloat9, 0 /* rotation */, cornerRadius, mTmpDestinationRect);
}
public PictureInPictureSurfaceTransaction scaleAndRotate(
@@ -125,8 +125,7 @@
.setWindowCrop(leash, mTmpDestinationRect)
.setPosition(leash, adjustedPositionX, adjustedPositionY)
.setCornerRadius(leash, cornerRadius);
- return new PictureInPictureSurfaceTransaction(
- adjustedPositionX, adjustedPositionY,
+ return newPipSurfaceTransaction(adjustedPositionX, adjustedPositionY,
mTmpFloat9, degree, cornerRadius, mTmpDestinationRect);
}
@@ -137,6 +136,17 @@
return mCornerRadius * scale;
}
+ private static PictureInPictureSurfaceTransaction newPipSurfaceTransaction(
+ float posX, float posY, float[] float9, float rotation, float cornerRadius,
+ Rect windowCrop) {
+ return new PictureInPictureSurfaceTransaction.Builder()
+ .setPosition(posX, posY)
+ .setTransform(float9, rotation)
+ .setCornerRadius(cornerRadius)
+ .setWindowCrop(windowCrop)
+ .build();
+ }
+
/** @return {@link SurfaceControl.Transaction} instance with vsync-id */
public static SurfaceControl.Transaction newSurfaceControlTransaction() {
final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
index b54208d..9ad30da 100644
--- a/services/core/java/com/android/server/wm/PinnedTaskController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -255,25 +255,27 @@
mDestRotatedBounds = null;
mPipTransaction = null;
final Rect areaBounds = taskArea.getBounds();
- if (pipTx != null) {
+ if (pipTx != null && pipTx.mPosition != null) {
// The transaction from recents animation is in old rotation. So the position needs to
// be rotated.
- float dx = pipTx.mPositionX;
- float dy = pipTx.mPositionY;
+ float dx = pipTx.mPosition.x;
+ float dy = pipTx.mPosition.y;
final Matrix matrix = pipTx.getMatrix();
if (pipTx.mRotation == 90) {
- dx = pipTx.mPositionY;
- dy = areaBounds.right - pipTx.mPositionX;
+ dx = pipTx.mPosition.y;
+ dy = areaBounds.right - pipTx.mPosition.x;
matrix.postRotate(-90);
} else if (pipTx.mRotation == -90) {
- dx = areaBounds.bottom - pipTx.mPositionY;
- dy = pipTx.mPositionX;
+ dx = areaBounds.bottom - pipTx.mPosition.y;
+ dy = pipTx.mPosition.x;
matrix.postRotate(90);
}
matrix.postTranslate(dx, dy);
final SurfaceControl leash = pinnedTask.getSurfaceControl();
- t.setMatrix(leash, matrix, new float[9])
- .setCornerRadius(leash, pipTx.mCornerRadius);
+ t.setMatrix(leash, matrix, new float[9]);
+ if (pipTx.hasCornerRadiusSet()) {
+ t.setCornerRadius(leash, pipTx.mCornerRadius);
+ }
Slog.i(TAG, "Seamless rotation PiP tx=" + pipTx + " pos=" + dx + "," + dy);
return;
}