Merge "Update animations for TM-QPR: OverviewSplitSelect > Confirmed transition" into tm-qpr-dev

This commit is contained in:
Jeremy Sim
2022-09-20 02:55:46 +00:00
committed by Android (Google) Code Review
8 changed files with 316 additions and 143 deletions
@@ -62,6 +62,7 @@ import com.android.launcher3.touch.AllAppsSwipeController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.util.RecentsAtomicAnimationFactory;
import com.android.quickstep.util.SplitAnimationTimings;
import com.android.quickstep.views.RecentsView;
/**
@@ -79,14 +80,6 @@ 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;
@@ -197,9 +190,10 @@ public class QuickstepAtomicAnimationFactory extends
} else if (fromState == NORMAL && toState == ALL_APPS) {
AllAppsSwipeController.applyNormalToAllAppsAnimConfig(mActivity, config);
} else if (fromState == OVERVIEW && toState == OVERVIEW_SPLIT_SELECT) {
SplitAnimationTimings timings = SplitAnimationTimings.OVERVIEW_TO_SPLIT;
config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, clampToProgress(LINEAR,
OVERVIEW_TO_SPLIT_ACTIONS_FADE_START_OFFSET,
OVERVIEW_TO_SPLIT_ACTIONS_FADE_END_OFFSET));
timings.getActionsFadeStartOffset(),
timings.getActionsFadeEndOffset()));
}
}
}
@@ -19,6 +19,7 @@ package com.android.launcher3.uioverrides.states;
import android.content.Context;
import com.android.launcher3.Launcher;
import com.android.quickstep.util.SplitAnimationTimings;
import com.android.quickstep.views.RecentsView;
/**
@@ -26,10 +27,6 @@ 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);
}
@@ -47,6 +44,8 @@ public class SplitScreenSelectState extends OverviewState {
@Override
public int getTransitionDuration(Context context, boolean isToState) {
return isToState ? ENTER_DURATION : EXIT_DURATION;
return isToState
? SplitAnimationTimings.ENTER_DURATION
: SplitAnimationTimings.ABORT_DURATION;
}
}
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2022 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.anim.Interpolators.DEACCEL_2;
import android.view.animation.Interpolator;
/**
* Timings for the Overview > OverviewSplitSelect animation.
*/
public class OverviewToSplitTimings implements SplitAnimationTimings {
public int getThumbnailFadeToGrayStart() { return 0; }
public int getThumbnailFadeToGrayEnd() { return 133; }
public int getDockedIconFadeInStart() { return 167; }
public int getDockedIconFadeInEnd() { return 250; }
public int getStagedRectSlideStart() { return 0; }
public int getStagedRectSlideEnd() { return 417; }
public int getGridSlideStart() { return 67; }
public int getGridSlideStagger() { return 16; }
public int getGridSlideDuration() { return 500; }
public int getActionsFadeStart() { return 0; }
public int getActionsFadeEnd() { return 83; }
public int getIconFadeStart() { return 0; }
public int getIconFadeEnd() { return 83; }
public int getInstructionsContainerFadeInStart() { return 167; }
public int getInstructionsContainerFadeInEnd() { return 250; }
public int getInstructionsTextFadeInStart() { return 217; }
public int getInstructionsTextFadeInEnd() { return 300; }
public int getInstructionsUnfoldStart() { return 167; }
public int getInstructionsUnfoldEnd() { return 500; }
public int getDuration() { return ENTER_DURATION; }
public Interpolator getStagedRectSlideInterpolator() { return DEACCEL_2; }
public float getGridSlideStartOffset() {
return (float) getGridSlideStart() / getDuration();
}
public float getGridSlideStaggerOffset() {
return (float) getGridSlideStagger() / getDuration();
}
public float getGridSlideDurationOffset() {
return (float) getGridSlideDuration() / getDuration();
}
public float getActionsFadeStartOffset() {
return (float) getActionsFadeStart() / getDuration();
}
public float getActionsFadeEndOffset() {
return (float) getActionsFadeEnd() / getDuration();
}
public float getIconFadeStartOffset() {
return (float) getIconFadeStart() / getDuration();
}
public float getIconFadeEndOffset() {
return (float) getIconFadeEnd() / getDuration();
}
public float getInstructionsContainerFadeInStartOffset() {
return (float) getInstructionsContainerFadeInStart() / getDuration();
}
public float getInstructionsContainerFadeInEndOffset() {
return (float) getInstructionsContainerFadeInEnd() / getDuration();
}
public float getInstructionsTextFadeInStartOffset() {
return (float) getInstructionsTextFadeInStart() / getDuration();
}
public float getInstructionsTextFadeInEndOffset() {
return (float) getInstructionsTextFadeInEnd() / getDuration();
}
public float getInstructionsUnfoldStartOffset() {
return (float) getInstructionsUnfoldStart() / getDuration();
}
public float getInstructionsUnfoldEndOffset() {
return (float) getInstructionsUnfoldEnd() / getDuration();
}
}
@@ -0,0 +1,79 @@
/*
* Copyright (C) 2022 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 android.view.animation.Interpolator;
/**
* An interface that supports the centralization of timing information for splitscreen animations.
*/
public interface SplitAnimationTimings {
int ENTER_DURATION = 866;
int ABORT_DURATION = 500;
int CONFIRM_DURATION = 383;
SplitAnimationTimings OVERVIEW_TO_SPLIT = new OverviewToSplitTimings();
SplitAnimationTimings SPLIT_TO_CONFIRM = new SplitToConfirmTimings();
// Shared methods
int getDuration();
int getThumbnailFadeToGrayStart();
int getThumbnailFadeToGrayEnd();
int getDockedIconFadeInStart();
int getDockedIconFadeInEnd();
int getStagedRectSlideStart();
int getStagedRectSlideEnd();
Interpolator getStagedRectSlideInterpolator();
default float getThumbnailFadeToGrayStartOffset() {
return (float) getThumbnailFadeToGrayStart() / getDuration();
}
default float getThumbnailFadeToGrayEndOffset() {
return (float) getThumbnailFadeToGrayEnd() / getDuration();
}
default float getDockedIconFadeInStartOffset() {
return (float) getDockedIconFadeInStart() / getDuration();
}
default float getDockedIconFadeInEndOffset() {
return (float) getDockedIconFadeInEnd() / getDuration();
}
default float getStagedRectSlideStartOffset() {
return (float) getStagedRectSlideStart() / getDuration();
}
default float getStagedRectSlideEndOffset() {
return (float) getStagedRectSlideEnd() / getDuration();
}
// Defaults for OverviewToSplit
default float getGridSlideStartOffset() { return 0; }
default float getGridSlideStaggerOffset() { return 0; }
default float getGridSlideDurationOffset() { return 0; }
default float getActionsFadeStartOffset() { return 0; }
default float getActionsFadeEndOffset() { return 0; }
default float getIconFadeStartOffset() { return 0; }
default float getIconFadeEndOffset() { return 0; }
default float getInstructionsContainerFadeInStartOffset() { return 0; }
default float getInstructionsContainerFadeInEndOffset() { return 0; }
default float getInstructionsTextFadeInStartOffset() { return 0; }
default float getInstructionsTextFadeInEndOffset() { return 0; }
default float getInstructionsUnfoldStartOffset() { return 0; }
default float getInstructionsUnfoldEndOffset() { return 0; }
// Defaults for SplitToConfirm
default float getInstructionsFadeStartOffset() { return 0; }
default float getInstructionsFadeEndOffset() { return 0; }
}
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2022 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.anim.Interpolators.LINEAR;
import android.view.animation.Interpolator;
/**
* Timings for the OverviewSplitSelect > confirmed animation.
*/
public class SplitToConfirmTimings implements SplitAnimationTimings {
public int getThumbnailFadeToGrayStart() { return 0; }
public int getThumbnailFadeToGrayEnd() { return 133; }
public int getDockedIconFadeInStart() { return 167; }
public int getDockedIconFadeInEnd() { return 250; }
public int getStagedRectSlideStart() { return 0; }
public int getStagedRectSlideEnd() { return 383; }
public int getInstructionsFadeStart() { return 0; }
public int getInstructionsFadeEnd() { return 67; }
public int getDuration() { return CONFIRM_DURATION; }
public Interpolator getStagedRectSlideInterpolator() { return LINEAR; }
public float getInstructionsFadeStartOffset() {
return (float) getInstructionsFadeStart() / getDuration();
}
public float getInstructionsFadeEndOffset() {
return (float) getInstructionsFadeEnd() / getDuration();
}
}
@@ -2,7 +2,6 @@ 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_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;
@@ -31,10 +30,10 @@ 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;
import com.android.quickstep.util.SplitAnimationTimings;
import com.android.quickstep.util.TaskCornerRadius;
import com.android.systemui.shared.system.QuickStepContract;
@@ -44,38 +43,14 @@ import com.android.systemui.shared.system.QuickStepContract;
* which will have the thumbnail from the provided existing TaskView overlaying the taskview itself.
*
* Can then animate the taskview using
* {@link #addAnimation(PendingAnimation, RectF, Rect, boolean, boolean)}
* {@link #addStagingAnimation(PendingAnimation, RectF, Rect, boolean, boolean)} or
* {@link #addConfirmAnimation(PendingAnimation, RectF, Rect, boolean, boolean)}
* giving a starting and ending bounds. Currently this is set to use the split placeholder view,
* but it could be generified.
*
* 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") {
@@ -236,8 +211,34 @@ public class FloatingTaskView extends FrameLayout {
layout(left, lp.topMargin, left + lp.width, lp.topMargin + lp.height);
}
public void addAnimation(PendingAnimation animation, RectF startingBounds, Rect endBounds,
boolean fadeWithThumbnail, boolean isStagedTask) {
/**
* Animates a FloatingTaskThumbnailView and its overlapping SplitPlaceholderView when a split
* is staged.
*/
public void addStagingAnimation(PendingAnimation animation, RectF startingBounds,
Rect endBounds, boolean fadeWithThumbnail, boolean isStagedTask) {
addAnimation(animation, startingBounds, endBounds, fadeWithThumbnail, isStagedTask,
SplitAnimationTimings.OVERVIEW_TO_SPLIT);
}
/**
* Animates the FloatingTaskThumbnailView and SplitPlaceholderView for the two thumbnails
* when a split is confirmed.
*/
public void addConfirmAnimation(PendingAnimation animation, RectF startingBounds,
Rect endBounds, boolean fadeWithThumbnail, boolean isStagedTask) {
addAnimation(animation, startingBounds, endBounds, fadeWithThumbnail, isStagedTask,
SplitAnimationTimings.SPLIT_TO_CONFIRM);
}
/**
* Sets up and builds a split staging animation.
* Called by {@link #addStagingAnimation(PendingAnimation, RectF, Rect, boolean, boolean)} and
* {@link #addConfirmAnimation(PendingAnimation, RectF, Rect, boolean, boolean)}.
*/
public void addAnimation(PendingAnimation animation, RectF startingBounds,
Rect endBounds, boolean fadeWithThumbnail, boolean isStagedTask,
SplitAnimationTimings timings) {
mFullscreenParams.setIsStagedTask(isStagedTask);
final BaseDragLayer dragLayer = mActivity.getDragLayer();
int[] dragLayerBounds = new int[2];
@@ -251,49 +252,54 @@ public class FloatingTaskView extends FrameLayout {
RectF floatingTaskViewBounds = new RectF();
if (fadeWithThumbnail) {
// This code block runs when animating from Overview > OverviewSplitSelect
// And for the second thumbnail on confirm
// This code block runs for the placeholder view during Overview > OverviewSplitSelect
// and for the selected (secondary) thumbnail during OverviewSplitSelect > Confirmed
// 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));
timings.getThumbnailFadeToGrayStartOffset(),
timings.getThumbnailFadeToGrayEndOffset()));
// SplitPlaceholderView: gray background fades in at the same time, then new icon fades
// in
// SplitPlaceholderView: gray background fades in at 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));
timings.getThumbnailFadeToGrayStartOffset(),
timings.getThumbnailFadeToGrayEndOffset()));
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));
LINEAR,
timings.getDockedIconFadeInStartOffset(),
timings.getDockedIconFadeInEndOffset()));
} else if (isStagedTask) {
// This code block runs when animating from Normal > OverviewSplitSelect
// and for the first thumbnail on confirm
// This code block runs for the placeholder view during Normal > OverviewSplitSelect
// and for the placeholder (primary) thumbnail during OverviewSplitSelect > Confirmed
// Fade in the placeholder view when split is initiated from homescreen / all apps
// Fade in the placeholder view during Normal > OverviewSplitSelect
if (mSplitPlaceholderView.getAlpha() == 0) {
animation.setViewAlpha(mSplitPlaceholderView, 0.3f, INSTANT);
animation.setViewAlpha(mSplitPlaceholderView, 1, ACCEL);
}
// No-op for placeholder during OverviewSplitSelect > Confirmed, alpha should be set
}
MultiValueUpdateListener listener = new MultiValueUpdateListener() {
// 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));
clampToProgress(timings.getStagedRectSlideInterpolator(),
timings.getStagedRectSlideStartOffset(),
timings.getStagedRectSlideEndOffset()));
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));
clampToProgress(timings.getStagedRectSlideInterpolator(),
timings.getStagedRectSlideStartOffset(),
timings.getStagedRectSlideEndOffset()));
final FloatProp mTaskViewScaleX = new FloatProp(1f, prop.finalTaskViewScaleX, 0,
animDuration, clampToProgress(DEACCEL_2,
OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_START_OFFSET,
OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_END_OFFSET));
animDuration, clampToProgress(timings.getStagedRectSlideInterpolator(),
timings.getStagedRectSlideStartOffset(),
timings.getStagedRectSlideEndOffset()));
final FloatProp mTaskViewScaleY = new FloatProp(1f, prop.finalTaskViewScaleY, 0,
animDuration, clampToProgress(DEACCEL_2,
OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_START_OFFSET,
OVERVIEW_TO_SPLIT_STAGED_RECT_SLIDE_END_OFFSET));
animDuration, clampToProgress(timings.getStagedRectSlideInterpolator(),
timings.getStagedRectSlideStartOffset(),
timings.getStagedRectSlideEndOffset()));
@Override
public void onUpdate(float percent, boolean initOnly) {
// Calculate the icon position.
@@ -305,6 +311,7 @@ public class FloatingTaskView extends FrameLayout {
update(floatingTaskViewBounds, percent);
}
};
transitionAnimator.addUpdateListener(listener);
}
@@ -39,7 +39,7 @@ 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.OVERSHOOT_0_75;
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_OVERVIEW_ACTIONS_SPLIT;
@@ -142,7 +142,6 @@ 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;
@@ -175,6 +174,7 @@ import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.SplitAnimationTimings;
import com.android.quickstep.util.SplitScreenBounds;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.util.SurfaceTransactionApplier;
@@ -419,54 +419,6 @@ 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;
@@ -2857,6 +2809,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
mOrientationHandler.getInitialSplitPlaceholderBounds(mSplitPlaceholderSize,
mSplitPlaceholderInset, mActivity.getDeviceProfile(),
mSplitSelectStateController.getActiveSplitStagePosition(), mTempRect);
SplitAnimationTimings timings = SplitAnimationTimings.OVERVIEW_TO_SPLIT;
RectF startingTaskRect = new RectF();
safeRemoveDragLayerView(mFirstFloatingTaskView);
@@ -2864,21 +2817,21 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
// Split staging is initiated
mSplitHiddenTaskView.setThumbnailVisibility(INVISIBLE);
anim.setViewAlpha(mSplitHiddenTaskView.getIconView(), 0, clampToProgress(LINEAR,
OVERVIEW_TO_SPLIT_ICON_FADE_START_OFFSET,
OVERVIEW_TO_SPLIT_ICON_FADE_END_OFFSET));
timings.getIconFadeStartOffset(),
timings.getIconFadeEndOffset()));
mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
mSplitHiddenTaskView.getThumbnail(),
mSplitHiddenTaskView.getThumbnail().getThumbnail(),
mSplitHiddenTaskView.getIconView().getDrawable(), startingTaskRect);
mFirstFloatingTaskView.setAlpha(1);
mFirstFloatingTaskView.addAnimation(anim, startingTaskRect, mTempRect,
mFirstFloatingTaskView.addStagingAnimation(anim, startingTaskRect, mTempRect,
true /* fadeWithThumbnail */, true /* isStagedTask */);
} else {
mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
mSplitSelectSource.view, null /* thumbnail */,
mSplitSelectSource.drawable, startingTaskRect);
mFirstFloatingTaskView.setAlpha(1);
mFirstFloatingTaskView.addAnimation(anim, startingTaskRect, mTempRect,
mFirstFloatingTaskView.addStagingAnimation(anim, startingTaskRect, mTempRect,
false /* fadeWithThumbnail */, true /* isStagedTask */);
}
@@ -2887,15 +2840,15 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
mSplitInstructionsView = SplitInstructionsView.getSplitInstructionsView(mActivity);
mSplitInstructionsView.setAlpha(0);
anim.setViewAlpha(mSplitInstructionsView, 1, clampToProgress(LINEAR,
OVERVIEW_TO_SPLIT_INSTRUCTIONS_CONTAINER_FADE_IN_START_OFFSET,
OVERVIEW_TO_SPLIT_INSTRUCTIONS_CONTAINER_FADE_IN_END_OFFSET));
timings.getInstructionsContainerFadeInStartOffset(),
timings.getInstructionsContainerFadeInEndOffset()));
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));
timings.getInstructionsTextFadeInStartOffset(),
timings.getInstructionsTextFadeInEndOffset()));
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));
timings.getInstructionsUnfoldStartOffset(),
timings.getInstructionsUnfoldEndOffset()));
InteractionJankMonitorWrapper.begin(this,
InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "First tile selected");
@@ -3184,24 +3137,26 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
: distanceFromDismissedTask;
// Set timings based on if user is initiating splitscreen on the focused task,
// or splitting/dismissing some other task.
SplitAnimationTimings timings = SplitAnimationTimings.OVERVIEW_TO_SPLIT;
float animationStartProgress = isStagingFocusedTask
? Utilities.boundToRange(
INITIAL_SPRING_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
+ ADDITIONAL_SPRING_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
* staggerColumn, 0f, dismissTranslationInterpolationEnd)
timings.getGridSlideStartOffset()
+ (timings.getGridSlideStaggerOffset() * 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)
timings.getGridSlideStartOffset()
+ (timings.getGridSlideStaggerOffset() * staggerColumn)
+ timings.getGridSlideDurationOffset(),
0f,
dismissTranslationInterpolationEnd)
: dismissTranslationInterpolationEnd;
Interpolator dismissInterpolator = isStagingFocusedTask ? OVERSHOOT_0_85 : LINEAR;
Interpolator dismissInterpolator = isStagingFocusedTask ? OVERSHOOT_0_75 : LINEAR;
if (taskView == nextFocusedTaskView) {
// Enlarge the task to be focused next, and translate into focus position.
@@ -4223,9 +4178,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
// TODO(194414938) starting bounds seem slightly off, investigate
Rect firstTaskStartingBounds = new Rect();
Rect firstTaskEndingBounds = mTempRect;
int duration = mActivity.getStateManager().getState().getTransitionDuration(mActivity,
false /* isToState */);
PendingAnimation pendingAnimation = new PendingAnimation(duration);
PendingAnimation pendingAnimation =
new PendingAnimation(SplitAnimationTimings.CONFIRM_DURATION);
SplitAnimationTimings timings = SplitAnimationTimings.SPLIT_TO_CONFIRM;
int halfDividerSize = getResources()
.getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2;
@@ -4235,7 +4190,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
secondTaskEndingBounds);
mFirstFloatingTaskView.getBoundsOnScreen(firstTaskStartingBounds);
mFirstFloatingTaskView.addAnimation(pendingAnimation,
mFirstFloatingTaskView.addConfirmAnimation(pendingAnimation,
new RectF(firstTaskStartingBounds), firstTaskEndingBounds,
false /* fadeWithThumbnail */, true /* isStagedTask */);
@@ -4244,8 +4199,13 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
thumbnailView, thumbnailView.getThumbnail(),
iconView.getDrawable(), secondTaskStartingBounds);
mSecondFloatingTaskView.setAlpha(1);
mSecondFloatingTaskView.addAnimation(pendingAnimation, secondTaskStartingBounds,
mSecondFloatingTaskView.addConfirmAnimation(pendingAnimation, secondTaskStartingBounds,
secondTaskEndingBounds, true /* fadeWithThumbnail */, false /* isStagedTask */);
pendingAnimation.setViewAlpha(mSplitInstructionsView, 0, clampToProgress(LINEAR,
timings.getInstructionsFadeStartOffset(),
timings.getInstructionsFadeEndOffset()));
pendingAnimation.addEndListener(aBoolean -> {
mSplitSelectStateController.launchSplitTasks(
aBoolean1 -> RecentsView.this.resetFromSplitSelectionState());
@@ -83,7 +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_0_75 = new OvershootInterpolator(0.75f);
public static final Interpolator OVERSHOOT_1_2 = new OvershootInterpolator(1.2f);
public static final Interpolator OVERSHOOT_1_7 = new OvershootInterpolator(1.7f);