diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java index 16c0566a29b59..ca16cfc5141bd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java @@ -59,11 +59,6 @@ public class PipBoundsHandler { private int mDefaultMinSize; private Point mScreenEdgeInsets; - private boolean mIsImeShowing; - private int mImeHeight; - private boolean mIsShelfShowing; - private int mShelfHeight; - public PipBoundsHandler(Context context, @NonNull PipBoundsState pipBoundsState) { mPipBoundsState = pipBoundsState; mSnapAlgorithm = new PipSnapAlgorithm(context); @@ -100,29 +95,6 @@ public class PipBoundsHandler { com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio); } - /** - * Sets both shelf visibility and its height if applicable. - * @return {@code true} if the internal shelf state is changed, {@code false} otherwise. - */ - public boolean setShelfHeight(boolean shelfVisible, int shelfHeight) { - final boolean shelfShowing = shelfVisible && shelfHeight > 0; - if (shelfShowing == mIsShelfShowing && shelfHeight == mShelfHeight) { - return false; - } - - mIsShelfShowing = shelfVisible; - mShelfHeight = shelfHeight; - return true; - } - - /** - * Responds to IPinnedStackListener on IME visibility change. - */ - public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { - mIsImeShowing = imeVisible; - mImeHeight = imeHeight; - } - /** * Responds to IPinnedStackListener on movement bounds change. * Note that both inset and normal bounds will be calculated here rather than in the caller. @@ -360,8 +332,10 @@ public class PipBoundsHandler { mDefaultMinSize, displayInfo.logicalWidth, displayInfo.logicalHeight); } Gravity.apply(mDefaultStackGravity, defaultSize.getWidth(), defaultSize.getHeight(), - insetBounds, 0, Math.max(mIsImeShowing ? mImeHeight : 0, - mIsShelfShowing ? mShelfHeight : 0), defaultBounds); + insetBounds, 0, Math.max( + mPipBoundsState.isImeShowing() ? mPipBoundsState.getImeHeight() : 0, + mPipBoundsState.isShelfShowing() + ? mPipBoundsState.getShelfHeight() : 0), defaultBounds); } return defaultBounds; } @@ -396,7 +370,8 @@ public class PipBoundsHandler { // Apply the movement bounds adjustments based on the current state. mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds, - (adjustForIme && mIsImeShowing) ? mImeHeight : 0); + (adjustForIme && mPipBoundsState.isImeShowing()) + ? mPipBoundsState.getImeHeight() : 0); return movementBounds; } @@ -437,10 +412,6 @@ public class PipBoundsHandler { pw.println(innerPrefix + "mMinAspectRatio=" + mMinAspectRatio); pw.println(innerPrefix + "mMaxAspectRatio=" + mMaxAspectRatio); pw.println(innerPrefix + "mDefaultStackGravity=" + mDefaultStackGravity); - pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing); - pw.println(innerPrefix + "mImeHeight=" + mImeHeight); - pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing); - pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight); pw.println(innerPrefix + "mSnapAlgorithm" + mSnapAlgorithm); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java index 8d229d3774a28..78f7e25ee3fae 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java @@ -33,6 +33,7 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; +import java.util.function.BiConsumer; /** * Singleton source of truth for the current state of PIP bounds. @@ -66,8 +67,13 @@ public final class PipBoundsState { /** The preferred minimum (and default) size specified by apps. */ private Size mOverrideMinSize; private final @NonNull AnimatingBoundsState mAnimatingBoundsState = new AnimatingBoundsState(); + private boolean mIsImeShowing; + private int mImeHeight; + private boolean mIsShelfShowing; + private int mShelfHeight; private Runnable mOnMinimalSizeChangeCallback; + private BiConsumer mOnShelfVisibilityChangeCallback; public PipBoundsState(Context context) { mContext = context; @@ -245,6 +251,46 @@ public final class PipBoundsState { return mAnimatingBoundsState; } + /** Set whether the IME is currently showing and its height. */ + public void setImeVisibility(boolean imeShowing, int imeHeight) { + mIsImeShowing = imeShowing; + mImeHeight = imeHeight; + } + + /** Returns whether the IME is currently showing. */ + public boolean isImeShowing() { + return mIsImeShowing; + } + + /** Returns the IME height. */ + public int getImeHeight() { + return mImeHeight; + } + + /** Set whether the shelf is showing and its height. */ + public void setShelfVisibility(boolean showing, int height) { + final boolean shelfShowing = showing && height > 0; + if (shelfShowing == mIsShelfShowing && height == mShelfHeight) { + return; + } + + mIsShelfShowing = showing; + mShelfHeight = height; + if (mOnShelfVisibilityChangeCallback != null) { + mOnShelfVisibilityChangeCallback.accept(mIsShelfShowing, mShelfHeight); + } + } + + /** Returns whether the shelf is currently showing. */ + public boolean isShelfShowing() { + return mIsShelfShowing; + } + + /** Returns the shelf height. */ + public int getShelfHeight() { + return mShelfHeight; + } + /** * Registers a callback when the minimal size of PIP that is set by the app changes. */ @@ -252,6 +298,12 @@ public final class PipBoundsState { mOnMinimalSizeChangeCallback = onMinimalSizeChangeCallback; } + /** Set a callback to be notified when the shelf visibility changes. */ + public void setOnShelfVisibilityChangeCallback( + BiConsumer onShelfVisibilityChangeCallback) { + mOnShelfVisibilityChangeCallback = onShelfVisibilityChangeCallback; + } + /** Source of truth for the current animation bounds of PIP. */ public static class AnimatingBoundsState { /** The bounds used when PIP is being dragged or animated. */ @@ -345,6 +397,10 @@ public final class PipBoundsState { pw.println(innerPrefix + "mStashOffset=" + mStashOffset); pw.println(innerPrefix + "mMinEdgeSize=" + mMinEdgeSize); pw.println(innerPrefix + "mOverrideMinSize=" + mOverrideMinSize); + pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing); + pw.println(innerPrefix + "mImeHeight=" + mImeHeight); + pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing); + pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight); if (mPipReentryState == null) { pw.println(innerPrefix + "mPipReentryState=null"); } else { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index c7926455e0dec..5b549664672d3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -125,8 +125,8 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac // not during the fixed rotation. In fixed rotation case, app is about to enter PiP // and we need the offsets preserved to calculate the destination bounds. if (!mIsInFixedRotation) { - mPipBoundsHandler.setShelfHeight(false, 0); - mPipBoundsHandler.onImeVisibilityChanged(false, 0); + mPipBoundsState.setShelfVisibility(false /* showing */, 0 /* height */); + mPipBoundsState.setImeVisibility(false /* showing */, 0 /* height */); mTouchHandler.onShelfVisibilityChanged(false, 0); mTouchHandler.onImeVisibilityChanged(false, 0); } @@ -168,7 +168,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { mMainExecutor.execute(() -> { - mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight); + mPipBoundsState.setImeVisibility(imeVisible, imeHeight); mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight); }); } @@ -247,6 +247,12 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac mPipBoundsState = pipBoundsState; mPipTaskOrganizer = pipTaskOrganizer; mMainExecutor = mainExecutor; + mMediaController = pipMediaController; + mMenuController = pipMenuActivityController; + mTouchHandler = pipTouchHandler; + mAppOpsListener = pipAppOpsListener; + mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(), + INPUT_CONSUMER_PIP); mPipTaskOrganizer.registerPipTransitionCallback(this); mPipTaskOrganizer.registerOnDisplayIdChangeCallback((int displayId) -> { final DisplayInfo newDisplayInfo = new DisplayInfo(); @@ -263,17 +269,17 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac false /* fromImeAdjustment */, false /* fromShelfAdjustment */, null /* wct */); }); - mMediaController = pipMediaController; - mMenuController = pipMenuActivityController; - mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(), - INPUT_CONSUMER_PIP); - mTouchHandler = pipTouchHandler; + mPipBoundsState.setOnShelfVisibilityChangeCallback((isShowing, height) -> { + mTouchHandler.onShelfVisibilityChanged(isShowing, height); + updateMovementBounds(mPipBoundsState.getBounds(), + false /* fromRotation */, false /* fromImeAdjustment */, + true /* fromShelfAdjustment */, null /* windowContainerTransaction */); + }); if (mTouchHandler != null) { // Register the listener for input consumer touch events. Only for Phone mPipInputConsumer.setInputListener(mTouchHandler::handleTouchEvent); mPipInputConsumer.setRegistrationListener(mTouchHandler::onRegistrationChanged); } - mAppOpsListener = pipAppOpsListener; displayController.addDisplayChangingController(mRotationController); displayController.addDisplayWindowListener(mFixedRotationListener); @@ -413,13 +419,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac private void setShelfHeightLocked(boolean visible, int height) { final int shelfHeight = visible ? height : 0; - final boolean changed = mPipBoundsHandler.setShelfHeight(visible, shelfHeight); - if (changed) { - mTouchHandler.onShelfVisibilityChanged(visible, shelfHeight); - updateMovementBounds(mPipBoundsState.getBounds(), - false /* fromRotation */, false /* fromImeAdjustment */, - true /* fromShelfAdjustment */, null /* windowContainerTransaction */); - } + mPipBoundsState.setShelfVisibility(visible, shelfHeight); } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java index 402d79c6fbd1b..fd055d1a6685b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java @@ -184,7 +184,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { mHandler.post(() -> { - mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight); + mPipBoundsState.setImeVisibility(imeVisible, imeHeight); if (mState == STATE_PIP) { if (mImeVisible != imeVisible) { if (imeVisible) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java index 440e23ccedb7d..ba60d3d03f99f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java @@ -242,7 +242,7 @@ public class PipBoundsHandlerTest extends ShellTestCase { mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO); final Rect oldPosition = mPipBoundsHandler.getEntryDestinationBounds(); - mPipBoundsHandler.setShelfHeight(true, shelfHeight); + mPipBoundsState.setShelfVisibility(true, shelfHeight); final Rect newPosition = mPipBoundsHandler.getEntryDestinationBounds(); oldPosition.offset(0, -shelfHeight); @@ -255,7 +255,7 @@ public class PipBoundsHandlerTest extends ShellTestCase { mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO); final Rect oldPosition = mPipBoundsHandler.getEntryDestinationBounds(); - mPipBoundsHandler.onImeVisibilityChanged(true, imeHeight); + mPipBoundsState.setImeVisibility(true, imeHeight); final Rect newPosition = mPipBoundsHandler.getEntryDestinationBounds(); oldPosition.offset(0, -imeHeight); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java index 5e11de7c72d73..59e10c1890467 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java @@ -19,6 +19,9 @@ package com.android.wm.shell.pip; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import android.content.ComponentName; import android.graphics.Rect; @@ -34,6 +37,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.function.BiConsumer; + /** * Tests for {@link PipBoundsState}. */ @@ -109,4 +114,25 @@ public class PipBoundsStateTest extends ShellTestCase { assertNull(mPipBoundsState.getReentryState()); } + + @Test + public void testSetShelfVisibility_changed_callbackInvoked() { + final BiConsumer callback = mock(BiConsumer.class); + mPipBoundsState.setOnShelfVisibilityChangeCallback(callback); + + mPipBoundsState.setShelfVisibility(true, 100); + + verify(callback).accept(true, 100); + } + + @Test + public void testSetShelfVisibility_notChanged_callbackNotInvoked() { + final BiConsumer callback = mock(BiConsumer.class); + mPipBoundsState.setShelfVisibility(true, 100); + mPipBoundsState.setOnShelfVisibilityChangeCallback(callback); + + mPipBoundsState.setShelfVisibility(true, 100); + + verify(callback, never()).accept(true, 100); + } }