From 732aed15d7312768378356e50b5fc80366b5ff85 Mon Sep 17 00:00:00 2001 From: mincheli Date: Thu, 22 Apr 2021 13:42:47 +0800 Subject: [PATCH] Makes magnification switch UI never overlap navigationBar and statusBar This change contrains the x,y postion of switch button to make the button never overlap navigation bar window and status bar window. When the orientation is changed or navigation mode is change, the position of switch button should be ajusted by the draggable bounds because the window insets are updated. Bug: 185288922 Test: atest MagnificationModeSwitchTest; atest ModeSwitchesControllerTest; Change-Id: Idc03275f39418c18a190cdff6ffb0e94280c6281 --- packages/SystemUI/res/values/dimens.xml | 2 +- .../MagnificationModeSwitch.java | 123 ++++++++++++++---- .../MagnificationModeSwitchTest.java | 95 +++++++++++--- .../accessibility/TestableWindowManager.java | 109 ++++++++++++++++ .../WindowMagnificationControllerTest.java | 122 ++++------------- 5 files changed, 311 insertions(+), 140 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index e7d714e60076e..ac4d534f72a00 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1293,7 +1293,7 @@ 36dp 90dp 48dp - 6dp + 16dp 35dp 45dp 45dp diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java index 9f77b7d26c96c..1ffccb78102af 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java @@ -22,14 +22,17 @@ import android.annotation.NonNull; import android.annotation.UiContext; import android.content.Context; import android.content.pm.ActivityInfo; +import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.Bundle; import android.os.UserHandle; import android.provider.Settings; +import android.util.MathUtils; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; +import android.view.WindowInsets; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.view.accessibility.AccessibilityManager; @@ -38,6 +41,7 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.widget.ImageView; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.systemui.R; import java.util.Collections; @@ -45,8 +49,8 @@ import java.util.Collections; /** * Shows/hides a {@link android.widget.ImageView} on the screen and changes the values of * {@link Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE} when the UI is toggled. - * The button icon is movable by dragging. And the button UI would automatically be dismissed after - * displaying for a period of time. + * 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 { @@ -64,25 +68,29 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL private final AccessibilityManager mAccessibilityManager; private final WindowManager mWindowManager; private final ImageView mImageView; + private final Runnable mWindowInsetChangeRunnable; + private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider; private int mMagnificationMode = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; private final LayoutParams mParams; + @VisibleForTesting + final Rect mDraggableWindowBounds = new Rect(); private boolean mIsVisible = false; private final MagnificationGestureDetector mGestureDetector; private boolean mSingleTapDetected = false; MagnificationModeSwitch(@UiContext Context context) { - this(context, createView(context)); + this(context, createView(context), new SfVsyncFrameCallbackProvider()); } @VisibleForTesting - MagnificationModeSwitch(Context context, @NonNull ImageView imageView) { + MagnificationModeSwitch(Context context, @NonNull ImageView imageView, + SfVsyncFrameCallbackProvider sfVsyncFrameProvider) { mContext = context; mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); - mWindowManager = (WindowManager) mContext.getSystemService( - Context.WINDOW_SERVICE); + mWindowManager = mContext.getSystemService(WindowManager.class); + mSfVsyncFrameProvider = sfVsyncFrameProvider; mParams = createLayoutParams(context); mImageView = imageView; - applyResourcesValues(); mImageView.setOnTouchListener(this::onTouch); mImageView.setAccessibilityDelegate(new View.AccessibilityDelegate() { @Override @@ -107,6 +115,15 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL return super.performAccessibilityAction(host, action, args); } }); + mWindowInsetChangeRunnable = this::onWindowInsetChanged; + mImageView.setOnApplyWindowInsetsListener((v, insets) -> { + // Adds a pending post check to avoiding redundant calculation because this callback + // is sent frequently when the switch icon window dragged by the users. + if (!mImageView.getHandler().hasCallbacks(mWindowInsetChangeRunnable)) { + mImageView.getHandler().post(mWindowInsetChangeRunnable); + } + return v.onApplyWindowInsets(insets); + }); mFadeInAnimationTask = () -> { mImageView.animate() @@ -133,11 +150,16 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL return mContext.getResources().getString(stringId); } - private void applyResourcesValues() { - final int padding = mContext.getResources().getDimensionPixelSize( - R.dimen.magnification_switch_button_padding); - mImageView.setPadding(padding, padding, padding, padding); - mImageView.setImageResource(getIconResId(mMagnificationMode)); + private void applyResourcesValuesWithDensityChanged() { + final int size = mContext.getResources().getDimensionPixelSize( + R.dimen.magnification_switch_button_size); + mParams.height = size; + mParams.width = size; + if (mIsVisible) { + mWindowManager.updateViewLayout(mImageView, mParams); + // Exclude magnification switch button from system gesture area. + setSystemGestureExclusion(); + } } private boolean onTouch(View v, MotionEvent event) { @@ -176,9 +198,11 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL } private void moveButton(float offsetX, float offsetY) { - mParams.x -= offsetX; - mParams.y -= offsetY; - mWindowManager.updateViewLayout(mImageView, mParams); + mSfVsyncFrameProvider.postFrameCallback(l -> { + mParams.x += offsetX; + mParams.y += offsetY; + updateButtonViewLayoutIfNeeded(); + }); } void removeButton() { @@ -193,16 +217,31 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL mImageView.setAlpha(0f); mWindowManager.removeView(mImageView); mIsVisible = false; - mParams.x = 0; - mParams.y = 0; } void showButton(int mode) { + showButton(mode, true); + } + + /** + * Shows magnification switch button for the specified magnification mode. + * When the button is going to be visible by calling this method, the layout position can be + * reset depending on the flag. + * + * @param mode The magnification mode + * @param resetPosition if the button position needs be reset + */ + private void showButton(int mode, boolean resetPosition) { if (mMagnificationMode != mode) { mMagnificationMode = mode; mImageView.setImageResource(getIconResId(mode)); } if (!mIsVisible) { + if (resetPosition) { + mDraggableWindowBounds.set(getDraggableWindowBounds()); + mParams.x = mDraggableWindowBounds.right; + mParams.y = mDraggableWindowBounds.bottom; + } mWindowManager.addView(mImageView, mParams); // Exclude magnification switch button from system gesture area. setSystemGestureExclusion(); @@ -229,12 +268,7 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL void onConfigurationChanged(int configDiff) { if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) { - applyResourcesValues(); - if (mIsVisible) { - mWindowManager.updateViewLayout(mImageView, mParams); - // Exclude magnification switch button from system gesture area. - setSystemGestureExclusion(); - } + applyResourcesValuesWithDensityChanged(); return; } if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) { @@ -243,6 +277,25 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL } } + private void onWindowInsetChanged() { + final Rect newBounds = getDraggableWindowBounds(); + if (mDraggableWindowBounds.equals(newBounds)) { + return; + } + mDraggableWindowBounds.set(newBounds); + updateButtonViewLayoutIfNeeded(); + } + + private void updateButtonViewLayoutIfNeeded() { + if (mIsVisible) { + mParams.x = MathUtils.constrain(mParams.x, mDraggableWindowBounds.left, + mDraggableWindowBounds.right); + mParams.y = MathUtils.constrain(mParams.y, mDraggableWindowBounds.top, + mDraggableWindowBounds.bottom); + mWindowManager.updateViewLayout(mImageView, mParams); + } + } + private void updateAccessibilityWindowTitle() { mParams.accessibilityTitle = getAccessibilityWindowTitle(mContext); if (mIsVisible) { @@ -283,17 +336,34 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL } private static LayoutParams createLayoutParams(Context context) { + final int size = context.getResources().getDimensionPixelSize( + R.dimen.magnification_switch_button_size); final LayoutParams params = new LayoutParams( - LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT, + size, + size, LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT); - params.gravity = Gravity.BOTTOM | Gravity.RIGHT; + params.gravity = Gravity.TOP | Gravity.LEFT; params.accessibilityTitle = getAccessibilityWindowTitle(context); return params; } + private Rect getDraggableWindowBounds() { + final int layoutMargin = mContext.getResources().getDimensionPixelSize( + R.dimen.magnification_switch_button_margin); + final Rect boundRect = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds()); + final Insets systemBars = + mWindowManager.getCurrentWindowMetrics().getWindowInsets() + .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()); + final Rect insets = new Rect(layoutMargin, + systemBars.top + layoutMargin, + mParams.width + layoutMargin, + mParams.height + layoutMargin + systemBars.bottom); + boundRect.inset(insets); + return boundRect; + } + private static String getAccessibilityWindowTitle(Context context) { return context.getString(com.android.internal.R.string.android_system_label); } @@ -305,5 +375,4 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL new Rect(0, 0, mImageView.getWidth(), mImageView.getHeight()))); }); } - } 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 3d504fbefefe7..1d475cdd4ac6c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java @@ -22,6 +22,7 @@ import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_UP; +import static android.view.WindowInsets.Type.systemBars; import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK; import static com.android.systemui.accessibility.MagnificationModeSwitch.DEFAULT_FADE_OUT_ANIMATION_DELAY_MS; @@ -33,6 +34,7 @@ import static junit.framework.Assert.assertNotNull; import static org.hamcrest.CoreMatchers.hasItems; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -41,19 +43,27 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.content.pm.ActivityInfo; +import android.graphics.Insets; +import android.graphics.Rect; +import android.os.Handler; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.Choreographer; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewPropertyAnimator; +import android.view.WindowInsets; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; @@ -61,6 +71,7 @@ import android.widget.ImageView; import androidx.test.filters.SmallTest; +import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; @@ -77,6 +88,7 @@ import java.util.List; @SmallTest @RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper public class MagnificationModeSwitchTest extends SysuiTestCase { private static final float FADE_IN_ALPHA = 1f; @@ -86,7 +98,10 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { @Mock private AccessibilityManager mAccessibilityManager; @Mock - private WindowManager mWindowManager; + private SfVsyncFrameCallbackProvider mSfVsyncFrameProvider; + @Mock + private Handler mHandler; + private TestableWindowManager mWindowManager; private ViewPropertyAnimator mViewPropertyAnimator; private MagnificationModeSwitch mMagnificationModeSwitch; private View.OnTouchListener mTouchListener; @@ -96,10 +111,8 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - WindowManager wm = mContext.getSystemService(WindowManager.class); - doAnswer(invocation -> - wm.getMaximumWindowMetrics() - ).when(mWindowManager).getMaximumWindowMetrics(); + final WindowManager wm = mContext.getSystemService(WindowManager.class); + mWindowManager = spy(new TestableWindowManager(wm)); mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager); mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager); mSpyImageView = Mockito.spy(new ImageView(mContext)); @@ -110,7 +123,14 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { return null; }).when(mSpyImageView).setOnTouchListener( any(View.OnTouchListener.class)); - mMagnificationModeSwitch = new MagnificationModeSwitch(mContext, mSpyImageView); + doAnswer(invocation -> { + Choreographer.FrameCallback callback = invocation.getArgument(0); + callback.doFrame(0); + return null; + }).when(mSfVsyncFrameProvider).postFrameCallback( + any(Choreographer.FrameCallback.class)); + mMagnificationModeSwitch = new MagnificationModeSwitch(mContext, mSpyImageView, + mSfVsyncFrameProvider); assertNotNull(mTouchListener); } @@ -178,19 +198,41 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { } @Test - public void onConfigurationChanged_buttonIsShowing_updateResourcesAndLayout() { + public void onDensityChanged_buttonIsShowing_updateResourcesAndLayout() { mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); resetAndStubMockImageViewAndAnimator(); mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY); - verify(mSpyImageView).setPadding(anyInt(), anyInt(), anyInt(), anyInt()); - verify(mSpyImageView).setImageResource( - getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN)); verify(mWindowManager).updateViewLayout(eq(mSpyImageView), any()); verify(mSpyImageView).setSystemGestureExclusionRects(any(List.class)); } + @Test + public void onApplyWindowInsetsWithBoundsChange_buttonIsShowing_updateLayoutPosition() { + mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); + + mMagnificationModeSwitch.mDraggableWindowBounds.inset(10, 10); + mSpyImageView.onApplyWindowInsets(WindowInsets.CONSUMED); + + verify(mWindowManager).updateViewLayout(eq(mSpyImageView), + any(WindowManager.LayoutParams.class)); + assertLayoutPosition(); + } + + @Test + public void onApplyWindowInsetsWithWindowInsetsChange_buttonIsShowing_draggableBoundsChanged() { + mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); + final Rect oldDraggableBounds = new Rect(mMagnificationModeSwitch.mDraggableWindowBounds); + + mWindowManager.setWindowInsets(new WindowInsets.Builder() + .setInsetsIgnoringVisibility(systemBars(), Insets.of(0, 20, 0, 20)) + .build()); + mSpyImageView.onApplyWindowInsets(WindowInsets.CONSUMED); + + assertNotEquals(oldDraggableBounds, mMagnificationModeSwitch.mDraggableWindowBounds); + } + @Test public void performSingleTap_fullscreenMode_removeViewAndChangeSettingsValue() { mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); @@ -344,12 +386,12 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { public void showButton_hasAccessibilityWindowTitle() { mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); - ArgumentCaptor paramsArgumentCaptor = ArgumentCaptor.forClass( - WindowManager.LayoutParams.class); - verify(mWindowManager).addView(eq(mSpyImageView), paramsArgumentCaptor.capture()); + final WindowManager.LayoutParams layoutPrams = + mWindowManager.getLayoutParamsFromAttachedView(); + assertNotNull(layoutPrams); assertEquals(getContext().getResources().getString( com.android.internal.R.string.android_system_label), - paramsArgumentCaptor.getValue().accessibilityTitle); + layoutPrams.accessibilityTitle); } @Test @@ -361,10 +403,10 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { com.android.internal.R.string.android_system_label, newA11yWindowTitle); mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_LOCALE); - ArgumentCaptor paramsArgumentCaptor = ArgumentCaptor.forClass( - WindowManager.LayoutParams.class); - verify(mWindowManager).updateViewLayout(eq(mSpyImageView), paramsArgumentCaptor.capture()); - assertEquals(newA11yWindowTitle, paramsArgumentCaptor.getValue().accessibilityTitle); + final WindowManager.LayoutParams layoutParams = + mWindowManager.getLayoutParamsFromAttachedView(); + assertNotNull(layoutParams); + assertEquals(newA11yWindowTitle, layoutParams.accessibilityTitle); } private void assertModeUnchanged(int expectedMode) { @@ -392,6 +434,13 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { private void resetAndStubMockImageViewAndAnimator() { resetAndStubMockAnimator(); Mockito.reset(mSpyImageView); + final Handler handler = mock(Handler.class); + when(mSpyImageView.getHandler()).thenReturn(handler); + doAnswer(invocation -> { + final Runnable runnable = invocation.getArgument(0); + runnable.run(); + return null; + }).when(handler).post(any(Runnable.class)); doAnswer(invocation -> { final Runnable runnable = invocation.getArgument(0); runnable.run(); @@ -440,4 +489,14 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { mFadeOutAnimation.run(); mFadeOutAnimation = null; } + + private void assertLayoutPosition() { + final int expectedX = mMagnificationModeSwitch.mDraggableWindowBounds.right; + final int expectedY = mMagnificationModeSwitch.mDraggableWindowBounds.bottom; + final WindowManager.LayoutParams layoutParams = + mWindowManager.getLayoutParamsFromAttachedView(); + assertNotNull(layoutParams); + assertEquals(expectedX, layoutParams.x); + assertEquals(expectedY, layoutParams.y); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java new file mode 100644 index 0000000000000..4f095acd6e6bc --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2021 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 android.view.WindowInsets.Type.systemGestures; + +import android.graphics.Insets; +import android.graphics.Region; +import android.view.Display; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowInsets; +import android.view.WindowManager; +import android.view.WindowMetrics; + +public class TestableWindowManager implements WindowManager { + + private final WindowManager mWindowManager; + private View mView; + private WindowInsets mWindowInsets = null; + + TestableWindowManager(WindowManager windowManager) { + mWindowManager = windowManager; + } + + @Override + public Display getDefaultDisplay() { + return mWindowManager.getDefaultDisplay(); + } + + @Override + public void removeViewImmediate(View view) { + mWindowManager.removeViewImmediate(view); + } + + @Override + public void requestAppKeyboardShortcuts(WindowManager.KeyboardShortcutsReceiver receiver, + int deviceId) { + mWindowManager.requestAppKeyboardShortcuts(receiver, deviceId); + } + + @Override + public Region getCurrentImeTouchRegion() { + return mWindowManager.getCurrentImeTouchRegion(); + } + + @Override + public void addView(View view, ViewGroup.LayoutParams params) { + mView = view; + mWindowManager.addView(view, params); + } + + @Override + public void updateViewLayout(View view, ViewGroup.LayoutParams params) { + mWindowManager.updateViewLayout(view, params); + } + + @Override + public void removeView(View view) { + mView = null; + mWindowManager.removeView(view); + } + + @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 windowMetrics = new WindowMetrics( + mWindowManager.getCurrentWindowMetrics().getBounds(), + mWindowInsets == null ? insets : mWindowInsets); + return windowMetrics; + } + + @Override + public WindowMetrics getMaximumWindowMetrics() { + return mWindowManager.getMaximumWindowMetrics(); + } + + public View getAttachedView() { + return mView; + } + + public WindowManager.LayoutParams getLayoutParamsFromAttachedView() { + if (mView == null) { + return null; + } + return (WindowManager.LayoutParams) mView.getLayoutParams(); + } + + public void setWindowInsets(WindowInsets insets) { + mWindowInsets = insets; + } +} 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 b8734df678d60..5fa63bc3d0619 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java @@ -17,7 +17,6 @@ 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; @@ -46,9 +45,7 @@ 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.Rect; -import android.graphics.Region; import android.os.Handler; import android.os.SystemClock; import android.testing.AndroidTestingRunner; @@ -58,10 +55,7 @@ import android.view.Display; import android.view.Surface; import android.view.SurfaceControl; import android.view.View; -import android.view.ViewGroup; -import android.view.WindowInsets; import android.view.WindowManager; -import android.view.WindowMetrics; import android.view.accessibility.AccessibilityNodeInfo; import androidx.test.InstrumentationRegistry; @@ -96,14 +90,13 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { private MirrorWindowControl mMirrorWindowControl; @Mock private WindowMagnifierCallback mWindowMagnifierCallback; - @Mock (answer = Answers.RETURNS_DEEP_STUBS) + @Mock(answer = Answers.RETURNS_DEEP_STUBS) private SurfaceControl.Transaction mTransaction; - private WindowManager mWindowManager; + private TestableWindowManager mWindowManager; private SysUiState mSysUiState = new SysUiState(); private Resources mResources; private WindowMagnificationController mWindowMagnificationController; private Instrumentation mInstrumentation; - private View mMirrorView; @Before public void setUp() { @@ -157,7 +150,9 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { timeout(LAYOUT_CHANGE_TIMEOUT_MS)).onWindowMagnifierBoundsChanged( eq(mContext.getDisplayId()), boundsCaptor.capture()); final Rect actualBounds = new Rect(); - mMirrorView.getBoundsOnScreen(actualBounds); + final View mirrorView = mWindowManager.getAttachedView(); + assertNotNull(mirrorView); + mirrorView.getBoundsOnScreen(actualBounds); assertEquals(actualBounds, boundsCaptor.getValue()); } @@ -218,7 +213,9 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { ArgumentCaptor runnableArgumentCaptor = ArgumentCaptor.forClass(Runnable.class); verify(mHandler).postDelayed(runnableArgumentCaptor.capture(), anyLong()); runnableArgumentCaptor.getValue().run(); - assertThat(mMirrorView.getStateDescription().toString(), containsString("300")); + final View mirrorView = mWindowManager.getAttachedView(); + assertNotNull(mirrorView); + assertThat(mirrorView.getStateDescription().toString(), containsString("300")); } @Test @@ -300,10 +297,11 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { mWindowMagnificationController.enableWindowMagnification(2.5f, Float.NaN, Float.NaN); }); - assertNotNull(mMirrorView); + final View mirrorView = mWindowManager.getAttachedView(); + assertNotNull(mirrorView); final AccessibilityNodeInfo nodeInfo = new AccessibilityNodeInfo(); - mMirrorView.onInitializeAccessibilityNodeInfo(nodeInfo); + mirrorView.onInitializeAccessibilityNodeInfo(nodeInfo); assertNotNull(nodeInfo.getContentDescription()); assertThat(nodeInfo.getStateDescription().toString(), containsString("250")); @@ -323,24 +321,24 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { mWindowMagnificationController.enableWindowMagnification(2.5f, Float.NaN, Float.NaN); }); - assertNotNull(mMirrorView); + final View mirrorView = mWindowManager.getAttachedView(); assertTrue( - mMirrorView.performAccessibilityAction(R.id.accessibility_action_zoom_out, null)); + mirrorView.performAccessibilityAction(R.id.accessibility_action_zoom_out, null)); // Minimum scale is 2.0. verify(mWindowMagnifierCallback).onPerformScaleAction(eq(displayId), eq(2.0f)); - assertTrue(mMirrorView.performAccessibilityAction(R.id.accessibility_action_zoom_in, null)); + assertTrue(mirrorView.performAccessibilityAction(R.id.accessibility_action_zoom_in, null)); verify(mWindowMagnifierCallback).onPerformScaleAction(eq(displayId), eq(3.5f)); // TODO: Verify the final state when the mirror surface is visible. - assertTrue(mMirrorView.performAccessibilityAction(R.id.accessibility_action_move_up, null)); + assertTrue(mirrorView.performAccessibilityAction(R.id.accessibility_action_move_up, null)); assertTrue( - mMirrorView.performAccessibilityAction(R.id.accessibility_action_move_down, null)); + mirrorView.performAccessibilityAction(R.id.accessibility_action_move_down, null)); assertTrue( - mMirrorView.performAccessibilityAction(R.id.accessibility_action_move_right, null)); + mirrorView.performAccessibilityAction(R.id.accessibility_action_move_right, null)); assertTrue( - mMirrorView.performAccessibilityAction(R.id.accessibility_action_move_left, null)); + mirrorView.performAccessibilityAction(R.id.accessibility_action_move_left, null)); } @Test @@ -351,7 +349,8 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { Float.NaN); }); - mMirrorView.performAccessibilityAction(R.id.accessibility_action_move_up, null); + final View mirrorView = mWindowManager.getAttachedView(); + mirrorView.performAccessibilityAction(R.id.accessibility_action_move_up, null); verify(mWindowMagnifierCallback).onAccessibilityActionPerformed(eq(displayId)); } @@ -363,12 +362,8 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { Float.NaN); }); - ArgumentCaptor paramsArgumentCaptor = ArgumentCaptor.forClass( - WindowManager.LayoutParams.class); - verify(mWindowManager).addView(eq(mMirrorView), paramsArgumentCaptor.capture()); assertEquals(getContext().getResources().getString( - com.android.internal.R.string.android_system_label), - paramsArgumentCaptor.getValue().accessibilityTitle); + com.android.internal.R.string.android_system_label), getAccessibilityWindowTitle()); } @Test @@ -400,15 +395,15 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { mWindowMagnificationController.onSingleTap(); }); + final View mirrorView = mWindowManager.getAttachedView(); final long timeout = SystemClock.uptimeMillis() + 1000; while (SystemClock.uptimeMillis() < timeout) { SystemClock.sleep(10); - - if (Float.compare(1.0f, mMirrorView.getScaleX()) < 0) { + if (Float.compare(1.0f, mirrorView.getScaleX()) < 0) { return; } } - fail("mMirrorView scale is not changed"); + fail("MirrorView scale is not changed"); } @Test @@ -428,77 +423,16 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { } private CharSequence getAccessibilityWindowTitle() { - if (mMirrorView == null) { - return null; + final View mirrorView = mWindowManager.getAttachedView(); + if (mirrorView == null) { + return null; } WindowManager.LayoutParams layoutParams = - (WindowManager.LayoutParams) mMirrorView.getLayoutParams(); + (WindowManager.LayoutParams) mirrorView.getLayoutParams(); return layoutParams.accessibilityTitle; } private boolean hasMagnificationOverlapFlag() { return (mSysUiState.getFlags() & SYSUI_STATE_MAGNIFICATION_OVERLAP) != 0; } - - private class TestableWindowManager implements WindowManager { - - private final WindowManager mWindowManager; - - TestableWindowManager(WindowManager windowManager) { - mWindowManager = windowManager; - } - - @Override - public Display getDefaultDisplay() { - return mWindowManager.getDefaultDisplay(); - } - - @Override - public void removeViewImmediate(View view) { - mWindowManager.removeViewImmediate(view); - } - - @Override - public void requestAppKeyboardShortcuts(KeyboardShortcutsReceiver receiver, int deviceId) { - mWindowManager.requestAppKeyboardShortcuts(receiver, deviceId); - } - - @Override - public Region getCurrentImeTouchRegion() { - return mWindowManager.getCurrentImeTouchRegion(); - } - - @Override - public void addView(View view, ViewGroup.LayoutParams params) { - mMirrorView = view; - mWindowManager.addView(view, params); - } - - @Override - public void updateViewLayout(View view, ViewGroup.LayoutParams params) { - mWindowManager.updateViewLayout(view, params); - } - - @Override - public void removeView(View view) { - mMirrorView = null; - mWindowManager.removeView(view); - } - - @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 windowMetrics = new WindowMetrics( - mWindowManager.getCurrentWindowMetrics().getBounds(), insets); - return windowMetrics; - } - - @Override - public WindowMetrics getMaximumWindowMetrics() { - return mWindowManager.getMaximumWindowMetrics(); - } - } }