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

This commit is contained in:
Jorim Jaggi
2019-06-28 13:48:37 +00:00
committed by Android (Google) Code Review
6 changed files with 175 additions and 8 deletions

View File

@@ -2294,6 +2294,7 @@ package android.provider {
field public static final String NAMESPACE_PRIVACY = "privacy";
field public static final String NAMESPACE_ROLLBACK = "rollback";
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 {
@@ -2310,6 +2311,10 @@ package android.provider {
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 {
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;

View File

@@ -284,6 +284,15 @@ public final class DeviceConfig {
*/
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
*
@@ -301,6 +310,23 @@ public final class DeviceConfig {
@TestApi
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();
@GuardedBy("sLock")
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_PORTRAIT;
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.FLAG_PRIVATE;
import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
import static android.view.Display.INVALID_DISPLAY;
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_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
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_INVALID;
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.WindowStateAnimator.DRAW_PENDING;
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 android.animation.AnimationHandler;
@@ -324,6 +330,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
private final RemoteCallbackList<ISystemGestureExclusionListener>
mSystemGestureExclusionListeners = new RemoteCallbackList<>();
private final Region mSystemGestureExclusion = new Region();
private int mSystemGestureExclusionLimit;
/**
* 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);
display.getDisplayInfo(mDisplayInfo);
display.getMetrics(mDisplayMetrics);
mSystemGestureExclusionLimit = mWmService.mSystemGestureExclusionLimitDp
* mDisplayMetrics.densityDpi / DENSITY_DEFAULT;
isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
mDisplayFrames = new DisplayFrames(mDisplayId, mDisplayInfo,
calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
@@ -1549,8 +1558,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
longSize = height;
}
final int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / mBaseDisplayDensity;
final int longSizeDp = longSize * DisplayMetrics.DENSITY_DEFAULT / mBaseDisplayDensity;
final int shortSizeDp = shortSize * DENSITY_DEFAULT / mBaseDisplayDensity;
final int longSizeDp = longSize * DENSITY_DEFAULT / mBaseDisplayDensity;
mDisplayPolicy.updateConfigurationAndScreenSizeDependentBehaviors();
mDisplayRotation.configure(width, height, shortSizeDp, longSizeDp);
@@ -2200,6 +2209,18 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
onDisplayChanged(this);
}
@Override
void onDisplayChanged(DisplayContent dc) {
super.onDisplayChanged(dc);
updateSystemGestureExclusionLimit();
}
void updateSystemGestureExclusionLimit() {
mSystemGestureExclusionLimit = mWmService.mSystemGestureExclusionLimitDp
* mDisplayMetrics.densityDpi / DENSITY_DEFAULT;
updateSystemGestureExclusion();
}
void initializeDisplayBaseInfo() {
final DisplayManagerInternal displayManagerInternal = mWmService.mDisplayManagerInternal;
if (displayManagerInternal != null) {
@@ -5110,24 +5131,35 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
@VisibleForTesting
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 touchableRegion = Region.obtain();
final Region local = Region.obtain();
final int[] remainingLeftRight =
{mSystemGestureExclusionLimit, mSystemGestureExclusionLimit};
// 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.
forAllWindows(w -> {
if (w.cantReceiveTouchInput() || !w.isVisible()
|| (w.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0) {
|| (w.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0
|| unhandled.isEmpty()) {
return;
}
final boolean modal =
(w.mAttrs.flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;
// Only keep the exclusion zones from the windows behind where the current window
// isn't touchable.
// Get the touchable region of the window, and intersect with where the screen is still
// touchable, i.e. touchable regions on top are not covering it yet.
w.getTouchableRegion(touchableRegion);
global.op(touchableRegion, Op.DIFFERENCE);
touchableRegion.op(unhandled, Op.INTERSECT);
rectListToRegion(w.getSystemGestureExclusion(), local);
@@ -5139,13 +5171,78 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// A window can only exclude system gestures where it is actually touchable
local.op(touchableRegion, Op.INTERSECT);
global.op(local, Op.UNION);
}, false /* topToBottom */);
// Apply restriction if necessary.
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();
touchableRegion.recycle();
unhandled.recycle();
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) {
mSystemGestureExclusionListeners.register(listener);
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.myPid;
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.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -154,6 +155,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Looper;
@@ -175,6 +177,7 @@ import android.os.SystemService;
import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.vr.IVrManager;
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 MIN_GESTURE_EXCLUSION_LIMIT_DP = 200;
final WindowTracing mWindowTracing;
final private KeyguardDisableHandler mKeyguardDisableHandler;
@@ -838,6 +843,8 @@ public class WindowManagerService extends IWindowManager.Stub
final ArrayList<WindowChangeListener> mWindowChangeListeners = new ArrayList<>();
boolean mWindowsChanged = false;
int mSystemGestureExclusionLimitDp;
public interface WindowChangeListener {
public void windowsChanged();
public void focusChanged();
@@ -1132,6 +1139,21 @@ public class WindowManagerService extends IWindowManager.Stub
this, mInputManager, mActivityTaskManager, 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());
}

View File

@@ -18,8 +18,10 @@ package com.android.server.wm.utils;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.RegionIterator;
import java.util.List;
import java.util.function.Consumer;
/**
* Utility methods to handle Regions.
@@ -42,4 +44,18 @@ public class RegionUtils {
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.WAKE_LOCK" />
<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) -->
<application android:debuggable="true"