Add translation component to swipe up resistance

Now recents view follows your finger all the way to the top of the
screen. Specifically, your finger tracks the bottom of the window
until resistance starts (when RecentsView is at 75% scale), then
we add translation to compensate for the slower rate of scaling
down, such that your finger slips to the top of the window by the
time it reaches the top of the screen.

Also reset this translation back to 0 in the state handlers.

Bug: 149934536
Fixes: 158701272
Change-Id: Iaee58da758d422f0173c29d002f5c451ce0c1809
This commit is contained in:
Tony Wickham
2020-07-01 17:25:28 -07:00
parent 3f20e33af6
commit ce8b2b5180
12 changed files with 78 additions and 13 deletions

View File

@@ -101,7 +101,8 @@ public abstract class SwipeUpAnimationLogic {
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

View File

@@ -19,6 +19,7 @@ import static com.android.launcher3.anim.Interpolators.LINEAR;
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.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_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 @@ public class FallbackRecentsStateController implements StateHandler<RecentsState
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));

View File

@@ -90,7 +90,6 @@ public class RecentsState implements BaseState<RecentsState> {
return new float[] { NO_SCALE, NO_OFFSET };
}
private static class ModalState extends RecentsState {
public ModalState(int id, int flags) {

View File

@@ -90,6 +90,7 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
// 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 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
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

View File

@@ -210,6 +210,19 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
}
};
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 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
view.setScaleY(scale);
view.mLastComputedTaskPushOutDistance = null;
view.updatePageOffsets();
view.setTaskViewsSecondaryTranslation(view.mTaskViewsSecondaryTranslation);
}
@Override
@@ -269,6 +283,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
protected boolean mFreezeViewVisibility;
private float mAdjacentPageOffset = 0;
private float mTaskViewsSecondaryTranslation = 0;
/**
* TODO: Call reloadIdNeeded in onTaskStackChanged.
@@ -1391,7 +1406,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
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)
@@ -1908,6 +1923,14 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
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
*/

View File

@@ -24,11 +24,13 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MO
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 @@ public abstract class BaseRecentsViewStateController<T extends RecentsView>
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 @@ public abstract class BaseRecentsViewStateController<T extends RecentsView>
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));

View File

@@ -28,6 +28,7 @@ import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_REC
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 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
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

View File

@@ -21,8 +21,10 @@ import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
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 com.android.launcher3.DeviceProfile;
@@ -57,6 +59,7 @@ public class AnimatorControllerWithResistance {
private static final float RECENTS_SCALE_MAX_RESIST = 0.5f;
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 +107,14 @@ public class AnimatorControllerWithResistance {
* @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) {
Rect startRect = new Rect();
LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, startRect,
recentsOrientedState.getOrientationHandler());
@@ -150,6 +156,19 @@ public class AnimatorControllerWithResistance {
resistAnim.addFloat(scaleTarget, scaleProperty, startScale, endScale,
scaleInterpolator);
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(RECENTS_SCALE_MAX_RESIST, RECENTS_SCALE_MAX_RESIST, 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();
resistAnim.addFloat(translationTarget, translationProperty, 0, endTranslation,
RECENTS_TRANSLATE_RESIST_INTERPOLATOR);
}
AnimatorPlaybackController resistanceController = resistAnim.createPlaybackController();
return new AnimatorControllerWithResistance(normalController, resistanceController);
}

View File

@@ -107,6 +107,11 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
action.call(target, 0, param);
}
@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);
@@ -219,8 +224,7 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
return -1;
}
@Override
public int getTaskDismissDirectionFactor() {
public int getSecondaryTranslationDirectionFactor() {
return 1;
}

View File

@@ -57,6 +57,7 @@ public interface PagedOrientationHandler {
<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);
@@ -75,7 +76,7 @@ public interface PagedOrientationHandler {
int getScrollOffsetEnd(View view, Rect insets);
SingleAxisSwipeDetector.Direction getOppositeSwipeDirection();
int getPrimaryTranslationDirectionFactor();
int getTaskDismissDirectionFactor();
int getSecondaryTranslationDirectionFactor();
int getTaskDragDisplacementFactor(boolean isRtl);
ChildBounds getChildBounds(View child, int childStart, int pageCenter, boolean layoutChild);
void setMaxScroll(AccessibilityEvent event, int maxScroll);

View File

@@ -104,6 +104,11 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
action.call(target, param, 0);
}
@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);
@@ -216,8 +221,7 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
return 1;
}
@Override
public int getTaskDismissDirectionFactor() {
public int getSecondaryTranslationDirectionFactor() {
return -1;
}

View File

@@ -28,7 +28,7 @@ import com.android.launcher3.Utilities;
public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
@Override
public int getTaskDismissDirectionFactor() {
public int getSecondaryTranslationDirectionFactor() {
return -1;
}