From 82865fe924fdaeb81cb7b152f4c39c0b90fce08d Mon Sep 17 00:00:00 2001 From: Ben Lin Date: Thu, 9 Dec 2021 15:02:18 -0800 Subject: [PATCH] Update PiP exclusion bounds in TaskBarDelegate. Navigation bar is only created and used when taskbar is not available. When taskbar is available, we will use TaskbarDelegate to be the one responsible to update pip exclusion bounds as PiP moves. Bug: 210038947 Test: Unfold, enter PiP, stash - PiP can be yanked out Change-Id: I8f789d3b603e41c3d15494afdadce2cddc4d4b9c --- .../src/com/android/wm/shell/pip/Pip.java | 14 +++++++--- .../android/wm/shell/pip/PipBoundsState.java | 26 +++++++++++++------ .../wm/shell/pip/phone/PipController.java | 11 ++++++-- .../wm/shell/pip/PipBoundsStateTest.java | 2 +- .../systemui/navigationbar/NavigationBar.java | 3 ++- .../NavigationBarController.java | 7 +++-- .../navigationbar/NavigationBarView.java | 12 ++++++--- .../navigationbar/TaskbarDelegate.java | 21 ++++++++++++++- .../NavigationBarControllerTest.java | 6 ++++- 9 files changed, 78 insertions(+), 24 deletions(-) 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 6d4773bdeb1f6..c0734e95ecb7f 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 @@ -112,11 +112,17 @@ public interface Pip { default void showPictureInPictureMenu() {} /** - * Called by NavigationBar in order to listen in for PiP bounds change. This is mostly used - * for times where the PiP bounds could conflict with SystemUI elements, such as a stashed - * PiP and the Back-from-Edge gesture. + * Called by NavigationBar and TaskbarDelegate in order to listen in for PiP bounds change. This + * is mostly used for times where the PiP bounds could conflict with SystemUI elements, such as + * a stashed PiP and the Back-from-Edge gesture. */ - default void setPipExclusionBoundsChangeListener(Consumer listener) { } + default void addPipExclusionBoundsChangeListener(Consumer listener) { } + + /** + * Remove a callback added previously. This is used when NavigationBar is removed from the + * view hierarchy or destroyed. + */ + default void removePipExclusionBoundsChangeListener(Consumer listener) { } /** * Dump the current state and information if need. 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 e3674dc920d5d..b3558ad4b91ef 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 @@ -38,6 +38,8 @@ import com.android.wm.shell.common.DisplayLayout; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.function.Consumer; @@ -89,7 +91,7 @@ public final class PipBoundsState { private @Nullable Runnable mOnMinimalSizeChangeCallback; private @Nullable TriConsumer mOnShelfVisibilityChangeCallback; - private @Nullable Consumer mOnPipExclusionBoundsChangeCallback; + private List> mOnPipExclusionBoundsChangeCallbacks = new ArrayList<>(); public PipBoundsState(@NonNull Context context) { mContext = context; @@ -108,8 +110,8 @@ public final class PipBoundsState { /** Set the current PIP bounds. */ public void setBounds(@NonNull Rect bounds) { mBounds.set(bounds); - if (mOnPipExclusionBoundsChangeCallback != null) { - mOnPipExclusionBoundsChangeCallback.accept(bounds); + for (Consumer callback : mOnPipExclusionBoundsChangeCallbacks) { + callback.accept(bounds); } } @@ -407,17 +409,25 @@ public final class PipBoundsState { } /** - * Set a callback to watch out for PiP bounds. This is mostly used by SystemUI's + * Add a callback to watch out for PiP bounds. This is mostly used by SystemUI's * Back-gesture handler, to avoid conflicting with PiP when it's stashed. */ - public void setPipExclusionBoundsChangeCallback( + public void addPipExclusionBoundsChangeCallback( @Nullable Consumer onPipExclusionBoundsChangeCallback) { - mOnPipExclusionBoundsChangeCallback = onPipExclusionBoundsChangeCallback; - if (mOnPipExclusionBoundsChangeCallback != null) { - mOnPipExclusionBoundsChangeCallback.accept(getBounds()); + mOnPipExclusionBoundsChangeCallbacks.add(onPipExclusionBoundsChangeCallback); + for (Consumer callback : mOnPipExclusionBoundsChangeCallbacks) { + callback.accept(getBounds()); } } + /** + * Remove a callback that was previously added. + */ + public void removePipExclusionBoundsChangeCallback( + @Nullable Consumer onPipExclusionBoundsChangeCallback) { + mOnPipExclusionBoundsChangeCallbacks.remove(onPipExclusionBoundsChangeCallback); + } + /** Source of truth for the current bounds of PIP that may be in motion. */ public static class MotionBoundsState { /** The bounds used when PIP is in motion (e.g. during a drag or animation) */ 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 26fd962ea6c56..a41fd8429e358 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 @@ -843,9 +843,16 @@ public class PipController implements PipTransitionController.PipTransitionCallb } @Override - public void setPipExclusionBoundsChangeListener(Consumer listener) { + public void addPipExclusionBoundsChangeListener(Consumer listener) { mMainExecutor.execute(() -> { - mPipBoundsState.setPipExclusionBoundsChangeCallback(listener); + mPipBoundsState.addPipExclusionBoundsChangeCallback(listener); + }); + } + + @Override + public void removePipExclusionBoundsChangeListener(Consumer listener) { + mMainExecutor.execute(() -> { + mPipBoundsState.removePipExclusionBoundsChangeCallback(listener); }); } 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 a6215d3347a83..8e30f65cee782 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 @@ -188,7 +188,7 @@ public class PipBoundsStateTest extends ShellTestCase { final Rect newBounds = new Rect(50, 50, 100, 75); mPipBoundsState.setBounds(currentBounds); - mPipBoundsState.setPipExclusionBoundsChangeCallback(callback); + mPipBoundsState.addPipExclusionBoundsChangeCallback(callback); // Setting the listener immediately calls back with the current bounds. verify(callback).accept(currentBounds); diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java index 7a12ecc097a27..963576bc7dc27 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java @@ -628,7 +628,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater); mSplitScreenOptional.ifPresent(mNavigationBarView::registerDockedListener); - mPipOptional.ifPresent(mNavigationBarView::registerPipExclusionBoundsChangeListener); + mPipOptional.ifPresent(mNavigationBarView::addPipExclusionBoundsChangeListener); prepareNavigationBarView(); checkNavBarModes(); @@ -699,6 +699,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, mHandler.removeCallbacks(mOnVariableDurationHomeLongClick); mHandler.removeCallbacks(mEnableLayoutTransitions); mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater); + mPipOptional.ifPresent(mNavigationBarView::removePipExclusionBoundsChangeListener); mFrame = null; mNavigationBarView = null; mOrientationHandle = null; diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java index bfabf716803ba..a984974c6bbae 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java @@ -59,9 +59,11 @@ import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode; import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.wm.shell.pip.Pip; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.Optional; import javax.inject.Inject; @@ -106,7 +108,8 @@ public class NavigationBarController implements NavigationBar.Factory navigationBarFactory, DumpManager dumpManager, AutoHideController autoHideController, - LightBarController lightBarController) { + LightBarController lightBarController, + Optional pipOptional) { mContext = context; mHandler = mainHandler; mNavigationBarFactory = navigationBarFactory; @@ -118,7 +121,7 @@ public class NavigationBarController implements mTaskbarDelegate = taskbarDelegate; mTaskbarDelegate.setDependencies(commandQueue, overviewProxyService, navBarHelper, navigationModeController, sysUiFlagsContainer, - dumpManager, autoHideController, lightBarController); + dumpManager, autoHideController, lightBarController, pipOptional); mIsTablet = isTablet(mContext); dumpManager.registerDumpable(this); } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java index 7c8c3e0dce440..7adb7ac92dc1e 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java @@ -75,12 +75,12 @@ import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; import com.android.systemui.navigationbar.buttons.NearestTouchFrame; import com.android.systemui.navigationbar.buttons.RotationContextButton; import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; -import com.android.systemui.shared.rotation.FloatingRotationButton; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; +import com.android.systemui.shared.navigationbar.RegionSamplingHelper; +import com.android.systemui.shared.rotation.FloatingRotationButton; import com.android.systemui.shared.rotation.RotationButton.RotationButtonUpdatesCallback; import com.android.systemui.shared.rotation.RotationButtonController; -import com.android.systemui.shared.navigationbar.RegionSamplingHelper; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.SysUiStatsLog; @@ -1386,8 +1386,12 @@ public class NavigationBarView extends FrameLayout implements legacySplitScreen.registerInSplitScreenListener(mDockedListener); } - void registerPipExclusionBoundsChangeListener(Pip pip) { - pip.setPipExclusionBoundsChangeListener(mPipListener); + void addPipExclusionBoundsChangeListener(Pip pip) { + pip.addPipExclusionBoundsChangeListener(mPipListener); + } + + void removePipExclusionBoundsChangeListener(Pip pip) { + pip.removePipExclusionBoundsChangeListener(mPipListener); } private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) { diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java index 68f4aeaa7f170..feda99fd34710 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java @@ -40,6 +40,7 @@ import android.app.StatusBarManager.WindowVisibleState; import android.content.ComponentCallbacks; import android.content.Context; import android.content.res.Configuration; +import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.inputmethodservice.InputMethodService; import android.os.IBinder; @@ -68,9 +69,12 @@ import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.BarTransitions; import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.LightBarTransitionsController; +import com.android.wm.shell.pip.Pip; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.Optional; +import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Singleton; @@ -91,6 +95,7 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, private AutoHideController mAutoHideController; private LightBarController mLightBarController; private LightBarTransitionsController mLightBarTransitionsController; + private Optional mPipOptional; private int mDisplayId; private int mNavigationIconHints; private final NavBarHelper.NavbarTaskbarStateUpdater mNavbarTaskbarStateUpdater = @@ -113,6 +118,7 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, private Context mWindowContext; private ScreenPinningNotify mScreenPinningNotify; private int mNavigationMode; + private final Consumer mPipListener; /** * Tracks the system calls for when taskbar should transiently show or hide so we can return @@ -143,6 +149,7 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, .create(context); mContext = context; mDisplayManager = mContext.getSystemService(DisplayManager.class); + mPipListener = mEdgeBackGestureHandler::setPipStashExclusionBounds; } public void setDependencies(CommandQueue commandQueue, @@ -151,7 +158,8 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, NavigationModeController navigationModeController, SysUiState sysUiState, DumpManager dumpManager, AutoHideController autoHideController, - LightBarController lightBarController) { + LightBarController lightBarController, + Optional pipOptional) { // TODO: adding this in the ctor results in a dagger dependency cycle :( mCommandQueue = commandQueue; mOverviewProxyService = overviewProxyService; @@ -162,6 +170,7 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, mAutoHideController = autoHideController; mLightBarController = lightBarController; mLightBarTransitionsController = createLightBarTransitionsController(); + mPipOptional = pipOptional; } // Separated into a method to keep setDependencies() clean/readable. @@ -207,6 +216,7 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, updateSysuiFlags(); mAutoHideController.setNavigationBar(mAutoHideUiElement); mLightBarController.setNavigationBar(mLightBarTransitionsController); + mPipOptional.ifPresent(this::addPipExclusionBoundsChangeListener); mInitialized = true; } @@ -228,9 +238,18 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, mAutoHideController.setNavigationBar(null); mLightBarTransitionsController.destroy(mContext); mLightBarController.setNavigationBar(null); + mPipOptional.ifPresent(this::removePipExclusionBoundsChangeListener); mInitialized = false; } + void addPipExclusionBoundsChangeListener(Pip pip) { + pip.addPipExclusionBoundsChangeListener(mPipListener); + } + + void removePipExclusionBoundsChangeListener(Pip pip) { + pip.removePipExclusionBoundsChangeListener(mPipListener); + } + /** * Returns {@code true} if this taskBar is {@link #init(int)}. Returns {@code false} if this * taskbar has not yet been {@link #init(int)} or has been {@link #destroy()}. diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java index 9d2541c0150fe..3e8e8748a6799 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java @@ -47,6 +47,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.wm.shell.pip.Pip; import org.junit.After; import org.junit.Before; @@ -55,6 +56,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Optional; + /** atest NavigationBarControllerTest */ @RunWith(AndroidTestingRunner.class) @RunWithLooper @@ -88,7 +91,8 @@ public class NavigationBarControllerTest extends SysuiTestCase { mNavigationBarFactory, mock(DumpManager.class), mock(AutoHideController.class), - mock(LightBarController.class))); + mock(LightBarController.class), + Optional.of(mock(Pip.class)))); initializeNavigationBars(); }