Merge "Refine getTransformationMatrix for windows in a re-parented display" into qt-dev

This commit is contained in:
Tiger Huang
2019-05-02 11:31:17 +00:00
committed by Android (Google) Code Review
9 changed files with 242 additions and 68 deletions

View File

@@ -317,7 +317,7 @@ public class ActivityView extends ViewGroup {
* regions and avoid focus switches by touches on this view.
*/
public void onLocationChanged() {
updateTapExcludeRegion();
updateLocationAndTapExcludeRegion();
}
@Override
@@ -329,37 +329,50 @@ public class ActivityView extends ViewGroup {
public boolean gatherTransparentRegion(Region region) {
// The tap exclude region may be affected by any view on top of it, so we detect the
// possible change by monitoring this function.
updateTapExcludeRegion();
updateLocationAndTapExcludeRegion();
return super.gatherTransparentRegion(region);
}
/** Compute and send current tap exclude region to WM for this view. */
private void updateTapExcludeRegion() {
if (!isAttachedToWindow()) {
/**
* Sends current location in window and tap exclude region to WM for this view.
*/
private void updateLocationAndTapExcludeRegion() {
if (mVirtualDisplay == null || !isAttachedToWindow()) {
return;
}
try {
int x = mLocationInWindow[0];
int y = mLocationInWindow[1];
getLocationInWindow(mLocationInWindow);
if (x != mLocationInWindow[0] || y != mLocationInWindow[1]) {
x = mLocationInWindow[0];
y = mLocationInWindow[1];
WindowManagerGlobal.getWindowSession().updateDisplayContentLocation(
getWindow(), x, y, mVirtualDisplay.getDisplay().getDisplayId());
}
updateTapExcludeRegion(x, y);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
/** Computes and sends current tap exclude region to WM for this view. */
private void updateTapExcludeRegion(int x, int y) throws RemoteException {
if (!canReceivePointerEvents()) {
cleanTapExcludeRegion();
return;
}
try {
getLocationInWindow(mLocationInWindow);
final int x = mLocationInWindow[0];
final int y = mLocationInWindow[1];
mTapExcludeRegion.set(x, y, x + getWidth(), y + getHeight());
mTapExcludeRegion.set(x, y, x + getWidth(), y + getHeight());
// There might be views on top of us. We need to subtract those areas from the tap
// exclude region.
final ViewParent parent = getParent();
if (parent instanceof ViewGroup) {
((ViewGroup) parent).subtractObscuredTouchableRegion(mTapExcludeRegion, this);
}
WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
mTapExcludeRegion);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
// There might be views on top of us. We need to subtract those areas from the tap
// exclude region.
final ViewParent parent = getParent();
if (parent != null) {
parent.subtractObscuredTouchableRegion(mTapExcludeRegion, this);
}
WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
mTapExcludeRegion);
}
private class SurfaceCallback implements SurfaceHolder.Callback {
@@ -379,7 +392,7 @@ public class ActivityView extends ViewGroup {
mVirtualDisplay.setDisplayState(true);
}
updateTapExcludeRegion();
updateLocationAndTapExcludeRegion();
}
@Override
@@ -387,7 +400,7 @@ public class ActivityView extends ViewGroup {
if (mVirtualDisplay != null) {
mVirtualDisplay.resize(width, height, getBaseDisplayDensity());
}
updateTapExcludeRegion();
updateLocationAndTapExcludeRegion();
}
@Override
@@ -471,7 +484,8 @@ public class ActivityView extends ViewGroup {
try {
// TODO: Find a way to consolidate these calls to the server.
wm.reparentDisplayContent(displayId, mRootSurfaceControl);
WindowManagerGlobal.getWindowSession().reparentDisplayContent(
getWindow(), mRootSurfaceControl, displayId);
wm.dontOverrideDisplayInfo(displayId);
if (mSingleTaskInstance) {
mActivityTaskManager.setDisplayToSingleTaskInstance(displayId);

View File

@@ -621,18 +621,6 @@ interface IWindowManager
*/
void setShouldShowIme(int displayId, boolean shouldShow);
/**
* Reparent the top layers for a display to the requested surfaceControl. The display that
* is going to be re-parented (the displayId passed in) needs to have been created by the same
* process that is requesting the re-parent. This is to ensure clients can't just re-parent
* display content info to any SurfaceControl, as this would be a security issue.
*
* @param displayId The id of the display.
* @param surfaceControlHandle The SurfaceControl that the top level layers for the
* display should be re-parented to.
*/
void reparentDisplayContent(int displayId, in SurfaceControl sc);
/**
* Waits for transactions to get applied before injecting input.
* This includes waiting for the input windows to get sent to InputManager.

View File

@@ -256,6 +256,31 @@ interface IWindowSession {
void updatePointerIcon(IWindow window);
/**
* Reparent the top layers for a display to the requested SurfaceControl. The display that is
* going to be re-parented (the displayId passed in) needs to have been created by the same
* process that is requesting the re-parent. This is to ensure clients can't just re-parent
* display content info to any SurfaceControl, as this would be a security issue.
*
* @param window The window which owns the SurfaceControl. This indicates the z-order of the
* windows of this display against the windows on the parent display.
* @param sc The SurfaceControl that the top level layers for the display should be re-parented
* to.
* @param displayId The id of the display to be re-parented.
*/
void reparentDisplayContent(IWindow window, in SurfaceControl sc, int displayId);
/**
* Update the location of a child display in its parent window. This enables windows in the
* child display to compute the global transformation matrix.
*
* @param window The parent window of the display.
* @param x The x coordinate in the parent window.
* @param y The y coordinate in the parent window.
* @param displayId The id of the display to be notified.
*/
void updateDisplayContentLocation(IWindow window, int x, int y, int displayId);
/**
* Update a tap exclude region identified by provided id in the window. Touches on this region
* will neither be dispatched to this window nor change the focus to this window. Passing an

View File

@@ -1108,6 +1108,7 @@ final class AccessibilityController {
// the window manager is still looking for where to put it.
// We will do the work when we get a focus change callback.
// TODO(b/112273690): Support multiple displays
// TODO(b/129098348): Support embedded displays
if (mService.getDefaultDisplayContentLocked().mCurrentFocus == null) {
return;
}
@@ -1400,7 +1401,28 @@ final class AccessibilityController {
if (w.isVisibleLw()) {
outWindows.put(mTempLayer++, w);
}
}, false /* traverseTopToBottom */ );
}, false /* traverseTopToBottom */);
mService.mRoot.forAllWindows(w -> {
final WindowState win = findRootDisplayParentWindow(w);
if (win != null && win.getDisplayContent().isDefaultDisplay && w.isVisibleLw()) {
// TODO(b/129098348): insert windows on child displays into outWindows based on
// root-display-parent window.
outWindows.put(mTempLayer++, w);
}
}, false /* traverseTopToBottom */);
}
private WindowState findRootDisplayParentWindow(WindowState win) {
WindowState displayParentWindow = win.getDisplayContent().getParentWindow();
if (displayParentWindow == null) {
return null;
}
WindowState candidate = displayParentWindow;
while (candidate != null) {
displayParentWindow = candidate;
candidate = displayParentWindow.getDisplayContent().getParentWindow();
}
return displayParentWindow;
}
private class MyHandler extends Handler {

View File

@@ -144,6 +144,7 @@ import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
@@ -541,6 +542,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
private final InsetsStateController mInsetsStateController;
/** @see #getParentWindow() */
private WindowState mParentWindow;
private Point mLocationInParentWindow = new Point();
private SurfaceControl mParentSurfaceControl;
private InputWindowHandle mPortalWindowHandle;
@@ -4923,11 +4928,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
/**
* Re-parent the DisplayContent's top surfaces, {@link #mWindowingLayer} and
* {@link #mOverlayLayer} to the specified surfaceControl.
* {@link #mOverlayLayer} to the specified SurfaceControl.
*
* @param win The window which owns the SurfaceControl. This indicates the z-order of the
* windows of this display against the windows on the parent display.
* @param sc The new SurfaceControl, where the DisplayContent's surfaces will be re-parented to.
*/
void reparentDisplayContent(SurfaceControl sc) {
void reparentDisplayContent(WindowState win, SurfaceControl sc) {
mParentWindow = win;
mParentSurfaceControl = sc;
if (mPortalWindowHandle == null) {
mPortalWindowHandle = createPortalWindowHandle(sc.toString());
@@ -4936,6 +4944,41 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
.reparent(mWindowingLayer, sc).reparent(mOverlayLayer, sc);
}
/**
* Get the window which owns the surface that this DisplayContent is re-parented to.
*
* @return the parent window.
*/
WindowState getParentWindow() {
return mParentWindow;
}
/**
* Update the location of this display in the parent window. This enables windows in this
* display to compute the global transformation matrix.
*
* @param win The parent window of this display.
* @param x The x coordinate in the parent window.
* @param y The y coordinate in the parent window.
*/
void updateLocation(WindowState win, int x, int y) {
if (mParentWindow != win) {
throw new IllegalArgumentException(
"The given window is not the parent window of this display.");
}
if (mLocationInParentWindow.x != x || mLocationInParentWindow.y != y) {
mLocationInParentWindow.x = x;
mLocationInParentWindow.y = y;
if (mWmService.mAccessibilityController != null) {
mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
}
}
}
Point getLocationInParentWindow() {
return mLocationInParentWindow;
}
@VisibleForTesting
SurfaceControl getWindowingLayer() {
return mWindowingLayer;

View File

@@ -425,6 +425,16 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
}
}
@Override
public void reparentDisplayContent(IWindow window, SurfaceControl sc, int displayId) {
mService.reparentDisplayContent(window, sc, displayId);
}
@Override
public void updateDisplayContentLocation(IWindow window, int x, int y, int displayId) {
mService.updateDisplayContentLocation(window, x, y, displayId);
}
@Override
public void updateTapExcludeRegion(IWindow window, int regionId, Region region) {
final long identity = Binder.clearCallingIdentity();

View File

@@ -1880,7 +1880,8 @@ public class WindowManagerService extends IWindowManager.Stub
// We need to report touchable region changes to accessibility.
if (mAccessibilityController != null
&& w.getDisplayContent().getDisplayId() == DEFAULT_DISPLAY) {
&& (w.getDisplayContent().getDisplayId() == DEFAULT_DISPLAY
|| w.getDisplayContent().getParentWindow() != null)) {
mAccessibilityController.onSomeWindowResizedOrMovedLocked();
}
}
@@ -2012,7 +2013,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (((attrChanges & LayoutParams.ACCESSIBILITY_TITLE_CHANGED) != 0)
&& (mAccessibilityController != null)
&& (win.getDisplayId() == DEFAULT_DISPLAY)) {
&& (win.getDisplayId() == DEFAULT_DISPLAY
|| win.getDisplayContent().getParentWindow() != null)) {
// No move or resize, but the controller checks for title changes as well
mAccessibilityController.onSomeWindowResizedOrMovedLocked();
}
@@ -6703,6 +6705,61 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
private void checkCallerOwnsDisplay(int displayId) {
final Display display = mDisplayManager.getDisplay(displayId);
if (display == null) {
throw new IllegalArgumentException(
"Cannot find display for non-existent displayId: " + displayId);
}
final int callingUid = Binder.getCallingUid();
final int displayOwnerUid = display.getOwnerUid();
if (callingUid != displayOwnerUid) {
throw new SecurityException("The caller doesn't own the display.");
}
}
/** @see Session#reparentDisplayContent(IWindow, SurfaceControl, int) */
void reparentDisplayContent(IWindow client, SurfaceControl sc, int displayId) {
checkCallerOwnsDisplay(displayId);
synchronized (mGlobalLock) {
final long token = Binder.clearCallingIdentity();
try {
final WindowState win = windowForClientLocked(null, client, false);
if (win == null) {
Slog.w(TAG_WM, "Bad requesting window " + client);
return;
}
getDisplayContentOrCreate(displayId, null).reparentDisplayContent(win, sc);
} finally {
Binder.restoreCallingIdentity(token);
}
}
}
/** @see Session#updateDisplayContentLocation(IWindow, int, int, int) */
void updateDisplayContentLocation(IWindow client, int x, int y, int displayId) {
checkCallerOwnsDisplay(displayId);
synchronized (mGlobalLock) {
final long token = Binder.clearCallingIdentity();
try {
final WindowState win = windowForClientLocked(null, client, false);
if (win == null) {
Slog.w(TAG_WM, "Bad requesting window " + client);
return;
}
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent != null) {
displayContent.updateLocation(win, x, y);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
}
/**
* Update a tap exclude region in the window identified by the provided id. Touches down on this
* region will not:
@@ -7537,31 +7594,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
@Override
public void reparentDisplayContent(int displayId, SurfaceControl sc) {
final Display display = mDisplayManager.getDisplay(displayId);
if (display == null) {
throw new IllegalArgumentException(
"Can't reparent display for non-existent displayId: " + displayId);
}
final int callingUid = Binder.getCallingUid();
final int displayOwnerUid = display.getOwnerUid();
if (callingUid != displayOwnerUid) {
throw new SecurityException("Only owner of the display can reparent surfaces to it.");
}
synchronized (mGlobalLock) {
long token = Binder.clearCallingIdentity();
try {
DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
displayContent.reparentDisplayContent(sc);
} finally {
Binder.restoreCallingIdentity(token);
}
}
}
@Override
public boolean injectInputAfterTransactionsApplied(InputEvent ev, int mode) {
boolean shouldWaitForAnimToComplete = false;

View File

@@ -3142,7 +3142,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
//TODO (multidisplay): Accessibility supported only for the default display.
if (mWmService.mAccessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) {
if (mWmService.mAccessibilityController != null && (getDisplayId() == DEFAULT_DISPLAY
|| getDisplayContent().getParentWindow() != null)) {
mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
}
@@ -4207,7 +4208,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
//TODO (multidisplay): Accessibility is supported only for the default display.
if (mWmService.mAccessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) {
if (mWmService.mAccessibilityController != null && (getDisplayId() == DEFAULT_DISPLAY
|| getDisplayContent().getParentWindow() != null)) {
mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
}
@@ -4646,6 +4648,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
int x = mSurfacePosition.x;
int y = mSurfacePosition.y;
// We might be on a display which has been re-parented to a view in another window, so here
// computes the global location of our display.
DisplayContent dc = getDisplayContent();
while (dc != null && dc.getParentWindow() != null) {
final WindowState displayParent = dc.getParentWindow();
x += displayParent.mWindowFrames.mFrame.left - displayParent.mAttrs.surfaceInsets.left
+ (dc.getLocationInParentWindow().x * displayParent.mGlobalScale + 0.5f);
y += displayParent.mWindowFrames.mFrame.top - displayParent.mAttrs.surfaceInsets.top
+ (dc.getLocationInParentWindow().y * displayParent.mGlobalScale + 0.5f);
dc = displayParent.getDisplayContent();
}
// If changed, also adjust transformFrameToSurfacePosition
final WindowContainer parent = getParent();
if (isChildWindow()) {

View File

@@ -493,4 +493,30 @@ public class WindowStateTests extends WindowTestsBase {
assertTrue(window.isVisible());
assertTrue(window.isVisibleByPolicy());
}
@Test
public void testGetTransformationMatrix() {
synchronized (mWm.mGlobalLock) {
final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
win0.getFrameLw().offsetTo(1, 0);
final DisplayContent dc = createNewDisplay();
dc.reparentDisplayContent(win0, win0.getSurfaceControl());
dc.updateLocation(win0, 2, 0);
final float[] values = new float[9];
final Matrix matrix = new Matrix();
final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
final WindowState win1 = createWindow(null, TYPE_APPLICATION, dc, "win1");
win1.mHasSurface = true;
win1.mSurfaceControl = mock(SurfaceControl.class);
win1.getFrameLw().offsetTo(3, 0);
win1.updateSurfacePosition(t);
win1.getTransformationMatrix(values, matrix);
matrix.getValues(values);
assertEquals(6f, values[Matrix.MTRANS_X], 0f);
assertEquals(0f, values[Matrix.MTRANS_Y], 0f);
}
}
}