diff options
12 files changed, 347 insertions, 15 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java new file mode 100644 index 000000000000..9d2a4d74a0e6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java @@ -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); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java index 698d60a5b13e..0649463c8238 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java @@ -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), diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java index 576f23ee780e..d6f8885f6230 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java @@ -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)); + } } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java index b9b7732605c0..bbf967310ca3 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java @@ -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() { diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java index 4ea2f7799c30..262f43b5bccb 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java @@ -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); diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java index 1e15a599f796..d2093c200ca2 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java @@ -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; } } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java index c3ba43950b6e..f8fd4f599796 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java @@ -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; diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/Position.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/Position.java index 7b7eda84df4c..fc21be280dd6 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/Position.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/Position.java @@ -17,6 +17,7 @@ package com.android.systemui.accessibility.floatingmenu; import android.annotation.FloatRange; +import android.annotation.NonNull; import android.text.TextUtils; /** @@ -62,6 +63,13 @@ public class Position { } /** + * 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}. * * @param percentageX the new percentage of X-axis of the screen, from 0.0 to 1.0. diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java new file mode 100644 index 000000000000..6391a2c8eff7 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java @@ -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); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java index f782a446c627..8c8d6aca7cd7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java @@ -16,13 +16,24 @@ package com.android.systemui.accessibility.floatingmenu; +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(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java index 8883cb783438..23c6ef1338b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java @@ -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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java index 513044d2c20d..6549de15dad2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java @@ -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)); } |