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();
- }
- }
}