diff options
5 files changed, 213 insertions, 31 deletions
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index de8287e5e8cb..68fcdeacd87b 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1196,7 +1196,6 @@ <dimen name="magnification_window_drag_corner_stroke">3dp</dimen> <!-- The extra padding to show the whole outer border --> <dimen name="magnifier_drag_handle_padding">3dp</dimen> - <dimen name="magnification_max_frame_size">300dp</dimen> <!-- Magnification settings panel --> <dimen name="magnification_setting_view_margin">24dp</dimen> <dimen name="magnification_setting_text_size">18sp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java index 6c8f8f39646e..4a31f3d9cf90 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 @@ -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,8 +275,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 = restoreMagnificationWindowFrameSizeIfPossible(); + setMagnificationFrame(windowFrameSize.getWidth(), windowFrameSize.getHeight(), mWindowBounds.width() / 2, mWindowBounds.height() / 2); computeBounceAnimationScale(); @@ -381,12 +384,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(); @@ -395,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) { @@ -519,12 +532,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold return false; } mWindowBounds.set(currentWindowBounds); - final Size windowSize = getDefaultWindowSizeWithWindowBounds(mWindowBounds); + final Size windowFrameSize = restoreMagnificationWindowFrameSizeIfPossible(); 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; } @@ -738,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; @@ -745,12 +760,18 @@ 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 restoreMagnificationWindowFrameSizeIfPossible() { + if (!mWindowMagnificationSizePrefs.isPreferenceSavedForCurrentDensity()) { + return getDefaultMagnificationWindowFrameSize(); + } + + return mWindowMagnificationSizePrefs.getSizeForCurrentDensity(); + } + + private Size getDefaultMagnificationWindowFrameSize() { + final int defaultSize = getMagnificationWindowSizeFromIndex(MagnificationSize.MEDIUM) + - 2 * mMirrorSurfaceMargin; + return new Size(defaultSize, defaultSize); } /** 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 000000000000..4d7ad2647c1f --- /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 11ad20672100..a48fa5da1970 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; @@ -100,6 +101,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 +315,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(() -> { @@ -543,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(() -> { @@ -568,26 +575,49 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { mWindowMagnificationController.getCenterY() / testWindowBounds.height(), 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_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; + // Screen size and density change + mContext.getResources().getConfiguration().smallestScreenWidthDp = + mContext.getResources().getConfiguration().smallestScreenWidthDp * 2; 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 @@ -1136,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 000000000000..04b0d7085115 --- /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(); + } +} |