From e9e4ca3ecd5a39487f83332d971b42d43560498d Mon Sep 17 00:00:00 2001 From: Hongwei Wang Date: Fri, 17 Jun 2022 14:00:12 -0700 Subject: [PATCH] Get PiP state from Shell in EdgeBackGestureHandler We use to rely on the onActivityPinned and onActivityUnpinned callbacks from Window Manager in EdgeBackGestureHandler to determine the current PiP state and it will always be reset to false when EdgeBackGestureHandler is being re-created, for instance, as a result of folded state change. Deprecated also the Pip#setPinnedStackAnimationListener interface method since it's not in use and it may cause confusions over IPip#setPinnedStackAnimationListener. Bug: 174702196 Bug: 198651351 Test: stash in unfolded state -> fold -> drag to unstash \ stash in folded state -> unfold -> drag to unstash Test: atest WMShellUnitTests:PipControllerTest Change-Id: Id874056415011ee8a55dadcd4ec6af6e1b568092 --- .../wm/shell/dagger/WMShellModule.java | 7 ++-- .../src/com/android/wm/shell/pip/Pip.java | 8 ++--- .../wm/shell/pip/PipTransitionState.java | 36 +++++++++++++++++-- .../wm/shell/pip/phone/PipController.java | 33 ++++++++++++++++- .../wm/shell/pip/phone/PipControllerTest.java | 10 +++--- .../gestural/EdgeBackGestureHandler.java | 32 ++++++++++------- 6 files changed, 98 insertions(+), 28 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 1e369899e3546..a8c1071eb69e4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -68,15 +68,15 @@ import com.android.wm.shell.pip.phone.PipTouchHandler; import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.transition.Transitions; -import com.android.wm.shell.unfold.UnfoldAnimationController; import com.android.wm.shell.unfold.ShellUnfoldProgressProvider; +import com.android.wm.shell.unfold.UnfoldAnimationController; import com.android.wm.shell.unfold.UnfoldBackgroundController; import com.android.wm.shell.unfold.UnfoldTransitionHandler; import com.android.wm.shell.unfold.animation.FullscreenUnfoldTaskAnimator; import com.android.wm.shell.unfold.animation.SplitTaskUnfoldAnimator; import com.android.wm.shell.unfold.animation.UnfoldTaskAnimator; -import com.android.wm.shell.unfold.qualifier.UnfoldTransition; import com.android.wm.shell.unfold.qualifier.UnfoldShellTransition; +import com.android.wm.shell.unfold.qualifier.UnfoldTransition; import com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel; import com.android.wm.shell.windowdecor.WindowDecorViewModel; @@ -218,6 +218,7 @@ public abstract class WMShellModule { PipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState, PipMotionHelper pipMotionHelper, PipMediaController pipMediaController, PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer, + PipTransitionState pipTransitionState, PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController, WindowManagerShellWrapper windowManagerShellWrapper, TaskStackListenerImpl taskStackListener, @@ -227,7 +228,7 @@ public abstract class WMShellModule { return Optional.ofNullable(PipController.create(context, displayController, pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper, - pipMediaController, phonePipMenuController, pipTaskOrganizer, + pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController, windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder, oneHandedController, mainExecutor)); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java index 3b3091a9caf3e..bbc47e47afc5f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java @@ -86,12 +86,12 @@ public interface Pip { } /** - * Registers the pinned stack animation listener. + * Set the callback when {@link PipTaskOrganizer#isInPip()} state is changed. * - * @param callback The callback of pinned stack animation. + * @param callback The callback accepts the result of {@link PipTaskOrganizer#isInPip()} + * when it's changed. */ - default void setPinnedStackAnimationListener(Consumer callback) { - } + default void setOnIsInPipStateChangedListener(Consumer callback) {} /** * Set the pinned stack with {@link PipAnimationController.AnimationType} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java index 85e56b7dd99f5..1a4be3b41911c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java @@ -17,12 +17,15 @@ package com.android.wm.shell.pip; import android.annotation.IntDef; +import android.annotation.NonNull; import android.app.PictureInPictureParams; import android.content.ComponentName; import android.content.pm.ActivityInfo; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; /** * Used to keep track of PiP leash state as it appears and animates by {@link PipTaskOrganizer} and @@ -37,6 +40,9 @@ public class PipTransitionState { public static final int ENTERED_PIP = 4; public static final int EXITING_PIP = 5; + private final List mOnPipTransitionStateChangedListeners = + new ArrayList<>(); + /** * If set to {@code true}, no entering PiP transition would be kicked off and most likely * it's due to the fact that Launcher is handling the transition directly when swiping @@ -65,7 +71,13 @@ public class PipTransitionState { } public void setTransitionState(@TransitionState int state) { - mState = state; + if (mState != state) { + for (int i = 0; i < mOnPipTransitionStateChangedListeners.size(); i++) { + mOnPipTransitionStateChangedListeners.get(i).onPipTransitionStateChanged( + mState, state); + } + mState = state; + } } public @TransitionState int getTransitionState() { @@ -73,8 +85,7 @@ public class PipTransitionState { } public boolean isInPip() { - return mState >= TASK_APPEARED - && mState != EXITING_PIP; + return isInPip(mState); } public void setInSwipePipToHomeTransition(boolean inSwipePipToHomeTransition) { @@ -94,4 +105,23 @@ public class PipTransitionState { return mState < ENTERING_PIP || mState == EXITING_PIP; } + + public void addOnPipTransitionStateChangedListener( + @NonNull OnPipTransitionStateChangedListener listener) { + mOnPipTransitionStateChangedListeners.add(listener); + } + + public void removeOnPipTransitionStateChangedListener( + @NonNull OnPipTransitionStateChangedListener listener) { + mOnPipTransitionStateChangedListeners.remove(listener); + } + + public static boolean isInPip(@TransitionState int state) { + return state >= TASK_APPEARED && state != EXITING_PIP; + } + + public interface OnPipTransitionStateChangedListener { + void onPipTransitionStateChanged(@TransitionState int oldState, + @TransitionState int newState); + } } 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 c3e6d82df781c..3000998f210d5 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 @@ -84,6 +84,7 @@ import com.android.wm.shell.pip.PipParamsChangedForwarder; import com.android.wm.shell.pip.PipSnapAlgorithm; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipTransitionController; +import com.android.wm.shell.pip.PipTransitionState; import com.android.wm.shell.pip.PipUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.transition.Transitions; @@ -128,11 +129,14 @@ public class PipController implements PipTransitionController.PipTransitionCallb protected PhonePipMenuController mMenuController; protected PipTaskOrganizer mPipTaskOrganizer; + private PipTransitionState mPipTransitionState; protected PinnedStackListenerForwarder.PinnedTaskListener mPinnedTaskListener = new PipControllerPinnedTaskListener(); private boolean mIsKeyguardShowingOrAnimating; + private Consumer mOnIsInPipStateChangedListener; + private interface PipAnimationListener { /** * Notifies the listener that the Pip animation is started. @@ -291,6 +295,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb PipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState, PipMotionHelper pipMotionHelper, PipMediaController pipMediaController, PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer, + PipTransitionState pipTransitionState, PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController, WindowManagerShellWrapper windowManagerShellWrapper, TaskStackListenerImpl taskStackListener, @@ -305,7 +310,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb return new PipController(context, displayController, pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper, pipMediaController, - phonePipMenuController, pipTaskOrganizer, pipTouchHandler, pipTransitionController, + phonePipMenuController, pipTaskOrganizer, pipTransitionState, + pipTouchHandler, pipTransitionController, windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder, oneHandedController, mainExecutor) .mImpl; @@ -321,6 +327,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb PipMediaController pipMediaController, PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer, + PipTransitionState pipTransitionState, PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController, WindowManagerShellWrapper windowManagerShellWrapper, @@ -344,6 +351,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipBoundsState = pipBoundsState; mPipMotionHelper = pipMotionHelper; mPipTaskOrganizer = pipTaskOrganizer; + mPipTransitionState = pipTransitionState; mMainExecutor = mainExecutor; mMediaController = pipMediaController; mMenuController = phonePipMenuController; @@ -370,6 +378,15 @@ public class PipController implements PipTransitionController.PipTransitionCallb onDisplayChanged(mDisplayController.getDisplayLayout(displayId), false /* saveRestoreSnapFraction */); }); + mPipTransitionState.addOnPipTransitionStateChangedListener((oldState, newState) -> { + if (mOnIsInPipStateChangedListener != null) { + final boolean wasInPip = PipTransitionState.isInPip(oldState); + final boolean nowInPip = PipTransitionState.isInPip(newState); + if (nowInPip != wasInPip) { + mOnIsInPipStateChangedListener.accept(nowInPip); + } + } + }); mPipBoundsState.setOnMinimalSizeChangeCallback( () -> { // The minimal size drives the normal bounds, so they need to be recalculated. @@ -664,6 +681,13 @@ public class PipController implements PipTransitionController.PipTransitionCallb } } + private void setOnIsInPipStateChangedListener(Consumer callback) { + mOnIsInPipStateChangedListener = callback; + if (mOnIsInPipStateChangedListener != null) { + callback.accept(mPipTransitionState.isInPip()); + } + } + private void setShelfHeightLocked(boolean visible, int height) { final int shelfHeight = visible ? height : 0; mPipBoundsState.setShelfVisibility(visible, shelfHeight); @@ -940,6 +964,13 @@ public class PipController implements PipTransitionController.PipTransitionCallb }); } + @Override + public void setOnIsInPipStateChangedListener(Consumer callback) { + mMainExecutor.execute(() -> { + PipController.this.setOnIsInPipStateChangedListener(callback); + }); + } + @Override public void setPinnedStackAnimationType(int animationType) { mMainExecutor.execute(() -> { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java index abd55dd7d6062..babc9707ef9ce 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java @@ -53,6 +53,7 @@ import com.android.wm.shell.pip.PipParamsChangedForwarder; import com.android.wm.shell.pip.PipSnapAlgorithm; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipTransitionController; +import com.android.wm.shell.pip.PipTransitionState; import org.junit.Before; import org.junit.Test; @@ -80,6 +81,7 @@ public class PipControllerTest extends ShellTestCase { @Mock private PipSnapAlgorithm mMockPipSnapAlgorithm; @Mock private PipMediaController mMockPipMediaController; @Mock private PipTaskOrganizer mMockPipTaskOrganizer; + @Mock private PipTransitionState mMockPipTransitionState; @Mock private PipTransitionController mMockPipTransitionController; @Mock private PipTouchHandler mMockPipTouchHandler; @Mock private PipMotionHelper mMockPipMotionHelper; @@ -104,8 +106,8 @@ public class PipControllerTest extends ShellTestCase { mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm, mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController, - mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTouchHandler, - mMockPipTransitionController, mMockWindowManagerShellWrapper, + mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState, + mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper, mMockTaskStackListener, mPipParamsChangedForwarder, mMockOneHandedController, mMockExecutor); when(mMockPipBoundsAlgorithm.getSnapAlgorithm()).thenReturn(mMockPipSnapAlgorithm); @@ -138,8 +140,8 @@ public class PipControllerTest extends ShellTestCase { mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm, mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController, - mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTouchHandler, - mMockPipTransitionController, mMockWindowManagerShellWrapper, + mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState, + mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper, mMockTaskStackListener, mPipParamsChangedForwarder, mMockOneHandedController, mMockExecutor)); } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index e210d685a370b..3039d9d56c803 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -84,13 +84,16 @@ import com.android.systemui.tracing.ProtoTracer; import com.android.systemui.tracing.nano.EdgeBackGestureHandlerProto; import com.android.systemui.tracing.nano.SystemUiTraceProto; import com.android.wm.shell.back.BackAnimation; +import com.android.wm.shell.pip.Pip; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.Executor; +import java.util.function.Consumer; import javax.inject.Inject; @@ -147,16 +150,6 @@ public class EdgeBackGestureHandler extends CurrentUserTracker mPackageName = "_UNKNOWN"; } } - - @Override - public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { - mIsInPipMode = true; - } - - @Override - public void onActivityUnpinned() { - mIsInPipMode = false; - } }; private DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener = @@ -188,6 +181,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker private final ViewConfiguration mViewConfiguration; private final WindowManager mWindowManager; private final IWindowManager mWindowManagerService; + private final Optional mPipOptional; private final FalsingManager mFalsingManager; // Activities which should not trigger Back gesture. private final List mGestureBlockingActivities = new ArrayList<>(); @@ -218,6 +212,8 @@ public class EdgeBackGestureHandler extends CurrentUserTracker // We temporarily disable back gesture when user is quickswitching // between apps of different orientations private boolean mDisabledForQuickstep; + // This gets updated when the value of PipTransitionState#isInPip changes. + private boolean mIsInPip; private final PointF mDownPoint = new PointF(); private final PointF mEndPoint = new PointF(); @@ -233,7 +229,6 @@ public class EdgeBackGestureHandler extends CurrentUserTracker private boolean mIsNavBarShownTransiently; private boolean mIsBackGestureAllowed; private boolean mGestureBlockingActivityRunning; - private boolean mIsInPipMode; private boolean mIsNewBackAffordanceEnabled; private InputMonitor mInputMonitor; @@ -302,6 +297,8 @@ public class EdgeBackGestureHandler extends CurrentUserTracker } }; + private final Consumer mOnIsInPipStateChangedListener = + (isInPip) -> mIsInPip = isInPip; EdgeBackGestureHandler( Context context, @@ -316,6 +313,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker ViewConfiguration viewConfiguration, WindowManager windowManager, IWindowManager windowManagerService, + Optional pipOptional, FalsingManager falsingManager, LatencyTracker latencyTracker, FeatureFlags featureFlags) { @@ -332,6 +330,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker mViewConfiguration = viewConfiguration; mWindowManager = windowManager; mWindowManagerService = windowManagerService; + mPipOptional = pipOptional; mFalsingManager = falsingManager; mLatencyTracker = latencyTracker; mFeatureFlags = featureFlags; @@ -491,6 +490,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker mPluginManager.removePluginListener(this); TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener); DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener); + mPipOptional.ifPresent(pip -> pip.setOnIsInPipStateChangedListener(null)); try { mWindowManagerService.unregisterSystemGestureExclusionListener( @@ -508,6 +508,8 @@ public class EdgeBackGestureHandler extends CurrentUserTracker TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener); DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mMainExecutor::execute, mOnPropertiesChangedListener); + mPipOptional.ifPresent( + pip -> pip.setOnIsInPipStateChangedListener(mOnIsInPipStateChangedListener)); try { mWindowManagerService.registerSystemGestureExclusionListener( @@ -680,7 +682,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker private boolean isWithinTouchRegion(int x, int y) { // If the point is inside the PiP or Nav bar overlay excluded bounds, then ignore the back // gesture - final boolean isInsidePip = mIsInPipMode && mPipExcludedBounds.contains(x, y); + final boolean isInsidePip = mIsInPip && mPipExcludedBounds.contains(x, y); if (isInsidePip || mNavBarOverlayExcludedBounds.contains(x, y)) { return false; } @@ -933,7 +935,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker pw.println(" mInRejectedExclusion=" + mInRejectedExclusion); pw.println(" mExcludeRegion=" + mExcludeRegion); pw.println(" mUnrestrictedExcludeRegion=" + mUnrestrictedExcludeRegion); - pw.println(" mIsInPipMode=" + mIsInPipMode); + pw.println(" mIsInPip=" + mIsInPip); pw.println(" mPipExcludedBounds=" + mPipExcludedBounds); pw.println(" mNavBarOverlayExcludedBounds=" + mNavBarOverlayExcludedBounds); pw.println(" mEdgeWidthLeft=" + mEdgeWidthLeft); @@ -1002,6 +1004,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker private final ViewConfiguration mViewConfiguration; private final WindowManager mWindowManager; private final IWindowManager mWindowManagerService; + private final Optional mPipOptional; private final FalsingManager mFalsingManager; private final LatencyTracker mLatencyTracker; private final FeatureFlags mFeatureFlags; @@ -1018,6 +1021,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker ViewConfiguration viewConfiguration, WindowManager windowManager, IWindowManager windowManagerService, + Optional pipOptional, FalsingManager falsingManager, LatencyTracker latencyTracker, FeatureFlags featureFlags) { @@ -1032,6 +1036,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker mViewConfiguration = viewConfiguration; mWindowManager = windowManager; mWindowManagerService = windowManagerService; + mPipOptional = pipOptional; mFalsingManager = falsingManager; mLatencyTracker = latencyTracker; mFeatureFlags = featureFlags; @@ -1052,6 +1057,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker mViewConfiguration, mWindowManager, mWindowManagerService, + mPipOptional, mFalsingManager, mLatencyTracker, mFeatureFlags);