summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
author Ikram Gabiyev <gabiyev@google.com> 2025-03-05 14:34:30 -0800
committer Ikram Gabiyev <gabiyev@google.com> 2025-03-06 10:00:11 -0800
commitff56fe9985c255cf78977846ef98ce814e5e9768 (patch)
tree28148ff103abbac592ca86cf38723b1fd231f851 /libs
parent46bc22e872a2b7df15534c2f82e4e7bde031fe20 (diff)
[PiP2] End overlay animation if user interacts
If source-rect-hint is not valid we run an app icon overlay fadeout animation after entering PiP. But with PiP2 using config-at-end transitions we actually allow users to interact with PiP earlier after entry than in PiP1. So if PiP is resized or tap-con-to-expand is triggered, overlay's offset and transform isn't really adjusted to reflect the new follow-up transitions with new buffer sizes. So we take the approach of just ending the overlay fadeout animation if needed when either EXITING_PIP or when we have SCHEDULED_BOUNDS_CHANGE. Bug: 399512881 Flag: com.android.wm.shell.enable_pip2 Test: enter PiP with wrong src-rect-hint, then tap app icon to reopen Test: enter PiP with wrong src-rect-hint, then pinch-resize after Change-Id: Icc0fb90bcac53b7e9e0df293f77dd37c88aadd92
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java45
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java26
2 files changed, 65 insertions, 6 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 383afcf6f821..f81f330e50c4 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
@@ -20,6 +20,7 @@ import android.app.PictureInPictureParams;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.SystemProperties;
import android.view.SurfaceControl;
import android.window.WindowContainerToken;
@@ -47,7 +48,7 @@ import java.util.function.Supplier;
/**
* Scheduler for Shell initiated PiP transitions and animations.
*/
-public class PipScheduler {
+public class PipScheduler implements PipTransitionState.PipTransitionStateChangedListener {
private static final String TAG = PipScheduler.class.getSimpleName();
/**
@@ -71,6 +72,7 @@ public class PipScheduler {
private final PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;
@Nullable private Runnable mUpdateMovementBoundsRunnable;
+ @Nullable private PipAlphaAnimator mOverlayFadeoutAnimator;
private PipAlphaAnimatorSupplier mPipAlphaAnimatorSupplier;
private Supplier<PictureInPictureParams> mPipParamsSupplier;
@@ -85,6 +87,7 @@ public class PipScheduler {
mPipBoundsState = pipBoundsState;
mMainExecutor = mainExecutor;
mPipTransitionState = pipTransitionState;
+ mPipTransitionState.addPipTransitionStateChangedListener(this);
mPipDesktopState = pipDesktopState;
mSplitScreenControllerOptional = splitScreenControllerOptional;
@@ -238,12 +241,16 @@ public class PipScheduler {
void startOverlayFadeoutAnimation(@NonNull SurfaceControl overlayLeash,
boolean withStartDelay, @NonNull Runnable onAnimationEnd) {
- PipAlphaAnimator animator = mPipAlphaAnimatorSupplier.get(mContext, overlayLeash,
+ mOverlayFadeoutAnimator = 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();
+ mOverlayFadeoutAnimator.setDuration(CONTENT_OVERLAY_FADE_OUT_DURATION_MS);
+ mOverlayFadeoutAnimator.setStartDelay(withStartDelay
+ ? EXTRA_CONTENT_OVERLAY_FADE_OUT_DELAY_MS : 0);
+ mOverlayFadeoutAnimator.setAnimationEndCallback(() -> {
+ onAnimationEnd.run();
+ mOverlayFadeoutAnimator = null;
+ });
+ mOverlayFadeoutAnimator.start();
}
void setUpdateMovementBoundsRunnable(@Nullable Runnable updateMovementBoundsRunnable) {
@@ -289,6 +296,21 @@ public class PipScheduler {
mSurfaceControlTransactionFactory = factory;
}
+ @Override
+ public void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
+ @PipTransitionState.TransitionState int newState,
+ @android.annotation.Nullable Bundle extra) {
+ switch (newState) {
+ case PipTransitionState.EXITING_PIP:
+ case PipTransitionState.SCHEDULED_BOUNDS_CHANGE:
+ if (mOverlayFadeoutAnimator != null && mOverlayFadeoutAnimator.isStarted()) {
+ mOverlayFadeoutAnimator.end();
+ mOverlayFadeoutAnimator = null;
+ }
+ break;
+ }
+ }
+
@VisibleForTesting
interface PipAlphaAnimatorSupplier {
PipAlphaAnimator get(@NonNull Context context,
@@ -303,6 +325,17 @@ public class PipScheduler {
mPipAlphaAnimatorSupplier = supplier;
}
+ @VisibleForTesting
+ void setOverlayFadeoutAnimator(@NonNull PipAlphaAnimator animator) {
+ mOverlayFadeoutAnimator = animator;
+ }
+
+ @VisibleForTesting
+ @Nullable
+ PipAlphaAnimator getOverlayFadeoutAnimator() {
+ return mOverlayFadeoutAnimator;
+ }
+
void setPipParamsSupplier(@NonNull Supplier<PictureInPictureParams> pipParamsSupplier) {
mPipParamsSupplier = pipParamsSupplier;
}
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 275e4882a79d..42f65dd71f16 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
@@ -17,6 +17,7 @@
package com.android.wm.shell.pip2.phone;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -86,6 +87,7 @@ public class PipSchedulerTest {
@Mock private SurfaceControl.Transaction mMockTransaction;
@Mock private PipAlphaAnimator mMockAlphaAnimator;
@Mock private SplitScreenController mMockSplitScreenController;
+ @Mock private SurfaceControl mMockLeash;
@Captor private ArgumentCaptor<Runnable> mRunnableArgumentCaptor;
@Captor private ArgumentCaptor<WindowContainerTransaction> mWctArgumentCaptor;
@@ -315,6 +317,30 @@ public class PipSchedulerTest {
verify(mMockAlphaAnimator, never()).start();
}
+ @Test
+ public void onPipTransitionStateChanged_exiting_endAnimation() {
+ mPipScheduler.setOverlayFadeoutAnimator(mMockAlphaAnimator);
+ when(mMockAlphaAnimator.isStarted()).thenReturn(true);
+ mPipScheduler.onPipTransitionStateChanged(PipTransitionState.ENTERED_PIP,
+ PipTransitionState.EXITING_PIP, null);
+
+ verify(mMockAlphaAnimator, times(1)).end();
+ assertNull("mOverlayFadeoutAnimator should be reset to null",
+ mPipScheduler.getOverlayFadeoutAnimator());
+ }
+
+ @Test
+ public void onPipTransitionStateChanged_scheduledBoundsChange_endAnimation() {
+ mPipScheduler.setOverlayFadeoutAnimator(mMockAlphaAnimator);
+ when(mMockAlphaAnimator.isStarted()).thenReturn(true);
+ mPipScheduler.onPipTransitionStateChanged(PipTransitionState.ENTERED_PIP,
+ PipTransitionState.SCHEDULED_BOUNDS_CHANGE, null);
+
+ verify(mMockAlphaAnimator, times(1)).end();
+ assertNull("mOverlayFadeoutAnimator should be reset to null",
+ mPipScheduler.getOverlayFadeoutAnimator());
+ }
+
private void setNullPipTaskToken() {
when(mMockPipTransitionState.getPipTaskToken()).thenReturn(null);
}