Merge "Add logging for adding pending icons to the workspace." into sc-dev
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 009ca27..827eb7d 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -693,7 +693,7 @@
matrix.postTranslate(windowTransX0, windowTransY0);
}
- floatingView.update(floatingIconBounds, mIconAlpha.value, percent, 0f,
+ floatingView.update(mIconAlpha.value, 255, floatingIconBounds, percent, 0f,
mWindowRadius.value * scale, true /* isOpening */);
builder.withMatrix(matrix)
.withWindowCrop(crop)
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index dbb8272..1b59c49 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1252,7 +1252,7 @@
HomeAnimationFactory homeAnimationFactory) {
RectFSpringAnim anim =
super.createWindowAnimationToHome(startProgress, homeAnimationFactory);
- anim.addOnUpdateListener((r, p) -> {
+ anim.addOnUpdateListener((v, r, p) -> {
updateSysUiFlags(Math.max(p, mCurrentShift.value));
});
anim.addAnimatorListener(new AnimationSuccessListener() {
@@ -1395,7 +1395,9 @@
mActivityInterface.onTransitionCancelled(wasVisible);
// Leave the pending invisible flag, as it may be used by wallpaper open animation.
- mActivity.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER);
+ if (mActivity != null) {
+ mActivity.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER);
+ }
}
protected void switchToScreenshot() {
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index ec1cc4a..f5698f7 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -48,6 +48,7 @@
import android.view.SurfaceControl.Transaction;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
@@ -56,6 +57,7 @@
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsState;
+import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
@@ -298,7 +300,8 @@
}
@Override
- public void update(RectF currentRect, float progress, float radius) {
+ public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
+ float radius) {
if (mSurfaceControl != null) {
currentRect.roundOut(mTempRect);
Transaction t = new Transaction();
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 311ac83..5ecd385 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -15,26 +15,45 @@
*/
package com.android.quickstep;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.Utilities.dpToPx;
+import static com.android.launcher3.Utilities.mapToRange;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
+import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.RectF;
import android.os.UserHandle;
import android.view.View;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.R;
+import com.android.launcher3.Workspace;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.SpringAnimationBuilder;
+import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.util.DynamicResource;
import com.android.launcher3.views.FloatingIconView;
+import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
+import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.system.InputConsumerController;
/**
@@ -66,24 +85,41 @@
} else {
workspaceView = null;
}
- final RectF iconLocation = new RectF();
boolean canUseWorkspaceView =
workspaceView != null && workspaceView.isAttachedToWindow();
- FloatingIconView floatingIconView = canUseWorkspaceView
- ? FloatingIconView.getFloatingIconView(mActivity, workspaceView,
- true /* hideOriginal */, iconLocation, false /* isOpening */)
- : null;
mActivity.getRootView().setForceHideBackArrow(true);
mActivity.setHintUserWillBeActive();
if (canUseWorkspaceView) {
+ final ResourceProvider rp = DynamicResource.provider(mActivity);
+ final float transY = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp));
+ float dpPerSecond = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp_per_s));
+ final float launcherAlphaMax =
+ rp.getFloat(R.dimen.swipe_up_launcher_alpha_max_progress);
+
+ RectF iconLocation = new RectF();
+ FloatingIconView floatingIconView = getFloatingIconView(mActivity, workspaceView,
+ true /* hideOriginal */, iconLocation, false /* isOpening */);
+
// We want the window alpha to be 0 once this threshold is met, so that the
// FolderIconView can be seen morphing into the icon shape.
float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION;
homeAnimFactory = new LauncherHomeAnimationFactory() {
+
+ // There is a delay in loading the icon, so we need to keep the window
+ // opaque until it is ready.
+ private boolean mIsFloatingIconReady = false;
+
+ private @Nullable ValueAnimator mBounceBackAnimator;
+
@Override
public RectF getWindowTargetRect() {
+ if (PROTOTYPE_APP_CLOSE.get()) {
+ // We want the target rect to be at this offset position, so that all
+ // launcher content can spring back upwards.
+ floatingIconView.setPositionOffsetY(transY);
+ }
return iconLocation;
}
@@ -92,17 +128,92 @@
anim.addAnimatorListener(floatingIconView);
floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged);
floatingIconView.setFastFinishRunnable(anim::end);
+ if (PROTOTYPE_APP_CLOSE.get()) {
+ mBounceBackAnimator = bounceBackToRestingPosition();
+ // Use a spring to put drag layer translation back to 0.
+ anim.addAnimatorListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ floatingIconView.setPositionOffsetY(0);
+ mBounceBackAnimator.start();
+ }
+ });
+
+ Workspace workspace = mActivity.getWorkspace();
+ workspace.setPivotToScaleWithSelf(mActivity.getHotseat());
+ }
+ }
+
+ private ValueAnimator bounceBackToRestingPosition() {
+ DragLayer dl = mActivity.getDragLayer();
+ Workspace workspace = mActivity.getWorkspace();
+ Hotseat hotseat = mActivity.getHotseat();
+
+ final float startValue = transY;
+ final float endValue = 0;
+ // Ensures the velocity is always aligned with the direction.
+ float pixelPerSecond = Math.abs(dpPerSecond)
+ * Math.signum(endValue - transY);
+
+ ValueAnimator springTransY = new SpringAnimationBuilder(dl.getContext())
+ .setStiffness(rp.getFloat(R.dimen.swipe_up_trans_y_stiffness))
+ .setDampingRatio(rp.getFloat(R.dimen.swipe_up_trans_y_damping))
+ .setMinimumVisibleChange(1f)
+ .setStartValue(startValue)
+ .setEndValue(endValue)
+ .setStartVelocity(pixelPerSecond)
+ .build(dl, VIEW_TRANSLATE_Y);
+ springTransY.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ dl.setTranslationY(0f);
+ dl.setAlpha(1f);
+ SCALE_PROPERTY.set(workspace, 1f);
+ SCALE_PROPERTY.set(hotseat, 1f);
+ }
+ });
+ return springTransY;
}
@Override
- public void update(RectF currentRect, float progress, float radius) {
- floatingIconView.update(currentRect, 1f, progress, windowAlphaThreshold,
- radius, false);
+ public boolean keepWindowOpaque() {
+ if (mIsFloatingIconReady || floatingIconView.isVisibleToUser()) {
+ mIsFloatingIconReady = true;
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void update(@Nullable AppCloseConfig config, RectF currentRect,
+ float progress, float radius) {
+ int fgAlpha = 255;
+ if (config != null && PROTOTYPE_APP_CLOSE.get()) {
+ DragLayer dl = mActivity.getDragLayer();
+ float translationY = config.getWorkspaceTransY();
+ dl.setTranslationY(translationY);
+
+ float alpha = mapToRange(progress, 0, launcherAlphaMax, 0, 1f, LINEAR);
+ dl.setAlpha(Math.min(alpha, 1f));
+
+ float scale = Math.min(1f, config.getWorkspaceScale());
+ SCALE_PROPERTY.set(mActivity.getWorkspace(), scale);
+ SCALE_PROPERTY.set(mActivity.getHotseat(), scale);
+ SCALE_PROPERTY.set(mActivity.getAppsView(), scale);
+
+ progress = config.getInterpolatedProgress();
+ fgAlpha = config.getFgAlpha();
+ }
+ floatingIconView.update(1f, fgAlpha, currentRect, progress,
+ windowAlphaThreshold, radius, false);
}
@Override
public void onCancel() {
floatingIconView.fastFinish();
+ if (mBounceBackAnimator != null) {
+ mBounceBackAnimator.cancel();
+ }
}
};
} else {
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index a8c09dc..0f34a72 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -17,6 +17,7 @@
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE;
import android.animation.Animator;
import android.content.Context;
@@ -26,6 +27,7 @@
import android.graphics.RectF;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.android.launcher3.DeviceProfile;
@@ -35,7 +37,9 @@
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.util.AnimatorControllerWithResistance;
+import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.RectFSpringAnim2;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
@@ -149,7 +153,10 @@
public void setAnimation(RectFSpringAnim anim) { }
- public void update(RectF currentRect, float progress, float radius) { }
+ public boolean keepWindowOpaque() { return false; }
+
+ public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
+ float radius) { }
public void onCancel() { }
@@ -199,7 +206,14 @@
homeToWindowPositionMap.invert(windowToHomePositionMap);
windowToHomePositionMap.mapRect(startRect);
- RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext);
+ RectFSpringAnim anim;
+ if (PROTOTYPE_APP_CLOSE.get()) {
+ anim = new RectFSpringAnim2(startRect, targetRect, mContext,
+ mTaskViewSimulator.getCurrentCornerRadius(),
+ cropRectF.width() / 2f);
+ } else {
+ anim = new RectFSpringAnim(startRect, targetRect, mContext);
+ }
homeAnimationFactory.setAnimation(anim);
SpringAnimationRunner runner = new SpringAnimationRunner(
@@ -259,18 +273,26 @@
}
@Override
- public void onUpdate(RectF currentRect, float progress) {
+ public void onUpdate(@Nullable AppCloseConfig config, RectF currentRect, float progress) {
mHomeAnim.setPlayFraction(progress);
mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect);
mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
+ float alpha = getWindowAlpha(progress);
+ if (config != null && PROTOTYPE_APP_CLOSE.get()) {
+ alpha = config.getWindowAlpha();
+ cornerRadius = config.getCornerRadius();
+ }
+ if (mAnimationFactory.keepWindowOpaque()) {
+ alpha = 1f;
+ }
mTransformParams
- .setTargetAlpha(getWindowAlpha(progress))
+ .setTargetAlpha(alpha)
.setCornerRadius(cornerRadius);
-
mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this));
- mAnimationFactory.update(currentRect, progress, mMatrix.mapRadius(cornerRadius));
+ mAnimationFactory.update(config, currentRect, progress,
+ mMatrix.mapRadius(cornerRadius));
}
@Override
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 8fc453d..1aa64fa 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -52,6 +52,7 @@
import com.android.quickstep.RecentsAnimationDeviceState;
import com.android.quickstep.SwipeUpAnimationLogic;
import com.android.quickstep.SwipeUpAnimationLogic.RunningWindowAnim;
+import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TransformParams;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
@@ -306,11 +307,12 @@
}
@Override
- public void update(RectF rect, float progress, float radius) {
+ public void update(@Nullable AppCloseConfig config, RectF rect, float progress,
+ float radius) {
mFakeIconView.setVisibility(View.VISIBLE);
mFakeIconView.update(rect, progress,
1f - SHAPE_PROGRESS_DURATION /* shapeProgressStart */,
- radius,
+ radius, 255,
false, /* isOpening */
mFakeIconView, mDp,
false /* isVerticalBarLayout */);
diff --git a/quickstep/src/com/android/quickstep/util/AppCloseConfig.java b/quickstep/src/com/android/quickstep/util/AppCloseConfig.java
new file mode 100644
index 0000000..bec3379
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/AppCloseConfig.java
@@ -0,0 +1,57 @@
+/*
+ * 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();
+
+}
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
index e5d2c53..02ec68a 100644
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -20,6 +20,7 @@
import android.graphics.PointF;
import android.graphics.RectF;
+import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
@@ -241,7 +242,7 @@
mCurrentCenterX + currentWidth / 2, mCurrentY + currentHeight);
}
for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
- onUpdateListener.onUpdate(mCurrentRect, mCurrentScaleProgress);
+ onUpdateListener.onUpdate(null, mCurrentRect, mCurrentScaleProgress);
}
}
}
@@ -266,7 +267,7 @@
}
public interface OnUpdateListener {
- void onUpdate(RectF currentRect, float progress);
+ void onUpdate(@Nullable AppCloseConfig values, RectF currentRect, float progress);
default void onCancel() { }
}
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java
new file mode 100644
index 0000000..95d56aa
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java
@@ -0,0 +1,390 @@
+/*
+ * 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 static com.android.launcher3.Utilities.dpToPx;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.util.PathParser;
+import android.util.Property;
+import android.view.animation.Interpolator;
+
+import androidx.core.view.animation.PathInterpolatorCompat;
+import androidx.dynamicanimation.animation.FloatPropertyCompat;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.DynamicResource;
+import com.android.systemui.plugins.ResourceProvider;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Applies spring forces to animate from a starting rect to a target rect,
+ * while providing update callbacks to the caller.
+ */
+public class RectFSpringAnim2 extends RectFSpringAnim {
+
+ private static final FloatPropertyCompat<RectFSpringAnim2> RECT_CENTER_X =
+ new FloatPropertyCompat<RectFSpringAnim2>("rectCenterXSpring") {
+ @Override
+ public float getValue(RectFSpringAnim2 anim) {
+ return anim.mCurrentCenterX;
+ }
+
+ @Override
+ public void setValue(RectFSpringAnim2 anim, float currentCenterX) {
+ anim.mCurrentCenterX = currentCenterX;
+ anim.onUpdate();
+ }
+ };
+
+ private static final FloatPropertyCompat<RectFSpringAnim2> RECT_Y =
+ new FloatPropertyCompat<RectFSpringAnim2>("rectYSpring") {
+ @Override
+ public float getValue(RectFSpringAnim2 anim) {
+ return anim.mCurrentY;
+ }
+
+ @Override
+ public void setValue(RectFSpringAnim2 anim, float y) {
+ anim.mCurrentY = y;
+ anim.onUpdate();
+ }
+ };
+
+ private static final Property<RectFSpringAnim2, Float> PROGRESS =
+ new Property<RectFSpringAnim2, Float>(Float.class, "rectFProgress") {
+ @Override
+ public Float get(RectFSpringAnim2 rectFSpringAnim) {
+ return rectFSpringAnim.mProgress;
+ }
+
+ @Override
+ public void set(RectFSpringAnim2 rectFSpringAnim, Float progress) {
+ rectFSpringAnim.mProgress = progress;
+ rectFSpringAnim.onUpdate();
+ }
+ };
+
+ private final RectF mStartRect;
+ private final RectF mTargetRect;
+ private final RectF mCurrentRect = new RectF();
+ private final List<OnUpdateListener> mOnUpdateListeners = new ArrayList<>();
+ private final List<Animator.AnimatorListener> mAnimatorListeners = new ArrayList<>();
+
+ private float mCurrentCenterX;
+ private float mCurrentY;
+
+ private float mTargetX;
+ private float mTargetY;
+
+ // If true, tracking the bottom of the rects, else tracking the top.
+ private final boolean mTrackingBottomY;
+ private float mProgress;
+ private SpringAnimation mRectXAnim;
+ private SpringAnimation mRectYAnim;
+ private ValueAnimator mRectScaleAnim;
+ private boolean mAnimsStarted;
+ private boolean mRectXAnimEnded;
+ private boolean mRectYAnimEnded;
+ private boolean mRectScaleAnimEnded;
+
+ private final float mXDamping;
+ private final float mXStiffness;
+
+ private final float mYDamping;
+ private float mYStiffness;
+
+ private long mDuration;
+
+ private final Interpolator mCloseInterpolator;
+
+ private AppCloseConfig mValues;
+ final float mStartRadius;
+ final float mEndRadius;
+
+ final float mHomeTransYEnd;
+ final float mScaleStart;
+
+ public RectFSpringAnim2(RectF startRect, RectF targetRect, Context context, float startRadius,
+ float endRadius) {
+ super(startRect, targetRect, context);
+ mStartRect = startRect;
+ mTargetRect = targetRect;
+
+ mTrackingBottomY = startRect.bottom < targetRect.bottom;
+ mCurrentY = mTrackingBottomY ? mStartRect.bottom : mStartRect.top;
+ mCurrentCenterX = mStartRect.centerX();
+
+ mTargetY = mTrackingBottomY ? mTargetRect.bottom : mTargetRect.top;
+ mTargetX = mTargetRect.centerX();
+
+ ResourceProvider rp = DynamicResource.provider(context);
+ mXDamping = rp.getFloat(R.dimen.swipe_up_rect_2_x_damping_ratio);
+ mXStiffness = rp.getFloat(R.dimen.swipe_up_rect_2_x_stiffness);
+
+ mYDamping = rp.getFloat(R.dimen.swipe_up_rect_2_y_damping_ratio);
+ mYStiffness = rp.getFloat(R.dimen.swipe_up_rect_2_y_stiffness);
+ mDuration = Math.round(rp.getFloat(R.dimen.swipe_up_duration));
+
+ mHomeTransYEnd = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp));
+ mScaleStart = rp.getFloat(R.dimen.swipe_up_scale_start);
+
+
+ if (!mTrackingBottomY) {
+ mYStiffness *= rp.getFloat(R.dimen.swipe_up_rect_2_y_stiffness_low_swipe_multiplier);
+ mDuration *= rp.getFloat(R.dimen.swipe_up_low_swipe_duration_multiplier);
+ }
+
+ mCloseInterpolator = getAppCloseInterpolator(context);
+
+ // End on a "round-enough" radius so that the shape reveal doesn't have to do too much
+ // rounding at the end of the animation.
+ mStartRadius = startRadius;
+ mEndRadius = endRadius;
+
+ setCanRelease(true);
+ }
+
+ public void onTargetPositionChanged() {
+ if (mRectXAnim != null && mTargetX != mTargetRect.centerX()) {
+ mTargetX = mTargetRect.centerX();
+ mRectXAnim.animateToFinalPosition(mTargetX);
+ }
+
+ if (mRectYAnim != null) {
+ if (mTrackingBottomY && mTargetY != mTargetRect.bottom) {
+ mTargetY = mTargetRect.bottom;
+ mRectYAnim.animateToFinalPosition(mTargetY);
+ } else if (!mTrackingBottomY && mTargetY != mTargetRect.top) {
+ mTargetY = mTargetRect.top;
+ mRectYAnim.animateToFinalPosition(mTargetY);
+ }
+ }
+ }
+
+ public void addOnUpdateListener(OnUpdateListener onUpdateListener) {
+ mOnUpdateListeners.add(onUpdateListener);
+ }
+
+ public void addAnimatorListener(Animator.AnimatorListener animatorListener) {
+ mAnimatorListeners.add(animatorListener);
+ }
+
+ /**
+ * Starts the fling/spring animation.
+ * @param context The activity context.
+ * @param velocityPxPerMs Velocity of swipe in px/ms.
+ */
+ public void start(Context context, PointF velocityPxPerMs) {
+ DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(context).getDeviceProfile(context);
+
+ mRectXAnim = new SpringAnimation(this, RECT_CENTER_X)
+ .setStartValue(mCurrentCenterX)
+ .setMinValue(Math.min(0, mCurrentCenterX))
+ .setMaxValue(Math.max(dp.widthPx, mCurrentCenterX))
+ .setStartVelocity(velocityPxPerMs.x * 1000)
+ .setSpring(new SpringForce(mTargetX)
+ .setStiffness(mXStiffness)
+ .setDampingRatio(mXDamping));
+ mRectXAnim.addEndListener(((animation, canceled, centerX, velocityX) -> {
+ mRectXAnimEnded = true;
+ maybeOnEnd();
+ }));
+
+ mRectYAnim = new SpringAnimation(this, RECT_Y)
+ .setStartValue(mCurrentY)
+ .setMinValue(Math.min(0, mCurrentY))
+ .setMaxValue(Math.max(dp.heightPx, mCurrentY))
+ .setStartVelocity(velocityPxPerMs.y * 1000)
+ .setSpring(new SpringForce(mTargetY)
+ .setStiffness(mYStiffness)
+ .setDampingRatio(mYDamping));
+ mRectYAnim.addEndListener(((animation, canceled, centerY, velocityY) -> {
+ mRectYAnimEnded = true;
+ maybeOnEnd();
+ }));
+
+ mRectScaleAnim = ObjectAnimator.ofFloat(this, PROGRESS, 0, 1f)
+ .setDuration(mDuration);
+ mRectScaleAnim.setInterpolator(mCloseInterpolator);
+ mRectScaleAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mRectScaleAnimEnded = true;
+ maybeOnEnd();
+ }
+ });
+
+ mValues = buildConfig();
+ mRectScaleAnim.addUpdateListener(mValues);
+
+ setCanRelease(false);
+ mAnimsStarted = true;
+
+ mRectXAnim.start();
+ mRectYAnim.start();
+ mRectScaleAnim.start();
+ for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
+ animatorListener.onAnimationStart(null);
+ }
+ }
+
+ private AppCloseConfig buildConfig() {
+ return new AppCloseConfig() {
+ FloatProp mHomeTransY = new FloatProp(0, mHomeTransYEnd, 0, mDuration, LINEAR);
+ FloatProp mHomeScale = new FloatProp(mScaleStart, 1f, 0, mDuration, LINEAR);
+ FloatProp mWindowFadeOut = new FloatProp(1f, 0f, 0, 116, LINEAR);
+ // There should be a slight overlap b/w window fading out and fg fading in.
+ // (fg startDelay < window fade out duration)
+ FloatProp mFgFadeIn = new FloatProp(0, 255f, 100, mDuration - 100, LINEAR);
+ FloatProp mRadius = new FloatProp(mStartRadius, mEndRadius, 0, mDuration, LINEAR);
+ FloatProp mThreePointInterpolation = new FloatProp(0, 1, 0, mDuration, LINEAR);
+
+ @Override
+ public float getWorkspaceTransY() {
+ return mHomeTransY.value;
+ }
+
+ @Override
+ public float getWorkspaceScale() {
+ return mHomeScale.value;
+ }
+
+ @Override
+ public float getWindowAlpha() {
+ return mWindowFadeOut.value;
+ }
+
+ @Override
+ public int getFgAlpha() {
+ return (int) mFgFadeIn.value;
+ }
+
+ @Override
+ public float getCornerRadius() {
+ return mRadius.value;
+ }
+
+ @Override
+ public float getInterpolatedProgress() {
+ return mThreePointInterpolation.value;
+ }
+
+ @Override
+ public void onUpdate(float percent) {}
+ };
+ }
+
+ public void end() {
+ if (mAnimsStarted) {
+ if (mRectXAnim.canSkipToEnd()) {
+ mRectXAnim.skipToEnd();
+ }
+ if (mRectYAnim.canSkipToEnd()) {
+ mRectYAnim.skipToEnd();
+ }
+ mRectScaleAnim.end();
+ }
+ mRectXAnimEnded = true;
+ mRectYAnimEnded = true;
+ mRectScaleAnimEnded = true;
+ maybeOnEnd();
+ }
+
+ private boolean isEnded() {
+ return mRectXAnimEnded && mRectYAnimEnded && mRectScaleAnimEnded;
+ }
+
+ private void onUpdate() {
+ if (isEnded()) {
+ // Prevent further updates from being called. This can happen between callbacks for
+ // ending the x/y/scale animations.
+ return;
+ }
+
+ if (!mOnUpdateListeners.isEmpty()) {
+ float rectProgress = mProgress;
+ float currentWidth = Utilities.mapRange(rectProgress, mStartRect.width(),
+ mTargetRect.width());
+ float currentHeight = Utilities.mapRange(rectProgress, mStartRect.height(),
+ mTargetRect.height());
+ if (mTrackingBottomY) {
+ mCurrentRect.set(mCurrentCenterX - currentWidth / 2, mCurrentY - currentHeight,
+ mCurrentCenterX + currentWidth / 2, mCurrentY);
+ } else {
+ mCurrentRect.set(mCurrentCenterX - currentWidth / 2, mCurrentY,
+ mCurrentCenterX + currentWidth / 2, mCurrentY + currentHeight);
+ }
+
+ float currentPlayTime = mRectScaleAnimEnded ? mRectScaleAnim.getDuration()
+ : mRectScaleAnim.getCurrentPlayTime();
+ float linearProgress = Math.min(1f, currentPlayTime / mRectScaleAnim.getDuration());
+ for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
+ onUpdateListener.onUpdate(mValues, mCurrentRect, linearProgress);
+ }
+ }
+ }
+
+ private void maybeOnEnd() {
+ if (mAnimsStarted && isEnded()) {
+ mAnimsStarted = false;
+ setCanRelease(true);
+ for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
+ animatorListener.onAnimationEnd(null);
+ }
+ }
+ }
+
+ public void cancel() {
+ if (mAnimsStarted) {
+ for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
+ onUpdateListener.onCancel();
+ }
+ }
+ end();
+ }
+
+ private Interpolator getAppCloseInterpolator(Context context) {
+ ResourceProvider rp = DynamicResource.provider(context);
+ String path = String.format("M 0,0 C %f, %f, %f, %f, %f, %f C %f, %f, %f, %f, 1, 1",
+ rp.getFloat(R.dimen.c1_a),
+ rp.getFloat(R.dimen.c1_b),
+ rp.getFloat(R.dimen.c1_c),
+ rp.getFloat(R.dimen.c1_d),
+ rp.getFloat(R.dimen.mp_x),
+ rp.getFloat(R.dimen.mp_y),
+ rp.getFloat(R.dimen.c2_a),
+ rp.getFloat(R.dimen.c2_b),
+ rp.getFloat(R.dimen.c2_c),
+ rp.getFloat(R.dimen.c2_d));
+ return PathInterpolatorCompat.create(PathParser.createPathFromPathData(path));
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 1df459e..de6c4f5 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
+import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM;
@@ -220,6 +221,9 @@
* @param totalRows Total number of rows.
*/
private void addStaggeredAnimationForView(View v, int row, int totalRows) {
+ if (PROTOTYPE_APP_CLOSE.get()) {
+ return;
+ }
// Invert the rows, because we stagger starting from the bottom of the screen.
int invertedRow = totalRows - row;
// Add 1 to the inverted row so that the bottom most row has a start delay.
diff --git a/res/values/config.xml b/res/values/config.xml
index db98811..b75af7f 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -134,8 +134,45 @@
<item name="swipe_up_rect_scale_stiffness" type="dimen" format="float">200</item>
<item name="swipe_up_rect_xy_fling_friction" type="dimen" format="float">1.5</item>
+
+ <item name="swipe_up_scale_start" type="dimen" format="float">0.98</item>
+ <item name="swipe_up_duration" type="dimen" format="float">500</item>
+
+ <item name="swipe_up_trans_y_dp" type="dimen" format="float">3</item>
+ <item name="swipe_up_trans_y_dp_per_s" type="dimen" format="float">3</item>
+
+ <item name="swipe_up_trans_y_damping" type="dimen" format="float">0.4</item>
+ <item name="swipe_up_trans_y_stiffness" type="dimen" format="float">200</item>
+
<item name="swipe_up_rect_xy_damping_ratio" type="dimen" format="float">0.8</item>
- <item name="swipe_up_rect_xy_stiffness" type="dimen" format="float">200</item>
+ <item name="swipe_up_rect_xy_stiffness" type="dimen" format="float">100</item>
+
+
+ <item name="swipe_up_rect_2_x_damping_ratio" type="dimen" format="float">1</item>
+ <item name="swipe_up_rect_2_x_stiffness" type="dimen" format="float">350</item>
+
+ <item name="swipe_up_rect_2_y_damping_ratio" type="dimen" format="float">1</item>
+ <item name="swipe_up_rect_2_y_stiffness" type="dimen" format="float">700</item>
+
+ <item name="swipe_up_rect_2_y_stiffness_low_swipe_multiplier" type="dimen" format="float">1</item>
+ <item name="swipe_up_low_swipe_duration_multiplier" type="dimen" format="float">1</item>
+
+ <item name="swipe_up_launcher_alpha_max_progress" type="dimen" format="float">0.85</item>
+
+
+ <item name="c1_a" type="dimen" format="float">0.05</item>
+ <item name="c1_b" type="dimen" format="float">0</item>
+ <item name="c1_c" type="dimen" format="float">0.133333</item>
+ <item name="c1_d" type="dimen" format="float">0.06</item>
+
+ <item name="mp_x" type="dimen" format="float">0.166666</item>
+ <item name="mp_y" type="dimen" format="float">.4</item>
+
+ <item name="c2_a" type="dimen" format="float">0.208333</item>
+ <item name="c2_b" type="dimen" format="float">.82</item>
+ <item name="c2_c" type="dimen" format="float">.25</item>
+ <item name="c2_d" type="dimen" format="float">1</item>
+
<item name="staggered_damping_ratio" type="dimen" format="float">0.7</item>
<item name="staggered_stiffness" type="dimen" format="float">150</item>
@@ -151,35 +188,32 @@
<dimen name="swipe_up_max_workspace_trans_y">-60dp</dimen>
<array name="dynamic_resources">
- <item>@dimen/all_apps_spring_damping_ratio</item>
- <item>@dimen/all_apps_spring_stiffness</item>
+ <item>@dimen/swipe_up_duration</item>
+ <item>@dimen/swipe_up_scale_start</item>
+ <item>@dimen/swipe_up_trans_y_dp</item>
+ <item>@dimen/swipe_up_trans_y_dp_per_s</item>
+ <item>@dimen/swipe_up_trans_y_damping</item>
+ <item>@dimen/swipe_up_trans_y_stiffness</item>
+ <item>@dimen/swipe_up_rect_2_x_damping_ratio</item>
+ <item>@dimen/swipe_up_rect_2_x_stiffness</item>
+ <item>@dimen/swipe_up_rect_2_y_damping_ratio</item>
+ <item>@dimen/swipe_up_rect_2_y_stiffness</item>
+ <item>@dimen/swipe_up_launcher_alpha_max_progress</item>
+ <item>@dimen/swipe_up_rect_2_y_stiffness_low_swipe_multiplier</item>
+ <item>@dimen/swipe_up_low_swipe_duration_multiplier</item>
- <item>@dimen/dismiss_task_trans_y_damping_ratio</item>
- <item>@dimen/dismiss_task_trans_y_stiffness</item>
+ <item>@dimen/c1_a</item>
+ <item>@dimen/c1_b</item>
+ <item>@dimen/c1_c</item>
+ <item>@dimen/c1_d</item>
- <item>@dimen/dismiss_task_trans_x_damping_ratio</item>
- <item>@dimen/dismiss_task_trans_x_stiffness</item>
+ <item>@dimen/mp_x</item>
+ <item>@dimen/mp_y</item>
- <item>@dimen/horizontal_spring_damping_ratio</item>
- <item>@dimen/horizontal_spring_stiffness</item>
-
- <item>@dimen/swipe_up_rect_scale_damping_ratio</item>
- <item>@dimen/swipe_up_rect_scale_stiffness</item>
-
- <item>@dimen/swipe_up_rect_xy_fling_friction</item>
- <item>@dimen/swipe_up_rect_xy_damping_ratio</item>
- <item>@dimen/swipe_up_rect_xy_stiffness</item>
-
- <item>@dimen/staggered_damping_ratio</item>
- <item>@dimen/staggered_stiffness</item>
- <item>@dimen/unlock_staggered_velocity_dp_per_s</item>
-
- <item>@dimen/swipe_up_fling_min_visible_change</item>
- <item>@dimen/swipe_up_y_overshoot</item>
-
- <item>@dimen/hint_scale_damping_ratio</item>
- <item>@dimen/hint_scale_stiffness</item>
- <item>@dimen/hint_scale_velocity_dp_per_s</item>
+ <item>@dimen/c2_a</item>
+ <item>@dimen/c2_b</item>
+ <item>@dimen/c2_c</item>
+ <item>@dimen/c2_d</item>
</array>
<string-array name="live_wallpapers_remove_sysui_scrims">
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 10091a1..5d941a7 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -3323,6 +3323,18 @@
}
}
+ /**
+ * Set the given view's pivot point to match the workspace's, so that it scales together. Since
+ * both this view and workspace can move, transform the point manually instead of using
+ * dragLayer.getDescendantCoordRelativeToSelf and related methods.
+ */
+ public void setPivotToScaleWithSelf(View sibling) {
+ sibling.setPivotY(getPivotY() + getTop()
+ - sibling.getTop() - sibling.getTranslationY());
+ sibling.setPivotX(getPivotX() + getLeft()
+ - sibling.getLeft() - sibling.getTranslationX());
+ }
+
@Override
public int getExpectedHeight() {
return getMeasuredHeight() <= 0 || !mIsLayoutValid
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index f4986f4..ed854dc 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -119,7 +119,7 @@
propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
}
- setPivotToScaleWithWorkspace(hotseat);
+ mWorkspace.setPivotToScaleWithSelf(hotseat);
float hotseatScale = hotseatScaleAndTranslation.scale;
if (shouldSpring) {
PendingAnimation pa = (PendingAnimation) propertySetter;
@@ -156,18 +156,6 @@
}
}
- /**
- * Set the given view's pivot point to match the workspace's, so that it scales together. Since
- * both this view and workspace can move, transform the point manually instead of using
- * dragLayer.getDescendantCoordRelativeToSelf and related methods.
- */
- private void setPivotToScaleWithWorkspace(View sibling) {
- sibling.setPivotY(mWorkspace.getPivotY() + mWorkspace.getTop()
- - sibling.getTop() - sibling.getTranslationY());
- sibling.setPivotX(mWorkspace.getPivotX() + mWorkspace.getLeft()
- - sibling.getLeft() - sibling.getTranslationX());
- }
-
public void setScrim(PropertySetter propertySetter, LauncherState state,
StateAnimationConfig config) {
Scrim workspaceDragScrim = mLauncher.getDragLayer().getWorkspaceDragScrim();
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 7a38937..11e831e 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -27,7 +27,6 @@
import com.android.launcher3.Utilities;
-
/**
* Common interpolators used in Launcher
*/
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 44e3138..272dfc2 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -233,6 +233,9 @@
public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag("NOTIFY_CRASHES", false,
"Sends a notification whenever launcher encounters an uncaught exception.");
+ public static final BooleanFlag PROTOTYPE_APP_CLOSE = getDebugFlag(
+ "PROTOTYPE_APP_CLOSE", false, "Enables new app close");
+
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/views/ClipIconView.java b/src/com/android/launcher3/views/ClipIconView.java
index 4e82336..a66b3f9 100644
--- a/src/com/android/launcher3/views/ClipIconView.java
+++ b/src/com/android/launcher3/views/ClipIconView.java
@@ -15,10 +15,13 @@
*/
package com.android.launcher3.views;
+import static com.android.launcher3.Utilities.boundToRange;
import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
+import static java.lang.Math.max;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -143,10 +146,9 @@
/**
* Update the icon UI to match the provided parameters during an animation frame
*/
- public void update(RectF rect, float progress, float shapeProgressStart,
- float cornerRadius, boolean isOpening, View container,
- DeviceProfile dp, boolean isVerticalBarLayout) {
-
+ public void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
+ int fgIconAlpha, boolean isOpening, View container, DeviceProfile dp,
+ boolean isVerticalBarLayout) {
MarginLayoutParams lp = (MarginLayoutParams) container.getLayoutParams();
float dX = mIsRtl
@@ -166,7 +168,7 @@
return;
}
- update(rect, progress, shapeProgressStart, cornerRadius, isOpening, scale,
+ update(rect, progress, shapeProgressStart, cornerRadius, fgIconAlpha, isOpening, scale,
minSize, lp, isVerticalBarLayout, dp);
container.setPivotX(0);
@@ -178,8 +180,8 @@
}
private void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
- boolean isOpening, float scale, float minSize, MarginLayoutParams parentLp,
- boolean isVerticalBarLayout, DeviceProfile dp) {
+ int fgIconAlpha, boolean isOpening, float scale, float minSize,
+ MarginLayoutParams parentLp, boolean isVerticalBarLayout, DeviceProfile dp) {
float dX = mIsRtl
? rect.left - (dp.widthPx - parentLp.getMarginStart() - parentLp.width)
: rect.left - parentLp.getMarginStart();
@@ -187,9 +189,9 @@
// shapeRevealProgress = 1 when progress = shapeProgressStart + SHAPE_PROGRESS_DURATION
float toMax = isOpening ? 1 / SHAPE_PROGRESS_DURATION : 1f;
- float shapeRevealProgress = Utilities.boundToRange(mapToRange(
- Math.max(shapeProgressStart, progress), shapeProgressStart, 1f, 0, toMax,
- LINEAR), 0, 1);
+
+ float shapeRevealProgress = boundToRange(mapToRange(max(shapeProgressStart, progress),
+ shapeProgressStart, 1f, 0, toMax, LINEAR), 0, 1);
if (isVerticalBarLayout) {
mOutline.right = (int) (rect.width() / scale);
@@ -231,6 +233,8 @@
sTmpRect.offset(diffX, diffY);
mForeground.setBounds(sTmpRect);
} else {
+ mForeground.setAlpha(fgIconAlpha);
+
// Spring the foreground relative to the icon's movement within the DragLayer.
int diffX = (int) (dX / dp.availableWidthPx * FG_TRANS_X_FACTOR);
int diffY = (int) (dY / dp.availableHeightPx * FG_TRANS_Y_FACTOR);
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 96268ce..d49320b 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -100,6 +100,8 @@
private ListenerView mListenerView;
private Runnable mFastFinishRunnable;
+ private float mIconOffsetY;
+
public FloatingIconView(Context context) {
this(context, null);
}
@@ -136,16 +138,18 @@
/**
* Positions this view to match the size and location of {@param rect}.
- * @param alpha The alpha to set this view.
+ * @param alpha The alpha[0, 1] of the entire floating view.
+ * @param fgIconAlpha The alpha[0-255] of the foreground layer of the icon (if applicable).
* @param progress A value from [0, 1] that represents the animation progress.
* @param shapeProgressStart The progress value at which to start the shape reveal.
* @param cornerRadius The corner radius of {@param rect}.
+ * @param isOpening True if view is used for app open animation, false for app close animation.
*/
- public void update(RectF rect, float alpha, float progress, float shapeProgressStart,
- float cornerRadius, boolean isOpening) {
+ public void update(float alpha, int fgIconAlpha, RectF rect, float progress,
+ float shapeProgressStart, float cornerRadius, boolean isOpening) {
setAlpha(alpha);
- mClipIconView.update(rect, progress, shapeProgressStart, cornerRadius, isOpening,
- this, mLauncher.getDeviceProfile(), mIsVerticalBarLayout);
+ mClipIconView.update(rect, progress, shapeProgressStart, cornerRadius, fgIconAlpha,
+ isOpening, this, mLauncher.getDeviceProfile(), mIsVerticalBarLayout);
}
@Override
@@ -478,11 +482,19 @@
@Override
public void onAnimationRepeat(Animator animator) {}
+ /**
+ * Offsets and updates the position of this view by {@param y}.
+ */
+ public void setPositionOffsetY(float y) {
+ mIconOffsetY = y;
+ onGlobalLayout();
+ }
+
@Override
public void onGlobalLayout() {
- if (mOriginalIcon.isAttachedToWindow() && mPositionOut != null) {
- getLocationBoundsForView(mLauncher, mOriginalIcon, mIsOpening,
- sTmpRectF);
+ if (mOriginalIcon != null && mOriginalIcon.isAttachedToWindow() && mPositionOut != null) {
+ getLocationBoundsForView(mLauncher, mOriginalIcon, mIsOpening, sTmpRectF);
+ sTmpRectF.offset(0, mIconOffsetY);
if (!sTmpRectF.equals(mPositionOut)) {
updatePosition(sTmpRectF, (InsettableFrameLayout.LayoutParams) getLayoutParams());
if (mOnTargetChangeRunnable != null) {
@@ -617,6 +629,7 @@
mClipIconView.recycle();
mBtvDrawable.setBackground(null);
mFastFinishRunnable = null;
+ mIconOffsetY = 0;
}
private static class IconLoadResult {