Merge "Using fractions in MultiValueUpdateListener instead of absolute durations" into main
This commit is contained in:
@@ -64,6 +64,7 @@ import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATI
|
||||
import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
|
||||
import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
|
||||
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
|
||||
import static com.android.quickstep.util.AnimUtils.clampToDuration;
|
||||
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
|
||||
@@ -748,34 +749,35 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
final float finalShadowRadius = appTargetsAreTranslucent ? 0 : mMaxShadowRadius;
|
||||
|
||||
MultiValueUpdateListener listener = new MultiValueUpdateListener() {
|
||||
FloatProp mDx = new FloatProp(0, prop.dX, 0, APP_LAUNCH_DURATION,
|
||||
mOpeningXInterpolator);
|
||||
FloatProp mDy = new FloatProp(0, prop.dY, 0, APP_LAUNCH_DURATION,
|
||||
mOpeningInterpolator);
|
||||
FloatProp mDx = new FloatProp(0, prop.dX, mOpeningXInterpolator);
|
||||
FloatProp mDy = new FloatProp(0, prop.dY, mOpeningInterpolator);
|
||||
|
||||
FloatProp mIconScaleToFitScreen = new FloatProp(prop.initialAppIconScale,
|
||||
prop.finalAppIconScale, 0, APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
prop.finalAppIconScale, mOpeningInterpolator);
|
||||
FloatProp mIconAlpha = new FloatProp(prop.iconAlphaStart, 0f,
|
||||
APP_LAUNCH_ALPHA_START_DELAY, APP_LAUNCH_ALPHA_DURATION, LINEAR);
|
||||
clampToDuration(LINEAR, APP_LAUNCH_ALPHA_START_DELAY, APP_LAUNCH_ALPHA_DURATION,
|
||||
APP_LAUNCH_DURATION));
|
||||
|
||||
FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius, 0,
|
||||
APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
FloatProp mShadowRadius = new FloatProp(0, finalShadowRadius, 0,
|
||||
APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius,
|
||||
mOpeningInterpolator);
|
||||
FloatProp mShadowRadius = new FloatProp(0, finalShadowRadius,
|
||||
mOpeningInterpolator);
|
||||
|
||||
FloatProp mCropRectCenterX = new FloatProp(prop.cropCenterXStart, prop.cropCenterXEnd,
|
||||
0, APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
mOpeningInterpolator);
|
||||
FloatProp mCropRectCenterY = new FloatProp(prop.cropCenterYStart, prop.cropCenterYEnd,
|
||||
0, APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
FloatProp mCropRectWidth = new FloatProp(prop.cropWidthStart, prop.cropWidthEnd, 0,
|
||||
APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
FloatProp mCropRectHeight = new FloatProp(prop.cropHeightStart, prop.cropHeightEnd, 0,
|
||||
APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
mOpeningInterpolator);
|
||||
FloatProp mCropRectWidth = new FloatProp(prop.cropWidthStart, prop.cropWidthEnd,
|
||||
mOpeningInterpolator);
|
||||
FloatProp mCropRectHeight = new FloatProp(prop.cropHeightStart, prop.cropHeightEnd,
|
||||
mOpeningInterpolator);
|
||||
|
||||
FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION,
|
||||
NAV_FADE_OUT_INTERPOLATOR);
|
||||
FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN,
|
||||
ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
|
||||
FloatProp mNavFadeOut = new FloatProp(1f, 0f, clampToDuration(
|
||||
NAV_FADE_OUT_INTERPOLATOR, 0, ANIMATION_NAV_FADE_OUT_DURATION,
|
||||
APP_LAUNCH_DURATION));
|
||||
FloatProp mNavFadeIn = new FloatProp(0f, 1f, clampToDuration(
|
||||
NAV_FADE_IN_INTERPOLATOR, ANIMATION_DELAY_NAV_FADE_IN,
|
||||
ANIMATION_NAV_FADE_IN_DURATION, APP_LAUNCH_DURATION));
|
||||
|
||||
@Override
|
||||
public void onUpdate(float percent, boolean initOnly) {
|
||||
@@ -968,37 +970,36 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
|
||||
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
|
||||
float mAppWindowScale = 1;
|
||||
final FloatProp mWidgetForegroundAlpha = new FloatProp(1 /* start */,
|
||||
0 /* end */, 0 /* delay */,
|
||||
WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* duration */, LINEAR);
|
||||
final FloatProp mWidgetFallbackBackgroundAlpha = new FloatProp(0 /* start */,
|
||||
1 /* end */, 0 /* delay */, 75 /* duration */, LINEAR);
|
||||
final FloatProp mPreviewAlpha = new FloatProp(0 /* start */, 1 /* end */,
|
||||
final FloatProp mWidgetForegroundAlpha = new FloatProp(1, 0, clampToDuration(
|
||||
LINEAR, 0, WIDGET_CROSSFADE_DURATION_MILLIS / 2, APP_LAUNCH_DURATION));
|
||||
|
||||
final FloatProp mWidgetFallbackBackgroundAlpha = new FloatProp(0, 1,
|
||||
clampToDuration(LINEAR, 0, 75, APP_LAUNCH_DURATION));
|
||||
final FloatProp mPreviewAlpha = new FloatProp(0, 1, clampToDuration(
|
||||
LINEAR,
|
||||
WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* delay */,
|
||||
WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* duration */, LINEAR);
|
||||
WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* duration */,
|
||||
APP_LAUNCH_DURATION));
|
||||
final FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius,
|
||||
0 /* start */, APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
final FloatProp mCornerRadiusProgress = new FloatProp(0, 1, 0, APP_LAUNCH_DURATION,
|
||||
mOpeningInterpolator);
|
||||
final FloatProp mCornerRadiusProgress = new FloatProp(0, 1, mOpeningInterpolator);
|
||||
|
||||
// Window & widget background positioning bounds
|
||||
final FloatProp mDx = new FloatProp(widgetBackgroundBounds.centerX(),
|
||||
windowTargetBounds.centerX(), 0 /* delay */, APP_LAUNCH_DURATION,
|
||||
mOpeningXInterpolator);
|
||||
windowTargetBounds.centerX(), mOpeningXInterpolator);
|
||||
final FloatProp mDy = new FloatProp(widgetBackgroundBounds.centerY(),
|
||||
windowTargetBounds.centerY(), 0 /* delay */, APP_LAUNCH_DURATION,
|
||||
mOpeningInterpolator);
|
||||
windowTargetBounds.centerY(), mOpeningInterpolator);
|
||||
final FloatProp mWidth = new FloatProp(widgetBackgroundBounds.width(),
|
||||
windowTargetBounds.width(), 0 /* delay */, APP_LAUNCH_DURATION,
|
||||
mOpeningInterpolator);
|
||||
windowTargetBounds.width(), mOpeningInterpolator);
|
||||
final FloatProp mHeight = new FloatProp(widgetBackgroundBounds.height(),
|
||||
windowTargetBounds.height(), 0 /* delay */, APP_LAUNCH_DURATION,
|
||||
mOpeningInterpolator);
|
||||
windowTargetBounds.height(), mOpeningInterpolator);
|
||||
|
||||
final FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION,
|
||||
NAV_FADE_OUT_INTERPOLATOR);
|
||||
final FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN,
|
||||
ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
|
||||
final FloatProp mNavFadeOut = new FloatProp(1f, 0f, clampToDuration(
|
||||
NAV_FADE_OUT_INTERPOLATOR, 0, ANIMATION_NAV_FADE_OUT_DURATION,
|
||||
APP_LAUNCH_DURATION));
|
||||
final FloatProp mNavFadeIn = new FloatProp(0f, 1f, clampToDuration(
|
||||
NAV_FADE_IN_INTERPOLATOR, ANIMATION_DELAY_NAV_FADE_IN,
|
||||
ANIMATION_NAV_FADE_IN_DURATION, APP_LAUNCH_DURATION));
|
||||
|
||||
@Override
|
||||
public void onUpdate(float percent, boolean initOnly) {
|
||||
@@ -1508,11 +1509,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
float startShadowRadius = areAllTargetsTranslucent(appTargets) ? 0 : mMaxShadowRadius;
|
||||
closingAnimator.setDuration(duration);
|
||||
closingAnimator.addUpdateListener(new MultiValueUpdateListener() {
|
||||
FloatProp mDy = new FloatProp(0, mClosingWindowTransY, 0, duration, DECELERATE_1_7);
|
||||
FloatProp mScale = new FloatProp(1f, 1f, 0, duration, DECELERATE_1_7);
|
||||
FloatProp mAlpha = new FloatProp(1f, 0f, 25, 125, LINEAR);
|
||||
FloatProp mShadowRadius = new FloatProp(startShadowRadius, 0, 0, duration,
|
||||
DECELERATE_1_7);
|
||||
FloatProp mDy = new FloatProp(0, mClosingWindowTransY, DECELERATE_1_7);
|
||||
FloatProp mScale = new FloatProp(1f, 1f, DECELERATE_1_7);
|
||||
FloatProp mAlpha = new FloatProp(1f, 0f, clampToDuration(LINEAR, 25, 125, duration));
|
||||
FloatProp mShadowRadius = new FloatProp(startShadowRadius, 0, DECELERATE_1_7);
|
||||
|
||||
@Override
|
||||
public void onUpdate(float percent, boolean initOnly) {
|
||||
|
||||
@@ -686,15 +686,10 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im
|
||||
float toScale = iconSize / mDragIconSize;
|
||||
float toAlpha = (target == originalView) ? 1f : 0f;
|
||||
MultiValueUpdateListener listener = new MultiValueUpdateListener() {
|
||||
final FloatProp mDx = new FloatProp(fromX, toPosition[0], 0,
|
||||
ANIM_DURATION_RETURN_ICON_TO_TASKBAR, Interpolators.FAST_OUT_SLOW_IN);
|
||||
final FloatProp mDy = new FloatProp(fromY, toPosition[1], 0,
|
||||
ANIM_DURATION_RETURN_ICON_TO_TASKBAR,
|
||||
FAST_OUT_SLOW_IN);
|
||||
final FloatProp mScale = new FloatProp(1f, toScale, 0,
|
||||
ANIM_DURATION_RETURN_ICON_TO_TASKBAR, FAST_OUT_SLOW_IN);
|
||||
final FloatProp mAlpha = new FloatProp(1f, toAlpha, 0,
|
||||
ANIM_DURATION_RETURN_ICON_TO_TASKBAR, Interpolators.ACCELERATE_2);
|
||||
final FloatProp mDx = new FloatProp(fromX, toPosition[0], FAST_OUT_SLOW_IN);
|
||||
final FloatProp mDy = new FloatProp(fromY, toPosition[1], FAST_OUT_SLOW_IN);
|
||||
final FloatProp mScale = new FloatProp(1f, toScale, FAST_OUT_SLOW_IN);
|
||||
final FloatProp mAlpha = new FloatProp(1f, toAlpha, Interpolators.ACCELERATE_2);
|
||||
@Override
|
||||
public void onUpdate(float percent, boolean initOnly) {
|
||||
animListener.updateDragShadow(mDx.value, mDy.value, mScale.value, mAlpha.value);
|
||||
|
||||
@@ -37,6 +37,7 @@ import static com.android.launcher3.QuickstepTransitionManager.SPLIT_DIVIDER_ANI
|
||||
import static com.android.launcher3.QuickstepTransitionManager.SPLIT_LAUNCH_DURATION;
|
||||
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
|
||||
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
|
||||
import static com.android.quickstep.util.AnimUtils.clampToDuration;
|
||||
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -267,10 +268,16 @@ public final class TaskViewUtils {
|
||||
if (navBarTarget != null) {
|
||||
final Rect cropRect = new Rect();
|
||||
out.addOnFrameListener(new MultiValueUpdateListener() {
|
||||
FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0,
|
||||
ANIMATION_NAV_FADE_OUT_DURATION, NAV_FADE_OUT_INTERPOLATOR);
|
||||
FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN,
|
||||
ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
|
||||
FloatProp mNavFadeOut = new FloatProp(1f, 0f, clampToDuration(
|
||||
NAV_FADE_OUT_INTERPOLATOR,
|
||||
0,
|
||||
ANIMATION_NAV_FADE_OUT_DURATION,
|
||||
out.getDuration()));
|
||||
FloatProp mNavFadeIn = new FloatProp(0f, 1f, clampToDuration(
|
||||
NAV_FADE_IN_INTERPOLATOR,
|
||||
ANIMATION_DELAY_NAV_FADE_IN,
|
||||
ANIMATION_NAV_FADE_IN_DURATION,
|
||||
out.getDuration()));
|
||||
|
||||
@Override
|
||||
public void onUpdate(float percent, boolean initOnly) {
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static com.android.app.animation.Interpolators.clampToProgress;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.IRemoteCallback;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.util.RunnableList;
|
||||
|
||||
@@ -67,4 +69,15 @@ public class AnimUtils {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a function that runs the given interpolator such that the entire progress is set
|
||||
* between the given duration. That is, we set the interpolation to 0 until startDelay and reach
|
||||
* 1 by (startDelay + duration).
|
||||
*/
|
||||
public static Interpolator clampToDuration(Interpolator interpolator, float startDelay,
|
||||
float duration, float totalDuration) {
|
||||
return clampToProgress(interpolator, startDelay / totalDuration,
|
||||
(startDelay + duration) / totalDuration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.annotation.FloatRange;
|
||||
import android.annotation.IntRange;
|
||||
|
||||
/*
|
||||
* Adds getter methods to {@link MultiValueUpdateListener} specific to app close animation,
|
||||
* so that the entire animation can be defined in one place.
|
||||
*/
|
||||
public abstract class AppCloseConfig extends MultiValueUpdateListener {
|
||||
|
||||
/**
|
||||
* Returns the translation y of the workspace contents.
|
||||
*/
|
||||
public abstract float getWorkspaceTransY();
|
||||
|
||||
/*
|
||||
* Returns the scale of the workspace contents.
|
||||
*/
|
||||
public abstract float getWorkspaceScale();
|
||||
|
||||
/*
|
||||
* Returns the alpha of the window.
|
||||
*/
|
||||
public abstract @FloatRange(from = 0, to = 1) float getWindowAlpha();
|
||||
|
||||
/*
|
||||
* Returns the alpha of the foreground layer of an adaptive icon.
|
||||
*/
|
||||
public abstract @IntRange(from = 0, to = 255) int getFgAlpha();
|
||||
|
||||
/*
|
||||
* Returns the corner radius of the window and icon.
|
||||
*/
|
||||
public abstract float getCornerRadius();
|
||||
|
||||
/*
|
||||
* Returns the interpolated progress of the animation.
|
||||
*/
|
||||
public abstract float getInterpolatedProgress();
|
||||
|
||||
}
|
||||
@@ -18,6 +18,8 @@ package com.android.quickstep.util;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
@@ -31,14 +33,11 @@ public abstract class MultiValueUpdateListener implements ValueAnimator.Animator
|
||||
@Override
|
||||
public final void onAnimationUpdate(ValueAnimator animator) {
|
||||
final float percent = animator.getAnimatedFraction();
|
||||
final float currentPlayTime = percent * animator.getDuration();
|
||||
|
||||
for (int i = mAllProperties.size() - 1; i >= 0; i--) {
|
||||
FloatProp prop = mAllProperties.get(i);
|
||||
float time = Math.max(0, currentPlayTime - prop.mDelay);
|
||||
float newPercent = Math.min(1f, time / prop.mDuration);
|
||||
newPercent = prop.mInterpolator.getInterpolation(newPercent);
|
||||
prop.value = prop.mEnd * newPercent + prop.mStart * (1 - newPercent);
|
||||
float interpolatedPercent = prop.mInterpolator.getInterpolation(percent);
|
||||
prop.value = Utilities.mapRange(interpolatedPercent, prop.mStart, prop.mEnd);
|
||||
}
|
||||
onUpdate(percent, false /* initOnly */);
|
||||
}
|
||||
@@ -55,17 +54,12 @@ public abstract class MultiValueUpdateListener implements ValueAnimator.Animator
|
||||
|
||||
private final float mStart;
|
||||
private final float mEnd;
|
||||
private final float mDelay;
|
||||
private final float mDuration;
|
||||
private final Interpolator mInterpolator;
|
||||
|
||||
public FloatProp(float start, float end, float delay, float duration, Interpolator i) {
|
||||
public FloatProp(float start, float end, Interpolator i) {
|
||||
value = mStart = start;
|
||||
mEnd = end;
|
||||
mDelay = delay;
|
||||
mDuration = duration;
|
||||
mInterpolator = i;
|
||||
|
||||
mAllProperties.add(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,69 +70,84 @@ import java.util.Optional
|
||||
import java.util.function.Supplier
|
||||
|
||||
/**
|
||||
* Utils class to help run animations for initiating split screen from launcher.
|
||||
* Will be expanded with future refactors. Works in conjunction with the state stored in
|
||||
* [SplitSelectStateController]
|
||||
* Utils class to help run animations for initiating split screen from launcher. Will be expanded
|
||||
* with future refactors. Works in conjunction with the state stored in [SplitSelectStateController]
|
||||
*/
|
||||
class SplitAnimationController(val splitSelectStateController: SplitSelectStateController) {
|
||||
companion object {
|
||||
// Break this out into maybe enums? Abstractions into its own classes? Tbd.
|
||||
data class SplitAnimInitProps(
|
||||
val originalView: View,
|
||||
val originalBitmap: Bitmap?,
|
||||
val iconDrawable: Drawable,
|
||||
val fadeWithThumbnail: Boolean,
|
||||
val isStagedTask: Boolean,
|
||||
val iconView: View?
|
||||
val originalView: View,
|
||||
val originalBitmap: Bitmap?,
|
||||
val iconDrawable: Drawable,
|
||||
val fadeWithThumbnail: Boolean,
|
||||
val isStagedTask: Boolean,
|
||||
val iconView: View?
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns different elements to animate for the initial split selection animation
|
||||
* depending on the state of the surface from which the split was initiated
|
||||
* Returns different elements to animate for the initial split selection animation depending on
|
||||
* the state of the surface from which the split was initiated
|
||||
*/
|
||||
fun getFirstAnimInitViews(taskViewSupplier: Supplier<TaskView>,
|
||||
splitSelectSourceSupplier: Supplier<SplitSelectSource?>)
|
||||
: SplitAnimInitProps {
|
||||
fun getFirstAnimInitViews(
|
||||
taskViewSupplier: Supplier<TaskView>,
|
||||
splitSelectSourceSupplier: Supplier<SplitSelectSource?>
|
||||
): SplitAnimInitProps {
|
||||
val splitSelectSource = splitSelectSourceSupplier.get()
|
||||
if (!splitSelectStateController.isAnimateCurrentTaskDismissal) {
|
||||
// Initiating from home
|
||||
return SplitAnimInitProps(splitSelectSource!!.view, originalBitmap = null,
|
||||
splitSelectSource.drawable, fadeWithThumbnail = false, isStagedTask = true,
|
||||
iconView = null)
|
||||
return SplitAnimInitProps(
|
||||
splitSelectSource!!.view,
|
||||
originalBitmap = null,
|
||||
splitSelectSource.drawable,
|
||||
fadeWithThumbnail = false,
|
||||
isStagedTask = true,
|
||||
iconView = null
|
||||
)
|
||||
} else if (splitSelectStateController.isDismissingFromSplitPair) {
|
||||
// Initiating split from overview, but on a split pair
|
||||
val taskView = taskViewSupplier.get()
|
||||
for (container : TaskIdAttributeContainer in taskView.taskIdAttributeContainers) {
|
||||
for (container: TaskIdAttributeContainer in taskView.taskIdAttributeContainers) {
|
||||
if (container.task.getKey().getId() == splitSelectStateController.initialTaskId) {
|
||||
val drawable = getDrawable(container.iconView, splitSelectSource)
|
||||
return SplitAnimInitProps(container.thumbnailView,
|
||||
container.thumbnailView.thumbnail, drawable!!,
|
||||
fadeWithThumbnail = true, isStagedTask = true,
|
||||
iconView = container.iconView.asView()
|
||||
return SplitAnimInitProps(
|
||||
container.thumbnailView,
|
||||
container.thumbnailView.thumbnail,
|
||||
drawable!!,
|
||||
fadeWithThumbnail = true,
|
||||
isStagedTask = true,
|
||||
iconView = container.iconView.asView()
|
||||
)
|
||||
}
|
||||
}
|
||||
throw IllegalStateException("Attempting to init split from existing split pair " +
|
||||
"without a valid taskIdAttributeContainer")
|
||||
throw IllegalStateException(
|
||||
"Attempting to init split from existing split pair " +
|
||||
"without a valid taskIdAttributeContainer"
|
||||
)
|
||||
} else {
|
||||
// Initiating split from overview on fullscreen task TaskView
|
||||
val taskView = taskViewSupplier.get()
|
||||
val drawable = getDrawable(taskView.iconView, splitSelectSource)
|
||||
return SplitAnimInitProps(taskView.thumbnail, taskView.thumbnail.thumbnail,
|
||||
drawable!!, fadeWithThumbnail = true, isStagedTask = true,
|
||||
taskView.iconView.asView()
|
||||
return SplitAnimInitProps(
|
||||
taskView.thumbnail,
|
||||
taskView.thumbnail.thumbnail,
|
||||
drawable!!,
|
||||
fadeWithThumbnail = true,
|
||||
isStagedTask = true,
|
||||
taskView.iconView.asView()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the drawable that's provided in iconView, however if that
|
||||
* is null it falls back to the drawable that's in splitSelectSource.
|
||||
* TaskView's icon drawable can be null if the TaskView is scrolled far enough off screen
|
||||
* Returns the drawable that's provided in iconView, however if that is null it falls back to
|
||||
* the drawable that's in splitSelectSource. TaskView's icon drawable can be null if the
|
||||
* TaskView is scrolled far enough off screen
|
||||
*
|
||||
* @return [Drawable]
|
||||
*/
|
||||
fun getDrawable(iconView: TaskViewIcon, splitSelectSource: SplitSelectSource?) : Drawable? {
|
||||
fun getDrawable(iconView: TaskViewIcon, splitSelectSource: SplitSelectSource?): Drawable? {
|
||||
if (iconView.drawable == null && splitSelectSource != null) {
|
||||
return splitSelectSource.drawable
|
||||
}
|
||||
@@ -140,21 +155,25 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
|
||||
}
|
||||
|
||||
/**
|
||||
* When selecting first app from split pair, second app's thumbnail remains. This animates
|
||||
* the second thumbnail by expanding it to take up the full taskViewWidth/Height and overlaying
|
||||
* it with [TaskThumbnailView]'s splashView. Adds animations to the provided builder.
|
||||
* Note: The app that **was not** selected as the first split app should be the container that's
|
||||
* passed through.
|
||||
* When selecting first app from split pair, second app's thumbnail remains. This animates the
|
||||
* second thumbnail by expanding it to take up the full taskViewWidth/Height and overlaying it
|
||||
* with [TaskThumbnailView]'s splashView. Adds animations to the provided builder. Note: The app
|
||||
* that **was not** selected as the first split app should be the container that's passed
|
||||
* through.
|
||||
*
|
||||
* @param builder Adds animation to this
|
||||
* @param taskIdAttributeContainer container of the app that **was not** selected
|
||||
* @param isPrimaryTaskSplitting if true, task that was split would be top/left in the pair
|
||||
* (opposite of that representing [taskIdAttributeContainer])
|
||||
* (opposite of that representing [taskIdAttributeContainer])
|
||||
*/
|
||||
fun addInitialSplitFromPair(taskIdAttributeContainer: TaskIdAttributeContainer,
|
||||
builder: PendingAnimation, deviceProfile: DeviceProfile,
|
||||
taskViewWidth: Int, taskViewHeight: Int,
|
||||
isPrimaryTaskSplitting: Boolean) {
|
||||
fun addInitialSplitFromPair(
|
||||
taskIdAttributeContainer: TaskIdAttributeContainer,
|
||||
builder: PendingAnimation,
|
||||
deviceProfile: DeviceProfile,
|
||||
taskViewWidth: Int,
|
||||
taskViewHeight: Int,
|
||||
isPrimaryTaskSplitting: Boolean
|
||||
) {
|
||||
val thumbnail = taskIdAttributeContainer.thumbnailView
|
||||
val iconView: View = taskIdAttributeContainer.iconView.asView()
|
||||
builder.add(ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLASH_ALPHA, 1f))
|
||||
@@ -170,35 +189,42 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
|
||||
)
|
||||
)
|
||||
builder.add(
|
||||
ObjectAnimator.ofFloat(
|
||||
iconView.splitTranslationY,
|
||||
MULTI_PROPERTY_VALUE,
|
||||
0f
|
||||
)
|
||||
ObjectAnimator.ofFloat(iconView.splitTranslationY, MULTI_PROPERTY_VALUE, 0f)
|
||||
)
|
||||
}
|
||||
if (deviceProfile.isLeftRightSplit) {
|
||||
// Center view first so scaling happens uniformly, alternatively we can move pivotX to 0
|
||||
val centerThumbnailTranslationX: Float = (taskViewWidth - thumbnail.width) / 2f
|
||||
val finalScaleX: Float = taskViewWidth.toFloat() / thumbnail.width
|
||||
builder.add(ObjectAnimator.ofFloat(thumbnail,
|
||||
TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, centerThumbnailTranslationX))
|
||||
builder.add(
|
||||
ObjectAnimator.ofFloat(
|
||||
thumbnail,
|
||||
TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X,
|
||||
centerThumbnailTranslationX
|
||||
)
|
||||
)
|
||||
if (!enableOverviewIconMenu()) {
|
||||
// icons are anchored from Gravity.END, so need to use negative translation
|
||||
val centerIconTranslationX: Float = (taskViewWidth - iconView.width) / 2f
|
||||
builder.add(ObjectAnimator.ofFloat(iconView, View.TRANSLATION_X,
|
||||
-centerIconTranslationX))
|
||||
builder.add(
|
||||
ObjectAnimator.ofFloat(iconView, View.TRANSLATION_X, -centerIconTranslationX)
|
||||
)
|
||||
}
|
||||
builder.add(ObjectAnimator.ofFloat(thumbnail, View.SCALE_X, finalScaleX))
|
||||
|
||||
// Reset other dimensions
|
||||
// TODO(b/271468547), can't set Y translate to 0, need to account for top space
|
||||
thumbnail.scaleY = 1f
|
||||
val translateYResetVal: Float = if (!isPrimaryTaskSplitting) 0f else
|
||||
deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat()
|
||||
builder.add(ObjectAnimator.ofFloat(thumbnail,
|
||||
val translateYResetVal: Float =
|
||||
if (!isPrimaryTaskSplitting) 0f
|
||||
else deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat()
|
||||
builder.add(
|
||||
ObjectAnimator.ofFloat(
|
||||
thumbnail,
|
||||
TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y,
|
||||
translateYResetVal))
|
||||
translateYResetVal
|
||||
)
|
||||
)
|
||||
} else {
|
||||
val thumbnailSize = taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx
|
||||
// Center view first so scaling happens uniformly, alternatively we can move pivotY to 0
|
||||
@@ -214,16 +240,21 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
|
||||
// translations otherwise this asymmetry causes problems..
|
||||
if (isPrimaryTaskSplitting) {
|
||||
centerThumbnailTranslationY = (thumbnailSize - thumbnail.height) / 2f
|
||||
centerThumbnailTranslationY += deviceProfile.overviewTaskThumbnailTopMarginPx
|
||||
.toFloat()
|
||||
centerThumbnailTranslationY +=
|
||||
deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat()
|
||||
} else {
|
||||
centerThumbnailTranslationY = (thumbnailSize - thumbnail.height) / 2f
|
||||
}
|
||||
val finalScaleY: Float = thumbnailSize.toFloat() / thumbnail.height
|
||||
builder.add(ObjectAnimator.ofFloat(thumbnail,
|
||||
TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y, centerThumbnailTranslationY))
|
||||
builder.add(
|
||||
ObjectAnimator.ofFloat(
|
||||
thumbnail,
|
||||
TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y,
|
||||
centerThumbnailTranslationY
|
||||
)
|
||||
)
|
||||
|
||||
if (!enableOverviewIconMenu()) {
|
||||
if (!enableOverviewIconMenu()) {
|
||||
// icons are anchored from Gravity.END, so need to use negative translation
|
||||
builder.add(ObjectAnimator.ofFloat(iconView, View.TRANSLATION_X, 0f))
|
||||
}
|
||||
@@ -231,8 +262,9 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
|
||||
|
||||
// Reset other dimensions
|
||||
thumbnail.scaleX = 1f
|
||||
builder.add(ObjectAnimator.ofFloat(thumbnail,
|
||||
TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, 0f))
|
||||
builder.add(
|
||||
ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, 0f)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,69 +282,94 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
|
||||
* Returns [AnimatorSet] which slides initial split placeholder view offscreen and logs an event
|
||||
* for why split is being dismissed
|
||||
*/
|
||||
fun createPlaceholderDismissAnim(launcher: StatefulActivity<*>,
|
||||
splitDismissEvent: EventEnum,
|
||||
duration: Long?) : AnimatorSet {
|
||||
fun createPlaceholderDismissAnim(
|
||||
launcher: StatefulActivity<*>,
|
||||
splitDismissEvent: EventEnum,
|
||||
duration: Long?
|
||||
): AnimatorSet {
|
||||
val animatorSet = AnimatorSet()
|
||||
duration?.let { animatorSet.duration = it }
|
||||
val recentsView : RecentsView<*, *> = launcher.getOverviewPanel()
|
||||
val floatingTask: FloatingTaskView = splitSelectStateController.firstFloatingTaskView
|
||||
?: return animatorSet
|
||||
val recentsView: RecentsView<*, *> = launcher.getOverviewPanel()
|
||||
val floatingTask: FloatingTaskView =
|
||||
splitSelectStateController.firstFloatingTaskView ?: return animatorSet
|
||||
|
||||
// We are in split selection state currently, transitioning to another state
|
||||
val dragLayer: BaseDragLayer<*> = launcher.dragLayer
|
||||
val onScreenRectF = RectF()
|
||||
Utilities.getBoundsForViewInDragLayer(dragLayer, floatingTask,
|
||||
Rect(0, 0, floatingTask.width, floatingTask.height),
|
||||
false, null, onScreenRectF)
|
||||
Utilities.getBoundsForViewInDragLayer(
|
||||
dragLayer,
|
||||
floatingTask,
|
||||
Rect(0, 0, floatingTask.width, floatingTask.height),
|
||||
false,
|
||||
null,
|
||||
onScreenRectF
|
||||
)
|
||||
// Get the part of the floatingTask that intersects with the DragLayer (i.e. the
|
||||
// on-screen portion)
|
||||
onScreenRectF.intersect(
|
||||
dragLayer.left.toFloat(),
|
||||
dragLayer.top.toFloat(),
|
||||
dragLayer.right.toFloat(),
|
||||
dragLayer.bottom
|
||||
.toFloat()
|
||||
dragLayer.left.toFloat(),
|
||||
dragLayer.top.toFloat(),
|
||||
dragLayer.right.toFloat(),
|
||||
dragLayer.bottom.toFloat()
|
||||
)
|
||||
animatorSet.play(ObjectAnimator.ofFloat(floatingTask,
|
||||
animatorSet.play(
|
||||
ObjectAnimator.ofFloat(
|
||||
floatingTask,
|
||||
FloatingTaskView.PRIMARY_TRANSLATE_OFFSCREEN,
|
||||
recentsView.pagedOrientationHandler
|
||||
.getFloatingTaskOffscreenTranslationTarget(
|
||||
floatingTask,
|
||||
onScreenRectF,
|
||||
floatingTask.stagePosition,
|
||||
launcher.deviceProfile
|
||||
)))
|
||||
animatorSet.addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
splitSelectStateController.resetState()
|
||||
safeRemoveViewFromDragLayer(launcher,
|
||||
splitSelectStateController.splitInstructionsView)
|
||||
recentsView.pagedOrientationHandler.getFloatingTaskOffscreenTranslationTarget(
|
||||
floatingTask,
|
||||
onScreenRectF,
|
||||
floatingTask.stagePosition,
|
||||
launcher.deviceProfile
|
||||
)
|
||||
)
|
||||
)
|
||||
animatorSet.addListener(
|
||||
object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
splitSelectStateController.resetState()
|
||||
safeRemoveViewFromDragLayer(
|
||||
launcher,
|
||||
splitSelectStateController.splitInstructionsView
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
splitSelectStateController.logExitReason(splitDismissEvent)
|
||||
return animatorSet
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [PendingAnimation] to animate in the chip to instruct a user to select a second
|
||||
* app for splitscreen
|
||||
* Returns a [PendingAnimation] to animate in the chip to instruct a user to select a second app
|
||||
* for splitscreen
|
||||
*/
|
||||
fun getShowSplitInstructionsAnim(launcher: StatefulActivity<*>) : PendingAnimation {
|
||||
fun getShowSplitInstructionsAnim(launcher: StatefulActivity<*>): PendingAnimation {
|
||||
safeRemoveViewFromDragLayer(launcher, splitSelectStateController.splitInstructionsView)
|
||||
val splitInstructionsView = SplitInstructionsView.getSplitInstructionsView(launcher)
|
||||
splitSelectStateController.splitInstructionsView = splitInstructionsView
|
||||
val timings = AnimUtils.getDeviceOverviewToSplitTimings(launcher.deviceProfile.isTablet)
|
||||
val anim = PendingAnimation(100 /*duration */)
|
||||
splitInstructionsView.alpha = 0f
|
||||
anim.setViewAlpha(splitInstructionsView, 1f,
|
||||
Interpolators.clampToProgress(Interpolators.LINEAR,
|
||||
timings.instructionsContainerFadeInStartOffset,
|
||||
timings.instructionsContainerFadeInEndOffset))
|
||||
anim.addFloat(splitInstructionsView, SplitInstructionsView.UNFOLD, 0.1f, 1f,
|
||||
Interpolators.clampToProgress(Interpolators.EMPHASIZED_DECELERATE,
|
||||
timings.instructionsUnfoldStartOffset,
|
||||
timings.instructionsUnfoldEndOffset))
|
||||
anim.setViewAlpha(
|
||||
splitInstructionsView,
|
||||
1f,
|
||||
Interpolators.clampToProgress(
|
||||
Interpolators.LINEAR,
|
||||
timings.instructionsContainerFadeInStartOffset,
|
||||
timings.instructionsContainerFadeInEndOffset
|
||||
)
|
||||
)
|
||||
anim.addFloat(
|
||||
splitInstructionsView,
|
||||
SplitInstructionsView.UNFOLD,
|
||||
0.1f,
|
||||
1f,
|
||||
Interpolators.clampToProgress(
|
||||
Interpolators.EMPHASIZED_DECELERATE,
|
||||
timings.instructionsUnfoldStartOffset,
|
||||
timings.instructionsUnfoldEndOffset
|
||||
)
|
||||
)
|
||||
return anim
|
||||
}
|
||||
|
||||
@@ -323,15 +380,20 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
|
||||
|
||||
/**
|
||||
* Animates the first placeholder view to fullscreen and launches its task.
|
||||
*
|
||||
* TODO(b/276361926): Remove the [resetCallback] option once contextual launches
|
||||
*/
|
||||
fun playAnimPlaceholderToFullscreen(launcher: StatefulActivity<*>, view: View,
|
||||
resetCallback: Optional<Runnable>) {
|
||||
fun playAnimPlaceholderToFullscreen(
|
||||
launcher: StatefulActivity<*>,
|
||||
view: View,
|
||||
resetCallback: Optional<Runnable>
|
||||
) {
|
||||
val stagedTaskView = view as FloatingTaskView
|
||||
|
||||
val isTablet: Boolean = launcher.deviceProfile.isTablet
|
||||
val duration = if (isTablet) SplitAnimationTimings.TABLET_CONFIRM_DURATION else
|
||||
SplitAnimationTimings.PHONE_CONFIRM_DURATION
|
||||
val duration =
|
||||
if (isTablet) SplitAnimationTimings.TABLET_CONFIRM_DURATION
|
||||
else SplitAnimationTimings.PHONE_CONFIRM_DURATION
|
||||
val pendingAnimation = PendingAnimation(duration.toLong())
|
||||
val firstTaskStartingBounds = Rect()
|
||||
val firstTaskEndingBounds = Rect()
|
||||
@@ -341,11 +403,12 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
|
||||
splitSelectStateController.setLaunchingFirstAppFullscreen()
|
||||
|
||||
stagedTaskView.addConfirmAnimation(
|
||||
pendingAnimation,
|
||||
RectF(firstTaskStartingBounds),
|
||||
firstTaskEndingBounds,
|
||||
false /* fadeWithThumbnail */,
|
||||
true /* isStagedTask */)
|
||||
pendingAnimation,
|
||||
RectF(firstTaskStartingBounds),
|
||||
firstTaskEndingBounds,
|
||||
false /* fadeWithThumbnail */,
|
||||
true /* isStagedTask */
|
||||
)
|
||||
|
||||
pendingAnimation.addEndListener {
|
||||
splitSelectStateController.launchInitialAppFullscreen {
|
||||
@@ -490,8 +553,8 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
|
||||
* When the user taps an app pair icon to launch split, this will play the tasks' launch
|
||||
* animation from the position of the icon.
|
||||
*
|
||||
* To find the root shell leash that we want to fade in, we do the following:
|
||||
* The Changes we receive in transitionInfo are structured like this
|
||||
* To find the root shell leash that we want to fade in, we do the following: The Changes we
|
||||
* receive in transitionInfo are structured like this
|
||||
*
|
||||
* Root (grandparent)
|
||||
* |
|
||||
@@ -503,9 +566,9 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
|
||||
* |
|
||||
* --> App 2 (right/bottom side child) (WINDOWING_MODE_MULTI_WINDOW)
|
||||
*
|
||||
* We want to animate the Root (grandparent) so that it affects both apps and the divider.
|
||||
* To do this, we find one of the nodes with WINDOWING_MODE_MULTI_WINDOW (one of the
|
||||
* left-side ones, for simplicity) and traverse the tree until we find the grandparent.
|
||||
* We want to animate the Root (grandparent) so that it affects both apps and the divider. To do
|
||||
* this, we find one of the nodes with WINDOWING_MODE_MULTI_WINDOW (one of the left-side ones,
|
||||
* for simplicity) and traverse the tree until we find the grandparent.
|
||||
*
|
||||
* This function is only called when we are animating the app pair in from scratch. It is NOT
|
||||
* called when we are animating in from an existing visible TaskView tile or an app that is
|
||||
@@ -544,8 +607,10 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
|
||||
// TODO (b/316490565): Replace this logic when SplitBounds is available to
|
||||
// startAnimation() and we can know the precise taskIds of launching tasks.
|
||||
// Find a change that has WINDOWING_MODE_MULTI_WINDOW.
|
||||
if (taskInfo.windowingMode == WINDOWING_MODE_MULTI_WINDOW &&
|
||||
(change.mode == TRANSIT_OPEN || change.mode == TRANSIT_TO_FRONT)) {
|
||||
if (
|
||||
taskInfo.windowingMode == WINDOWING_MODE_MULTI_WINDOW &&
|
||||
(change.mode == TRANSIT_OPEN || change.mode == TRANSIT_TO_FRONT)
|
||||
) {
|
||||
// Check if it is a left/top app.
|
||||
val isLeftTopApp =
|
||||
(dp.isLeftRightSplit && change.endAbsBounds.left == 0) ||
|
||||
@@ -614,8 +679,6 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
|
||||
FloatProp(
|
||||
floatingView.startingPosition.left,
|
||||
dp.widthPx / 2f - floatingView.startingPosition.width() / 2f,
|
||||
0f /* delay */,
|
||||
timings.getDuration().toFloat(),
|
||||
Interpolators.clampToProgress(
|
||||
timings.getStagedRectXInterpolator(),
|
||||
timings.stagedRectSlideStartOffset,
|
||||
@@ -626,8 +689,6 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
|
||||
FloatProp(
|
||||
floatingView.startingPosition.top,
|
||||
dp.heightPx / 2f - floatingView.startingPosition.height() / 2f,
|
||||
0f /* delay */,
|
||||
timings.getDuration().toFloat(),
|
||||
Interpolators.clampToProgress(
|
||||
Interpolators.EMPHASIZED,
|
||||
timings.stagedRectSlideStartOffset,
|
||||
@@ -638,8 +699,6 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
|
||||
FloatProp(
|
||||
1f /* start */,
|
||||
dp.widthPx / floatingView.startingPosition.width(),
|
||||
0f /* delay */,
|
||||
timings.getDuration().toFloat(),
|
||||
Interpolators.clampToProgress(
|
||||
Interpolators.EMPHASIZED,
|
||||
timings.stagedRectSlideStartOffset,
|
||||
@@ -650,8 +709,6 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
|
||||
FloatProp(
|
||||
1f /* start */,
|
||||
dp.heightPx / floatingView.startingPosition.height(),
|
||||
0f /* delay */,
|
||||
timings.getDuration().toFloat(),
|
||||
Interpolators.clampToProgress(
|
||||
Interpolators.EMPHASIZED,
|
||||
timings.stagedRectSlideStartOffset,
|
||||
|
||||
@@ -22,6 +22,7 @@ import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALL_APPS_EDU_SHOWN;
|
||||
import static com.android.quickstep.util.AnimUtils.clampToDuration;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -187,10 +188,14 @@ public class AllAppsEduView extends AbstractFloatingView {
|
||||
intro.setInterpolator(LINEAR);
|
||||
intro.setDuration(introDuration);
|
||||
intro.addUpdateListener((new MultiValueUpdateListener() {
|
||||
FloatProp mCircleAlpha = new FloatProp(0, 255, 0, firstPart, LINEAR);
|
||||
FloatProp mCircleScale = new FloatProp(2f, 1f, 0, firstPart, OVERSHOOT_1_7);
|
||||
FloatProp mDeltaY = new FloatProp(0, transY, firstPart, secondPart, FAST_OUT_SLOW_IN);
|
||||
FloatProp mGradientAlpha = new FloatProp(0, 255, firstPart, secondPart * 0.3f, LINEAR);
|
||||
FloatProp mCircleAlpha = new FloatProp(0, 255,
|
||||
clampToDuration(LINEAR, 0, firstPart, introDuration));
|
||||
FloatProp mCircleScale = new FloatProp(2f, 1f,
|
||||
clampToDuration(OVERSHOOT_1_7, 0, firstPart, introDuration));
|
||||
FloatProp mDeltaY = new FloatProp(0, transY,
|
||||
clampToDuration(FAST_OUT_SLOW_IN, firstPart, secondPart, introDuration));
|
||||
FloatProp mGradientAlpha = new FloatProp(0, 255,
|
||||
clampToDuration(LINEAR, firstPart, secondPart * 0.3f, introDuration));
|
||||
|
||||
@Override
|
||||
public void onUpdate(float progress, boolean initOnly) {
|
||||
|
||||
@@ -328,20 +328,20 @@ public class FloatingTaskView extends FrameLayout {
|
||||
|
||||
MultiValueUpdateListener listener = new MultiValueUpdateListener() {
|
||||
// SplitPlaceholderView: rectangle translates and stretches to new position
|
||||
final FloatProp mDx = new FloatProp(0, prop.dX, 0, animDuration,
|
||||
final FloatProp mDx = new FloatProp(0, prop.dX,
|
||||
clampToProgress(timings.getStagedRectXInterpolator(),
|
||||
timings.getStagedRectSlideStartOffset(),
|
||||
timings.getStagedRectSlideEndOffset()));
|
||||
final FloatProp mDy = new FloatProp(0, prop.dY, 0, animDuration,
|
||||
final FloatProp mDy = new FloatProp(0, prop.dY,
|
||||
clampToProgress(timings.getStagedRectYInterpolator(),
|
||||
timings.getStagedRectSlideStartOffset(),
|
||||
timings.getStagedRectSlideEndOffset()));
|
||||
final FloatProp mTaskViewScaleX = new FloatProp(1f, prop.finalTaskViewScaleX, 0,
|
||||
animDuration, clampToProgress(timings.getStagedRectScaleXInterpolator(),
|
||||
final FloatProp mTaskViewScaleX = new FloatProp(1f, prop.finalTaskViewScaleX,
|
||||
clampToProgress(timings.getStagedRectScaleXInterpolator(),
|
||||
timings.getStagedRectSlideStartOffset(),
|
||||
timings.getStagedRectSlideEndOffset()));
|
||||
final FloatProp mTaskViewScaleY = new FloatProp(1f, prop.finalTaskViewScaleY, 0,
|
||||
animDuration, clampToProgress(timings.getStagedRectScaleYInterpolator(),
|
||||
final FloatProp mTaskViewScaleY = new FloatProp(1f, prop.finalTaskViewScaleY,
|
||||
clampToProgress(timings.getStagedRectScaleYInterpolator(),
|
||||
timings.getStagedRectSlideStartOffset(),
|
||||
timings.getStagedRectSlideEndOffset()));
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user