summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Tiger Huang <tigerhuang@google.com> 2019-04-18 14:35:09 -0700
committer Tiger Huang <tigerhuang@google.com> 2019-05-02 12:53:55 +0800
commitd8ec93860957c95d00b1c1fa18ba2f302d06720e (patch)
treeb494ba05fc7531b98a1c1cf857ee2a83418b1873
parent81894407855a3a4769b966f857ea867092c358ac (diff)
Refine getTransformationMatrix for windows in a re-parented display
Currently, the translation of the transformation matrix computed by WindowState.getTransformationMatrix is related to its own display. However, if the display has been re-parented, the translation might be misplaced to the visual result. This CL makes it return the global transformation matrix. Bug: 129098348 Test: atest WindowStateTests Change-Id: I38da5b84a11890bf0f4a57eb9d5b7e71bdcc16a9
-rw-r--r--core/java/android/app/ActivityView.java62
-rw-r--r--core/java/android/view/IWindowManager.aidl12
-rw-r--r--core/java/android/view/IWindowSession.aidl25
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java24
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java47
-rw-r--r--services/core/java/com/android/server/wm/Session.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java86
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java26
9 files changed, 242 insertions, 68 deletions
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index fc6fffabc917..b64b2dcc4f61 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -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,39 +329,52 @@ 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()) {
- return;
- }
- if (!canReceivePointerEvents()) {
- cleanTapExcludeRegion();
+ /**
+ * 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);
- final int x = mLocationInWindow[0];
- final int y = mLocationInWindow[1];
- 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);
+ if (x != mLocationInWindow[0] || y != mLocationInWindow[1]) {
+ x = mLocationInWindow[0];
+ y = mLocationInWindow[1];
+ WindowManagerGlobal.getWindowSession().updateDisplayContentLocation(
+ getWindow(), x, y, mVirtualDisplay.getDisplay().getDisplayId());
}
-
- WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
- mTapExcludeRegion);
+ 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;
+ }
+ 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 != null) {
+ parent.subtractObscuredTouchableRegion(mTapExcludeRegion, this);
+ }
+
+ WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
+ mTapExcludeRegion);
+ }
+
private class SurfaceCallback implements SurfaceHolder.Callback {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
@@ -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);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index c730fe2dc114..b347a78a8780 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -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.
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index b52fdb8399d1..d269323d50a4 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -257,6 +257,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
* invalid region will remove the area from the exclude region of this window.
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 6ce42ec4cb44..b6a5be807fb6 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -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 {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3f783f67b73c..b4b60ea4bb6f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -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;
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index b33f8c7ad658..34273f3f23a5 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -426,6 +426,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();
try {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4f849cde8948..7c1ea208e270 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -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:
@@ -7538,31 +7595,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;
if (ev instanceof KeyEvent) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8123182a3e4b..2a621be8071a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -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()) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 98d055c78e3c..3a8d3b74c08f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -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);
+ }
+ }
}