Merge "Fix TaskViewTouchController success progress to match haptic" into ub-launcher3-rvc-qpr-dev
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 085b9b3..5ccc1e8 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -17,6 +17,7 @@
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 @@
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 @@
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
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 131fcbf..daa1aad 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -25,6 +25,7 @@
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 @@
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 @@
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 @@
: 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) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index c1a585e..61f6702 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -19,13 +19,13 @@
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.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.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 @@
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 @@
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(false /* mightNeedToRefill */));
@@ -212,8 +222,13 @@
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);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 9316938..dbff20a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -21,11 +21,8 @@
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 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 @@
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 @@
mToState.getOverviewScrimAlpha(mLauncher));
}
mReachedOverview = false;
+ mOverviewResistYAnim = null;
}
@Override
@@ -160,6 +159,9 @@
mNormalToHintOverviewScrimAnimator = null;
mCurrentAnimation.dispatchOnCancelWithoutCancelRunnable(() -> {
mLauncher.getStateManager().goToState(OVERVIEW, true, () -> {
+ mOverviewResistYAnim = AnimatorControllerWithResistance
+ .createRecentsResistanceFromOverviewAnim(mLauncher, null)
+ .createPlaybackController();
mReachedOverview = true;
maybeSwipeInteractionToOverviewComplete();
});
@@ -173,13 +175,6 @@
}
}
- // 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 @@
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 @@
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 @@
.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();
+ }
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 821ada4..5c9fd47 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -22,7 +22,6 @@
import static com.android.launcher3.LauncherState.QUICK_SWITCH;
import static com.android.launcher3.anim.AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD;
import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
-import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_5;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
@@ -47,6 +46,7 @@
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
+import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import android.animation.Animator;
@@ -74,7 +74,9 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.VibratorWrapper;
+import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.util.ShelfPeekAnim;
@@ -90,16 +92,17 @@
BothAxesSwipeDetector.Listener, MotionPauseDetector.OnMotionPauseListener {
/** The minimum progress of the scale/translationY animation until drag end. */
- private static final float Y_ANIM_MIN_PROGRESS = 0.15f;
+ private static final float Y_ANIM_MIN_PROGRESS = 0.25f;
private static final Interpolator FADE_OUT_INTERPOLATOR = DEACCEL_5;
private static final Interpolator TRANSLATE_OUT_INTERPOLATOR = ACCEL_0_75;
- private static final Interpolator SCALE_DOWN_INTERPOLATOR = DEACCEL;
+ private static final Interpolator SCALE_DOWN_INTERPOLATOR = LINEAR;
private final BaseQuickstepLauncher mLauncher;
private final BothAxesSwipeDetector mSwipeDetector;
private final ShelfPeekAnim mShelfPeekAnim;
private final float mXRange;
private final float mYRange;
+ private final float mMaxYProgress;
private final MotionPauseDetector mMotionPauseDetector;
private final float mMotionPauseMinDisplacement;
private final LauncherRecentsView mRecentsView;
@@ -113,7 +116,7 @@
// and the other two to set overview properties based on x and y progress.
private AnimatorPlaybackController mNonOverviewAnim;
private AnimatorPlaybackController mXOverviewAnim;
- private AnimatorPlaybackController mYOverviewAnim;
+ private AnimatedFloat mYOverviewAnim;
public NoButtonQuickSwitchTouchController(BaseQuickstepLauncher launcher) {
mLauncher = launcher;
@@ -123,6 +126,7 @@
mXRange = mLauncher.getDeviceProfile().widthPx / 2f;
mYRange = LayoutUtils.getShelfTrackingDistance(
mLauncher, mLauncher.getDeviceProfile(), mRecentsView.getPagedOrientationHandler());
+ mMaxYProgress = mLauncher.getDeviceProfile().heightPx / mYRange;
mMotionPauseDetector = new MotionPauseDetector(mLauncher);
mMotionPauseMinDisplacement = mLauncher.getResources().getDimension(
R.dimen.motion_pause_detector_min_displacement_from_app);
@@ -270,8 +274,18 @@
SCALE_DOWN_INTERPOLATOR);
yAnim.setFloat(mRecentsView, FULLSCREEN_PROGRESS,
toState.getOverviewFullscreenProgress(), SCALE_DOWN_INTERPOLATOR);
- mYOverviewAnim = yAnim.createPlaybackController();
- mYOverviewAnim.dispatchOnStart();
+ AnimatorPlaybackController yNormalController = yAnim.createPlaybackController();
+ AnimatorControllerWithResistance yAnimWithResistance = AnimatorControllerWithResistance
+ .createForRecents(yNormalController, mLauncher,
+ mRecentsView.getPagedViewOrientedState(), mLauncher.getDeviceProfile(),
+ mRecentsView, RECENTS_SCALE_PROPERTY, mRecentsView,
+ TASK_SECONDARY_TRANSLATION);
+ mYOverviewAnim = new AnimatedFloat(() -> {
+ if (mYOverviewAnim != null) {
+ yAnimWithResistance.setProgress(mYOverviewAnim.value, mMaxYProgress);
+ }
+ });
+ yNormalController.dispatchOnStart();
}
@Override
@@ -307,7 +321,7 @@
mXOverviewAnim.setPlayFraction(xProgress);
}
if (mYOverviewAnim != null) {
- mYOverviewAnim.setPlayFraction(yProgress);
+ mYOverviewAnim.updateValue(yProgress);
}
return true;
}
@@ -354,9 +368,11 @@
} else if (verticalFling) {
targetState = velocity.y > 0 ? QUICK_SWITCH : NORMAL;
} else {
- // If user isn't flinging, just snap to the closest state based on x progress.
+ // If user isn't flinging, just snap to the closest state.
boolean passedHorizontalThreshold = mXOverviewAnim.getInterpolatedProgress() > 0.5f;
- targetState = passedHorizontalThreshold ? QUICK_SWITCH : NORMAL;
+ boolean passedVerticalThreshold = mYOverviewAnim.value > 1f;
+ targetState = passedHorizontalThreshold && !passedVerticalThreshold
+ ? QUICK_SWITCH : NORMAL;
}
// Animate the various components to the target state.
@@ -375,9 +391,9 @@
boolean flingUpToNormal = verticalFling && velocity.y < 0 && targetState == NORMAL;
- float yProgress = mYOverviewAnim.getProgressFraction();
+ float yProgress = mYOverviewAnim.value;
float startYProgress = Utilities.boundToRange(yProgress
- - velocity.y * getSingleFrameMs(mLauncher) / mYRange, 0f, 1f);
+ - velocity.y * getSingleFrameMs(mLauncher) / mYRange, 0f, mMaxYProgress);
final float endYProgress;
if (flingUpToNormal) {
endYProgress = 1;
@@ -387,12 +403,11 @@
} else {
endYProgress = 0;
}
- long yDuration = BaseSwipeDetector.calculateDuration(velocity.y,
- Math.abs(endYProgress - startYProgress));
- ValueAnimator yOverviewAnim = mYOverviewAnim.getAnimationPlayer();
- yOverviewAnim.setFloatValues(startYProgress, endYProgress);
+ float yDistanceToCover = Math.abs(endYProgress - startYProgress) * mYRange;
+ long yDuration = (long) (yDistanceToCover / Math.max(1f, Math.abs(velocity.y)));
+ ValueAnimator yOverviewAnim = mYOverviewAnim.animateToValue(startYProgress, endYProgress);
yOverviewAnim.setDuration(yDuration);
- mYOverviewAnim.dispatchOnStart();
+ mYOverviewAnim.updateValue(startYProgress);
ValueAnimator nonOverviewAnim = mNonOverviewAnim.getAnimationPlayer();
if (flingUpToNormal && !mIsHomeScreenVisible) {
@@ -457,7 +472,7 @@
mXOverviewAnim.getAnimationPlayer().cancel();
}
if (mYOverviewAnim != null) {
- mYOverviewAnim.getAnimationPlayer().cancel();
+ mYOverviewAnim.cancelAnimation();
}
mShelfPeekAnim.setShelfState(ShelfAnimState.CANCEL, LINEAR, 0);
mMotionPauseDetector.clear();
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
index 929b11a..ed33532 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
@@ -488,6 +488,16 @@
recentsAttachedToAppWindow = mIsShelfPeeking || mIsLikelyToStartNewTask;
}
mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
+
+ // Reapply window transform throughout the attach animation, as the animation affects how
+ // much the window is bound by overscroll (vs moving freely).
+ if (animate) {
+ ValueAnimator reapplyWindowTransformAnim = ValueAnimator.ofFloat(0, 1);
+ reapplyWindowTransformAnim.addUpdateListener(anim -> applyWindowTransform());
+ reapplyWindowTransformAnim.setDuration(RECENTS_ATTACH_DURATION).start();
+ } else {
+ applyWindowTransform();
+ }
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java
index 137f8091..2963b6c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -101,7 +101,8 @@
AnimatorPlaybackController normalController = pa.createPlaybackController();
mWindowTransitionController = AnimatorControllerWithResistance.createForRecents(
normalController, mContext, mTaskViewSimulator.getOrientationState(),
- mDp, mTaskViewSimulator.recentsViewScale, AnimatedFloat.VALUE);
+ mDp, mTaskViewSimulator.recentsViewScale, AnimatedFloat.VALUE,
+ mTaskViewSimulator.recentsViewSecondaryTranslation, AnimatedFloat.VALUE);
}
@UiThread
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 163c232..24a7610 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL;
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 static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
@@ -26,6 +27,7 @@
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
+import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
@@ -86,6 +88,8 @@
config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
setter.setFloat(mRecentsView, ADJACENT_PAGE_OFFSET, scaleAndOffset[1],
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
+ setter.setFloat(mRecentsView, TASK_SECONDARY_TRANSLATION, 0f,
+ config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
setter.setFloat(mRecentsView, TASK_MODALNESS, state.getOverviewModalness(),
config.getInterpolator(ANIM_OVERVIEW_MODAL, LINEAR));
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsState.java
index 211a30c..f15a9de 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsState.java
@@ -90,7 +90,6 @@
return new float[] { NO_SCALE, NO_OFFSET };
}
-
private static class ModalState extends RecentsState {
public ModalState(int id, int flags) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/OverviewToHomeAnim.java
new file mode 100644
index 0000000..d2e1ded
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/OverviewToHomeAnim.java
@@ -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);
+ }
+ }
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
index c5918fe..db64464 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -90,6 +90,7 @@
// RecentsView properties
public final AnimatedFloat recentsViewScale = new AnimatedFloat();
public final AnimatedFloat fullScreenProgress = new AnimatedFloat();
+ public final AnimatedFloat recentsViewSecondaryTranslation = new AnimatedFloat();
private final ScrollState mScrollState = new ScrollState();
// Cached calculations
@@ -274,8 +275,10 @@
mOrientationState.getOrientationHandler().set(
mMatrix, MATRIX_POST_TRANSLATE, mScrollState.scroll);
- // Apply recensView matrix
+ // Apply RecentsView matrix
mMatrix.postScale(recentsViewScale.value, recentsViewScale.value, mPivot.x, mPivot.y);
+ mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
+ recentsViewSecondaryTranslation.value);
applyWindowToHomeRotation(mMatrix);
// Crop rect is the inverse of thumbnail matrix
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
index 79d57c5..1bf2fbf 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
@@ -105,6 +105,7 @@
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 @@
}
boolean isHidden = mHiddenFlags != 0;
mMultiValueAlpha.getProperty(INDEX_HIDDEN_FLAGS_ALPHA).setValue(isHidden ? 0 : 1);
- setVisibility(isHidden ? INVISIBLE : VISIBLE);
}
/**
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 857a020..217997d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -210,6 +210,19 @@
}
};
+ public static final FloatProperty<RecentsView> TASK_SECONDARY_TRANSLATION =
+ new FloatProperty<RecentsView>("taskSecondaryTranslation") {
+ @Override
+ public void setValue(RecentsView recentsView, float v) {
+ recentsView.setTaskViewsSecondaryTranslation(v);
+ }
+
+ @Override
+ public Float get(RecentsView recentsView) {
+ return recentsView.mTaskViewsSecondaryTranslation;
+ }
+ };
+
/** Same as normal SCALE_PROPERTY, but also updates page offsets that depend on this scale. */
public static final FloatProperty<RecentsView> RECENTS_SCALE_PROPERTY =
new FloatProperty<RecentsView>("recentsScale") {
@@ -219,6 +232,7 @@
view.setScaleY(scale);
view.mLastComputedTaskPushOutDistance = null;
view.updatePageOffsets();
+ view.setTaskViewsSecondaryTranslation(view.mTaskViewsSecondaryTranslation);
}
@Override
@@ -269,6 +283,7 @@
protected boolean mFreezeViewVisibility;
private float mAdjacentPageOffset = 0;
+ private float mTaskViewsSecondaryTranslation = 0;
/**
* TODO: Call reloadIdNeeded in onTaskStackChanged.
@@ -1391,7 +1406,7 @@
FloatProperty<View> secondaryViewTranslate =
mOrientationHandler.getSecondaryViewTranslate();
int secondaryTaskDimension = mOrientationHandler.getSecondaryDimension(taskView);
- int verticalFactor = mOrientationHandler.getTaskDismissDirectionFactor();
+ int verticalFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor();
ResourceProvider rp = DynamicResource.provider(mActivity);
SpringProperty sp = new SpringProperty(SpringProperty.FLAG_CAN_SPRING_ON_START)
@@ -1853,7 +1868,9 @@
: i < modalMidpoint
? modalLeftOffsetSize
: modalRightOffsetSize;
- getChildAt(i).setTranslationX(translation + modalTranslation);
+ float totalTranslation = translation + modalTranslation;
+ mOrientationHandler.getPrimaryViewTranslate().set(getChildAt(i),
+ totalTranslation * mOrientationHandler.getPrimaryTranslationDirectionFactor());
}
updateCurveProperties();
}
@@ -1906,6 +1923,14 @@
return distanceToOffscreen * offsetProgress;
}
+ private void setTaskViewsSecondaryTranslation(float translation) {
+ mTaskViewsSecondaryTranslation = translation;
+ for (int i = 0; i < getTaskViewCount(); i++) {
+ TaskView task = getTaskViewAt(i);
+ mOrientationHandler.getSecondaryViewTranslate().set(task, translation / getScaleY());
+ }
+ }
+
/**
* TODO: Do not assume motion across X axis for adjacent page
*/
@@ -2290,7 +2315,14 @@
if (pageIndex == -1) {
return 0;
}
- return getScrollForPage(pageIndex) - mOrientationHandler.getPrimaryScroll(this);
+ // Unbound the scroll (due to overscroll) if the adjacent tasks are offset away from it.
+ // This allows the page to move freely, given there's no visual indication why it shouldn't.
+ int boundedScroll = mOrientationHandler.getPrimaryScroll(this);
+ int unboundedScroll = getUnboundedScroll();
+ float unboundedProgress = mAdjacentPageOffset;
+ int scroll = Math.round(unboundedScroll * unboundedProgress
+ + boundedScroll * (1 - unboundedProgress));
+ return getScrollForPage(pageIndex) - scroll;
}
public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
index a8d6442..fad6427 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -479,17 +479,18 @@
boolean isOrientationDifferent;
mClipBottom = -1;
+ int thumbnailRotation = thumbnailData.rotation;
+ int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation);
+ Rect thumbnailInsets = getBoundedInsets(
+ dp.getInsets(), thumbnailData.insets, deltaRotate);
+
float scale = thumbnailData.scale;
- Rect activityInsets = dp.getInsets();
- Rect thumbnailInsets = getBoundedInsets(activityInsets, thumbnailData.insets);
final float thumbnailWidth = thumbnailPosition.width()
- (thumbnailInsets.left + thumbnailInsets.right) * scale;
final float thumbnailHeight = thumbnailPosition.height()
- (thumbnailInsets.top + thumbnailInsets.bottom) * scale;
final float thumbnailScale;
- int thumbnailRotation = thumbnailData.rotation;
- int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation);
// Landscape vs portrait change
boolean windowingModeSupportsRotation = !dp.isMultiWindowMode
@@ -558,7 +559,10 @@
mIsOrientationChanged = isOrientationDifferent;
}
- private Rect getBoundedInsets(Rect activityInsets, Rect insets) {
+ private Rect getBoundedInsets(Rect activityInsets, Rect insets, int deltaRotation) {
+ if (deltaRotation != 0) {
+ return insets;
+ }
return new Rect(Math.min(insets.left, activityInsets.left),
Math.min(insets.top, activityInsets.top),
Math.min(insets.right, activityInsets.right),
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 6e120e8..1b8e244 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -24,11 +24,13 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCRIM_FADE;
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 static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
+import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.util.FloatProperty;
@@ -63,6 +65,7 @@
float[] scaleAndOffset = state.getOverviewScaleAndOffset(mLauncher);
RECENTS_SCALE_PROPERTY.set(mRecentsView, scaleAndOffset[0]);
ADJACENT_PAGE_OFFSET.set(mRecentsView, scaleAndOffset[1]);
+ TASK_SECONDARY_TRANSLATION.set(mRecentsView, 0f);
getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
@@ -97,6 +100,8 @@
config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
setter.setFloat(mRecentsView, ADJACENT_PAGE_OFFSET, scaleAndOffset[1],
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
+ setter.setFloat(mRecentsView, TASK_SECONDARY_TRANSLATION, 0f,
+ config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 31630ff..bdf525d 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -28,6 +28,7 @@
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
+import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.animation.Animator;
import android.annotation.TargetApi;
@@ -357,7 +358,8 @@
AnimatorControllerWithResistance controllerWithResistance =
AnimatorControllerWithResistance.createForRecents(controller, mActivity,
recentsView.getPagedViewOrientedState(), mActivity.getDeviceProfile(),
- recentsView, RECENTS_SCALE_PROPERTY);
+ recentsView, RECENTS_SCALE_PROPERTY, recentsView,
+ TASK_SECONDARY_TRANSLATION);
mCallback.accept(controllerWithResistance);
// Creating the activity controller animation sometimes reapplies the launcher state
diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
index d58329a..a19a67c 100644
--- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
+++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
@@ -18,19 +18,27 @@
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;
+import android.graphics.Matrix;
import android.graphics.PointF;
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
@@ -46,17 +54,35 @@
*/
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;
private final AnimatorPlaybackController mNormalController;
private final AnimatorPlaybackController mResistanceController;
@@ -104,11 +130,32 @@
* @param dp Used to compute start and end values.
* @param scaleTarget The target for the scaleProperty.
* @param scaleProperty Animate the value to change the scale of the window/recents view.
+ * @param translationTarget The target for the translationProperty.
+ * @param translationProperty Animate the value to change the translation of the recents view.
*/
- public static <SCALE> AnimatorControllerWithResistance createForRecents(
+ public static <SCALE, TRANSLATION> AnimatorControllerWithResistance createForRecents(
AnimatorPlaybackController normalController, Context context,
RecentsOrientedState recentsOrientedState, DeviceProfile dp, SCALE scaleTarget,
- FloatProperty<SCALE> scaleProperty) {
+ 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());
@@ -119,7 +166,9 @@
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(
@@ -135,9 +184,9 @@
} 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;
@@ -150,8 +199,32 @@
resistAnim.addFloat(scaleTarget, scaleProperty, startScale, endScale,
scaleInterpolator);
- AnimatorPlaybackController resistanceController = resistAnim.createPlaybackController();
- return new AnimatorControllerWithResistance(normalController, resistanceController);
+ if (!isTwoButtonMode) {
+ // 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(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() * params.translationFactor;
+ resistAnim.addFloat(translationTarget, translationProperty, 0, endTranslation,
+ RECENTS_TRANSLATE_RESIST_INTERPOLATOR);
+ }
+
+ 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);
+ }
}
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index f2a5c65..833ce15 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -42,6 +42,7 @@
import androidx.annotation.Nullable;
+import com.android.launcher3.Launcher.OnResumeCallback;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
@@ -108,10 +109,20 @@
private void updateTheme() {
if (mThemeRes != Themes.getActivityThemeRes(this)) {
- recreate();
+ // Workaround (b/162812884): The system currently doesn't allow recreating an activity
+ // when it is not resumed, in such a case defer recreation until it is possible
+ if (hasBeenResumed()) {
+ recreate();
+ } else {
+ addOnResumeCallback(this::recreate);
+ }
}
}
+ protected void addOnResumeCallback(OnResumeCallback callback) {
+ // To be overridden
+ }
+
@Override
public void onActionModeStarted(ActionMode mode) {
super.onActionModeStarted(mode);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 4675362..03e4b06 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1943,6 +1943,7 @@
return result;
}
+ @Override
public void addOnResumeCallback(OnResumeCallback callback) {
mOnResumeCallbacks.add(callback);
}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 2abde02..e754618 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -316,7 +316,10 @@
LAUNCHER_NAVIGATION_MODE_2_BUTTON(624),
@UiEvent(doc = "System navigation mode is 0 button mode/gesture navigation mode .")
- LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON(625);
+ LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON(625),
+
+ @UiEvent(doc = "User tapped on image content in Overview Select mode.")
+ LAUNCHER_SELECT_MODE_IMAGE(627);
// ADD MORE
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
index f90ad3c..8b72177 100644
--- a/src/com/android/launcher3/states/StateAnimationConfig.java
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -71,6 +71,7 @@
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 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() { }
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 1aaa608..4fd1633 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -108,6 +108,11 @@
}
@Override
+ public <T> void setSecondary(T target, Float2DAction<T> action, float param) {
+ action.call(target, param, 0);
+ }
+
+ @Override
public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
return event.getY(pointerIndex);
}
@@ -215,7 +220,11 @@
}
@Override
- public int getTaskDismissDirectionFactor() {
+ public int getPrimaryTranslationDirectionFactor() {
+ return -1;
+ }
+
+ public int getSecondaryTranslationDirectionFactor() {
return 1;
}
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index f88cdb3..c0d488b 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -57,6 +57,7 @@
<T> void set(T target, Int2DAction<T> action, int param);
<T> void set(T target, Float2DAction<T> action, float param);
+ <T> void setSecondary(T target, Float2DAction<T> action, float param);
float getPrimaryDirection(MotionEvent event, int pointerIndex);
float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId);
int getMeasuredSize(View view);
@@ -74,7 +75,8 @@
int getScrollOffsetStart(View view, Rect insets);
int getScrollOffsetEnd(View view, Rect insets);
SingleAxisSwipeDetector.Direction getOppositeSwipeDirection();
- int getTaskDismissDirectionFactor();
+ int getPrimaryTranslationDirectionFactor();
+ int getSecondaryTranslationDirectionFactor();
int getTaskDragDisplacementFactor(boolean isRtl);
ChildBounds getChildBounds(View child, int childStart, int pageCenter, boolean layoutChild);
void setMaxScroll(AccessibilityEvent event, int maxScroll);
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index f18b109..9e53e5f 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -105,6 +105,11 @@
}
@Override
+ public <T> void setSecondary(T target, Float2DAction<T> action, float param) {
+ action.call(target, 0, param);
+ }
+
+ @Override
public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
return event.getX(pointerIndex);
}
@@ -212,7 +217,11 @@
}
@Override
- public int getTaskDismissDirectionFactor() {
+ public int getPrimaryTranslationDirectionFactor() {
+ return 1;
+ }
+
+ public int getSecondaryTranslationDirectionFactor() {
return -1;
}
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index e91f16d..7153452 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -28,7 +28,7 @@
public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
@Override
- public int getTaskDismissDirectionFactor() {
+ public int getSecondaryTranslationDirectionFactor() {
return -1;
}
diff --git a/src/com/android/launcher3/util/MultiValueAlpha.java b/src/com/android/launcher3/util/MultiValueAlpha.java
index a8642b0..5be9529 100644
--- a/src/com/android/launcher3/util/MultiValueAlpha.java
+++ b/src/com/android/launcher3/util/MultiValueAlpha.java
@@ -19,6 +19,8 @@
import android.util.FloatProperty;
import android.view.View;
+import com.android.launcher3.anim.AlphaUpdateListener;
+
import java.util.Arrays;
/**
@@ -44,6 +46,8 @@
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 @@
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 @@
mValue = value;
mView.setAlpha(mOthers * mValue);
+ if (mUpdateVisibility) {
+ AlphaUpdateListener.updateVisibility(mView);
+ }
}
public float getValue() {