Loading core/res/res/values/dimens.xml +3 −0 Original line number Diff line number Diff line Loading @@ -606,6 +606,9 @@ <!-- The padding ratio of the Accessibility icon foreground drawable --> <item name="accessibility_icon_foreground_padding_ratio" type="dimen">21.88%</item> <!-- The minimum window size of the accessibility window magnifier --> <dimen name="accessibility_window_magnifier_min_size">122dp</dimen> <!-- Margin around the various security views --> <dimen name="keyguard_muliuser_selector_margin">8dp</dimen> Loading core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -4399,6 +4399,7 @@ <java-symbol type="color" name="accessibility_focus_highlight_color" /> <!-- Width of the outline stroke used by the accessibility focus rectangle --> <java-symbol type="dimen" name="accessibility_focus_highlight_stroke_width" /> <java-symbol type="dimen" name="accessibility_window_magnifier_min_size" /> <java-symbol type="bool" name="config_attachNavBarToAppDuringTransition" /> Loading packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +86 −29 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import android.os.Handler; import android.os.RemoteException; import android.util.Log; import android.util.Range; import android.util.Size; import android.view.Choreographer; import android.view.Display; import android.view.Gravity; Loading @@ -62,6 +63,8 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.accessibility.IRemoteMagnificationAnimationCallback; import androidx.core.math.MathUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.systemui.R; Loading Loading @@ -166,6 +169,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold private final Rect mMagnificationFrameBoundary = new Rect(); // The top Y of the system gesture rect at the bottom. Set to -1 if it is invalid. private int mSystemGestureTop = -1; private int mMinWindowSize; private final WindowMagnificationAnimationController mAnimationController; private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider; Loading Loading @@ -208,8 +212,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold mBounceEffectDuration = mResources.getInteger( com.android.internal.R.integer.config_shortAnimTime); updateDimensions(); setMagnificationFrameWith(mWindowBounds, mWindowBounds.width() / 2, mWindowBounds.height() / 2); final Size windowSize = getDefaultWindowSizeWithWindowBounds(mWindowBounds); setMagnificationFrame(windowSize.getWidth(), windowSize.getHeight(), mWindowBounds.width() / 2, mWindowBounds.height() / 2); computeBounceAnimationScale(); mMirrorWindowControl = mirrorWindowControl; Loading Loading @@ -281,6 +287,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold R.dimen.magnification_drag_view_size); mOuterBorderSize = mResources.getDimensionPixelSize( R.dimen.magnification_outer_border_margin); mMinWindowSize = mResources.getDimensionPixelSize( com.android.internal.R.dimen.accessibility_window_magnifier_min_size); } private void computeBounceAnimationScale() { Loading Loading @@ -414,9 +422,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold return false; } mWindowBounds.set(currentWindowBounds); final Size windowSize = getDefaultWindowSizeWithWindowBounds(mWindowBounds); final float newCenterX = (getCenterX()) * mWindowBounds.width() / oldWindowBounds.width(); final float newCenterY = (getCenterY()) * mWindowBounds.height() / oldWindowBounds.height(); setMagnificationFrameWith(mWindowBounds, (int) newCenterX, (int) newCenterY); setMagnificationFrame(windowSize.getWidth(), windowSize.getHeight(), (int) newCenterX, (int) newCenterY); calculateMagnificationFrameBoundary(); return true; } Loading Loading @@ -454,11 +465,6 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold mWindowBounds.set(currentWindowBounds); calculateMagnificationFrameBoundary(); if (!isWindowVisible()) { return; } // Keep MirrorWindow position on the screen unchanged when device rotates 90° // clockwise or anti-clockwise. Loading @@ -469,14 +475,13 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold } else if (rotationDegree == 270) { matrix.postTranslate(0, mWindowBounds.height()); } // The rect of MirrorView is going to be transformed. LayoutParams params = (LayoutParams) mMirrorView.getLayoutParams(); mTmpRect.set(params.x, params.y, params.x + params.width, params.y + params.height); final RectF transformedRect = new RectF(mTmpRect); final RectF transformedRect = new RectF(mMagnificationFrame); // The window frame is going to be transformed by the rotation matrix. transformedRect.inset(-mMirrorSurfaceMargin, -mMirrorSurfaceMargin); matrix.mapRect(transformedRect); moveWindowMagnifier(transformedRect.left - mTmpRect.left, transformedRect.top - mTmpRect.top); setWindowSizeAndCenter((int) transformedRect.width(), (int) transformedRect.height(), (int) transformedRect.centerX(), (int) transformedRect.centerY()); } /** Returns the rotation degree change of two {@link Surface.Rotation} */ Loading Loading @@ -573,16 +578,52 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold } } private void setMagnificationFrameWith(Rect windowBounds, int centerX, int centerY) { /** * Sets the window size with given width and height in pixels without changing the * window center. The width or the height will be clamped in the range * [{@link #mMinWindowSize}, screen width or height]. * * @param width the window width in pixels * @param height the window height in pixels. */ public void setWindowSize(int width, int height) { setWindowSizeAndCenter(width, height, Float.NaN, Float.NaN); } void setWindowSizeAndCenter(int width, int height, float centerX, float centerY) { width = MathUtils.clamp(width, mMinWindowSize, mWindowBounds.width()); height = MathUtils.clamp(height, mMinWindowSize, mWindowBounds.height()); if (Float.isNaN(centerX)) { centerX = mMagnificationFrame.centerX(); } if (Float.isNaN(centerX)) { centerY = mMagnificationFrame.centerY(); } final int frameWidth = width - 2 * mMirrorSurfaceMargin; final int frameHeight = height - 2 * mMirrorSurfaceMargin; setMagnificationFrame(frameWidth, frameHeight, (int) centerX, (int) centerY); calculateMagnificationFrameBoundary(); // Correct the frame position to ensure it is inside the boundary. updateMagnificationFramePosition(0, 0); modifyWindowMagnification(true); } private void setMagnificationFrame(int width, int height, int centerX, int centerY) { // Sets the initial frame area for the mirror and place it to the given center on the // display. final int initX = centerX - width / 2; final int initY = centerY - height / 2; mMagnificationFrame.set(initX, initY, initX + width, initY + height); } private Size getDefaultWindowSizeWithWindowBounds(Rect windowBounds) { int initSize = Math.min(windowBounds.width(), windowBounds.height()) / 2; initSize = Math.min(mResources.getDimensionPixelSize(R.dimen.magnification_max_frame_size), initSize); initSize += 2 * mMirrorSurfaceMargin; final int initX = centerX - initSize / 2; final int initY = centerY - initSize / 2; mMagnificationFrame.set(initX, initY, initX + initSize, initY + initSize); return new Size(initSize, initSize); } /** Loading @@ -596,8 +637,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold } mTransaction.show(mMirrorSurface) .reparent(mMirrorSurface, mMirrorSurfaceView.getSurfaceControl()); modifyWindowMagnification(mTransaction); modifyWindowMagnification(false); } private void addDragTouchListeners() { Loading @@ -615,18 +655,25 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold } /** * Modifies the placement of the mirrored content when the position of mMirrorView is updated. * Modifies the placement of the mirrored content when the position or size of mMirrorView is * updated. * * @param computeWindowSize set to {@code true} to compute window size with * {@link #mMagnificationFrame}. */ private void modifyWindowMagnification(SurfaceControl.Transaction t) { private void modifyWindowMagnification(boolean computeWindowSize) { mSfVsyncFrameProvider.postFrameCallback(mMirrorViewGeometryVsyncCallback); updateMirrorViewLayout(); updateMirrorViewLayout(computeWindowSize); } /** * Updates the layout params of MirrorView and translates MirrorView position when the view is * moved close to the screen edges. * Updates the layout params of MirrorView based on the size of {@link #mMagnificationFrame} * and translates MirrorView position when the view is moved close to the screen edges; * * @param computeWindowSize set to {@code true} to compute window size with * {@link #mMagnificationFrame}. */ private void updateMirrorViewLayout() { private void updateMirrorViewLayout(boolean computeWindowSize) { if (!isWindowVisible()) { return; } Loading @@ -637,6 +684,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold (LayoutParams) mMirrorView.getLayoutParams(); params.x = mMagnificationFrame.left - mMirrorSurfaceMargin; params.y = mMagnificationFrame.top - mMirrorSurfaceMargin; if (computeWindowSize) { params.width = mMagnificationFrame.width() + 2 * mMirrorSurfaceMargin; params.height = mMagnificationFrame.height() + 2 * mMirrorSurfaceMargin; } // Translates MirrorView position to make MirrorSurfaceView that is inside MirrorView // able to move close to the screen edges. Loading Loading @@ -899,7 +950,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold createMirrorWindow(); showControls(); } else { modifyWindowMagnification(mTransaction); modifyWindowMagnification(false); } } Loading Loading @@ -930,7 +981,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold return; } if (updateMagnificationFramePosition((int) offsetX, (int) offsetY)) { modifyWindowMagnification(mTransaction); modifyWindowMagnification(false); } } Loading Loading @@ -1014,9 +1065,15 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold pw.println(" mOverlapWithGestureInsets:" + mOverlapWithGestureInsets); pw.println(" mScale:" + mScale); pw.println(" mMirrorViewBounds:" + (isWindowVisible() ? mMirrorViewBounds : "empty")); pw.println(" mMagnificationFrameBoundary:" + (isWindowVisible() ? mMagnificationFrameBoundary : "empty")); pw.println(" mMagnificationFrame:" + (isWindowVisible() ? mMagnificationFrame : "empty")); pw.println(" mSourceBounds:" + (isWindowVisible() ? mSourceBounds : "empty")); pw.println(" mSystemGestureTop:" + mSystemGestureTop); pw.println(" mMagnificationFrameOffsetX:" + mMagnificationFrameOffsetX); pw.println(" mMagnificationFrameOffsetY:" + mMagnificationFrameOffsetY); } private class MirrorWindowA11yDelegate extends View.AccessibilityDelegate { Loading packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +117 −7 Original line number Diff line number Diff line Loading @@ -88,6 +88,7 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @LargeTest @TestableLooper.RunWithLooper Loading Loading @@ -345,15 +346,17 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { @Test public void onOrientationChanged_disabled_updateDisplayRotation() { final Display display = Mockito.spy(mContext.getDisplay()); when(display.getRotation()).thenReturn(Surface.ROTATION_90); when(mContext.getDisplay()).thenReturn(display); final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds()); // Rotate the window clockwise 90 degree. windowBounds.set(windowBounds.top, windowBounds.left, windowBounds.bottom, windowBounds.right); mWindowManager.setWindowBounds(windowBounds); final int newRotation = simulateRotateTheDevice(); mInstrumentation.runOnMainSync(() -> { mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION); }); mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.onConfigurationChanged( ActivityInfo.CONFIG_ORIENTATION)); assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation); assertEquals(newRotation, mWindowMagnificationController.mRotation); } @Test Loading Loading @@ -603,6 +606,113 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { ReferenceTestUtils.waitForCondition(() -> hasMagnificationOverlapFlag()); } @Test public void setMinimumWindowSize_enabled_expectedWindowSize() { final int minimumWindowSize = mResources.getDimensionPixelSize( com.android.internal.R.dimen.accessibility_window_magnifier_min_size); final int expectedWindowHeight = minimumWindowSize; final int expectedWindowWidth = minimumWindowSize; mInstrumentation.runOnMainSync( () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN)); final AtomicInteger actualWindowHeight = new AtomicInteger(); final AtomicInteger actualWindowWidth = new AtomicInteger(); mInstrumentation.runOnMainSync(() -> { mWindowMagnificationController.setWindowSize(expectedWindowWidth, expectedWindowHeight); actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height); actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width); }); assertEquals(expectedWindowHeight, actualWindowHeight.get()); assertEquals(expectedWindowWidth, actualWindowWidth.get()); } @Test public void setMinimumWindowSizeThenEnable_expectedWindowSize() { final int minimumWindowSize = mResources.getDimensionPixelSize( com.android.internal.R.dimen.accessibility_window_magnifier_min_size); final int expectedWindowHeight = minimumWindowSize; final int expectedWindowWidth = minimumWindowSize; final AtomicInteger actualWindowHeight = new AtomicInteger(); final AtomicInteger actualWindowWidth = new AtomicInteger(); mInstrumentation.runOnMainSync(() -> { mWindowMagnificationController.setWindowSize(expectedWindowWidth, expectedWindowHeight); mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN); actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height); actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width); }); assertEquals(expectedWindowHeight, actualWindowHeight.get()); assertEquals(expectedWindowWidth, actualWindowWidth.get()); } @Test public void setWindowSizeLessThanMin_enabled_minimumWindowSize() { final int minimumWindowSize = mResources.getDimensionPixelSize( com.android.internal.R.dimen.accessibility_window_magnifier_min_size); mInstrumentation.runOnMainSync( () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN)); final AtomicInteger actualWindowHeight = new AtomicInteger(); final AtomicInteger actualWindowWidth = new AtomicInteger(); mInstrumentation.runOnMainSync(() -> { mWindowMagnificationController.setWindowSize(minimumWindowSize - 10, minimumWindowSize - 10); actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height); actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width); }); assertEquals(minimumWindowSize, actualWindowHeight.get()); assertEquals(minimumWindowSize, actualWindowWidth.get()); } @Test public void setWindowSizeLargerThanScreenSize_enabled_windowSizeIsScreenSize() { final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds(); mInstrumentation.runOnMainSync( () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN)); final AtomicInteger actualWindowHeight = new AtomicInteger(); final AtomicInteger actualWindowWidth = new AtomicInteger(); mInstrumentation.runOnMainSync(() -> { mWindowMagnificationController.setWindowSize(bounds.width() + 10, bounds.height() + 10); actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height); actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width); }); assertEquals(bounds.height(), actualWindowHeight.get()); assertEquals(bounds.width(), actualWindowWidth.get()); } @Test public void setWindowCenterOutOfScreen_enabled_magnificationCenterIsInsideTheScreen() { final int minimumWindowSize = mResources.getDimensionPixelSize( com.android.internal.R.dimen.accessibility_window_magnifier_min_size); final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds(); mInstrumentation.runOnMainSync( () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN)); final AtomicInteger magnificationCenterX = new AtomicInteger(); final AtomicInteger magnificationCenterY = new AtomicInteger(); mInstrumentation.runOnMainSync(() -> { mWindowMagnificationController.setWindowSizeAndCenter(minimumWindowSize, minimumWindowSize, bounds.right, bounds.bottom); magnificationCenterX.set((int) mWindowMagnificationController.getCenterX()); magnificationCenterY.set((int) mWindowMagnificationController.getCenterY()); }); assertTrue(magnificationCenterX.get() < bounds.right); assertTrue(magnificationCenterY.get() < bounds.bottom); } private CharSequence getAccessibilityWindowTitle() { final View mirrorView = mWindowManager.getAttachedView(); if (mirrorView == null) { Loading Loading
core/res/res/values/dimens.xml +3 −0 Original line number Diff line number Diff line Loading @@ -606,6 +606,9 @@ <!-- The padding ratio of the Accessibility icon foreground drawable --> <item name="accessibility_icon_foreground_padding_ratio" type="dimen">21.88%</item> <!-- The minimum window size of the accessibility window magnifier --> <dimen name="accessibility_window_magnifier_min_size">122dp</dimen> <!-- Margin around the various security views --> <dimen name="keyguard_muliuser_selector_margin">8dp</dimen> Loading
core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -4399,6 +4399,7 @@ <java-symbol type="color" name="accessibility_focus_highlight_color" /> <!-- Width of the outline stroke used by the accessibility focus rectangle --> <java-symbol type="dimen" name="accessibility_focus_highlight_stroke_width" /> <java-symbol type="dimen" name="accessibility_window_magnifier_min_size" /> <java-symbol type="bool" name="config_attachNavBarToAppDuringTransition" /> Loading
packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +86 −29 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import android.os.Handler; import android.os.RemoteException; import android.util.Log; import android.util.Range; import android.util.Size; import android.view.Choreographer; import android.view.Display; import android.view.Gravity; Loading @@ -62,6 +63,8 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.accessibility.IRemoteMagnificationAnimationCallback; import androidx.core.math.MathUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.systemui.R; Loading Loading @@ -166,6 +169,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold private final Rect mMagnificationFrameBoundary = new Rect(); // The top Y of the system gesture rect at the bottom. Set to -1 if it is invalid. private int mSystemGestureTop = -1; private int mMinWindowSize; private final WindowMagnificationAnimationController mAnimationController; private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider; Loading Loading @@ -208,8 +212,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold mBounceEffectDuration = mResources.getInteger( com.android.internal.R.integer.config_shortAnimTime); updateDimensions(); setMagnificationFrameWith(mWindowBounds, mWindowBounds.width() / 2, mWindowBounds.height() / 2); final Size windowSize = getDefaultWindowSizeWithWindowBounds(mWindowBounds); setMagnificationFrame(windowSize.getWidth(), windowSize.getHeight(), mWindowBounds.width() / 2, mWindowBounds.height() / 2); computeBounceAnimationScale(); mMirrorWindowControl = mirrorWindowControl; Loading Loading @@ -281,6 +287,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold R.dimen.magnification_drag_view_size); mOuterBorderSize = mResources.getDimensionPixelSize( R.dimen.magnification_outer_border_margin); mMinWindowSize = mResources.getDimensionPixelSize( com.android.internal.R.dimen.accessibility_window_magnifier_min_size); } private void computeBounceAnimationScale() { Loading Loading @@ -414,9 +422,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold return false; } mWindowBounds.set(currentWindowBounds); final Size windowSize = getDefaultWindowSizeWithWindowBounds(mWindowBounds); final float newCenterX = (getCenterX()) * mWindowBounds.width() / oldWindowBounds.width(); final float newCenterY = (getCenterY()) * mWindowBounds.height() / oldWindowBounds.height(); setMagnificationFrameWith(mWindowBounds, (int) newCenterX, (int) newCenterY); setMagnificationFrame(windowSize.getWidth(), windowSize.getHeight(), (int) newCenterX, (int) newCenterY); calculateMagnificationFrameBoundary(); return true; } Loading Loading @@ -454,11 +465,6 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold mWindowBounds.set(currentWindowBounds); calculateMagnificationFrameBoundary(); if (!isWindowVisible()) { return; } // Keep MirrorWindow position on the screen unchanged when device rotates 90° // clockwise or anti-clockwise. Loading @@ -469,14 +475,13 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold } else if (rotationDegree == 270) { matrix.postTranslate(0, mWindowBounds.height()); } // The rect of MirrorView is going to be transformed. LayoutParams params = (LayoutParams) mMirrorView.getLayoutParams(); mTmpRect.set(params.x, params.y, params.x + params.width, params.y + params.height); final RectF transformedRect = new RectF(mTmpRect); final RectF transformedRect = new RectF(mMagnificationFrame); // The window frame is going to be transformed by the rotation matrix. transformedRect.inset(-mMirrorSurfaceMargin, -mMirrorSurfaceMargin); matrix.mapRect(transformedRect); moveWindowMagnifier(transformedRect.left - mTmpRect.left, transformedRect.top - mTmpRect.top); setWindowSizeAndCenter((int) transformedRect.width(), (int) transformedRect.height(), (int) transformedRect.centerX(), (int) transformedRect.centerY()); } /** Returns the rotation degree change of two {@link Surface.Rotation} */ Loading Loading @@ -573,16 +578,52 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold } } private void setMagnificationFrameWith(Rect windowBounds, int centerX, int centerY) { /** * Sets the window size with given width and height in pixels without changing the * window center. The width or the height will be clamped in the range * [{@link #mMinWindowSize}, screen width or height]. * * @param width the window width in pixels * @param height the window height in pixels. */ public void setWindowSize(int width, int height) { setWindowSizeAndCenter(width, height, Float.NaN, Float.NaN); } void setWindowSizeAndCenter(int width, int height, float centerX, float centerY) { width = MathUtils.clamp(width, mMinWindowSize, mWindowBounds.width()); height = MathUtils.clamp(height, mMinWindowSize, mWindowBounds.height()); if (Float.isNaN(centerX)) { centerX = mMagnificationFrame.centerX(); } if (Float.isNaN(centerX)) { centerY = mMagnificationFrame.centerY(); } final int frameWidth = width - 2 * mMirrorSurfaceMargin; final int frameHeight = height - 2 * mMirrorSurfaceMargin; setMagnificationFrame(frameWidth, frameHeight, (int) centerX, (int) centerY); calculateMagnificationFrameBoundary(); // Correct the frame position to ensure it is inside the boundary. updateMagnificationFramePosition(0, 0); modifyWindowMagnification(true); } private void setMagnificationFrame(int width, int height, int centerX, int centerY) { // Sets the initial frame area for the mirror and place it to the given center on the // display. final int initX = centerX - width / 2; final int initY = centerY - height / 2; mMagnificationFrame.set(initX, initY, initX + width, initY + height); } private Size getDefaultWindowSizeWithWindowBounds(Rect windowBounds) { int initSize = Math.min(windowBounds.width(), windowBounds.height()) / 2; initSize = Math.min(mResources.getDimensionPixelSize(R.dimen.magnification_max_frame_size), initSize); initSize += 2 * mMirrorSurfaceMargin; final int initX = centerX - initSize / 2; final int initY = centerY - initSize / 2; mMagnificationFrame.set(initX, initY, initX + initSize, initY + initSize); return new Size(initSize, initSize); } /** Loading @@ -596,8 +637,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold } mTransaction.show(mMirrorSurface) .reparent(mMirrorSurface, mMirrorSurfaceView.getSurfaceControl()); modifyWindowMagnification(mTransaction); modifyWindowMagnification(false); } private void addDragTouchListeners() { Loading @@ -615,18 +655,25 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold } /** * Modifies the placement of the mirrored content when the position of mMirrorView is updated. * Modifies the placement of the mirrored content when the position or size of mMirrorView is * updated. * * @param computeWindowSize set to {@code true} to compute window size with * {@link #mMagnificationFrame}. */ private void modifyWindowMagnification(SurfaceControl.Transaction t) { private void modifyWindowMagnification(boolean computeWindowSize) { mSfVsyncFrameProvider.postFrameCallback(mMirrorViewGeometryVsyncCallback); updateMirrorViewLayout(); updateMirrorViewLayout(computeWindowSize); } /** * Updates the layout params of MirrorView and translates MirrorView position when the view is * moved close to the screen edges. * Updates the layout params of MirrorView based on the size of {@link #mMagnificationFrame} * and translates MirrorView position when the view is moved close to the screen edges; * * @param computeWindowSize set to {@code true} to compute window size with * {@link #mMagnificationFrame}. */ private void updateMirrorViewLayout() { private void updateMirrorViewLayout(boolean computeWindowSize) { if (!isWindowVisible()) { return; } Loading @@ -637,6 +684,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold (LayoutParams) mMirrorView.getLayoutParams(); params.x = mMagnificationFrame.left - mMirrorSurfaceMargin; params.y = mMagnificationFrame.top - mMirrorSurfaceMargin; if (computeWindowSize) { params.width = mMagnificationFrame.width() + 2 * mMirrorSurfaceMargin; params.height = mMagnificationFrame.height() + 2 * mMirrorSurfaceMargin; } // Translates MirrorView position to make MirrorSurfaceView that is inside MirrorView // able to move close to the screen edges. Loading Loading @@ -899,7 +950,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold createMirrorWindow(); showControls(); } else { modifyWindowMagnification(mTransaction); modifyWindowMagnification(false); } } Loading Loading @@ -930,7 +981,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold return; } if (updateMagnificationFramePosition((int) offsetX, (int) offsetY)) { modifyWindowMagnification(mTransaction); modifyWindowMagnification(false); } } Loading Loading @@ -1014,9 +1065,15 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold pw.println(" mOverlapWithGestureInsets:" + mOverlapWithGestureInsets); pw.println(" mScale:" + mScale); pw.println(" mMirrorViewBounds:" + (isWindowVisible() ? mMirrorViewBounds : "empty")); pw.println(" mMagnificationFrameBoundary:" + (isWindowVisible() ? mMagnificationFrameBoundary : "empty")); pw.println(" mMagnificationFrame:" + (isWindowVisible() ? mMagnificationFrame : "empty")); pw.println(" mSourceBounds:" + (isWindowVisible() ? mSourceBounds : "empty")); pw.println(" mSystemGestureTop:" + mSystemGestureTop); pw.println(" mMagnificationFrameOffsetX:" + mMagnificationFrameOffsetX); pw.println(" mMagnificationFrameOffsetY:" + mMagnificationFrameOffsetY); } private class MirrorWindowA11yDelegate extends View.AccessibilityDelegate { Loading
packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +117 −7 Original line number Diff line number Diff line Loading @@ -88,6 +88,7 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @LargeTest @TestableLooper.RunWithLooper Loading Loading @@ -345,15 +346,17 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { @Test public void onOrientationChanged_disabled_updateDisplayRotation() { final Display display = Mockito.spy(mContext.getDisplay()); when(display.getRotation()).thenReturn(Surface.ROTATION_90); when(mContext.getDisplay()).thenReturn(display); final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds()); // Rotate the window clockwise 90 degree. windowBounds.set(windowBounds.top, windowBounds.left, windowBounds.bottom, windowBounds.right); mWindowManager.setWindowBounds(windowBounds); final int newRotation = simulateRotateTheDevice(); mInstrumentation.runOnMainSync(() -> { mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION); }); mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.onConfigurationChanged( ActivityInfo.CONFIG_ORIENTATION)); assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation); assertEquals(newRotation, mWindowMagnificationController.mRotation); } @Test Loading Loading @@ -603,6 +606,113 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { ReferenceTestUtils.waitForCondition(() -> hasMagnificationOverlapFlag()); } @Test public void setMinimumWindowSize_enabled_expectedWindowSize() { final int minimumWindowSize = mResources.getDimensionPixelSize( com.android.internal.R.dimen.accessibility_window_magnifier_min_size); final int expectedWindowHeight = minimumWindowSize; final int expectedWindowWidth = minimumWindowSize; mInstrumentation.runOnMainSync( () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN)); final AtomicInteger actualWindowHeight = new AtomicInteger(); final AtomicInteger actualWindowWidth = new AtomicInteger(); mInstrumentation.runOnMainSync(() -> { mWindowMagnificationController.setWindowSize(expectedWindowWidth, expectedWindowHeight); actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height); actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width); }); assertEquals(expectedWindowHeight, actualWindowHeight.get()); assertEquals(expectedWindowWidth, actualWindowWidth.get()); } @Test public void setMinimumWindowSizeThenEnable_expectedWindowSize() { final int minimumWindowSize = mResources.getDimensionPixelSize( com.android.internal.R.dimen.accessibility_window_magnifier_min_size); final int expectedWindowHeight = minimumWindowSize; final int expectedWindowWidth = minimumWindowSize; final AtomicInteger actualWindowHeight = new AtomicInteger(); final AtomicInteger actualWindowWidth = new AtomicInteger(); mInstrumentation.runOnMainSync(() -> { mWindowMagnificationController.setWindowSize(expectedWindowWidth, expectedWindowHeight); mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN); actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height); actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width); }); assertEquals(expectedWindowHeight, actualWindowHeight.get()); assertEquals(expectedWindowWidth, actualWindowWidth.get()); } @Test public void setWindowSizeLessThanMin_enabled_minimumWindowSize() { final int minimumWindowSize = mResources.getDimensionPixelSize( com.android.internal.R.dimen.accessibility_window_magnifier_min_size); mInstrumentation.runOnMainSync( () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN)); final AtomicInteger actualWindowHeight = new AtomicInteger(); final AtomicInteger actualWindowWidth = new AtomicInteger(); mInstrumentation.runOnMainSync(() -> { mWindowMagnificationController.setWindowSize(minimumWindowSize - 10, minimumWindowSize - 10); actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height); actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width); }); assertEquals(minimumWindowSize, actualWindowHeight.get()); assertEquals(minimumWindowSize, actualWindowWidth.get()); } @Test public void setWindowSizeLargerThanScreenSize_enabled_windowSizeIsScreenSize() { final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds(); mInstrumentation.runOnMainSync( () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN)); final AtomicInteger actualWindowHeight = new AtomicInteger(); final AtomicInteger actualWindowWidth = new AtomicInteger(); mInstrumentation.runOnMainSync(() -> { mWindowMagnificationController.setWindowSize(bounds.width() + 10, bounds.height() + 10); actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height); actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width); }); assertEquals(bounds.height(), actualWindowHeight.get()); assertEquals(bounds.width(), actualWindowWidth.get()); } @Test public void setWindowCenterOutOfScreen_enabled_magnificationCenterIsInsideTheScreen() { final int minimumWindowSize = mResources.getDimensionPixelSize( com.android.internal.R.dimen.accessibility_window_magnifier_min_size); final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds(); mInstrumentation.runOnMainSync( () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN)); final AtomicInteger magnificationCenterX = new AtomicInteger(); final AtomicInteger magnificationCenterY = new AtomicInteger(); mInstrumentation.runOnMainSync(() -> { mWindowMagnificationController.setWindowSizeAndCenter(minimumWindowSize, minimumWindowSize, bounds.right, bounds.bottom); magnificationCenterX.set((int) mWindowMagnificationController.getCenterX()); magnificationCenterY.set((int) mWindowMagnificationController.getCenterY()); }); assertTrue(magnificationCenterX.get() < bounds.right); assertTrue(magnificationCenterY.get() < bounds.bottom); } private CharSequence getAccessibilityWindowTitle() { final View mirrorView = mWindowManager.getAttachedView(); if (mirrorView == null) { Loading