diff options
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 1e369899e354..a8c1071eb69e 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 3b3091a9caf3..bbc47e47afc5 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<Boolean> callback) { - } + default void setOnIsInPipStateChangedListener(Consumer<Boolean> 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 85e56b7dd99f..1a4be3b41911 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<OnPipTransitionStateChangedListener> 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 c3e6d82df781..3000998f210d 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<Boolean> 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<Boolean> 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); @@ -941,6 +965,13 @@ public class PipController implements PipTransitionController.PipTransitionCallb } @Override + public void setOnIsInPipStateChangedListener(Consumer<Boolean> callback) { + mMainExecutor.execute(() -> { + PipController.this.setOnIsInPipStateChangedListener(callback); + }); + } + + @Override public void setPinnedStackAnimationType(int animationType) { mMainExecutor.execute(() -> { PipController.this.setPinnedStackAnimationType(animationType); 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 abd55dd7d606..babc9707ef9c 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 e210d685a370..3039d9d56c80 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<Pip> mPipOptional; private final FalsingManager mFalsingManager; // Activities which should not trigger Back gesture. private final List<ComponentName> 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<Boolean> mOnIsInPipStateChangedListener = + (isInPip) -> mIsInPip = isInPip; EdgeBackGestureHandler( Context context, @@ -316,6 +313,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker ViewConfiguration viewConfiguration, WindowManager windowManager, IWindowManager windowManagerService, + Optional<Pip> 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<Pip> 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<Pip> 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); |