Refactor the design and improve the animations of Accessibility Floating Menu(4/n).

Actions of this change:
1) Add default or restore values for the start position.
2) Customize the available bounds of the accessibility floating menu depending on the floating menu bounds, margin, and the window insets of the navigation bars, status bars, and display cutout.
3) Apply view-based animations for translation.
4) Exclude the system gestures area and customize the touch region to avoid it conflict with the floating menu and block the touch events.

Bug: 227715451
Test: atest MenuViewLayerTest MenuAnimationControllerTest MenuContainerViewTest MenuInfoRepositoryTest
Change-Id: I809702556308014cfebb5f71d0ef7219027bbb33
This commit is contained in:
Peter Liang
2022-08-29 15:55:06 +08:00
parent 24c1470c9e
commit a8fecd7eb5
12 changed files with 349 additions and 17 deletions

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2022 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.floatingmenu;
import android.graphics.PointF;
import androidx.dynamicanimation.animation.DynamicAnimation;
/**
* Controls the interaction animations of the menu view {@link MenuView}.
*/
class MenuAnimationController {
private final MenuView mMenuView;
MenuAnimationController(MenuView menuView) {
mMenuView = menuView;
}
void moveToPosition(PointF position) {
DynamicAnimation.TRANSLATION_X.setValue(mMenuView, position.x);
DynamicAnimation.TRANSLATION_Y.setValue(mMenuView, position.y);
mMenuView.onBoundsInParentChanged((int) position.x, (int) position.y);
}
}

View File

