summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java53
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java27
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java26
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java2
5 files changed, 86 insertions, 23 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index 7805ec34e105..383afcf6f821 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -16,9 +16,11 @@
package com.android.wm.shell.pip2.phone;
+import android.app.PictureInPictureParams;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.os.SystemProperties;
import android.view.SurfaceControl;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -28,6 +30,7 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
+import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipDesktopState;
@@ -39,6 +42,7 @@ import com.android.wm.shell.shared.split.SplitScreenConstants;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.util.Optional;
+import java.util.function.Supplier;
/**
* Scheduler for Shell initiated PiP transitions and animations.
@@ -46,6 +50,15 @@ import java.util.Optional;
public class PipScheduler {
private static final String TAG = PipScheduler.class.getSimpleName();
+ /**
+ * The fixed start delay in ms when fading out the content overlay from bounds animation.
+ * The fadeout animation is guaranteed to start after the client has drawn under the new config.
+ */
+ public static final int EXTRA_CONTENT_OVERLAY_FADE_OUT_DELAY_MS =
+ SystemProperties.getInt(
+ "persist.wm.debug.extra_content_overlay_fade_out_delay_ms", 400);
+ private static final int CONTENT_OVERLAY_FADE_OUT_DURATION_MS = 500;
+
private final Context mContext;
private final PipBoundsState mPipBoundsState;
private final ShellExecutor mMainExecutor;
@@ -60,6 +73,7 @@ public class PipScheduler {
@Nullable private Runnable mUpdateMovementBoundsRunnable;
private PipAlphaAnimatorSupplier mPipAlphaAnimatorSupplier;
+ private Supplier<PictureInPictureParams> mPipParamsSupplier;
public PipScheduler(Context context,
PipBoundsState pipBoundsState,
@@ -222,6 +236,16 @@ public class PipScheduler {
tx.apply();
}
+ void startOverlayFadeoutAnimation(@NonNull SurfaceControl overlayLeash,
+ boolean withStartDelay, @NonNull Runnable onAnimationEnd) {
+ PipAlphaAnimator animator = mPipAlphaAnimatorSupplier.get(mContext, overlayLeash,
+ null /* startTx */, null /* finishTx */, PipAlphaAnimator.FADE_OUT);
+ animator.setDuration(CONTENT_OVERLAY_FADE_OUT_DURATION_MS);
+ animator.setStartDelay(withStartDelay ? EXTRA_CONTENT_OVERLAY_FADE_OUT_DELAY_MS : 0);
+ animator.setAnimationEndCallback(onAnimationEnd);
+ animator.start();
+ }
+
void setUpdateMovementBoundsRunnable(@Nullable Runnable updateMovementBoundsRunnable) {
mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
}
@@ -236,6 +260,25 @@ public class PipScheduler {
if (mPipBoundsState.getBounds().equals(newBounds)) {
return;
}
+
+ // Take a screenshot of PiP and fade it out after resize is finished if seamless resize
+ // is off and if the PiP size is changing.
+ boolean animateCrossFadeResize = !getPipParams().isSeamlessResizeEnabled()
+ && !(mPipBoundsState.getBounds().width() == newBounds.width()
+ && mPipBoundsState.getBounds().height() == newBounds.height());
+ if (animateCrossFadeResize) {
+ final Rect crop = new Rect(newBounds);
+ crop.offsetTo(0, 0);
+ // Note: Put this at layer=MAX_VALUE-2 since the input consumer for PIP is placed at
+ // MAX_VALUE-1
+ final SurfaceControl snapshotSurface = ScreenshotUtils.takeScreenshot(
+ mSurfaceControlTransactionFactory.getTransaction(),
+ mPipTransitionState.getPinnedTaskLeash(), crop, Integer.MAX_VALUE - 2);
+ startOverlayFadeoutAnimation(snapshotSurface, false /* withStartDelay */, () -> {
+ mSurfaceControlTransactionFactory.getTransaction().remove(snapshotSurface).apply();
+ });
+ }
+
mPipBoundsState.setBounds(newBounds);
maybeUpdateMovementBounds();
}
@@ -259,4 +302,14 @@ public class PipScheduler {
void setPipAlphaAnimatorSupplier(@NonNull PipAlphaAnimatorSupplier supplier) {
mPipAlphaAnimatorSupplier = supplier;
}
+
+ void setPipParamsSupplier(@NonNull Supplier<PictureInPictureParams> pipParamsSupplier) {
+ mPipParamsSupplier = pipParamsSupplier;
+ }
+
+ @NonNull
+ private PictureInPictureParams getPipParams() {
+ if (mPipParamsSupplier == null) return new PictureInPictureParams.Builder().build();
+ return mPipParamsSupplier.get();
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
index dbcbf3663827..d6634845ee21 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
@@ -91,6 +91,7 @@ public class PipTaskListener implements ShellTaskOrganizer.TaskListener,
});
}
mPipResizeAnimatorSupplier = PipResizeAnimator::new;
+ mPipScheduler.setPipParamsSupplier(this::getPictureInPictureParams);
}
void setPictureInPictureParams(@Nullable PictureInPictureParams params) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 0cfab11dbc64..91fbd456eb63 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -50,7 +50,6 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.SystemProperties;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
@@ -102,15 +101,6 @@ public class PipTransition extends PipTransitionController implements
"animating_bounds_change_duration";
static final int BOUNDS_CHANGE_JUMPCUT_DURATION = 0;
- /**
- * The fixed start delay in ms when fading out the content overlay from bounds animation.
- * The fadeout animation is guaranteed to start after the client has drawn under the new config.
- */
- private static final int EXTRA_CONTENT_OVERLAY_FADE_OUT_DELAY_MS =
- SystemProperties.getInt(
- "persist.wm.debug.extra_content_overlay_fade_out_delay_ms", 400);
- private static final int CONTENT_OVERLAY_FADE_OUT_DURATION_MS = 500;
-
//
// Dependencies
//
@@ -481,7 +471,8 @@ public class PipTransition extends PipTransitionController implements
if (swipePipToHomeOverlay != null) {
// fadeout the overlay if needed.
- startOverlayFadeoutAnimation(swipePipToHomeOverlay, () -> {
+ mPipScheduler.startOverlayFadeoutAnimation(swipePipToHomeOverlay,
+ true /* withStartDelay */, () -> {
SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
tx.remove(swipePipToHomeOverlay);
tx.apply();
@@ -542,8 +533,8 @@ public class PipTransition extends PipTransitionController implements
animator.setAnimationStartCallback(() -> animator.setEnterStartState(pipChange));
animator.setAnimationEndCallback(() -> {
if (animator.getContentOverlayLeash() != null) {
- startOverlayFadeoutAnimation(animator.getContentOverlayLeash(),
- animator::clearAppIconOverlay);
+ mPipScheduler.startOverlayFadeoutAnimation(animator.getContentOverlayLeash(),
+ true /* withStartDelay */, animator::clearAppIconOverlay);
}
finishTransition();
});
@@ -551,16 +542,6 @@ public class PipTransition extends PipTransitionController implements
return true;
}
- private void startOverlayFadeoutAnimation(@NonNull SurfaceControl overlayLeash,
- @NonNull Runnable onAnimationEnd) {
- PipAlphaAnimator animator = new PipAlphaAnimator(mContext, overlayLeash,
- null /* startTx */, null /* finishTx */, PipAlphaAnimator.FADE_OUT);
- animator.setDuration(CONTENT_OVERLAY_FADE_OUT_DURATION_MS);
- animator.setStartDelay(EXTRA_CONTENT_OVERLAY_FADE_OUT_DELAY_MS);
- animator.setAnimationEndCallback(onAnimationEnd);
- animator.start();
- }
-
private void handleBoundsEnterFixedRotation(TransitionInfo info,
TransitionInfo.Change outPipTaskChange,
TransitionInfo.Change outPipActivityChange) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
index 0c1952910d1a..275e4882a79d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
@@ -28,6 +28,7 @@ import static org.mockito.kotlin.VerificationKt.times;
import static org.mockito.kotlin.VerificationKt.verify;
import android.app.ActivityManager;
+import android.app.PictureInPictureParams;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Matrix;
@@ -47,6 +48,7 @@ import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip2.animation.PipAlphaAnimator;
import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.util.StubTransaction;
import org.junit.Before;
import org.junit.Test;
@@ -107,6 +109,8 @@ public class PipSchedulerTest {
mPipScheduler.setSurfaceControlTransactionFactory(mMockFactory);
mPipScheduler.setPipAlphaAnimatorSupplier((context, leash, startTx, finishTx, direction) ->
mMockAlphaAnimator);
+ final PictureInPictureParams params = new PictureInPictureParams.Builder().build();
+ mPipScheduler.setPipParamsSupplier(() -> params);
SurfaceControl testLeash = new SurfaceControl.Builder()
.setContainerLayer()
@@ -289,6 +293,28 @@ public class PipSchedulerTest {
verify(mMockUpdateMovementBoundsRunnable, times(1)).run();
}
+ @Test
+ public void finishResize_nonSeamless_alphaAnimatorStarted() {
+ final PictureInPictureParams params =
+ new PictureInPictureParams.Builder().setSeamlessResizeEnabled(false).build();
+ mPipScheduler.setPipParamsSupplier(() -> params);
+ when(mMockFactory.getTransaction()).thenReturn(new StubTransaction());
+
+ mPipScheduler.scheduleFinishResizePip(TEST_BOUNDS);
+
+ verify(mMockAlphaAnimator, times(1)).start();
+ }
+
+ @Test
+ public void finishResize_seamless_animatorNotStarted() {
+ final PictureInPictureParams params =
+ new PictureInPictureParams.Builder().setSeamlessResizeEnabled(true).build();
+ mPipScheduler.setPipParamsSupplier(() -> params);
+
+ mPipScheduler.scheduleFinishResizePip(TEST_BOUNDS);
+ verify(mMockAlphaAnimator, never()).start();
+ }
+
private void setNullPipTaskToken() {
when(mMockPipTransitionState.getPipTaskToken()).thenReturn(null);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java
index 1b462c30e017..333569a7206e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java
@@ -294,6 +294,8 @@ public class PipTaskListenerTest {
mPipTaskListener = new PipTaskListener(mMockContext, mMockShellTaskOrganizer,
mMockPipTransitionState, mMockPipScheduler, mMockPipBoundsState,
mMockPipBoundsAlgorithm, mMockShellExecutor);
+ clearInvocations(mMockPipScheduler);
+
Bundle extras = new Bundle();
extras.putBoolean(ANIMATING_ASPECT_RATIO_CHANGE, false);