diff --git a/proguard.flags b/proguard.flags
index cac8930d5d..086337dfa2 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -39,7 +39,7 @@
public int getY();
}
--keep class com.android.launcher3.dragndrop.DragLayer$LayoutParams {
+-keep class com.android.launcher3.views.BaseDragLayer$LayoutParams {
public void setWidth(int);
public int getWidth();
public void setHeight(int);
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index d531a463b0..8b28597dd1 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -47,7 +47,21 @@
+ android:exported="true"
+ android:excludeFromRecents="true" />
+
+
+
+
+
+
+
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 9006831b02..e414fa033b 100644
Binary files a/quickstep/libs/sysui_shared.jar and b/quickstep/libs/sysui_shared.jar differ
diff --git a/quickstep/res/drawable-hdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-hdpi/recents_horizontal_scrim_left.png
deleted file mode 100644
index d4f995dfb1..0000000000
Binary files a/quickstep/res/drawable-hdpi/recents_horizontal_scrim_left.png and /dev/null differ
diff --git a/quickstep/res/drawable-hdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-hdpi/recents_horizontal_scrim_right.png
deleted file mode 100644
index 9013c1a2fb..0000000000
Binary files a/quickstep/res/drawable-hdpi/recents_horizontal_scrim_right.png and /dev/null differ
diff --git a/quickstep/res/drawable-mdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-mdpi/recents_horizontal_scrim_left.png
deleted file mode 100644
index 6e924ecbd9..0000000000
Binary files a/quickstep/res/drawable-mdpi/recents_horizontal_scrim_left.png and /dev/null differ
diff --git a/quickstep/res/drawable-mdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-mdpi/recents_horizontal_scrim_right.png
deleted file mode 100644
index 33d0edd787..0000000000
Binary files a/quickstep/res/drawable-mdpi/recents_horizontal_scrim_right.png and /dev/null differ
diff --git a/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_left.png
deleted file mode 100644
index 20c85e6711..0000000000
Binary files a/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_left.png and /dev/null differ
diff --git a/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_right.png
deleted file mode 100644
index 58a1ca07bf..0000000000
Binary files a/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_right.png and /dev/null differ
diff --git a/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_left.png
deleted file mode 100644
index 9d3dc318b9..0000000000
Binary files a/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_left.png and /dev/null differ
diff --git a/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_right.png
deleted file mode 100644
index 7fb248b9fa..0000000000
Binary files a/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_right.png and /dev/null differ
diff --git a/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_left.png
deleted file mode 100644
index 49ec7aa61c..0000000000
Binary files a/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_left.png and /dev/null differ
diff --git a/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_right.png
deleted file mode 100644
index a8922e2381..0000000000
Binary files a/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_right.png and /dev/null differ
diff --git a/quickstep/res/layout/fallback_recents_activity.xml b/quickstep/res/layout/fallback_recents_activity.xml
index c41684455b..b3fc4ed58c 100644
--- a/quickstep/res/layout/fallback_recents_activity.xml
+++ b/quickstep/res/layout/fallback_recents_activity.xml
@@ -15,15 +15,17 @@
-->
+ android:clipToPadding="false"
+ android:theme="@style/HomeScreenElementTheme" />
\ No newline at end of file
diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml
index 54a90cfe84..89e057148f 100644
--- a/quickstep/res/layout/overview_panel.xml
+++ b/quickstep/res/layout/overview_panel.xml
@@ -21,7 +21,7 @@
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
- android:alpha="0.0"
- android:visibility="invisible" >
+ android:visibility="invisible"
+ android:focusableInTouchMode="true" >
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 849719191c..b751e0d9c9 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -22,7 +22,6 @@
2dp
20dp
10dp
- 100dp
@@ -34,7 +33,7 @@
25dp
80dp
- 120dp
+ 140dp
80dp
150%
diff --git a/quickstep/res/xml/indexable_launcher_prefs.xml b/quickstep/res/xml/indexable_launcher_prefs.xml
new file mode 100644
index 0000000000..2655402015
--- /dev/null
+++ b/quickstep/res/xml/indexable_launcher_prefs.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 872e6ca020..f91933979e 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -15,27 +15,92 @@
*/
package com.android.launcher3;
+import static com.android.systemui.shared.recents.utilities.Utilities
+ .postAtFrontOfQueueAsynchronously;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.os.Handler;
+import android.support.annotation.BinderThread;
+import android.support.annotation.UiThread;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
+@TargetApi(Build.VERSION_CODES.P)
+public abstract class LauncherAnimationRunner extends AnimatorListenerAdapter
+ implements RemoteAnimationRunnerCompat {
-public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat {
+ private static final int REFRESH_RATE_MS = 16;
- AnimatorSet mAnimator;
- private Launcher mLauncher;
+ private final Handler mHandler;
- LauncherAnimationRunner(Launcher launcher) {
- mLauncher = launcher;
+ private Runnable mSysFinishRunnable;
+
+ private AnimatorSet mAnimator;
+
+ public LauncherAnimationRunner(Handler handler) {
+ mHandler = handler;
}
+ @BinderThread
+ @Override
+ public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats, Runnable runnable) {
+ postAtFrontOfQueueAsynchronously(mHandler, () -> {
+ // Finish any previous animation
+ finishSystemAnimation();
+
+ mSysFinishRunnable = runnable;
+ mAnimator = getAnimator(targetCompats);
+ if (mAnimator == null) {
+ finishSystemAnimation();
+ return;
+ }
+ mAnimator.addListener(this);
+ mAnimator.start();
+ // Because t=0 has the app icon in its original spot, we can skip the
+ // first frame and have the same movement one frame earlier.
+ mAnimator.setCurrentPlayTime(REFRESH_RATE_MS);
+
+ });
+ }
+
+
+ @UiThread
+ public abstract AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats);
+
+ @UiThread
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (animation == mAnimator) {
+ mAnimator = null;
+ finishSystemAnimation();
+ }
+ }
+
+ /**
+ * Called by the system
+ */
+ @BinderThread
@Override
public void onAnimationCancelled() {
- postAtFrontOfQueueAsynchronously(mLauncher.getWindow().getDecorView().getHandler(), () -> {
+ postAtFrontOfQueueAsynchronously(mHandler, () -> {
if (mAnimator != null) {
- mAnimator.cancel();
+ mAnimator.removeListener(this);
+ mAnimator.end();
+ mAnimator = null;
}
});
}
+
+ @UiThread
+ private void finishSystemAnimation() {
+ if (mSysFinishRunnable != null) {
+ mSysFinishRunnable.run();
+ mSysFinishRunnable = null;
+ }
+ }
}
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index ba0cbfa77d..5a090d9e4c 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -21,7 +21,6 @@ import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber;
import static com.android.systemui.shared.recents.utilities.Utilities.getSurface;
-import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
@@ -41,6 +40,7 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.view.Surface;
import android.view.View;
@@ -80,7 +80,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
implements OnDeviceProfileChangeListener {
private static final String TAG = "LauncherTransition";
- private static final int REFRESH_RATE_MS = 16;
private static final int STATUS_BAR_TRANSITION_DURATION = 120;
private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION =
@@ -99,7 +98,9 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
private final DragLayer mDragLayer;
private final Launcher mLauncher;
- private DeviceProfile mDeviceProfile;
+
+ private final Handler mHandler;
+ private final boolean mIsRtl;
private final float mContentTransY;
private final float mWorkspaceTransY;
@@ -107,17 +108,23 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
private final float mRecentsTransY;
private final float mRecentsScale;
+ private DeviceProfile mDeviceProfile;
private View mFloatingView;
- private boolean mIsRtl;
- private LauncherTransitionAnimator mCurrentAnimator;
+ private final AnimatorListenerAdapter mReapplyStateListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mLauncher.getStateManager().reapplyState();
+ }
+ };
public LauncherAppTransitionManagerImpl(Context context) {
mLauncher = Launcher.getLauncher(context);
mDragLayer = mLauncher.getDragLayer();
+ mHandler = new Handler(Looper.getMainLooper());
+ mIsRtl = Utilities.isRtl(mLauncher.getResources());
mDeviceProfile = mLauncher.getDeviceProfile();
- mIsRtl = Utilities.isRtl(mLauncher.getResources());
Resources res = mLauncher.getResources();
mContentTransY = res.getDimensionPixelSize(R.dimen.content_trans_y);
@@ -135,26 +142,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
mDeviceProfile = dp;
}
- private void setCurrentAnimator(LauncherTransitionAnimator animator) {
- if (isAnimating()) {
- mCurrentAnimator.cancel();
- }
- mCurrentAnimator = animator;
- }
-
- @Override
- public void finishLauncherAnimation() {
- if (isAnimating()) {
- mCurrentAnimator.finishLauncherAnimation();
- }
- mCurrentAnimator = null;
- }
-
- @Override
- public boolean isAnimating() {
- return mCurrentAnimator != null && mCurrentAnimator.isRunning();
- }
-
/**
* @return ActivityOptions with remote animations that controls how the window of the opening
* targets are displayed.
@@ -162,58 +149,26 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
@Override
public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
if (hasControlRemoteAppTransitionPermission()) {
- TaskView taskView = findTaskViewToLaunch(launcher, v);
try {
- RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mLauncher) {
+ RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler) {
+
@Override
- public void onAnimationStart(RemoteAnimationTargetCompat[] targets,
- Runnable finishedCallback) {
- // Post at front of queue ignoring sync barriers to make sure it gets
- // processed before the next frame.
- postAtFrontOfQueueAsynchronously(v.getHandler(), () -> {
- final boolean removeTrackingView;
- LauncherTransitionAnimator animator = composeRecentsLaunchAnimator(
- taskView == null ? v : taskView, targets);
- if (animator != null) {
- // We are animating the task view directly, do not remove it after
- removeTrackingView = false;
- } else {
- animator = composeAppLaunchAnimator(v, targets);
- // A new floating view is created for the animation, remove it after
- removeTrackingView = true;
- }
-
- setCurrentAnimator(animator);
- mAnimator = animator.getAnimatorSet();
- mAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // Reset launcher to normal state
- v.setVisibility(View.VISIBLE);
- if (removeTrackingView) {
- ((ViewGroup) mDragLayer.getParent()).removeView(
- mFloatingView);
- }
-
- mDragLayer.setAlpha(1f);
- mDragLayer.setTranslationY(0f);
-
- View appsView = mLauncher.getAppsView();
- appsView.setAlpha(1f);
- appsView.setTranslationY(0f);
-
- finishedCallback.run();
- }
- });
- mAnimator.start();
- // Because t=0 has the app icon in its original spot, we can skip the
- // first frame and have the same movement one frame earlier.
- mAnimator.setCurrentPlayTime(REFRESH_RATE_MS);
- });
+ public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
+ Animator[] anims = composeRecentsLaunchAnimator(v, targetCompats);
+ AnimatorSet anim = new AnimatorSet();
+ if (anims != null) {
+ anim.playTogether(anims);
+ } else {
+ anim.play(getLauncherAnimators(v, targetCompats));
+ anim.play(getWindowAnimators(v, targetCompats));
+ }
+ mLauncher.getStateManager().setCurrentAnimation(anim);
+ return anim;
}
};
- int duration = taskView != null ? RECENTS_LAUNCH_DURATION : APP_LAUNCH_DURATION;
+ int duration = findTaskViewToLaunch(launcher, v, null) != null
+ ? RECENTS_LAUNCH_DURATION : APP_LAUNCH_DURATION;
int statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION;
return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
runner, duration, statusBarTransitionDelay));
@@ -232,18 +187,19 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
* Otherwise, we will assume we are using a normal app transition, but it's possible that the
* opening remote target (which we don't get until onAnimationStart) will resolve to a TaskView.
*/
- private TaskView findTaskViewToLaunch(Launcher launcher, View v) {
+ private TaskView findTaskViewToLaunch(
+ BaseDraggingActivity activity, View v, RemoteAnimationTargetCompat[] targets) {
if (v instanceof TaskView) {
return (TaskView) v;
}
- if (!launcher.isInState(LauncherState.OVERVIEW)) {
- return null;
- }
+ RecentsView recentsView = activity.getOverviewPanel();
+
+ // It's possible that the launched view can still be resolved to a visible task view, check
+ // the task id of the opening task and see if we can find a match.
if (v.getTag() instanceof ItemInfo) {
ItemInfo itemInfo = (ItemInfo) v.getTag();
ComponentName componentName = itemInfo.getTargetComponent();
if (componentName != null) {
- RecentsView recentsView = launcher.getOverviewPanel();
for (int i = 0; i < recentsView.getChildCount(); i++) {
TaskView taskView = (TaskView) recentsView.getPageAt(i);
if (recentsView.isTaskViewVisible(taskView)) {
@@ -255,32 +211,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
}
}
}
- return null;
- }
- /**
- * Composes the animations for a launch from the recents list if possible.
- */
- private LauncherTransitionAnimator composeRecentsLaunchAnimator(View v,
- RemoteAnimationTargetCompat[] targets) {
- RecentsView recentsView = mLauncher.getOverviewPanel();
- boolean launcherClosing = launcherIsATargetWithMode(targets, MODE_CLOSING);
- MutableBoolean skipLauncherChanges = new MutableBoolean(!launcherClosing);
- if (v instanceof TaskView) {
- // We already found a task view to launch, so use that for the animation.
- TaskView taskView = (TaskView) v;
- return new LauncherTransitionAnimator(getRecentsLauncherAnimator(recentsView, taskView),
- getRecentsWindowAnimator(taskView, skipLauncherChanges, targets));
- }
-
- // It's possible that the launched view can still be resolved to a visible task view, check
- // the task id of the opening task and see if we can find a match.
-
- // Ensure recents is actually visible
- if (!mLauncher.getStateManager().getState().overviewUi) {
+ if (targets == null) {
return null;
}
-
// Resolve the opening task id
int openingTaskId = -1;
for (RemoteAnimationTargetCompat target : targets) {
@@ -301,19 +235,35 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
if (taskView == null || !recentsView.isTaskViewVisible(taskView)) {
return null;
}
+ return taskView;
+ }
+
+ /**
+ * Composes the animations for a launch from the recents list if possible.
+ */
+ private Animator[] composeRecentsLaunchAnimator(View v,
+ RemoteAnimationTargetCompat[] targets) {
+ // Ensure recents is actually visible
+ if (!mLauncher.getStateManager().getState().overviewUi) {
+ return null;
+ }
+
+ RecentsView recentsView = mLauncher.getOverviewPanel();
+ boolean launcherClosing = launcherIsATargetWithMode(targets, MODE_CLOSING);
+ boolean skipLauncherChanges = !launcherClosing;
+
+ TaskView taskView = findTaskViewToLaunch(mLauncher, v, targets);
+ if (taskView == null) {
+ return null;
+ }
// Found a visible recents task that matches the opening app, lets launch the app from there
Animator launcherAnim;
- AnimatorListenerAdapter windowAnimEndListener;
+ final AnimatorListenerAdapter windowAnimEndListener;
if (launcherClosing) {
launcherAnim = getRecentsLauncherAnimator(recentsView, taskView);
- windowAnimEndListener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // Make sure recents gets fixed up by resetting task alphas and scales, etc.
- mLauncher.getStateManager().reapplyState();
- }
- };
+ // Make sure recents gets fixed up by resetting task alphas and scales, etc.
+ windowAnimEndListener = mReapplyStateListener;
} else {
AnimatorPlaybackController controller =
mLauncher.getStateManager()
@@ -330,7 +280,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
Animator windowAnim = getRecentsWindowAnimator(taskView, skipLauncherChanges, targets);
windowAnim.addListener(windowAnimEndListener);
- return new LauncherTransitionAnimator(launcherAnim, windowAnim, skipLauncherChanges);
+ return new Animator[] {launcherAnim, windowAnim};
}
/**
@@ -372,26 +322,24 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
} else {
// We are launching an adjacent task, so parallax the center and other adjacent task.
TaskView centerTask = (TaskView) recentsView.getPageAt(centerTaskIndex);
- float translationX = Math.abs(v.getTranslationX());
- ObjectAnimator centerTaskParallaxToRight =
+ float translationX = mRecentsTransX / 2;
+ ObjectAnimator centerTaskParallaxOffscreen =
LauncherAnimUtils.ofPropertyValuesHolder(centerTask,
new PropertyListBuilder()
- .scale(v.getScaleX())
.translationX(isRtl ? -translationX : translationX)
.build());
- launcherAnimator.play(centerTaskParallaxToRight);
+ launcherAnimator.play(centerTaskParallaxOffscreen);
int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex);
if (otherAdjacentTaskIndex >= 0
&& otherAdjacentTaskIndex < recentsView.getPageCount()) {
TaskView otherAdjacentTask = (TaskView) recentsView.getPageAt(
otherAdjacentTaskIndex);
- ObjectAnimator otherAdjacentTaskParallaxToRight =
+ ObjectAnimator otherAdjacentTaskParallaxOffscreen =
LauncherAnimUtils.ofPropertyValuesHolder(otherAdjacentTask,
new PropertyListBuilder()
- .translationX(otherAdjacentTask.getTranslationX()
- + (isRtl ? -translationX : translationX))
+ .translationX(isRtl ? -translationX : translationX)
.build());
- launcherAnimator.play(otherAdjacentTaskParallaxToRight);
+ launcherAnimator.play(otherAdjacentTaskParallaxOffscreen);
}
}
@@ -420,7 +368,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
* @return Animator that controls the window of the opening targets for the recents launch
* animation.
*/
- private ValueAnimator getRecentsWindowAnimator(TaskView v, MutableBoolean skipLauncherChanges,
+ private ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipLauncherChanges,
RemoteAnimationTargetCompat[] targets) {
Rect taskViewBounds = new Rect();
mDragLayer.getDescendantRectRelativeToSelf(v, taskViewBounds);
@@ -456,7 +404,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
final float percent = animation.getAnimatedFraction();
TaskWindowBounds tw = recentsInterpolator.interpolate(percent);
- if (!skipLauncherChanges.value) {
+ if (!skipLauncherChanges) {
v.setScaleX(tw.taskScale);
v.setScaleY(tw.taskScale);
v.setTranslationX(tw.taskX);
@@ -471,9 +419,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
crop.set(tw.winCrop);
// Fade in the app window.
- float alphaDelay = 0;
float alphaDuration = 75;
- float alpha = getValue(0f, 1f, alphaDelay, alphaDuration,
+ float alpha = getValue(0f, 1f, 0, alphaDuration,
appAnimator.getDuration() * percent, Interpolators.LINEAR);
TransactionCompat t = new TransactionCompat();
@@ -487,7 +434,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
t.setMatrix(target.leash, matrix);
t.setWindowCrop(target.leash, crop);
- if (!skipLauncherChanges.value) {
+ if (!skipLauncherChanges) {
t.deferTransactionUntil(target.leash, surface, frameNumber);
}
}
@@ -504,15 +451,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
return appAnimator;
}
- /**
- * Composes the animations for a launch from an app icon.
- */
- private LauncherTransitionAnimator composeAppLaunchAnimator(View v,
- RemoteAnimationTargetCompat[] targets) {
- return new LauncherTransitionAnimator(getLauncherAnimators(v, targets),
- getWindowAnimators(v, targets));
- }
-
/**
* @return Animators that control the movements of the Launcher and icon of the opening target.
*/
@@ -543,7 +481,9 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
if (mLauncher.isInState(LauncherState.ALL_APPS) && !mDeviceProfile.isVerticalBarLayout()) {
// All Apps in portrait mode is full screen, so we only animate AllAppsContainerView.
- View appsView = mLauncher.getAppsView();
+ final View appsView = mLauncher.getAppsView();
+ final float startAlpha = appsView.getAlpha();
+ final float startY = appsView.getTranslationY();
appsView.setAlpha(alphas[0]);
appsView.setTranslationY(trans[0]);
@@ -556,6 +496,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
launcherAnimator.play(alpha);
launcherAnimator.play(transY);
+
+ launcherAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ appsView.setAlpha(startAlpha);
+ appsView.setTranslationY(startY);
+ }
+ });
} else {
mDragLayer.setAlpha(alphas[0]);
mDragLayer.setTranslationY(trans[0]);
@@ -570,6 +518,13 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
launcherAnimator.play(dragLayerAlpha);
launcherAnimator.play(dragLayerTransY);
+ launcherAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDragLayer.setAlpha(1);
+ mDragLayer.setTranslationY(0);
+ }
+ });
}
return launcherAnimator;
}
@@ -588,22 +543,19 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
// Position the floating view exactly on top of the original
Rect rect = new Rect();
- final boolean isDeepShortcutTextView = v instanceof DeepShortcutTextView
- && v.getParent() != null && v.getParent() instanceof DeepShortcutView;
- if (isDeepShortcutTextView) {
- // Deep shortcut views have their icon drawn in a sibling view.
+ final boolean fromDeepShortcutView = v.getParent() instanceof DeepShortcutView;
+ if (fromDeepShortcutView) {
+ // Deep shortcut views have their icon drawn in a separate view.
DeepShortcutView view = (DeepShortcutView) v.getParent();
mDragLayer.getDescendantRectRelativeToSelf(view.getIconView(), rect);
} else {
mDragLayer.getDescendantRectRelativeToSelf(v, rect);
}
- final int viewLocationStart = mIsRtl
- ? mDeviceProfile.widthPx - rect.right
- : rect.left;
- final int viewLocationTop = rect.top;
+ int viewLocationLeft = rect.left;
+ int viewLocationTop = rect.top;
float startScale = 1f;
- if (isBubbleTextView && !isDeepShortcutTextView) {
+ if (isBubbleTextView && !fromDeepShortcutView) {
BubbleTextView btv = (BubbleTextView) v;
btv.getIconBounds(rect);
Drawable dr = btv.getIcon();
@@ -613,12 +565,24 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
} else {
rect.set(0, 0, rect.width(), rect.height());
}
+ viewLocationLeft += rect.left;
+ viewLocationTop += rect.top;
+ int viewLocationStart = mIsRtl
+ ? mDeviceProfile.widthPx - rect.right
+ : viewLocationLeft;
LayoutParams lp = new LayoutParams(rect.width(), rect.height());
lp.ignoreInsets = true;
- lp.setMarginStart(viewLocationStart + rect.left);
- lp.topMargin = viewLocationTop + rect.top;
+ lp.setMarginStart(viewLocationStart);
+ lp.topMargin = viewLocationTop;
mFloatingView.setLayoutParams(lp);
+ // Set the properties here already to make sure they'are available when running the first
+ // animation frame.
+ mFloatingView.setLeft(viewLocationLeft);
+ mFloatingView.setTop(viewLocationTop);
+ mFloatingView.setRight(viewLocationLeft + rect.width());
+ mFloatingView.setBottom(viewLocationTop + rect.height());
+
// Swap the two views in place.
((ViewGroup) mDragLayer.getParent()).addView(mFloatingView);
v.setVisibility(View.INVISIBLE);
@@ -663,6 +627,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
alpha.setInterpolator(Interpolators.LINEAR);
appIconAnimatorSet.play(alpha);
+ appIconAnimatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Reset launcher to normal state
+ v.setVisibility(View.VISIBLE);
+ ((ViewGroup) mDragLayer.getParent()).removeView(mFloatingView);
+ }
+ });
return appIconAnimatorSet;
}
@@ -671,10 +643,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
*/
private ValueAnimator getWindowAnimators(View v, RemoteAnimationTargetCompat[] targets) {
Rect bounds = new Rect();
- boolean isDeepShortcutTextView = v instanceof DeepShortcutTextView
- && v.getParent() != null && v.getParent() instanceof DeepShortcutView;
- if (isDeepShortcutTextView) {
- // Deep shortcut views have their icon drawn in a sibling view.
+ if (v.getParent() instanceof DeepShortcutView) {
+ // Deep shortcut views have their icon drawn in a separate view.
DeepShortcutView view = (DeepShortcutView) v.getParent();
mDragLayer.getDescendantRectRelativeToSelf(view.getIconView(), bounds);
} else if (v instanceof BubbleTextView) {
@@ -728,9 +698,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
matrix.postTranslate(transX0, transY0);
// Fade in the app window.
- float alphaDelay = 0;
float alphaDuration = 60;
- float alpha = getValue(0f, 1f, alphaDelay, alphaDuration,
+ float alpha = getValue(0f, 1f, 0, alphaDuration,
appAnimator.getDuration() * percent, Interpolators.LINEAR);
// Animate the window crop so that it starts off as a square, and then reveals
@@ -775,6 +744,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
try {
RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat();
definition.addRemoteAnimation(WindowManagerWrapper.TRANSIT_WALLPAPER_OPEN,
+ WindowManagerWrapper.ACTIVITY_TYPE_STANDARD,
new RemoteAnimationAdapterCompat(getWallpaperOpenRunner(),
CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
@@ -802,40 +772,25 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
* ie. pressing home, swiping up from nav bar.
*/
private RemoteAnimationRunnerCompat getWallpaperOpenRunner() {
- return new LauncherAnimationRunner(mLauncher) {
+ return new LauncherAnimationRunner(mHandler) {
@Override
- public void onAnimationStart(RemoteAnimationTargetCompat[] targets,
- Runnable finishedCallback) {
- Handler handler = mLauncher.getWindow().getDecorView().getHandler();
- postAtFrontOfQueueAsynchronously(handler, () -> {
- if ((Utilities.getPrefs(mLauncher)
- .getBoolean("pref_use_screenshot_for_swipe_up", false)
- && mLauncher.getStateManager().getState().overviewUi)
- || !launcherIsATargetWithMode(targets, MODE_OPENING)) {
- // We use a separate transition for Overview mode. And we can skip the
- // animation in cases where Launcher is not in the set of opening targets.
- // This can happen when Launcher is already visible. ie. Closing a dialog.
- setCurrentAnimator(null);
- finishedCallback.run();
- return;
- }
+ public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
+ if (mLauncher.getStateManager().getState().overviewUi) {
+ // We use a separate transition for Overview mode.
+ return null;
+ }
- LauncherTransitionAnimator animator = new LauncherTransitionAnimator(
- getLauncherResumeAnimation(), getClosingWindowAnimators(targets));
- setCurrentAnimator(animator);
- mAnimator = animator.getAnimatorSet();
- mAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- finishedCallback.run();
- }
- });
- mAnimator.start();
+ AnimatorSet anim = new AnimatorSet();
+ anim.play(getClosingWindowAnimators(targetCompats));
- // Because t=0 has the app icon in its original spot, we can skip the
- // first frame and have the same movement one frame earlier.
- mAnimator.setCurrentPlayTime(REFRESH_RATE_MS);
- });
+ if (launcherIsATargetWithMode(targetCompats, MODE_OPENING)) {
+ AnimatorSet contentAnimation = getLauncherResumeAnimation();
+ anim.play(contentAnimation);
+
+ // Only register the content animation for cancellation when state changes
+ mLauncher.getStateManager().setCurrentAnimation(contentAnimation);
+ }
+ return anim;
}
};
}
@@ -906,12 +861,17 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
return contentAnimator;
} else {
AnimatorSet workspaceAnimator = new AnimatorSet();
+
mLauncher.getWorkspace().setTranslationY(mWorkspaceTransY);
- mLauncher.getWorkspace().setAlpha(0f);
workspaceAnimator.play(ObjectAnimator.ofFloat(mLauncher.getWorkspace(),
View.TRANSLATION_Y, mWorkspaceTransY, 0));
- workspaceAnimator.play(ObjectAnimator.ofFloat(mLauncher.getWorkspace(), View.ALPHA,
- 0, 1f));
+
+ View currentPage = ((CellLayout) mLauncher.getWorkspace()
+ .getChildAt(mLauncher.getWorkspace().getCurrentPage()))
+ .getShortcutsAndWidgets();
+ currentPage.setAlpha(0f);
+ workspaceAnimator.play(ObjectAnimator.ofFloat(currentPage, View.ALPHA, 0, 1f));
+
workspaceAnimator.setStartDelay(LAUNCHER_RESUME_START_DELAY);
workspaceAnimator.setDuration(333);
workspaceAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
@@ -939,6 +899,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
AnimatorSet resumeLauncherAnimation = new AnimatorSet();
resumeLauncherAnimation.play(workspaceAnimator);
resumeLauncherAnimation.playSequentially(allAppsSlideIn, allAppsOvershoot);
+
+ resumeLauncherAnimation.addListener(mReapplyStateListener);
return resumeLauncherAnimation;
}
}
diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java
new file mode 100644
index 0000000000..0d1038a2d9
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+
+import com.android.launcher3.states.InternalStateHandler;
+import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
+
+import java.util.function.BiPredicate;
+
+@TargetApi(Build.VERSION_CODES.P)
+public class LauncherInitListener extends InternalStateHandler implements ActivityInitListener {
+
+ private final BiPredicate mOnInitListener;
+
+ public LauncherInitListener(BiPredicate onInitListener) {
+ mOnInitListener = onInitListener;
+ }
+
+ @Override
+ protected boolean init(Launcher launcher, boolean alreadyOnHome) {
+ // For the duration of the gesture, lock the screen orientation to ensure that we do not
+ // rotate mid-quickscrub
+ launcher.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK);
+ return mOnInitListener.test(launcher, alreadyOnHome);
+ }
+
+ @Override
+ public void register() {
+ initWhenReady();
+ }
+
+ @Override
+ public void unregister() {
+ clearReference();
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java b/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java
deleted file mode 100644
index ab9234b516..0000000000
--- a/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2018 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;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-
-/**
- * Creates an AnimatorSet consisting on one Animator for Launcher transition, and one Animator for
- * the Window transitions.
- *
- * Allows for ending the Launcher animator without ending the Window animator.
- */
-public class LauncherTransitionAnimator {
-
- private final MutableBoolean mLauncherAnimCancelState;
-
- private AnimatorSet mAnimatorSet;
- private Animator mLauncherAnimator;
- private Animator mWindowAnimator;
-
- LauncherTransitionAnimator(Animator launcherAnimator, Animator windowAnimator) {
- this(launcherAnimator, windowAnimator, new MutableBoolean(false));
- }
-
-
- LauncherTransitionAnimator(Animator launcherAnimator, Animator windowAnimator,
- MutableBoolean launcherAnimCancelState) {
- mLauncherAnimCancelState = launcherAnimCancelState;
- if (launcherAnimator != null) {
- mLauncherAnimator = launcherAnimator;
- }
- mWindowAnimator = windowAnimator;
-
- mAnimatorSet = new AnimatorSet();
- if (launcherAnimator != null) {
- mAnimatorSet.play(launcherAnimator);
- }
- mAnimatorSet.play(windowAnimator);
- }
-
- public AnimatorSet getAnimatorSet() {
- return mAnimatorSet;
- }
-
- public void cancel() {
- mAnimatorSet.cancel();
- mLauncherAnimCancelState.value = true;
- }
-
- public boolean isRunning() {
- return mAnimatorSet.isRunning();
- }
-
- public void finishLauncherAnimation() {
- if (mLauncherAnimator != null) {
- mLauncherAnimCancelState.value = true;
- mLauncherAnimator.end();
- }
- }
-}
diff --git a/quickstep/src/com/android/launcher3/MutableBoolean.java b/quickstep/src/com/android/launcher3/MutableBoolean.java
deleted file mode 100644
index 75382171af..0000000000
--- a/quickstep/src/com/android/launcher3/MutableBoolean.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2018 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;
-
-public class MutableBoolean {
- public boolean value;
-
- public MutableBoolean(boolean value) {
- this.value = value;
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
index 31261d9853..2626e7cccc 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
@@ -24,7 +24,6 @@ import android.view.View;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -33,8 +32,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
*/
public class AllAppsState extends LauncherState {
- private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY
- | FLAG_SHOW_SCRIM | FLAG_ALL_APPS_SCRIM;
+ private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY | FLAG_ALL_APPS_SCRIM;
private static final PageAlphaProvider PAGE_ALPHA_PROVIDER = new PageAlphaProvider(DEACCEL_2) {
@Override
@@ -85,8 +83,15 @@ public class AllAppsState extends LauncherState {
}
@Override
- public float getHoseatAlpha(Launcher launcher) {
- return 0;
+ public int getVisibleElements(Launcher launcher) {
+ return ALL_APPS_HEADER | ALL_APPS_HEADER_EXTRA | ALL_APPS_CONTENT;
+ }
+
+ @Override
+ public float[] getOverviewTranslationFactor(Launcher launcher) {
+ // Keep the same translation as in overview, so that we don't slide around when
+ // transitioning to All Apps.
+ return LauncherState.OVERVIEW.getOverviewTranslationFactor(launcher);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/DragPauseDetector.java b/quickstep/src/com/android/launcher3/uioverrides/DragPauseDetector.java
deleted file mode 100644
index 6df1aba01d..0000000000
--- a/quickstep/src/com/android/launcher3/uioverrides/DragPauseDetector.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2017 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.uioverrides;
-
-import com.android.launcher3.Alarm;
-import com.android.launcher3.OnAlarmListener;
-
-/**
- * Utility class to detect a pause during a drag.
- */
-public class DragPauseDetector implements OnAlarmListener {
-
- private static final float MAX_VELOCITY_TO_PAUSE = 0.2f;
- private static final long PAUSE_DURATION = 100;
-
- private final Alarm mAlarm;
- private final Runnable mOnPauseCallback;
-
- private boolean mTriggered = false;
- private int mDisabledFlags = 0;
-
- public DragPauseDetector(Runnable onPauseCallback) {
- mOnPauseCallback = onPauseCallback;
-
- mAlarm = new Alarm();
- mAlarm.setOnAlarmListener(this);
- mAlarm.setAlarm(PAUSE_DURATION);
- }
-
- public void onDrag(float velocity) {
- if (mTriggered || !isEnabled()) {
- return;
- }
-
- if (Math.abs(velocity) > MAX_VELOCITY_TO_PAUSE) {
- // Cancel any previous alarm and set a new alarm
- mAlarm.setAlarm(PAUSE_DURATION);
- }
- }
-
- @Override
- public void onAlarm(Alarm alarm) {
- if (!mTriggered && isEnabled()) {
- mTriggered = true;
- mOnPauseCallback.run();
- }
- }
-
- public boolean isTriggered () {
- return mTriggered;
- }
-
- public boolean isEnabled() {
- return mDisabledFlags == 0;
- }
-
- public void addDisabledFlags(int flags) {
- boolean wasEnabled = isEnabled();
- mDisabledFlags |= flags;
- resetAlarm(wasEnabled);
- }
-
- public void clearDisabledFlags(int flags) {
- boolean wasEnabled = isEnabled();
- mDisabledFlags &= ~flags;
- resetAlarm(wasEnabled);
- }
-
- private void resetAlarm(boolean wasEnabled) {
- boolean isEnabled = isEnabled();
- if (wasEnabled == isEnabled) {
- // Nothing has changed
- } if (isEnabled && !mTriggered) {
- mAlarm.setAlarm(PAUSE_DURATION);
- } else if (!isEnabled) {
- mAlarm.cancelAlarm();
- }
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
deleted file mode 100644
index 97ac3e6069..0000000000
--- a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2018 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.uioverrides;
-
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.touch.SwipeDetector.DIRECTION_NEGATIVE;
-import static com.android.launcher3.touch.SwipeDetector.DIRECTION_POSITIVE;
-import static com.android.launcher3.touch.SwipeDetector.HORIZONTAL;
-import static com.android.launcher3.touch.SwipeDetector.VERTICAL;
-import static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR;
-
-import android.graphics.Rect;
-import android.metrics.LogMaker;
-import android.view.MotionEvent;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import com.android.launcher3.util.VerticalSwipeController;
-import com.android.quickstep.views.RecentsView;
-
-class EventLogTags {
- private EventLogTags() {
- } // don't instantiate
-
- /** 524292 sysui_multi_action (content|4) */
- public static final int SYSUI_MULTI_ACTION = 524292;
-
- public static void writeSysuiMultiAction(Object[] content) {
- android.util.EventLog.writeEvent(SYSUI_MULTI_ACTION, content);
- }
-}
-
-class MetricsLogger {
- private static MetricsLogger sMetricsLogger;
-
- private static MetricsLogger getLogger() {
- if (sMetricsLogger == null) {
- sMetricsLogger = new MetricsLogger();
- }
- return sMetricsLogger;
- }
-
- protected void saveLog(Object[] rep) {
- EventLogTags.writeSysuiMultiAction(rep);
- }
-
- public void write(LogMaker content) {
- if (content.getType() == 0/*MetricsEvent.TYPE_UNKNOWN*/) {
- content.setType(4/*MetricsEvent.TYPE_ACTION*/);
- }
- saveLog(content.serialize());
- }
-}
-
-/**
- * Extension of {@link VerticalSwipeController} to go from NORMAL to OVERVIEW.
- */
-public class EdgeSwipeController extends VerticalSwipeController implements
- OnDeviceProfileChangeListener {
-
- private static final Rect sTempRect = new Rect();
-
- private final MetricsLogger mMetricsLogger = new MetricsLogger();
-
- public EdgeSwipeController(Launcher l) {
- super(l, NORMAL, OVERVIEW, l.getDeviceProfile().isVerticalBarLayout()
- ? HORIZONTAL : VERTICAL);
- l.addOnDeviceProfileChangeListener(this);
- }
-
- @Override
- public void onDeviceProfileChanged(DeviceProfile dp) {
- mDetector.updateDirection(dp.isVerticalBarLayout() ? HORIZONTAL : VERTICAL);
- }
-
- @Override
- protected boolean shouldInterceptTouch(MotionEvent ev) {
- return mLauncher.isInState(NORMAL) && (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
- }
-
- @Override
- protected int getSwipeDirection(MotionEvent ev) {
- return isTransitionFlipped() ? DIRECTION_NEGATIVE : DIRECTION_POSITIVE;
- }
-
- public EdgeSwipeController(Launcher l, LauncherState baseState) {
- super(l, baseState);
- }
-
- @Override
- protected boolean isTransitionFlipped() {
- return mLauncher.getDeviceProfile().isSeascape();
- }
-
- @Override
- protected void onTransitionComplete(boolean wasFling, boolean stateChanged) {
- if (stateChanged && mToState instanceof OverviewState) {
- // Mimic ActivityMetricsLogger.logAppTransitionMultiEvents() logging for
- // "Recents" activity for app transition tests.
- final LogMaker builder = new LogMaker(761/*APP_TRANSITION*/);
- builder.setPackageName("com.android.systemui");
- builder.addTaggedData(871/*FIELD_CLASS_NAME*/,
- "com.android.systemui.recents.RecentsActivity");
- builder.addTaggedData(319/*APP_TRANSITION_DELAY_MS*/,
- 0/* zero time */);
- mMetricsLogger.write(builder);
-
- // Add user event logging for launcher pipeline
- int direction = Direction.UP;
- if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- direction = Direction.LEFT;
- if (mLauncher.getDeviceProfile().isSeascape()) {
- direction = Direction.RIGHT;
- }
- }
- mLauncher.getUserEventDispatcher().logStateChangeAction(
- wasFling ? Touch.FLING : Touch.SWIPE, direction,
- ContainerType.NAVBAR, ContainerType.WORKSPACE, // src target
- ContainerType.TASKSWITCHER, // dst target
- mLauncher.getWorkspace().getCurrentPage());
- }
- }
-
- @Override
- protected float getShiftRange() {
- return getShiftRange(mLauncher);
- }
-
- public static float getShiftRange(Launcher launcher) {
- RecentsView.getPageRect(launcher.getDeviceProfile(), launcher, sTempRect);
- DragLayer dl = launcher.getDragLayer();
- Rect insets = dl.getInsets();
- DeviceProfile dp = launcher.getDeviceProfile();
-
- if (dp.isVerticalBarLayout()) {
- if (dp.isSeascape()) {
- return insets.left + sTempRect.left;
- } else {
- return dl.getWidth() - sTempRect.right + insets.right;
- }
- } else {
- return dl.getHeight() - sTempRect.bottom + insets.bottom;
- }
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
index 9541d0d052..99bf2649b9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.uioverrides;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.quickstep.QuickScrubController;
import com.android.quickstep.views.RecentsView;
@@ -25,12 +26,10 @@ import com.android.quickstep.views.RecentsView;
public class FastOverviewState extends OverviewState {
private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_DISABLE_RESTORE
- | FLAG_DISABLE_INTERACTION | FLAG_OVERVIEW_UI;
-
- private static final boolean DEBUG_DIFFERENT_UI = false;
+ | FLAG_DISABLE_INTERACTION | FLAG_OVERVIEW_UI | FLAG_HIDE_BACK_BUTTON;
public FastOverviewState(int id) {
- super(id, QuickScrubController.QUICK_SWITCH_START_DURATION, STATE_FLAGS);
+ super(id, QuickScrubController.QUICK_SCRUB_START_DURATION, STATE_FLAGS);
}
@Override
@@ -40,11 +39,18 @@ public class FastOverviewState extends OverviewState {
recentsView.getQuickScrubController().onFinishedTransitionToQuickScrub();
}
+ public void onStateEnabled(Launcher launcher) {
+ super.onStateEnabled(launcher);
+ AbstractFloatingView.closeAllOpenViews(launcher);
+ }
+
@Override
- public float getHoseatAlpha(Launcher launcher) {
- if (DEBUG_DIFFERENT_UI) {
- return 0;
- }
- return super.getHoseatAlpha(launcher);
+ public int getVisibleElements(Launcher launcher) {
+ return NONE;
+ }
+
+ @Override
+ public float[] getOverviewTranslationFactor(Launcher launcher) {
+ return new float[] {0f, 0.5f};
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
new file mode 100644
index 0000000000..23add9595c
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
@@ -0,0 +1,71 @@
+package com.android.launcher3.uioverrides;
+
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR;
+
+import android.view.MotionEvent;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.touch.AbstractStateChangeTouchController;
+import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.quickstep.util.SysuiEventLogger;
+
+/**
+ * Touch controller for handling edge swipes in landscape/seascape UI
+ */
+public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchController {
+
+ public LandscapeEdgeSwipeController(Launcher l) {
+ super(l, SwipeDetector.HORIZONTAL);
+ }
+
+ @Override
+ protected boolean canInterceptTouch(MotionEvent ev) {
+ if (mCurrentAnimation != null) {
+ // If we are already animating from a previous state, we can intercept.
+ return true;
+ }
+ if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ return false;
+ }
+ return mLauncher.isInState(NORMAL) && (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
+ }
+
+ @Override
+ protected int getSwipeDirection(MotionEvent ev) {
+ mFromState = NORMAL;
+ mToState = OVERVIEW;
+ return SwipeDetector.DIRECTION_BOTH;
+ }
+
+ @Override
+ protected float getShiftRange() {
+ return mLauncher.getDragLayer().getWidth();
+ }
+
+ @Override
+ protected float initCurrentAnimation() {
+ float range = getShiftRange();
+ long maxAccuracy = (long) (2 * range);
+ mCurrentAnimation = mLauncher.getStateManager()
+ .createAnimationToNewWorkspace(mToState, maxAccuracy);
+ return (mLauncher.getDeviceProfile().isSeascape() ? 2 : -2) / range;
+ }
+
+ @Override
+ protected int getDirectionForLog() {
+ return mLauncher.getDeviceProfile().isSeascape() ? Direction.RIGHT : Direction.LEFT;
+ }
+
+ @Override
+ protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
+ super.onSwipeInteractionCompleted(targetState, logAction);
+ if (mFromState == NORMAL && targetState == OVERVIEW) {
+ SysuiEventLogger.writeDummyRecentsTransition(0);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java
new file mode 100644
index 0000000000..720b20ac1b
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 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.uioverrides;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
+import android.view.MotionEvent;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.quickstep.TouchInteractionService;
+import com.android.quickstep.views.RecentsView;
+
+/**
+ * Touch controller from going from OVERVIEW to ALL_APPS
+ */
+public class LandscapeStatesTouchController extends PortraitStatesTouchController {
+
+ public LandscapeStatesTouchController(Launcher l) {
+ super(l);
+ }
+
+ @Override
+ protected boolean canInterceptTouch(MotionEvent ev) {
+ if (mCurrentAnimation != null) {
+ // If we are already animating from a previous state, we can intercept.
+ return true;
+ }
+ if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ return false;
+ }
+ if (mLauncher.isInState(ALL_APPS)) {
+ // In all-apps only listen if the container cannot scroll itself
+ return mLauncher.getAppsView().shouldContainerScroll(ev);
+ } else if (mLauncher.isInState(NORMAL)) {
+ return true;
+ } else if (mLauncher.isInState(OVERVIEW)) {
+ RecentsView rv = mLauncher.getOverviewPanel();
+ return ev.getY() > (rv.getBottom() - rv.getPaddingBottom());
+ } else {
+ return false;
+ }
+ }
+
+ protected LauncherState getTargetState() {
+ if (mLauncher.isInState(ALL_APPS)) {
+ // Should swipe down go to OVERVIEW instead?
+ return TouchInteractionService.isConnected() ?
+ mLauncher.getStateManager().getLastState() : NORMAL;
+ } else {
+ return ALL_APPS;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index abb4ecf4c9..a72b1b15bf 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -22,6 +22,7 @@ import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
import android.graphics.Rect;
import android.view.View;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Workspace;
@@ -56,6 +57,11 @@ public class OverviewState extends LauncherState {
return getScaleAndTranslationForPageRect(launcher, pageRect);
}
+ @Override
+ public float[] getOverviewTranslationFactor(Launcher launcher) {
+ return new float[] {0f, 0f};
+ }
+
@Override
public void onStateEnabled(Launcher launcher) {
RecentsView rv = launcher.getOverviewPanel();
@@ -100,4 +106,29 @@ public class OverviewState extends LauncherState {
return new float[] {scale, 0, translationY};
}
+
+ @Override
+ public int getVisibleElements(Launcher launcher) {
+ if (launcher.getDeviceProfile().isVerticalBarLayout()) {
+ return NONE;
+ } else {
+ return launcher.getAppsView().getFloatingHeaderView().hasVisibleContent()
+ ? HOTSEAT_EXTRA | ALL_APPS_HEADER_EXTRA : HOTSEAT_ICONS | HOTSEAT_EXTRA;
+ }
+ }
+
+ @Override
+ public float getVerticalProgress(Launcher launcher) {
+ if ((getVisibleElements(launcher) & ALL_APPS_HEADER_EXTRA) == 0) {
+ // We have no all apps content, so we're still at the fully down progress.
+ return super.getVerticalProgress(launcher);
+ }
+ return 1 - (getDefaultSwipeHeight(launcher)
+ / launcher.getAllAppsController().getShiftRange());
+ }
+
+ public static float getDefaultSwipeHeight(Launcher launcher) {
+ DeviceProfile dp = launcher.getDeviceProfile();
+ return dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeUpController.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeUpController.java
deleted file mode 100644
index 4fb388613e..0000000000
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeUpController.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2017 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.uioverrides;
-
-import static com.android.launcher3.LauncherState.OVERVIEW;
-
-import android.view.MotionEvent;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.touch.SwipeDetector;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import com.android.launcher3.util.VerticalSwipeController;
-
-/**
- * Extension of {@link VerticalSwipeController} which allows swipe up from OVERVIEW to ALL_APPS
- * Note that the swipe down is handled by {@link TwoStepSwipeController}.
- */
-public class OverviewSwipeUpController extends VerticalSwipeController {
-
- public OverviewSwipeUpController(Launcher l) {
- super(l, OVERVIEW);
- }
-
- @Override
- protected boolean shouldInterceptTouch(MotionEvent ev) {
- if (!mLauncher.isInState(OVERVIEW)) {
- return false;
- }
- if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- return ev.getY() >
- mLauncher.getDragLayer().getHeight() * OVERVIEW.getVerticalProgress(mLauncher);
- } else {
- return mLauncher.getDragLayer().isEventOverHotseat(ev);
- }
- }
-
- @Override
- protected int getSwipeDirection(MotionEvent ev) {
- return SwipeDetector.DIRECTION_POSITIVE;
- }
-
- @Override
- protected void onTransitionComplete(boolean wasFling, boolean stateChanged) {
- if (stateChanged) {
- // Transition complete. log the action
- mLauncher.getUserEventDispatcher().logStateChangeAction(
- wasFling ? Touch.FLING : Touch.SWIPE,
- Direction.UP,
- ContainerType.HOTSEAT,
- ContainerType.TASKSWITCHER,
- ContainerType.ALLAPPS,
- mLauncher.getWorkspace().getCurrentPage());
- }
-
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
new file mode 100644
index 0000000000..1e006e5752
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2018 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.uioverrides;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATION;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.view.MotionEvent;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.touch.AbstractStateChangeTouchController;
+import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.quickstep.TouchInteractionService;
+import com.android.quickstep.util.SysuiEventLogger;
+
+/**
+ * Touch controller for handling various state transitions in portrait UI.
+ */
+public class PortraitStatesTouchController extends AbstractStateChangeTouchController {
+
+ private static final float TOTAL_DISTANCE_MULTIPLIER = 2f;
+ private static final float LINEAR_SCALE_LIMIT = 1 / TOTAL_DISTANCE_MULTIPLIER;
+
+ // Much be greater than LINEAR_SCALE_LIMIT;
+ private static final float MAXIMUM_DISTANCE_FACTOR = 0.9f;
+
+ // Maximum amount to overshoot.
+ private static final float MAX_OVERSHOOT = 0.3f;
+
+ private static final double PI_BY_2 = Math.PI / 2;
+
+ private InterpolatorWrapper mAllAppsInterpolatorWrapper = new InterpolatorWrapper();
+
+ // If > 0, the animation progress is clamped at that value as long as user is dragging.
+ private float mClampProgressUpdate = -1;
+
+ // If true, we will finish the current animation instantly on second touch.
+ private boolean mFinishFastOnSecondTouch;
+
+ private final Interpolator mAllAppsDampedInterpolator = new Interpolator() {
+
+ private final double mAngleMultiplier = Math.PI /
+ (2 * (MAXIMUM_DISTANCE_FACTOR - LINEAR_SCALE_LIMIT));
+
+ @Override
+ public float getInterpolation(float v) {
+ if (v <= LINEAR_SCALE_LIMIT) {
+ return v * TOTAL_DISTANCE_MULTIPLIER;
+ }
+ float overshoot = (v - LINEAR_SCALE_LIMIT);
+ return (float) (1 + MAX_OVERSHOOT * Math.sin(overshoot * mAngleMultiplier));
+ }
+ };
+
+ private final Interpolator mOverviewBoundInterpolator = (v) -> {
+ if (v >= MAXIMUM_DISTANCE_FACTOR) {
+ return 1;
+ }
+ return FAST_OUT_SLOW_IN.getInterpolation(v / MAXIMUM_DISTANCE_FACTOR);
+ };
+
+ public PortraitStatesTouchController(Launcher l) {
+ super(l, SwipeDetector.VERTICAL);
+ }
+
+ @Override
+ protected boolean canInterceptTouch(MotionEvent ev) {
+ if (mCurrentAnimation != null) {
+ if (mFinishFastOnSecondTouch) {
+ // TODO: Animate to finish instead.
+ mCurrentAnimation.getAnimationPlayer().end();
+ }
+
+ // If we are already animating from a previous state, we can intercept.
+ return true;
+ }
+ if (mLauncher.isInState(ALL_APPS)) {
+ // In all-apps only listen if the container cannot scroll itself
+ if (!mLauncher.getAppsView().shouldContainerScroll(ev)) {
+ return false;
+ }
+ } else {
+ // For all other states, only listen if the event originated below the hotseat height
+ DeviceProfile dp = mLauncher.getDeviceProfile();
+ int hotseatHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
+ if (ev.getY() < (mLauncher.getDragLayer().getHeight() - hotseatHeight)) {
+ return false;
+ }
+ }
+ if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ protected int getSwipeDirection(MotionEvent ev) {
+ final int directionsToDetectScroll;
+ if (mLauncher.isInState(ALL_APPS)) {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_NEGATIVE;
+ mStartContainerType = ContainerType.ALLAPPS;
+ } else if (mLauncher.isInState(NORMAL)) {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
+ mStartContainerType = ContainerType.HOTSEAT;
+ } else if (mLauncher.isInState(OVERVIEW)) {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
+ mStartContainerType = ContainerType.TASKSWITCHER;
+ } else {
+ return 0;
+ }
+ mFromState = mLauncher.getStateManager().getState();
+ mToState = getTargetState();
+ if (mFromState == mToState) {
+ return 0;
+ }
+ return directionsToDetectScroll;
+ }
+
+ protected LauncherState getTargetState() {
+ if (mLauncher.isInState(ALL_APPS)) {
+ // Should swipe down go to OVERVIEW instead?
+ return TouchInteractionService.isConnected() ?
+ mLauncher.getStateManager().getLastState() : NORMAL;
+ } else if (mLauncher.isInState(OVERVIEW)) {
+ return ALL_APPS;
+ } else {
+ return TouchInteractionService.isConnected() ? OVERVIEW : ALL_APPS;
+ }
+ }
+
+ private AnimatorSetBuilder getNormalToOverviewAnimation() {
+ mAllAppsInterpolatorWrapper.baseInterpolator = mAllAppsDampedInterpolator;
+
+ AnimatorSetBuilder builder = new AnimatorSetBuilder();
+ builder.setInterpolator(ANIM_VERTICAL_PROGRESS, mAllAppsInterpolatorWrapper);
+
+ builder.setInterpolator(ANIM_OVERVIEW_TRANSLATION, mOverviewBoundInterpolator);
+ return builder;
+ }
+
+ @Override
+ protected void updateProgress(float fraction) {
+ if (mClampProgressUpdate > 0) {
+ mCurrentAnimation.setPlayFraction(Math.min(fraction, mClampProgressUpdate));
+ } else {
+ super.updateProgress(fraction);
+ }
+ }
+
+ @Override
+ protected float initCurrentAnimation() {
+ float range = getShiftRange();
+ long maxAccuracy = (long) (2 * range);
+
+ float startVerticalShift = mFromState.getVerticalProgress(mLauncher) * range;
+ float endVerticalShift = mToState.getVerticalProgress(mLauncher) * range;
+
+ float totalShift = endVerticalShift - startVerticalShift;
+
+ final AnimatorSetBuilder builder;
+
+ if (mFromState == NORMAL && mToState == OVERVIEW && totalShift != 0) {
+ builder = getNormalToOverviewAnimation();
+ totalShift = totalShift * TOTAL_DISTANCE_MULTIPLIER;
+ mClampProgressUpdate = MAXIMUM_DISTANCE_FACTOR;
+ } else {
+ builder = new AnimatorSetBuilder();
+ mClampProgressUpdate = -1;
+ }
+
+ mCurrentAnimation = mLauncher.getStateManager()
+ .createAnimationToNewWorkspace(mToState, builder, maxAccuracy);
+
+ if (totalShift == 0) {
+ totalShift = Math.signum(mFromState.ordinal - mToState.ordinal)
+ * OverviewState.getDefaultSwipeHeight(mLauncher);
+ }
+ return 1 / totalShift;
+ }
+
+ @Override
+ protected void updateSwipeCompleteAnimation(ValueAnimator animator, long expectedDuration,
+ LauncherState targetState, float velocity, boolean isFling) {
+ if (mFromState == NORMAL && mToState == OVERVIEW && targetState == OVERVIEW) {
+ mFinishFastOnSecondTouch = true;
+
+ // Update all apps interpolator
+ float currentFraction = mCurrentAnimation.getProgressFraction();
+ float absVelocity = Math.abs(velocity);
+ float currentValue = mAllAppsDampedInterpolator.getInterpolation(currentFraction);
+
+ if (isFling && absVelocity > 1 && currentFraction < LINEAR_SCALE_LIMIT) {
+
+ // TODO: Clean up these magic calculations
+ // Linearly interpolate the max value based on the velocity.
+ float maxValue = Math.max(absVelocity > 4 ? 1 + MAX_OVERSHOOT :
+ 1 + (absVelocity - 1) * MAX_OVERSHOOT / 3,
+ currentValue);
+ double angleToPeak = PI_BY_2 - Math.asin(currentValue / maxValue);
+
+ if (expectedDuration != 0 && angleToPeak != 0) {
+
+ float distanceLeft = 1 - currentFraction;
+ mAllAppsInterpolatorWrapper.baseInterpolator = (f) -> {
+ float scaledF = (f - currentFraction) / distanceLeft;
+
+ if (scaledF < 0.5f) {
+ double angle = PI_BY_2 - angleToPeak + scaledF * angleToPeak / 0.5f;
+ return (float) (maxValue * Math.sin(angle));
+ }
+
+ scaledF = ((scaledF - .5f) / .5f);
+ double angle = PI_BY_2 + 3 * scaledF * PI_BY_2;
+ float amplitude = (1 - scaledF) * (1 - scaledF) * (maxValue - 1);
+ return 1 + (float) (amplitude * Math.sin(angle));
+ };
+
+ animator.setDuration(expectedDuration).setInterpolator(LINEAR);
+ return;
+ }
+ }
+
+ if (currentFraction < LINEAR_SCALE_LIMIT) {
+ mAllAppsInterpolatorWrapper.baseInterpolator = LINEAR;
+ super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState,
+ velocity, isFling);
+ return;
+ }
+ float extraValue = mAllAppsDampedInterpolator.getInterpolation(currentFraction) - 1;
+ float distanceLeft = 1 - currentFraction;
+
+ animator.setFloatValues(currentFraction, 1);
+ mAllAppsInterpolatorWrapper.baseInterpolator = (f) -> {
+ float scaledF = (f - currentFraction) / distanceLeft;
+
+ double angle = scaledF * 1.5 * Math.PI;
+ float amplitude = (1 - scaledF) * (1 - scaledF) * extraValue;
+ return 1 + (float) (amplitude * Math.sin(angle));
+ };
+ animator.setDuration(200).setInterpolator(LINEAR);
+ return;
+ }
+ mFinishFastOnSecondTouch = false;
+ super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState,
+ velocity, isFling);
+ }
+
+ @Override
+ protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
+ super.onSwipeInteractionCompleted(targetState, logAction);
+ if (mFromState == NORMAL && targetState == OVERVIEW) {
+ SysuiEventLogger.writeDummyRecentsTransition(0);
+ }
+ }
+
+ private static class InterpolatorWrapper implements Interpolator {
+
+ public TimeInterpolator baseInterpolator = LINEAR;
+
+ @Override
+ public float getInterpolation(float v) {
+ return baseInterpolator.getInterpolation(v);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index b7f79b321c..d8f206c5ed 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -16,36 +16,32 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.AlphaUpdateListener.updateVisibility;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATION;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
+import static com.android.quickstep.views.LauncherRecentsView.TRANSLATION_X_FACTOR;
+import static com.android.quickstep.views.LauncherRecentsView.TRANSLATION_Y_FACTOR;
+import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.view.View;
+import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
+import android.os.Build;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.PagedView;
-import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.anim.Interpolators;
-import com.android.quickstep.AnimatedFloat;
-import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.TaskView;
+import com.android.launcher3.anim.PropertySetter;
+import com.android.quickstep.views.LauncherRecentsView;
+@TargetApi(Build.VERSION_CODES.O)
public class RecentsViewStateController implements StateHandler {
private final Launcher mLauncher;
- private final RecentsView mRecentsView;
-
- private final AnimatedFloat mTransitionProgress = new AnimatedFloat(this::onTransitionProgress);
- // The fraction representing the visibility of the RecentsView. This allows delaying the
- // overall transition while the RecentsView is being shown or hidden.
- private final AnimatedFloat mVisibilityMultiplier = new AnimatedFloat(this::onVisibilityProgress);
-
- private boolean mIsRecentsSlidingInOrOut;
+ private final LauncherRecentsView mRecentsView;
public RecentsViewStateController(Launcher launcher) {
mLauncher = launcher;
@@ -54,8 +50,11 @@ public class RecentsViewStateController implements StateHandler {
@Override
public void setState(LauncherState state) {
- setVisibility(state.overviewUi);
- setTransitionProgress(state.overviewUi ? 1 : 0);
+ mRecentsView.setContentAlpha(state.overviewUi ? 1 : 0);
+ updateVisibility(mRecentsView, isAccessibilityEnabled(mLauncher));
+ float[] translationFactor = state.getOverviewTranslationFactor(mLauncher);
+ mRecentsView.setTranslationXFactor(translationFactor[0]);
+ mRecentsView.setTranslationYFactor(translationFactor[1]);
if (state.overviewUi) {
mRecentsView.resetTaskVisuals();
}
@@ -64,11 +63,9 @@ public class RecentsViewStateController implements StateHandler {
@Override
public void setStateWithAnimation(final LauncherState toState,
AnimatorSetBuilder builder, AnimationConfig config) {
- LauncherState fromState = mLauncher.getStateManager().getState();
- mIsRecentsSlidingInOrOut = fromState == NORMAL && toState.overviewUi
- || fromState.overviewUi && toState == NORMAL;
// Scroll to the workspace card before changing to the NORMAL state.
+ LauncherState fromState = mLauncher.getStateManager().getState();
int currPage = mRecentsView.getCurrentPage();
if (fromState.overviewUi && toState == NORMAL && currPage != 0 && !config.userControlled) {
int maxSnapDuration = PagedView.SLOW_PAGE_SNAP_ANIMATION_DURATION;
@@ -79,78 +76,24 @@ public class RecentsViewStateController implements StateHandler {
builder.setStartDelay(snapDuration / 4);
}
- ObjectAnimator progressAnim =
- mTransitionProgress.animateToValue(toState.overviewUi ? 1 : 0);
- progressAnim.setDuration(config.duration);
- progressAnim.setInterpolator(Interpolators.LINEAR);
- progressAnim.addListener(new AnimationSuccessListener() {
+ PropertySetter setter = config.getProperSetter(builder);
+ float[] translationFactor = toState.getOverviewTranslationFactor(mLauncher);
+ setter.setFloat(mRecentsView, TRANSLATION_X_FACTOR,
+ translationFactor[0],
+ builder.getInterpolator(ANIM_OVERVIEW_TRANSLATION, LINEAR));
+ setter.setFloat(mRecentsView, TRANSLATION_Y_FACTOR,
+ translationFactor[1],
+ builder.getInterpolator(ANIM_OVERVIEW_TRANSLATION, LINEAR));
+ setter.setFloat(mRecentsView, CONTENT_ALPHA, toState.overviewUi ? 1 : 0, LINEAR);
- @Override
- public void onAnimationSuccess(Animator animator) {
- mRecentsView.setCurrentPage(mRecentsView.getPageNearestToCenterOfScreen());
- }
- });
- builder.play(progressAnim);
-
- ObjectAnimator visibilityAnim = animateVisibility(toState.overviewUi);
- visibilityAnim.setDuration(config.duration);
- visibilityAnim.setInterpolator(Interpolators.LINEAR);
- builder.play(visibilityAnim);
- }
-
- public void setVisibility(boolean isVisible) {
- mVisibilityMultiplier.cancelAnimation();
- mRecentsView.setVisibility(isVisible ? View.VISIBLE : View.GONE);
- mVisibilityMultiplier.updateValue(isVisible ? 1 : 0);
- }
-
- public ObjectAnimator animateVisibility(boolean isVisible) {
- ObjectAnimator anim = mVisibilityMultiplier.animateToValue(isVisible ? 1 : 0);
- if (isVisible) {
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mRecentsView.setVisibility(View.VISIBLE);
- }
+ if (toState.overviewUi) {
+ ValueAnimator updateAnim = ValueAnimator.ofFloat(0, 1);
+ updateAnim.addUpdateListener(valueAnimator -> {
+ // While animating into recents, update the visible task data as needed
+ mRecentsView.loadVisibleTaskData();
});
- } else {
- anim.addListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationSuccess(Animator animator) {
- mRecentsView.setVisibility(View.GONE);
- }
- });
- }
- return anim;
- }
-
- public void setTransitionProgress(float progress) {
- mTransitionProgress.cancelAnimation();
- mTransitionProgress.updateValue(progress);
- }
-
- private void onTransitionProgress() {
- applyProgress();
- if (mIsRecentsSlidingInOrOut) {
- float interpolatedProgress = ACCEL.getInterpolation(mTransitionProgress.value);
- // Slide in from the side as we swipe.
- int translation = mRecentsView.getWidth();
- if (mRecentsView.isRtl()) {
- translation = -translation;
- }
- mRecentsView.setTranslationX(translation * (1 - interpolatedProgress));
- }
- }
-
- private void onVisibilityProgress() {
- applyProgress();
- }
-
- private void applyProgress() {
- mRecentsView.setAlpha(mTransitionProgress.value * mVisibilityMultiplier.value);
- if (mIsRecentsSlidingInOrOut) {
- // While animating into recents, update the visible task data as needed
- mRecentsView.loadVisibleTaskData();
+ updateAnim.setDuration(config.duration);
+ builder.play(updateAnim);
}
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TaggedAnimatorSetBuilder.java b/quickstep/src/com/android/launcher3/uioverrides/TaggedAnimatorSetBuilder.java
deleted file mode 100644
index 651a753544..0000000000
--- a/quickstep/src/com/android/launcher3/uioverrides/TaggedAnimatorSetBuilder.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2017 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.uioverrides;
-
-import android.animation.Animator;
-import android.util.SparseArray;
-
-import com.android.launcher3.anim.AnimatorSetBuilder;
-
-import java.util.Collections;
-import java.util.List;
-
-public class TaggedAnimatorSetBuilder extends AnimatorSetBuilder {
-
- /**
- * Map of the index in {@link #mAnims} to tag. All the animations in {@link #mAnims} starting
- * from this index correspond to the tag (until a new tag is specified for an index)
- */
- private final SparseArray