diff options
10 files changed, 424 insertions, 13 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationController.java new file mode 100644 index 000000000000..f56a15427452 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationController.java @@ -0,0 +1,175 @@ +/* + * 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.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.ComponentCallbacks; +import android.content.res.Configuration; +import android.view.MotionEvent; + +import androidx.annotation.NonNull; +import androidx.dynamicanimation.animation.DynamicAnimation; + +import com.android.systemui.R; +import com.android.wm.shell.bubbles.DismissView; +import com.android.wm.shell.common.magnetictarget.MagnetizedObject; + +/** + * Controls the interaction between {@link MagnetizedObject} and + * {@link MagnetizedObject.MagneticTarget}. + */ +class DismissAnimationController implements ComponentCallbacks { + private static final float COMPLETELY_OPAQUE = 1.0f; + private static final float COMPLETELY_TRANSPARENT = 0.0f; + private static final float CIRCLE_VIEW_DEFAULT_SCALE = 1.0f; + private static final float ANIMATING_MAX_ALPHA = 0.7f; + + private final DismissView mDismissView; + private final MenuView mMenuView; + private final ValueAnimator mDismissAnimator; + private final MagnetizedObject<?> mMagnetizedObject; + private float mMinDismissSize; + private float mSizePercent; + + DismissAnimationController(DismissView dismissView, MenuView menuView) { + mDismissView = dismissView; + mDismissView.setPivotX(dismissView.getWidth() / 2.0f); + mDismissView.setPivotY(dismissView.getHeight() / 2.0f); + mMenuView = menuView; + + updateResources(); + + mDismissAnimator = ValueAnimator.ofFloat(COMPLETELY_OPAQUE, COMPLETELY_TRANSPARENT); + mDismissAnimator.addUpdateListener(dismissAnimation -> { + final float animatedValue = (float) dismissAnimation.getAnimatedValue(); + final float scaleValue = Math.max(animatedValue, mSizePercent); + dismissView.getCircle().setScaleX(scaleValue); + dismissView.getCircle().setScaleY(scaleValue); + + menuView.setAlpha(Math.max(animatedValue, ANIMATING_MAX_ALPHA)); + }); + + mDismissAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(@NonNull Animator animation, boolean isReverse) { + super.onAnimationEnd(animation, isReverse); + + if (isReverse) { + mDismissView.getCircle().setScaleX(CIRCLE_VIEW_DEFAULT_SCALE); + mDismissView.getCircle().setScaleY(CIRCLE_VIEW_DEFAULT_SCALE); + mMenuView.setAlpha(COMPLETELY_OPAQUE); + } + } + }); + + mMagnetizedObject = + new MagnetizedObject<MenuView>(mMenuView.getContext(), mMenuView, + new MenuAnimationController.MenuPositionProperty( + DynamicAnimation.TRANSLATION_X), + new MenuAnimationController.MenuPositionProperty( + DynamicAnimation.TRANSLATION_Y)) { + @Override + public void getLocationOnScreen(MenuView underlyingObject, int[] loc) { + underlyingObject.getLocationOnScreen(loc); + } + + @Override + public float getHeight(MenuView underlyingObject) { + return underlyingObject.getHeight(); + } + + @Override + public float getWidth(MenuView underlyingObject) { + return underlyingObject.getWidth(); + } + }; + + final MagnetizedObject.MagneticTarget magneticTarget = new MagnetizedObject.MagneticTarget( + dismissView.getCircle(), (int) mMinDismissSize); + mMagnetizedObject.addTarget(magneticTarget); + } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + updateResources(); + } + + @Override + public void onLowMemory() { + // Do nothing + } + + void showDismissView(boolean show) { + if (show) { + mDismissView.show(); + } else { + mDismissView.hide(); + } + } + + void setMagnetListener(MagnetizedObject.MagnetListener magnetListener) { + mMagnetizedObject.setMagnetListener(magnetListener); + } + + void maybeConsumeDownMotionEvent(MotionEvent event) { + mMagnetizedObject.maybeConsumeMotionEvent(event); + } + + /** + * This used to pass {@link MotionEvent#ACTION_DOWN} to the magnetized object to check if it was + * within the magnetic field. It should be used in the {@link MenuListViewTouchHandler}. + * + * @param event that move the magnetized object which is also the menu list view. + * @return true if the location of the motion events moves within the magnetic field of a + * target, but false if didn't set + * {@link DismissAnimationController#setMagnetListener(MagnetizedObject.MagnetListener)}. + */ + boolean maybeConsumeMoveMotionEvent(MotionEvent event) { + return mMagnetizedObject.maybeConsumeMotionEvent(event); + } + + /** + * This used to pass {@link MotionEvent#ACTION_UP} to the magnetized object to check if it was + * within the magnetic field. It should be used in the {@link MenuListViewTouchHandler}. + * + * @param event that move the magnetized object which is also the menu list view. + * @return true if the location of the motion events moves within the magnetic field of a + * target, but false if didn't set + * {@link DismissAnimationController#setMagnetListener(MagnetizedObject.MagnetListener)}. + */ + boolean maybeConsumeUpMotionEvent(MotionEvent event) { + return mMagnetizedObject.maybeConsumeMotionEvent(event); + } + + void animateDismissMenu(boolean scaleUp) { + if (scaleUp) { + mDismissAnimator.start(); + } else { + mDismissAnimator.reverse(); + } + } + + private void updateResources() { + final float maxDismissSize = mDismissView.getResources().getDimensionPixelSize( + R.dimen.dismiss_circle_size); + mMinDismissSize = mDismissView.getResources().getDimensionPixelSize( + R.dimen.dismiss_circle_small); + mSizePercent = mMinDismissSize / maxDismissSize; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java index d6d039903505..e5313adf94d4 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java @@ -47,6 +47,8 @@ class MenuAnimationController { private static final float MIN_PERCENT = 0.0f; private static final float MAX_PERCENT = 1.0f; private static final float COMPLETELY_OPAQUE = 1.0f; + private static final float COMPLETELY_TRANSPARENT = 0.0f; + private static final float SCALE_SHRINK = 0.0f; private static final float FLING_FRICTION_SCALAR = 1.9f; private static final float DEFAULT_FRICTION = 4.2f; private static final float SPRING_AFTER_FLING_DAMPING_RATIO = 0.85f; @@ -297,6 +299,15 @@ class MenuAnimationController { mMenuView.onDraggingStart(); } + void startShrinkAnimation(Runnable endAction) { + mMenuView.animate() + .scaleX(SCALE_SHRINK) + .scaleY(SCALE_SHRINK) + .alpha(COMPLETELY_TRANSPARENT) + .translationY(mMenuView.getTranslationY()) + .withEndAction(endAction).start(); + } + private void onSpringAnimationEnd(PointF position) { mMenuView.onBoundsInParentChanged((int) position.x, (int) position.y); constrainPositionAndUpdate(position); diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java index 3146c9f0d2af..bc3cf0a6bab0 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java @@ -38,9 +38,12 @@ class MenuListViewTouchHandler implements RecyclerView.OnItemTouchListener { private final PointF mMenuTranslationDown = new PointF(); private boolean mIsDragging = false; private float mTouchSlop; + private final DismissAnimationController mDismissAnimationController; - MenuListViewTouchHandler(MenuAnimationController menuAnimationController) { + MenuListViewTouchHandler(MenuAnimationController menuAnimationController, + DismissAnimationController dismissAnimationController) { mMenuAnimationController = menuAnimationController; + mDismissAnimationController = dismissAnimationController; } @Override @@ -61,6 +64,7 @@ class MenuListViewTouchHandler implements RecyclerView.OnItemTouchListener { mMenuTranslationDown.set(menuView.getTranslationX(), menuView.getTranslationY()); mMenuAnimationController.cancelAnimations(); + mDismissAnimationController.maybeConsumeDownMotionEvent(motionEvent); break; case MotionEvent.ACTION_MOVE: if (mIsDragging || Math.hypot(dx, dy) > mTouchSlop) { @@ -69,8 +73,13 @@ class MenuListViewTouchHandler implements RecyclerView.OnItemTouchListener { mMenuAnimationController.onDraggingStart(); } - mMenuAnimationController.moveToPositionX(mMenuTranslationDown.x + dx); - mMenuAnimationController.moveToPositionYIfNeeded(mMenuTranslationDown.y + dy); + mDismissAnimationController.showDismissView(/* show= */ true); + + if (!mDismissAnimationController.maybeConsumeMoveMotionEvent(motionEvent)) { + mMenuAnimationController.moveToPositionX(mMenuTranslationDown.x + dx); + mMenuAnimationController.moveToPositionYIfNeeded( + mMenuTranslationDown.y + dy); + } } break; case MotionEvent.ACTION_UP: @@ -79,10 +88,18 @@ class MenuListViewTouchHandler implements RecyclerView.OnItemTouchListener { final float endX = mMenuTranslationDown.x + dx; mIsDragging = false; - if (!mMenuAnimationController.maybeMoveToEdgeAndHide(endX)) { + if (mMenuAnimationController.maybeMoveToEdgeAndHide(endX)) { + mDismissAnimationController.showDismissView(/* show= */ false); + mMenuAnimationController.fadeOutIfEnabled(); + + return true; + } + + if (!mDismissAnimationController.maybeConsumeUpMotionEvent(motionEvent)) { mVelocityTracker.computeCurrentVelocity(VELOCITY_UNIT_SECONDS); mMenuAnimationController.flingMenuThenSpringToEdge(endX, mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity()); + mDismissAnimationController.showDismissView(/* show= */ false); } // Avoid triggering the listener of the item. 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 15d139cf15da..2e8570cb5260 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java @@ -42,7 +42,7 @@ import java.util.Collections; import java.util.List; /** - * The menu view displays the accessibility features. + * The container view displays the accessibility features. */ @SuppressLint("ViewConstructor") class MenuView extends FrameLayout implements @@ -70,7 +70,6 @@ class MenuView extends FrameLayout implements mMenuViewModel = menuViewModel; mMenuViewAppearance = menuViewAppearance; mMenuAnimationController = new MenuAnimationController(this); - mAdapter = new AccessibilityTargetAdapter(mTargetFeatures); mTargetFeaturesView = new RecyclerView(context); mTargetFeaturesView.setAdapter(mAdapter); @@ -112,6 +111,10 @@ class MenuView extends FrameLayout implements mTargetFeaturesView.addOnItemTouchListener(listener); } + MenuAnimationController getMenuAnimationController() { + return mMenuAnimationController; + } + @SuppressLint("NotifyDataSetChanged") private void onItemSizeChanged() { mAdapter.setItemPadding(mMenuViewAppearance.getMenuPadding()); 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 5252519e9faf..26bf5e354164 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java @@ -19,12 +19,20 @@ package com.android.systemui.accessibility.floatingmenu; import android.annotation.IntDef; import android.annotation.SuppressLint; import android.content.Context; +import android.content.res.Configuration; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; import android.view.MotionEvent; import android.view.WindowManager; import android.widget.FrameLayout; import androidx.annotation.NonNull; +import com.android.internal.annotations.VisibleForTesting; +import com.android.wm.shell.bubbles.DismissView; +import com.android.wm.shell.common.magnetictarget.MagnetizedObject; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -34,24 +42,83 @@ import java.lang.annotation.RetentionPolicy; @SuppressLint("ViewConstructor") class MenuViewLayer extends FrameLayout { private final MenuView mMenuView; + private final DismissView mDismissView; + private final Handler mHandler = new Handler(Looper.getMainLooper()); + private final IAccessibilityFloatingMenu mFloatingMenu; + private final DismissAnimationController mDismissAnimationController; @IntDef({ - LayerIndex.MENU_VIEW + LayerIndex.MENU_VIEW, + LayerIndex.DISMISS_VIEW }) @Retention(RetentionPolicy.SOURCE) @interface LayerIndex { int MENU_VIEW = 0; + int DISMISS_VIEW = 1; } - MenuViewLayer(@NonNull Context context, WindowManager windowManager) { + @VisibleForTesting + final Runnable mDismissMenuAction = new Runnable() { + @Override + public void run() { + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* value= */ ""); + mFloatingMenu.hide(); + } + }; + + MenuViewLayer(@NonNull Context context, WindowManager windowManager, + IAccessibilityFloatingMenu floatingMenu) { super(context); + mFloatingMenu = floatingMenu; + final MenuViewModel menuViewModel = new MenuViewModel(context); final MenuViewAppearance menuViewAppearance = new MenuViewAppearance(context, windowManager); mMenuView = new MenuView(context, menuViewModel, menuViewAppearance); + final MenuAnimationController menuAnimationController = + mMenuView.getMenuAnimationController(); + + mDismissView = new DismissView(context); + mDismissAnimationController = new DismissAnimationController(mDismissView, mMenuView); + mDismissAnimationController.setMagnetListener(new MagnetizedObject.MagnetListener() { + @Override + public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) { + mDismissAnimationController.animateDismissMenu(/* scaleUp= */ true); + } + + @Override + public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target, + float velocityX, float velocityY, boolean wasFlungOut) { + mDismissAnimationController.animateDismissMenu(/* scaleUp= */ false); + } + + @Override + public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) { + menuAnimationController.startShrinkAnimation(() -> { + mMenuView.hide(); + + mHandler.post(mDismissMenuAction); + }); + + mDismissView.hide(); + mDismissAnimationController.animateDismissMenu(/* scaleUp= */ false); + } + }); + + final MenuListViewTouchHandler menuListViewTouchHandler = new MenuListViewTouchHandler( + menuAnimationController, mDismissAnimationController); + mMenuView.addOnItemTouchListenerToList(menuListViewTouchHandler); addView(mMenuView, LayerIndex.MENU_VIEW); + addView(mDismissView, LayerIndex.DISMISS_VIEW); + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + mDismissView.updateResources(); } @Override @@ -68,6 +135,7 @@ class MenuViewLayer extends FrameLayout { super.onAttachedToWindow(); mMenuView.show(); + mContext.registerComponentCallbacks(mDismissAnimationController); } @Override @@ -75,5 +143,7 @@ class MenuViewLayer extends FrameLayout { super.onDetachedFromWindow(); mMenuView.hide(); + mHandler.removeCallbacksAndMessages(/* token= */ null); + mContext.unregisterComponentCallbacks(mDismissAnimationController); } } 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 d2093c200ca2..c185546e34fa 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java @@ -34,7 +34,7 @@ class MenuViewLayerController implements IAccessibilityFloatingMenu { MenuViewLayerController(Context context, WindowManager windowManager) { mWindowManager = windowManager; - mMenuViewLayer = new MenuViewLayer(context, windowManager); + mMenuViewLayer = new MenuViewLayer(context, windowManager, this); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java new file mode 100644 index 000000000000..8ef65dcb2c3a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java @@ -0,0 +1,67 @@ +/* + * 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 org.mockito.Mockito.verify; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.WindowManager; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.wm.shell.bubbles.DismissView; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Tests for {@link DismissAnimationController}. */ +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class DismissAnimationControllerTest extends SysuiTestCase { + private DismissAnimationController mDismissAnimationController; + private DismissView mDismissView; + + @Before + public void setUp() throws Exception { + final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class); + final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext); + final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext, + stubWindowManager); + final MenuView stubMenuView = new MenuView(mContext, stubMenuViewModel, + stubMenuViewAppearance); + mDismissView = new DismissView(mContext); + mDismissAnimationController = new DismissAnimationController(mDismissView, stubMenuView); + } + + @Test + public void showDismissView_success() { + mDismissAnimationController.showDismissView(true); + + verify(mDismissView).show(); + } + + @Test + public void hideDismissView_success() { + mDismissAnimationController.showDismissView(false); + + verify(mDismissView).hide(); + } +} 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 index dbf291c49ee5..31a7361b7338 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java @@ -18,9 +18,16 @@ package com.android.systemui.accessibility.floatingmenu; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + import android.graphics.PointF; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.view.View; +import android.view.ViewPropertyAnimator; import android.view.WindowManager; import androidx.test.filters.SmallTest; @@ -36,6 +43,8 @@ import org.junit.runner.RunWith; @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class MenuAnimationControllerTest extends SysuiTestCase { + + private ViewPropertyAnimator mViewPropertyAnimator; private MenuView mMenuView; private MenuAnimationController mMenuAnimationController; @@ -45,7 +54,11 @@ public class MenuAnimationControllerTest extends SysuiTestCase { final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext, stubWindowManager); final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext); - mMenuView = new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance); + + mMenuView = spy(new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance)); + mViewPropertyAnimator = spy(mMenuView.animate()); + doReturn(mViewPropertyAnimator).when(mMenuView).animate(); + mMenuAnimationController = new MenuAnimationController(mMenuView); } @@ -58,4 +71,11 @@ public class MenuAnimationControllerTest extends SysuiTestCase { assertThat(mMenuView.getTranslationX()).isEqualTo(50); assertThat(mMenuView.getTranslationY()).isEqualTo(60); } + + @Test + public void startShrinkAnimation_verifyAnimationEndAction() { + mMenuAnimationController.startShrinkAnimation(() -> mMenuView.setVisibility(View.VISIBLE)); + + verify(mViewPropertyAnimator).withEndAction(any(Runnable.class)); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java index c5b9a294fc34..4acb394bee95 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java @@ -21,6 +21,8 @@ import static android.view.View.OVER_SCROLL_NEVER; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -36,6 +38,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.accessibility.dialog.AccessibilityTarget; import com.android.systemui.SysuiTestCase; import com.android.systemui.accessibility.MotionEventHelper; +import com.android.wm.shell.bubbles.DismissView; import org.junit.After; import org.junit.Before; @@ -57,7 +60,9 @@ public class MenuListViewTouchHandlerTest extends SysuiTestCase { private MenuView mStubMenuView; private MenuListViewTouchHandler mTouchHandler; private MenuAnimationController mMenuAnimationController; + private DismissAnimationController mDismissAnimationController; private RecyclerView mStubListView; + private DismissView mDismissView; @Before public void setUp() throws Exception { @@ -69,7 +74,11 @@ public class MenuListViewTouchHandlerTest extends SysuiTestCase { mStubMenuView.setTranslationX(0); mStubMenuView.setTranslationY(0); mMenuAnimationController = spy(new MenuAnimationController(mStubMenuView)); - mTouchHandler = new MenuListViewTouchHandler(mMenuAnimationController); + mDismissView = spy(new DismissView(mContext)); + mDismissAnimationController = + spy(new DismissAnimationController(mDismissView, mStubMenuView)); + mTouchHandler = new MenuListViewTouchHandler(mMenuAnimationController, + mDismissAnimationController); final AccessibilityTargetAdapter stubAdapter = new AccessibilityTargetAdapter(mStubTargets); mStubListView = (RecyclerView) mStubMenuView.getChildAt(0); mStubListView.setAdapter(stubAdapter); @@ -88,7 +97,9 @@ public class MenuListViewTouchHandlerTest extends SysuiTestCase { } @Test - public void onActionMoveEvent_shouldMoveToPosition() { + public void onActionMoveEvent_notConsumedEvent_shouldMoveToPosition() { + doReturn(false).when(mDismissAnimationController).maybeConsumeMoveMotionEvent( + any(MotionEvent.class)); final int offset = 100; final MotionEvent stubDownEvent = mMotionEventHelper.obtainMotionEvent(/* downTime= */ 0, /* eventTime= */ 1, @@ -108,6 +119,24 @@ public class MenuListViewTouchHandlerTest extends SysuiTestCase { } @Test + public void onActionMoveEvent_shouldShowDismissView() { + final int offset = 100; + final MotionEvent stubDownEvent = + mMotionEventHelper.obtainMotionEvent(/* downTime= */ 0, /* eventTime= */ 1, + MotionEvent.ACTION_DOWN, mStubMenuView.getTranslationX(), + mStubMenuView.getTranslationY()); + final MotionEvent stubMoveEvent = + mMotionEventHelper.obtainMotionEvent(/* downTime= */ 0, /* eventTime= */ 3, + MotionEvent.ACTION_MOVE, mStubMenuView.getTranslationX() + offset, + mStubMenuView.getTranslationY() + offset); + + mTouchHandler.onInterceptTouchEvent(mStubListView, stubDownEvent); + mTouchHandler.onInterceptTouchEvent(mStubListView, stubMoveEvent); + + verify(mDismissView).show(); + } + + @Test public void dragAndDrop_shouldFlingMenuThenSpringToEdge() { final int offset = 100; final MotionEvent stubDownEvent = 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 23c6ef1338b3..8162035878b8 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 @@ -23,6 +23,8 @@ import static com.android.systemui.accessibility.floatingmenu.MenuViewLayer.Laye import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.verify; + import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.View; @@ -33,8 +35,12 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; /** Tests for {@link MenuViewLayer}. */ @RunWith(AndroidTestingRunner.class) @@ -43,10 +49,16 @@ import org.junit.runner.RunWith; public class MenuViewLayerTest extends SysuiTestCase { private MenuViewLayer mMenuViewLayer; + @Rule + public MockitoRule mockito = MockitoJUnit.rule(); + + @Mock + private IAccessibilityFloatingMenu mFloatingMenu; + @Before public void setUp() throws Exception { final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class); - mMenuViewLayer = new MenuViewLayer(mContext, stubWindowManager); + mMenuViewLayer = new MenuViewLayer(mContext, stubWindowManager, mFloatingMenu); } @Test @@ -64,4 +76,11 @@ public class MenuViewLayerTest extends SysuiTestCase { assertThat(menuView.getVisibility()).isEqualTo(GONE); } + + @Test + public void tiggerDismissMenuAction_hideFloatingMenu() { + mMenuViewLayer.mDismissMenuAction.run(); + + verify(mFloatingMenu).hide(); + } } |