Merge "Have responsive taskbar UI during swipe up gesture." into tm-qpr-dev am: caa398ed35

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/20333665

Change-Id: Id96043e6aa186eb04bc5d171fdb72159ae7e4c42
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Jon Miranda
2022-11-08 18:26:43 +00:00
committed by Automerger Merge Worker
12 changed files with 327 additions and 20 deletions
@@ -192,7 +192,15 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
*/
public Animator createAnimToLauncher(@NonNull LauncherState toState,
@NonNull RecentsAnimationCallbacks callbacks, long duration) {
return mTaskbarLauncherStateController.createAnimToLauncher(toState, callbacks, duration);
AnimatorSet set = new AnimatorSet();
Animator taskbarState = mTaskbarLauncherStateController
.createAnimToLauncher(toState, callbacks, duration);
long halfDuration = Math.round(duration * 0.5f);
Animator translation =
mControllers.taskbarTranslationController.createAnimToLauncher(halfDuration);
set.playTogether(taskbarState, translation);
return set;
}
public boolean isDraggingItem() {
@@ -30,6 +30,7 @@ import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.RevealOutlineAnimation;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
@@ -66,6 +67,7 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
// Initialized in init.
private TaskbarControllers mControllers;
private int mTaskbarSize;
// The bounds we want to clip to in the settled state when showing the stashed handle.
private final Rect mStashedHandleBounds = new Rect();
@@ -96,15 +98,18 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
Resources resources = mActivity.getResources();
if (isPhoneGestureNavMode(mActivity.getDeviceProfile())) {
mStashedHandleView.getLayoutParams().height =
resources.getDimensionPixelSize(R.dimen.taskbar_size);
mTaskbarSize = resources.getDimensionPixelSize(R.dimen.taskbar_size);
mStashedHandleWidth =
resources.getDimensionPixelSize(R.dimen.taskbar_stashed_small_screen);
} else {
mStashedHandleView.getLayoutParams().height = deviceProfile.taskbarSize;
mTaskbarSize = deviceProfile.taskbarSize;
mStashedHandleWidth = resources
.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width);
}
int taskbarBottomMargin = DisplayController.isTransientTaskbar(mActivity)
? resources.getDimensionPixelSize(R.dimen.transient_taskbar_margin)
: 0;
mStashedHandleView.getLayoutParams().height = mTaskbarSize + taskbarBottomMargin;
mTaskbarStashedHandleAlpha.get(ALPHA_INDEX_STASHED).setValue(
isPhoneGestureNavMode(deviceProfile) ? 1 : 0);
@@ -181,9 +186,17 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
* morphs into the size of where the taskbar icons will be.
*/
public Animator createRevealAnimToIsStashed(boolean isStashed) {
Rect visualBounds = new Rect(mControllers.taskbarViewController.getIconLayoutBounds());
if (DisplayController.isTransientTaskbar(mActivity)) {
// Account for the full visual height of the transient taskbar.
int heightDiff = (mTaskbarSize - visualBounds.height()) / 2;
visualBounds.top -= heightDiff;
visualBounds.bottom += heightDiff;
}
final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider(
mStashedHandleRadius, mStashedHandleRadius,
mControllers.taskbarViewController.getIconLayoutBounds(), mStashedHandleBounds);
mStashedHandleRadius, mStashedHandleRadius, visualBounds, mStashedHandleBounds);
boolean isReversed = !isStashed;
boolean changingDirection = mWasLastRevealAnimReversed != isReversed;
@@ -219,6 +232,13 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
mStashedHandleView.setScaleY(mTaskbarStashedHandleHintScale.value);
}
/**
* Sets the translation of the stashed handle during the swipe up gesture.
*/
protected void setTranslationYForSwipe(float transY) {
mStashedHandleView.setTranslationY(transY);
}
/**
* Should be called when the home button is disabled, so we can hide this handle as well.
*/
@@ -79,6 +79,7 @@ import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.AutohideSuspendFlag;
import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
import com.android.launcher3.testing.TestLogging;
@@ -224,6 +225,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
new TaskbarAllAppsController(),
new TaskbarInsetsController(this),
new VoiceInteractionWindowController(this),
new TaskbarTranslationController(this),
isDesktopMode
? new DesktopTaskbarRecentAppsController(this)
: TaskbarRecentAppsController.DEFAULT);
@@ -835,6 +837,20 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
}
/**
* Called to start the taskbar translation spring to its settled translation (0).
*/
public void startTranslationSpring() {
mControllers.taskbarTranslationController.startSpring();
}
/**
* Returns a callback to help monitor the swipe gesture.
*/
public TransitionCallback getTranslationCallbacks() {
return mControllers.taskbarTranslationController.getTransitionCallback();
}
/**
* Called when a transient Autohide flag suspend status changes.
*/
@@ -34,6 +34,7 @@ class TaskbarBackgroundRenderer(context: TaskbarActivityContext) {
val paint: Paint = Paint()
var backgroundHeight = context.deviceProfile.taskbarSize.toFloat()
var translationYForSwipe = 0f
private var maxBackgroundHeight = context.deviceProfile.taskbarSize.toFloat()
private val transientBackgroundBounds = context.transientTaskbarBounds
@@ -114,11 +115,13 @@ class TaskbarBackgroundRenderer(context: TaskbarActivityContext) {
canvas.translate(canvas.width - rightCornerRadius, -rightCornerRadius)
canvas.drawPath(invertedRightCornerPath, paint)
} else {
// Approximates the stash/unstash animation to transform the background.
val scaleFactor = backgroundHeight / maxBackgroundHeight
val width = transientBackgroundBounds.width()
val widthScale = mapToRange(scaleFactor, 0f, 1f, 0.4f, 1f, Interpolators.LINEAR)
val newWidth = widthScale * width
val delta = width - newWidth
canvas.translate(0f, bottomMargin * ((1f - scaleFactor) / 2f))
// Draw shadow.
val shadowAlpha = mapToRange(paint.alpha.toFloat(), 0f, 255f, 0f, 25f,
@@ -132,9 +135,9 @@ class TaskbarBackgroundRenderer(context: TaskbarActivityContext) {
canvas.drawRoundRect(
transientBackgroundBounds.left + (delta / 2f),
0f,
translationYForSwipe,
transientBackgroundBounds.right - (delta / 2f),
backgroundHeight,
backgroundHeight + translationYForSwipe,
radius, radius, paint
)
}
@@ -56,6 +56,7 @@ public class TaskbarControllers {
public final TaskbarInsetsController taskbarInsetsController;
public final VoiceInteractionWindowController voiceInteractionWindowController;
public final TaskbarRecentAppsController taskbarRecentAppsController;
public final TaskbarTranslationController taskbarTranslationController;
public final TaskbarOverlayController taskbarOverlayController;
@Nullable private LoggableTaskbarController[] mControllersToLog = null;
@@ -92,6 +93,7 @@ public class TaskbarControllers {
TaskbarAllAppsController taskbarAllAppsController,
TaskbarInsetsController taskbarInsetsController,
VoiceInteractionWindowController voiceInteractionWindowController,
TaskbarTranslationController taskbarTranslationController,
TaskbarRecentAppsController taskbarRecentAppsController) {
this.taskbarActivityContext = taskbarActivityContext;
this.taskbarDragController = taskbarDragController;
@@ -113,6 +115,7 @@ public class TaskbarControllers {
this.taskbarAllAppsController = taskbarAllAppsController;
this.taskbarInsetsController = taskbarInsetsController;
this.voiceInteractionWindowController = voiceInteractionWindowController;
this.taskbarTranslationController = taskbarTranslationController;
this.taskbarRecentAppsController = taskbarRecentAppsController;
}
@@ -144,6 +147,7 @@ public class TaskbarControllers {
taskbarInsetsController.init(this);
voiceInteractionWindowController.init(this);
taskbarRecentAppsController.init(this);
taskbarTranslationController.init(this);
mControllersToLog = new LoggableTaskbarController[] {
taskbarDragController, navButtonController, navbarButtonsViewController,
@@ -151,7 +155,7 @@ public class TaskbarControllers {
taskbarUnfoldAnimationController, taskbarKeyguardController,
stashedHandleViewController, taskbarStashController, taskbarEduController,
taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController,
voiceInteractionWindowController
voiceInteractionWindowController, taskbarTranslationController
};
mBackgroundRendererControllers = new BackgroundRendererController[] {
taskbarDragLayerController, taskbarScrimViewController,
@@ -175,6 +175,14 @@ public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> {
invalidate();
}
/*
* Sets the translation of the background during the swipe up gesture.
*/
protected void setBackgroundTranslationYForSwipe(float translationY) {
mBackgroundRenderer.setTranslationYForSwipe(translationY);
invalidate();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
@@ -150,6 +150,13 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
updateNavBarDarkIntensityMultiplier();
}
/**
* Sets the translation of the background during the swipe up gesture.
*/
public void setTranslationYForSwipe(float transY) {
mTaskbarDragLayer.setBackgroundTranslationYForSwipe(transY);
}
private void updateBackgroundOffset() {
mTaskbarDragLayer.setTaskbarBackgroundOffset(mBgOffset.value);
@@ -0,0 +1,197 @@
/*
* 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.launcher3.taskbar;
import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
import static com.android.quickstep.AnimatedFloat.VALUE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.SpringForce;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.AnimatedFloat;
import java.io.PrintWriter;
/**
* Class responsible for translating the transient taskbar UI during a swipe gesture.
*
* The translation is controlled, in priority order:
* - animation to home
* - a spring animation
* - controlled by user
*
* The spring animation will play start once the user lets go or when user pauses to go to overview.
* When the user goes home, the stash animation will play.
*/
public class TaskbarTranslationController implements TaskbarControllers.LoggableTaskbarController {
private final TaskbarActivityContext mContext;
private TaskbarControllers mControllers;
private final AnimatedFloat mTranslationYForSwipe = new AnimatedFloat(
this::updateTranslationYForSwipe);
private boolean mHasSprungOnceThisGesture;
private @Nullable ValueAnimator mSpringBounce;
private boolean mGestureEnded;
private boolean mAnimationToHomeRunning;
private final boolean mIsTransientTaskbar;
private final TransitionCallback mCallback;
public TaskbarTranslationController(TaskbarActivityContext context) {
mContext = context;
mIsTransientTaskbar = DisplayController.isTransientTaskbar(mContext);
mCallback = new TransitionCallback();
}
/**
* Initialization method.
*/
public void init(TaskbarControllers controllers) {
mControllers = controllers;
}
/**
* Called to cancel any existing animations.
*/
public void cancelAnimationIfExists() {
if (mSpringBounce != null) {
mSpringBounce.cancel();
mSpringBounce = null;
}
reset();
}
private void updateTranslationYForSwipe() {
if (!mIsTransientTaskbar) {
return;
}
float transY = mTranslationYForSwipe.value;
mControllers.stashedHandleViewController.setTranslationYForSwipe(transY);
mControllers.taskbarViewController.setTranslationYForSwipe(transY);
mControllers.taskbarDragLayerController.setTranslationYForSwipe(transY);
}
/**
* Starts a spring aniamtion to set the views back to the resting state.
*/
public void startSpring() {
if (mHasSprungOnceThisGesture || mAnimationToHomeRunning) {
return;
}
mSpringBounce = new SpringAnimationBuilder(mContext)
.setStartValue(mTranslationYForSwipe.value)
.setEndValue(0)
.setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY)
.setStiffness(SpringForce.STIFFNESS_LOW)
.build(mTranslationYForSwipe, VALUE);
mSpringBounce.addListener(forEndCallback(() -> {
if (mGestureEnded) {
reset();
}
}));
mSpringBounce.start();
mHasSprungOnceThisGesture = true;
}
private void reset() {
mGestureEnded = false;
mHasSprungOnceThisGesture = false;
}
/**
* Returns a callback to help monitor the swipe gesture.
*/
public TransitionCallback getTransitionCallback() {
return mCallback;
}
/**
* Returns an animation to reset the taskbar translation for animation back to launcher.
*/
public ObjectAnimator createAnimToLauncher(long duration) {
ObjectAnimator animator = ObjectAnimator.ofFloat(mTranslationYForSwipe, VALUE, 0);
animator.setInterpolator(Interpolators.LINEAR);
animator.setDuration(duration);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
cancelAnimationIfExists();
mAnimationToHomeRunning = true;
}
@Override
public void onAnimationEnd(Animator animation) {
mAnimationToHomeRunning = false;
reset();
}
});
return animator;
}
/**
* Helper class to communicate to/from the input consumer.
*/
public class TransitionCallback {
/**
* Called when there is movement to move the taskbar.
*/
public void onActionMove(float dY) {
if (mAnimationToHomeRunning
|| (mHasSprungOnceThisGesture && !mGestureEnded)) {
return;
}
mTranslationYForSwipe.updateValue(dY);
}
/**
* Called when swipe gesture has ended.
*/
public void onActionEnd() {
if (mHasSprungOnceThisGesture) {
reset();
} else {
mGestureEnded = true;
startSpring();
}
}
}
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
pw.println(prefix + "TaskbarTranslationController:");
pw.println(prefix + "\tmTranslationYForSwipe=" + mTranslationYForSwipe.value);
pw.println(prefix + "\tmHasSprungOnceThisGesture=" + mHasSprungOnceThisGesture);
pw.println(prefix + "\tmAnimationToHomeRunning=" + mAnimationToHomeRunning);
pw.println(prefix + "\tmGestureEnded=" + mGestureEnded);
pw.println(prefix + "\tmSpringBounce is running=" + (mSpringBounce != null
&& mSpringBounce.isRunning()));
}
}
@@ -105,6 +105,13 @@ public class TaskbarUIController {
return mControllers.taskbarStashController.isStashed();
}
/**
* Called at the end of the swipe gesture on Transient taskbar.
*/
public void startTranslationSpring() {
mControllers.taskbarActivityContext.startTranslationSpring();
}
/*
* @param ev MotionEvent in screen coordinates.
* @return Whether any Taskbar item could handle the given MotionEvent if given the chance.
@@ -91,6 +91,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
this::updateTranslationY);
private AnimatedFloat mTaskbarNavButtonTranslationY;
private AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay;
private float mTaskbarIconTranslationYForSwipe;
private final int mTaskbarBottomMargin;
@@ -260,9 +261,18 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
mTaskbarView.setScaleY(scale);
}
/**
* Sets the translation of the TaskbarView during the swipe up gesture.
*/
public void setTranslationYForSwipe(float transY) {
mTaskbarIconTranslationYForSwipe = transY;
updateTranslationY();
}
private void updateTranslationY() {
mTaskbarView.setTranslationY(mTaskbarIconTranslationYForHome.value
+ mTaskbarIconTranslationYForStash.value);
+ mTaskbarIconTranslationYForStash.value
+ mTaskbarIconTranslationYForSwipe);
}
private void updateIconsBackground() {
@@ -99,6 +99,7 @@ import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.tracing.InputConsumerProto;
import com.android.launcher3.tracing.SwipeHandlerProto;
import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
@@ -662,6 +663,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
true/* moveFocusedTask */,
new ActiveGestureLog.CompoundString(
"motion pause detected (animate=true)"));
Optional.ofNullable(mActivityInterface.getTaskbarController())
.ifPresent(TaskbarUIController::startTranslationSpring);
performHapticFeedback();
}
@@ -27,9 +27,13 @@ import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import androidx.annotation.Nullable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
import com.android.launcher3.touch.OverScroll;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.InputConsumer;
import com.android.systemui.shared.system.InputMonitorCompat;
@@ -48,7 +52,7 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer {
private final float mUnstashArea;
private final float mScreenWidth;
private final int mTaskbarThreshold;
private final int mTaskbarThresholdY;
private boolean mHasPassedTaskbarThreshold;
private final PointF mDownPos = new PointF();
@@ -57,6 +61,8 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer {
private final boolean mIsTransientTaskbar;
private final @Nullable TransitionCallback mTransitionCallback;
public TaskbarStashInputConsumer(Context context, InputConsumer delegate,
InputMonitorCompat inputMonitor, TaskbarActivityContext taskbarActivityContext) {
super(delegate, inputMonitor);
@@ -66,7 +72,9 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer {
Resources res = context.getResources();
mUnstashArea = res.getDimensionPixelSize(R.dimen.taskbar_unstash_input_area);
mTaskbarThreshold = res.getDimensionPixelSize(R.dimen.taskbar_nav_threshold);
int taskbarThreshold = res.getDimensionPixelSize(R.dimen.taskbar_nav_threshold);
int screenHeight = taskbarActivityContext.getDeviceProfile().heightPx;
mTaskbarThresholdY = screenHeight - taskbarThreshold;
mIsTransientTaskbar = DisplayController.isTransientTaskbar(context);
@@ -76,6 +84,10 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer {
onLongPressDetected(motionEvent);
}
});
mTransitionCallback = mIsTransientTaskbar
? taskbarActivityContext.getTranslationCallbacks()
: null;
}
@Override
@@ -138,16 +150,25 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer {
break;
}
mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
float displacementY = mLastPos.y - mDownPos.y;
float verticalDist = Math.abs(displacementY);
boolean passedTaskbarThreshold = verticalDist >= mTaskbarThreshold;
if (!mHasPassedTaskbarThreshold
&& passedTaskbarThreshold
&& mIsTransientTaskbar) {
mHasPassedTaskbarThreshold = true;
if (mIsTransientTaskbar) {
float dY = mLastPos.y - mDownPos.y;
boolean passedTaskbarThreshold = dY < 0
&& mLastPos.y < mTaskbarThresholdY;
mTaskbarActivityContext.onSwipeToUnstashTaskbar();
if (!mHasPassedTaskbarThreshold
&& passedTaskbarThreshold) {
mHasPassedTaskbarThreshold = true;
mTaskbarActivityContext.onSwipeToUnstashTaskbar();
}
if (dY < 0) {
dY = -OverScroll.dampedScroll(-dY, mTaskbarThresholdY);
if (mTransitionCallback != null) {
mTransitionCallback.onActionMove(dY);
}
}
}
break;
case MotionEvent.ACTION_UP:
@@ -158,6 +179,9 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer {
}
mTaskbarActivityContext.setAutohideSuspendFlag(
FLAG_AUTOHIDE_SUSPEND_TOUCHING, false);
if (mTransitionCallback != null) {
mTransitionCallback.onActionEnd();
}
mHasPassedTaskbarThreshold = false;
break;
}