Merge "Fix incorrect boundary/appearance after folding the device" into sc-v2-dev

This commit is contained in:
Ryan Lin
2021-06-18 08:57:34 +00:00
committed by Android (Google) Code Review
3 changed files with 147 additions and 38 deletions

View File

@@ -28,6 +28,7 @@ import android.annotation.Nullable;
import android.annotation.UiContext;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.Matrix;
@@ -35,6 +36,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
@@ -76,6 +78,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
MirrorWindowControl.MirrorWindowDelegate, MagnificationGestureDetector.OnGestureListener {
private static final String TAG = "WindowMagnificationController";
@SuppressWarnings("isloggabletaglength")
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG) || Build.IS_DEBUGGABLE;
// Delay to avoid updating state description too frequently.
private static final int UPDATE_STATE_DESCRIPTION_DELAY_MS = 100;
// It should be consistent with the value defined in WindowMagnificationGestureHandler.
@@ -158,14 +162,15 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mRotation = display.getRotation();
mWm = context.getSystemService(WindowManager.class);
mWindowBounds = mWm.getCurrentWindowMetrics().getBounds();
mWindowBounds = new Rect(mWm.getCurrentWindowMetrics().getBounds());
mResources = mContext.getResources();
mScale = mResources.getInteger(R.integer.magnification_default_scale);
mBounceEffectDuration = mResources.getInteger(
com.android.internal.R.integer.config_shortAnimTime);
updateDimensions();
setInitialStartBounds();
setMagnificationFrameWith(mWindowBounds, mWindowBounds.width() / 2,
mWindowBounds.height() / 2);
computeBounceAnimationScale();
mMirrorWindowControl = mirrorWindowControl;
@@ -286,18 +291,59 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
* @param configDiff a bit mask of the differences between the configurations
*/
void onConfigurationChanged(int configDiff) {
if (DEBUG) {
Log.d(TAG, "onConfigurationChanged = " + Configuration.configurationDiffToString(
configDiff));
}
if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) {
onRotate();
}
if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) {
updateAccessibilityWindowTitleIfNeeded();
}
boolean reCreateWindow = false;
if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
updateDimensions();
computeBounceAnimationScale();
if (isWindowVisible()) {
deleteWindowMagnification();
enableWindowMagnification(Float.NaN, Float.NaN, Float.NaN);
}
} else if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) {
onRotate();
} else if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) {
updateAccessibilityWindowTitleIfNeeded();
reCreateWindow = true;
}
if ((configDiff & ActivityInfo.CONFIG_SCREEN_SIZE) != 0) {
reCreateWindow |= handleScreenSizeChanged();
}
// Recreate the window again to correct the window appearance due to density or
// window size changed not caused by rotation.
if (isWindowVisible() && reCreateWindow) {
deleteWindowMagnification();
enableWindowMagnification(Float.NaN, Float.NaN, Float.NaN);
}
}
/**
* Calculates the magnification frame if the window bounds is changed.
* Note that the orientation also changes the wind bounds, so it should be handled first.
*
* @return {@code true} if the magnification frame is changed with the new window bounds.
*/
private boolean handleScreenSizeChanged() {
final Rect oldWindowBounds = new Rect(mWindowBounds);
final Rect currentWindowBounds = mWm.getCurrentWindowMetrics().getBounds();
if (currentWindowBounds.equals(oldWindowBounds)) {
if (DEBUG) {
Log.d(TAG, "updateMagnificationFrame -- window bounds is not changed");
}
return false;
}
mWindowBounds.set(currentWindowBounds);
final float newCenterX = (getCenterX()) * mWindowBounds.width() / oldWindowBounds.width();
final float newCenterY = (getCenterY()) * mWindowBounds.height() / oldWindowBounds.height();
setMagnificationFrameWith(mWindowBounds, (int) newCenterX, (int) newCenterY);
calculateMagnificationFrameBoundary();
return true;
}
private void updateSystemUIStateIfNeeded() {
@@ -311,30 +357,42 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mWm.updateViewLayout(mMirrorView, params);
}
/** Handles MirrorWindow position when the device rotation changed. */
/**
* Keep MirrorWindow position on the screen unchanged when device rotates 90° clockwise or
* anti-clockwise.
*/
private void onRotate() {
final Display display = mContext.getDisplay();
final int oldRotation = mRotation;
mWindowBounds = mWm.getCurrentWindowMetrics().getBounds();
setMagnificationFrameBoundary();
mRotation = display.getRotation();
final int rotationDegree = getDegreeFromRotation(mRotation, oldRotation);
if (rotationDegree == 0 || rotationDegree == 180) {
Log.w(TAG, "onRotate -- rotate with the device. skip it");
return;
}
final Rect currentWindowBounds = new Rect(mWm.getCurrentWindowMetrics().getBounds());
if (currentWindowBounds.width() != mWindowBounds.height()
|| currentWindowBounds.height() != mWindowBounds.width()) {
Log.w(TAG, "onRotate -- unexpected window height/width");
return;
}
mWindowBounds.set(currentWindowBounds);
calculateMagnificationFrameBoundary();
if (!isWindowVisible()) {
return;
}
// Keep MirrorWindow position on the screen unchanged when device rotates 90°
// clockwise or anti-clockwise.
final int rotationDegree = getDegreeFromRotation(mRotation, oldRotation);
final Matrix matrix = new Matrix();
matrix.setRotate(rotationDegree);
if (rotationDegree == 90) {
matrix.postTranslate(mWindowBounds.width(), 0);
} else if (rotationDegree == 270) {
matrix.postTranslate(0, mWindowBounds.height());
} else {
Log.w(TAG, "Invalid rotation change. " + rotationDegree);
return;
}
// The rect of MirrorView is going to be transformed.
LayoutParams params =
@@ -440,12 +498,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
}
}
private void setInitialStartBounds() {
private void setMagnificationFrameWith(Rect windowBounds, int centerX, int centerY) {
// Sets the initial frame area for the mirror and places it in the center of the display.
final int initSize = Math.min(mWindowBounds.width(), mWindowBounds.height()) / 2
final int initSize = Math.min(windowBounds.width(), windowBounds.height()) / 2
+ 2 * mMirrorSurfaceMargin;
final int initX = mWindowBounds.width() / 2 - initSize / 2;
final int initY = mWindowBounds.height() / 2 - initSize / 2;
final int initX = centerX - initSize / 2;
final int initY = centerY - initSize / 2;
mMagnificationFrame.set(initX, initY, initX + initSize, initY + initSize);
}
@@ -553,7 +611,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mSourceBounds.set(left, top, right, bottom);
}
private void setMagnificationFrameBoundary() {
private void calculateMagnificationFrameBoundary() {
// Calculates width and height for magnification frame could exceed out the screen.
// TODO : re-calculating again when scale is changed.
// The half width of magnification frame.
@@ -644,7 +702,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
: centerY - mMagnificationFrame.exactCenterY();
mScale = Float.isNaN(scale) ? mScale : scale;
setMagnificationFrameBoundary();
calculateMagnificationFrameBoundary();
updateMagnificationFramePosition((int) offsetX, (int) offsetY);
if (!isWindowVisible()) {
createMirrorWindow();
@@ -764,6 +822,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
pw.println(" mOverlapWithGestureInsets:" + mOverlapWithGestureInsets);
pw.println(" mScale:" + mScale);
pw.println(" mMirrorViewBounds:" + (isWindowVisible() ? mMirrorViewBounds : "empty"));
pw.println(" mSourceBounds:"
+ (isWindowVisible() ? mSourceBounds : "empty"));
pw.println(" mSystemGestureTop:" + mSystemGestureTop);
}

View File

@@ -16,9 +16,6 @@
package com.android.systemui.accessibility;
import static android.view.WindowInsets.Type.systemGestures;
import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Region;
import android.view.Display;
@@ -79,14 +76,11 @@ public class TestableWindowManager implements WindowManager {
@Override
public WindowMetrics getCurrentWindowMetrics() {
final Insets systemGesturesInsets = Insets.of(0, 0, 0, 10);
final WindowInsets insets = new WindowInsets.Builder()
.setInsets(systemGestures(), systemGesturesInsets)
.build();
final WindowMetrics realMetrics = mWindowManager.getCurrentWindowMetrics();
final WindowMetrics windowMetrics = new WindowMetrics(
mWindowBounds == null ? mWindowManager.getCurrentWindowMetrics().getBounds()
mWindowBounds == null ? realMetrics.getBounds()
: mWindowBounds,
mWindowInsets == null ? insets : mWindowInsets);
mWindowInsets == null ? realMetrics.getWindowInsets() : mWindowInsets);
return windowMetrics;
}
@@ -106,10 +100,20 @@ public class TestableWindowManager implements WindowManager {
return (WindowManager.LayoutParams) mView.getLayoutParams();
}
/**
* Sets the given window bounds to current window metrics.
*
* @param bounds the window bounds
*/
public void setWindowBounds(Rect bounds) {
mWindowBounds = bounds;
}
/**
* Sets the given window insets to the current window metics.
*
* @param insets the window insets.
*/
public void setWindowInsets(WindowInsets insets) {
mWindowInsets = insets;
}

View File

@@ -17,6 +17,7 @@
package com.android.systemui.accessibility;
import static android.view.Choreographer.FrameCallback;
import static android.view.WindowInsets.Type.systemGestures;
import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_MAGNIFICATION_OVERLAP;
@@ -45,6 +46,8 @@ import android.app.Instrumentation;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Handler;
import android.os.SystemClock;
@@ -55,6 +58,7 @@ import android.view.Display;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -239,11 +243,13 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_LOCALE);
mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_SCREEN_SIZE);
});
}
@Test
public void onOrientationChanged_enabled_updateDisplayRotationAndLayout() {
public void onOrientationChanged_enabled_updateDisplayRotationAndCenterStayAtSamePosition() {
final Display display = Mockito.spy(mContext.getDisplay());
when(display.getRotation()).thenReturn(Surface.ROTATION_90);
when(mContext.getDisplay()).thenReturn(display);
@@ -251,13 +257,22 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
Float.NaN);
});
final PointF expectedCenter = new PointF(mWindowMagnificationController.getCenterY(),
mWindowMagnificationController.getCenterX());
final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
// Rotate the window 90 degrees.
windowBounds.set(windowBounds.top, windowBounds.left, windowBounds.bottom,
windowBounds.right);
mWindowManager.setWindowBounds(windowBounds);
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
});
assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation);
// The first invocation is called when the surface is created.
final PointF actualCenter = new PointF(mWindowMagnificationController.getCenterX(),
mWindowMagnificationController.getCenterY());
assertEquals(expectedCenter, actualCenter);
verify(mWindowManager, times(2)).updateViewLayout(any(), any());
}
@@ -274,6 +289,33 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation);
}
@Test
public void onScreenSizeChanged_enabledAtTheCenterOfScreen_keepSameWindowSizeRatio() {
// The default position is at the center of the screen.
final float expectedRatio = 0.5f;
final Rect testWindowBounds = new Rect(
mWindowManager.getCurrentWindowMetrics().getBounds());
testWindowBounds.set(testWindowBounds.left, testWindowBounds.top,
testWindowBounds.right + 100, testWindowBounds.bottom + 100);
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
Float.NaN);
});
mWindowManager.setWindowBounds(testWindowBounds);
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_SCREEN_SIZE);
});
// The ratio of center to window size should be the same.
assertEquals(expectedRatio,
mWindowMagnificationController.getCenterX() / testWindowBounds.width(),
0);
assertEquals(expectedRatio,
mWindowMagnificationController.getCenterY() / testWindowBounds.height(),
0);
}
@Test
public void onDensityChanged_enabled_updateDimensionsAndResetWindowMagnification() {
mInstrumentation.runOnMainSync(() -> {
@@ -419,9 +461,12 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
}
@Test
public void moveWindowMagnificationToTheBottom_enabled_overlapFlagIsTrue() {
final WindowManager wm = mContext.getSystemService(WindowManager.class);
final Rect bounds = wm.getCurrentWindowMetrics().getBounds();
public void moveWindowMagnificationToTheBottom_enabledWithGestureInset_overlapFlagIsTrue() {
final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
final WindowInsets testInsets = new WindowInsets.Builder()
.setInsets(systemGestures(), Insets.of(0, 0, 0, 10))
.build();
mWindowManager.setWindowInsets(testInsets);
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
Float.NaN);