Update overview from home transitions am: 03a4a0cd53
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/12184426 Change-Id: Iac33ad0742264a97e754a1cc4336ed3ab727944a
This commit is contained in:
+7
-4
@@ -17,6 +17,7 @@ package com.android.launcher3.uioverrides;
|
||||
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_BUTTONS;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
|
||||
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
|
||||
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
|
||||
import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
|
||||
@@ -57,7 +58,7 @@ public final class RecentsViewStateController extends
|
||||
mRecentsView.updateEmptyMessage();
|
||||
mRecentsView.resetTaskVisuals();
|
||||
}
|
||||
setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, state);
|
||||
setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig(), state);
|
||||
mRecentsView.setFullscreenProgress(state.getOverviewFullscreenProgress());
|
||||
}
|
||||
|
||||
@@ -75,17 +76,19 @@ public final class RecentsViewStateController extends
|
||||
AnimationSuccessListener.forRunnable(mRecentsView::resetTaskVisuals));
|
||||
}
|
||||
|
||||
setAlphas(builder, toState);
|
||||
setAlphas(builder, config, toState);
|
||||
builder.setFloat(mRecentsView, FULLSCREEN_PROGRESS,
|
||||
toState.getOverviewFullscreenProgress(), LINEAR);
|
||||
}
|
||||
|
||||
private void setAlphas(PropertySetter propertySetter, LauncherState state) {
|
||||
private void setAlphas(PropertySetter propertySetter, StateAnimationConfig config,
|
||||
LauncherState state) {
|
||||
float buttonAlpha = (state.getVisibleElements(mLauncher) & OVERVIEW_BUTTONS) != 0 ? 1 : 0;
|
||||
propertySetter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
|
||||
buttonAlpha, LINEAR);
|
||||
propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlpha(),
|
||||
MultiValueAlpha.VALUE, buttonAlpha, LINEAR);
|
||||
MultiValueAlpha.VALUE, buttonAlpha, config.getInterpolator(
|
||||
ANIM_OVERVIEW_ACTIONS_FADE, LINEAR));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+11
-4
@@ -25,6 +25,7 @@ import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_PEEK;
|
||||
import static com.android.launcher3.WorkspaceStateTransitionAnimation.getSpringScaleAnimator;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
|
||||
@@ -163,10 +164,15 @@ public class QuickstepAtomicAnimationFactory extends
|
||||
config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
|
||||
config.setInterpolator(ANIM_ALL_APPS_FADE, ACCEL);
|
||||
config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
|
||||
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
|
||||
config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
|
||||
Workspace workspace = mActivity.getWorkspace();
|
||||
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL_DEACCEL);
|
||||
|
||||
if (SysUINavigationMode.getMode(mActivity) == NO_BUTTON) {
|
||||
config.setInterpolator(ANIM_OVERVIEW_FADE, FINAL_FRAME);
|
||||
} else {
|
||||
config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
|
||||
}
|
||||
|
||||
Workspace workspace = mActivity.getWorkspace();
|
||||
// Start from a higher workspace scale, but only if we're invisible so we don't jump.
|
||||
boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE;
|
||||
if (isWorkspaceVisible) {
|
||||
@@ -206,8 +212,10 @@ public class QuickstepAtomicAnimationFactory extends
|
||||
config.setInterpolator(ANIM_WORKSPACE_SCALE,
|
||||
fromState == NORMAL ? ACCEL : OVERSHOOT_1_2);
|
||||
config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL);
|
||||
config.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
|
||||
} else {
|
||||
config.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
|
||||
config.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
|
||||
|
||||
// Scale up the recents, if it is not coming from the side
|
||||
RecentsView overview = mActivity.getOverviewPanel();
|
||||
@@ -225,7 +233,6 @@ public class QuickstepAtomicAnimationFactory extends
|
||||
: OVERSHOOT_1_7;
|
||||
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator);
|
||||
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, translationInterpolator);
|
||||
config.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
|
||||
} else if (fromState == HINT_STATE && toState == NORMAL) {
|
||||
config.setInterpolator(ANIM_DEPTH, DEACCEL_3);
|
||||
if (mHintToNormalDuration == -1) {
|
||||
|
||||
+20
-5
@@ -19,13 +19,13 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_EDU;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE;
|
||||
import static com.android.launcher3.touch.AbstractStateChangeTouchController.SUCCESS_TRANSITION_PROGRESS;
|
||||
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
@@ -45,6 +45,7 @@ import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.graphics.OverviewScrim;
|
||||
import com.android.launcher3.logging.StatsLogManager;
|
||||
import com.android.launcher3.states.StateAnimationConfig;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
@@ -52,7 +53,9 @@ import com.android.launcher3.touch.SingleAxisSwipeDetector;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.quickstep.util.AnimatorControllerWithResistance;
|
||||
import com.android.quickstep.util.AssistantUtilities;
|
||||
import com.android.quickstep.util.OverviewToHomeAnim;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
|
||||
@@ -63,6 +66,8 @@ public class NavBarToHomeTouchController implements TouchController,
|
||||
SingleAxisSwipeDetector.Listener {
|
||||
|
||||
private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL_3;
|
||||
// How much of the overview scrim we can remove during the transition.
|
||||
private static final float OVERVIEW_TO_HOME_SCRIM_PROGRESS = 0.5f;
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final SingleAxisSwipeDetector mSwipeDetector;
|
||||
@@ -156,8 +161,13 @@ public class NavBarToHomeTouchController implements TouchController,
|
||||
final PendingAnimation builder = new PendingAnimation(accuracy);
|
||||
if (mStartState.overviewUi) {
|
||||
RecentsView recentsView = mLauncher.getOverviewPanel();
|
||||
builder.setFloat(recentsView, ADJACENT_PAGE_OFFSET,
|
||||
-mPullbackDistance / recentsView.getPageOffsetScale(), PULLBACK_INTERPOLATOR);
|
||||
AnimatorControllerWithResistance.createRecentsResistanceFromOverviewAnim(mLauncher,
|
||||
builder);
|
||||
float endScrimAlpha = Utilities.mapRange(OVERVIEW_TO_HOME_SCRIM_PROGRESS,
|
||||
mStartState.getOverviewScrimAlpha(mLauncher),
|
||||
mEndState.getOverviewScrimAlpha(mLauncher));
|
||||
builder.setFloat(mLauncher.getDragLayer().getOverviewScrim(),
|
||||
OverviewScrim.SCRIM_PROGRESS, endScrimAlpha, PULLBACK_INTERPOLATOR);
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
builder.addOnFrameCallback(recentsView::redrawLiveTile);
|
||||
}
|
||||
@@ -211,8 +221,13 @@ public class NavBarToHomeTouchController implements TouchController,
|
||||
recentsView.switchToScreenshot(null,
|
||||
() -> recentsView.finishRecentsAnimation(true /* toRecents */, null));
|
||||
}
|
||||
mLauncher.getStateManager().goToState(mEndState, true,
|
||||
() -> onSwipeInteractionCompleted(mEndState));
|
||||
if (mStartState == OVERVIEW) {
|
||||
new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(mEndState))
|
||||
.animateWithVelocity(velocity);
|
||||
} else {
|
||||
mLauncher.getStateManager().goToState(mEndState, true,
|
||||
() -> onSwipeInteractionCompleted(mEndState));
|
||||
}
|
||||
if (mStartState != mEndState) {
|
||||
logStateChange(mStartState.containerType, logAction);
|
||||
}
|
||||
|
||||
+26
-45
@@ -21,11 +21,8 @@ import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
|
||||
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.PointF;
|
||||
@@ -35,14 +32,15 @@ import android.view.MotionEvent;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.graphics.OverviewScrim;
|
||||
import com.android.launcher3.statemanager.StateManager;
|
||||
import com.android.launcher3.states.StateAnimationConfig;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.util.VibratorWrapper;
|
||||
import com.android.quickstep.util.StaggeredWorkspaceAnim;
|
||||
import com.android.quickstep.util.AnimatorControllerWithResistance;
|
||||
import com.android.quickstep.util.OverviewToHomeAnim;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
/**
|
||||
@@ -62,10 +60,10 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo
|
||||
|
||||
private boolean mDidTouchStartInNavBar;
|
||||
private boolean mReachedOverview;
|
||||
private boolean mIsOverviewRehidden;
|
||||
private boolean mIsHomeStaggeredAnimFinished;
|
||||
// The last recorded displacement before we reached overview.
|
||||
private PointF mStartDisplacement = new PointF();
|
||||
private float mStartY;
|
||||
private AnimatorPlaybackController mOverviewResistYAnim;
|
||||
|
||||
// Normal to Hint animation has flag SKIP_OVERVIEW, so we update this scrim with this animator.
|
||||
private ObjectAnimator mNormalToHintOverviewScrimAnimator;
|
||||
@@ -123,6 +121,7 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo
|
||||
mToState.getOverviewScrimAlpha(mLauncher));
|
||||
}
|
||||
mReachedOverview = false;
|
||||
mOverviewResistYAnim = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -160,6 +159,9 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo
|
||||
mNormalToHintOverviewScrimAnimator = null;
|
||||
mCurrentAnimation.dispatchOnCancelWithoutCancelRunnable(() -> {
|
||||
mLauncher.getStateManager().goToState(OVERVIEW, true, () -> {
|
||||
mOverviewResistYAnim = AnimatorControllerWithResistance
|
||||
.createRecentsResistanceFromOverviewAnim(mLauncher, null)
|
||||
.createPlaybackController();
|
||||
mReachedOverview = true;
|
||||
maybeSwipeInteractionToOverviewComplete();
|
||||
});
|
||||
@@ -173,13 +175,6 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo
|
||||
}
|
||||
}
|
||||
|
||||
// Used if flinging back to home after reaching overview
|
||||
private void maybeSwipeInteractionToHomeComplete() {
|
||||
if (mIsHomeStaggeredAnimFinished && mIsOverviewRehidden) {
|
||||
onSwipeInteractionCompleted(NORMAL, Touch.FLING);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlingOverviewAnim() {
|
||||
return mDidTouchStartInNavBar && super.handlingOverviewAnim();
|
||||
@@ -193,11 +188,17 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo
|
||||
if (mMotionPauseDetector.isPaused()) {
|
||||
if (!mReachedOverview) {
|
||||
mStartDisplacement.set(xDisplacement, yDisplacement);
|
||||
mStartY = event.getY();
|
||||
} else {
|
||||
mRecentsView.setTranslationX((xDisplacement - mStartDisplacement.x)
|
||||
* OVERVIEW_MOVEMENT_FACTOR);
|
||||
mRecentsView.setTranslationY((yDisplacement - mStartDisplacement.y)
|
||||
* OVERVIEW_MOVEMENT_FACTOR);
|
||||
float yProgress = (mStartDisplacement.y - yDisplacement) / mStartY;
|
||||
if (yProgress > 0 && mOverviewResistYAnim != null) {
|
||||
mOverviewResistYAnim.setPlayFraction(yProgress);
|
||||
} else {
|
||||
mRecentsView.setTranslationY((yDisplacement - mStartDisplacement.y)
|
||||
* OVERVIEW_MOVEMENT_FACTOR);
|
||||
}
|
||||
}
|
||||
// Stay in Overview.
|
||||
return true;
|
||||
@@ -212,35 +213,8 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo
|
||||
StateManager<LauncherState> stateManager = mLauncher.getStateManager();
|
||||
boolean goToHomeInsteadOfOverview = isFling;
|
||||
if (goToHomeInsteadOfOverview) {
|
||||
if (velocity > 0) {
|
||||
stateManager.goToState(NORMAL, true,
|
||||
() -> onSwipeInteractionCompleted(NORMAL, Touch.FLING));
|
||||
} else {
|
||||
mIsHomeStaggeredAnimFinished = mIsOverviewRehidden = false;
|
||||
|
||||
StaggeredWorkspaceAnim staggeredWorkspaceAnim = new StaggeredWorkspaceAnim(
|
||||
mLauncher, velocity, false /* animateOverviewScrim */);
|
||||
staggeredWorkspaceAnim.addAnimatorListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
mIsHomeStaggeredAnimFinished = true;
|
||||
maybeSwipeInteractionToHomeComplete();
|
||||
}
|
||||
}).start();
|
||||
|
||||
// StaggeredWorkspaceAnim doesn't animate overview, so we handle it here.
|
||||
stateManager.cancelAnimation();
|
||||
StateAnimationConfig config = new StateAnimationConfig();
|
||||
config.duration = OVERVIEW.getTransitionDuration(mLauncher);
|
||||
config.animFlags = PLAY_ATOMIC_OVERVIEW_PEEK;
|
||||
AnimatorSet anim = stateManager.createAtomicAnimation(
|
||||
stateManager.getState(), NORMAL, config);
|
||||
anim.addListener(AnimationSuccessListener.forRunnable(() -> {
|
||||
mIsOverviewRehidden = true;
|
||||
maybeSwipeInteractionToHomeComplete();
|
||||
}));
|
||||
anim.start();
|
||||
}
|
||||
new OverviewToHomeAnim(mLauncher, ()-> onSwipeInteractionCompleted(NORMAL, Touch.FLING))
|
||||
.animateWithVelocity(velocity);
|
||||
}
|
||||
if (mReachedOverview) {
|
||||
float distanceDp = dpiFromPx(Math.max(
|
||||
@@ -256,6 +230,13 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo
|
||||
.withEndAction(goToHomeInsteadOfOverview
|
||||
? null
|
||||
: this::maybeSwipeInteractionToOverviewComplete);
|
||||
if (!goToHomeInsteadOfOverview) {
|
||||
// Return to normal properties for the overview state.
|
||||
StateAnimationConfig config = new StateAnimationConfig();
|
||||
config.duration = duration;
|
||||
LauncherState state = mLauncher.getStateManager().getState();
|
||||
mLauncher.getStateManager().createAtomicAnimation(state, state, config).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.quickstep.util;
|
||||
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
|
||||
import static com.android.launcher3.anim.Interpolators.INSTANT;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.util.Log;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.statemanager.StateManager;
|
||||
import com.android.launcher3.states.StateAnimationConfig;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
/**
|
||||
* Runs an animation from overview to home. Currently, this animation is just a wrapper around the
|
||||
* normal state transition, in order to keep RecentsView at the same scale and translationY that
|
||||
* it started out at as it translates offscreen. It also scrolls RecentsView to page 0 and may play
|
||||
* a {@link StaggeredWorkspaceAnim} if we're starting from an upward fling.
|
||||
*/
|
||||
public class OverviewToHomeAnim {
|
||||
|
||||
private static final String TAG = "OverviewToHomeAnim";
|
||||
|
||||
// Constants to specify how to scroll RecentsView to the default page if it's not already there.
|
||||
private static final int DEFAULT_PAGE = 0;
|
||||
private static final int PER_PAGE_SCROLL_DURATION = 150;
|
||||
private static final int MAX_PAGE_SCROLL_DURATION = 750;
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final Runnable mOnReachedHome;
|
||||
|
||||
// Only run mOnReachedHome when both of these are true.
|
||||
private boolean mIsHomeStaggeredAnimFinished;
|
||||
private boolean mIsOverviewHidden;
|
||||
|
||||
public OverviewToHomeAnim(Launcher launcher, Runnable onReachedHome) {
|
||||
mLauncher = launcher;
|
||||
mOnReachedHome = onReachedHome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the animation. If velocity < 0 (i.e. upwards), also plays a
|
||||
* {@link StaggeredWorkspaceAnim}.
|
||||
*/
|
||||
public void animateWithVelocity(float velocity) {
|
||||
StateManager<LauncherState> stateManager = mLauncher.getStateManager();
|
||||
LauncherState startState = stateManager.getState();
|
||||
if (startState != OVERVIEW) {
|
||||
Log.e(TAG, "animateFromOverviewToHome: unexpected start state " + startState);
|
||||
}
|
||||
|
||||
boolean playStaggeredWorkspaceAnim = velocity < 0;
|
||||
if (playStaggeredWorkspaceAnim) {
|
||||
StaggeredWorkspaceAnim staggeredWorkspaceAnim = new StaggeredWorkspaceAnim(
|
||||
mLauncher, velocity, false /* animateOverviewScrim */);
|
||||
staggeredWorkspaceAnim.addAnimatorListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
mIsHomeStaggeredAnimFinished = true;
|
||||
maybeOverviewToHomeAnimComplete();
|
||||
}
|
||||
}).start();
|
||||
} else {
|
||||
mIsHomeStaggeredAnimFinished = true;
|
||||
}
|
||||
|
||||
RecentsView recentsView = mLauncher.getOverviewPanel();
|
||||
int numPagesToScroll = recentsView.getNextPage() - DEFAULT_PAGE;
|
||||
int scrollDuration = Math.min(MAX_PAGE_SCROLL_DURATION,
|
||||
numPagesToScroll * PER_PAGE_SCROLL_DURATION);
|
||||
int duration = Math.max(scrollDuration, startState.getTransitionDuration(mLauncher));
|
||||
|
||||
StateAnimationConfig config = new UseFirstInterpolatorStateAnimConfig();
|
||||
config.duration = duration;
|
||||
config.animFlags = playStaggeredWorkspaceAnim
|
||||
// StaggeredWorkspaceAnim doesn't animate overview, so we handle it here.
|
||||
? PLAY_ATOMIC_OVERVIEW_PEEK
|
||||
: ANIM_ALL_COMPONENTS;
|
||||
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, DEACCEL);
|
||||
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, FINAL_FRAME);
|
||||
config.setInterpolator(ANIM_OVERVIEW_SCALE, FINAL_FRAME);
|
||||
config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, INSTANT);
|
||||
AnimatorSet anim = stateManager.createAtomicAnimation(
|
||||
startState, NORMAL, config);
|
||||
anim.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
mIsOverviewHidden = true;
|
||||
maybeOverviewToHomeAnimComplete();
|
||||
}
|
||||
});
|
||||
stateManager.cancelAnimation();
|
||||
anim.start();
|
||||
recentsView.snapToPage(DEFAULT_PAGE, duration);
|
||||
}
|
||||
|
||||
private void maybeOverviewToHomeAnimComplete() {
|
||||
if (mIsHomeStaggeredAnimFinished && mIsOverviewHidden) {
|
||||
mOnReachedHome.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around StateAnimationConfig that doesn't allow interpolators to be set if they are
|
||||
* already set. This ensures they aren't overridden before being used.
|
||||
*/
|
||||
private static class UseFirstInterpolatorStateAnimConfig extends StateAnimationConfig {
|
||||
@Override
|
||||
public void setInterpolator(int animId, Interpolator interpolator) {
|
||||
if (mInterpolators[animId] == null || interpolator == null) {
|
||||
super.setInterpolator(animId, interpolator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -105,6 +105,7 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
public OverviewActionsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr, 0);
|
||||
mMultiValueAlpha = new MultiValueAlpha(this, 4);
|
||||
mMultiValueAlpha.setUpdateVisibility(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -168,7 +169,6 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
}
|
||||
boolean isHidden = mHiddenFlags != 0;
|
||||
mMultiValueAlpha.getProperty(INDEX_HIDDEN_FLAGS_ALPHA).setValue(isHidden ? 0 : 1);
|
||||
setVisibility(isHidden ? INVISIBLE : VISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.android.quickstep.util;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
|
||||
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
|
||||
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
|
||||
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.content.Context;
|
||||
@@ -27,12 +29,16 @@ import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.FloatProperty;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.quickstep.LauncherActivityInterface;
|
||||
import com.android.quickstep.SysUINavigationMode;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
/**
|
||||
* Controls an animation that can go beyond progress = 1, at which point resistance should be
|
||||
@@ -48,15 +54,32 @@ public class AnimatorControllerWithResistance {
|
||||
*/
|
||||
public static final float TWO_BUTTON_EXTRA_DRAG_FACTOR = 0.25f;
|
||||
|
||||
/**
|
||||
* Start slowing down the rate of scaling down when recents view is smaller than this scale.
|
||||
*/
|
||||
private static final float RECENTS_SCALE_START_RESIST = 0.75f;
|
||||
private enum RecentsParams {
|
||||
FROM_APP(0.75f, 0.5f, 1f),
|
||||
FROM_OVERVIEW(1f, 0.75f, 0.5f);
|
||||
|
||||
/**
|
||||
* Recents view will reach this scale at the very end of the drag.
|
||||
*/
|
||||
private static final float RECENTS_SCALE_MAX_RESIST = 0.5f;
|
||||
RecentsParams(float scaleStartResist, float scaleMaxResist, float translationFactor) {
|
||||
this.scaleStartResist = scaleStartResist;
|
||||
this.scaleMaxResist = scaleMaxResist;
|
||||
this.translationFactor = translationFactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start slowing down the rate of scaling down when recents view is smaller than this scale.
|
||||
*/
|
||||
public final float scaleStartResist;
|
||||
|
||||
/**
|
||||
* Recents view will reach this scale at the very end of the drag.
|
||||
*/
|
||||
public final float scaleMaxResist;
|
||||
|
||||
/**
|
||||
* How much translation to apply to RecentsView when the drag reaches the top of the screen,
|
||||
* where 0 will keep it centered and 1 will have it barely touch the top of the screen.
|
||||
*/
|
||||
public final float translationFactor;
|
||||
}
|
||||
|
||||
private static final TimeInterpolator RECENTS_SCALE_RESIST_INTERPOLATOR = DEACCEL;
|
||||
private static final TimeInterpolator RECENTS_TRANSLATE_RESIST_INTERPOLATOR = LINEAR;
|
||||
@@ -115,6 +138,24 @@ public class AnimatorControllerWithResistance {
|
||||
RecentsOrientedState recentsOrientedState, DeviceProfile dp, SCALE scaleTarget,
|
||||
FloatProperty<SCALE> scaleProperty, TRANSLATION translationTarget,
|
||||
FloatProperty<TRANSLATION> translationProperty) {
|
||||
|
||||
PendingAnimation resistAnim = createRecentsResistanceAnim(null, context,
|
||||
recentsOrientedState, dp, scaleTarget, scaleProperty, translationTarget,
|
||||
translationProperty, RecentsParams.FROM_APP);
|
||||
|
||||
AnimatorPlaybackController resistanceController = resistAnim.createPlaybackController();
|
||||
return new AnimatorControllerWithResistance(normalController, resistanceController);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the resistance animation for {@link #createForRecents}, or can be used separately
|
||||
* when starting from recents, i.e. {@link #createRecentsResistanceFromOverviewAnim}.
|
||||
*/
|
||||
public static <SCALE, TRANSLATION> PendingAnimation createRecentsResistanceAnim(
|
||||
@Nullable PendingAnimation resistAnim, Context context,
|
||||
RecentsOrientedState recentsOrientedState, DeviceProfile dp, SCALE scaleTarget,
|
||||
FloatProperty<SCALE> scaleProperty, TRANSLATION translationTarget,
|
||||
FloatProperty<TRANSLATION> translationProperty, RecentsParams params) {
|
||||
Rect startRect = new Rect();
|
||||
LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, startRect,
|
||||
recentsOrientedState.getOrientationHandler());
|
||||
@@ -125,7 +166,9 @@ public class AnimatorControllerWithResistance {
|
||||
distanceToCover = (long)
|
||||
((dp.heightPx - startRect.bottom) * TWO_BUTTON_EXTRA_DRAG_FACTOR);
|
||||
}
|
||||
PendingAnimation resistAnim = new PendingAnimation(distanceToCover * 2);
|
||||
if (resistAnim == null) {
|
||||
resistAnim = new PendingAnimation(distanceToCover * 2);
|
||||
}
|
||||
|
||||
PointF pivot = new PointF();
|
||||
float fullscreenScale = recentsOrientedState.getFullScreenScaleAndPivot(
|
||||
@@ -141,9 +184,9 @@ public class AnimatorControllerWithResistance {
|
||||
} else {
|
||||
// Create an interpolator that resists the scale so the scale doesn't get smaller than
|
||||
// RECENTS_SCALE_MAX_RESIST.
|
||||
float startResist = Utilities.getProgress(RECENTS_SCALE_START_RESIST, startScale,
|
||||
float startResist = Utilities.getProgress(params.scaleStartResist , startScale,
|
||||
endScale);
|
||||
float maxResist = Utilities.getProgress(RECENTS_SCALE_MAX_RESIST, startScale, endScale);
|
||||
float maxResist = Utilities.getProgress(params.scaleMaxResist, startScale, endScale);
|
||||
scaleInterpolator = t -> {
|
||||
if (t < startResist) {
|
||||
return t;
|
||||
@@ -160,17 +203,28 @@ public class AnimatorControllerWithResistance {
|
||||
// Compute where the task view would be based on the end scale, if we didn't translate.
|
||||
RectF endRectF = new RectF(startRect);
|
||||
Matrix temp = new Matrix();
|
||||
temp.setScale(RECENTS_SCALE_MAX_RESIST, RECENTS_SCALE_MAX_RESIST, pivot.x, pivot.y);
|
||||
temp.setScale(params.scaleMaxResist, params.scaleMaxResist, pivot.x, pivot.y);
|
||||
temp.mapRect(endRectF);
|
||||
// Translate such that the task view touches the top of the screen when drag does.
|
||||
float endTranslation = endRectF.top * recentsOrientedState.getOrientationHandler()
|
||||
.getSecondaryTranslationDirectionFactor();
|
||||
.getSecondaryTranslationDirectionFactor() * params.translationFactor;
|
||||
resistAnim.addFloat(translationTarget, translationProperty, 0, endTranslation,
|
||||
RECENTS_TRANSLATE_RESIST_INTERPOLATOR);
|
||||
}
|
||||
|
||||
AnimatorPlaybackController resistanceController = resistAnim.createPlaybackController();
|
||||
return new AnimatorControllerWithResistance(normalController, resistanceController);
|
||||
return resistAnim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to update or create a PendingAnimation suitable for animating
|
||||
* a RecentsView interaction that started from the overview state.
|
||||
*/
|
||||
public static PendingAnimation createRecentsResistanceFromOverviewAnim(
|
||||
BaseDraggingActivity activity, @Nullable PendingAnimation resistanceAnim) {
|
||||
RecentsView recentsView = activity.getOverviewPanel();
|
||||
return createRecentsResistanceAnim(resistanceAnim, activity,
|
||||
recentsView.getPagedViewOrientedState(), activity.getDeviceProfile(),
|
||||
recentsView, RECENTS_SCALE_PROPERTY, recentsView, TASK_SECONDARY_TRANSLATION,
|
||||
RecentsParams.FROM_OVERVIEW);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ public class StateAnimationConfig {
|
||||
ANIM_ALL_APPS_HEADER_FADE,
|
||||
ANIM_OVERVIEW_MODAL,
|
||||
ANIM_DEPTH,
|
||||
ANIM_OVERVIEW_ACTIONS_FADE,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface AnimType {}
|
||||
@@ -89,10 +90,11 @@ public class StateAnimationConfig {
|
||||
public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions
|
||||
public static final int ANIM_OVERVIEW_MODAL = 13;
|
||||
public static final int ANIM_DEPTH = 14;
|
||||
public static final int ANIM_OVERVIEW_ACTIONS_FADE = 15;
|
||||
|
||||
private static final int ANIM_TYPES_COUNT = 15;
|
||||
private static final int ANIM_TYPES_COUNT = 16;
|
||||
|
||||
private final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
|
||||
protected final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
|
||||
|
||||
public StateAnimationConfig() { }
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ package com.android.launcher3.util;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.anim.AlphaUpdateListener;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
@@ -44,6 +46,8 @@ public class MultiValueAlpha {
|
||||
private final AlphaProperty[] mMyProperties;
|
||||
|
||||
private int mValidMask;
|
||||
// Whether we should change from INVISIBLE to VISIBLE and vice versa at low alpha values.
|
||||
private boolean mUpdateVisibility;
|
||||
|
||||
public MultiValueAlpha(View view, int size) {
|
||||
mView = view;
|
||||
@@ -66,6 +70,11 @@ public class MultiValueAlpha {
|
||||
return mMyProperties[index];
|
||||
}
|
||||
|
||||
/** Sets whether we should update between INVISIBLE and VISIBLE based on alpha. */
|
||||
public void setUpdateVisibility(boolean updateVisibility) {
|
||||
mUpdateVisibility = updateVisibility;
|
||||
}
|
||||
|
||||
public class AlphaProperty {
|
||||
|
||||
private final int mMyMask;
|
||||
@@ -99,6 +108,9 @@ public class MultiValueAlpha {
|
||||
mValue = value;
|
||||
|
||||
mView.setAlpha(mOthers * mValue);
|
||||
if (mUpdateVisibility) {
|
||||
AlphaUpdateListener.updateVisibility(mView);
|
||||
}
|
||||
}
|
||||
|
||||
public float getValue() {
|
||||
|
||||
Reference in New Issue
Block a user