Update animations for TM-QPR: Overview > OverviewSplitSelect transition
This change updates the Overview > OverviewSplitSelect animation to the latest spec. This is a re-upload of a previous change, ag/19464657, but no longer will cause the b/241165022 issue. Includes: - New timings - Task thumbnails slide in with an "overshoot" animation - Icons fade out and fade in appropriately - SplitInstructionsView has a new compound "unfold" animation Bug: 236760307 Test: Manual on tablet. Made sure the b/241165022 issue is fixed. Change-Id: Ia22f6b6d7b9474b782e693fae2320a34a2985b18
This commit is contained in:
@@ -33,7 +33,6 @@ import android.util.FloatProperty;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.anim.AnimatorListeners;
|
||||
@@ -71,7 +70,10 @@ public final class RecentsViewStateController extends
|
||||
// DepthController to prevent optimizations which might occlude the layers behind
|
||||
mLauncher.getDepthController().setHasContentBehindLauncher(state.overviewUi);
|
||||
|
||||
handleSplitSelectionState(state, null);
|
||||
PendingAnimation builder =
|
||||
new PendingAnimation(state.getTransitionDuration(mLauncher, true));
|
||||
|
||||
handleSplitSelectionState(state, builder, /* animate */false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,7 +94,7 @@ public final class RecentsViewStateController extends
|
||||
builder.addListener(AnimatorListeners.forSuccessCallback(() ->
|
||||
mLauncher.getDepthController().setHasContentBehindLauncher(toState.overviewUi)));
|
||||
|
||||
handleSplitSelectionState(toState, builder);
|
||||
handleSplitSelectionState(toState, builder, /* animate */true);
|
||||
|
||||
setAlphas(builder, config, toState);
|
||||
builder.setFloat(mRecentsView, FULLSCREEN_PROGRESS,
|
||||
@@ -105,8 +107,7 @@ public final class RecentsViewStateController extends
|
||||
* will add animations to builder.
|
||||
*/
|
||||
private void handleSplitSelectionState(@NonNull LauncherState toState,
|
||||
@Nullable PendingAnimation builder) {
|
||||
boolean animate = builder != null;
|
||||
@NonNull PendingAnimation builder, boolean animate) {
|
||||
PagedOrientationHandler orientationHandler =
|
||||
((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
|
||||
Pair<FloatProperty, FloatProperty> taskViewsFloat =
|
||||
@@ -115,18 +116,15 @@ public final class RecentsViewStateController extends
|
||||
mLauncher.getDeviceProfile());
|
||||
|
||||
if (toState == OVERVIEW_SPLIT_SELECT) {
|
||||
// Animation to "dismiss" selected taskView
|
||||
PendingAnimation splitSelectInitAnimation = mRecentsView.createSplitSelectInitAnimation(
|
||||
mRecentsView.createSplitSelectInitAnimation(builder,
|
||||
toState.getTransitionDuration(mLauncher, true /* isToState */));
|
||||
// Add properties to shift remaining taskViews to get out of placeholder view
|
||||
splitSelectInitAnimation.setFloat(mRecentsView, taskViewsFloat.first,
|
||||
builder.setFloat(mRecentsView, taskViewsFloat.first,
|
||||
toState.getSplitSelectTranslation(mLauncher), LINEAR);
|
||||
splitSelectInitAnimation.setFloat(mRecentsView, taskViewsFloat.second, 0, LINEAR);
|
||||
builder.setFloat(mRecentsView, taskViewsFloat.second, 0, LINEAR);
|
||||
|
||||
if (!animate) {
|
||||
splitSelectInitAnimation.buildAnim().start();
|
||||
} else {
|
||||
builder.add(splitSelectInitAnimation.buildAnim());
|
||||
builder.buildAnim().start();
|
||||
}
|
||||
|
||||
mRecentsView.applySplitPrimaryScrollOffset();
|
||||
|
||||
+12
@@ -79,6 +79,14 @@ public class QuickstepAtomicAnimationFactory extends
|
||||
private static final int PER_PAGE_SCROLL_DURATION = 150;
|
||||
private static final int MAX_PAGE_SCROLL_DURATION = 750;
|
||||
|
||||
private static final int OVERVIEW_TO_SPLIT_ACTIONS_FADE_START = 0;
|
||||
private static final int OVERVIEW_TO_SPLIT_ACTIONS_FADE_END = 83;
|
||||
|
||||
private static final float OVERVIEW_TO_SPLIT_ACTIONS_FADE_START_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_ACTIONS_FADE_START / SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float OVERVIEW_TO_SPLIT_ACTIONS_FADE_END_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_ACTIONS_FADE_END / SplitScreenSelectState.ENTER_DURATION;
|
||||
|
||||
// Due to use of physics, duration may differ between devices so we need to calculate and
|
||||
// cache the value.
|
||||
private int mHintToNormalDuration = -1;
|
||||
@@ -188,6 +196,10 @@ public class QuickstepAtomicAnimationFactory extends
|
||||
AllAppsSwipeController.applyAllAppsToNormalConfig(mActivity, config);
|
||||
} else if (fromState == NORMAL && toState == ALL_APPS) {
|
||||
AllAppsSwipeController.applyNormalToAllAppsAnimConfig(mActivity, config);
|
||||
} else if (fromState == OVERVIEW && toState == OVERVIEW_SPLIT_SELECT) {
|
||||
config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, clampToProgress(LINEAR,
|
||||
OVERVIEW_TO_SPLIT_ACTIONS_FADE_START_OFFSET,
|
||||
OVERVIEW_TO_SPLIT_ACTIONS_FADE_END_OFFSET));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.launcher3.uioverrides.states;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
@@ -24,6 +26,10 @@ import com.android.quickstep.views.RecentsView;
|
||||
* pinned and user is selecting the second one
|
||||
*/
|
||||
public class SplitScreenSelectState extends OverviewState {
|
||||
public static final int ENTER_DURATION = 866;
|
||||
public static final int EXIT_DURATION = 500;
|
||||
// TODO: Add ability to differentiate between Split > Home and Split > Confirmed timings
|
||||
|
||||
public SplitScreenSelectState(int id) {
|
||||
super(id);
|
||||
}
|
||||
@@ -38,4 +44,9 @@ public class SplitScreenSelectState extends OverviewState {
|
||||
RecentsView recentsView = launcher.getOverviewPanel();
|
||||
return recentsView.getSplitSelectTranslation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTransitionDuration(Context context, boolean isToState) {
|
||||
return isToState ? ENTER_DURATION : EXIT_DURATION;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -236,7 +236,8 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
PendingAnimation pa;
|
||||
if (goingUp) {
|
||||
currentInterpolator = Interpolators.LINEAR;
|
||||
pa = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
|
||||
pa = new PendingAnimation(maxDuration);
|
||||
mRecentsView.createTaskDismissAnimation(pa, mTaskBeingDragged,
|
||||
true /* animateTaskView */, true /* removeTask */, maxDuration,
|
||||
false /* dismissingForSplitSelection*/);
|
||||
|
||||
|
||||
@@ -114,8 +114,11 @@ public class FallbackRecentsStateController implements StateHandler<RecentsState
|
||||
|
||||
RecentsState currentState = mActivity.getStateManager().getState();
|
||||
if (isSplitSelectionState(state) && !isSplitSelectionState(currentState)) {
|
||||
setter.add(mRecentsView.createSplitSelectInitAnimation(
|
||||
state.getTransitionDuration(mActivity, true /* isToState */)).buildAnim());
|
||||
int duration = state.getTransitionDuration(mActivity, true /* isToState */);
|
||||
// TODO (b/246851887): Pass in setter as a NO_ANIM PendingAnimation instead
|
||||
PendingAnimation pa = new PendingAnimation(duration);
|
||||
mRecentsView.createSplitSelectInitAnimation(pa, duration);
|
||||
setter.add(pa.buildAnim());
|
||||
}
|
||||
|
||||
Pair<FloatProperty, FloatProperty> taskViewsFloat =
|
||||
|
||||
@@ -54,6 +54,8 @@ import java.util.ArrayList;
|
||||
public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsState>
|
||||
implements StateListener<RecentsState> {
|
||||
|
||||
private static final int TASK_DISMISS_DURATION = 150;
|
||||
|
||||
@Nullable
|
||||
private Task mHomeTask;
|
||||
|
||||
@@ -105,8 +107,9 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsSta
|
||||
if (mHomeTask != null && endTarget == RECENTS && animatorSet != null) {
|
||||
TaskView tv = getTaskViewByTaskId(mHomeTask.key.id);
|
||||
if (tv != null) {
|
||||
PendingAnimation pa = createTaskDismissAnimation(tv, true, false, 150,
|
||||
false /* dismissingForSplitSelection*/);
|
||||
PendingAnimation pa = new PendingAnimation(TASK_DISMISS_DURATION);
|
||||
createTaskDismissAnimation(pa, tv, true, false,
|
||||
TASK_DISMISS_DURATION, false /* dismissingForSplitSelection*/);
|
||||
pa.addEndListener(e -> setCurrentTask(-1));
|
||||
AnimatorPlaybackController controller = pa.createPlaybackController();
|
||||
controller.dispatchOnStart();
|
||||
|
||||
@@ -2,8 +2,10 @@ package com.android.quickstep.views;
|
||||
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
|
||||
import static com.android.launcher3.anim.Interpolators.INSTANT;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.clampToProgress;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
@@ -24,12 +26,12 @@ import androidx.annotation.Nullable;
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.InsettableFrameLayout;
|
||||
import com.android.launcher3.LauncherAnimUtils;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.statemanager.StatefulActivity;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.uioverrides.states.SplitScreenSelectState;
|
||||
import com.android.launcher3.util.SplitConfigurationOptions;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.quickstep.util.MultiValueUpdateListener;
|
||||
@@ -49,6 +51,31 @@ import com.android.systemui.shared.system.QuickStepContract;
|
||||
* TODO: Figure out how to copy thumbnail data from existing TaskView to this view.
|
||||
*/
|
||||
public class FloatingTaskView extends FrameLayout {
|
||||
private static final int OVERVIEW_TO_SPLIT_THUMBNAIL_FADE_TO_GRAY_START = 0;
|
||||
private static final int OVERVIEW_TO_SPLIT_THUMBNAIL_FADE_TO_GRAY_END = 133;
|
||||
private static final int OVERVIEW_TO_SPLIT_DOCKED_ICON_FADE_IN_START = 167;
|
||||
private static final int OVERVIEW_TO_SPLIT_DOCKED_ICON_FADE_IN_END = 250;
|
||||
private static final int OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_START = 0;
|
||||
private static final int OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_END = 417;
|
||||
|
||||
private static final float OVERVIEW_TO_SPLIT_THUMBNAIL_FADE_TO_GRAY_START_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_THUMBNAIL_FADE_TO_GRAY_START
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float OVERVIEW_TO_SPLIT_THUMBNAIL_FADE_TO_GRAY_END_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_THUMBNAIL_FADE_TO_GRAY_END
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float OVERVIEW_TO_SPLIT_DOCKED_ICON_FADE_IN_START_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_DOCKED_ICON_FADE_IN_START
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float OVERVIEW_TO_SPLIT_DOCKED_ICON_FADE_IN_END_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_DOCKED_ICON_FADE_IN_END
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_START_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_START
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_END_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_END
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
|
||||
public static final FloatProperty<FloatingTaskView> PRIMARY_TRANSLATE_OFFSCREEN =
|
||||
new FloatProperty<FloatingTaskView>("floatingTaskPrimaryTranslateOffscreen") {
|
||||
@@ -224,26 +251,49 @@ public class FloatingTaskView extends FrameLayout {
|
||||
RectF floatingTaskViewBounds = new RectF();
|
||||
|
||||
if (fadeWithThumbnail) {
|
||||
animation.addFloat(mSplitPlaceholderView, SplitPlaceholderView.ALPHA_FLOAT,
|
||||
0, 1, ACCEL);
|
||||
animation.addFloat(mThumbnailView, LauncherAnimUtils.VIEW_ALPHA,
|
||||
1, 0, DEACCEL_3);
|
||||
// This code block runs when animating from Overview > OverviewSplitSelect
|
||||
// And for the second thumbnail on confirm
|
||||
|
||||
// FloatingTaskThumbnailView: thumbnail fades out to transparent
|
||||
animation.setViewAlpha(mThumbnailView, 0, clampToProgress(LINEAR,
|
||||
OVERVIEW_TO_SPLIT_THUMBNAIL_FADE_TO_GRAY_START_OFFSET,
|
||||
OVERVIEW_TO_SPLIT_THUMBNAIL_FADE_TO_GRAY_END_OFFSET));
|
||||
|
||||
// SplitPlaceholderView: gray background fades in at the same time, then new icon fades
|
||||
// in
|
||||
animation.setViewAlpha(mSplitPlaceholderView, 1, clampToProgress(LINEAR,
|
||||
OVERVIEW_TO_SPLIT_THUMBNAIL_FADE_TO_GRAY_START_OFFSET,
|
||||
OVERVIEW_TO_SPLIT_THUMBNAIL_FADE_TO_GRAY_END_OFFSET));
|
||||
animation.setViewAlpha(mSplitPlaceholderView.getIconView(), 1, clampToProgress(
|
||||
LINEAR, OVERVIEW_TO_SPLIT_DOCKED_ICON_FADE_IN_START_OFFSET,
|
||||
OVERVIEW_TO_SPLIT_DOCKED_ICON_FADE_IN_END_OFFSET));
|
||||
} else if (isStagedTask) {
|
||||
// This code block runs when animating from Normal > OverviewSplitSelect
|
||||
// and for the first thumbnail on confirm
|
||||
|
||||
// Fade in the placeholder view when split is initiated from homescreen / all apps
|
||||
// icons.
|
||||
if (mSplitPlaceholderView.getAlpha() == 0) {
|
||||
animation.addFloat(mSplitPlaceholderView, SplitPlaceholderView.ALPHA_FLOAT,
|
||||
0.3f, 1, ACCEL);
|
||||
animation.setViewAlpha(mSplitPlaceholderView, 0.3f, INSTANT);
|
||||
animation.setViewAlpha(mSplitPlaceholderView, 1, ACCEL);
|
||||
}
|
||||
}
|
||||
|
||||
MultiValueUpdateListener listener = new MultiValueUpdateListener() {
|
||||
final FloatProp mDx = new FloatProp(0, prop.dX, 0, animDuration, LINEAR);
|
||||
final FloatProp mDy = new FloatProp(0, prop.dY, 0, animDuration, LINEAR);
|
||||
// SplitPlaceholderView: rectangle translates and stretches to new position
|
||||
final FloatProp mDx = new FloatProp(0, prop.dX, 0, animDuration,
|
||||
clampToProgress(DEACCEL_2, OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_START_OFFSET,
|
||||
OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_END_OFFSET));
|
||||
final FloatProp mDy = new FloatProp(0, prop.dY, 0, animDuration,
|
||||
clampToProgress(DEACCEL_2, OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_START_OFFSET,
|
||||
OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_END_OFFSET));
|
||||
final FloatProp mTaskViewScaleX = new FloatProp(1f, prop.finalTaskViewScaleX, 0,
|
||||
animDuration, LINEAR);
|
||||
animDuration, clampToProgress(DEACCEL_2,
|
||||
OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_START_OFFSET,
|
||||
OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_END_OFFSET));
|
||||
final FloatProp mTaskViewScaleY = new FloatProp(1f, prop.finalTaskViewScaleY, 0,
|
||||
animDuration, LINEAR);
|
||||
animDuration, clampToProgress(DEACCEL_2,
|
||||
OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_START_OFFSET,
|
||||
OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_END_OFFSET));
|
||||
@Override
|
||||
public void onUpdate(float percent, boolean initOnly) {
|
||||
// Calculate the icon position.
|
||||
|
||||
@@ -35,9 +35,11 @@ import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
|
||||
import static com.android.launcher3.anim.Interpolators.EMPHASIZED_DECELERATE;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_0_85;
|
||||
import static com.android.launcher3.anim.Interpolators.clampToProgress;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
|
||||
@@ -138,6 +140,7 @@ import com.android.launcher3.statemanager.BaseState;
|
||||
import com.android.launcher3.statemanager.StatefulActivity;
|
||||
import com.android.launcher3.touch.OverScroll;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.uioverrides.states.SplitScreenSelectState;
|
||||
import com.android.launcher3.util.DynamicResource;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
@@ -414,6 +417,54 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
private static final float ANIMATION_DISMISS_PROGRESS_MIDPOINT = 0.5f;
|
||||
private static final float END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.75f;
|
||||
|
||||
private static final int OVERVIEW_TO_SPLIT_THUMBNAIL_SLIDE_START = 67;
|
||||
private static final int OVERVIEW_TO_SPLIT_THUMBNAIL_SLIDE_OFFSET = 16;
|
||||
private static final int SPRING_DISMISS_TRANSLATION_DURATION = 500;
|
||||
|
||||
private static final float INITIAL_SPRING_DISMISS_TRANSLATION_INTERPOLATION_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_THUMBNAIL_SLIDE_START
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float ADDITIONAL_SPRING_DISMISS_TRANSLATION_INTERPOLATION_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_THUMBNAIL_SLIDE_OFFSET
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float END_SPRING_DISMISS_TRANSLATION_INTERPOLATION_OFFSET =
|
||||
(float) SPRING_DISMISS_TRANSLATION_DURATION
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
|
||||
private static final int OVERVIEW_TO_SPLIT_ICON_FADE_START = 0;
|
||||
private static final int OVERVIEW_TO_SPLIT_ICON_FADE_END = 83;
|
||||
private static final int OVERVIEW_TO_SPLIT_INSTRUCTIONS_CONTAINER_FADE_IN_START = 167;
|
||||
private static final int OVERVIEW_TO_SPLIT_INSTRUCTIONS_CONTAINER_FADE_IN_END = 250;
|
||||
private static final int OVERVIEW_TO_SPLIT_INSTRUCTIONS_TEXT_FADE_IN_START = 217;
|
||||
private static final int OVERVIEW_TO_SPLIT_INSTRUCTIONS_TEXT_FADE_IN_END = 300;
|
||||
private static final int OVERVIEW_TO_SPLIT_INSTRUCTIONS_UNFOLD_START = 167;
|
||||
private static final int OVERVIEW_TO_SPLIT_INSTRUCTIONS_UNFOLD_END = 500;
|
||||
|
||||
private static final float OVERVIEW_TO_SPLIT_ICON_FADE_START_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_ICON_FADE_START
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float OVERVIEW_TO_SPLIT_ICON_FADE_END_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_ICON_FADE_END
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float OVERVIEW_TO_SPLIT_INSTRUCTIONS_CONTAINER_FADE_IN_START_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_INSTRUCTIONS_CONTAINER_FADE_IN_START
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float OVERVIEW_TO_SPLIT_INSTRUCTIONS_CONTAINER_FADE_IN_END_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_INSTRUCTIONS_CONTAINER_FADE_IN_END
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float OVERVIEW_TO_SPLIT_INSTRUCTIONS_TEXT_FADE_IN_START_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_INSTRUCTIONS_TEXT_FADE_IN_START
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float OVERVIEW_TO_SPLIT_INSTRUCTIONS_TEXT_FADE_IN_END_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_INSTRUCTIONS_TEXT_FADE_IN_END
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float OVERVIEW_TO_SPLIT_INSTRUCTIONS_UNFOLD_START_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_INSTRUCTIONS_UNFOLD_START
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
private static final float OVERVIEW_TO_SPLIT_INSTRUCTIONS_UNFOLD_END_OFFSET =
|
||||
(float) OVERVIEW_TO_SPLIT_INSTRUCTIONS_UNFOLD_END
|
||||
/ SplitScreenSelectState.ENTER_DURATION;
|
||||
|
||||
private static final float SIGNIFICANT_MOVE_SCREEN_WIDTH_PERCENTAGE = 0.15f;
|
||||
|
||||
protected final RecentsOrientedState mOrientationState;
|
||||
@@ -2808,11 +2859,11 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
|
||||
RectF startingTaskRect = new RectF();
|
||||
if (mSplitHiddenTaskView != null) {
|
||||
// Split staging is initiated, hide the original TaskView thumbnail.
|
||||
// Toggled back on in resetFromSplitSelectionState().
|
||||
// Split staging is initiated
|
||||
mSplitHiddenTaskView.setThumbnailVisibility(INVISIBLE);
|
||||
anim.addFloat(mSplitHiddenTaskView, TaskView.ICON_ALPHA, 1, 0,
|
||||
clampToProgress(LINEAR, 0, 0.167f));
|
||||
anim.setViewAlpha(mSplitHiddenTaskView.getIconView(), 0, clampToProgress(LINEAR,
|
||||
OVERVIEW_TO_SPLIT_ICON_FADE_START_OFFSET,
|
||||
OVERVIEW_TO_SPLIT_ICON_FADE_END_OFFSET));
|
||||
mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
|
||||
mSplitHiddenTaskView.getThumbnail(),
|
||||
mSplitHiddenTaskView.getThumbnail().getThumbnail(),
|
||||
@@ -2829,9 +2880,19 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
false /* fadeWithThumbnail */, true /* isStagedTask */);
|
||||
}
|
||||
|
||||
// SplitInstructionsView: animate in
|
||||
mSplitInstructionsView = SplitInstructionsView.getSplitInstructionsView(mActivity);
|
||||
mSplitInstructionsView.setAlpha(0);
|
||||
anim.addFloat(mSplitInstructionsView, SplitInstructionsView.ALPHA_FLOAT, 0, 1, ACCEL);
|
||||
anim.setViewAlpha(mSplitInstructionsView, 1, clampToProgress(LINEAR,
|
||||
OVERVIEW_TO_SPLIT_INSTRUCTIONS_CONTAINER_FADE_IN_START_OFFSET,
|
||||
OVERVIEW_TO_SPLIT_INSTRUCTIONS_CONTAINER_FADE_IN_END_OFFSET));
|
||||
anim.setViewAlpha(mSplitInstructionsView.getTextView(), 1, clampToProgress(LINEAR,
|
||||
OVERVIEW_TO_SPLIT_INSTRUCTIONS_TEXT_FADE_IN_START_OFFSET,
|
||||
OVERVIEW_TO_SPLIT_INSTRUCTIONS_TEXT_FADE_IN_END_OFFSET));
|
||||
anim.addFloat(mSplitInstructionsView, mSplitInstructionsView.UNFOLD, 0.1f, 1,
|
||||
clampToProgress(EMPHASIZED_DECELERATE,
|
||||
OVERVIEW_TO_SPLIT_INSTRUCTIONS_UNFOLD_START_OFFSET,
|
||||
OVERVIEW_TO_SPLIT_INSTRUCTIONS_UNFOLD_END_OFFSET));
|
||||
|
||||
InteractionJankMonitorWrapper.begin(this,
|
||||
InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "First tile selected");
|
||||
@@ -2858,17 +2919,16 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
* @param dismissingForSplitSelection task dismiss animation is used for entering split
|
||||
* selection state from app icon
|
||||
*/
|
||||
public PendingAnimation createTaskDismissAnimation(TaskView dismissedTaskView,
|
||||
public void createTaskDismissAnimation(PendingAnimation anim, TaskView dismissedTaskView,
|
||||
boolean animateTaskView, boolean shouldRemoveTask, long duration,
|
||||
boolean dismissingForSplitSelection) {
|
||||
if (mPendingAnimation != null) {
|
||||
mPendingAnimation.createPlaybackController().dispatchOnCancel().dispatchOnEnd();
|
||||
}
|
||||
PendingAnimation anim = new PendingAnimation(duration);
|
||||
|
||||
int count = getPageCount();
|
||||
if (count == 0) {
|
||||
return anim;
|
||||
return;
|
||||
}
|
||||
|
||||
boolean showAsGrid = showAsGrid();
|
||||
@@ -3113,11 +3173,33 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
// Animate task with index >= dismissed index and in the same row as the
|
||||
// dismissed index or next focused index. Offset successive task dismissal
|
||||
// durations for a staggered effect.
|
||||
float animationStartProgress = Utilities.boundToRange(
|
||||
INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
+ ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
* ++distanceFromDismissedTask, 0f,
|
||||
dismissTranslationInterpolationEnd);
|
||||
distanceFromDismissedTask++;
|
||||
boolean isStagingFocusedTask =
|
||||
isFocusedTaskDismissed && nextFocusedTaskView == null;
|
||||
int staggerColumn = isStagingFocusedTask
|
||||
? (int) Math.ceil(distanceFromDismissedTask / 2f)
|
||||
: distanceFromDismissedTask;
|
||||
// Set timings based on if user is initiating splitscreen on the focused task,
|
||||
// or splitting/dismissing some other task.
|
||||
float animationStartProgress = isStagingFocusedTask
|
||||
? Utilities.boundToRange(
|
||||
INITIAL_SPRING_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
+ ADDITIONAL_SPRING_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
* staggerColumn, 0f, dismissTranslationInterpolationEnd)
|
||||
: Utilities.boundToRange(
|
||||
INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
+ ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
* staggerColumn, 0f, dismissTranslationInterpolationEnd);
|
||||
float animationEndProgress = isStagingFocusedTask
|
||||
? Utilities.boundToRange(
|
||||
INITIAL_SPRING_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
+ END_SPRING_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
+ ADDITIONAL_SPRING_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
* staggerColumn,
|
||||
0f, dismissTranslationInterpolationEnd)
|
||||
: dismissTranslationInterpolationEnd;
|
||||
Interpolator dismissInterpolator = isStagingFocusedTask ? OVERSHOOT_0_85 : LINEAR;
|
||||
|
||||
if (taskView == nextFocusedTaskView) {
|
||||
// Enlarge the task to be focused next, and translate into focus position.
|
||||
float scale = mTaskWidth / (float) mLastComputedGridTaskSize.width();
|
||||
@@ -3140,7 +3222,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
} else {
|
||||
float primaryTranslation =
|
||||
nextFocusedTaskView != null ? nextFocusedTaskWidth : dismissedTaskWidth;
|
||||
if (isFocusedTaskDismissed && nextFocusedTaskView == null) {
|
||||
if (isStagingFocusedTask) {
|
||||
// Moves less if focused task is not in scroll position.
|
||||
int focusedTaskScroll = getScrollForPage(dismissedIndex);
|
||||
int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
|
||||
@@ -3156,8 +3238,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
|
||||
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(),
|
||||
mIsRtl ? primaryTranslation : -primaryTranslation,
|
||||
clampToProgress(LINEAR, animationStartProgress,
|
||||
dismissTranslationInterpolationEnd));
|
||||
clampToProgress(dismissInterpolator, animationStartProgress,
|
||||
animationEndProgress));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3389,7 +3471,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
mPendingAnimation = null;
|
||||
}
|
||||
});
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3557,8 +3638,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
|
||||
public void dismissTask(TaskView taskView, boolean animateTaskView, boolean removeTask) {
|
||||
runDismissAnimation(createTaskDismissAnimation(taskView, animateTaskView, removeTask,
|
||||
DISMISS_TASK_DURATION, false /* dismissingForSplitSelection*/));
|
||||
PendingAnimation pa = new PendingAnimation(DISMISS_TASK_DURATION);
|
||||
createTaskDismissAnimation(pa, taskView, animateTaskView, removeTask, DISMISS_TASK_DURATION,
|
||||
false /* dismissingForSplitSelection*/);
|
||||
runDismissAnimation(pa);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@@ -4090,14 +4173,17 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
splitSelectSource.position.stagePosition, splitSelectSource.user);
|
||||
}
|
||||
|
||||
public PendingAnimation createSplitSelectInitAnimation(int duration) {
|
||||
/**
|
||||
* Modifies a PendingAnimation with the animations for entering split staging
|
||||
*/
|
||||
public void createSplitSelectInitAnimation(PendingAnimation builder, int duration) {
|
||||
if (mSplitHiddenTaskView != null) {
|
||||
return createTaskDismissAnimation(mSplitHiddenTaskView, true, false, duration,
|
||||
// Splitting from Overview
|
||||
createTaskDismissAnimation(builder, mSplitHiddenTaskView, true, false, duration,
|
||||
true /* dismissingForSplitSelection*/);
|
||||
} else {
|
||||
PendingAnimation anim = new PendingAnimation(duration);
|
||||
createInitialSplitSelectAnimation(anim);
|
||||
return anim;
|
||||
// Splitting from Home
|
||||
createInitialSplitSelectAnimation(builder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4209,8 +4295,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
resetTaskVisuals();
|
||||
mSplitHiddenTaskViewIndex = -1;
|
||||
if (mSplitHiddenTaskView != null) {
|
||||
// Toggle thumbnail visibility back on (turned off in
|
||||
// createInitialSplitSelectAnimation()).
|
||||
mSplitHiddenTaskView.setThumbnailVisibility(VISIBLE);
|
||||
mSplitHiddenTaskView = null;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
@@ -40,18 +41,18 @@ import com.android.launcher3.util.DisplayController;
|
||||
*/
|
||||
public class SplitInstructionsView extends FrameLayout {
|
||||
private final StatefulActivity mLauncher;
|
||||
private AppCompatTextView mTextView;
|
||||
|
||||
public static final FloatProperty<SplitInstructionsView> ALPHA_FLOAT =
|
||||
new FloatProperty<SplitInstructionsView>("SplitInstructionsAlpha") {
|
||||
public static final FloatProperty<SplitInstructionsView> UNFOLD =
|
||||
new FloatProperty<SplitInstructionsView>("SplitInstructionsUnfold") {
|
||||
@Override
|
||||
public void setValue(SplitInstructionsView splitInstructionsView, float v) {
|
||||
splitInstructionsView.setVisibility(v != 0 ? VISIBLE : GONE);
|
||||
splitInstructionsView.setAlpha(v);
|
||||
splitInstructionsView.setScaleY(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(SplitInstructionsView splitInstructionsView) {
|
||||
return splitInstructionsView.getAlpha();
|
||||
return splitInstructionsView.getScaleY();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -77,6 +78,14 @@ public class SplitInstructionsView extends FrameLayout {
|
||||
false
|
||||
);
|
||||
|
||||
splitInstructionsView.mTextView = splitInstructionsView.findViewById(
|
||||
R.id.split_instructions_text);
|
||||
|
||||
// Since textview overlays base view, and we sometimes manipulate the alpha of each
|
||||
// simultaneously, force overlapping rendering to false prevents redrawing of pixels,
|
||||
// improving performance at the cost of some accuracy.
|
||||
splitInstructionsView.forceHasOverlappingRendering(false);
|
||||
|
||||
dragLayer.addView(splitInstructionsView);
|
||||
return splitInstructionsView;
|
||||
}
|
||||
@@ -120,4 +129,8 @@ public class SplitInstructionsView extends FrameLayout {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public AppCompatTextView getTextView() {
|
||||
return mTextView;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.TypedValue;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
@@ -33,20 +32,6 @@ public class SplitPlaceholderView extends FrameLayout {
|
||||
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private final Rect mTempRect = new Rect();
|
||||
|
||||
public static final FloatProperty<SplitPlaceholderView> ALPHA_FLOAT =
|
||||
new FloatProperty<SplitPlaceholderView>("SplitViewAlpha") {
|
||||
@Override
|
||||
public void setValue(SplitPlaceholderView splitPlaceholderView, float v) {
|
||||
splitPlaceholderView.setVisibility(v != 0 ? VISIBLE : GONE);
|
||||
splitPlaceholderView.setAlpha(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(SplitPlaceholderView splitPlaceholderView) {
|
||||
return splitPlaceholderView.getAlpha();
|
||||
}
|
||||
};
|
||||
|
||||
@Nullable
|
||||
private IconView mIconView;
|
||||
|
||||
|
||||
@@ -323,19 +323,6 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
}
|
||||
};
|
||||
|
||||
public static final FloatProperty<TaskView> ICON_ALPHA =
|
||||
new FloatProperty<TaskView>("iconAlpha") {
|
||||
@Override
|
||||
public void setValue(TaskView taskView, float v) {
|
||||
taskView.mIconView.setAlpha(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(TaskView taskView) {
|
||||
return taskView.mIconView.getAlpha();
|
||||
}
|
||||
};
|
||||
|
||||
@Nullable
|
||||
protected Task mTask;
|
||||
protected TaskThumbnailView mSnapshotView;
|
||||
|
||||
@@ -83,6 +83,7 @@ public class Interpolators {
|
||||
EXAGGERATED_EASE = new PathInterpolator(exaggeratedEase);
|
||||
}
|
||||
|
||||
public static final Interpolator OVERSHOOT_0_85 = new OvershootInterpolator(0.85f);
|
||||
public static final Interpolator OVERSHOOT_1_2 = new OvershootInterpolator(1.2f);
|
||||
public static final Interpolator OVERSHOOT_1_7 = new OvershootInterpolator(1.7f);
|
||||
|
||||
|
||||
@@ -453,7 +453,7 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
|
||||
public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
|
||||
int splitInstructionsWidth, int threeButtonNavShift) {
|
||||
out.setPivotX(0);
|
||||
out.setPivotY(0);
|
||||
out.setPivotY(splitInstructionsHeight);
|
||||
out.setRotation(getDegreesRotated());
|
||||
int distanceToEdge = out.getResources().getDimensionPixelSize(
|
||||
R.dimen.split_instructions_bottom_margin_phone_landscape);
|
||||
@@ -461,8 +461,8 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
|
||||
int insetCorrectionX = dp.getInsets().left;
|
||||
// Center the view in case of unbalanced insets on top or bottom of screen
|
||||
int insetCorrectionY = (dp.getInsets().bottom - dp.getInsets().top) / 2;
|
||||
out.setTranslationX(splitInstructionsHeight + distanceToEdge - insetCorrectionX);
|
||||
out.setTranslationY(((splitInstructionsHeight - splitInstructionsWidth) / 2f)
|
||||
out.setTranslationX(distanceToEdge - insetCorrectionX);
|
||||
out.setTranslationY(((-splitInstructionsHeight - splitInstructionsWidth) / 2f)
|
||||
+ insetCorrectionY);
|
||||
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) out.getLayoutParams();
|
||||
// Setting gravity to LEFT instead of the lint-recommended START because we always want this
|
||||
|
||||
@@ -520,7 +520,7 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
|
||||
public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
|
||||
int splitInstructionsWidth, int threeButtonNavShift) {
|
||||
out.setPivotX(0);
|
||||
out.setPivotY(0);
|
||||
out.setPivotY(splitInstructionsHeight);
|
||||
out.setRotation(getDegreesRotated());
|
||||
int distanceToEdge;
|
||||
if ((DisplayController.getNavigationMode(out.getContext()) == THREE_BUTTONS)
|
||||
|
||||
@@ -190,7 +190,7 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
|
||||
public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
|
||||
int splitInstructionsWidth, int threeButtonNavShift) {
|
||||
out.setPivotX(0);
|
||||
out.setPivotY(0);
|
||||
out.setPivotY(splitInstructionsHeight);
|
||||
out.setRotation(getDegreesRotated());
|
||||
int distanceToEdge = out.getResources().getDimensionPixelSize(
|
||||
R.dimen.split_instructions_bottom_margin_phone_landscape);
|
||||
@@ -198,9 +198,8 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
|
||||
int insetCorrectionX = dp.getInsets().right;
|
||||
// Center the view in case of unbalanced insets on top or bottom of screen
|
||||
int insetCorrectionY = (dp.getInsets().bottom - dp.getInsets().top) / 2;
|
||||
out.setTranslationX(splitInstructionsWidth - splitInstructionsHeight - distanceToEdge
|
||||
+ insetCorrectionX);
|
||||
out.setTranslationY(((splitInstructionsHeight + splitInstructionsWidth) / 2f)
|
||||
out.setTranslationX(splitInstructionsWidth - distanceToEdge + insetCorrectionX);
|
||||
out.setTranslationY(((-splitInstructionsHeight + splitInstructionsWidth) / 2f)
|
||||
+ insetCorrectionY);
|
||||
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) out.getLayoutParams();
|
||||
// Setting gravity to RIGHT instead of the lint-recommended END because we always want this
|
||||
|
||||
Reference in New Issue
Block a user