Gestures: Assemble per-window exclusion zones
Adds a facility to listen for per-window exclusion zones and assembles them into a per-display exclusion zone ready for consumption by interested parties. Bug: 126360272 Test: atest DisplayContentTests Change-Id: Ic186f86ca551af98a5f77beb254d257c281a4160
This commit is contained in:
@@ -383,6 +383,7 @@ java_defaults {
|
||||
"core/java/android/view/IRecentsAnimationRunner.aidl",
|
||||
"core/java/android/view/IRemoteAnimationFinishedCallback.aidl",
|
||||
"core/java/android/view/IRotationWatcher.aidl",
|
||||
"core/java/android/view/ISystemGestureExclusionListener.aidl",
|
||||
"core/java/android/view/IWallpaperVisibilityListener.aidl",
|
||||
"core/java/android/view/IWindow.aidl",
|
||||
"core/java/android/view/IWindowFocusObserver.aidl",
|
||||
|
||||
34
core/java/android/view/ISystemGestureExclusionListener.aidl
Normal file
34
core/java/android/view/ISystemGestureExclusionListener.aidl
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2019, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.view;
|
||||
|
||||
import android.graphics.Region;
|
||||
|
||||
/**
|
||||
* Listener for changes to the system gesture exclusion region
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface ISystemGestureExclusionListener {
|
||||
/**
|
||||
* Called when the system gesture exclusion for the given display changed.
|
||||
* @param displayId the display whose system gesture exclusion changed
|
||||
* @param systemGestureExclusion a {@code Region} where the app would like priority over the
|
||||
* system gestures, in display coordinates.
|
||||
*/
|
||||
void onSystemGestureExclusionChanged(int displayId, in Region systemGestureExclusion);
|
||||
}
|
||||
@@ -40,6 +40,7 @@ import android.view.IOnKeyguardExitResult;
|
||||
import android.view.IPinnedStackListener;
|
||||
import android.view.RemoteAnimationAdapter;
|
||||
import android.view.IRotationWatcher;
|
||||
import android.view.ISystemGestureExclusionListener;
|
||||
import android.view.IWallpaperVisibilityListener;
|
||||
import android.view.IWindowSession;
|
||||
import android.view.IWindowSessionCallback;
|
||||
@@ -280,6 +281,18 @@ interface IWindowManager
|
||||
void unregisterWallpaperVisibilityListener(IWallpaperVisibilityListener listener,
|
||||
int displayId);
|
||||
|
||||
/**
|
||||
* Registers a system gesture exclusion listener for a given display.
|
||||
*/
|
||||
void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener,
|
||||
int displayId);
|
||||
|
||||
/**
|
||||
* Unregisters a system gesture exclusion listener for a given display.
|
||||
*/
|
||||
void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener,
|
||||
int displayId);
|
||||
|
||||
/**
|
||||
* Used only for assist -- request a screenshot of the current application.
|
||||
*/
|
||||
|
||||
@@ -32,6 +32,8 @@ import android.view.InsetsState;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* System private per-application interface to the window manager.
|
||||
*
|
||||
@@ -265,4 +267,10 @@ interface IWindowSession {
|
||||
* that new state.
|
||||
*/
|
||||
void insetsModified(IWindow window, in InsetsState state);
|
||||
|
||||
|
||||
/**
|
||||
* Called when the system gesture exclusion has changed.
|
||||
*/
|
||||
void reportSystemGestureExclusionChanged(IWindow window, in List<Rect> exclusionRects);
|
||||
}
|
||||
|
||||
@@ -3990,7 +3990,11 @@ public final class ViewRootImpl implements ViewParent,
|
||||
void systemGestureExclusionChanged() {
|
||||
final List<Rect> rectsForWindowManager = mGestureExclusionTracker.computeChangedRects();
|
||||
if (rectsForWindowManager != null) {
|
||||
// TODO Send to WM
|
||||
try {
|
||||
mWindowSession.reportSystemGestureExclusionChanged(mWindow, rectsForWindowManager);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
mAttachInfo.mTreeObserver
|
||||
.dispatchOnSystemGestureExclusionRectsChanged(rectsForWindowManager);
|
||||
}
|
||||
|
||||
@@ -20,12 +20,16 @@ import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Paint.FontMetricsInt;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
import android.hardware.input.InputManager;
|
||||
import android.hardware.input.InputManager.InputDeviceListener;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.view.ISystemGestureExclusionListener;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
@@ -34,6 +38,7 @@ import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowManagerGlobal;
|
||||
import android.view.WindowManagerPolicyConstants.PointerEventListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -124,12 +129,16 @@ public class PointerLocationView extends View implements InputDeviceListener,
|
||||
private int mActivePointerId;
|
||||
private final ArrayList<PointerState> mPointers = new ArrayList<PointerState>();
|
||||
private final PointerCoords mTempCoords = new PointerCoords();
|
||||
|
||||
|
||||
private final Region mSystemGestureExclusion = new Region();
|
||||
private final Path mSystemGestureExclusionPath = new Path();
|
||||
private final Paint mSystemGestureExclusionPaint;
|
||||
|
||||
private final VelocityTracker mVelocity;
|
||||
private final VelocityTracker mAltVelocity;
|
||||
|
||||
private final FasterStringBuilder mText = new FasterStringBuilder();
|
||||
|
||||
|
||||
private boolean mPrintCoords = true;
|
||||
|
||||
public PointerLocationView(Context c) {
|
||||
@@ -168,7 +177,11 @@ public class PointerLocationView extends View implements InputDeviceListener,
|
||||
mPathPaint.setARGB(255, 0, 96, 255);
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
mPaint.setStrokeWidth(1);
|
||||
|
||||
|
||||
mSystemGestureExclusionPaint = new Paint();
|
||||
mSystemGestureExclusionPaint.setARGB(25, 255, 0, 0);
|
||||
mSystemGestureExclusionPaint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
|
||||
PointerState ps = new PointerState();
|
||||
mPointers.add(ps);
|
||||
mActivePointerId = 0;
|
||||
@@ -236,6 +249,12 @@ public class PointerLocationView extends View implements InputDeviceListener,
|
||||
|
||||
final int NP = mPointers.size();
|
||||
|
||||
if (!mSystemGestureExclusion.isEmpty()) {
|
||||
mSystemGestureExclusionPath.reset();
|
||||
mSystemGestureExclusion.getBoundaryPath(mSystemGestureExclusionPath);
|
||||
canvas.drawPath(mSystemGestureExclusionPath, mSystemGestureExclusionPaint);
|
||||
}
|
||||
|
||||
// Labels
|
||||
if (mActivePointerId >= 0) {
|
||||
final PointerState ps = mPointers.get(mActivePointerId);
|
||||
@@ -719,6 +738,12 @@ public class PointerLocationView extends View implements InputDeviceListener,
|
||||
super.onAttachedToWindow();
|
||||
|
||||
mIm.registerInputDeviceListener(this, getHandler());
|
||||
try {
|
||||
WindowManagerGlobal.getWindowManagerService().registerSystemGestureExclusionListener(
|
||||
mSystemGestureExclusionListener, mContext.getDisplayId());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
logInputDevices();
|
||||
}
|
||||
|
||||
@@ -727,6 +752,12 @@ public class PointerLocationView extends View implements InputDeviceListener,
|
||||
super.onDetachedFromWindow();
|
||||
|
||||
mIm.unregisterInputDeviceListener(this);
|
||||
try {
|
||||
WindowManagerGlobal.getWindowManagerService().unregisterSystemGestureExclusionListener(
|
||||
mSystemGestureExclusionListener, mContext.getDisplayId());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -876,4 +907,17 @@ public class PointerLocationView extends View implements InputDeviceListener,
|
||||
return oldLength;
|
||||
}
|
||||
}
|
||||
|
||||
private ISystemGestureExclusionListener mSystemGestureExclusionListener =
|
||||
new ISystemGestureExclusionListener.Stub() {
|
||||
@Override
|
||||
public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion) {
|
||||
Region exclusion = Region.obtain(systemGestureExclusion);
|
||||
getHandler().post(() -> {
|
||||
mSystemGestureExclusion.set(exclusion);
|
||||
exclusion.recycle();
|
||||
invalidate();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -128,6 +128,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.rectListToRegion;
|
||||
|
||||
import android.animation.AnimationHandler;
|
||||
import android.annotation.CallSuper;
|
||||
@@ -151,6 +152,7 @@ import android.os.Debug;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.Trace;
|
||||
@@ -163,6 +165,7 @@ import android.view.Display;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.DisplayInfo;
|
||||
import android.view.Gravity;
|
||||
import android.view.ISystemGestureExclusionListener;
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputDevice;
|
||||
import android.view.InputWindowHandle;
|
||||
@@ -308,6 +311,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
private DisplayRotation mDisplayRotation;
|
||||
DisplayFrames mDisplayFrames;
|
||||
|
||||
private final RemoteCallbackList<ISystemGestureExclusionListener>
|
||||
mSystemGestureExclusionListeners = new RemoteCallbackList<>();
|
||||
private final Region mSystemGestureExclusion = new Region();
|
||||
|
||||
/**
|
||||
* For default display it contains real metrics, empty for others.
|
||||
* @see WindowManagerService#createWatermarkInTransaction()
|
||||
@@ -2788,6 +2795,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
pw.println();
|
||||
mWallpaperController.dump(pw, " ");
|
||||
|
||||
pw.println();
|
||||
pw.print("mSystemGestureExclusion=");
|
||||
if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() > 0) {
|
||||
pw.println(mSystemGestureExclusion);
|
||||
} else {
|
||||
pw.println("<no lstnrs>");
|
||||
}
|
||||
|
||||
pw.println();
|
||||
pw.println(prefix + "Application tokens in top down Z order:");
|
||||
for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
|
||||
@@ -4913,6 +4928,100 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
return mWindowingLayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the display's system gesture exclusion.
|
||||
*
|
||||
* @return true, if the exclusion changed.
|
||||
*/
|
||||
boolean updateSystemGestureExclusion() {
|
||||
if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() == 0) {
|
||||
// No one's interested anyways.
|
||||
return false;
|
||||
}
|
||||
|
||||
final Region systemGestureExclusion = calculateSystemGestureExclusion();
|
||||
try {
|
||||
if (mSystemGestureExclusion.equals(systemGestureExclusion)) {
|
||||
return false;
|
||||
}
|
||||
mSystemGestureExclusion.set(systemGestureExclusion);
|
||||
for (int i = mSystemGestureExclusionListeners.beginBroadcast() - 1; i >= 0; --i) {
|
||||
try {
|
||||
mSystemGestureExclusionListeners.getBroadcastItem(i)
|
||||
.onSystemGestureExclusionChanged(mDisplayId, systemGestureExclusion);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to notify SystemGestureExclusionListener", e);
|
||||
}
|
||||
}
|
||||
mSystemGestureExclusionListeners.finishBroadcast();
|
||||
return true;
|
||||
} finally {
|
||||
systemGestureExclusion.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Region calculateSystemGestureExclusion() {
|
||||
final Region global = Region.obtain();
|
||||
final Region touchableRegion = Region.obtain();
|
||||
final Region local = Region.obtain();
|
||||
|
||||
// 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) {
|
||||
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.
|
||||
w.getTouchableRegion(touchableRegion);
|
||||
global.op(touchableRegion, Op.DIFFERENCE);
|
||||
|
||||
rectListToRegion(w.getSystemGestureExclusion(), local);
|
||||
|
||||
// Transform to display coordinates
|
||||
local.scale(w.mGlobalScale);
|
||||
final Rect frame = w.getWindowFrames().mFrame;
|
||||
local.translate(frame.left, frame.top);
|
||||
|
||||
// A window can only exclude system gestures where it is actually touchable
|
||||
local.op(touchableRegion, Op.INTERSECT);
|
||||
|
||||
global.op(local, Op.UNION);
|
||||
}, false /* topToBottom */);
|
||||
local.recycle();
|
||||
touchableRegion.recycle();
|
||||
return global;
|
||||
}
|
||||
|
||||
void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener) {
|
||||
mSystemGestureExclusionListeners.register(listener);
|
||||
final boolean changed;
|
||||
if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() == 1) {
|
||||
changed = updateSystemGestureExclusion();
|
||||
} else {
|
||||
changed = false;
|
||||
}
|
||||
|
||||
if (!changed) {
|
||||
// If updateSystemGestureExclusion changed the exclusion, it will already have
|
||||
// notified the listener. Otherwise, we'll do it here.
|
||||
try {
|
||||
listener.onSystemGestureExclusionChanged(mDisplayId, mSystemGestureExclusion);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to notify SystemGestureExclusionListener during register", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener) {
|
||||
mSystemGestureExclusionListeners.unregister(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a portal window handle for input. This window transports any touch to the display
|
||||
* indicated by {@link InputWindowHandle#portalToDisplayId} if the touch hits this window.
|
||||
|
||||
@@ -654,6 +654,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
|
||||
// Finally update all input windows now that the window changes have stabilized.
|
||||
forAllDisplays(dc -> {
|
||||
dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
|
||||
dc.updateSystemGestureExclusion();
|
||||
});
|
||||
|
||||
mWmService.setHoldScreenLocked(mHoldScreen);
|
||||
|
||||
@@ -57,6 +57,7 @@ import com.android.server.wm.WindowManagerService.H;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@@ -314,6 +315,16 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportSystemGestureExclusionChanged(IWindow window, List<Rect> exclusionRects) {
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mService.reportSystemGestureExclusionChanged(this, window, exclusionRects);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
|
||||
private void actionOnWallpaper(IBinder window,
|
||||
BiConsumer<WallpaperController, WindowState> action) {
|
||||
final WindowState windowState = mService.windowForClientLocked(this, window, true);
|
||||
|
||||
@@ -202,6 +202,7 @@ import android.view.IOnKeyguardExitResult;
|
||||
import android.view.IPinnedStackListener;
|
||||
import android.view.IRecentsAnimationRunner;
|
||||
import android.view.IRotationWatcher;
|
||||
import android.view.ISystemGestureExclusionListener;
|
||||
import android.view.IWallpaperVisibilityListener;
|
||||
import android.view.IWindow;
|
||||
import android.view.IWindowId;
|
||||
@@ -274,6 +275,7 @@ import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/** {@hide} */
|
||||
public class WindowManagerService extends IWindowManager.Stub
|
||||
@@ -3787,6 +3789,42 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener,
|
||||
int displayId) {
|
||||
synchronized (mGlobalLock) {
|
||||
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
|
||||
if (displayContent == null) {
|
||||
throw new IllegalArgumentException("Trying to register visibility event "
|
||||
+ "for invalid display: " + displayId);
|
||||
}
|
||||
displayContent.registerSystemGestureExclusionListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener,
|
||||
int displayId) {
|
||||
synchronized (mGlobalLock) {
|
||||
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
|
||||
if (displayContent == null) {
|
||||
throw new IllegalArgumentException("Trying to register visibility event "
|
||||
+ "for invalid display: " + displayId);
|
||||
}
|
||||
displayContent.unregisterSystemGestureExclusionListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
void reportSystemGestureExclusionChanged(Session session, IWindow window,
|
||||
List<Rect> exclusionRects) {
|
||||
synchronized (mGlobalLock) {
|
||||
final WindowState win = windowForClientLocked(session, window, true);
|
||||
if (win.setSystemGestureExclusion(exclusionRects)) {
|
||||
win.getDisplayContent().updateSystemGestureExclusion();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerDisplayFoldListener(IDisplayFoldListener listener) {
|
||||
mPolicy.registerDisplayFoldListener(listener);
|
||||
|
||||
@@ -205,6 +205,7 @@ import java.io.PrintWriter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/** A window in the window manager. */
|
||||
@@ -363,6 +364,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
*/
|
||||
private final Rect mInsetFrame = new Rect();
|
||||
|
||||
/**
|
||||
* List of rects where system gestures should be ignored.
|
||||
*
|
||||
* Coordinates are relative to the window's position.
|
||||
*/
|
||||
private final List<Rect> mExclusionRects = new ArrayList<>();
|
||||
|
||||
// If a window showing a wallpaper: the requested offset for the
|
||||
// wallpaper; if a wallpaper window: the currently applied offset.
|
||||
float mWallpaperX = -1;
|
||||
@@ -612,6 +620,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
}
|
||||
}
|
||||
|
||||
List<Rect> getSystemGestureExclusion() {
|
||||
return mExclusionRects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the system gesture exclusion rects.
|
||||
*
|
||||
* @return {@code true} if anything changed
|
||||
*/
|
||||
boolean setSystemGestureExclusion(List<Rect> exclusionRects) {
|
||||
if (mExclusionRects.equals(exclusionRects)) {
|
||||
return false;
|
||||
}
|
||||
mExclusionRects.clear();
|
||||
mExclusionRects.addAll(exclusionRects);
|
||||
return true;
|
||||
}
|
||||
|
||||
interface PowerManagerWrapper {
|
||||
void wakeUp(long time, @WakeReason int reason, String details);
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.wm.utils;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utility methods to handle Regions.
|
||||
*/
|
||||
public class RegionUtils {
|
||||
|
||||
private RegionUtils() {}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a list of rects into a {@code Region}.
|
||||
*
|
||||
* @param rects the list of rects to convert
|
||||
* @param outRegion the Region to set to the list of rects
|
||||
*/
|
||||
public static void rectListToRegion(List<Rect> rects, Region outRegion) {
|
||||
outRegion.setEmpty();
|
||||
final int n = rects.size();
|
||||
for (int i = 0; i < n; i++) {
|
||||
outRegion.union(rects.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,8 @@ import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
|
||||
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
|
||||
import static android.view.DisplayCutout.fromBoundingRect;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
||||
@@ -57,12 +59,15 @@ import android.annotation.SuppressLint;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.metrics.LogMaker;
|
||||
import android.os.SystemClock;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.MutableBoolean;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.Gravity;
|
||||
import android.view.ISystemGestureExclusionListener;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.ViewRootImpl;
|
||||
@@ -672,6 +677,60 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateSystemGestureExclusion() throws Exception {
|
||||
final DisplayContent dc = createNewDisplay();
|
||||
final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
|
||||
win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
|
||||
win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40)));
|
||||
|
||||
dc.setLayoutNeeded();
|
||||
dc.performLayout(true /* initial */, false /* updateImeWindows */);
|
||||
|
||||
win.setHasSurface(true);
|
||||
dc.updateSystemGestureExclusion();
|
||||
|
||||
final MutableBoolean invoked = new MutableBoolean(false);
|
||||
final ISystemGestureExclusionListener.Stub verifier =
|
||||
new ISystemGestureExclusionListener.Stub() {
|
||||
@Override
|
||||
public void onSystemGestureExclusionChanged(int displayId, Region actual) {
|
||||
Region expected = Region.obtain();
|
||||
expected.set(10, 20, 30, 40);
|
||||
assertEquals(expected, actual);
|
||||
invoked.value = true;
|
||||
}
|
||||
};
|
||||
try {
|
||||
dc.registerSystemGestureExclusionListener(verifier);
|
||||
} finally {
|
||||
dc.unregisterSystemGestureExclusionListener(verifier);
|
||||
}
|
||||
assertTrue("SystemGestureExclusionListener was not invoked", invoked.value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateSystemGestureExclusion() throws Exception {
|
||||
final DisplayContent dc = createNewDisplay();
|
||||
final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
|
||||
win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
|
||||
win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40)));
|
||||
|
||||
final WindowState win2 = createWindow(null, TYPE_APPLICATION, dc, "win2");
|
||||
win2.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
|
||||
win2.setSystemGestureExclusion(Collections.singletonList(new Rect(20, 30, 40, 50)));
|
||||
|
||||
dc.setLayoutNeeded();
|
||||
dc.performLayout(true /* initial */, false /* updateImeWindows */);
|
||||
|
||||
win.setHasSurface(true);
|
||||
win2.setHasSurface(true);
|
||||
|
||||
final Region expected = Region.obtain();
|
||||
expected.set(20, 30, 40, 50);
|
||||
assertEquals(expected, dc.calculateSystemGestureExclusion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrientationChangeLogging() {
|
||||
MetricsLogger mockLogger = mock(MetricsLogger.class);
|
||||
|
||||
Reference in New Issue
Block a user