Report changed keep clear areas to TvPipController

Bug: 218416347
Test: atest DisplayContentTests#testKeepClearAreasMultipleWindows
Test: atest WindowStateTests#testKeepClearAreas
Change-Id: Ic61b1f11a27b0411baa5dfc5146c96700f751527
This commit is contained in:
Robert Horvath
2022-02-08 13:57:41 +01:00
parent b34bc34f42
commit a197b9759f
8 changed files with 100 additions and 30 deletions

View File

@@ -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<Rect> restricted,
List<Rect> unrestricted) {
private void onKeepClearAreasChanged(int displayId, Set<Rect> restricted,
Set<Rect> 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<Rect> restricted,
List<Rect> 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<Rect> restricted,
List<Rect> unrestricted) {}
default void onKeepClearAreasChanged(int displayId, Set<Rect> restricted,
Set<Rect> unrestricted) {}
}
}

View File

@@ -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));
}

View File

@@ -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<Rect> 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<Rect> mUnrestrictedKeepClearAreas = new ArraySet<>();
private @Nullable Runnable mOnMinimalSizeChangeCallback;
private @Nullable TriConsumer<Boolean, Integer, Boolean> 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<Rect> restrictedAreas,
@NonNull Set<Rect> unrestrictedAreas) {
mRestrictedKeepClearAreas.clear();
mRestrictedKeepClearAreas.addAll(restrictedAreas);
mUnrestrictedKeepClearAreas.clear();
mUnrestrictedKeepClearAreas.addAll(unrestrictedAreas);
}
@NonNull
public Set<Rect> getRestrictedKeepClearAreas() {
return mRestrictedKeepClearAreas;
}
@NonNull
public Set<Rect> getUnrestrictedKeepClearAreas() {
return mUnrestrictedKeepClearAreas;
}
/**
* Initialize states when first entering PiP.
*/

View File

@@ -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<Rect> restricted,
Set<Rect> 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.
*/

View File

@@ -414,6 +414,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
private final Region mSystemGestureExclusionUnrestricted = new Region();
private int mSystemGestureExclusionLimit;
private Set<Rect> mRestrictedKeepClearAreas = new ArraySet<>();
private Set<Rect> 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<Rect> keepClearAreas = getKeepClearAreas();
final Set<Rect> 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<Rect> restrictedKeepClearAreas = new ArrayList();
final List<Rect> unrestrictedKeepClearAreas = new ArrayList();
final Set<Rect> restrictedKeepClearAreas = new ArraySet<>();
final Set<Rect> 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<Rect> outRestricted, List<Rect> outUnrestricted) {
void getKeepClearAreas(Set<Rect> outRestricted, Set<Rect> 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<Rect> getKeepClearAreas() {
final ArrayList<Rect> keepClearAreas = new ArrayList<Rect>();
Set<Rect> getKeepClearAreas() {
final Set<Rect> keepClearAreas = new ArraySet<>();
getKeepClearAreas(keepClearAreas, keepClearAreas);
return keepClearAreas;
}

View File

@@ -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<Rect> restricted,
List<Rect> unrestricted) {
void dispatchKeepClearAreasChanged(DisplayContent display, Set<Rect> restricted,
Set<Rect> 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) {
}
}

View File

@@ -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<WindowState> 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<Rect> outRestricted, List<Rect> outUnrestricted) {
void getKeepClearAreas(Collection<Rect> outRestricted, Collection<Rect> 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<WindowState> 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<Rect> outRestricted, List<Rect> outUnrestricted, Matrix tmpMatrix,
float[] float9) {
void getKeepClearAreas(Collection<Rect> outRestricted, Collection<Rect> outUnrestricted,
Matrix tmpMatrix, float[] float9) {
outRestricted.addAll(getRectsInScreenSpace(mKeepClearAreas, tmpMatrix, float9));
outUnrestricted.addAll(
getRectsInScreenSpace(mUnrestrictedKeepClearAreas, tmpMatrix, float9));

View File

@@ -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) {