Merge "Add staggered springs animation when swiping up to home." into ub-launcher3-qt-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ea068967ae
@@ -27,4 +27,5 @@
|
||||
<!-- Swipe up to home related -->
|
||||
<dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
|
||||
<dimen name="swipe_up_y_overshoot">10dp</dimen>
|
||||
<dimen name="swipe_up_max_workspace_trans_y">-80dp</dimen>
|
||||
</resources>
|
||||
+15
-1
@@ -57,6 +57,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.quickstep.util.StaggeredWorkspaceAnim;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
@@ -151,8 +152,21 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
@NonNull
|
||||
@Override
|
||||
public AnimatorPlaybackController createActivityAnimationToHome() {
|
||||
// Return an empty APC here since we have an non-user controlled animation to home.
|
||||
long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
|
||||
return activity.getStateManager().createAnimationToNewWorkspace(NORMAL, accuracy);
|
||||
AnimatorSet as = new AnimatorSet();
|
||||
as.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
activity.getStateManager().goToState(NORMAL, false);
|
||||
}
|
||||
});
|
||||
return AnimatorPlaybackController.wrap(as, accuracy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playAtomicAnimation(float velocity) {
|
||||
new StaggeredWorkspaceAnim(activity, workspaceView, velocity).start();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+1
@@ -1057,6 +1057,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
setStateOnUiThread(target.endState);
|
||||
}
|
||||
});
|
||||
homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
|
||||
windowAnim.start(velocityPxPerMs);
|
||||
mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
|
||||
mLauncherTransitionController = null;
|
||||
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.dynamicanimation.animation.SpringForce;
|
||||
|
||||
import com.android.launcher3.CellLayout;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAnimUtils.ViewProgressProperty;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ShortcutAndWidgetContainer;
|
||||
import com.android.launcher3.anim.SpringObjectAnimator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
|
||||
/**
|
||||
* Creates an animation where all the workspace items are moved into their final location,
|
||||
* staggered row by row from the bottom up.
|
||||
* This is used in conjunction with the swipe up to home animation.
|
||||
*/
|
||||
public class StaggeredWorkspaceAnim {
|
||||
|
||||
private static final int APP_CLOSE_ROW_START_DELAY_MS = 16;
|
||||
private static final int ALPHA_DURATION_MS = 200;
|
||||
|
||||
private static final float MAX_VELOCITY_PX_PER_S = 22f;
|
||||
|
||||
private static final float DAMPING_RATIO =
|
||||
(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY + SpringForce.DAMPING_RATIO_LOW_BOUNCY) / 2f;
|
||||
private static final float STIFFNESS = SpringForce.STIFFNESS_LOW;
|
||||
|
||||
private final float mVelocity;
|
||||
private final float mSpringTransY;
|
||||
private final View mViewToIgnore;
|
||||
|
||||
private final List<ValueAnimator> mAnimators = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* @param floatingViewOriginalView The FloatingIconView's original view.
|
||||
*/
|
||||
public StaggeredWorkspaceAnim(Launcher launcher, @Nullable View floatingViewOriginalView,
|
||||
float velocity) {
|
||||
mVelocity = velocity;
|
||||
// We ignore this view since it's visibility and position is controlled by
|
||||
// the FloatingIconView.
|
||||
mViewToIgnore = floatingViewOriginalView;
|
||||
|
||||
// Scale the translationY based on the initial velocity to better sync the workspace items
|
||||
// with the floating view.
|
||||
float transFactor = 0.1f + 0.9f * Math.abs(velocity) / MAX_VELOCITY_PX_PER_S;
|
||||
mSpringTransY = transFactor * launcher.getResources()
|
||||
.getDimensionPixelSize(R.dimen.swipe_up_max_workspace_trans_y);;
|
||||
|
||||
DeviceProfile grid = launcher.getDeviceProfile();
|
||||
ShortcutAndWidgetContainer currentPage = ((CellLayout) launcher.getWorkspace()
|
||||
.getChildAt(launcher.getWorkspace().getCurrentPage()))
|
||||
.getShortcutsAndWidgets();
|
||||
|
||||
// Hotseat and QSB takes up two additional rows.
|
||||
int totalRows = grid.inv.numRows + (grid.isVerticalBarLayout() ? 0 : 2);
|
||||
|
||||
// Set up springs on workspace items.
|
||||
for (int i = currentPage.getChildCount() - 1; i >= 0; i--) {
|
||||
View child = currentPage.getChildAt(i);
|
||||
CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
|
||||
addStaggeredAnimationForView(child, lp.cellY + lp.cellVSpan, totalRows);
|
||||
}
|
||||
|
||||
// Set up springs for the hotseat and qsb.
|
||||
if (grid.isVerticalBarLayout()) {
|
||||
ViewGroup hotseat = (ViewGroup) launcher.getHotseat().getChildAt(0);
|
||||
for (int i = hotseat.getChildCount() - 1; i >= 0; i--) {
|
||||
View child = hotseat.getChildAt(i);
|
||||
CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
|
||||
addStaggeredAnimationForView(child, lp.cellY + 1, totalRows);
|
||||
}
|
||||
} else {
|
||||
View hotseat = launcher.getHotseat().getChildAt(0);
|
||||
addStaggeredAnimationForView(hotseat, grid.inv.numRows + 1, totalRows);
|
||||
|
||||
View qsb = launcher.findViewById(R.id.search_container_all_apps);
|
||||
addStaggeredAnimationForView(qsb, grid.inv.numRows + 2, totalRows);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the animation.
|
||||
*/
|
||||
public void start() {
|
||||
for (Animator a : mAnimators) {
|
||||
if (a instanceof SpringObjectAnimator) {
|
||||
((SpringObjectAnimator) a).startSpring(1f, mVelocity, null);
|
||||
} else {
|
||||
a.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an alpha/trans animator for {@param v}, with a start delay based on the view's row.
|
||||
*
|
||||
* @param v A view on the workspace.
|
||||
* @param row The bottom-most row that contains the view.
|
||||
* @param totalRows Total number of rows.
|
||||
*/
|
||||
private void addStaggeredAnimationForView(View v, int row, int totalRows) {
|
||||
if (v == mViewToIgnore) {
|
||||
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.
|
||||
long startDelay = (long) ((invertedRow + 1) * APP_CLOSE_ROW_START_DELAY_MS);
|
||||
|
||||
v.setTranslationY(mSpringTransY);
|
||||
SpringObjectAnimator springTransY = new SpringObjectAnimator<>(
|
||||
new ViewProgressProperty(v, View.TRANSLATION_Y), "staggeredSpringTransY", 1f,
|
||||
DAMPING_RATIO, STIFFNESS, mSpringTransY, 0);
|
||||
springTransY.setStartDelay(startDelay);
|
||||
mAnimators.add(springTransY);
|
||||
|
||||
v.setAlpha(0);
|
||||
ObjectAnimator alpha = ObjectAnimator.ofFloat(v, View.ALPHA, 0f, 1f);
|
||||
alpha.setInterpolator(LINEAR);
|
||||
alpha.setDuration(ALPHA_DURATION_MS);
|
||||
alpha.setStartDelay(startDelay);
|
||||
mAnimators.add(alpha);
|
||||
}
|
||||
}
|
||||
@@ -143,5 +143,9 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
|
||||
@NonNull RectF getWindowTargetRect();
|
||||
|
||||
@NonNull AnimatorPlaybackController createActivityAnimationToHome();
|
||||
|
||||
default void playAtomicAnimation(float velocity) {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.util.Property;
|
||||
|
||||
@@ -139,7 +141,7 @@ public class SpringObjectAnimator<T extends ProgressInterface> extends ValueAnim
|
||||
/**
|
||||
* Initializes and sets up the spring to take over controlling the object.
|
||||
*/
|
||||
void startSpring(float end, float velocity, OnAnimationEndListener endListener) {
|
||||
public void startSpring(float end, float velocity, OnAnimationEndListener endListener) {
|
||||
// Cancel the spring so we can set new start velocity and final position. We need to remove
|
||||
// the listener since the spring is not actually ending.
|
||||
mSpring.removeEndListener(endListener);
|
||||
@@ -149,7 +151,13 @@ public class SpringObjectAnimator<T extends ProgressInterface> extends ValueAnim
|
||||
mProperty.switchToSpring();
|
||||
|
||||
mSpring.setStartVelocity(velocity);
|
||||
mSpring.animateToFinalPosition(end == 0 ? mValues[0] : mValues[1]);
|
||||
|
||||
float startValue = end == 0 ? mValues[1] : mValues[0];
|
||||
float endValue = end == 0 ? mValues[0] : mValues[1];
|
||||
mSpring.setStartValue(startValue);
|
||||
new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||
mSpring.animateToFinalPosition(endValue);
|
||||
}, getStartDelay());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user