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 -->
<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>

View File

@@ -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" />

View File

@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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() {
@@ -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;
}
@@ -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.
@@ -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} */
@@ -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);
}
/**
@@ -596,8 +637,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
}
mTransaction.show(mMirrorSurface)
.reparent(mMirrorSurface, mMirrorSurfaceView.getSurfaceControl());
modifyWindowMagnification(mTransaction);
modifyWindowMagnification(false);
}
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);
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;
}
@@ -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.
@@ -899,7 +950,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
createMirrorWindow();
showControls();
} else {
modifyWindowMagnification(mTransaction);
modifyWindowMagnification(false);
}
}
@@ -930,7 +981,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
return;
}
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(" 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 {

View File

@@ -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
@@ -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
@@ -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) {