From e216d2dff090635afcc8474c7ebb3ac313beb5ef Mon Sep 17 00:00:00 2001 From: ryanlwlin Date: Mon, 17 Jan 2022 11:46:15 +0800 Subject: [PATCH] Fix incorrect magnification window size when the dvice is folded When the foldable is folded /unfolded, we will refetch the display size to compute the appropriate the window size. The signal of display size changed is from onConfigurationChanged which is invoked by Application context. However, we get the display size from the WindowContxt. To fix it, we register the callback with the WindowContext based on the view visiblty, and update the configuration related values before showing the window. Test: manual test atest com.android.systemui.accessibility Bug: 213958569 Bug: 214318642 Change-Id: Ic98f782f98b9c29f58d08e064985da731e13aa93 --- .../MagnificationModeSwitch.java | 24 ++++++- .../accessibility/WindowMagnification.java | 15 ----- .../WindowMagnificationController.java | 27 +++++++- .../MagnificationModeSwitchTest.java | 12 +++- .../ModeSwitchesControllerTest.java | 1 - .../WindowMagnificationControllerTest.java | 65 ++++++++++++++----- .../WindowMagnificationTest.java | 10 --- 7 files changed, 106 insertions(+), 48 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java index 052ec86d83985..dbd215d9c7134 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java @@ -22,8 +22,10 @@ import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_M import android.annotation.NonNull; import android.annotation.UiContext; +import android.content.ComponentCallbacks; import android.content.Context; import android.content.pm.ActivityInfo; +import android.content.res.Configuration; import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; @@ -54,7 +56,8 @@ import java.util.Collections; * The button icon is movable by dragging and it would not overlap navigation bar window. * And the button UI would automatically be dismissed after displaying for a period of time. */ -class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureListener { +class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureListener, + ComponentCallbacks { @VisibleForTesting static final long FADING_ANIMATION_DURATION_MS = 300; @@ -75,6 +78,7 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL private int mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_NONE; private final LayoutParams mParams; private final SwitchListener mSwitchListener; + private final Configuration mConfiguration; @VisibleForTesting final Rect mDraggableWindowBounds = new Rect(); private boolean mIsVisible = false; @@ -101,6 +105,7 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL MagnificationModeSwitch(Context context, @NonNull ImageView imageView, SfVsyncFrameCallbackProvider sfVsyncFrameProvider, SwitchListener switchListener) { mContext = context; + mConfiguration = new Configuration(context.getResources().getConfiguration()); mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); mWindowManager = mContext.getSystemService(WindowManager.class); mSfVsyncFrameProvider = sfVsyncFrameProvider; @@ -270,6 +275,7 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL mIsFadeOutAnimating = false; mImageView.setAlpha(0f); mWindowManager.removeView(mImageView); + mContext.unregisterComponentCallbacks(this); mIsVisible = false; } @@ -291,6 +297,8 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL mImageView.setImageResource(getIconResId(mode)); } if (!mIsVisible) { + onConfigurationChanged(mContext.getResources().getConfiguration()); + mContext.registerComponentCallbacks(this); if (resetPosition) { mDraggableWindowBounds.set(getDraggableWindowBounds()); mParams.x = mDraggableWindowBounds.right; @@ -321,7 +329,21 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL } } + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + final int configDiff = newConfig.diff(mConfiguration); + mConfiguration.setTo(newConfig); + onConfigurationChanged(configDiff); + } + + @Override + public void onLowMemory() { + } + void onConfigurationChanged(int configDiff) { + if (configDiff == 0) { + return; + } if ((configDiff & (ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE)) != 0) { final Rect previousDraggableBounds = new Rect(mDraggableWindowBounds); diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java index 4784bc12099b2..885a1777f30b2 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java @@ -23,7 +23,6 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_M import android.annotation.MainThread; import android.annotation.Nullable; import android.content.Context; -import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.os.Handler; @@ -65,7 +64,6 @@ public class WindowMagnification extends CoreStartable implements WindowMagnifie private final OverviewProxyService mOverviewProxyService; private WindowMagnificationConnectionImpl mWindowMagnificationConnectionImpl; - private Configuration mLastConfiguration; private SysUiState mSysUiState; private static class ControllerSupplier extends @@ -107,7 +105,6 @@ public class WindowMagnification extends CoreStartable implements WindowMagnifie SysUiState sysUiState, OverviewProxyService overviewProxyService) { super(context); mHandler = mainHandler; - mLastConfiguration = new Configuration(context.getResources().getConfiguration()); mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); mCommandQueue = commandQueue; mModeSwitchesController = modeSwitchesController; @@ -117,18 +114,6 @@ public class WindowMagnification extends CoreStartable implements WindowMagnifie mHandler, this, context.getSystemService(DisplayManager.class), sysUiState); } - @Override - public void onConfigurationChanged(Configuration newConfig) { - final int configDiff = newConfig.diff(mLastConfiguration); - mLastConfiguration.setTo(newConfig); - mMagnificationControllerSupplier.forEach( - magnificationController -> magnificationController.onConfigurationChanged( - configDiff)); - if (mModeSwitchesController != null) { - mModeSwitchesController.onConfigurationChanged(configDiff); - } - } - @Override public void start() { mCommandQueue.addCallback(this); diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java index aa1a43397f659..0d20403b08f2e 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java @@ -26,6 +26,7 @@ import android.animation.PropertyValuesHolder; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UiContext; +import android.content.ComponentCallbacks; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -76,7 +77,8 @@ import java.util.Locale; * Class to handle adding and removing a window magnification. */ class WindowMagnificationController implements View.OnTouchListener, SurfaceHolder.Callback, - MirrorWindowControl.MirrorWindowDelegate, MagnificationGestureDetector.OnGestureListener { + MirrorWindowControl.MirrorWindowDelegate, MagnificationGestureDetector.OnGestureListener, + ComponentCallbacks { private static final String TAG = "WindowMagnificationController"; @SuppressWarnings("isloggabletaglength") @@ -143,6 +145,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold private View mTopDrag; private View mRightDrag; private View mBottomDrag; + private final Configuration mConfiguration; @NonNull private final WindowMagnifierCallback mWindowMagnifierCallback; @@ -191,6 +194,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold mSfVsyncFrameProvider = sfVsyncFrameProvider; mWindowMagnifierCallback = callback; mSysUiState = sysUiState; + mConfiguration = new Configuration(context.getResources().getConfiguration()); final Display display = mContext.getDisplay(); mDisplayId = mContext.getDisplayId(); @@ -339,6 +343,18 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold } mMirrorViewBounds.setEmpty(); updateSystemUIStateIfNeeded(); + mContext.unregisterComponentCallbacks(this); + } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + final int configDiff = newConfig.diff(mConfiguration); + mConfiguration.setTo(newConfig); + onConfigurationChanged(configDiff); + } + + @Override + public void onLowMemory() { } /** @@ -351,6 +367,9 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold Log.d(TAG, "onConfigurationChanged = " + Configuration.configurationDiffToString( configDiff)); } + if (configDiff == 0) { + return; + } if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) { onRotate(); } @@ -390,7 +409,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold if (currentWindowBounds.equals(oldWindowBounds)) { if (DEBUG) { - Log.d(TAG, "updateMagnificationFrame -- window bounds is not changed"); + Log.d(TAG, "handleScreenSizeChanged -- window bounds is not changed"); } return false; } @@ -851,6 +870,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold deleteWindowMagnification(); return; } + if (!isWindowVisible()) { + onConfigurationChanged(mResources.getConfiguration()); + mContext.registerComponentCallbacks(this); + } mMagnificationFrameOffsetX = Float.isNaN(magnificationFrameOffsetRatioX) ? mMagnificationFrameOffsetX diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java index 6ddfbb2f430f6..bc89da7d504c5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java @@ -111,6 +111,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + mContext = Mockito.spy(getContext()); final WindowManager wm = mContext.getSystemService(WindowManager.class); mSwitchListener = new SwitchListenerStub(); mWindowManager = spy(new TestableWindowManager(wm)); @@ -139,16 +140,18 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { public void tearDown() { mFadeOutAnimation = null; mMotionEventHelper.recycleEvents(); + mMagnificationModeSwitch.removeButton(); } @Test - public void removeButton_buttonIsShowing_removeView() { + public void removeButton_buttonIsShowing_removeViewAndUnregisterComponentCallbacks() { mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); mMagnificationModeSwitch.removeButton(); verify(mWindowManager).removeView(mSpyImageView); verify(mViewPropertyAnimator).cancel(); + verify(mContext).unregisterComponentCallbacks(mMagnificationModeSwitch); } @Test @@ -463,6 +466,13 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { layoutPrams.accessibilityTitle); } + @Test + public void showButton_registerComponentCallbacks() { + mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); + + verify(mContext).registerComponentCallbacks(mMagnificationModeSwitch); + } + @Test public void onLocaleChanged_buttonIsShowing_updateA11yWindowTitle() { final String newA11yWindowTitle = "new a11y window title"; diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java index 216f63fce8858..a56218b082242 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java @@ -91,7 +91,6 @@ public class ModeSwitchesControllerTest extends SysuiTestCase { verify(mModeSwitch).onConfigurationChanged(ActivityInfo.CONFIG_DENSITY); } - @Test public void testOnSwitchClick_showWindowModeButton_invokeListener() { mModeSwitchesController.showButton(Display.DEFAULT_DISPLAY, diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java index 5ad651728c66a..dcb7307250fe2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java @@ -16,6 +16,8 @@ package com.android.systemui.accessibility; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.Choreographer.FrameCallback; import static android.view.WindowInsets.Type.systemGestures; import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; @@ -45,6 +47,7 @@ import static org.mockito.Mockito.when; import android.app.Instrumentation; 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.PointF; @@ -223,13 +226,9 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { final int screenSize = mContext.getResources().getDimensionPixelSize( R.dimen.magnification_max_frame_size) * 10; mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize)); - //We need to initialize new one because the window size is determined when initialization. - final WindowMagnificationController controller = new WindowMagnificationController(mContext, - mHandler, mWindowMagnificationAnimationController, mSfVsyncFrameProvider, - mMirrorWindowControl, mTransaction, mWindowMagnifierCallback, mSysUiState); mInstrumentation.runOnMainSync(() -> { - controller.enableWindowMagnificationInternal(Float.NaN, Float.NaN, + mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN); }); @@ -242,17 +241,17 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { } @Test - public void deleteWindowMagnification_destroyControl() { - mInstrumentation.runOnMainSync(() -> { - mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN, - Float.NaN); - }); + public void deleteWindowMagnification_destroyControlAndUnregisterComponentCallback() { + mInstrumentation.runOnMainSync( + () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, + Float.NaN, + Float.NaN)); - mInstrumentation.runOnMainSync(() -> { - mWindowMagnificationController.deleteWindowMagnification(); - }); + mInstrumentation.runOnMainSync( + () -> mWindowMagnificationController.deleteWindowMagnification()); verify(mMirrorWindowControl).destroyControl(); + verify(mContext).unregisterComponentCallbacks(mWindowMagnificationController); } @Test @@ -322,11 +321,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { @Test public void onOrientationChanged_enabled_updateDisplayRotationAndCenterStayAtSamePosition() { - final Display display = Mockito.spy(mContext.getDisplay()); - final int currentRotation = display.getRotation(); - final int newRotation = (currentRotation + 1) % 4; - when(display.getRotation()).thenReturn(newRotation); - when(mContext.getDisplay()).thenReturn(display); + final int newRotation = simulateRotateTheDevice(); final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds()); final float center = Math.min(windowBounds.exactCenterX(), windowBounds.exactCenterY()); final float displayWidth = windowBounds.width(); @@ -534,6 +529,30 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { assertEquals(Float.NaN, mWindowMagnificationController.getScale(), 0); } + @Test + public void enableWindowMagnification_rotationIsChanged_updateRotationValue() { + final Configuration config = mContext.getResources().getConfiguration(); + config.orientation = config.orientation == ORIENTATION_LANDSCAPE ? ORIENTATION_PORTRAIT + : ORIENTATION_LANDSCAPE; + final int newRotation = simulateRotateTheDevice(); + + mInstrumentation.runOnMainSync( + () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, + Float.NaN, Float.NaN)); + + assertEquals(newRotation, mWindowMagnificationController.mRotation); + } + + @Test + public void enableWindowMagnification_registerComponentCallback() { + mInstrumentation.runOnMainSync( + () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, + Float.NaN, + Float.NaN)); + + verify(mContext).registerComponentCallbacks(mWindowMagnificationController); + } + @Test public void onLocaleChanged_enabled_updateA11yWindowTitle() { final String newA11yWindowTitle = "new a11y window title"; @@ -610,4 +629,14 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { .build(); mWindowManager.setWindowInsets(testInsets); } + + @Surface.Rotation + private int simulateRotateTheDevice() { + final Display display = Mockito.spy(mContext.getDisplay()); + final int currentRotation = display.getRotation(); + final int newRotation = (currentRotation + 1) % 4; + when(display.getRotation()).thenReturn(newRotation); + when(mContext.getDisplay()).thenReturn(display); + return newRotation; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java index 343658d312729..d3f30c508b8ba 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java @@ -30,7 +30,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.os.RemoteException; @@ -158,15 +157,6 @@ public class WindowMagnificationTest extends SysuiTestCase { verify(mConnectionCallback).onDrag(TEST_DISPLAY); } - @Test - public void onConfigurationChanged_updateModeSwitches() { - final Configuration config = new Configuration(); - config.densityDpi = Configuration.DENSITY_DPI_ANY; - mWindowMagnification.onConfigurationChanged(config); - - verify(mModeSwitchesController).onConfigurationChanged(anyInt()); - } - @Test public void overviewProxyIsConnected_noController_resetFlag() { mOverviewProxyListener.onConnectionChanged(true);