Merge "Update gesture nav edu motion and colors" into udc-dev

This commit is contained in:
Schneider Victor-tulias
2023-05-26 16:12:06 +00:00
committed by Android (Google) Code Review
12 changed files with 113 additions and 211 deletions
@@ -15,10 +15,6 @@
*/
package com.android.quickstep.interaction;
import static com.android.launcher3.QuickstepTransitionManager.ANIMATION_NAV_FADE_OUT_DURATION;
import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_OUT_INTERPOLATOR;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
import android.animation.Animator;
@@ -28,30 +24,19 @@ import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.ColorInt;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Outline;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.RoundedCorner;
import android.view.View;
import android.view.ViewOutlineProvider;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ViewAnimator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.quickstep.util.MultiValueUpdateListener;
import java.util.ArrayList;
import java.util.Arrays;
/**
* Helper View for the gesture tutorial mock previous app task view.
@@ -61,8 +46,6 @@ import java.util.Arrays;
*/
public class AnimatedTaskView extends ConstraintLayout {
private static final long ANIMATE_TO_FULL_SCREEN_DURATION = 300;
private View mFullTaskView;
private View mTopTaskView;
private View mBottomTaskView;
@@ -72,17 +55,16 @@ public class AnimatedTaskView extends ConstraintLayout {
private float mTaskViewAnimatedRadius;
public AnimatedTaskView(@NonNull Context context) {
super(context);
this(context, null);
}
public AnimatedTaskView(@NonNull Context context,
@Nullable AttributeSet attrs) {
super(context, attrs);
public AnimatedTaskView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public AnimatedTaskView(
@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this(context, attrs, defStyleAttr, 0);
}
public AnimatedTaskView(
@@ -104,97 +86,6 @@ public class AnimatedTaskView extends ConstraintLayout {
setToSingleRowLayout(false);
}
void animateToFillScreen(@Nullable Runnable onAnimationEndCallback) {
if (mTaskViewOutlineProvider == null) {
// This is an illegal state.
return;
}
// calculate start and end corner radius
Outline startOutline = new Outline();
mTaskViewOutlineProvider.getOutline(this, startOutline);
Rect outlineStartRect = new Rect();
startOutline.getRect(outlineStartRect);
float outlineStartRadius = startOutline.getRadius();
final Display display = mContext.getDisplay();;
RoundedCorner corner = display.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT);
float outlineEndRadius = corner.getRadius();
// create animation
AnimatorSet set = new AnimatorSet();
ArrayList<Animator> animations = new ArrayList<>();
// center view
animations.add(ObjectAnimator.ofFloat(this, TRANSLATION_X, 0));
// retrieve start animation matrix to scale off of
Matrix matrix = getAnimationMatrix();
if (matrix == null) {
// This is an illegal state.
return;
}
float[] matrixValues = new float[9];
matrix.getValues(matrixValues);
float[] newValues = matrixValues.clone();
ValueAnimator transformAnimation = ValueAnimator.ofFloat(0, 1);
MultiValueUpdateListener listener = new MultiValueUpdateListener() {
Matrix currentMatrix = new Matrix();
FloatProp mOutlineRadius = new FloatProp(outlineStartRadius, outlineEndRadius, 0,
ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
FloatProp mTransX = new FloatProp(matrixValues[Matrix.MTRANS_X], 0f, 0,
ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
FloatProp mTransY = new FloatProp(matrixValues[Matrix.MTRANS_Y], 0f, 0,
ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
FloatProp mScaleX = new FloatProp(matrixValues[Matrix.MSCALE_X], 1f, 0,
ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
FloatProp mScaleY = new FloatProp(matrixValues[Matrix.MSCALE_Y], 1f, 0,
ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
@Override
public void onUpdate(float percent, boolean initOnly) {
// scale corner radius to match display radius
mTaskViewAnimatedRadius = mOutlineRadius.value;
mFullTaskView.invalidateOutline();
// translate to center, ends at translation x:0, y:0
newValues[Matrix.MTRANS_X] = mTransX.value;
newValues[Matrix.MTRANS_Y] = mTransY.value;
// scale to full size, ends at scale 1
newValues[Matrix.MSCALE_X] = mScaleX.value;
newValues[Matrix.MSCALE_Y] = mScaleY.value;
// create and set new animation matrix
currentMatrix.setValues(newValues);
setAnimationMatrix(currentMatrix);
}
};
transformAnimation.addUpdateListener(listener);
animations.add(transformAnimation);
set.playSequentially(animations);
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
addAnimatedOutlineProvider(mFullTaskView, outlineStartRect, outlineStartRadius);
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (onAnimationEndCallback != null) {
onAnimationEndCallback.run();
}
}
});
set.start();
}
AnimatorSet createAnimationToMultiRowLayout() {
if (mTaskViewOutlineProvider == null) {
// This is an illegal state.
@@ -136,7 +136,7 @@ final class BackGestureTutorialController extends TutorialController {
}
@Override
protected int getSwipeActionColor() {
protected int getFakeLauncherColor() {
return mTutorialFragment.mRootView.mColorSurfaceContainer;
}
@@ -104,11 +104,9 @@ final class HomeGestureTutorialController extends SwipeUpGestureTutorialControll
@Override
protected int getMockAppTaskLayoutResId() {
return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
? R.layout.swipe_up_gesture_tutorial_shape
: mTutorialFragment.isLargeScreen()
? R.layout.gesture_tutorial_tablet_mock_webpage
: R.layout.gesture_tutorial_mock_webpage;
return mTutorialFragment.isLargeScreen()
? R.layout.gesture_tutorial_tablet_mock_webpage
: R.layout.gesture_tutorial_mock_webpage;
}
@Override
@@ -121,7 +119,12 @@ final class HomeGestureTutorialController extends SwipeUpGestureTutorialControll
}
@Override
protected int getSwipeActionColor() {
protected int getFakeTaskViewColor() {
return isGestureCompleted() ? getFakeLauncherColor() : getExitingAppColor();
}
@Override
protected int getFakeLauncherColor() {
return mTutorialFragment.mRootView.mColorSurfaceContainer;
}
@@ -148,7 +151,7 @@ final class HomeGestureTutorialController extends SwipeUpGestureTutorialControll
case BACK_CANCELLED_FROM_LEFT:
case BACK_CANCELLED_FROM_RIGHT:
case BACK_NOT_STARTED_TOO_FAR_FROM_EDGE:
resetTaskView();
resetTaskViews();
showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
break;
}
@@ -178,18 +181,18 @@ final class HomeGestureTutorialController extends SwipeUpGestureTutorialControll
}
case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
resetTaskView();
resetTaskViews();
showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
break;
case OVERVIEW_GESTURE_COMPLETED:
fadeOutFakeTaskView(true, true, () -> {
fadeOutFakeTaskView(true, () -> {
showFeedback(R.string.home_gesture_feedback_overview_detected);
showFakeTaskbar(/* animateFromHotseat= */ false);
});
break;
case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
case HOME_OR_OVERVIEW_CANCELLED:
fadeOutFakeTaskView(false, true, null);
fadeOutFakeTaskView(false, null);
showFeedback(R.string.home_gesture_feedback_wrong_swipe_direction);
break;
}
@@ -25,7 +25,9 @@ import android.annotation.TargetApi;
import android.graphics.PointF;
import android.os.Build;
import android.os.Handler;
import android.view.View;
import androidx.annotation.ColorInt;
import androidx.core.graphics.ColorUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -43,6 +45,8 @@ import java.util.Map;
@TargetApi(Build.VERSION_CODES.R)
final class OverviewGestureTutorialController extends SwipeUpGestureTutorialController {
private static final float LAUNCHER_COLOR_BLENDING_RATIO = 0.4f;
OverviewGestureTutorialController(OverviewGestureTutorialFragment fragment,
TutorialType tutorialType) {
super(fragment, tutorialType);
@@ -112,11 +116,9 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont
@Override
protected int getMockAppTaskLayoutResId() {
return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
? R.layout.gesture_tutorial_mock_task_view
: mTutorialFragment.isLargeScreen()
? R.layout.gesture_tutorial_tablet_mock_conversation_list
: R.layout.gesture_tutorial_mock_conversation_list;
return mTutorialFragment.isLargeScreen()
? R.layout.gesture_tutorial_tablet_mock_conversation_list
: R.layout.gesture_tutorial_mock_conversation_list;
}
@Override
@@ -128,11 +130,31 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont
: R.raw.overview_gesture_tutorial_animation;
}
@Override
protected int getSwipeActionColor() {
@ColorInt
private int getFakeTaskViewStartColor() {
return mTutorialFragment.mRootView.mColorSurfaceOverview;
}
@ColorInt
private int getFakeTaskViewEndColor() {
return getMockPreviousAppTaskThumbnailColor();
}
@Override
protected int getFakeTaskViewColor() {
return isGestureCompleted()
? getFakeTaskViewEndColor()
: getFakeTaskViewStartColor();
}
@Override
protected int getFakeLauncherColor() {
return ColorUtils.blendARGB(
mTutorialFragment.mRootView.mColorSurfaceContainer,
mTutorialFragment.mRootView.mColorOnSurfaceOverview,
LAUNCHER_COLOR_BLENDING_RATIO);
}
@Override
protected int getHotseatIconColor() {
return mTutorialFragment.mRootView.mColorOnSurfaceOverview;
@@ -159,7 +181,7 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont
case BACK_CANCELLED_FROM_LEFT:
case BACK_CANCELLED_FROM_RIGHT:
case BACK_NOT_STARTED_TOO_FAR_FROM_EDGE:
resetTaskView();
resetTaskViews();
showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
break;
}
@@ -190,7 +212,7 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont
}
case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
resetTaskView();
resetTaskViews();
showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
break;
case OVERVIEW_GESTURE_COMPLETED:
@@ -204,7 +226,7 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont
break;
case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
case HOME_OR_OVERVIEW_CANCELLED:
fadeOutFakeTaskView(false, true, null);
fadeOutFakeTaskView(false, null);
showFeedback(R.string.overview_gesture_feedback_wrong_swipe_direction);
break;
}
@@ -229,15 +251,21 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
new Handler().postDelayed(() -> {
mFakeTaskView.setVisibility(View.INVISIBLE);
if (!mTutorialFragment.isLargeScreen()) {
mFakePreviousTaskView.animateToFillScreen(
() -> onSuccessAnimationComplete());
} else {
onSuccessAnimationComplete();
}
}, TASK_VIEW_FILL_SCREEN_ANIMATION_DELAY_MILLIS);
new Handler().postDelayed(
() -> fadeOutFakeTaskView(
/* toOverviewFirst= */ true,
/* animatePreviousTask= */ false,
/* resetViews= */ false,
/* updateListener= */ v -> mFakeTaskView.setBackgroundColor(
ColorUtils.blendARGB(
getFakeTaskViewStartColor(),
getFakeTaskViewEndColor(),
v.getAnimatedFraction())),
/* onEndRunnable= */ () -> {
showSuccessFeedback();
resetTaskViews();
}),
TASK_VIEW_FILL_SCREEN_ANIMATION_DELAY_MILLIS);
}
});
}
@@ -259,9 +287,4 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont
animset.start();
mRunningWindowAnim = SwipeUpAnimationLogic.RunningWindowAnim.wrap(animset);
}
private void onSuccessAnimationComplete() {
mFakeLauncherView.setBackgroundColor(getMockPreviousAppTaskThumbnailColor());
showSuccessFeedback();
}
}
@@ -78,7 +78,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
private final AnimatorListenerAdapter mResetTaskView = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
resetTaskView();
resetTaskViews();
}
};
@@ -122,7 +122,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
mRunningWindowAnim = null;
}
void resetTaskView() {
void resetTaskViews() {
mFakeHotseatView.setVisibility(View.INVISIBLE);
mFakeIconView.setVisibility(View.INVISIBLE);
if (mTutorialFragment.getActivity() != null) {
@@ -141,10 +141,21 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
mShowPreviousTasks = false;
mRunningWindowAnim = null;
}
void fadeOutFakeTaskView(boolean toOverviewFirst, @Nullable Runnable onEndRunnable) {
fadeOutFakeTaskView(
toOverviewFirst,
/* animatePreviousTask= */ true,
/* resetViews= */ true,
/* updateListener= */ null,
onEndRunnable);
}
/** Fades the task view, optionally after animating to a fake Overview. */
void fadeOutFakeTaskView(boolean toOverviewFirst, boolean reset,
@Nullable Runnable onEndRunnable) {
void fadeOutFakeTaskView(boolean toOverviewFirst,
boolean animatePreviousTask,
boolean resetViews,
@Nullable ValueAnimator.AnimatorUpdateListener updateListener,
@Nullable Runnable onEndRunnable) {
cancelRunningAnimation();
PendingAnimation anim = new PendingAnimation(300);
if (toOverviewFirst) {
@@ -155,20 +166,20 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
public void onAnimationEnd(Animator animation, boolean isReverse) {
PendingAnimation fadeAnim =
new PendingAnimation(TASK_VIEW_END_ANIMATION_DURATION_MILLIS);
if (reset) {
fadeAnim.setFloat(mTaskViewSwipeUpAnimation
.getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
fadeAnim.setFloat(mTaskViewSwipeUpAnimation
.getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
if (resetViews) {
fadeAnim.addListener(mResetTaskView);
} else {
fadeAnim.setViewAlpha(mFakeTaskView, 0, ACCEL);
fadeAnim.setViewAlpha(mFakePreviousTaskView, 0, ACCEL);
}
if (onEndRunnable != null) {
fadeAnim.addListener(AnimatorListeners.forSuccessCallback(onEndRunnable));
}
if (updateListener != null) {
fadeAnim.addOnFrameListener(updateListener);
}
AnimatorSet animset = fadeAnim.buildAnim();
if (reset && mTutorialFragment.isLargeScreen()) {
if (animatePreviousTask && mTutorialFragment.isLargeScreen()) {
animset.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
@@ -190,13 +201,10 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
}
});
} else {
if (reset) {
anim.setFloat(mTaskViewSwipeUpAnimation
.getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
anim.setFloat(mTaskViewSwipeUpAnimation
.getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
if (resetViews) {
anim.addListener(mResetTaskView);
} else {
anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
anim.setViewAlpha(mFakePreviousTaskView, 0, ACCEL);
}
if (onEndRunnable != null) {
anim.addListener(AnimatorListeners.forSuccessCallback(onEndRunnable));
@@ -268,7 +268,12 @@ abstract class TutorialController implements BackGestureAttemptCallback,
}
@ColorInt
protected abstract int getSwipeActionColor();
protected int getFakeTaskViewColor() {
return Color.TRANSPARENT;
}
@ColorInt
protected abstract int getFakeLauncherColor();
@ColorInt
protected int getExitingAppColor() {
@@ -445,6 +450,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
}
private void showSuccessPage() {
pauseAndHideLottieAnimation();
mCheckmarkAnimation.setVisibility(View.VISIBLE);
mCheckmarkAnimation.playAnimation();
mFeedbackTitleView.setTextAppearance(mContext, getSuccessTitleTextAppearance());
@@ -591,7 +597,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
protected void resetViewsForBackGesture() {
mFakeTaskView.setVisibility(View.VISIBLE);
mFakeTaskView.setBackgroundColor(getSwipeActionColor());
mFakeTaskView.setBackgroundColor(getFakeTaskViewColor());
mExitingAppView.setVisibility(View.VISIBLE);
// reset the exiting app's dimensions
@@ -690,11 +696,10 @@ abstract class TutorialController implements BackGestureAttemptCallback,
mContext, getMockWallpaperResId()));
mTutorialFragment.updateFeedbackAnimation();
mFakeLauncherView.setBackgroundColor(ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
? getSwipeActionColor()
? getFakeLauncherColor()
: mContext.getColor(R.color.gesture_tutorial_fake_wallpaper_color));
updateFakeViewLayout(mFakeHotseatView, getMockHotseatResId());
mHotseatIconView = mFakeHotseatView.findViewById(R.id.hotseat_icon_1);
updateFakeViewLayout(mFakeTaskView, getMockAppTaskLayoutResId());
mFakeTaskView.animate().alpha(1).setListener(
AnimatorListeners.forSuccessCallback(() -> mFakeTaskView.animate().cancel()));
mFakePreviousTaskView.setFakeTaskViewFillColor(getMockPreviousAppTaskThumbnailColor());
@@ -703,12 +708,15 @@ abstract class TutorialController implements BackGestureAttemptCallback,
if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
mExitingAppView.setBackgroundColor(getExitingAppColor());
mFakeTaskView.setBackgroundColor(getFakeTaskViewColor());
updateHotseatChildViewColor(mFakeIconView);
updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_2));
updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_3));
updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_4));
updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_5));
updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_search_bar));
} else {
updateFakeViewLayout(mFakeTaskView, getMockAppTaskLayoutResId());
}
}
}
@@ -143,6 +143,7 @@ abstract class TutorialFragment extends GestureSandboxFragment implements OnTouc
return null;
}
@NonNull
abstract TutorialController createController(TutorialType type);
abstract Class<? extends TutorialController> getControllerClass();
@@ -374,9 +375,15 @@ abstract class TutorialFragment extends GestureSandboxFragment implements OnTouc
void changeController(TutorialType tutorialType) {
if (getControllerClass().isInstance(mTutorialController)) {
mTutorialController.setTutorialType(tutorialType);
if (isGestureComplete()) {
mTutorialController.setGestureCompleted();
}
mTutorialController.fadeTaskViewAndRun(mTutorialController::transitToController);
} else {
mTutorialController = createController(tutorialType);
if (isGestureComplete()) {
mTutorialController.setGestureCompleted();
}
mTutorialController.transitToController();
}
mEdgeBackGestureHandler.registerBackGestureAttemptCallback(mTutorialController);