From a197b9759fbcd91640802bf65449ccece038905b Mon Sep 17 00:00:00 2001 From: Robert Horvath Date: Tue, 8 Feb 2022 13:57:41 +0100 Subject: [PATCH] Report changed keep clear areas to TvPipController Bug: 218416347 Test: atest DisplayContentTests#testKeepClearAreasMultipleWindows Test: atest WindowStateTests#testKeepClearAreas Change-Id: Ic61b1f11a27b0411baa5dfc5146c96700f751527 --- .../wm/shell/common/DisplayController.java | 13 ++++--- .../android/wm/shell/dagger/TvPipModule.java | 2 + .../android/wm/shell/pip/PipBoundsState.java | 39 +++++++++++++++++++ .../wm/shell/pip/tv/TvPipController.java | 18 ++++++++- .../com/android/server/wm/DisplayContent.java | 25 ++++++++---- .../wm/DisplayWindowListenerController.java | 11 +++--- .../com/android/server/wm/WindowState.java | 15 +++---- .../server/wm/DisplayContentTests.java | 7 ++-- 8 files changed, 100 insertions(+), 30 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java index 9384e2b4dfdf9..d22fb50390527 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java @@ -22,6 +22,7 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.os.RemoteException; +import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import android.view.Display; @@ -36,6 +37,7 @@ import com.android.wm.shell.common.annotations.ShellMainThread; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * This module deals with display rotations coming from WM. When WM starts a rotation: after it has @@ -245,8 +247,8 @@ public class DisplayController { } } - private void onKeepClearAreasChanged(int displayId, List restricted, - List unrestricted) { + private void onKeepClearAreasChanged(int displayId, Set restricted, + Set unrestricted) { synchronized (mDisplays) { if (mDisplays.get(displayId) == null || getDisplay(displayId) == null) { Slog.w(TAG, "Skipping onKeepClearAreasChanged on unknown" @@ -323,7 +325,8 @@ public class DisplayController { public void onKeepClearAreasChanged(int displayId, List restricted, List unrestricted) { mMainExecutor.execute(() -> { - DisplayController.this.onKeepClearAreasChanged(displayId, restricted, unrestricted); + DisplayController.this.onKeepClearAreasChanged(displayId, + new ArraySet<>(restricted), new ArraySet<>(unrestricted)); }); } } @@ -364,7 +367,7 @@ public class DisplayController { /** * Called when keep-clear areas on a display have changed. */ - default void onKeepClearAreasChanged(int displayId, List restricted, - List unrestricted) {} + default void onKeepClearAreasChanged(int displayId, Set restricted, + Set unrestricted) {} } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java index 4f160427dca66..491dff08187f4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java @@ -68,6 +68,7 @@ public abstract class TvPipModule { PipTransitionController pipTransitionController, TvPipNotificationController tvPipNotificationController, TaskStackListenerImpl taskStackListener, + DisplayController displayController, WindowManagerShellWrapper windowManagerShellWrapper, @ShellMainThread ShellExecutor mainExecutor) { return Optional.of( @@ -81,6 +82,7 @@ public abstract class TvPipModule { pipMediaController, tvPipNotificationController, taskStackListener, + displayController, windowManagerShellWrapper, mainExecutor)); } 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 bebf2cad83a42..210ea54baf588 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 @@ -28,6 +28,7 @@ import android.content.pm.ActivityInfo; import android.graphics.Point; import android.graphics.Rect; import android.os.RemoteException; +import android.util.ArraySet; import android.util.Log; import android.util.Size; import android.view.Display; @@ -43,6 +44,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.function.Consumer; /** @@ -90,6 +92,24 @@ public class PipBoundsState { private int mShelfHeight; /** Whether the user has resized the PIP manually. */ private boolean mHasUserResizedPip; + /** + * Areas defined by currently visible apps that they prefer to keep clear from overlays such as + * the PiP. Restricted areas may only move the PiP a limited amount from its anchor position. + * The system will try to respect these areas, but when not possible will ignore them. + * + * @see android.view.View#setPreferKeepClearRects + */ + private final Set mRestrictedKeepClearAreas = new ArraySet<>(); + /** + * Areas defined by currently visible apps holding + * {@link android.Manifest.permission#SET_UNRESTRICTED_KEEP_CLEAR_AREAS} that they prefer to + * keep clear from overlays such as the PiP. + * Unrestricted areas can move the PiP farther than restricted areas, and the system will try + * harder to respect these areas. + * + * @see android.view.View#setPreferKeepClearRects + */ + private final Set mUnrestrictedKeepClearAreas = new ArraySet<>(); private @Nullable Runnable mOnMinimalSizeChangeCallback; private @Nullable TriConsumer mOnShelfVisibilityChangeCallback; @@ -367,6 +387,25 @@ public class PipBoundsState { } } + /** Set the keep clear areas onscreen. The PiP should ideally not cover them. */ + public void setKeepClearAreas(@NonNull Set restrictedAreas, + @NonNull Set unrestrictedAreas) { + mRestrictedKeepClearAreas.clear(); + mRestrictedKeepClearAreas.addAll(restrictedAreas); + mUnrestrictedKeepClearAreas.clear(); + mUnrestrictedKeepClearAreas.addAll(unrestrictedAreas); + } + + @NonNull + public Set getRestrictedKeepClearAreas() { + return mRestrictedKeepClearAreas; + } + + @NonNull + public Set getUnrestrictedKeepClearAreas() { + return mUnrestrictedKeepClearAreas; + } + /** * Initialize states when first entering PiP. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java index 50691803e8f92..3c830e0a0d62e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java @@ -37,6 +37,7 @@ import android.view.Gravity; import com.android.wm.shell.R; import com.android.wm.shell.WindowManagerShellWrapper; +import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerCallback; @@ -50,12 +51,14 @@ import com.android.wm.shell.pip.PipTransitionController; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Set; /** * Manages the picture-in-picture (PIP) UI and states. */ public class TvPipController implements PipTransitionController.PipTransitionCallback, - TvPipMenuController.Delegate, TvPipNotificationController.Delegate { + TvPipMenuController.Delegate, TvPipNotificationController.Delegate, + DisplayController.OnDisplaysChangedListener { private static final String TAG = "TvPipController"; static final boolean DEBUG = false; @@ -112,6 +115,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal PipMediaController pipMediaController, TvPipNotificationController pipNotificationController, TaskStackListenerImpl taskStackListener, + DisplayController displayController, WindowManagerShellWrapper wmShell, ShellExecutor mainExecutor) { return new TvPipController( @@ -124,6 +128,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal pipMediaController, pipNotificationController, taskStackListener, + displayController, wmShell, mainExecutor).mImpl; } @@ -138,6 +143,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal PipMediaController pipMediaController, TvPipNotificationController pipNotificationController, TaskStackListenerImpl taskStackListener, + DisplayController displayController, WindowManagerShellWrapper wmShell, ShellExecutor mainExecutor) { mContext = context; @@ -163,6 +169,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal registerTaskStackListenerCallback(taskStackListener); registerWmShellPinnedStackListener(wmShell); + displayController.addDisplayWindowListener(this); } private void onConfigurationChanged(Configuration newConfig) { @@ -253,6 +260,15 @@ public class TvPipController implements PipTransitionController.PipTransitionCal return mTvPipBoundsState.getTvFixedPipOrientation(); } + @Override + public void onKeepClearAreasChanged(int displayId, Set restricted, + Set unrestricted) { + if (mTvPipBoundsState.getDisplayId() == displayId) { + mTvPipBoundsState.setKeepClearAreas(restricted, unrestricted); + movePinnedStack(); + } + } + /** * Animate to the updated position of the PiP based on the state and position of the PiP. */ diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index e80d323c3e36f..718a28de6af93 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -414,6 +414,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp private final Region mSystemGestureExclusionUnrestricted = new Region(); private int mSystemGestureExclusionLimit; + private Set mRestrictedKeepClearAreas = new ArraySet<>(); + private Set mUnrestrictedKeepClearAreas = new ArraySet<>(); + /** * For default display it contains real metrics, empty for others. * @see WindowManagerService#createWatermark() @@ -3351,7 +3354,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp pw.println(mSystemGestureExclusion); } - final List keepClearAreas = getKeepClearAreas(); + final Set keepClearAreas = getKeepClearAreas(); if (!keepClearAreas.isEmpty()) { pw.println(); pw.print(" keepClearAreas="); @@ -5453,11 +5456,17 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } void updateKeepClearAreas() { - final List restrictedKeepClearAreas = new ArrayList(); - final List unrestrictedKeepClearAreas = new ArrayList(); + final Set restrictedKeepClearAreas = new ArraySet<>(); + final Set unrestrictedKeepClearAreas = new ArraySet<>(); getKeepClearAreas(restrictedKeepClearAreas, unrestrictedKeepClearAreas); - mWmService.mDisplayNotificationController.dispatchKeepClearAreasChanged( - this, restrictedKeepClearAreas, unrestrictedKeepClearAreas); + + if (!mRestrictedKeepClearAreas.equals(restrictedKeepClearAreas) + || !mUnrestrictedKeepClearAreas.equals(unrestrictedKeepClearAreas)) { + mRestrictedKeepClearAreas = restrictedKeepClearAreas; + mUnrestrictedKeepClearAreas = unrestrictedKeepClearAreas; + mWmService.mDisplayNotificationController.dispatchKeepClearAreasChanged( + this, restrictedKeepClearAreas, unrestrictedKeepClearAreas); + } } /** @@ -5469,7 +5478,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * For context on restricted vs unrestricted keep-clear areas, see * {@link android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS}. */ - void getKeepClearAreas(List outRestricted, List outUnrestricted) { + void getKeepClearAreas(Set outRestricted, Set outUnrestricted) { final Matrix tmpMatrix = new Matrix(); final float[] tmpFloat9 = new float[9]; forAllWindows(w -> { @@ -5486,8 +5495,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp /** * Returns all keep-clear areas from visible, relevant windows on this display. */ - ArrayList getKeepClearAreas() { - final ArrayList keepClearAreas = new ArrayList(); + Set getKeepClearAreas() { + final Set keepClearAreas = new ArraySet<>(); getKeepClearAreas(keepClearAreas, keepClearAreas); return keepClearAreas; } diff --git a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java index e18d5396831a2..fa7a99d55896d 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java +++ b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java @@ -23,7 +23,8 @@ import android.os.RemoteException; import android.util.IntArray; import android.view.IDisplayWindowListener; -import java.util.List; +import java.util.ArrayList; +import java.util.Set; /** * Manages dispatch of relevant hierarchy changes to interested listeners. Listeners are assumed @@ -120,13 +121,13 @@ class DisplayWindowListenerController { mDisplayListeners.finishBroadcast(); } - void dispatchKeepClearAreasChanged(DisplayContent display, List restricted, - List unrestricted) { + void dispatchKeepClearAreasChanged(DisplayContent display, Set restricted, + Set unrestricted) { int count = mDisplayListeners.beginBroadcast(); for (int i = 0; i < count; ++i) { try { - mDisplayListeners.getBroadcastItem(i).onKeepClearAreasChanged( - display.mDisplayId, restricted, unrestricted); + mDisplayListeners.getBroadcastItem(i).onKeepClearAreasChanged(display.mDisplayId, + new ArrayList<>(restricted), new ArrayList<>(unrestricted)); } catch (RemoteException e) { } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index d547275dcf0c2..ccd42364f6a39 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -263,6 +263,7 @@ import dalvik.annotation.optimization.NeverCompile; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.function.Consumer; @@ -1034,10 +1035,10 @@ class WindowState extends WindowContainer implements WindowManagerP * The system is more careful about restricted ones and may apply restrictions to them, while * the unrestricted ones are considered safe. * - * @param outRestricted list to add restricted keep-clear areas to - * @param outUnrestricted list to add unrestricted keep-clear areas to + * @param outRestricted collection to add restricted keep-clear areas to + * @param outUnrestricted collection to add unrestricted keep-clear areas to */ - void getKeepClearAreas(List outRestricted, List outUnrestricted) { + void getKeepClearAreas(Collection outRestricted, Collection outUnrestricted) { final Matrix tmpMatrix = new Matrix(); final float[] tmpFloat9 = new float[9]; getKeepClearAreas(outRestricted, outUnrestricted, tmpMatrix, tmpFloat9); @@ -1049,13 +1050,13 @@ class WindowState extends WindowContainer implements WindowManagerP * The system is more careful about restricted ones and may apply restrictions to them, while * the unrestricted ones are considered safe. * - * @param outRestricted list to add restricted keep-clear areas to - * @param outUnrestricted list to add unrestricted keep-clear areas to + * @param outRestricted collection to add restricted keep-clear areas to + * @param outUnrestricted collection to add unrestricted keep-clear areas to * @param tmpMatrix a temporary matrix to be used for transformations * @param float9 a temporary array of 9 floats */ - void getKeepClearAreas(List outRestricted, List outUnrestricted, Matrix tmpMatrix, - float[] float9) { + void getKeepClearAreas(Collection outRestricted, Collection outUnrestricted, + Matrix tmpMatrix, float[] float9) { outRestricted.addAll(getRectsInScreenSpace(mKeepClearAreas, tmpMatrix, float9)); outUnrestricted.addAll( getRectsInScreenSpace(mUnrestrictedKeepClearAreas, tmpMatrix, float9)); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index ed5ea9c15734a..12f987dfcd8d6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -2388,19 +2388,18 @@ public class DisplayContentTests extends WindowTestsBase { w2.setKeepClearAreas(Arrays.asList(rect2), Collections.emptyList()); // No keep clear areas on display, because the windows are not visible - assertEquals(Arrays.asList(), mDisplayContent.getKeepClearAreas()); + assertEquals(Collections.emptySet(), mDisplayContent.getKeepClearAreas()); makeWindowVisible(w1); // The returned keep-clear areas contain the areas just from the visible window - assertEquals(new ArraySet(Arrays.asList(rect1)), - new ArraySet(mDisplayContent.getKeepClearAreas())); + assertEquals(new ArraySet(Arrays.asList(rect1)), mDisplayContent.getKeepClearAreas()); makeWindowVisible(w1, w2); // The returned keep-clear areas contain the areas from all visible windows assertEquals(new ArraySet(Arrays.asList(rect1, rect2)), - new ArraySet(mDisplayContent.getKeepClearAreas())); + mDisplayContent.getKeepClearAreas()); } private void removeRootTaskTests(Runnable runnable) {