Merge "Hide keyboard while the home button get pressed" into ub-launcher3-master
diff --git a/go/quickstep/src/com/android/launcher3/GoLauncherAppTransitionManagerImpl.java b/go/quickstep/src/com/android/launcher3/GoLauncherAppTransitionManagerImpl.java
index 96b4ae5..d189c50 100644
--- a/go/quickstep/src/com/android/launcher3/GoLauncherAppTransitionManagerImpl.java
+++ b/go/quickstep/src/com/android/launcher3/GoLauncherAppTransitionManagerImpl.java
@@ -31,7 +31,8 @@
@Override
protected void composeRecentsLaunchAnimator(AnimatorSet anim, View v,
RemoteAnimationTargetCompat[] targets, boolean launcherClosing) {
- //TODO: Implement this based off IconRecentsView
+ // Stubbed. Recents launch animation will come from the recents view itself and will not
+ // use remote animations.
}
@Override
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/go/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 5382607..cec12a8 100644
--- a/go/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -43,7 +43,7 @@
}
@Override
- public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
+ public float[] getOverviewScaleAndTranslationY(Launcher launcher) {
return new float[] {1f, 0f};
}
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 784af7d..0b12ab0 100644
--- a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -16,16 +16,15 @@
package com.android.launcher3.uioverrides;
import static com.android.quickstep.views.IconRecentsView.CONTENT_ALPHA;
-import static com.android.quickstep.views.IconRecentsView.TRANSLATION_Y_FACTOR;
import android.util.FloatProperty;
-import androidx.annotation.NonNull;
-
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherRecentsToActivityHelper;
import com.android.quickstep.views.IconRecentsView;
+import androidx.annotation.NonNull;
+
/**
* State handler for Go's {@link IconRecentsView}.
*/
@@ -39,11 +38,6 @@
}
@Override
- FloatProperty<IconRecentsView> getTranslationYFactorProperty() {
- return TRANSLATION_Y_FACTOR;
- }
-
- @Override
FloatProperty<IconRecentsView> getContentAlphaProperty() {
return CONTENT_ALPHA;
}
diff --git a/go/quickstep/src/com/android/quickstep/RecentsActivity.java b/go/quickstep/src/com/android/quickstep/RecentsActivity.java
index c814a71..447e7e7 100644
--- a/go/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/go/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -61,7 +61,7 @@
@Override
public ActivityOptions getActivityLaunchOptions(View v) {
- //TODO: Hook into recents launch animation
+ // Stubbed. Recents launch animation will come from the recents view itself.
return null;
}
diff --git a/go/quickstep/src/com/android/quickstep/TaskInputController.java b/go/quickstep/src/com/android/quickstep/TaskInputController.java
index d97ac8d..8433007 100644
--- a/go/quickstep/src/com/android/quickstep/TaskInputController.java
+++ b/go/quickstep/src/com/android/quickstep/TaskInputController.java
@@ -15,6 +15,10 @@
*/
package com.android.quickstep;
+import android.app.ActivityOptions;
+import android.view.View;
+
+import com.android.quickstep.views.TaskItemView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -37,9 +41,16 @@
* @param viewHolder the task view holder that has been tapped
*/
public void onTaskClicked(TaskHolder viewHolder) {
- // TODO: Add app launch animation as part of the launch options here.
+ TaskItemView itemView = (TaskItemView) (viewHolder.itemView);
+ View v = itemView.getThumbnailView();
+ int left = 0;
+ int top = 0;
+ int width = v.getMeasuredWidth();
+ int height = v.getMeasuredHeight();
+
+ ActivityOptions opts = ActivityOptions.makeClipRevealAnimation(v, left, top, width, height);
ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(viewHolder.getTask().key,
- null /* options */, null /* resultCallback */, null /* resultCallbackHandler */);
+ opts, null /* resultCallback */, null /* resultCallbackHandler */);
}
public void onTaskSwiped(TaskHolder viewHolder) {
diff --git a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
index 3fdaefe..504f640 100644
--- a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
+++ b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
@@ -46,20 +46,6 @@
*/
public final class IconRecentsView extends FrameLayout {
- public static final FloatProperty<IconRecentsView> TRANSLATION_Y_FACTOR =
- new FloatProperty<IconRecentsView>("translationYFactor") {
-
- @Override
- public void setValue(IconRecentsView view, float v) {
- view.setTranslationYFactor(v);
- }
-
- @Override
- public Float get(IconRecentsView view) {
- return view.mTranslationYFactor;
- }
- };
-
public static final FloatProperty<IconRecentsView> CONTENT_ALPHA =
new FloatProperty<IconRecentsView>("contentAlpha") {
@Override
@@ -91,7 +77,6 @@
private final TaskInputController mTaskInputController;
private RecentsToActivityHelper mActivityHelper;
- private float mTranslationYFactor;
private RecyclerView mTaskRecyclerView;
private View mEmptyView;
@@ -170,15 +155,6 @@
return view.getThumbnailView();
}
- public void setTranslationYFactor(float translationFactor) {
- mTranslationYFactor = translationFactor;
- setTranslationY(computeTranslationYForFactor(mTranslationYFactor));
- }
-
- private float computeTranslationYForFactor(float translationYFactor) {
- return translationYFactor * (getPaddingBottom() - getPaddingTop());
- }
-
/**
* Update the content view so that the appropriate view is shown based off the current list
* of tasks.
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/BackgroundAppState.java
index fdb80da..f712753 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/BackgroundAppState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/BackgroundAppState.java
@@ -52,7 +52,7 @@
}
@Override
- public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
+ public float[] getOverviewScaleAndTranslationY(Launcher launcher) {
// Initialize the recents view scale to what it would be when starting swipe up
RecentsView recentsView = launcher.getOverviewPanel();
recentsView.getTaskSize(sTempRect);
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/OverviewState.java
index 79e127a..2360eeb 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -69,7 +69,7 @@
}
@Override
- public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
+ public float[] getOverviewScaleAndTranslationY(Launcher launcher) {
return new float[] {1f, 0f};
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 0b3bd6c..0d5574f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.uioverrides;
-import static com.android.quickstep.views.LauncherRecentsView.TRANSLATION_Y_FACTOR;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
import android.animation.ValueAnimator;
@@ -23,8 +22,6 @@
import android.os.Build;
import android.util.FloatProperty;
-import androidx.annotation.NonNull;
-
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
@@ -32,6 +29,8 @@
import com.android.quickstep.views.LauncherRecentsView;
import com.android.quickstep.views.RecentsView;
+import androidx.annotation.NonNull;
+
/**
* State handler for handling UI changes for {@link LauncherRecentsView}. In addition to managing
* the basic view properties, this class also manages changes in the task visuals.
@@ -80,11 +79,6 @@
}
@Override
- FloatProperty<LauncherRecentsView> getTranslationYFactorProperty() {
- return TRANSLATION_Y_FACTOR;
- }
-
- @Override
FloatProperty<RecentsView> getContentAlphaProperty() {
return CONTENT_ALPHA;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java
index d61ed72..ef46b3b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java
@@ -21,7 +21,6 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
-import android.content.ComponentName;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -90,7 +89,7 @@
@NonNull
@Override
- public Animator createActivityAnimationToHome() {
+ public AnimatorPlaybackController createActivityAnimationToHome() {
Animator anim = ObjectAnimator.ofFloat(recentsView, CONTENT_ALPHA, 0);
anim.addListener(new AnimationSuccessListener() {
@Override
@@ -98,7 +97,10 @@
recentsView.startHome();
}
});
- return anim;
+ AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.play(anim);
+ long accuracy = 2 * Math.max(recentsView.getWidth(), recentsView.getHeight());
+ return AnimatorPlaybackController.wrap(animatorSet, accuracy);
}
};
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index e95e2a0..279b83c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -56,9 +56,7 @@
import com.android.launcher3.anim.SpringObjectAnimator;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.userevent.nano.LauncherLogProto;
-import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.LayoutUtils;
@@ -144,10 +142,9 @@
@NonNull
@Override
- public Animator createActivityAnimationToHome() {
+ public AnimatorPlaybackController createActivityAnimationToHome() {
long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
- return activity.getStateManager().createAnimationToNewWorkspace(
- NORMAL, accuracy).getTarget();
+ return activity.getStateManager().createAnimationToNewWorkspace(NORMAL, accuracy);
}
};
}
@@ -308,7 +305,7 @@
// starting to line up the side pages during swipe up)
float prevRvScale = recentsView.getScaleX();
float prevRvTransY = recentsView.getTranslationY();
- float targetRvScale = endState.getOverviewScaleAndTranslationYFactor(launcher)[0];
+ float targetRvScale = endState.getOverviewScaleAndTranslationY(launcher)[0];
SCALE_PROPERTY.set(recentsView, targetRvScale);
recentsView.setTranslationY(0);
ClipAnimationHelper clipHelper = new ClipAnimationHelper(launcher);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
index 84097a1..c8dcf80 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
@@ -21,7 +21,6 @@
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;
-
import static com.android.launcher3.util.RaceConditionTracker.ENTER;
import static com.android.launcher3.util.RaceConditionTracker.EXIT;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
@@ -45,8 +44,6 @@
import android.view.ViewConfiguration;
import android.view.WindowManager;
-import androidx.annotation.UiThread;
-
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.RaceConditionTracker;
@@ -63,6 +60,8 @@
import java.util.function.Consumer;
+import androidx.annotation.UiThread;
+
/**
* Input consumer for handling events originating from an activity other than Launcher
*/
@@ -131,7 +130,8 @@
mVelocityTracker = VelocityTracker.obtain();
mActivityControlHelper = activityControl;
- mIsDeferredDownTarget = isDeferredDownTarget;
+ boolean continuingPreviousGesture = swipeSharedState.getActiveListener() != null;
+ mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget;
mOverviewCallbacks = overviewCallbacks;
mTaskOverlayFactory = taskOverlayFactory;
mInputConsumer = inputConsumer;
@@ -143,8 +143,7 @@
mDragSlop = NavigationBarCompat.getQuickStepDragSlopPx();
mTouchSlop = NavigationBarCompat.getQuickStepTouchSlopPx();
- // If active listener isn't null, we are continuing the previous gesture.
- mPassedTouchSlop = mPassedDragSlop = mSwipeSharedState.getActiveListener() != null;
+ mPassedTouchSlop = mPassedDragSlop = continuingPreviousGesture;
}
@Override
@@ -331,12 +330,13 @@
mVelocityTracker.computeCurrentVelocity(1000,
ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
float velocityX = mVelocityTracker.getXVelocity(mActivePointerId);
+ float velocityY = mVelocityTracker.getYVelocity(mActivePointerId);
float velocity = isNavBarOnRight() ? velocityX
: isNavBarOnLeft() ? -velocityX
- : mVelocityTracker.getYVelocity(mActivePointerId);
+ : velocityY;
mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement);
- mInteractionHandler.onGestureEnded(velocity, velocityX);
+ mInteractionHandler.onGestureEnded(velocity, new PointF(velocityX, velocityY));
} else {
// Since we start touch tracking on DOWN, we may reach this state without actually
// starting the gesture. In that case, just cleanup immediately.
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index fd53f9c..eb1e7b4 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -43,12 +43,12 @@
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
@@ -85,6 +85,7 @@
import com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState;
import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory;
import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.quickstep.util.SwipeAnimationTargetSet;
import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener;
@@ -92,7 +93,6 @@
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.recents.utilities.RectFEvaluator;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -110,7 +110,7 @@
implements SwipeAnimationListener, OnApplyWindowInsetsListener {
private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName();
- private static final String[] STATE_NAMES = DEBUG_STATES ? new String[17] : null;
+ private static final String[] STATE_NAMES = DEBUG_STATES ? new String[16] : null;
private static int getFlagForIndex(int index, String name) {
if (DEBUG_STATES) {
@@ -133,37 +133,33 @@
getFlagForIndex(4, "STATE_SCALED_CONTROLLER_HOME");
private static final int STATE_SCALED_CONTROLLER_RECENTS =
getFlagForIndex(5, "STATE_SCALED_CONTROLLER_RECENTS");
- private static final int STATE_SCALED_CONTROLLER_LAST_TASK =
- getFlagForIndex(6, "STATE_SCALED_CONTROLLER_LAST_TASK");
private static final int STATE_HANDLER_INVALIDATED =
- getFlagForIndex(7, "STATE_HANDLER_INVALIDATED");
+ getFlagForIndex(6, "STATE_HANDLER_INVALIDATED");
private static final int STATE_GESTURE_STARTED =
- getFlagForIndex(8, "STATE_GESTURE_STARTED");
+ getFlagForIndex(7, "STATE_GESTURE_STARTED");
private static final int STATE_GESTURE_CANCELLED =
- getFlagForIndex(9, "STATE_GESTURE_CANCELLED");
+ getFlagForIndex(8, "STATE_GESTURE_CANCELLED");
private static final int STATE_GESTURE_COMPLETED =
- getFlagForIndex(10, "STATE_GESTURE_COMPLETED");
+ getFlagForIndex(9, "STATE_GESTURE_COMPLETED");
private static final int STATE_CAPTURE_SCREENSHOT =
- getFlagForIndex(11, "STATE_CAPTURE_SCREENSHOT");
+ getFlagForIndex(10, "STATE_CAPTURE_SCREENSHOT");
private static final int STATE_SCREENSHOT_CAPTURED =
- getFlagForIndex(12, "STATE_SCREENSHOT_CAPTURED");
+ getFlagForIndex(11, "STATE_SCREENSHOT_CAPTURED");
private static final int STATE_SCREENSHOT_VIEW_SHOWN =
- getFlagForIndex(13, "STATE_SCREENSHOT_VIEW_SHOWN");
+ getFlagForIndex(12, "STATE_SCREENSHOT_VIEW_SHOWN");
private static final int STATE_RESUME_LAST_TASK =
- getFlagForIndex(14, "STATE_RESUME_LAST_TASK");
+ getFlagForIndex(13, "STATE_RESUME_LAST_TASK");
private static final int STATE_START_NEW_TASK =
- getFlagForIndex(15, "STATE_START_NEW_TASK");
+ getFlagForIndex(14, "STATE_START_NEW_TASK");
private static final int STATE_CURRENT_TASK_FINISHED =
- getFlagForIndex(16, "STATE_CURRENT_TASK_FINISHED");
+ getFlagForIndex(15, "STATE_CURRENT_TASK_FINISHED");
private static final int LAUNCHER_UI_STATES =
STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
- // For debugging, keep in sync with above states
-
enum GestureEndTarget {
HOME(1, STATE_SCALED_CONTROLLER_HOME, true, false, ContainerType.WORKSPACE),
@@ -172,7 +168,7 @@
NEW_TASK(0, STATE_START_NEW_TASK, false, true, ContainerType.APP),
- LAST_TASK(0, STATE_SCALED_CONTROLLER_LAST_TASK, false, false, ContainerType.APP);
+ LAST_TASK(0, STATE_RESUME_LAST_TASK, false, true, ContainerType.APP);
GestureEndTarget(float endShift, int endState, boolean isLauncher, boolean canBeContinued,
int containerType) {
@@ -234,6 +230,7 @@
private ThumbnailData mTaskSnapshot;
private MultiStateCallback mStateCallback;
+ // Used to control launcher components throughout the swipe gesture.
private AnimatorPlaybackController mLauncherTransitionController;
private T mActivity;
@@ -274,10 +271,8 @@
private void initStateCallbacks() {
mStateCallback = new MultiStateCallback(STATE_NAMES);
- // Re-setup the recents UI when gesture starts, as the state could have been changed during
- // that time by a previous window transition.
- mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_GESTURE_STARTED,
- this::setupRecentsViewUi);
+ mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED,
+ this::onLauncherPresentAndGestureStarted);
mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED,
this::initializeLauncherAnimationController);
@@ -285,9 +280,6 @@
mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN,
this::launcherFrameDrawn);
- mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED,
- this::notifyGestureStartedAsync);
-
mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_STARTED
| STATE_GESTURE_CANCELLED,
this::resetStateForAnimationCancel);
@@ -295,8 +287,6 @@
mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_APP_CONTROLLER_RECEIVED,
this::sendRemoteAnimationsToAnimationFactory);
- mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_SCALED_CONTROLLER_LAST_TASK,
- this::resumeLastTaskForQuickstep);
mStateCallback.addCallback(STATE_RESUME_LAST_TASK | STATE_APP_CONTROLLER_RECEIVED,
this::resumeLastTask);
mStateCallback.addCallback(STATE_START_NEW_TASK | STATE_APP_CONTROLLER_RECEIVED,
@@ -326,8 +316,7 @@
mStateCallback.addCallback(STATE_HANDLER_INVALIDATED, this::invalidateHandler);
mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
this::invalidateHandlerWithLauncher);
- mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED
- | STATE_SCALED_CONTROLLER_LAST_TASK,
+ mStateCallback.addCallback(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK,
this::notifyTransitionCancelled);
mStateCallback.addCallback(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED,
@@ -414,6 +403,8 @@
} else {
activity.setOnStartCallback(this::onLauncherStart);
}
+
+ setupRecentsViewUi();
return true;
}
@@ -425,8 +416,12 @@
return;
}
- mAnimationFactory = mActivityControlHelper.prepareRecentsUI(mActivity,
- mWasLauncherAlreadyVisible, true, this::onAnimatorPlaybackControllerCreated);
+ // If we've already ended the gesture and are going home, don't prepare recents UI,
+ // as that will set the state as BACKGROUND_APP, overriding the animation to NORMAL.
+ if (mGestureEndTarget != HOME) {
+ mAnimationFactory = mActivityControlHelper.prepareRecentsUI(mActivity,
+ mWasLauncherAlreadyVisible, true, this::onAnimatorPlaybackControllerCreated);
+ }
AbstractFloatingView.closeAllOpenViews(activity, mWasLauncherAlreadyVisible);
if (mWasLauncherAlreadyVisible) {
@@ -450,11 +445,18 @@
});
}
- setupRecentsViewUi();
activity.getRootView().setOnApplyWindowInsetsListener(this);
mStateCallback.setState(STATE_LAUNCHER_STARTED);
}
+ private void onLauncherPresentAndGestureStarted() {
+ // Re-setup the recents UI when gesture starts, as the state could have been changed during
+ // that time by a previous window transition.
+ setupRecentsViewUi();
+
+ notifyGestureStartedAsync();
+ }
+
private void setupRecentsViewUi() {
if (mContinuingLastGesture) {
return;
@@ -677,15 +679,19 @@
}
}
+ /**
+ * @param endVelocity The velocity in the direction of the nav bar to the middle of the screen.
+ * @param velocity The x and y components of the velocity when the gesture ends.
+ */
@UiThread
- public void onGestureEnded(float endVelocity, float velocityX) {
+ public void onGestureEnded(float endVelocity, PointF velocity) {
float flingThreshold = mContext.getResources()
.getDimension(R.dimen.quickstep_fling_threshold_velocity);
boolean isFling = mGestureStarted && Math.abs(endVelocity) > flingThreshold;
setStateOnUiThread(STATE_GESTURE_COMPLETED);
mLogAction = isFling ? Touch.FLING : Touch.SWIPE;
- handleNormalGestureEnd(endVelocity, isFling, velocityX);
+ handleNormalGestureEnd(endVelocity, isFling, velocity);
}
@UiThread
@@ -703,9 +709,8 @@
}
@UiThread
- private void handleNormalGestureEnd(float endVelocity, boolean isFling, float velocityX) {
- float velocityPxPerMs = endVelocity / 1000;
- float velocityXPxPerMs = velocityX / 1000;
+ private void handleNormalGestureEnd(float endVelocity, boolean isFling, PointF velocity) {
+ PointF velocityPxPerMs = new PointF(velocity.x / 1000, velocity.y / 1000);
long duration = MAX_SWIPE_DURATION;
float currentShift = mCurrentShift.value;
final GestureEndTarget endTarget;
@@ -720,7 +725,7 @@
final int lastTaskIndex = mRecentsView.getTaskViewCount() - 1;
final int runningTaskIndex = mRecentsView.getRunningTaskIndex();
taskToLaunch = nextPage <= lastTaskIndex ? nextPage : lastTaskIndex;
- goingToNewTask = mRecentsView != null && taskToLaunch != runningTaskIndex;
+ goingToNewTask = runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex;
} else {
goingToNewTask = false;
}
@@ -750,7 +755,7 @@
} else {
if (SWIPE_HOME.get() && endVelocity < 0 && !mIsShelfPeeking) {
// If swiping at a diagonal, base end target on the faster velocity.
- endTarget = goingToNewTask && Math.abs(velocityX) > Math.abs(endVelocity)
+ endTarget = goingToNewTask && Math.abs(velocity.x) > Math.abs(endVelocity)
? NEW_TASK : HOME;
} else if (endVelocity < 0 && (!goingToNewTask || reachedOverviewThreshold)) {
// If user scrolled to a new task, only go to recents if they already passed
@@ -760,14 +765,15 @@
endTarget = goingToNewTask ? NEW_TASK : LAST_TASK;
}
endShift = endTarget.endShift;
- startShift = Utilities.boundToRange(currentShift - velocityPxPerMs
+ startShift = Utilities.boundToRange(currentShift - velocityPxPerMs.y
* SINGLE_FRAME_MS / mTransitionDragLength, 0, 1);
float minFlingVelocity = mContext.getResources()
.getDimension(R.dimen.quickstep_fling_min_velocity);
if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) {
if (endTarget == RECENTS) {
Interpolators.OvershootParams overshoot = new Interpolators.OvershootParams(
- startShift, endShift, endShift, velocityPxPerMs, mTransitionDragLength);
+ startShift, endShift, endShift, velocityPxPerMs.y,
+ mTransitionDragLength);
endShift = overshoot.end;
interpolator = overshoot.interpolator;
duration = Utilities.boundToRange(overshoot.duration, MIN_OVERSHOOT_DURATION,
@@ -778,7 +784,7 @@
// we want the page's snap velocity to approximately match the velocity at
// which the user flings, so we scale the duration by a value near to the
// derivative of the scroll interpolator at zero, ie. 2.
- long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs));
+ long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y));
duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
}
}
@@ -803,7 +809,7 @@
}
} else if (endTarget == NEW_TASK || endTarget == LAST_TASK) {
// Let RecentsView handle the scrolling to the task, which we launch in startNewTask()
- // or resumeLastTaskForQuickstep().
+ // or resumeLastTask().
if (mRecentsView != null) {
duration = Math.max(duration, mRecentsView.getScroller().getDuration());
}
@@ -835,14 +841,14 @@
/** Animates to the given progress, where 0 is the current app and 1 is overview. */
@UiThread
private void animateToProgress(float start, float end, long duration, Interpolator interpolator,
- GestureEndTarget target, float velocityPxPerMs) {
+ GestureEndTarget target, PointF velocityPxPerMs) {
mRecentsAnimationWrapper.runOnInit(() -> animateToProgressInternal(start, end, duration,
interpolator, target, velocityPxPerMs));
}
@UiThread
private void animateToProgressInternal(float start, float end, long duration,
- Interpolator interpolator, GestureEndTarget target, float velocityPxPerMs) {
+ Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
mGestureEndTarget = target;
if (mGestureEndTarget.canBeContinued) {
@@ -855,9 +861,8 @@
RecentsModel.INSTANCE.get(mContext).endStabilizationSession();
}
- HomeAnimationFactory homeAnimFactory;
- Animator windowAnim;
if (mGestureEndTarget == HOME) {
+ HomeAnimationFactory homeAnimFactory;
if (mActivity != null) {
homeAnimFactory = mActivityControlHelper.prepareHomeUI(mActivity);
} else {
@@ -872,27 +877,33 @@
@NonNull
@Override
- public Animator createActivityAnimationToHome() {
- return new AnimatorSet();
+ public AnimatorPlaybackController createActivityAnimationToHome() {
+ return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
}
};
mStateCallback.addChangeHandler(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
isPresent -> mRecentsView.startHome());
}
- windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
+ RectFSpringAnim windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
+ windowAnim.addAnimatorListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ setStateOnUiThread(target.endState);
+ }
+ });
+ windowAnim.start(velocityPxPerMs);
mLauncherTransitionController = null;
} else {
- windowAnim = mCurrentShift.animateToValue(start, end);
- homeAnimFactory = null;
+ Animator windowAnim = mCurrentShift.animateToValue(start, end);
+ windowAnim.setDuration(duration).setInterpolator(interpolator);
+ windowAnim.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ setStateOnUiThread(target.endState);
+ }
+ });
+ windowAnim.start();
}
- windowAnim.setDuration(duration).setInterpolator(interpolator);
- windowAnim.addListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationSuccess(Animator animator) {
- setStateOnUiThread(target.endState);
- }
- });
- windowAnim.start();
// Always play the entire launcher animation when going home, since it is separate from
// the animation that has been controlled thus far.
if (mGestureEndTarget == HOME) {
@@ -903,12 +914,6 @@
// interpolate over the remaining progress (end - start).
TimeInterpolator adjustedInterpolator = Interpolators.mapToProgress(
interpolator, start, end);
- if (homeAnimFactory != null) {
- Animator homeAnim = homeAnimFactory.createActivityAnimationToHome();
- homeAnim.setDuration(duration).setInterpolator(adjustedInterpolator);
- homeAnim.start();
- mLauncherTransitionController = null;
- }
if (mLauncherTransitionController == null) {
return;
}
@@ -920,50 +925,41 @@
mLauncherTransitionController.getAnimationPlayer().setDuration(duration);
if (QUICKSTEP_SPRINGS.get()) {
- mLauncherTransitionController.dispatchOnStartWithVelocity(end, velocityPxPerMs);
+ mLauncherTransitionController.dispatchOnStartWithVelocity(end, velocityPxPerMs.y);
}
mLauncherTransitionController.getAnimationPlayer().start();
}
}
/**
- * Creates an Animator that transforms the current app window into the home app.
+ * Creates an animation that transforms the current app window into the home app.
* @param startProgress The progress of {@link #mCurrentShift} to start the window from.
* @param homeAnimationFactory The home animation factory.
*/
- private Animator createWindowAnimationToHome(float startProgress,
+ private RectFSpringAnim createWindowAnimationToHome(float startProgress,
HomeAnimationFactory homeAnimationFactory) {
final RemoteAnimationTargetSet targetSet = mRecentsAnimationWrapper.targetSet;
- RectF startRect = new RectF(mClipAnimationHelper.applyTransform(targetSet,
+ final RectF startRect = new RectF(mClipAnimationHelper.applyTransform(targetSet,
mTransformParams.setProgress(startProgress)));
- RectF originalTarget = new RectF(mClipAnimationHelper.getTargetRect());
- final RectF finalTarget = homeAnimationFactory.getWindowTargetRect();
-
- final RectFEvaluator rectFEvaluator = new RectFEvaluator();
- final RectF targetRect = new RectF();
- final RectF currentRect = new RectF();
+ final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
final View floatingView = homeAnimationFactory.getFloatingView();
final boolean isFloatingIconView = floatingView instanceof FloatingIconView;
- ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+ RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect);
if (isFloatingIconView) {
- anim.addListener((FloatingIconView) floatingView);
+ anim.addAnimatorListener((FloatingIconView) floatingView);
}
+ AnimatorPlaybackController homeAnim = homeAnimationFactory.createActivityAnimationToHome();
+
// 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.
final float windowAlphaThreshold = isFloatingIconView ? 0.75f : 1f;
- anim.addUpdateListener(animation -> {
- float progress = animation.getAnimatedFraction();
+ anim.addOnUpdateListener((currentRect, progress) -> {
float interpolatedProgress = Interpolators.ACCEL_1_5.getInterpolation(progress);
- // Initially go towards original target (task view in recents),
- // but accelerate towards the final target.
- // TODO: This is technically not correct. Instead, motion should continue at
- // the released velocity but accelerate towards the target.
- targetRect.set(rectFEvaluator.evaluate(interpolatedProgress,
- originalTarget, finalTarget));
- currentRect.set(rectFEvaluator.evaluate(interpolatedProgress, startRect, targetRect));
+
+ homeAnim.setPlayFraction(progress);
float iconAlpha = Utilities.mapToRange(interpolatedProgress, 0,
windowAlphaThreshold, 0f, 1f, Interpolators.LINEAR);
@@ -975,10 +971,17 @@
((FloatingIconView) floatingView).update(currentRect, iconAlpha, progress,
windowAlphaThreshold);
}
+
});
- anim.addListener(new AnimationSuccessListener() {
+ anim.addAnimatorListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ homeAnim.dispatchOnStart();
+ }
+
@Override
public void onAnimationSuccess(Animator animator) {
+ homeAnim.getAnimationPlayer().end();
if (mRecentsView != null) {
mRecentsView.post(mRecentsView::resetTaskVisuals);
}
@@ -988,16 +991,11 @@
}
@UiThread
- private void resumeLastTaskForQuickstep() {
- setStateOnUiThread(STATE_RESUME_LAST_TASK);
- doLogGesture(LAST_TASK);
- reset();
- }
-
- @UiThread
private void resumeLastTask() {
mRecentsAnimationWrapper.finish(false /* toRecents */, null);
TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", false);
+ doLogGesture(LAST_TASK);
+ reset();
}
@UiThread
@@ -1005,18 +1003,15 @@
// Launch the task user scrolled to (mRecentsView.getNextPage()).
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
// We finish recents animation inside launchTask() when live tile is enabled.
- mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false,
- result -> setStateOnUiThread(STATE_HANDLER_INVALIDATED),
- mMainThreadHandler);
+ mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false);
} else {
mRecentsAnimationWrapper.finish(true /* toRecents */, () -> {
- mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false,
- result -> setStateOnUiThread(STATE_HANDLER_INVALIDATED),
- mMainThreadHandler);
+ mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false);
});
}
TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", false);
doLogGesture(NEW_TASK);
+ reset();
}
public void reset() {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
new file mode 100644
index 0000000..2edeb3a
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -0,0 +1,179 @@
+/*
+ * 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.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.util.FloatProperty;
+
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.FlingSpringAnim;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
+import androidx.dynamicanimation.animation.FloatPropertyCompat;
+
+/**
+ * Applies spring forces to animate from a starting rect to a target rect,
+ * while providing update callbacks to the caller.
+ */
+public class RectFSpringAnim {
+
+ /**
+ * Although the rect position animation takes an indefinite amount of time since it depends on
+ * the initial velocity and applied forces, scaling from the starting rect to the target rect
+ * can be done in parallel at a fixed duration. Update callbacks are sent based on the progress
+ * of this animation, while the end callback is sent after all animations finish.
+ */
+ private static final long RECT_SCALE_DURATION = 180;
+
+ private static final FloatPropertyCompat<RectFSpringAnim> RECT_CENTER_X =
+ new FloatPropertyCompat<RectFSpringAnim>("rectCenterXSpring") {
+ @Override
+ public float getValue(RectFSpringAnim anim) {
+ return anim.mCurrentCenterX;
+ }
+
+ @Override
+ public void setValue(RectFSpringAnim anim, float currentCenterX) {
+ anim.mCurrentCenterX = currentCenterX;
+ anim.onUpdate();
+ }
+ };
+
+ private static final FloatPropertyCompat<RectFSpringAnim> RECT_CENTER_Y =
+ new FloatPropertyCompat<RectFSpringAnim>("rectCenterYSpring") {
+ @Override
+ public float getValue(RectFSpringAnim anim) {
+ return anim.mCurrentCenterY;
+ }
+
+ @Override
+ public void setValue(RectFSpringAnim anim, float currentCenterY) {
+ anim.mCurrentCenterY = currentCenterY;
+ anim.onUpdate();
+ }
+ };
+
+ private static final FloatProperty<RectFSpringAnim> RECT_SCALE_PROGRESS =
+ new FloatProperty<RectFSpringAnim>("rectScaleProgress") {
+ @Override
+ public Float get(RectFSpringAnim anim) {
+ return anim.mCurrentScaleProgress;
+ }
+
+ @Override
+ public void setValue(RectFSpringAnim anim, float currentScaleProgress) {
+ anim.mCurrentScaleProgress = currentScaleProgress;
+ anim.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 mCurrentCenterY;
+ private float mCurrentScaleProgress;
+ private boolean mRectXAnimEnded;
+ private boolean mRectYAnimEnded;
+ private boolean mRectScaleAnimEnded;
+
+ public RectFSpringAnim(RectF startRect, RectF targetRect) {
+ mStartRect = startRect;
+ mTargetRect = targetRect;
+ mCurrentCenterX = mStartRect.centerX();
+ mCurrentCenterY = mStartRect.centerY();
+ }
+
+ public void addOnUpdateListener(OnUpdateListener onUpdateListener) {
+ mOnUpdateListeners.add(onUpdateListener);
+ }
+
+ public void addAnimatorListener(Animator.AnimatorListener animatorListener) {
+ mAnimatorListeners.add(animatorListener);
+ }
+
+ public void start(PointF velocityPxPerMs) {
+ // Only tell caller that we ended if both x and y animations have ended.
+ OnAnimationEndListener onXEndListener = ((animation, canceled, centerX, velocityX) -> {
+ mRectXAnimEnded = true;
+ maybeOnEnd();
+ });
+ OnAnimationEndListener onYEndListener = ((animation, canceled, centerY, velocityY) -> {
+ mRectYAnimEnded = true;
+ maybeOnEnd();
+ });
+ FlingSpringAnim rectXAnim = new FlingSpringAnim(this, RECT_CENTER_X, mCurrentCenterX,
+ mTargetRect.centerX(), velocityPxPerMs.x * 1000, onXEndListener);
+ FlingSpringAnim rectYAnim = new FlingSpringAnim(this, RECT_CENTER_Y, mCurrentCenterY,
+ mTargetRect.centerY(), velocityPxPerMs.y * 1000, onYEndListener);
+
+ ValueAnimator rectScaleAnim = ObjectAnimator.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat(RECT_SCALE_PROGRESS, 1))
+ .setDuration(RECT_SCALE_DURATION);
+ rectScaleAnim.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ mRectScaleAnimEnded = true;
+ maybeOnEnd();
+ }
+ });
+
+ rectXAnim.start();
+ rectYAnim.start();
+ rectScaleAnim.start();
+ for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
+ animatorListener.onAnimationStart(null);
+ }
+ }
+
+ private void onUpdate() {
+ if (!mOnUpdateListeners.isEmpty()) {
+ float currentWidth = Utilities.mapRange(mCurrentScaleProgress, mStartRect.width(),
+ mTargetRect.width());
+ float currentHeight = Utilities.mapRange(mCurrentScaleProgress, mStartRect.height(),
+ mTargetRect.height());
+ mCurrentRect.set(mCurrentCenterX - currentWidth / 2, mCurrentCenterY - currentHeight / 2,
+ mCurrentCenterX + currentWidth / 2, mCurrentCenterY + currentHeight / 2);
+ for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
+ onUpdateListener.onUpdate(mCurrentRect, mCurrentScaleProgress);
+ }
+ }
+ }
+
+ private void maybeOnEnd() {
+ if (mRectXAnimEnded && mRectYAnimEnded && mRectScaleAnimEnded) {
+ for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
+ animatorListener.onAnimationEnd(null);
+ }
+ }
+ }
+
+ public interface OnUpdateListener {
+ void onUpdate(RectF currentRect, float progress);
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java
index cf42a36..19e9cb4 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -198,7 +198,7 @@
final ActivityOptions options = ActivityOptions.makeScaleUpAnimation(
this, 0, 0,
getWidth(), getHeight());
- launcher.startActivityForResult(intent, 0, options.toBundle());
+ launcher.startActivity(intent, options.toBundle());
launcher.getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.Touch.TAP,
LauncherLogProto.ControlType.APP_USAGE_SETTINGS, this);
} catch (ActivityNotFoundException e) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index 97bce5e..8f2a2d7 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -56,27 +56,6 @@
@TargetApi(Build.VERSION_CODES.O)
public class LauncherRecentsView extends RecentsView<Launcher> {
- public static final FloatProperty<LauncherRecentsView> TRANSLATION_Y_FACTOR =
- new FloatProperty<LauncherRecentsView>("translationYFactor") {
-
- @Override
- public void setValue(LauncherRecentsView view, float v) {
- view.setTranslationYFactor(v);
- }
-
- @Override
- public Float get(LauncherRecentsView view) {
- return view.mTranslationYFactor;
- }
- };
-
- /**
- * A ratio representing the view's relative placement within its padded space. For example, 0
- * is top aligned and 0.5 is centered vertically.
- */
- @ViewDebug.ExportedProperty(category = "launcher")
- private float mTranslationYFactor;
-
private final TransformParams mTransformParams = new TransformParams();
private ChipsContainer mChipsContainer;
@@ -104,12 +83,6 @@
}
@Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- setTranslationYFactor(mTranslationYFactor);
- }
-
- @Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mChipsContainer = mActivity.findViewById(R.id.hints);
@@ -117,9 +90,9 @@
params.bottomMargin = mActivity.getDeviceProfile().chipHintBottomMarginPx;
}
- public void setTranslationYFactor(float translationFactor) {
- mTranslationYFactor = translationFactor;
- setTranslationY(computeTranslationYForFactor(mTranslationYFactor));
+ @Override
+ public void setTranslationY(float translationY) {
+ super.setTranslationY(translationY);
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
LauncherState state = mActivity.getStateManager().getState();
if (state == OVERVIEW || state == ALL_APPS) {
@@ -128,10 +101,6 @@
}
}
- public float computeTranslationYForFactor(float translationYFactor) {
- return translationYFactor * (getPaddingBottom() - getPaddingTop());
- }
-
public void setHintVisibility(float v) {
if (mChipsContainer != null && ENABLE_HINTS_IN_OVERVIEW.get()) {
mChipsContainer.setHintVisibility(v);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
index 1eaa8bc..5ae562e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
@@ -78,8 +78,9 @@
}
@Override
- public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
- return new float[] {0.9f, -0.2f};
+ public float[] getOverviewScaleAndTranslationY(Launcher launcher) {
+ float slightParallax = -launcher.getDeviceProfile().allAppsCellHeightPx * 0.3f;
+ return new float[] {0.9f, slightParallax};
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index df9dbe4..e74d84d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -26,8 +26,6 @@
import android.view.View;
import android.view.animation.Interpolator;
-import androidx.annotation.NonNull;
-
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
@@ -35,6 +33,8 @@
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PropertySetter;
+import androidx.annotation.NonNull;
+
/**
* State handler for recents view. Manages UI changes and animations for recents view based off the
* current {@link LauncherState}.
@@ -53,9 +53,9 @@
@Override
public void setState(@NonNull LauncherState state) {
- float[] scaleTranslationYFactor = state.getOverviewScaleAndTranslationYFactor(mLauncher);
- SCALE_PROPERTY.set(mRecentsView, scaleTranslationYFactor[0]);
- getTranslationYFactorProperty().set(mRecentsView, scaleTranslationYFactor[1]);
+ float[] scaleTranslationY = state.getOverviewScaleAndTranslationY(mLauncher);
+ SCALE_PROPERTY.set(mRecentsView, scaleTranslationY[0]);
+ mRecentsView.setTranslationY(scaleTranslationY[1]);
getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
}
@@ -79,11 +79,11 @@
void setStateWithAnimationInternal(@NonNull final LauncherState toState,
@NonNull AnimatorSetBuilder builder, @NonNull AnimationConfig config) {
PropertySetter setter = config.getPropertySetter(builder);
- float[] scaleTranslationYFactor = toState.getOverviewScaleAndTranslationYFactor(mLauncher);
+ float[] scaleTranslationY = toState.getOverviewScaleAndTranslationY(mLauncher);
Interpolator scaleAndTransYInterpolator = getScaleAndTransYInterpolator(toState, builder);
- setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleTranslationYFactor[0],
+ setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleTranslationY[0],
scaleAndTransYInterpolator);
- setter.setFloat(mRecentsView, getTranslationYFactorProperty(), scaleTranslationYFactor[1],
+ setter.setFloat(mRecentsView, View.TRANSLATION_Y, scaleTranslationY[1],
scaleAndTransYInterpolator);
setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
builder.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
@@ -102,13 +102,6 @@
}
/**
- * Get property for translation Y factor for the recents view.
- *
- * @return the float property for the recents view
- */
- abstract FloatProperty getTranslationYFactorProperty();
-
- /**
* Get property for content alpha for the recents view.
*
* @return the float property for the view's content alpha
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index 75be2e4..418f7f4 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -15,7 +15,6 @@
*/
package com.android.quickstep;
-import android.animation.Animator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
@@ -132,6 +131,6 @@
@NonNull RectF getWindowTargetRect();
- @NonNull Animator createActivityAnimationToHome();
+ @NonNull AnimatorPlaybackController createActivityAnimationToHome();
}
}
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index cee1c26..875288a 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -192,13 +192,7 @@
return getWorkspaceScaleAndTranslation(launcher);
}
- /**
- * Returns 2 floats designating how to transition overview:
- * scale for the current and adjacent pages
- * translationY factor where 0 is top aligned and 0.5 is centered vertically
- */
- public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
- // TODO: Simplify to use a constant value instead of a factor.
+ public float[] getOverviewScaleAndTranslationY(Launcher launcher) {
return new float[] {1.1f, 0f};
}
diff --git a/src/com/android/launcher3/anim/FlingSpringAnim.java b/src/com/android/launcher3/anim/FlingSpringAnim.java
new file mode 100644
index 0000000..3d21d82
--- /dev/null
+++ b/src/com/android/launcher3/anim/FlingSpringAnim.java
@@ -0,0 +1,60 @@
+/*
+ * 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.launcher3.anim;
+
+import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
+import androidx.dynamicanimation.animation.FlingAnimation;
+import androidx.dynamicanimation.animation.FloatPropertyCompat;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
+
+/**
+ * Given a property to animate and a target value and starting velocity, first apply friction to
+ * the fling until we pass the target, then apply a spring force to pull towards the target.
+ */
+public class FlingSpringAnim {
+
+ private static final float FLING_FRICTION = 1.5f;
+ // Have the spring pull towards the target if we've slowed down too much before reaching it.
+ private static final float FLING_END_THRESHOLD_PX = 50f;
+ private static final float SPRING_STIFFNESS = 350f;
+ private static final float SPRING_DAMPING = SpringForce.DAMPING_RATIO_LOW_BOUNCY;
+
+ private final FlingAnimation mFlingAnim;
+
+ public <K> FlingSpringAnim(K object, FloatPropertyCompat<K> property, float startPosition,
+ float targetPosition, float startVelocity, OnAnimationEndListener onEndListener) {
+ mFlingAnim = new FlingAnimation(object, property)
+ .setFriction(FLING_FRICTION)
+ .setMinimumVisibleChange(FLING_END_THRESHOLD_PX)
+ .setStartVelocity(startVelocity)
+ .setMinValue(Math.min(startPosition, targetPosition))
+ .setMaxValue(Math.max(startPosition, targetPosition));
+ mFlingAnim.addEndListener(((animation, canceled, value, velocity) -> {
+ SpringAnimation springAnim = new SpringAnimation(object, property)
+ .setStartVelocity(velocity)
+ .setSpring(new SpringForce(targetPosition)
+ .setStiffness(SPRING_STIFFNESS)
+ .setDampingRatio(SPRING_DAMPING));
+ springAnim.addEndListener(onEndListener);
+ springAnim.start();
+ }));
+ }
+
+ public void start() {
+ mFlingAnim.start();
+ }
+}
diff --git a/src/com/android/launcher3/anim/SpringObjectAnimator.java b/src/com/android/launcher3/anim/SpringObjectAnimator.java
index cc70e32..f74590b 100644
--- a/src/com/android/launcher3/anim/SpringObjectAnimator.java
+++ b/src/com/android/launcher3/anim/SpringObjectAnimator.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.anim;
+import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -32,8 +34,6 @@
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
-
/**
* This animator allows for an object's property to be be controlled by an {@link ObjectAnimator} or
* a {@link SpringAnimation}. It extends ValueAnimator so it can be used in an AnimatorSet.
@@ -51,9 +51,9 @@
private SpringProperty<T> mProperty;
private ArrayList<AnimatorListener> mListeners;
- private boolean mSpringEnded = false;
- private boolean mAnimatorEnded = false;
- private boolean mEnded = false;
+ private boolean mSpringEnded = true;
+ private boolean mAnimatorEnded = true;
+ private boolean mEnded = true;
private static final FloatPropertyCompat<ProgressInterface> sFloatProperty =
new FloatPropertyCompat<ProgressInterface>("springObjectAnimator") {
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index e5c70da..2a5418d 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.views;
+import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -55,8 +57,6 @@
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
-import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
-
/**
* A view that is created to look like another view with the purpose of creating fluid animations.
*/
@@ -143,9 +143,6 @@
setBackgroundDrawableBounds(bgScale);
mRevealAnimator.setCurrentFraction(shapeRevealProgress);
- if (Float.compare(shapeRevealProgress, 1f) >= 0f) {
- mRevealAnimator.end();
- }
}
invalidate();
invalidateOutline();
@@ -160,6 +157,9 @@
@Override
public void onAnimationEnd(Animator animator) {
+ if (mRevealAnimator != null) {
+ mRevealAnimator.end();
+ }
if (mEndRunnable != null) {
mEndRunnable.run();
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 1353a23..122151e 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -44,6 +44,13 @@
return LauncherInstrumentation.ContainerType.ALL_APPS;
}
+ private boolean hasClickableIcon(UiObject2 allAppsContainer, BySelector appIconSelector) {
+ final UiObject2 icon = allAppsContainer.findObject(appIconSelector);
+ if (icon == null) return false;
+ final UiObject2 navBar = mLauncher.waitForSystemUiObject("navigation_bar_frame");
+ return icon.getVisibleBounds().bottom < navBar.getVisibleBounds().top;
+ }
+
/**
* Finds an icon. Fails if the icon doesn't exist. Scrolls the app list when needed to make
* sure the icon is visible.
@@ -55,10 +62,10 @@
public AppIcon getAppIcon(String appName) {
final UiObject2 allAppsContainer = verifyActiveContainer();
final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher);
- if (!allAppsContainer.hasObject(appIconSelector)) {
+ if (!hasClickableIcon(allAppsContainer, appIconSelector)) {
scrollBackToBeginning();
int attempts = 0;
- while (!allAppsContainer.hasObject(appIconSelector) &&
+ while (!hasClickableIcon(allAppsContainer, appIconSelector) &&
allAppsContainer.scroll(Direction.DOWN, 0.8f)) {
LauncherInstrumentation.assertTrue(
"Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,