Support the feature of Drag to remove for the Accessibility Floating Menu(1/n).

Goals:
Based on the animation implementation and improvements, provide the capability of dismissing the accessibility floating menu view on the home screen.

Actions:
1) Add and interact between the magnetized object and magnetic target.

Bug: 237716018
Test: atest MenuTouchHandlerTest MenuViewLayerTest
Change-Id: I9428c3a3e4e26b9fa4595bc2b6a3a7526c54cef1
This commit is contained in:
Peter Liang
2022-09-27 00:00:44 +08:00
parent f9b8309c03
commit ae8863ee77
10 changed files with 424 additions and 13 deletions

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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.

View File

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

View File

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

View File

@@ -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

View File

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

View File

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

View File

@@ -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,
@@ -107,6 +118,24 @@ public class MenuListViewTouchHandlerTest extends SysuiTestCase {
assertThat(mStubMenuView.getTranslationY()).isEqualTo(offset);
}
@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;

View File

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