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

This commit is contained in:
PETER LIANG
2022-10-22 07:12:52 +00:00
committed by Android (Google) Code Review
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));
}