From 3c79503330d4ae12c74746e471c141e24923ac2b Mon Sep 17 00:00:00 2001 From: Candice Lo Date: Wed, 14 Jun 2023 09:23:15 +0000 Subject: [PATCH 1/2] Match default magnifier window size to Medium in settings We would like to initialize the magnifier to be Medium size, which is one of the sizes that provided through magnification settings panel icon buttons, so that users could get back to the initial window size easily. Since we are following the sizes provided by the settings panel, we will need to rethink if those provided sizes are appropriate and useful for users with different screen sizes. We would like to deal with the issue in a separate bug. Bug: 265363901 Test: manually - check the magnifier is initialized to be Medium size Test: atest WindowMagnificationControllerTest Change-Id: I37762e002cb766b06f99817c87a25c9539faed6d --- packages/SystemUI/res/values/dimens.xml | 1 - .../WindowMagnificationController.java | 32 ++++++++++--------- .../WindowMagnificationControllerTest.java | 22 +++++++------ 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 5a15dcec52233..fd5416efd0ca5 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1188,7 +1188,6 @@ 3dp 3dp - 300dp 24dp 18sp diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java index 6c8f8f39646e1..197aa90723cb1 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java @@ -124,7 +124,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold private float mScale; /** - * MagnificationFrame represents the bound of {@link #mMirrorSurface} and is constrained + * MagnificationFrame represents the bound of {@link #mMirrorSurfaceView} and is constrained * by the {@link #mMagnificationFrameBoundary}. * We use MagnificationFrame to calculate the position of {@link #mMirrorView}. * We combine MagnificationFrame with {@link #mMagnificationFrameOffsetX} and @@ -272,8 +272,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold com.android.internal.R.integer.config_shortAnimTime); updateDimensions(); - final Size windowSize = getDefaultWindowSizeWithWindowBounds(mWindowBounds); - setMagnificationFrame(windowSize.getWidth(), windowSize.getHeight(), + final Size windowFrameSize = getDefaultMagnificationWindowFrameSize(); + setMagnificationFrame(windowFrameSize.getWidth(), windowFrameSize.getHeight(), mWindowBounds.width() / 2, mWindowBounds.height() / 2); computeBounceAnimationScale(); @@ -381,12 +381,16 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold if (!mMagnificationSizeScaleOptions.contains(index)) { return; } - final float scale = mMagnificationSizeScaleOptions.get(index, 1.0f); - final int initSize = Math.min(mWindowBounds.width(), mWindowBounds.height()) / 3; - int size = (int) (initSize * scale); + int size = getMagnificationWindowSizeFromIndex(index); setWindowSize(size, size); } + int getMagnificationWindowSizeFromIndex(@MagnificationSize int index) { + final float scale = mMagnificationSizeScaleOptions.get(index, 1.0f); + int initSize = Math.min(mWindowBounds.width(), mWindowBounds.height()) / 3; + return (int) (initSize * scale) - (int) (initSize * scale) % 2; + } + void setEditMagnifierSizeMode(boolean enable) { mEditSizeEnable = enable; applyResourcesValues(); @@ -519,12 +523,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold return false; } mWindowBounds.set(currentWindowBounds); - final Size windowSize = getDefaultWindowSizeWithWindowBounds(mWindowBounds); + final Size windowFrameSize = getDefaultMagnificationWindowFrameSize(); final float newCenterX = (getCenterX()) * mWindowBounds.width() / oldWindowBounds.width(); final float newCenterY = (getCenterY()) * mWindowBounds.height() / oldWindowBounds.height(); - setMagnificationFrame(windowSize.getWidth(), windowSize.getHeight(), (int) newCenterX, - (int) newCenterY); + setMagnificationFrame(windowFrameSize.getWidth(), windowFrameSize.getHeight(), + (int) newCenterX, (int) newCenterY); calculateMagnificationFrameBoundary(); return true; } @@ -745,12 +749,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold 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; - return new Size(initSize, initSize); + private Size getDefaultMagnificationWindowFrameSize() { + final int defaultSize = getMagnificationWindowSizeFromIndex(MagnificationSize.MEDIUM) + - 2 * mMirrorSurfaceMargin; + return new Size(defaultSize, defaultSize); } /** 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 36cdfe642874f..670ed400681b6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java @@ -100,6 +100,7 @@ import com.google.common.util.concurrent.AtomicDouble; import org.junit.After; import org.junit.Assume; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; @@ -313,10 +314,10 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { assertFalse(rects.isEmpty()); } + @Ignore("The default window size should be constrained after fixing b/288056772") @Test public void enableWindowMagnification_LargeScreen_windowSizeIsConstrained() { - final int screenSize = mContext.getResources().getDimensionPixelSize( - R.dimen.magnification_max_frame_size) * 10; + final int screenSize = mWindowManager.getCurrentWindowMetrics().getBounds().width() * 10; mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize)); mInstrumentation.runOnMainSync(() -> { @@ -568,26 +569,27 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { mWindowMagnificationController.getCenterY() / testWindowBounds.height(), 0); } + @Test - public void screenSizeIsChangedToLarge_enabled_windowSizeIsConstrained() { + public void screenSizeIsChangedToLarge_enabled_defaultWindowSize() { mInstrumentation.runOnMainSync(() -> { mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN); }); - final int screenSize = mContext.getResources().getDimensionPixelSize( - R.dimen.magnification_max_frame_size) * 10; + final int screenSize = mWindowManager.getCurrentWindowMetrics().getBounds().width() * 10; mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize)); mInstrumentation.runOnMainSync(() -> { mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_SCREEN_SIZE); }); - final int halfScreenSize = screenSize / 2; + final int defaultWindowSize = + mWindowMagnificationController.getMagnificationWindowSizeFromIndex( + WindowMagnificationSettings.MagnificationSize.MEDIUM); WindowManager.LayoutParams params = mWindowManager.getLayoutParamsFromAttachedView(); - // The frame size should be the half of smaller value of window height/width unless it - //exceed the max frame size. - assertTrue(params.width < halfScreenSize); - assertTrue(params.height < halfScreenSize); + + assertTrue(params.width == defaultWindowSize); + assertTrue(params.height == defaultWindowSize); } @Test From b4a82ddb2df47c80f9632c3bc1b79013131dec0d Mon Sep 17 00:00:00 2001 From: Candice Lo Date: Thu, 13 Jul 2023 07:00:26 +0000 Subject: [PATCH 2/2] Keeping the magnifier window size in SharedPreference Using the smallest width dp as the key to save magnifier window's width and height. If no corresponding saved window size is found, use the Medium size provided by the settings panel button to be the default magnifier size. Bug: 265363901 Bug: 283019152 Test: atest WindowMagnificationControllerTest Test: atest WindowMagnificationSizePrefsTest Test: manually - test window size is restored after the device restarts Change-Id: Id35c2ff394c9a4907240833f3d43b0d412ef6caf --- .../WindowMagnificationController.java | 23 +++++- .../WindowMagnificationSizePrefs.java | 71 +++++++++++++++++++ .../WindowMagnificationControllerTest.java | 43 +++++++++-- .../WindowMagnificationSizePrefsTest.java | 56 +++++++++++++++ 4 files changed, 186 insertions(+), 7 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSizePrefs.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSizePrefsTest.java diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java index 197aa90723cb1..4a31f3d9cf908 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java @@ -225,6 +225,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold private boolean mAllowDiagonalScrolling = false; private boolean mEditSizeEnable = false; private boolean mSettingsPanelVisibility = false; + @VisibleForTesting + WindowMagnificationSizePrefs mWindowMagnificationSizePrefs; @Nullable private final MirrorWindowControl mMirrorWindowControl; @@ -249,6 +251,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold mWindowMagnifierCallback = callback; mSysUiState = sysUiState; mConfiguration = new Configuration(context.getResources().getConfiguration()); + mWindowMagnificationSizePrefs = new WindowMagnificationSizePrefs(mContext); final Display display = mContext.getDisplay(); mDisplayId = mContext.getDisplayId(); @@ -272,7 +275,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold com.android.internal.R.integer.config_shortAnimTime); updateDimensions(); - final Size windowFrameSize = getDefaultMagnificationWindowFrameSize(); + final Size windowFrameSize = restoreMagnificationWindowFrameSizeIfPossible(); setMagnificationFrame(windowFrameSize.getWidth(), windowFrameSize.getHeight(), mWindowBounds.width() / 2, mWindowBounds.height() / 2); computeBounceAnimationScale(); @@ -399,6 +402,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold updateDimensions(); applyTapExcludeRegion(); } + + if (!enable) { + // Keep the magnifier size when exiting edit mode + mWindowMagnificationSizePrefs.saveSizeForCurrentDensity( + new Size(mMagnificationFrame.width(), mMagnificationFrame.height())); + } } void setDiagonalScrolling(boolean enable) { @@ -523,7 +532,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold return false; } mWindowBounds.set(currentWindowBounds); - final Size windowFrameSize = getDefaultMagnificationWindowFrameSize(); + final Size windowFrameSize = restoreMagnificationWindowFrameSizeIfPossible(); final float newCenterX = (getCenterX()) * mWindowBounds.width() / oldWindowBounds.width(); final float newCenterY = (getCenterY()) * mWindowBounds.height() / oldWindowBounds.height(); @@ -742,6 +751,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold } private void setMagnificationFrame(int width, int height, int centerX, int centerY) { + mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(new Size(width, height)); + // Sets the initial frame area for the mirror and place it to the given center on the // display. final int initX = centerX - width / 2; @@ -749,6 +760,14 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold mMagnificationFrame.set(initX, initY, initX + width, initY + height); } + private Size restoreMagnificationWindowFrameSizeIfPossible() { + if (!mWindowMagnificationSizePrefs.isPreferenceSavedForCurrentDensity()) { + return getDefaultMagnificationWindowFrameSize(); + } + + return mWindowMagnificationSizePrefs.getSizeForCurrentDensity(); + } + private Size getDefaultMagnificationWindowFrameSize() { final int defaultSize = getMagnificationWindowSizeFromIndex(MagnificationSize.MEDIUM) - 2 * mMirrorSurfaceMargin; diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSizePrefs.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSizePrefs.java new file mode 100644 index 0000000000000..4d7ad2647c1f4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSizePrefs.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Size; + +/** + * Class to handle SharedPreference for window magnification size. + */ +public final class WindowMagnificationSizePrefs { + + private static final String WINDOW_MAGNIFICATION_PREFERENCES = + "window_magnification_preferences"; + Context mContext; + SharedPreferences mWindowMagnificationSizePreferences; + + public WindowMagnificationSizePrefs(Context context) { + mContext = context; + mWindowMagnificationSizePreferences = mContext + .getSharedPreferences(WINDOW_MAGNIFICATION_PREFERENCES, Context.MODE_PRIVATE); + } + + /** + * Uses smallest screen width DP as the key for preference. + */ + private String getKey() { + return String.valueOf( + mContext.getResources().getConfiguration().smallestScreenWidthDp); + } + + /** + * Saves the window frame size for current screen density. + */ + public void saveSizeForCurrentDensity(Size size) { + mWindowMagnificationSizePreferences.edit() + .putString(getKey(), size.toString()).apply(); + } + + /** + * Check if there is a preference saved for current screen density. + * + * @return true if there is a preference saved for current screen density, false if it is unset. + */ + public boolean isPreferenceSavedForCurrentDensity() { + return mWindowMagnificationSizePreferences.contains(getKey()); + } + + /** + * Gets the size preference for current screen density. + */ + public Size getSizeForCurrentDensity() { + return Size.parseSize(mWindowMagnificationSizePreferences.getString(getKey(), null)); + } + +} 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 670ed400681b6..f1615c86d7892 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java @@ -71,6 +71,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableResources; import android.text.TextUtils; +import android.util.Size; import android.view.Display; import android.view.IWindowSession; import android.view.MotionEvent; @@ -544,17 +545,22 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { } @Test - public void onScreenSizeChanged_enabledAtTheCenterOfScreen_keepSameWindowSizeRatio() { + public void onScreenSizeAndDensityChanged_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.enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN); }); + + // Screen size and density change + mContext.getResources().getConfiguration().smallestScreenWidthDp = + mContext.getResources().getConfiguration().smallestScreenWidthDp * 2; + final Rect testWindowBounds = new Rect( + mWindowManager.getCurrentWindowMetrics().getBounds()); + testWindowBounds.set(testWindowBounds.left, testWindowBounds.top, + testWindowBounds.right + 100, testWindowBounds.bottom + 100); mWindowManager.setWindowBounds(testWindowBounds); mInstrumentation.runOnMainSync(() -> { @@ -570,6 +576,25 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { 0); } + @Test + public void onScreenChangedToSavedDensity_enabled_restoreSavedMagnifierWindow() { + mContext.getResources().getConfiguration().smallestScreenWidthDp = + mContext.getResources().getConfiguration().smallestScreenWidthDp * 2; + int windowFrameSize = mResources.getDimensionPixelSize( + com.android.internal.R.dimen.accessibility_window_magnifier_min_size); + mWindowMagnificationController.mWindowMagnificationSizePrefs.saveSizeForCurrentDensity( + new Size(windowFrameSize, windowFrameSize)); + + mInstrumentation.runOnMainSync(() -> { + mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN, + Float.NaN); + }); + + WindowManager.LayoutParams params = mWindowManager.getLayoutParamsFromAttachedView(); + assertTrue(params.width == windowFrameSize); + assertTrue(params.height == windowFrameSize); + } + @Test public void screenSizeIsChangedToLarge_enabled_defaultWindowSize() { mInstrumentation.runOnMainSync(() -> { @@ -577,6 +602,9 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { Float.NaN); }); final int screenSize = mWindowManager.getCurrentWindowMetrics().getBounds().width() * 10; + // Screen size and density change + mContext.getResources().getConfiguration().smallestScreenWidthDp = + mContext.getResources().getConfiguration().smallestScreenWidthDp * 2; mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize)); mInstrumentation.runOnMainSync(() -> { @@ -1138,6 +1166,11 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { mWindowManager.setWindowInsets(testInsets); } + private int updateMirrorSurfaceMarginDimension() { + return mContext.getResources().getDimensionPixelSize( + R.dimen.magnification_mirror_surface_margin); + } + @Surface.Rotation private int simulateRotateTheDevice() { final Display display = Mockito.spy(mContext.getDisplay()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSizePrefsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSizePrefsTest.java new file mode 100644 index 0000000000000..04b0d70851157 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSizePrefsTest.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility; + +import static com.google.common.truth.Truth.assertThat; + +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.util.Size; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class WindowMagnificationSizePrefsTest extends SysuiTestCase { + + WindowMagnificationSizePrefs mWindowMagnificationSizePrefs = + new WindowMagnificationSizePrefs(mContext); + + @Test + public void saveSizeForCurrentDensity_getExpectedSize() { + Size testSize = new Size(500, 500); + mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(testSize); + + assertThat(mWindowMagnificationSizePrefs.getSizeForCurrentDensity()) + .isEqualTo(testSize); + } + + @Test + public void saveSizeForCurrentDensity_containsPreferenceForCurrentDensity() { + Size testSize = new Size(500, 500); + mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(testSize); + + assertThat(mWindowMagnificationSizePrefs.isPreferenceSavedForCurrentDensity()) + .isTrue(); + } +}