@@ -23,15 +23,18 @@ import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTT
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
import static com.android.systemui.accessibility.floatingmenu.MenuViewAppearance.MenuSizeType.SMALL;
import android.annotation.FloatRange;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import com.android.internal.accessibility.dialog.AccessibilityTarget;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Prefs;
import java.util.List;
@@ -39,9 +42,16 @@ import java.util.List;
* Stores and observe the settings contents for the menu view.
*/
class MenuInfoRepository {
@FloatRange(from = 0.0, to = 1.0)
private static final float DEFAULT_MENU_POSITION_X_PERCENT = 1.0f;
@FloatRange(from = 0.0, to = 1.0)
private static final float DEFAULT_MENU_POSITION_Y_PERCENT = 0.9f;
private final Context mContext;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final OnSettingsContentsChanged mSettingsContentsCallback;
private Position mPercentagePosition;
private final ContentObserver mMenuTargetFeaturesContentObserver =
new ContentObserver(mHandler) {
@@ -65,6 +75,12 @@ class MenuInfoRepository {
MenuInfoRepository(Context context, OnSettingsContentsChanged settingsContentsChanged) {
mContext = context;
mSettingsContentsCallback = settingsContentsChanged;
mPercentagePosition = getStartPosition();
}
void loadMenuPosition(OnInfoReady<Position> callback) {
callback.onReady(mPercentagePosition);
}
void loadMenuTargetFeatures(OnInfoReady<List<AccessibilityTarget>> callback) {
@@ -75,6 +91,21 @@ class MenuInfoRepository {
callback.onReady(getMenuSizeTypeFromSettings(mContext));
}
void updateMenuSavingPosition(Position percentagePosition) {
mPercentagePosition = percentagePosition;
Prefs.putString(mContext, Prefs.Key.ACCESSIBILITY_FLOATING_MENU_POSITION,
percentagePosition.toString());
}
private Position getStartPosition() {
final String absolutePositionString = Prefs.getString(mContext,
Prefs.Key.ACCESSIBILITY_FLOATING_MENU_POSITION, /* defaultValue= */ null);
return TextUtils.isEmpty(absolutePositionString)
? new Position(DEFAULT_MENU_POSITION_X_PERCENT, DEFAULT_MENU_POSITION_Y_PERCENT)
: Position.fromString(absolutePositionString);
}
void registerContentObservers() {
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS),

View File

@@ -21,7 +21,11 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import androidx.lifecycle.Observer;
@@ -31,18 +35,25 @@ import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.accessibility.dialog.AccessibilityTarget;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* The container view displays the accessibility features.
*/
@SuppressLint("ViewConstructor")
class MenuView extends FrameLayout {
class MenuView extends FrameLayout implements
ViewTreeObserver.OnComputeInternalInsetsListener {
private static final int INDEX_MENU_ITEM = 0;
private final List<AccessibilityTarget> mTargetFeatures = new ArrayList<>();
private final AccessibilityTargetAdapter mAdapter;
private final MenuViewModel mMenuViewModel;
private final MenuAnimationController mMenuAnimationController;
private final Rect mBoundsInParent = new Rect();
private final RecyclerView mTargetFeaturesView;
private final ViewTreeObserver.OnDrawListener mSystemGestureExcludeUpdater =
this::updateSystemGestureExcludeRects;
private final Observer<Position> mPercentagePositionObserver = this::onPercentagePosition;
private final Observer<Integer> mSizeTypeObserver = this::onSizeTypeChanged;
private final Observer<List<AccessibilityTarget>> mTargetFeaturesObserver =
this::onTargetFeaturesChanged;
@@ -53,6 +64,7 @@ class MenuView extends FrameLayout {
mMenuViewModel = menuViewModel;
mMenuViewAppearance = menuViewAppearance;
mMenuAnimationController = new MenuAnimationController(this);
mAdapter = new AccessibilityTargetAdapter(mTargetFeatures);
mTargetFeaturesView = new RecyclerView(context);
mTargetFeaturesView.setAdapter(mAdapter);
@@ -60,16 +72,25 @@ class MenuView extends FrameLayout {
setLayoutParams(new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
// Avoid drawing out of bounds of the parent view
setClipToOutline(true);
loadLayoutResources();
addView(mTargetFeaturesView);
}
@Override
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
inoutInfo.touchableRegion.set(mBoundsInParent);
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
loadLayoutResources();
mTargetFeaturesView.setOverScrollMode(mMenuViewAppearance.getMenuScrollMode());
}
@SuppressLint("NotifyDataSetChanged")
@@ -80,6 +101,10 @@ class MenuView extends FrameLayout {
}
private void onSizeChanged() {
mBoundsInParent.set(mBoundsInParent.left, mBoundsInParent.top,
mBoundsInParent.left + mMenuViewAppearance.getMenuWidth(),
mBoundsInParent.top + mMenuViewAppearance.getMenuHeight());
final FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) getLayoutParams();
layoutParams.height = mMenuViewAppearance.getMenuHeight();
setLayoutParams(layoutParams);
@@ -96,6 +121,18 @@ class MenuView extends FrameLayout {
mMenuViewAppearance.getMenuStrokeColor());
}
private void onPercentagePosition(Position percentagePosition) {
mMenuViewAppearance.setPercentagePosition(percentagePosition);
onPositionChanged();
}
private void onPositionChanged() {
final PointF position = mMenuViewAppearance.getMenuPosition();
mMenuAnimationController.moveToPosition(position);
onBoundsInParentChanged((int) position.x, (int) position.y);
}
@SuppressLint("NotifyDataSetChanged")
private void onSizeTypeChanged(int newSizeType) {
mMenuViewAppearance.setSizeType(newSizeType);
@@ -106,6 +143,7 @@ class MenuView extends FrameLayout {
onSizeChanged();
onEdgeChanged();
onPositionChanged();
}
private void onTargetFeaturesChanged(List<AccessibilityTarget> newTargetFeatures) {
@@ -113,24 +151,37 @@ class MenuView extends FrameLayout {
mTargetFeatures.clear();
mTargetFeatures.addAll(newTargetFeatures);
mMenuViewAppearance.setTargetFeaturesSize(mTargetFeatures.size());
mTargetFeaturesView.setOverScrollMode(mMenuViewAppearance.getMenuScrollMode());
mAdapter.notifyDataSetChanged();
onSizeChanged();
onEdgeChanged();
onPositionChanged();
}
void show() {
mMenuViewModel.getPercentagePositionData().observeForever(mPercentagePositionObserver);
mMenuViewModel.getTargetFeaturesData().observeForever(mTargetFeaturesObserver);
mMenuViewModel.getSizeTypeData().observeForever(mSizeTypeObserver);
setVisibility(VISIBLE);
mMenuViewModel.registerContentObservers();
getViewTreeObserver().addOnComputeInternalInsetsListener(this);
getViewTreeObserver().addOnDrawListener(mSystemGestureExcludeUpdater);
}
void hide() {
setVisibility(GONE);
mBoundsInParent.setEmpty();
mMenuViewModel.getPercentagePositionData().removeObserver(mPercentagePositionObserver);
mMenuViewModel.getTargetFeaturesData().removeObserver(mTargetFeaturesObserver);
mMenuViewModel.getSizeTypeData().removeObserver(mSizeTypeObserver);
mMenuViewModel.unregisterContentObservers();
getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
getViewTreeObserver().removeOnDrawListener(mSystemGestureExcludeUpdater);
}
void onBoundsInParentChanged(int newLeft, int newTop) {
mBoundsInParent.offsetTo(newLeft, newTop);
}
void loadLayoutResources() {
@@ -141,6 +192,7 @@ class MenuView extends FrameLayout {
onItemSizeChanged();
onSizeChanged();
onEdgeChanged();
onPositionChanged();
}
private InstantInsetLayerDrawable getContainerViewInsetLayer() {
@@ -150,4 +202,9 @@ class MenuView extends FrameLayout {
private GradientDrawable getContainerViewGradient() {
return (GradientDrawable) getContainerViewInsetLayer().getDrawable(INDEX_MENU_ITEM);
}
private void updateSystemGestureExcludeRects() {
final ViewGroup parentView = (ViewGroup) getParent();
parentView.setSystemGestureExclusionRects(Collections.singletonList(mBoundsInParent));
}
}

View File

@@ -16,12 +16,21 @@
package com.android.systemui.accessibility.floatingmenu;
import static android.view.View.OVER_SCROLL_ALWAYS;
import static android.view.View.OVER_SCROLL_NEVER;
import static com.android.systemui.accessibility.floatingmenu.MenuViewAppearance.MenuSizeType.SMALL;
import android.annotation.IntDef;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
import androidx.annotation.DimenRes;
@@ -34,9 +43,13 @@ import java.lang.annotation.RetentionPolicy;
* Provides the layout resources information of the {@link MenuView}.
*/
class MenuViewAppearance {
private final WindowManager mWindowManager;
private final Resources mRes;
private final Position mPercentagePosition = new Position(/* percentageX= */
0f, /* percentageY= */ 0f);
private int mTargetFeaturesSize;
private int mSizeType;
private int mMargin;
private int mSmallPadding;
private int mLargePadding;
private int mSmallIconSize;
@@ -62,13 +75,15 @@ class MenuViewAppearance {
int LARGE = 1;
}
MenuViewAppearance(Context context) {
MenuViewAppearance(Context context, WindowManager windowManager) {
mWindowManager = windowManager;
mRes = context.getResources();
update();
}
void update() {
mMargin = mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_margin);
mSmallPadding =
mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_small_padding);
mLargePadding =
@@ -81,7 +96,7 @@ class MenuViewAppearance {
mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_small_single_radius);
mSmallMultipleRadius = mRes.getDimensionPixelSize(
R.dimen.accessibility_floating_menu_small_multiple_radius);
mRadii = createRadii(getMenuRadius(mTargetFeaturesSize));
mRadii = createRadii(isMenuOnLeftSide(), getMenuRadius(mTargetFeaturesSize));
mLargeSingleRadius =
mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_large_single_radius);
mLargeMultipleRadius = mRes.getDimensionPixelSize(
@@ -98,13 +113,48 @@ class MenuViewAppearance {
void setSizeType(int sizeType) {
mSizeType = sizeType;
mRadii = createRadii(getMenuRadius(mTargetFeaturesSize));
mRadii = createRadii(isMenuOnLeftSide(), getMenuRadius(mTargetFeaturesSize));
}
void setTargetFeaturesSize(int targetFeaturesSize) {
mTargetFeaturesSize = targetFeaturesSize;
mRadii = createRadii(getMenuRadius(targetFeaturesSize));
mRadii = createRadii(isMenuOnLeftSide(), getMenuRadius(targetFeaturesSize));
}
void setPercentagePosition(Position percentagePosition) {
mPercentagePosition.update(percentagePosition);
mRadii = createRadii(isMenuOnLeftSide(), getMenuRadius(mTargetFeaturesSize));
}
Rect getMenuDraggableBounds() {
final int margin = getMenuMargin();
final Rect draggableBounds = getWindowAvailableBounds();
// Initializes start position for mapping the translation of the menu view.
final WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
final WindowInsets windowInsets = windowMetrics.getWindowInsets();
final Insets displayCutoutInsets = windowInsets.getInsetsIgnoringVisibility(
WindowInsets.Type.displayCutout());
draggableBounds.offset(-displayCutoutInsets.left, -displayCutoutInsets.top);
draggableBounds.top += margin;
draggableBounds.right -= getMenuWidth();
draggableBounds.bottom -= Math.min(
getWindowAvailableBounds().height() - draggableBounds.top,
calculateActualMenuHeight() + margin);
return draggableBounds;
}
PointF getMenuPosition() {
final Rect draggableBounds = getMenuDraggableBounds();
return new PointF(
draggableBounds.left
+ draggableBounds.width() * mPercentagePosition.getPercentageX(),
draggableBounds.top
+ draggableBounds.height() * mPercentagePosition.getPercentageY());
}
Drawable getMenuBackground() {
@@ -115,20 +165,32 @@ class MenuViewAppearance {
return mElevation;
}
int getMenuWidth() {
return getMenuPadding() * 2 + getMenuIconSize();
}
int getMenuHeight() {
return calculateActualMenuHeight();
return Math.min(getWindowAvailableBounds().height() - mMargin * 2,
calculateActualMenuHeight());
}
int getMenuIconSize() {
return mSizeType == SMALL ? mSmallIconSize : mLargeIconSize;
}
private int getMenuMargin() {
return mMargin;
}
int getMenuPadding() {
return mSizeType == SMALL ? mSmallPadding : mLargePadding;
}
int[] getMenuInsets() {
return new int[]{mInset, 0, 0, 0};
final int left = isMenuOnLeftSide() ? mInset : 0;
final int right = isMenuOnLeftSide() ? 0 : mInset;
return new int[]{left, 0, right, 0};
}
int getMenuStrokeWidth() {
@@ -147,6 +209,14 @@ class MenuViewAppearance {
return mSizeType == SMALL ? getSmallSize(itemCount) : getLargeSize(itemCount);
}
int getMenuScrollMode() {
return hasExceededMaxWindowHeight() ? OVER_SCROLL_ALWAYS : OVER_SCROLL_NEVER;
}
private boolean hasExceededMaxWindowHeight() {
return calculateActualMenuHeight() > getWindowAvailableBounds().height();
}
@DimenRes
private int getSmallSize(int itemCount) {
return itemCount > 1 ? mSmallMultipleRadius : mSmallSingleRadius;
@@ -157,8 +227,29 @@ class MenuViewAppearance {
return itemCount > 1 ? mLargeMultipleRadius : mLargeSingleRadius;
}
private static float[] createRadii(float radius) {
return new float[]{0.0f, 0.0f, radius, radius, radius, radius, 0.0f, 0.0f};
private static float[] createRadii(boolean isMenuOnLeftSide, float radius) {
return isMenuOnLeftSide
? new float[]{0.0f, 0.0f, radius, radius, radius, radius, 0.0f, 0.0f}
: new float[]{radius, radius, 0.0f, 0.0f, 0.0f, 0.0f, radius, radius};
}
private Rect getWindowAvailableBounds() {
final WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
final WindowInsets windowInsets = windowMetrics.getWindowInsets();
final Insets insets = windowInsets.getInsetsIgnoringVisibility(
WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
final Rect bounds = new Rect(windowMetrics.getBounds());
bounds.left += insets.left;
bounds.right -= insets.right;
bounds.top += insets.top;
bounds.bottom -= insets.bottom;
return bounds;
}
private boolean isMenuOnLeftSide() {
return mPercentagePosition.getPercentageX() < 0.5f;
}
private int calculateActualMenuHeight() {

View File

@@ -19,6 +19,7 @@ package com.android.systemui.accessibility.floatingmenu;
import android.annotation.IntDef;
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.WindowManager;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
@@ -41,11 +42,12 @@ class MenuViewLayer extends FrameLayout {
int MENU_VIEW = 0;
}
MenuViewLayer(@NonNull Context context) {
MenuViewLayer(@NonNull Context context, WindowManager windowManager) {
super(context);
final MenuViewModel menuViewModel = new MenuViewModel(context);
final MenuViewAppearance menuViewAppearance = new MenuViewAppearance(context);
final MenuViewAppearance menuViewAppearance = new MenuViewAppearance(context,
windowManager);
mMenuView = new MenuView(context, menuViewModel, menuViewAppearance);
addView(mMenuView, LayerIndex.MENU_VIEW);

View File

@@ -20,6 +20,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_
import android.content.Context;
import android.graphics.PixelFormat;
import android.view.WindowInsets;
import android.view.WindowManager;
/**
@@ -33,7 +34,7 @@ class MenuViewLayerController implements IAccessibilityFloatingMenu {
MenuViewLayerController(Context context, WindowManager windowManager) {
mWindowManager = windowManager;
mMenuViewLayer = new MenuViewLayer(context);
mMenuViewLayer = new MenuViewLayer(context, windowManager);
}
@Override
@@ -68,9 +69,10 @@ class MenuViewLayerController implements IAccessibilityFloatingMenu {
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.receiveInsetsIgnoringZOrder = true;
params.privateFlags |= PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
params.windowAnimations = android.R.style.Animation_Translucent;
params.setFitInsetsTypes(WindowInsets.Type.navigationBars());
return params;
}
}

View File

@@ -33,6 +33,7 @@ class MenuViewModel implements MenuInfoRepository.OnSettingsContentsChanged {
private final MutableLiveData<List<AccessibilityTarget>> mTargetFeaturesData =
new MutableLiveData<>();
private final MutableLiveData<Integer> mSizeTypeData = new MutableLiveData<>();
private final MutableLiveData<Position> mPercentagePositionData = new MutableLiveData<>();
private final MenuInfoRepository mInfoRepository;
MenuViewModel(Context context) {
@@ -49,6 +50,11 @@ class MenuViewModel implements MenuInfoRepository.OnSettingsContentsChanged {
mSizeTypeData.setValue(newSizeType);
}
LiveData<Position> getPercentagePositionData() {
mInfoRepository.loadMenuPosition(mPercentagePositionData::setValue);
return mPercentagePositionData;
}
LiveData<Integer> getSizeTypeData() {
mInfoRepository.loadMenuSizeType(mSizeTypeData::setValue);
return mSizeTypeData;

View File

@@ -17,6 +17,7 @@
package com.android.systemui.accessibility.floatingmenu;
import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.text.TextUtils;
/**
@@ -61,6 +62,13 @@ public class Position {
return mPercentageX + ", " + mPercentageY;
}
/**
* Updates the position with {@code percentagePosition}.
*/
public void update(@NonNull Position percentagePosition) {
update(percentagePosition.getPercentageX(), percentagePosition.getPercentageY());
}
/**
* Updates the position with {@code percentageX} and {@code percentageY}.
*

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2022 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.floatingmenu;
import static com.google.common.truth.Truth.assertThat;
import android.graphics.PointF;
import android.testing.AndroidTestingRunner;
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Tests for {@link MenuAnimationController}. */
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class MenuAnimationControllerTest extends SysuiTestCase {
private MenuView mMenuView;
private MenuAnimationController mMenuAnimationController;
@Before
public void setUp() throws Exception {
final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
stubWindowManager);
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext);
mMenuView = new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance);
mMenuAnimationController = new MenuAnimationController(mMenuView);
}
@Test
public void moveToPosition_matchPosition() {
final PointF destination = new PointF(50, 60);
mMenuAnimationController.moveToPosition(destination);
assertThat(mMenuView.getTranslationX()).isEqualTo(50);
assertThat(mMenuView.getTranslationY()).isEqualTo(60);
}
}

View File

@@ -16,13 +16,24 @@
package com.android.systemui.accessibility.floatingmenu;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.systemBars;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
import androidx.test.filters.SmallTest;
@@ -38,6 +49,7 @@ import org.mockito.junit.MockitoRule;
/** Tests for {@link MenuViewLayerController}. */
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class MenuViewLayerControllerTest extends SysuiTestCase {
@Rule
@@ -46,10 +58,20 @@ public class MenuViewLayerControllerTest extends SysuiTestCase {
@Mock
private WindowManager mWindowManager;
@Mock
private WindowMetrics mWindowMetrics;
private MenuViewLayerController mMenuViewLayerController;
@Before
public void setUp() throws Exception {
final WindowManager wm = mContext.getSystemService(WindowManager.class);
doAnswer(invocation -> wm.getMaximumWindowMetrics()).when(
mWindowManager).getMaximumWindowMetrics();
mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
when(mWindowMetrics.getBounds()).thenReturn(new Rect(0, 0, 1080, 2340));
when(mWindowMetrics.getWindowInsets()).thenReturn(stubDisplayInsets());
mMenuViewLayerController = new MenuViewLayerController(mContext, mWindowManager);
}
@@ -68,4 +90,14 @@ public class MenuViewLayerControllerTest extends SysuiTestCase {
verify(mWindowManager).removeView(any(View.class));
}
private WindowInsets stubDisplayInsets() {
final int stubStatusBarHeight = 118;
final int stubNavigationBarHeight = 125;
return new WindowInsets.Builder()
.setVisible(systemBars() | displayCutout(), true)
.setInsets(systemBars() | displayCutout(),
Insets.of(0, stubStatusBarHeight, 0, stubNavigationBarHeight))
.build();
}
}

View File

@@ -26,6 +26,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
@@ -44,7 +45,8 @@ public class MenuViewLayerTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
mMenuViewLayer = new MenuViewLayer(mContext);
final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
mMenuViewLayer = new MenuViewLayer(mContext, stubWindowManager);
}
@Test

View File

@@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify;
import android.app.UiModeManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
@@ -52,7 +53,9 @@ public class MenuViewTest extends SysuiTestCase {
mNightMode = mUiModeManager.getNightMode();
mUiModeManager.setNightMode(MODE_NIGHT_YES);
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext);
final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext);
final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
stubWindowManager);
mMenuView = spy(new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance));
}