Merge "Support set window size API" into tm-dev

This commit is contained in:
Ryan Lin
2022-02-23 01:22:02 +00:00
committed by Android (Google) Code Review
4 changed files with 207 additions and 36 deletions

View File

@@ -606,6 +606,9 @@
<!-- The padding ratio of the Accessibility icon foreground drawable --> <!-- The padding ratio of the Accessibility icon foreground drawable -->
<item name="accessibility_icon_foreground_padding_ratio" type="dimen">21.88%</item> <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 --> <!-- Margin around the various security views -->
<dimen name="keyguard_muliuser_selector_margin">8dp</dimen> <dimen name="keyguard_muliuser_selector_margin">8dp</dimen>

View File

@@ -4399,6 +4399,7 @@
<java-symbol type="color" name="accessibility_focus_highlight_color" /> <java-symbol type="color" name="accessibility_focus_highlight_color" />
<!-- Width of the outline stroke used by the accessibility focus rectangle --> <!-- 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_focus_highlight_stroke_width" />
<java-symbol type="dimen" name="accessibility_window_magnifier_min_size" />
<java-symbol type="bool" name="config_attachNavBarToAppDuringTransition" /> <java-symbol type="bool" name="config_attachNavBarToAppDuringTransition" />

View File

@@ -43,6 +43,7 @@ import android.os.Handler;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import android.util.Range; import android.util.Range;
import android.util.Size;
import android.view.Choreographer; import android.view.Choreographer;
import android.view.Display; import android.view.Display;
import android.view.Gravity; import android.view.Gravity;
@@ -62,6 +63,8 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.IRemoteMagnificationAnimationCallback; import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import androidx.core.math.MathUtils;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.R; import com.android.systemui.R;
@@ -166,6 +169,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
private final Rect mMagnificationFrameBoundary = new Rect(); private final Rect mMagnificationFrameBoundary = new Rect();
// The top Y of the system gesture rect at the bottom. Set to -1 if it is invalid. // The top Y of the system gesture rect at the bottom. Set to -1 if it is invalid.
private int mSystemGestureTop = -1; private int mSystemGestureTop = -1;
private int mMinWindowSize;
private final WindowMagnificationAnimationController mAnimationController; private final WindowMagnificationAnimationController mAnimationController;
private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider; private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
@@ -208,8 +212,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mBounceEffectDuration = mResources.getInteger( mBounceEffectDuration = mResources.getInteger(
com.android.internal.R.integer.config_shortAnimTime); com.android.internal.R.integer.config_shortAnimTime);
updateDimensions(); 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(); computeBounceAnimationScale();
mMirrorWindowControl = mirrorWindowControl; mMirrorWindowControl = mirrorWindowControl;
@@ -281,6 +287,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
R.dimen.magnification_drag_view_size); R.dimen.magnification_drag_view_size);
mOuterBorderSize = mResources.getDimensionPixelSize( mOuterBorderSize = mResources.getDimensionPixelSize(
R.dimen.magnification_outer_border_margin); R.dimen.magnification_outer_border_margin);
mMinWindowSize = mResources.getDimensionPixelSize(
com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
} }
private void computeBounceAnimationScale() { private void computeBounceAnimationScale() {
@@ -414,9 +422,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
return false; return false;
} }
mWindowBounds.set(currentWindowBounds); mWindowBounds.set(currentWindowBounds);
final Size windowSize = getDefaultWindowSizeWithWindowBounds(mWindowBounds);
final float newCenterX = (getCenterX()) * mWindowBounds.width() / oldWindowBounds.width(); final float newCenterX = (getCenterX()) * mWindowBounds.width() / oldWindowBounds.width();
final float newCenterY = (getCenterY()) * mWindowBounds.height() / oldWindowBounds.height(); final float newCenterY = (getCenterY()) * mWindowBounds.height() / oldWindowBounds.height();
setMagnificationFrameWith(mWindowBounds, (int) newCenterX, (int) newCenterY);
setMagnificationFrame(windowSize.getWidth(), windowSize.getHeight(), (int) newCenterX,
(int) newCenterY);
calculateMagnificationFrameBoundary(); calculateMagnificationFrameBoundary();
return true; return true;
} }
@@ -454,11 +465,6 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mWindowBounds.set(currentWindowBounds); mWindowBounds.set(currentWindowBounds);
calculateMagnificationFrameBoundary();
if (!isWindowVisible()) {
return;
}
// Keep MirrorWindow position on the screen unchanged when device rotates 90° // Keep MirrorWindow position on the screen unchanged when device rotates 90°
// clockwise or anti-clockwise. // clockwise or anti-clockwise.
@@ -469,14 +475,13 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
} else if (rotationDegree == 270) { } else if (rotationDegree == 270) {
matrix.postTranslate(0, mWindowBounds.height()); matrix.postTranslate(0, mWindowBounds.height());
} }
// The rect of MirrorView is going to be transformed.
LayoutParams params = final RectF transformedRect = new RectF(mMagnificationFrame);
(LayoutParams) mMirrorView.getLayoutParams(); // The window frame is going to be transformed by the rotation matrix.
mTmpRect.set(params.x, params.y, params.x + params.width, params.y + params.height); transformedRect.inset(-mMirrorSurfaceMargin, -mMirrorSurfaceMargin);
final RectF transformedRect = new RectF(mTmpRect);
matrix.mapRect(transformedRect); matrix.mapRect(transformedRect);
moveWindowMagnifier(transformedRect.left - mTmpRect.left, setWindowSizeAndCenter((int) transformedRect.width(), (int) transformedRect.height(),
transformedRect.top - mTmpRect.top); (int) transformedRect.centerX(), (int) transformedRect.centerY());
} }
/** Returns the rotation degree change of two {@link Surface.Rotation} */ /** Returns the rotation degree change of two {@link Surface.Rotation} */
@@ -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 // Sets the initial frame area for the mirror and place it to the given center on the
// display. // 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; int initSize = Math.min(windowBounds.width(), windowBounds.height()) / 2;
initSize = Math.min(mResources.getDimensionPixelSize(R.dimen.magnification_max_frame_size), initSize = Math.min(mResources.getDimensionPixelSize(R.dimen.magnification_max_frame_size),
initSize); initSize);
initSize += 2 * mMirrorSurfaceMargin; initSize += 2 * mMirrorSurfaceMargin;
final int initX = centerX - initSize / 2; return new Size(initSize, initSize);
final int initY = centerY - initSize / 2;
mMagnificationFrame.set(initX, initY, initX + initSize, initY + initSize);
} }
/** /**
@@ -596,8 +637,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
} }
mTransaction.show(mMirrorSurface) mTransaction.show(mMirrorSurface)
.reparent(mMirrorSurface, mMirrorSurfaceView.getSurfaceControl()); .reparent(mMirrorSurface, mMirrorSurfaceView.getSurfaceControl());
modifyWindowMagnification(false);
modifyWindowMagnification(mTransaction);
} }
private void addDragTouchListeners() { private void addDragTouchListeners() {
@@ -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); mSfVsyncFrameProvider.postFrameCallback(mMirrorViewGeometryVsyncCallback);
updateMirrorViewLayout(); updateMirrorViewLayout(computeWindowSize);
} }
/** /**
* Updates the layout params of MirrorView and translates MirrorView position when the view is * Updates the layout params of MirrorView based on the size of {@link #mMagnificationFrame}
* moved close to the screen edges. * 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()) { if (!isWindowVisible()) {
return; return;
} }
@@ -637,6 +684,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
(LayoutParams) mMirrorView.getLayoutParams(); (LayoutParams) mMirrorView.getLayoutParams();
params.x = mMagnificationFrame.left - mMirrorSurfaceMargin; params.x = mMagnificationFrame.left - mMirrorSurfaceMargin;
params.y = mMagnificationFrame.top - 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 // Translates MirrorView position to make MirrorSurfaceView that is inside MirrorView
// able to move close to the screen edges. // able to move close to the screen edges.
@@ -899,7 +950,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
createMirrorWindow(); createMirrorWindow();
showControls(); showControls();
} else { } else {
modifyWindowMagnification(mTransaction); modifyWindowMagnification(false);
} }
} }
@@ -930,7 +981,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
return; return;
} }
if (updateMagnificationFramePosition((int) offsetX, (int) offsetY)) { if (updateMagnificationFramePosition((int) offsetX, (int) offsetY)) {
modifyWindowMagnification(mTransaction); modifyWindowMagnification(false);
} }
} }
@@ -1014,9 +1065,15 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
pw.println(" mOverlapWithGestureInsets:" + mOverlapWithGestureInsets); pw.println(" mOverlapWithGestureInsets:" + mOverlapWithGestureInsets);
pw.println(" mScale:" + mScale); pw.println(" mScale:" + mScale);
pw.println(" mMirrorViewBounds:" + (isWindowVisible() ? mMirrorViewBounds : "empty")); pw.println(" mMirrorViewBounds:" + (isWindowVisible() ? mMirrorViewBounds : "empty"));
pw.println(" mMagnificationFrameBoundary:"
+ (isWindowVisible() ? mMagnificationFrameBoundary : "empty"));
pw.println(" mMagnificationFrame:"
+ (isWindowVisible() ? mMagnificationFrame : "empty"));
pw.println(" mSourceBounds:" pw.println(" mSourceBounds:"
+ (isWindowVisible() ? mSourceBounds : "empty")); + (isWindowVisible() ? mSourceBounds : "empty"));
pw.println(" mSystemGestureTop:" + mSystemGestureTop); pw.println(" mSystemGestureTop:" + mSystemGestureTop);
pw.println(" mMagnificationFrameOffsetX:" + mMagnificationFrameOffsetX);
pw.println(" mMagnificationFrameOffsetY:" + mMagnificationFrameOffsetY);
} }
private class MirrorWindowA11yDelegate extends View.AccessibilityDelegate { private class MirrorWindowA11yDelegate extends View.AccessibilityDelegate {

View File

@@ -88,6 +88,7 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@LargeTest @LargeTest
@TestableLooper.RunWithLooper @TestableLooper.RunWithLooper
@@ -345,15 +346,17 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
@Test @Test
public void onOrientationChanged_disabled_updateDisplayRotation() { public void onOrientationChanged_disabled_updateDisplayRotation() {
final Display display = Mockito.spy(mContext.getDisplay()); final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
when(display.getRotation()).thenReturn(Surface.ROTATION_90); // Rotate the window clockwise 90 degree.
when(mContext.getDisplay()).thenReturn(display); windowBounds.set(windowBounds.top, windowBounds.left, windowBounds.bottom,
windowBounds.right);
mWindowManager.setWindowBounds(windowBounds);
final int newRotation = simulateRotateTheDevice();
mInstrumentation.runOnMainSync(() -> { mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.onConfigurationChanged(
mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION); ActivityInfo.CONFIG_ORIENTATION));
});
assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation); assertEquals(newRotation, mWindowMagnificationController.mRotation);
} }
@Test @Test
@@ -603,6 +606,113 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
ReferenceTestUtils.waitForCondition(() -> hasMagnificationOverlapFlag()); 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() { private CharSequence getAccessibilityWindowTitle() {
final View mirrorView = mWindowManager.getAttachedView(); final View mirrorView = mWindowManager.getAttachedView();
if (mirrorView == null) { if (mirrorView == null) {