diff options
| author | 2024-03-07 06:28:59 +0000 | |
|---|---|---|
| committer | 2024-03-21 07:30:03 +0000 | |
| commit | f75ad18ed082dd0a95ab277f8214b1070e1fc8d6 (patch) | |
| tree | 30957518014efbcf5015bd36a8ae5874f0f6a977 | |
| parent | 99075875adc670ea7a3ef409ddc85d41f7095c07 (diff) | |
fix(magnification): directly use the window touchableRegion in AccessibilityController magnification recomputeBounds
In AccessibilityController recomputeBounds, currently it create a touchable rect from the WindowState's touchableRegion to compute the magnification region. However, if there are separated rects in the touchableRegion, then the created touchable rect might be a large rect consisting of non-touchable areas in that WindowState. Therefore, the fix is to directly use the WindowState's exact touchableRegion in computation so the non-touchable areas will not be included. The fix is guarded behind a flag to verify with rollout process, so we can check if there are some side-effect or performance issues.
Bug: 323366243
Flag: ACONFIG com.android.window.flags.use_window_original_touchable_region_when_magnification_recompute_bounds DEVELOPMENT
Test: manually flip flag
atest AccessibilityMagnificationTest
Change-Id: I4681e286f7b4465fca5c77d579be104ff73ad42f
| -rw-r--r-- | core/java/android/window/flags/accessibility.aconfig | 12 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/AccessibilityController.java | 63 |
2 files changed, 65 insertions, 10 deletions
diff --git a/core/java/android/window/flags/accessibility.aconfig b/core/java/android/window/flags/accessibility.aconfig index 90b54bd76a60..590e88ba11f0 100644 --- a/core/java/android/window/flags/accessibility.aconfig +++ b/core/java/android/window/flags/accessibility.aconfig @@ -13,6 +13,16 @@ flag { description: "Always draw fullscreen orange border in fullscreen magnification" bug: "291891390" metadata { - purpose: PURPOSE_BUGFIX + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "use_window_original_touchable_region_when_magnification_recompute_bounds" + namespace: "accessibility" + description: "The flag controls whether to use the window original touchable regions in accessibilityController recomputeBounds" + bug: "323366243" + metadata { + purpose: PURPOSE_BUGFIX } }
\ No newline at end of file diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 418998870f16..3f041cb48ee2 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -961,16 +961,37 @@ final class AccessibilityController { populateTransformationMatrix(windowState, matrix); Region touchableRegion = mTempRegion3; windowState.getTouchableRegion(touchableRegion); - Rect touchableFrame = mTempRect1; - touchableRegion.getBounds(touchableFrame); - RectF windowFrame = mTempRectF; - windowFrame.set(touchableFrame); - windowFrame.offset(-windowState.getFrame().left, - -windowState.getFrame().top); - matrix.mapRect(windowFrame); Region windowBounds = mTempRegion2; - windowBounds.set((int) windowFrame.left, (int) windowFrame.top, - (int) windowFrame.right, (int) windowFrame.bottom); + if (Flags.useWindowOriginalTouchableRegionWhenMagnificationRecomputeBounds()) { + // For b/323366243, if using the bounds from touchableRegion.getBounds, in + // non-magnifiable windowBounds computation, part of the non-touchableRegion + // may be included into nonMagnifiedBounds. This will make users lose + // the magnification control on mis-included areas. + // Therefore, to prevent the above issue, we change to use the window exact + // touchableRegion in magnificationRegion computation. + // Like the original approach, the touchableRegion is in non-magnified display + // space, so first we need to offset the region by the windowFrames bounds, then + // apply the transform matrix to the region to get the exact region in magnified + // display space. + // TODO: For a long-term plan, since touchable regions provided by WindowState + // doesn't actually reflect the real touchable regions on display, we should + // delete the WindowState dependency and migrate to use the touchableRegion + // from WindowInfoListener data. (b/330653961) + touchableRegion.translate(-windowState.getFrame().left, + -windowState.getFrame().top); + applyMatrixToRegion(matrix, touchableRegion); + windowBounds.set(touchableRegion); + } else { + Rect touchableFrame = mTempRect1; + touchableRegion.getBounds(touchableFrame); + RectF windowFrame = mTempRectF; + windowFrame.set(touchableFrame); + windowFrame.offset(-windowState.getFrame().left, + -windowState.getFrame().top); + matrix.mapRect(windowFrame); + windowBounds.set((int) windowFrame.left, (int) windowFrame.top, + (int) windowFrame.right, (int) windowFrame.bottom); + } // Only update new regions Region portionOfWindowAlreadyAccountedFor = mTempRegion3; portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion); @@ -1066,6 +1087,30 @@ final class AccessibilityController { || windowType == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY; } + private void applyMatrixToRegion(Matrix matrix, Region region) { + // Since Matrix does not support mapRegion api, so we follow the Matrix#mapRect logic + // to apply the matrix to the given region. + // In Matrix#mapRect, the internal calculation is applying the transform matrix to + // rect's 4 corner points with the below calculation. (see SkMatrix::mapPoints) + // |A B C| |x| Ax+By+C Dx+Ey+F + // |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + // |G H I| |1| Gx+Hy+I Gx+Hy+I + // For magnification usage, the matrix is created from + // WindowState#getTransformationMatrix. We can simplify the matrix calculation to be + // |scale 0 trans_x| |x| + // | 0 scale trans_y| |y| = (scale*x + trans_x, scale*y + trans_y) + // | 0 0 1 | |1| + // So, to follow the simplified matrix computation, we first scale the region with + // matrix.scale, then translate the region with matrix.trans_x and matrix.trans_y. + float[] transformArray = sTempFloats; + matrix.getValues(transformArray); + // For magnification transform matrix, the scale_x and scale_y are equal. + region.scale(transformArray[Matrix.MSCALE_X]); + region.translate( + (int) transformArray[Matrix.MTRANS_X], + (int) transformArray[Matrix.MTRANS_Y]); + } + private void populateWindowsOnScreen(SparseArray<WindowState> outWindows) { mTempLayer = 0; mDisplayContent.forAllWindows((w) -> { |