From 8a2c1cbc5a4731ac5b95a8ade0be6b7074fdf966 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Fri, 16 Jul 2021 12:15:35 -1000 Subject: [PATCH] Add taskbar stashing feedforward, i.e. hint at upcoming stash/unstash Also fix unstashing not working in 3P launchers by moving the unstash call from LauncherTaskbarUIController to TaskbarActivityContext Test: long press taskbar background and stashed handle, watch it hint towards the new stashed/unstashed state respectively and then complete the animation when the long press is triggered Fixes: 193926311 Fixes: 192926350 Change-Id: I0e538be9129bf5c600d07f360b8106d7077862ad --- .../taskbar/LauncherTaskbarUIController.java | 5 -- .../taskbar/StashedHandleViewController.java | 20 +++++++ .../taskbar/TaskbarActivityContext.java | 16 ++++++ .../launcher3/taskbar/TaskbarManager.java | 5 ++ .../taskbar/TaskbarStashController.java | 54 +++++++++++++++++++ .../taskbar/TaskbarUIController.java | 4 -- .../launcher3/taskbar/TaskbarView.java | 9 ++++ .../taskbar/TaskbarViewController.java | 36 +++++++++++++ .../quickstep/BaseActivityInterface.java | 8 --- .../quickstep/LauncherActivityInterface.java | 9 ---- .../quickstep/TouchInteractionService.java | 2 +- .../TaskbarStashInputConsumer.java | 48 +++++++++++++++-- 12 files changed, 184 insertions(+), 32 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 8b11154636..b5c834dd31 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -233,11 +233,6 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } } - @Override - public boolean onLongPressToUnstashTaskbar() { - return mControllers.taskbarStashController.onLongPressToUnstashTaskbar(); - } - /** * @param ev MotionEvent in screen coordinates. * @return Whether any Taskbar item could handle the given MotionEvent if given the chance. diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java index 8c14ff6d16..df37261c8a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java @@ -40,6 +40,8 @@ public class StashedHandleViewController { private final int mStashedHandleHeight; private final AnimatedFloat mTaskbarStashedHandleAlpha = new AnimatedFloat( this::updateStashedHandleAlpha); + private final AnimatedFloat mTaskbarStashedHandleHintScale = new AnimatedFloat( + this::updateStashedHandleHintScale); // Initialized in init. private TaskbarControllers mControllers; @@ -64,6 +66,7 @@ public class StashedHandleViewController { mStashedHandleView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarSize; updateStashedHandleAlpha(); + mTaskbarStashedHandleHintScale.updateValue(1f); final int stashedTaskbarHeight = mControllers.taskbarStashController.getStashedHeight(); mStashedHandleView.setOutlineProvider(new ViewOutlineProvider() { @@ -80,12 +83,24 @@ public class StashedHandleViewController { outline.setRoundRect(mStashedHandleBounds, mStashedHandleRadius); } }); + + mStashedHandleView.addOnLayoutChangeListener((view, i, i1, i2, i3, i4, i5, i6, i7) -> { + final int stashedCenterX = view.getWidth() / 2; + final int stashedCenterY = view.getHeight() - stashedTaskbarHeight / 2; + + view.setPivotX(stashedCenterX); + view.setPivotY(stashedCenterY); + }); } public AnimatedFloat getStashedHandleAlpha() { return mTaskbarStashedHandleAlpha; } + public AnimatedFloat getStashedHandleHintScale() { + return mTaskbarStashedHandleHintScale; + } + /** * Creates and returns a {@link RevealOutlineAnimation} Animator that updates the stashed handle * shape and size. When stashed, the shape is a thin rounded pill. When unstashed, the shape @@ -105,4 +120,9 @@ public class StashedHandleViewController { protected void updateStashedHandleAlpha() { mStashedHandleView.setAlpha(mTaskbarStashedHandleAlpha.value); } + + protected void updateStashedHandleHintScale() { + mStashedHandleView.setScaleX(mTaskbarStashedHandleHintScale.value); + mStashedHandleView.setScaleY(mTaskbarStashedHandleHintScale.value); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index e11f4c17f1..dbe528f6af 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -332,4 +332,20 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ AbstractFloatingView.closeAllOpenViews(this); } + + /** + * Called when we detect a long press in the nav region before passing the gesture slop. + * @return Whether taskbar handled the long press, and thus should cancel the gesture. + */ + public boolean onLongPressToUnstashTaskbar() { + return mControllers.taskbarStashController.onLongPressToUnstashTaskbar(); + } + + /** + * Called when we detect a motion down or up/cancel in the nav region while stashed. + * @param animateForward Whether to animate towards the unstashed hint state or back to stashed. + */ + public void startTaskbarUnstashHint(boolean animateForward) { + mControllers.taskbarStashController.startUnstashHint(animateForward); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index a226db9f98..45eabedb9f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -27,6 +27,7 @@ import android.hardware.display.DisplayManager; import android.view.Display; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; @@ -188,4 +189,8 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen mDisplayController.removeChangeListener(this); mSysUINavigationMode.removeModeChangeListener(this); } + + public @Nullable TaskbarActivityContext getCurrentActivityContext() { + return mTaskbarActivityContext; + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 6e20398174..f7e675da11 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -23,6 +23,7 @@ import android.animation.AnimatorSet; import android.annotation.Nullable; import android.content.SharedPreferences; import android.content.res.Resources; +import android.view.ViewConfiguration; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -46,6 +47,22 @@ public class TaskbarStashController { */ private static final float STASHED_TASKBAR_SCALE = 0.5f; + /** + * How long the hint animation plays, starting on motion down. + */ + private static final long TASKBAR_HINT_STASH_DURATION = + ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT; + + /** + * The scale that TaskbarView animates to when hinting towards the stashed state. + */ + private static final float STASHED_TASKBAR_HINT_SCALE = 0.9f; + + /** + * The scale that the stashed handle animates to when hinting towards the unstashed state. + */ + private static final float UNSTASHED_TASKBAR_HANDLE_HINT_SCALE = 1.1f; + /** * The SharedPreferences key for whether user has manually stashed the taskbar. */ @@ -71,6 +88,7 @@ public class TaskbarStashController { private AnimatedFloat mIconTranslationYForStash; // Stashed handle properties. private AnimatedFloat mTaskbarStashedHandleAlpha; + private AnimatedFloat mTaskbarStashedHandleHintScale; /** Whether the user has manually invoked taskbar stashing, which we persist. */ private boolean mIsStashedInApp; @@ -102,6 +120,7 @@ public class TaskbarStashController { StashedHandleViewController stashedHandleController = controllers.stashedHandleViewController; mTaskbarStashedHandleAlpha = stashedHandleController.getStashedHandleAlpha(); + mTaskbarStashedHandleHintScale = stashedHandleController.getStashedHandleHintScale(); mIsStashedInApp = supportsStashing() && mPrefs.getBoolean(SHARED_PREFS_STASHED_KEY, DEFAULT_STASHED_PREF); @@ -240,6 +259,9 @@ public class TaskbarStashController { if (stashedHandleRevealAnim != null) { fullLengthAnimatorSet.play(stashedHandleRevealAnim); } + // Return the stashed handle to its default scale in case it was changed as part of the + // feedforward hint. Note that the reveal animation above also visually scales it. + fullLengthAnimatorSet.play(mTaskbarStashedHandleHintScale.animateToValue(1f)); fullLengthAnimatorSet.setDuration(duration); firstHalfAnimatorSet.setDuration((long) (duration * firstHalfDurationScale)); @@ -265,4 +287,36 @@ public class TaskbarStashController { }); return mAnimator; } + + /** + * Creates and starts a partial stash animation, hinting at the new state that will trigger when + * long press is detected. + * @param animateForward Whether we are going towards the new stashed state or returning to the + * unstashed state. + */ + public void startStashHint(boolean animateForward) { + if (isStashed() || !supportsStashing()) { + // Already stashed, no need to hint in that direction. + return; + } + mIconScaleForStash.animateToValue( + animateForward ? STASHED_TASKBAR_HINT_SCALE : 1) + .setDuration(TASKBAR_HINT_STASH_DURATION).start(); + } + + /** + * Creates and starts a partial unstash animation, hinting at the new state that will trigger + * when long press is detected. + * @param animateForward Whether we are going towards the new unstashed state or returning to + * the stashed state. + */ + public void startUnstashHint(boolean animateForward) { + if (!isStashed()) { + // Already unstashed, no need to hint in that direction. + return; + } + mTaskbarStashedHandleHintScale.animateToValue( + animateForward ? UNSTASHED_TASKBAR_HANDLE_HINT_SCALE : 1) + .setDuration(TASKBAR_HINT_STASH_DURATION).start(); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index 6d0e3c6baf..260cedc706 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -33,8 +33,4 @@ public class TaskbarUIController { } protected void updateContentInsets(Rect outContentInsets) { } - - protected boolean onLongPressToUnstashTaskbar() { - return false; - } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index 820d40af27..6f53f2b60c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -222,6 +222,15 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar return super.dispatchTouchEvent(ev); } + @Override + public boolean onTouchEvent(MotionEvent event) { + if (!mTouchEnabled) { + return true; + } + mControllerCallbacks.onTouchEvent(event); + return super.onTouchEvent(event); + } + public void setTouchesEnabled(boolean touchEnabled) { this.mTouchEnabled = touchEnabled; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index 94c0ebeaf6..6b95f08090 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -17,14 +17,17 @@ package com.android.launcher3.taskbar; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X; +import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.quickstep.AnimatedFloat.VALUE; import android.graphics.Rect; +import android.view.MotionEvent; import android.view.View; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.model.data.ItemInfo; @@ -188,6 +191,11 @@ public class TaskbarViewController { * Callbacks for {@link TaskbarView} to interact with its controller. */ public class TaskbarViewCallbacks { + private final float mSquaredTouchSlop = Utilities.squaredTouchSlop(mActivity); + + private float mDownX, mDownY; + private boolean mCanceledStashHint; + public View.OnClickListener getIconOnClickListener() { return mActivity::onTaskbarIconClicked; } @@ -199,5 +207,33 @@ public class TaskbarViewController { public View.OnLongClickListener getBackgroundOnLongClickListener() { return view -> mControllers.taskbarStashController.updateAndAnimateIsStashedInApp(true); } + + public void onTouchEvent(MotionEvent motionEvent) { + final float x = motionEvent.getRawX(); + final float y = motionEvent.getRawY(); + switch (motionEvent.getAction()) { + case MotionEvent.ACTION_DOWN: + mDownX = x; + mDownY = y; + mControllers.taskbarStashController.startStashHint(/* animateForward = */ true); + mCanceledStashHint = false; + break; + case MotionEvent.ACTION_MOVE: + if (!mCanceledStashHint + && squaredHypot(mDownX - x, mDownY - y) > mSquaredTouchSlop) { + mControllers.taskbarStashController.startStashHint( + /* animateForward= */ false); + mCanceledStashHint = true; + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + if (!mCanceledStashHint) { + mControllers.taskbarStashController.startStashHint( + /* animateForward= */ false); + } + break; + } + } } } diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index 1412b1add6..2699b0795b 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -363,14 +363,6 @@ public abstract class BaseActivityInterface mSquaredTouchSlop) { + mTaskbarActivityContext.startTaskbarUnstashHint( + /* animateForward = */ false); + mCanceledUnstashHint = true; + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + if (!mCanceledUnstashHint) { + mTaskbarActivityContext.startTaskbarUnstashHint( + /* animateForward = */ false); + } + break; + } + } } } private void onLongPressDetected(MotionEvent motionEvent) { - if (mActivityInterface.onLongPressToUnstashTaskbar()) { + if (mTaskbarActivityContext != null + && mTaskbarActivityContext.onLongPressToUnstashTaskbar()) { setActive(motionEvent); } }