Merge "GestureNav: Limit exclusion rects" into qt-dev am: ea3216d462

am: de8014e068

Change-Id: Ibaa2b5dbe34ed53f3c64feca4d71dfa43b6d5f44
This commit is contained in:
Jorim Jaggi
2019-06-28 08:53:29 -07:00
committed by android-build-merger
6 changed files with 175 additions and 8 deletions

View File

@@ -2295,6 +2295,7 @@ package android.provider {
field public static final String NAMESPACE_PRIVACY = "privacy"; field public static final String NAMESPACE_PRIVACY = "privacy";
field public static final String NAMESPACE_ROLLBACK = "rollback"; field public static final String NAMESPACE_ROLLBACK = "rollback";
field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot"; field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
field public static final String NAMESPACE_WINDOW_MANAGER = "android:window_manager";
} }
public static interface DeviceConfig.OnPropertiesChangedListener { public static interface DeviceConfig.OnPropertiesChangedListener {
@@ -2311,6 +2312,10 @@ package android.provider {
method @Nullable public String getString(@NonNull String, @Nullable String); method @Nullable public String getString(@NonNull String, @Nullable String);
} }
public static interface DeviceConfig.WindowManager {
field public static final String KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP = "system_gesture_exclusion_limit_dp";
}
public final class MediaStore { public final class MediaStore {
method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;

View File

@@ -284,6 +284,15 @@ public final class DeviceConfig {
*/ */
public static final String NAMESPACE_SETTINGS_UI = "settings_ui"; public static final String NAMESPACE_SETTINGS_UI = "settings_ui";
/**
* Namespace for window manager related features. The names to access the properties in this
* namespace should be defined in {@link WindowManager}.
*
* @hide
*/
@TestApi
public static final String NAMESPACE_WINDOW_MANAGER = "android:window_manager";
/** /**
* List of namespaces which can be read without READ_DEVICE_CONFIG permission * List of namespaces which can be read without READ_DEVICE_CONFIG permission
* *
@@ -301,6 +310,23 @@ public final class DeviceConfig {
@TestApi @TestApi
public static final String NAMESPACE_PRIVACY = "privacy"; public static final String NAMESPACE_PRIVACY = "privacy";
/**
* Interface for accessing keys belonging to {@link #NAMESPACE_WINDOW_MANAGER}.
* @hide
*/
@TestApi
public interface WindowManager {
/**
* Key for accessing the system gesture exclusion limit (an integer in dp).
*
* @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER
* @hide
*/
@TestApi
String KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP = "system_gesture_exclusion_limit_dp";
}
private static final Object sLock = new Object(); private static final Object sLock = new Object();
@GuardedBy("sLock") @GuardedBy("sLock")
private static ArrayMap<OnPropertyChangedListener, Pair<String, Executor>> sSingleListeners = private static ArrayMap<OnPropertyChangedListener, Pair<String, Executor>> sSingleListeners =

View File

@@ -30,16 +30,21 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE; import static android.view.Display.FLAG_PRIVATE;
import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.INVALID_DISPLAY;
import static android.view.InsetsState.TYPE_IME; import static android.view.InsetsState.TYPE_IME;
import static android.view.InsetsState.TYPE_LEFT_GESTURES;
import static android.view.InsetsState.TYPE_RIGHT_GESTURES;
import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90; import static android.view.Surface.ROTATION_90;
import static android.view.View.GONE; import static android.view.View.GONE;
import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
import static android.view.WindowManager.DOCKED_BOTTOM; import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID; import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_TOP; import static android.view.WindowManager.DOCKED_TOP;
@@ -135,6 +140,7 @@ import static com.android.server.wm.WindowManagerService.logSurface;
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP; import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING; import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW; import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
import static com.android.server.wm.utils.RegionUtils.forEachRect;
import static com.android.server.wm.utils.RegionUtils.rectListToRegion; import static com.android.server.wm.utils.RegionUtils.rectListToRegion;
import android.animation.AnimationHandler; import android.animation.AnimationHandler;
@@ -324,6 +330,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
private final RemoteCallbackList<ISystemGestureExclusionListener> private final RemoteCallbackList<ISystemGestureExclusionListener>
mSystemGestureExclusionListeners = new RemoteCallbackList<>(); mSystemGestureExclusionListeners = new RemoteCallbackList<>();
private final Region mSystemGestureExclusion = new Region(); private final Region mSystemGestureExclusion = new Region();
private int mSystemGestureExclusionLimit;
/** /**
* For default display it contains real metrics, empty for others. * For default display it contains real metrics, empty for others.
@@ -894,6 +901,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mWallpaperController = new WallpaperController(mWmService, this); mWallpaperController = new WallpaperController(mWmService, this);
display.getDisplayInfo(mDisplayInfo); display.getDisplayInfo(mDisplayInfo);
display.getMetrics(mDisplayMetrics); display.getMetrics(mDisplayMetrics);
mSystemGestureExclusionLimit = mWmService.mSystemGestureExclusionLimitDp
* mDisplayMetrics.densityDpi / DENSITY_DEFAULT;
isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY; isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
mDisplayFrames = new DisplayFrames(mDisplayId, mDisplayInfo, mDisplayFrames = new DisplayFrames(mDisplayId, mDisplayInfo,
calculateDisplayCutoutForRotation(mDisplayInfo.rotation)); calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
@@ -1549,8 +1558,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
longSize = height; longSize = height;
} }
final int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / mBaseDisplayDensity; final int shortSizeDp = shortSize * DENSITY_DEFAULT / mBaseDisplayDensity;
final int longSizeDp = longSize * DisplayMetrics.DENSITY_DEFAULT / mBaseDisplayDensity; final int longSizeDp = longSize * DENSITY_DEFAULT / mBaseDisplayDensity;
mDisplayPolicy.updateConfigurationAndScreenSizeDependentBehaviors(); mDisplayPolicy.updateConfigurationAndScreenSizeDependentBehaviors();
mDisplayRotation.configure(width, height, shortSizeDp, longSizeDp); mDisplayRotation.configure(width, height, shortSizeDp, longSizeDp);
@@ -2200,6 +2209,18 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
onDisplayChanged(this); onDisplayChanged(this);
} }
@Override
void onDisplayChanged(DisplayContent dc) {
super.onDisplayChanged(dc);
updateSystemGestureExclusionLimit();
}
void updateSystemGestureExclusionLimit() {
mSystemGestureExclusionLimit = mWmService.mSystemGestureExclusionLimitDp
* mDisplayMetrics.densityDpi / DENSITY_DEFAULT;
updateSystemGestureExclusion();
}
void initializeDisplayBaseInfo() { void initializeDisplayBaseInfo() {
final DisplayManagerInternal displayManagerInternal = mWmService.mDisplayManagerInternal; final DisplayManagerInternal displayManagerInternal = mWmService.mDisplayManagerInternal;
if (displayManagerInternal != null) { if (displayManagerInternal != null) {
@@ -5140,24 +5161,35 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
@VisibleForTesting @VisibleForTesting
Region calculateSystemGestureExclusion() { Region calculateSystemGestureExclusion() {
final Region unhandled = Region.obtain();
unhandled.set(0, 0, mDisplayFrames.mDisplayWidth, mDisplayFrames.mDisplayHeight);
final Rect leftEdge = mInsetsStateController.getSourceProvider(TYPE_LEFT_GESTURES)
.getSource().getFrame();
final Rect rightEdge = mInsetsStateController.getSourceProvider(TYPE_RIGHT_GESTURES)
.getSource().getFrame();
final Region global = Region.obtain(); final Region global = Region.obtain();
final Region touchableRegion = Region.obtain(); final Region touchableRegion = Region.obtain();
final Region local = Region.obtain(); final Region local = Region.obtain();
final int[] remainingLeftRight =
{mSystemGestureExclusionLimit, mSystemGestureExclusionLimit};
// Traverse all windows bottom up to assemble the gesture exclusion rects. // Traverse all windows bottom up to assemble the gesture exclusion rects.
// For each window, we only take the rects that fall within its touchable region. // For each window, we only take the rects that fall within its touchable region.
forAllWindows(w -> { forAllWindows(w -> {
if (w.cantReceiveTouchInput() || !w.isVisible() if (w.cantReceiveTouchInput() || !w.isVisible()
|| (w.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0) { || (w.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0
|| unhandled.isEmpty()) {
return; return;
} }
final boolean modal = final boolean modal =
(w.mAttrs.flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0; (w.mAttrs.flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;
// Only keep the exclusion zones from the windows behind where the current window // Get the touchable region of the window, and intersect with where the screen is still
// isn't touchable. // touchable, i.e. touchable regions on top are not covering it yet.
w.getTouchableRegion(touchableRegion); w.getTouchableRegion(touchableRegion);
global.op(touchableRegion, Op.DIFFERENCE); touchableRegion.op(unhandled, Op.INTERSECT);
rectListToRegion(w.getSystemGestureExclusion(), local); rectListToRegion(w.getSystemGestureExclusion(), local);
@@ -5169,13 +5201,78 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// A window can only exclude system gestures where it is actually touchable // A window can only exclude system gestures where it is actually touchable
local.op(touchableRegion, Op.INTERSECT); local.op(touchableRegion, Op.INTERSECT);
global.op(local, Op.UNION); // Apply restriction if necessary.
}, false /* topToBottom */); if (needsGestureExclusionRestrictions(w, mLastDispatchedSystemUiVisibility)) {
// Processes the region along the left edge.
remainingLeftRight[0] = addToGlobalAndConsumeLimit(local, global, leftEdge,
remainingLeftRight[0]);
// Processes the region along the right edge.
remainingLeftRight[1] = addToGlobalAndConsumeLimit(local, global, rightEdge,
remainingLeftRight[1]);
// Adds the middle (unrestricted area)
final Region middle = Region.obtain(local);
middle.op(leftEdge, Op.DIFFERENCE);
middle.op(rightEdge, Op.DIFFERENCE);
global.op(middle, Op.UNION);
middle.recycle();
} else {
global.op(local, Op.UNION);
}
unhandled.op(touchableRegion, Op.DIFFERENCE);
}, true /* topToBottom */);
local.recycle(); local.recycle();
touchableRegion.recycle(); touchableRegion.recycle();
unhandled.recycle();
return global; return global;
} }
/**
* @return Whether gesture exclusion area should be restricted from the window depending on the
* current SystemUI visibility flags.
*/
private static boolean needsGestureExclusionRestrictions(WindowState win, int sysUiVisibility) {
final int type = win.mAttrs.type;
final int stickyHideNavFlags =
SYSTEM_UI_FLAG_HIDE_NAVIGATION | SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
final boolean stickyHideNav =
(sysUiVisibility & stickyHideNavFlags) == stickyHideNavFlags;
return !stickyHideNav && type != TYPE_INPUT_METHOD && type != TYPE_STATUS_BAR
&& win.getActivityType() != ACTIVITY_TYPE_HOME;
}
/**
* Adds a local gesture exclusion area to the global area while applying a limit per edge.
*
* @param local The gesture exclusion area to add.
* @param global The destination.
* @param edge Only processes the part in that region.
* @param limit How much limit in pixels we have.
* @return How much of the limit are remaining.
*/
private static int addToGlobalAndConsumeLimit(Region local, Region global, Rect edge,
int limit) {
final Region r = Region.obtain(local);
r.op(edge, Op.INTERSECT);
final int[] remaining = {limit};
forEachRect(r, rect -> {
if (remaining[0] <= 0) {
return;
}
final int height = rect.height();
if (height > remaining[0]) {
rect.bottom = rect.top + remaining[0];
}
remaining[0] -= height;
global.op(rect, Op.UNION);
});
r.recycle();
return remaining[0];
}
void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener) { void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener) {
mSystemGestureExclusionListeners.register(listener); mSystemGestureExclusionListeners.register(listener);
final boolean changed; final boolean changed;

View File

@@ -32,6 +32,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID; import static android.os.Process.SYSTEM_UID;
import static android.os.Process.myPid; import static android.os.Process.myPid;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.INVALID_DISPLAY;
@@ -154,6 +155,7 @@ import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Debug; import android.os.Debug;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder; import android.os.IBinder;
import android.os.IRemoteCallback; import android.os.IRemoteCallback;
import android.os.Looper; import android.os.Looper;
@@ -175,6 +177,7 @@ import android.os.SystemService;
import android.os.Trace; import android.os.Trace;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.WorkSource; import android.os.WorkSource;
import android.provider.DeviceConfig;
import android.provider.Settings; import android.provider.Settings;
import android.service.vr.IVrManager; import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks; import android.service.vr.IVrStateCallbacks;
@@ -380,6 +383,8 @@ public class WindowManagerService extends IWindowManager.Stub
private static final int ANIMATION_COMPLETED_TIMEOUT_MS = 5000; private static final int ANIMATION_COMPLETED_TIMEOUT_MS = 5000;
private static final int MIN_GESTURE_EXCLUSION_LIMIT_DP = 200;
final WindowTracing mWindowTracing; final WindowTracing mWindowTracing;
final private KeyguardDisableHandler mKeyguardDisableHandler; final private KeyguardDisableHandler mKeyguardDisableHandler;
@@ -838,6 +843,8 @@ public class WindowManagerService extends IWindowManager.Stub
final ArrayList<WindowChangeListener> mWindowChangeListeners = new ArrayList<>(); final ArrayList<WindowChangeListener> mWindowChangeListeners = new ArrayList<>();
boolean mWindowsChanged = false; boolean mWindowsChanged = false;
int mSystemGestureExclusionLimitDp;
public interface WindowChangeListener { public interface WindowChangeListener {
public void windowsChanged(); public void windowsChanged();
public void focusChanged(); public void focusChanged();
@@ -1132,6 +1139,21 @@ public class WindowManagerService extends IWindowManager.Stub
this, mInputManager, mActivityTaskManager, mH.getLooper()); this, mInputManager, mActivityTaskManager, mH.getLooper());
mDragDropController = new DragDropController(this, mH.getLooper()); mDragDropController = new DragDropController(this, mH.getLooper());
mSystemGestureExclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP,
DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
new HandlerExecutor(mH), properties -> {
synchronized (mGlobalLock) {
final int exclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP,
properties.getInt(KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
if (mSystemGestureExclusionLimitDp != exclusionLimitDp) {
mSystemGestureExclusionLimitDp = exclusionLimitDp;
mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit);
}
}
});
LocalServices.addService(WindowManagerInternal.class, new LocalService()); LocalServices.addService(WindowManagerInternal.class, new LocalService());
} }

View File

@@ -18,8 +18,10 @@ package com.android.server.wm.utils;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.Region; import android.graphics.Region;
import android.graphics.RegionIterator;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
/** /**
* Utility methods to handle Regions. * Utility methods to handle Regions.
@@ -42,4 +44,18 @@ public class RegionUtils {
outRegion.union(rects.get(i)); outRegion.union(rects.get(i));
} }
} }
/**
* Applies actions on each rect contained within a {@code Region}.
*
* @param region the given region.
* @param rectConsumer the action holder.
*/
public static void forEachRect(Region region, Consumer<Rect> rectConsumer) {
final RegionIterator it = new RegionIterator(region);
final Rect rect = new Rect();
while (it.next(rect)) {
rectConsumer.accept(rect);
}
}
} }

View File

@@ -36,6 +36,7 @@
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" /> <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.REORDER_TASKS" /> <uses-permission android:name="android.permission.REORDER_TASKS" />
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) --> <!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) -->
<application android:debuggable="true" <application android:debuggable="true"