From 90fb1576fbf578f3e767f930bf75ef34cb9cce29 Mon Sep 17 00:00:00 2001 From: Jason Chang Date: Tue, 7 Jul 2020 21:12:27 +0800 Subject: [PATCH] Implement Tutorial panel for one handed To educate users using one-handed mode showing tutorial at top region when one handed triggered Bug: 151800576 Test: manual Change-Id: I255a08bf4527554ee8970c3baaf85b8956b2ca83 --- .../res/drawable-hdpi/one_handed_tutorial.png | Bin 0 -> 1766 bytes .../res/drawable-mdpi/one_handed_tutorial.png | Bin 0 -> 1054 bytes .../drawable-xhdpi/one_handed_tutorial.png | Bin 0 -> 2215 bytes .../drawable-xxhdpi/one_handed_tutorial.png | Bin 0 -> 3649 bytes .../drawable-xxxhdpi/one_handed_tutorial.png | Bin 0 -> 5029 bytes packages/SystemUI/res/values/strings.xml | 5 + .../SystemUI/res/xml/one_handed_tutorial.xml | 67 ++++++++ .../onehanded/OneHandedAnimationCallback.java | 6 + .../OneHandedAnimationController.java | 38 +++-- .../OneHandedDisplayAreaOrganizer.java | 8 +- .../onehanded/OneHandedGestureHandler.java | 10 +- .../onehanded/OneHandedManagerImpl.java | 4 + .../onehanded/OneHandedTouchHandler.java | 5 +- .../onehanded/OneHandedTutorialHandler.java | 161 ++++++++++++++++++ .../OneHandedAnimationControllerTest.java | 2 + .../OneHandedDisplayAreaOrganizerTest.java | 6 +- .../OneHandedGestureHandlerTest.java | 5 +- .../onehanded/OneHandedManagerImplTest.java | 5 +- .../onehanded/OneHandedTouchHandlerTest.java | 5 +- .../OneHandedTutorialHandlerTest.java | 80 +++++++++ 20 files changed, 382 insertions(+), 25 deletions(-) create mode 100644 packages/SystemUI/res/drawable-hdpi/one_handed_tutorial.png create mode 100644 packages/SystemUI/res/drawable-mdpi/one_handed_tutorial.png create mode 100644 packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.png create mode 100644 packages/SystemUI/res/drawable-xxhdpi/one_handed_tutorial.png create mode 100644 packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.png create mode 100644 packages/SystemUI/res/xml/one_handed_tutorial.xml create mode 100644 packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java diff --git a/packages/SystemUI/res/drawable-hdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-hdpi/one_handed_tutorial.png new file mode 100644 index 0000000000000000000000000000000000000000..6c1f1cfdea7cc9367167f2843f88c2b75af87898 GIT binary patch literal 1766 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 Y7t>K3mqje`=l}o!07*qoM6N<$g7j6}WB>pF literal 0 HcmV?d00001 diff --git a/packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.png new file mode 100644 index 0000000000000000000000000000000000000000..3ff692f0c6fca8ed86aaa3e6bfd39373c5d23777 GIT binary patch literal 2215 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 Y&0WsT)6(?&^b-QijLnTI4P0>l16g76C;$Ke literal 0 HcmV?d00001 diff --git a/packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.png new file mode 100644 index 0000000000000000000000000000000000000000..173abedae48a5e3e78962dfa6a8c769b051717e7 GIT binary patch literal 5029 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 HF0uasG@w1& literal 0 HcmV?d00001 diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 8b6543ac73bdf..77d3f4513957d 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2838,4 +2838,9 @@ + + + Using one-handed mode + + To exit, swipe up from the bottom of the screen or tap anywhere above the app diff --git a/packages/SystemUI/res/xml/one_handed_tutorial.xml b/packages/SystemUI/res/xml/one_handed_tutorial.xml new file mode 100644 index 0000000000000..dc54caf0f14aa --- /dev/null +++ b/packages/SystemUI/res/xml/one_handed_tutorial.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java index c581ac6775322..264ace7493839 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java @@ -42,4 +42,10 @@ public interface OneHandedAnimationCallback { default void onOneHandedAnimationCancel( OneHandedAnimationController.OneHandedTransitionAnimator animator) { } + + /** + * Called when OneHanded animator is updating offset + */ + default void onTutorialAnimationUpdate(int offset) {} + } diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java index 1926c44abcba7..2b07ac3f4d8ab 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java @@ -28,7 +28,9 @@ import androidx.annotation.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import javax.inject.Inject; @@ -121,7 +123,8 @@ public class OneHandedAnimationController { private T mEndValue; private T mCurrentValue; - private OneHandedAnimationCallback mOneHandedAnimationCallback; + private final List mOneHandedAnimationCallbacks = + new ArrayList<>(); private OneHandedSurfaceTransactionHelper mSurfaceTransactionHelper; private OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; @@ -142,9 +145,11 @@ public class OneHandedAnimationController { @Override public void onAnimationStart(Animator animation) { mCurrentValue = mStartValue; - if (mOneHandedAnimationCallback != null) { - mOneHandedAnimationCallback.onOneHandedAnimationStart(this); - } + mOneHandedAnimationCallbacks.forEach( + (callback) -> { + callback.onOneHandedAnimationStart(this); + } + ); } @Override @@ -152,17 +157,21 @@ public class OneHandedAnimationController { mCurrentValue = mEndValue; final SurfaceControl.Transaction tx = newSurfaceControlTransaction(); onEndTransaction(mLeash, tx); - if (mOneHandedAnimationCallback != null) { - mOneHandedAnimationCallback.onOneHandedAnimationEnd(tx, this); - } + mOneHandedAnimationCallbacks.forEach( + (callback) -> { + callback.onOneHandedAnimationEnd(tx, this); + } + ); } @Override public void onAnimationCancel(Animator animation) { mCurrentValue = mEndValue; - if (mOneHandedAnimationCallback != null) { - mOneHandedAnimationCallback.onOneHandedAnimationCancel(this); - } + mOneHandedAnimationCallbacks.forEach( + (callback) -> { + callback.onOneHandedAnimationCancel(this); + } + ); } @Override @@ -173,6 +182,11 @@ public class OneHandedAnimationController { public void onAnimationUpdate(ValueAnimator animation) { applySurfaceControlTransaction(mLeash, newSurfaceControlTransaction(), animation.getAnimatedFraction()); + mOneHandedAnimationCallbacks.forEach( + (callback) -> { + callback.onTutorialAnimationUpdate(((Rect) mCurrentValue).top); + } + ); } void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) { @@ -192,9 +206,9 @@ public class OneHandedAnimationController { mSurfaceTransactionHelper = helper; } - OneHandedTransitionAnimator setOneHandedAnimationCallback( + OneHandedTransitionAnimator setOneHandedAnimationCallbacks( OneHandedAnimationCallback callback) { - mOneHandedAnimationCallback = callback; + mOneHandedAnimationCallbacks.add(callback); return this; } diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java index c0b9258f39fdf..8550959aa2c47 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java @@ -82,6 +82,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen private OneHandedAnimationController mAnimationController; private OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; + private OneHandedTutorialHandler mTutorialHandler; private List mTransitionCallbacks = new ArrayList<>(); @VisibleForTesting @@ -148,7 +149,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen @Inject public OneHandedDisplayAreaOrganizer(Context context, DisplayController displayController, - OneHandedAnimationController animationController) { + OneHandedAnimationController animationController, + OneHandedTutorialHandler tutorialHandler) { mUpdateHandler = new Handler(OneHandedThread.get().getLooper(), mUpdateCallback); mAnimationController = animationController; mDisplayController = displayController; @@ -157,6 +159,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen mEnterExitAnimationDurationMs = context.getResources().getInteger( com.android.systemui.R.integer.config_one_handed_translate_animation_duration); mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new; + mTutorialHandler = tutorialHandler; } @Override @@ -272,7 +275,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen mAnimationController.getAnimator(leash, fromBounds, toBounds); if (animator != null) { animator.setTransitionDirection(direction) - .setOneHandedAnimationCallback(mOneHandedAnimationCallback) + .setOneHandedAnimationCallbacks(mOneHandedAnimationCallback) + .setOneHandedAnimationCallbacks(mTutorialHandler.getAnimationCallback()) .setDuration(durationMs) .start(); } diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java index 71c5f80203301..ded386159dca5 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java @@ -53,8 +53,8 @@ import javax.inject.Singleton; */ @Singleton public class OneHandedGestureHandler implements OneHandedTransitionCallback, - NavigationModeController.ModeChangedListener, - DisplayChangeController.OnDisplayChangingListener { + NavigationModeController.ModeChangedListener, + DisplayChangeController.OnDisplayChangingListener { private static final String TAG = "OneHandedGestureHandler"; private static final boolean DEBUG_GESTURE = false; @@ -87,8 +87,8 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, * Constructor of OneHandedGestureHandler, we only handle the gesture of * {@link Display#DEFAULT_DISPLAY} * - * @param context {@link Context} - * @param displayController {@link DisplayController} + * @param context {@link Context} + * @param displayController {@link DisplayController} * @param navigationModeController {@link NavigationModeController} */ @Inject @@ -103,7 +103,7 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, mDragDistThreshold = context.getResources().getDimensionPixelSize( R.dimen.gestures_onehanded_drag_threshold); final float slop = ViewConfiguration.get(context).getScaledTouchSlop(); - mSquaredSlop = slop * slop; + mSquaredSlop = slop * slop; updateIsEnabled(); } diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java index 70a81aaed249a..51e5875868524 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java @@ -57,6 +57,7 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { private final OneHandedGestureHandler mGestureHandler; private final OneHandedTimeoutHandler mTimeoutHandler; private final OneHandedTouchHandler mTouchHandler; + private final OneHandedTutorialHandler mTutorialHandler; private final SysUiState mSysUiFlagContainer; private Context mContext; @@ -107,6 +108,7 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { DisplayController displayController, OneHandedDisplayAreaOrganizer displayAreaOrganizer, OneHandedTouchHandler touchHandler, + OneHandedTutorialHandler tutorialHandler, OneHandedGestureHandler gestureHandler, SysUiState sysUiState) { mContext = context; @@ -120,6 +122,7 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { context.getContentResolver()); mTimeoutHandler = OneHandedTimeoutHandler.get(); mTouchHandler = touchHandler; + mTutorialHandler = tutorialHandler; mGestureHandler = gestureHandler; updateOneHandedEnabled(); setupGestures(); @@ -230,6 +233,7 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { mDisplayAreaOrganizer.registerTransitionCallback(mTransitionCallback); mDisplayAreaOrganizer.registerTransitionCallback(mTouchHandler); mDisplayAreaOrganizer.registerTransitionCallback(mGestureHandler); + mDisplayAreaOrganizer.registerTransitionCallback(mTutorialHandler); } /** diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java index 3d4338c1e2200..d616a3a45b90d 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java @@ -58,6 +58,7 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpa OneHandedTouchEventCallback mTouchEventCallback; private boolean mIsEnabled; + private boolean mIsOnStopTransitioning; private boolean mIsInOutsideRegion; @Inject @@ -96,8 +97,9 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpa case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { mTimeoutHandler.resetTimer(); - if (mIsInOutsideRegion) { + if (mIsInOutsideRegion && !mIsOnStopTransitioning) { mTouchEventCallback.onStop(); + mIsOnStopTransitioning = true; } // Reset flag for next operation mIsInOutsideRegion = false; @@ -146,6 +148,7 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpa @Override public void onStopFinished(Rect bounds) { mLastUpdatedBounds.set(bounds); + mIsOnStopTransitioning = false; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java new file mode 100644 index 0000000000000..8a67da53e6a2a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2020 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.onehanded; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.graphics.Point; +import android.graphics.Rect; +import android.os.Handler; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; + +import com.android.systemui.Dumpable; +import com.android.systemui.R; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Manages the user tutorial handling for One Handed operations, including animations synchronized + * with one-handed translation. + * Refer {@link OneHandedGestureHandler} and {@link OneHandedTouchHandler} to see start and stop + * one handed gesture + */ +@Singleton +public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Dumpable { + private static final String TAG = "OneHandedTutorialHandler"; + private final Rect mLastUpdatedBounds = new Rect(); + private final WindowManager mWindowManager; + + private View mTutorialView; + private Point mDisplaySize = new Point(); + private Handler mUpdateHandler; + + /** + * Container of the tutorial panel showing at outside region when one handed starting + */ + private ViewGroup mTargetViewContainer; + private int mTutorialAreaHeight; + + private final OneHandedAnimationCallback mAnimationCallback = new OneHandedAnimationCallback() { + @Override + public void onTutorialAnimationUpdate(int offset) { + mUpdateHandler.post(() -> onAnimationUpdate(offset)); + } + }; + + @Inject + public OneHandedTutorialHandler(Context context) { + context.getDisplay().getRealSize(mDisplaySize); + mUpdateHandler = new Handler(); + mWindowManager = context.getSystemService(WindowManager.class); + mTargetViewContainer = new FrameLayout(context); + mTargetViewContainer.setClipChildren(false); + mTutorialAreaHeight = Math.round(mDisplaySize.y * context.getResources().getFraction( + R.fraction.config_one_handed_offset, 1, 1)); + mTutorialView = LayoutInflater.from(context).inflate(R.xml.one_handed_tutorial, null); + mTargetViewContainer.addView(mTutorialView); + createOrUpdateTutorialTarget(); + } + + @Override + public void onStartFinished(Rect bounds) { + mUpdateHandler.post(() -> updateFinished(View.VISIBLE, 0f)); + } + + @Override + public void onStopFinished(Rect bounds) { + mUpdateHandler.post(() -> updateFinished( + View.INVISIBLE, -mTargetViewContainer.getHeight())); + } + + private void updateFinished(int visible, float finalPosition) { + mTargetViewContainer.setVisibility(visible); + mTargetViewContainer.setTranslationY(finalPosition); + } + + /** + * Adds the tutorial target view to the WindowManager and update its layout, so it's ready + * to be animated in. + */ + private void createOrUpdateTutorialTarget() { + mUpdateHandler.post(() -> { + if (!mTargetViewContainer.isAttachedToWindow()) { + mTargetViewContainer.setVisibility(View.INVISIBLE); + + try { + mWindowManager.addView(mTargetViewContainer, getTutorialTargetLayoutParams()); + } catch (IllegalStateException e) { + // This shouldn't happen, but if the target is already added, just update its + // layout params. + mWindowManager.updateViewLayout( + mTargetViewContainer, getTutorialTargetLayoutParams()); + } + } else { + mWindowManager.updateViewLayout(mTargetViewContainer, + getTutorialTargetLayoutParams()); + } + }); + } + + OneHandedAnimationCallback getAnimationCallback() { + return mAnimationCallback; + } + + /** + * Returns layout params for the dismiss target, using the latest display metrics. + */ + private WindowManager.LayoutParams getTutorialTargetLayoutParams() { + final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + mDisplaySize.x, mTutorialAreaHeight, 0, 0, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.TRANSLUCENT); + lp.gravity = Gravity.TOP | Gravity.LEFT; + lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; + lp.setFitInsetsTypes(0 /* types */); + lp.setTitle("one-handed-tutorial-overlay"); + + return lp; + } + + @Override + public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { + final String innerPrefix = " "; + pw.println(TAG + "states: "); + pw.print(innerPrefix + "mLastUpdatedBounds="); + pw.println(mLastUpdatedBounds); + } + + private void onAnimationUpdate(float value) { + mTargetViewContainer.setVisibility(View.VISIBLE); + mTargetViewContainer.setTransitionGroup(true); + mTargetViewContainer.setTranslationY(value - mTargetViewContainer.getHeight()); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java index 583d0692565fd..73164b520b9d9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java @@ -44,6 +44,7 @@ public class OneHandedAnimationControllerTest extends OneHandedTestCase { private static final int TEST_BOUNDS_HEIGHT = 1000; OneHandedAnimationController mOneHandedAnimationController; + OneHandedTutorialHandler mTutorialHandler; @Mock private SurfaceControl mMockLeash; @@ -52,6 +53,7 @@ public class OneHandedAnimationControllerTest extends OneHandedTestCase { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + mTutorialHandler = new OneHandedTutorialHandler(mContext); mOneHandedAnimationController = new OneHandedAnimationController( new OneHandedSurfaceTransactionHelper(mContext)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java index 3231b2852e7c4..a989cd1f9c404 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java @@ -61,6 +61,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { DisplayAreaInfo mDisplayAreaInfo; Display mDisplay; OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer; + OneHandedTutorialHandler mTutorialHandler; OneHandedAnimationController.OneHandedTransitionAnimator mFakeAnimator; WindowContainerToken mToken; SurfaceControl mLeash; @@ -97,14 +98,15 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { mMockSurfaceTransactionHelper); when(mMockAnimator.isRunning()).thenReturn(true); when(mMockAnimator.setDuration(anyInt())).thenReturn(mFakeAnimator); - when(mMockAnimator.setOneHandedAnimationCallback(any())).thenReturn(mFakeAnimator); + when(mMockAnimator.setOneHandedAnimationCallbacks(any())).thenReturn(mFakeAnimator); when(mMockAnimator.setTransitionDirection(anyInt())).thenReturn(mFakeAnimator); when(mMockLeash.getWidth()).thenReturn(DISPLAY_WIDTH); when(mMockLeash.getHeight()).thenReturn(DISPLAY_HEIGHT); mDisplayAreaOrganizer = new OneHandedDisplayAreaOrganizer(mContext, mMockDisplayController, - mMockAnimationController); + mMockAnimationController, + mTutorialHandler); mUpdateHandler = mDisplayAreaOrganizer.getUpdateHandler(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java index 3b284b14c36f4..694f51be4e30e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java @@ -48,6 +48,7 @@ import org.mockito.MockitoAnnotations; public class OneHandedGestureHandlerTest extends OneHandedTestCase { Instrumentation mInstrumentation; OneHandedTouchHandler mTouchHandler; + OneHandedTutorialHandler mTutorialHandler; OneHandedGestureHandler mGestureHandler; OneHandedManagerImpl mOneHandedManagerImpl; @Mock @@ -62,13 +63,15 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mInstrumentation = InstrumentationRegistry.getInstrumentation(); - mTouchHandler = Mockito.spy(new OneHandedTouchHandler()); + mTouchHandler = new OneHandedTouchHandler(); + mTutorialHandler = new OneHandedTutorialHandler(mContext); mGestureHandler = Mockito.spy(new OneHandedGestureHandler( mContext, mMockDisplayController, mMockNavigationModeController)); mOneHandedManagerImpl = new OneHandedManagerImpl(mInstrumentation.getContext(), mMockDisplayController, mMockDisplayAreaOrganizer, mTouchHandler, + mTutorialHandler, mGestureHandler, mMockSysUiState); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java index 55bec54eacb8f..3418ebf75e0cf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java @@ -57,6 +57,8 @@ public class OneHandedManagerImplTest extends OneHandedTestCase { @Mock OneHandedTouchHandler mMockTouchHandler; @Mock + OneHandedTutorialHandler mMockTutorialHandler; + @Mock OneHandedGestureHandler mMockGestureHandler; @Mock SysUiState mMockSysUiState; @@ -69,6 +71,7 @@ public class OneHandedManagerImplTest extends OneHandedTestCase { mMockDisplayController, mMockDisplayAreaOrganizer, mMockTouchHandler, + mMockTutorialHandler, mMockGestureHandler, mMockSysUiState); mTimeoutHandler = Mockito.spy(OneHandedTimeoutHandler.get()); @@ -84,7 +87,7 @@ public class OneHandedManagerImplTest extends OneHandedTestCase { final OneHandedAnimationController animationController = new OneHandedAnimationController( transactionHelper); OneHandedDisplayAreaOrganizer displayAreaOrganizer = new OneHandedDisplayAreaOrganizer( - mContext, mMockDisplayController, animationController); + mContext, mMockDisplayController, animationController, mMockTutorialHandler); assertThat(displayAreaOrganizer.isInOneHanded()).isFalse(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java index 3a4ba6a213dc0..fdb28d3d43b5a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java @@ -46,6 +46,7 @@ import org.mockito.MockitoAnnotations; public class OneHandedTouchHandlerTest extends OneHandedTestCase { Instrumentation mInstrumentation; OneHandedTouchHandler mTouchHandler; + OneHandedTutorialHandler mTutorialHandler; OneHandedGestureHandler mGestureHandler; OneHandedManagerImpl mOneHandedManagerImpl; @Mock @@ -68,13 +69,15 @@ public class OneHandedTouchHandlerTest extends OneHandedTestCase { mMockDisplayController, mMockDisplayAreaOrganizer, mTouchHandler, + mTutorialHandler, mGestureHandler, mMockSysUiState); } @Test public void testOneHandedManager_registerForDisplayAreaOrganizer() { - verify(mMockDisplayAreaOrganizer, times(1)).registerTransitionCallback(mTouchHandler); + verify(mMockDisplayAreaOrganizer, times(1)) + .registerTransitionCallback(mTouchHandler); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java new file mode 100644 index 0000000000000..f4aa00eaf02fd --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2020 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.onehanded; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.app.Instrumentation; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.systemui.model.SysUiState; +import com.android.systemui.statusbar.phone.NavigationModeController; +import com.android.wm.shell.common.DisplayController; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class OneHandedTutorialHandlerTest extends OneHandedTestCase { + Instrumentation mInstrumentation; + OneHandedTouchHandler mTouchHandler; + OneHandedTutorialHandler mTutorialHandler; + OneHandedGestureHandler mGestureHandler; + OneHandedManagerImpl mOneHandedManagerImpl; + @Mock + DisplayController mMockDisplayController; + @Mock + NavigationModeController mMockNavigationModeController; + @Mock + OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer; + @Mock + SysUiState mMockSysUiState; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mTouchHandler = new OneHandedTouchHandler(); + mTutorialHandler = Mockito.spy(new OneHandedTutorialHandler(mContext)); + mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController, + mMockNavigationModeController); + mOneHandedManagerImpl = new OneHandedManagerImpl(mInstrumentation.getContext(), + mMockDisplayController, + mMockDisplayAreaOrganizer, + mTouchHandler, + mTutorialHandler, + mGestureHandler, + mMockSysUiState); + } + + @Test + public void testOneHandedManager_registerForDisplayAreaOrganizer() { + verify(mMockDisplayAreaOrganizer, times(1)) + .registerTransitionCallback(mTutorialHandler); + } +}