Merge "Fix proguard flag" into ub-launcher3-master
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 4a26494..8b28597 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -47,7 +47,8 @@
<!-- STOPSHIP: Change exported to false once all the integration is complete.
It is set to true so that the activity can be started from command line -->
<activity android:name="com.android.quickstep.RecentsActivity"
- android:exported="true" />
+ android:exported="true"
+ android:excludeFromRecents="true" />
<!-- Content provider to settings search -->
<provider
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 33987e2..6e56055 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 872e6ca..f919339 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 8e66526..e809d21 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.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.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 @@
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 @@
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,35 @@
private final float mRecentsTransY;
private final float mRecentsScale;
+ private DeviceProfile mDeviceProfile;
private View mFloatingView;
- private boolean mIsRtl;
- private LauncherTransitionAnimator mCurrentAnimator;
+ private final AnimatorListenerAdapter mUiResetListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDragLayer.setAlpha(1f);
+ mDragLayer.setTranslationY(0f);
+
+ View appsView = mLauncher.getAppsView();
+ appsView.setAlpha(1f);
+ appsView.setTranslationY(0f);
+ }
+ };
+
+ 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 +154,6 @@
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 +161,35 @@
@Override
public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
if (hasControlRemoteAppTransitionPermission()) {
- TaskView taskView = findTaskViewToLaunch(launcher, v);
try {
- RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mLauncher) {
- @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;
- }
+ RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler) {
- setCurrentAnimator(animator);
- mAnimator = animator.getAnimatorSet();
- mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ 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));
+ anim.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();
+ ((ViewGroup) mDragLayer.getParent()).removeView(mFloatingView);
}
});
- 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);
- });
+ anim.addListener(mUiResetListener);
+ }
+ 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 +208,19 @@
* 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 +232,10 @@
}
}
}
- 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 +256,35 @@
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 +301,7 @@
Animator windowAnim = getRecentsWindowAnimator(taskView, skipLauncherChanges, targets);
windowAnim.addListener(windowAnimEndListener);
- return new LauncherTransitionAnimator(launcherAnim, windowAnim, skipLauncherChanges);
+ return new Animator[] {launcherAnim, windowAnim};
}
/**
@@ -418,7 +389,7 @@
* @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);
@@ -454,7 +425,7 @@
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);
@@ -469,9 +440,8 @@
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();
@@ -485,7 +455,7 @@
t.setMatrix(target.leash, matrix);
t.setWindowCrop(target.leash, crop);
- if (!skipLauncherChanges.value) {
+ if (!skipLauncherChanges) {
t.deferTransactionUntil(target.leash, surface, frameNumber);
}
}
@@ -503,15 +473,6 @@
}
/**
- * 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.
*/
private AnimatorSet getLauncherAnimators(View v, RemoteAnimationTargetCompat[] targets) {
@@ -726,9 +687,8 @@
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
@@ -801,42 +761,25 @@
* 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 (mLauncher.getStateManager().getState().overviewUi) {
- // We use a separate transition for Overview mode.
- 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;
+ }
- // We can skip the Launcher content 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. We still need to animate the window though.
- LauncherTransitionAnimator animator = new LauncherTransitionAnimator(
- launcherIsATargetWithMode(targets, MODE_OPENING)
- ? getLauncherResumeAnimation()
- : null,
- getClosingWindowAnimators(targets));
+ AnimatorSet anim = new AnimatorSet();
+ anim.play(getClosingWindowAnimators(targetCompats));
- setCurrentAnimator(animator);
- mAnimator = animator.getAnimatorSet();
- mAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- finishedCallback.run();
- }
- });
- mAnimator.start();
+ if (launcherIsATargetWithMode(targetCompats, MODE_OPENING)) {
+ AnimatorSet contentAnimation = getLauncherResumeAnimation();
+ anim.play(contentAnimation);
- // 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);
- });
+ // Only register the content animation for cancellation when state changes
+ mLauncher.getStateManager().setCurrentAnimation(contentAnimation);
+ }
+ return anim;
}
};
}
@@ -903,16 +846,22 @@
if (mLauncher.isInState(LauncherState.ALL_APPS)
|| mLauncher.getDeviceProfile().isVerticalBarLayout()) {
AnimatorSet contentAnimator = getLauncherContentAnimator(true /* show */);
+ contentAnimator.addListener(mUiResetListener);
contentAnimator.setStartDelay(LAUNCHER_RESUME_START_DELAY);
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);
@@ -940,6 +889,8 @@
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 0000000..0d1038a
--- /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<Launcher, Boolean> mOnInitListener;
+
+ public LauncherInitListener(BiPredicate<Launcher, Boolean> 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 ab9234b..0000000
--- 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 7538217..0000000
--- 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/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 789185a..637ce60 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.LauncherState.NORMAL;
+import android.content.Context;
import android.view.View;
import android.view.View.AccessibilityDelegate;
@@ -73,7 +74,8 @@
}
}
}
- OverviewInteractionState.setBackButtonVisible(launcher, shouldBackButtonBeVisible);
+ OverviewInteractionState.getInstance(launcher)
+ .setBackButtonVisible(shouldBackButtonBeVisible);
}
public static void resetOverview(Launcher launcher) {
@@ -81,15 +83,15 @@
recents.reset();
}
- public static void onStart(Launcher launcher) {
- RecentsModel model = RecentsModel.getInstance(launcher);
+ public static void onStart(Context context) {
+ RecentsModel model = RecentsModel.getInstance(context);
if (model != null) {
model.onStart();
}
}
- public static void onTrimMemory(Launcher launcher, int level) {
- RecentsModel model = RecentsModel.getInstance(launcher);
+ public static void onTrimMemory(Context context, int level) {
+ RecentsModel model = RecentsModel.getInstance(context);
if (model != null) {
model.onTrimMemory(level);
}
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
new file mode 100644
index 0000000..a9da4f9
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -0,0 +1,308 @@
+/*
+ * 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.quickstep;
+
+import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.app.ActivityOptions;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.View;
+
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherInitListener;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.util.ViewOnDrawExecutor;
+import com.android.quickstep.views.LauncherLayoutListener;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.ActivityOptionsCompat;
+import com.android.systemui.shared.system.AssistDataReceiver;
+import com.android.systemui.shared.system.RecentsAnimationListener;
+import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
+
+import java.util.function.BiPredicate;
+
+/**
+ * Utility class which abstracts out the logical differences between Launcher and RecentsActivity.
+ */
+public interface ActivityControlHelper<T extends BaseDraggingActivity> {
+
+ LayoutListener createLayoutListener(T activity);
+
+ void onQuickstepGestureStarted(T activity, boolean activityVisible);
+
+ void onQuickInteractionStart(T activity, boolean activityVisible);
+
+ void executeOnNextDraw(T activity, TaskView targetView, Runnable action);
+
+ void onTransitionCancelled(T activity, boolean activityVisible);
+
+ int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect);
+
+ void onSwipeUpComplete(T activity);
+
+ void prepareRecentsUI(T activity, boolean activityVisible);
+
+ AnimatorPlaybackController createControllerForVisibleActivity(T activity);
+
+ AnimatorPlaybackController createControllerForHiddenActivity(T activity, int transitionLength);
+
+ ActivityInitListener createActivityInitListener(BiPredicate<T, Boolean> onInitListener);
+
+ void startRecents(Context context, Intent intent, AssistDataReceiver assistDataReceiver,
+ RecentsAnimationListener remoteAnimationListener);
+
+ class LauncherActivityControllerHelper implements ActivityControlHelper<Launcher> {
+
+ @Override
+ public LayoutListener createLayoutListener(Launcher activity) {
+ return new LauncherLayoutListener(activity);
+ }
+
+ @Override
+ public void onQuickstepGestureStarted(Launcher activity, boolean activityVisible) {
+ activity.onQuickstepGestureStarted(activityVisible);
+ }
+
+ @Override
+ public void onQuickInteractionStart(Launcher activity, boolean activityVisible) {
+ activity.getStateManager().goToState(FAST_OVERVIEW, activityVisible);
+ }
+
+ @Override
+ public void executeOnNextDraw(Launcher activity, TaskView targetView, Runnable action) {
+ ViewOnDrawExecutor executor = new ViewOnDrawExecutor() {
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ if (!isCompleted()) {
+ runAllTasks();
+ }
+ }
+ };
+ executor.attachTo(activity, targetView, false /* waitForLoadAnimation */);
+ executor.execute(action);
+ }
+
+ @Override
+ public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
+ RecentsView.getPageRect(dp, context, outRect);
+ if (dp.isVerticalBarLayout()) {
+ Rect targetInsets = dp.getInsets();
+ int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
+ return dp.hotseatBarSizePx + dp.hotseatBarSidePaddingPx + hotseatInset;
+ } else {
+ return dp.heightPx - outRect.bottom;
+ }
+ }
+
+ @Override
+ public void onTransitionCancelled(Launcher activity, boolean activityVisible) {
+ LauncherState startState = activity.getStateManager().getRestState();
+ activity.getStateManager().goToState(startState, activityVisible);
+ }
+
+ @Override
+ public void onSwipeUpComplete(Launcher activity) {
+ // Re apply state in case we did something funky during the transition.
+ activity.getStateManager().reapplyState();
+ }
+
+ @Override
+ public void prepareRecentsUI(Launcher activity, boolean activityVisible) {
+ LauncherState startState = activity.getStateManager().getState();
+ if (startState.disableRestore) {
+ startState = activity.getStateManager().getRestState();
+ }
+ activity.getStateManager().setRestState(startState);
+
+ if (!activityVisible) {
+ activity.getStateManager().goToState(OVERVIEW, false);
+
+ // Optimization, hide the all apps view to prevent layout while initializing
+ activity.getAppsView().setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public AnimatorPlaybackController createControllerForVisibleActivity(Launcher activity) {
+ DeviceProfile dp = activity.getDeviceProfile();
+ long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
+ return activity.getStateManager().createAnimationToNewWorkspace(OVERVIEW, accuracy);
+ }
+
+ @Override
+ public AnimatorPlaybackController createControllerForHiddenActivity(
+ Launcher activity, int transitionLength) {
+ float startProgress;
+ AllAppsTransitionController controller = activity.getAllAppsController();
+
+ if (activity.getDeviceProfile().isVerticalBarLayout()) {
+ startProgress = 1;
+ } else {
+ float scrollRange = Math.max(controller.getShiftRange(), 1);
+ startProgress = (transitionLength / scrollRange) + 1;
+ }
+ AnimatorSet anim = new AnimatorSet();
+ ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(controller, ALL_APPS_PROGRESS,
+ startProgress, OVERVIEW.getVerticalProgress(activity));
+ shiftAnim.setInterpolator(LINEAR);
+ anim.play(shiftAnim);
+
+ // TODO: Link this animation to state animation, so that it is cancelled
+ // automatically on state change
+ anim.setDuration(transitionLength * 2);
+ return AnimatorPlaybackController.wrap(anim, transitionLength * 2);
+ }
+
+ @Override
+ public ActivityInitListener createActivityInitListener(
+ BiPredicate<Launcher, Boolean> onInitListener) {
+ return new LauncherInitListener(onInitListener);
+ }
+
+ @Override
+ public void startRecents(Context context, Intent intent,
+ AssistDataReceiver assistDataReceiver,
+ RecentsAnimationListener remoteAnimationListener) {
+ ActivityManagerWrapper.getInstance().startRecentsActivity(
+ intent, assistDataReceiver, remoteAnimationListener, null, null);
+ }
+ }
+
+ class FallbackActivityControllerHelper implements ActivityControlHelper<RecentsActivity> {
+
+ @Override
+ public void onQuickstepGestureStarted(RecentsActivity activity, boolean activityVisible) {
+ // TODO:
+ }
+
+ @Override
+ public void onQuickInteractionStart(RecentsActivity activity, boolean activityVisible) {
+ // TODO:
+ }
+
+ @Override
+ public void executeOnNextDraw(RecentsActivity activity, TaskView targetView,
+ Runnable action) {
+ // TODO:
+ new Handler(Looper.getMainLooper()).post(action);
+ }
+
+ @Override
+ public void onTransitionCancelled(RecentsActivity activity, boolean activityVisible) {
+ // TODO:
+ }
+
+ @Override
+ public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
+ FallbackRecentsView.getCenterPageRect(dp, context, outRect);
+ if (dp.isVerticalBarLayout()) {
+ Rect targetInsets = dp.getInsets();
+ int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
+ return dp.hotseatBarSizePx + dp.hotseatBarSidePaddingPx + hotseatInset;
+ } else {
+ return dp.heightPx - outRect.bottom;
+ }
+ }
+
+ @Override
+ public void onSwipeUpComplete(RecentsActivity activity) {
+ // TODO:
+ }
+
+ @Override
+ public void prepareRecentsUI(RecentsActivity activity, boolean activityVisible) {
+ // TODO:
+ }
+
+ @Override
+ public AnimatorPlaybackController createControllerForVisibleActivity(
+ RecentsActivity activity) {
+ DeviceProfile dp = activity.getDeviceProfile();
+ return createControllerForHiddenActivity(activity, Math.max(dp.widthPx, dp.heightPx));
+ }
+
+ @Override
+ public AnimatorPlaybackController createControllerForHiddenActivity(
+ RecentsActivity activity, int transitionLength) {
+ // We do not animate anything. Create a empty controller
+ AnimatorSet anim = new AnimatorSet();
+ return AnimatorPlaybackController.wrap(anim, transitionLength * 2);
+ }
+
+ @Override
+ public LayoutListener createLayoutListener(RecentsActivity activity) {
+ // We do not change anything as part of layout changes in fallback activity. Return a
+ // default layout listener.
+ return new LayoutListener() {
+ @Override
+ public void open() { }
+
+ @Override
+ public void setHandler(WindowTransformSwipeHandler handler) { }
+
+ @Override
+ public void finish() { }
+ };
+ }
+
+ @Override
+ public ActivityInitListener createActivityInitListener(
+ BiPredicate<RecentsActivity, Boolean> onInitListener) {
+ return new RecentsActivityTracker(onInitListener);
+ }
+
+ @Override
+ public void startRecents(Context context, Intent intent,
+ AssistDataReceiver assistDataReceiver,
+ final RecentsAnimationListener remoteAnimationListener) {
+ ActivityOptions options =
+ ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
+ new FallbackActivityOptions(remoteAnimationListener), 10000, 10000));
+ context.startActivity(intent, options.toBundle());
+ }
+ }
+
+ interface LayoutListener {
+
+ void open();
+
+ void setHandler(WindowTransformSwipeHandler handler);
+
+ void finish();
+ }
+
+ interface ActivityInitListener {
+
+ void register();
+
+ void unregister();
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityOptions.java b/quickstep/src/com/android/quickstep/FallbackActivityOptions.java
new file mode 100644
index 0000000..3a7fb2d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/FallbackActivityOptions.java
@@ -0,0 +1,82 @@
+/*
+ * 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.quickstep;
+
+import android.graphics.Rect;
+import android.util.Log;
+
+import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
+import com.android.systemui.shared.system.RecentsAnimationListener;
+import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.WindowManagerWrapper;
+
+/**
+ * Temporary class to create activity options to emulate recents transition for fallback activtiy.
+ */
+public class FallbackActivityOptions implements RemoteAnimationRunnerCompat {
+
+ private final RecentsAnimationListener mListener;
+
+ public FallbackActivityOptions(RecentsAnimationListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats,
+ Runnable runnable) {
+ DummyRecentsAnimationControllerCompat dummyRecentsAnim =
+ new DummyRecentsAnimationControllerCompat(runnable);
+
+ Rect insets = new Rect();
+ WindowManagerWrapper.getInstance().getStableInsets(insets);
+ mListener.onAnimationStart(dummyRecentsAnim, targetCompats, insets, null);
+ }
+
+ @Override
+ public void onAnimationCancelled() {
+ mListener.onAnimationCanceled();
+ }
+
+ private static class DummyRecentsAnimationControllerCompat
+ extends RecentsAnimationControllerCompat {
+
+ final Runnable mFinishCallback;
+
+ public DummyRecentsAnimationControllerCompat(Runnable finishCallback) {
+ mFinishCallback = finishCallback;
+ }
+
+ @Override
+ public ThumbnailData screenshotTask(int taskId) {
+ return new ThumbnailData();
+ }
+
+ @Override
+ public void setInputConsumerEnabled(boolean enabled) { }
+
+ @Override
+ public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) { }
+
+ @Override
+ public void finish(boolean toHome) {
+ if (toHome) {
+ mFinishCallback.run();
+ }
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/FallbackRecentsView.java
index 22f6e0c..032d753 100644
--- a/quickstep/src/com/android/quickstep/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/FallbackRecentsView.java
@@ -48,10 +48,21 @@
setPadding(padding.left, padding.top, padding.right, padding.bottom);
}
- public static void verticalCenter(Rect padding, DeviceProfile dp) {
+ private static void verticalCenter(Rect padding, DeviceProfile dp) {
Rect insets = dp.getInsets();
int totalSpace = (padding.top + padding.bottom - insets.top - insets.bottom) / 2;
padding.top = insets.top + totalSpace;
padding.bottom = insets.bottom + totalSpace;
}
+
+ public static void getCenterPageRect(DeviceProfile grid, Context context, Rect outRect) {
+ Rect targetPadding = getPadding(grid, context);
+ verticalCenter(targetPadding, grid);
+ Rect insets = grid.getInsets();
+ outRect.set(
+ targetPadding.left + insets.left,
+ targetPadding.top + insets.top,
+ grid.widthPx - targetPadding.right - insets.right,
+ grid.heightPx - targetPadding.bottom - insets.bottom);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index 69e7933..ab19c6e 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -22,7 +22,6 @@
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;
-import static com.android.quickstep.TouchInteractionService.DEBUG_SHOW_OVERVIEW_BUTTON;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
@@ -36,6 +35,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
+import android.util.Log;
import android.view.Choreographer;
import android.view.Display;
import android.view.MotionEvent;
@@ -46,7 +46,6 @@
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.util.TraceHelper;
-import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.AssistDataReceiver;
import com.android.systemui.shared.system.BackgroundExecutor;
@@ -67,13 +66,13 @@
public class OtherActivityTouchConsumer extends ContextWrapper implements TouchConsumer {
private static final long LAUNCHER_DRAW_TIMEOUT_MS = 150;
- private static final int[] DEFERRED_HIT_TARGETS = DEBUG_SHOW_OVERVIEW_BUTTON
+ private static final int[] DEFERRED_HIT_TARGETS = false
? new int[] {HIT_TARGET_BACK, HIT_TARGET_OVERVIEW} : new int[] {HIT_TARGET_BACK};
private final RunningTaskInfo mRunningTask;
private final RecentsModel mRecentsModel;
private final Intent mHomeIntent;
- private final ISystemUiProxy mISystemUiProxy;
+ private final ActivityControlHelper mActivityControlHelper;
private final MainThreadExecutor mMainThreadExecutor;
private final Choreographer mBackgroundThreadChoreographer;
@@ -93,7 +92,7 @@
private boolean mIsGoingToHome;
public OtherActivityTouchConsumer(Context base, RunningTaskInfo runningTaskInfo,
- RecentsModel recentsModel, Intent homeIntent, ISystemUiProxy systemUiProxy,
+ RecentsModel recentsModel, Intent homeIntent, ActivityControlHelper activityControl,
MainThreadExecutor mainThreadExecutor, Choreographer backgroundThreadChoreographer,
@HitTarget int downHitTarget, VelocityTracker velocityTracker) {
super(base);
@@ -101,7 +100,7 @@
mRecentsModel = recentsModel;
mHomeIntent = homeIntent;
mVelocityTracker = velocityTracker;
- mISystemUiProxy = systemUiProxy;
+ mActivityControlHelper = activityControl;
mMainThreadExecutor = mainThreadExecutor;
mBackgroundThreadChoreographer = backgroundThreadChoreographer;
mIsDeferredDownTarget = Arrays.binarySearch(DEFERRED_HIT_TARGETS, downHitTarget) >= 0;
@@ -205,8 +204,8 @@
private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
// Create the shared handler
- final WindowTransformSwipeHandler handler =
- new WindowTransformSwipeHandler(mRunningTask, this, touchTimeMs);
+ final WindowTransformSwipeHandler handler = new WindowTransformSwipeHandler(
+ mRunningTask, this, touchTimeMs, mActivityControlHelper);
// Preload the plan
mRecentsModel.loadTasks(mRunningTask.id, null);
@@ -223,8 +222,7 @@
handler.initWhenReady();
TraceHelper.beginSection("RecentsController");
- Runnable startActivity = () -> ActivityManagerWrapper.getInstance()
- .startRecentsActivity(mHomeIntent,
+ Runnable startActivity = () -> mActivityControlHelper.startRecents(this, mHomeIntent,
new AssistDataReceiver() {
@Override
public void onHandleAssistData(Bundle bundle) {
@@ -253,7 +251,7 @@
handler.onRecentsAnimationCanceled();
}
}
- }, null, null);
+ });
if (Looper.myLooper() != Looper.getMainLooper()) {
startActivity.run();
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index ef58fad..38c25a3 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -16,7 +16,6 @@
package com.android.quickstep;
import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.quickstep.TouchInteractionService.DEBUG_SHOW_OVERVIEW_BUTTON;
import android.annotation.TargetApi;
import android.app.ActivityManager.RecentTaskInfo;
@@ -33,6 +32,8 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.states.InternalStateHandler;
+import com.android.quickstep.ActivityControlHelper.FallbackActivityControllerHelper;
+import com.android.quickstep.ActivityControlHelper.LauncherActivityControllerHelper;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -42,7 +43,7 @@
@TargetApi(Build.VERSION_CODES.P)
public class OverviewCommandHelper extends InternalStateHandler {
- private static final boolean DEBUG_START_FALLBACK_ACTIVITY = DEBUG_SHOW_OVERVIEW_BUTTON;
+ private static final boolean DEBUG_START_FALLBACK_ACTIVITY = false;
private final Context mContext;
private final ActivityManagerWrapper mAM;
@@ -61,7 +62,15 @@
.setPackage(context.getPackageName())
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ResolveInfo info = context.getPackageManager().resolveActivity(homeIntent, 0);
- launcher = new ComponentName(context.getPackageName(), info.activityInfo.name);
+
+ if (DEBUG_START_FALLBACK_ACTIVITY) {
+ launcher = new ComponentName(context, RecentsActivity.class);
+ homeIntent.addCategory(Intent.CATEGORY_DEFAULT)
+ .removeCategory(Intent.CATEGORY_HOME);
+ } else {
+ launcher = new ComponentName(context.getPackageName(), info.activityInfo.name);
+ }
+
// Clear the packageName as system can fail to dedupe it b/64108432
homeIntent.setComponent(launcher).setPackage(null);
}
@@ -74,7 +83,7 @@
public void onOverviewToggle() {
getLauncher().runOnUiThread(() -> {
- if (DEBUG_START_FALLBACK_ACTIVITY) {
+ if (isUsingFallbackActivity()) {
mContext.startActivity(new Intent(mContext, RecentsActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent
.FLAG_ACTIVITY_CLEAR_TASK));
@@ -147,4 +156,15 @@
return false;
}
+ public boolean isUsingFallbackActivity() {
+ return DEBUG_START_FALLBACK_ACTIVITY;
+ }
+
+ public ActivityControlHelper getActivityControlHelper() {
+ if (DEBUG_START_FALLBACK_ACTIVITY) {
+ return new FallbackActivityControllerHelper();
+ } else {
+ return new LauncherActivityControllerHelper();
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
index 4af89bf..522a883 100644
--- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
@@ -15,20 +15,28 @@
*/
package com.android.quickstep;
-import static com.android.quickstep.TouchInteractionService.DEBUG_SHOW_OVERVIEW_BUTTON;
+import static com.android.launcher3.Utilities.getPrefs;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_QUICK_SCRUB;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_HIDE_BACK_BUTTON;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.support.annotation.WorkerThread;
import android.util.Log;
+import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.util.UiThreadHelper;
import com.android.systemui.shared.recents.ISystemUiProxy;
+import java.util.concurrent.ExecutionException;
+
/**
* Sets overview interaction flags, such as:
*
@@ -39,55 +47,109 @@
*
* @see com.android.systemui.shared.system.NavigationBarCompat.InteractionType and associated flags.
*/
-public class OverviewInteractionState {
+public class OverviewInteractionState implements OnSharedPreferenceChangeListener {
private static final String TAG = "OverviewFlags";
- private static final Handler sUiHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- updateOverviewInteractionFlag((Context) msg.obj, msg.what, msg.arg1 == 1);
- }
- };
- private static final Handler sBackgroundHandler = new Handler(
- UiThreadHelper.getBackgroundLooper()) {
- @Override
- public void handleMessage(Message msg) {
- ISystemUiProxy systemUiProxy = (ISystemUiProxy) msg.obj;
- int flags = msg.what;
- try {
- systemUiProxy.setInteractionState(flags);
- } catch (RemoteException e) {
- Log.w(TAG, "Unable to update overview interaction flags", e);
+
+ // We do not need any synchronization for this variable as its only written on UI thread.
+ private static OverviewInteractionState INSTANCE;
+
+ public static OverviewInteractionState getInstance(final Context context) {
+ if (INSTANCE == null) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ INSTANCE = new OverviewInteractionState(context.getApplicationContext());
+ } else {
+ try {
+ return new MainThreadExecutor().submit(
+ () -> OverviewInteractionState.getInstance(context)).get();
+ } catch (InterruptedException|ExecutionException e) {
+ throw new RuntimeException(e);
+ }
}
}
- };
-
- private static int sFlags = DEBUG_SHOW_OVERVIEW_BUTTON ? FLAG_SHOW_OVERVIEW_BUTTON : 0;
-
- public static void setBackButtonVisible(Context context, boolean visible) {
- updateFlagOnUi(context, FLAG_HIDE_BACK_BUTTON, !visible);
+ return INSTANCE;
}
- private static void updateFlagOnUi(Context context, int flag, boolean enabled) {
- sUiHandler.removeMessages(flag);
- sUiHandler.sendMessage(sUiHandler.obtainMessage(flag, enabled ? 1 : 0, 0, context));
+ private static final String KEY_SWIPE_UP_ENABLED = "pref_enable_quickstep";
+
+ private static final int MSG_SET_PROXY = 200;
+ private static final int MSG_SET_BACK_BUTTON_VISIBLE = 201;
+ private static final int MSG_SET_SWIPE_UP_ENABLED = 202;
+
+ private final Handler mUiHandler;
+ private final Handler mBgHandler;
+
+ // These are updated on the background thread
+ private ISystemUiProxy mISystemUiProxy;
+ private boolean mBackButtonVisible = true;
+ private boolean mSwipeUpEnabled = true;
+
+ private OverviewInteractionState(Context context) {
+ mUiHandler = new Handler(this::handleUiMessage);
+ mBgHandler = new Handler(UiThreadHelper.getBackgroundLooper(), this::handleBgMessage);
+
+ SharedPreferences prefs = getPrefs(context);
+ prefs.registerOnSharedPreferenceChangeListener(this);
+ onSharedPreferenceChanged(prefs, KEY_SWIPE_UP_ENABLED);
}
- private static void updateOverviewInteractionFlag(Context context, int flag, boolean enabled) {
- if (enabled) {
- sFlags |= flag;
- } else {
- sFlags &= ~flag;
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences prefs, String s) {
+ if (KEY_SWIPE_UP_ENABLED.equals(s)) {
+ mUiHandler.removeMessages(MSG_SET_SWIPE_UP_ENABLED);
+ boolean swipeUpEnabled = prefs.getBoolean(s, true);
+ mUiHandler.obtainMessage(MSG_SET_SWIPE_UP_ENABLED,
+ swipeUpEnabled ? 1 : 0, 0).sendToTarget();
}
+ }
- ISystemUiProxy systemUiProxy = RecentsModel.getInstance(context).getSystemUiProxy();
- if (systemUiProxy == null) {
- Log.w(TAG, "Unable to update overview interaction flags; not bound to service");
+ public void setBackButtonVisible(boolean visible) {
+ mUiHandler.removeMessages(MSG_SET_BACK_BUTTON_VISIBLE);
+ mUiHandler.obtainMessage(MSG_SET_BACK_BUTTON_VISIBLE, visible ? 1 : 0, 0)
+ .sendToTarget();
+ }
+
+ public void setSystemUiProxy(ISystemUiProxy proxy) {
+ mBgHandler.obtainMessage(MSG_SET_PROXY, proxy).sendToTarget();
+ }
+
+ private boolean handleUiMessage(Message msg) {
+ mBgHandler.obtainMessage(msg.what, msg.arg1, msg.arg2).sendToTarget();
+ return true;
+ }
+
+ private boolean handleBgMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_PROXY:
+ mISystemUiProxy = (ISystemUiProxy) msg.obj;
+ break;
+ case MSG_SET_BACK_BUTTON_VISIBLE:
+ mBackButtonVisible = msg.arg1 != 0;
+ break;
+ case MSG_SET_SWIPE_UP_ENABLED:
+ mSwipeUpEnabled = msg.arg1 != 0;
+ break;
+ }
+ applyFlags();
+ return true;
+ }
+
+ @WorkerThread
+ private void applyFlags() {
+ if (mISystemUiProxy == null) {
return;
}
- // If we aren't already setting these flags, do so now on the background thread.
- if (!sBackgroundHandler.hasMessages(sFlags)) {
- sBackgroundHandler.sendMessage(sBackgroundHandler.obtainMessage(sFlags, systemUiProxy));
+
+ int flags;
+ if (mSwipeUpEnabled) {
+ flags = mBackButtonVisible ? 0 : FLAG_HIDE_BACK_BUTTON;
+ } else {
+ flags = FLAG_DISABLE_SWIPE_UP | FLAG_DISABLE_QUICK_SCRUB | FLAG_SHOW_OVERVIEW_BUTTON;
+ }
+ try {
+ mISystemUiProxy.setInteractionState(flags);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to update overview interaction flags", e);
}
}
}
diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java
index a154b29..d263fbf 100644
--- a/quickstep/src/com/android/quickstep/QuickScrubController.java
+++ b/quickstep/src/com/android/quickstep/QuickScrubController.java
@@ -84,7 +84,10 @@
}
int page = mRecentsView.getNextPage();
Runnable launchTaskRunnable = () -> {
- ((TaskView) mRecentsView.getPageAt(page)).launchTask(true);
+ TaskView taskView = ((TaskView) mRecentsView.getPageAt(page));
+ if (taskView != null) {
+ taskView.launchTask(true);
+ }
};
int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen())
* QUICKSCRUB_END_SNAP_DURATION_PER_PAGE;
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 1d443fd..12e1a2b 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -25,6 +25,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.badge.BadgeInfo;
+import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.views.BaseDragLayer;
/**
@@ -49,6 +50,8 @@
setContentView(R.layout.fallback_recents_activity);
mRecentsRootView = findViewById(R.id.drag_layer);
mFallbackRecentsView = findViewById(R.id.overview_panel);
+
+ RecentsActivityTracker.onRecentsActivityCreate(this);
}
@Override
@@ -57,6 +60,11 @@
}
@Override
+ public View getRootView() {
+ return mRecentsRootView;
+ }
+
+ @Override
public <T extends View> T getOverviewPanel() {
return (T) mFallbackRecentsView;
}
@@ -73,4 +81,16 @@
@Override
public void invalidateParent(ItemInfo info) { }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ UiFactory.onStart(this);
+ }
+
+ @Override
+ public void onTrimMemory(int level) {
+ super.onTrimMemory(level);
+ UiFactory.onTrimMemory(this, level);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/RecentsActivityTracker.java b/quickstep/src/com/android/quickstep/RecentsActivityTracker.java
new file mode 100644
index 0000000..6a82dc0
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/RecentsActivityTracker.java
@@ -0,0 +1,65 @@
+/*
+ * 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.quickstep;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+
+import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
+
+import java.lang.ref.WeakReference;
+import java.util.function.BiPredicate;
+
+/**
+ * Utility class to track create/destroy for RecentsActivity
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class RecentsActivityTracker implements ActivityInitListener {
+
+ private static final Object LOCK = new Object();
+ private static WeakReference<RecentsActivityTracker> sTracker = new WeakReference<>(null);
+
+ private final BiPredicate<RecentsActivity, Boolean> mOnInitListener;
+
+ public RecentsActivityTracker(BiPredicate<RecentsActivity, Boolean> onInitListener) {
+ mOnInitListener = onInitListener;
+ }
+
+ @Override
+ public void register() {
+ synchronized (LOCK) {
+ sTracker = new WeakReference<>(this);
+ }
+ }
+
+ @Override
+ public void unregister() {
+ synchronized (LOCK) {
+ if (sTracker.get() == this) {
+ sTracker.clear();
+ }
+ }
+ }
+
+ public static void onRecentsActivityCreate(RecentsActivity activity) {
+ synchronized (LOCK) {
+ RecentsActivityTracker tracker = sTracker.get();
+ if (tracker != null && tracker.mOnInitListener.test(activity, false)) {
+ sTracker.clear();
+ }
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index ecd6c26..df7214e 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -47,7 +47,6 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
-import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.IOverviewProxy;
@@ -61,7 +60,6 @@
@TargetApi(Build.VERSION_CODES.O)
public class TouchInteractionService extends Service {
- public static final boolean DEBUG_SHOW_OVERVIEW_BUTTON = false;
public static final boolean DEBUG_OPEN_OVERVIEW_VIA_ALT_TAB = false;
private static final SparseArray<String> sMotionEventNames;
@@ -107,9 +105,7 @@
mRecentsModel.setSystemUiProxy(mISystemUiProxy);
RemoteRunnable.executeSafely(() -> mISystemUiProxy.setRecentsOnboardingText(
getResources().getString(R.string.recents_swipe_up_onboarding)));
- Launcher launcher = (Launcher) LauncherAppState.getInstance(
- TouchInteractionService.this).getModel().getCallback();
- UiFactory.onLauncherStateOrFocusChanged(launcher);
+ mOverviewInteractionState.setSystemUiProxy(mISystemUiProxy);
}
@Override
@@ -174,6 +170,7 @@
private MainThreadExecutor mMainThreadExecutor;
private ISystemUiProxy mISystemUiProxy;
private OverviewCommandHelper mOverviewCommandHelper;
+ private OverviewInteractionState mOverviewInteractionState;
private Choreographer mMainThreadChoreographer;
private Choreographer mBackgroundThreadChoreographer;
@@ -187,6 +184,7 @@
mOverviewCommandHelper = new OverviewCommandHelper(this);
mMainThreadChoreographer = Choreographer.getInstance();
mEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer);
+ mOverviewInteractionState = OverviewInteractionState.getInstance(this);
sConnected = true;
@@ -235,7 +233,8 @@
tracker = VelocityTracker.obtain();
}
return new OtherActivityTouchConsumer(this, runningTaskInfo, mRecentsModel,
- mOverviewCommandHelper.homeIntent, mISystemUiProxy, mMainThreadExecutor,
+ mOverviewCommandHelper.homeIntent,
+ mOverviewCommandHelper.getActivityControlHelper(), mMainThreadExecutor,
mBackgroundThreadChoreographer, downHitTarget, tracker);
}
}
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 060d680..96cd4a0 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -15,22 +15,16 @@
*/
package com.android.quickstep;
-import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
-import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_START_DURATION;
import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SWITCH;
import static com.android.quickstep.TouchConsumer.isInteractionQuick;
-import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
+import static com.android.systemui.shared.recents.utilities.Utilities
+ .postAtFrontOfQueueAsynchronously;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import android.animation.Animator;
-import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
@@ -53,24 +47,22 @@
import android.view.ViewTreeObserver.OnDrawListener;
import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherState;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.logging.UserEventDispatcher;
-import com.android.launcher3.states.InternalStateHandler;
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.TraceHelper;
-import com.android.launcher3.util.ViewOnDrawExecutor;
+import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
+import com.android.quickstep.ActivityControlHelper.LayoutListener;
import com.android.quickstep.TouchConsumer.InteractionType;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -120,7 +112,7 @@
}
@TargetApi(Build.VERSION_CODES.O)
-public class WindowTransformSwipeHandler extends InternalStateHandler {
+public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName();
private static final boolean DEBUG_STATES = false;
@@ -209,12 +201,14 @@
private final Context mContext;
private final int mRunningTaskId;
+ private final ActivityControlHelper<T> mActivityControlHelper;
+ private final ActivityInitListener mActivityInitListener;
private MultiStateCallback mStateCallback;
private AnimatorPlaybackController mLauncherTransitionController;
- private Launcher mLauncher;
- private LauncherLayoutListener mLauncherLayoutListener;
+ private T mActivity;
+ private LayoutListener mLayoutListener;
private RecentsView mRecentsView;
private QuickScrubController mQuickScrubController;
@@ -237,10 +231,15 @@
private long mLauncherFrameDrawnTime;
private final MetricsLogger mMetricsLogger = new MetricsLogger();
- WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs) {
+ WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs,
+ ActivityControlHelper<T> controller) {
mContext = context;
mRunningTaskId = runningTaskInfo.id;
mTouchTimeMs = touchTimeMs;
+ mActivityControlHelper = controller;
+ mActivityInitListener = mActivityControlHelper
+ .createActivityInitListener(this::onActivityInit);
+
// Register the input consumer on the UI thread, to ensure that it runs after any pending
// unregister calls
mMainExecutor.execute(mInputConsumer::registerInputConsumer);
@@ -313,7 +312,8 @@
mSourceStackBounds.height() - mSourceInsets.bottom);
Rect tempRect = new Rect();
- RecentsView.getPageRect(dp, mContext, tempRect);
+ mTransitionDragLength = mActivityControlHelper
+ .getSwipeUpDestinationAndLength(dp, mContext, tempRect);
mTargetRect.set(tempRect);
mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left,
@@ -334,14 +334,6 @@
Math.max(mSourceStackBounds.width() - scaledTargetRect.right, 0),
Math.max(mSourceStackBounds.height() - scaledTargetRect.bottom, 0));
mSourceRect.set(scaledTargetRect);
-
- Rect targetInsets = dp.getInsets();
- if (dp.isVerticalBarLayout()) {
- int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
- mTransitionDragLength = dp.hotseatBarSizePx + dp.hotseatBarSidePaddingPx + hotseatInset;
- } else {
- mTransitionDragLength = dp.heightPx - tempRect.bottom;
- }
}
private long getFadeInDuration() {
@@ -356,40 +348,39 @@
}
}
- @Override
- protected boolean init(final Launcher launcher, boolean alreadyOnHome) {
- if (launcher == mLauncher) {
+ public void initWhenReady() {
+ mActivityInitListener.register();
+ }
+
+ private boolean onActivityInit(final T activity, Boolean alreadyOnHome) {
+ if (mActivity == activity) {
return true;
}
- if (mLauncher != null) {
+ if (mActivity != null) {
// The launcher may have been recreated as a result of device rotation.
int oldState = mStateCallback.getState() & ~LAUNCHER_UI_STATES;
initStateCallbacks();
mStateCallback.setState(oldState);
- mLauncherLayoutListener.setHandler(null);
+ mLayoutListener.setHandler(null);
}
mWasLauncherAlreadyVisible = alreadyOnHome;
- mLauncher = launcher;
+ mActivity = activity;
- // For the duration of the gesture, lock the screen orientation to ensure that we do not
- // rotate mid-quickscrub
- mLauncher.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK);
-
- mRecentsView = mLauncher.getOverviewPanel();
+ mRecentsView = activity.getOverviewPanel();
mQuickScrubController = mRecentsView.getQuickScrubController();
- mLauncherLayoutListener = new LauncherLayoutListener(mLauncher);
+ mLayoutListener = mActivityControlHelper.createLayoutListener(mActivity);
mStateCallback.setState(STATE_LAUNCHER_PRESENT);
if (alreadyOnHome) {
- onLauncherStart(launcher);
+ onLauncherStart(activity);
} else {
- launcher.setOnStartCallback(this::onLauncherStart);
+ activity.setOnStartCallback(this::onLauncherStart);
}
return true;
}
- private void onLauncherStart(final Launcher launcher) {
- if (mLauncher != launcher) {
+ private void onLauncherStart(final T activity) {
+ if (mActivity != activity) {
return;
}
if ((mStateCallback.getState() & STATE_HANDLER_INVALIDATED) != 0) {
@@ -397,31 +388,21 @@
}
mStateCallback.setState(STATE_LAUNCHER_STARTED);
- LauncherState startState = mLauncher.getStateManager().getState();
- if (startState.disableRestore) {
- startState = mLauncher.getStateManager().getRestState();
- }
- mLauncher.getStateManager().setRestState(startState);
-
- AbstractFloatingView.closeAllOpenViews(mLauncher, mWasLauncherAlreadyVisible);
+ mActivityControlHelper.prepareRecentsUI(mActivity, mWasLauncherAlreadyVisible);
+ AbstractFloatingView.closeAllOpenViews(activity, mWasLauncherAlreadyVisible);
- if (mWasLauncherAlreadyVisible && !mLauncher.getAppTransitionManager().isAnimating()) {
- DeviceProfile dp = mLauncher.getDeviceProfile();
- long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
- mLauncherTransitionController = mLauncher.getStateManager()
- .createAnimationToNewWorkspace(OVERVIEW, accuracy);
+ if (mWasLauncherAlreadyVisible) {
+ mLauncherTransitionController = mActivityControlHelper
+ .createControllerForVisibleActivity(activity);
mLauncherTransitionController.dispatchOnStart();
mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
mStateCallback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_DRAWN);
} else {
TraceHelper.beginSection("WTS-init");
- mLauncher.getStateManager().goToState(OVERVIEW, false);
- TraceHelper.partitionSection("WTS-init", "State changed");
-
// TODO: Implement a better animation for fading in
- View rootView = mLauncher.getRootView();
+ View rootView = activity.getRootView();
rootView.setAlpha(0);
rootView.getViewTreeObserver().addOnDrawListener(new OnDrawListener() {
@@ -430,21 +411,18 @@
TraceHelper.endSection("WTS-init", "Launcher frame is drawn");
rootView.post(() ->
rootView.getViewTreeObserver().removeOnDrawListener(this));
- if (launcher != mLauncher) {
+ if (activity != mActivity) {
return;
}
mStateCallback.setState(STATE_LAUNCHER_DRAWN);
}
});
-
- // Optimization, hide the all apps view to prevent layout while initializing
- mLauncher.getAppsView().setVisibility(View.GONE);
}
mRecentsView.showTask(mRunningTaskId);
mRecentsView.setFirstTaskIconScaledDown(true /* isScaledDown */, false /* animate */);
- mLauncherLayoutListener.open();
+ mLayoutListener.open();
}
public void setLauncherOnDrawCallback(Runnable callback) {
@@ -452,7 +430,7 @@
}
private void launcherFrameDrawn() {
- View rootView = mLauncher.getRootView();
+ View rootView = mActivity.getRootView();
if (rootView.getAlpha() < 1) {
if (mGestureStarted) {
final MultiStateCallback callback = mStateCallback;
@@ -471,7 +449,7 @@
}
private void initializeLauncherAnimationController() {
- mLauncherLayoutListener.setHandler(this);
+ mLayoutListener.setHandler(this);
onLauncherLayoutChanged();
final long transitionDelay = mLauncherFrameDrawnTime - mTouchTimeMs;
@@ -508,7 +486,7 @@
}
private void onQuickInteractionStart() {
- mLauncher.getStateManager().goToState(FAST_OVERVIEW,
+ mActivityControlHelper.onQuickInteractionStart(mActivity,
mWasLauncherAlreadyVisible || mGestureStarted);
mQuickScrubController.onQuickScrubStart(false);
}
@@ -523,32 +501,14 @@
}
/**
- * Called by {@link #mLauncherLayoutListener} when launcher layout changes
+ * Called by {@link #mLayoutListener} when launcher layout changes
*/
public void onLauncherLayoutChanged() {
- initTransitionEndpoints(mLauncher.getDeviceProfile());
+ initTransitionEndpoints(mActivity.getDeviceProfile());
if (!mWasLauncherAlreadyVisible) {
- float startProgress;
- AllAppsTransitionController controller = mLauncher.getAllAppsController();
-
- if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- startProgress = 1;
- } else {
- float scrollRange = Math.max(controller.getShiftRange(), 1);
- startProgress = (mTransitionDragLength / scrollRange) + 1;
- }
- AnimatorSet anim = new AnimatorSet();
- ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(controller, ALL_APPS_PROGRESS,
- startProgress, OVERVIEW.getVerticalProgress(mLauncher));
- shiftAnim.setInterpolator(LINEAR);
- anim.play(shiftAnim);
-
- // TODO: Link this animation to state animation, so that it is cancelled
- // automatically on state change
- anim.setDuration(mTransitionDragLength * 2);
- mLauncherTransitionController =
- AnimatorPlaybackController.wrap(anim, mTransitionDragLength * 2);
+ mLauncherTransitionController = mActivityControlHelper
+ .createControllerForHiddenActivity(mActivity, mTransitionDragLength);
mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
}
}
@@ -661,14 +621,13 @@
}
}
}
-
mRecentsAnimationWrapper.setController(controller, apps);
setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
}
public void onRecentsAnimationCanceled() {
mRecentsAnimationWrapper.setController(null, null);
- clearReference();
+ mActivityInitListener.unregister();
setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
}
@@ -684,9 +643,10 @@
* on both background and UI threads
*/
private void notifyGestureStarted() {
- final Launcher curLauncher = mLauncher;
- if (curLauncher != null) {
- curLauncher.onQuickstepGestureStarted(mWasLauncherAlreadyVisible);
+ final T curActivity = mActivity;
+ if (curActivity != null) {
+ mActivityControlHelper.onQuickstepGestureStarted(
+ curActivity, mWasLauncherAlreadyVisible);
}
}
@@ -770,25 +730,20 @@
mGestureEndCallback.run();
}
- clearReference();
+ mActivityInitListener.unregister();
mInputConsumer.unregisterInputConsumer();
}
private void invalidateHandlerWithLauncher() {
mLauncherTransitionController = null;
- mLauncherLayoutListener.setHandler(null);
- mLauncherLayoutListener.close(false);
-
- // Restore the requested orientation to the user preference after the gesture has ended
- mLauncher.getRotationHelper().setStateHandlerRequest(REQUEST_NONE);
+ mLayoutListener.finish();
mRecentsView.setFirstTaskIconScaledDown(false /* isScaledDown */, false /* animate */);
}
private void resetStateForAnimationCancel() {
- LauncherState startState = mLauncher.getStateManager().getRestState();
- boolean animate = mWasLauncherAlreadyVisible || mGestureStarted;
- mLauncher.getStateManager().goToState(startState, animate);
+ boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted;
+ mActivityControlHelper.onTransitionCancelled(mActivity, wasVisible);
}
public void layoutListenerClosed() {
@@ -817,17 +772,8 @@
if (taskView != null) {
// Defer finishing the animation until the next launcher frame with the
// new thumbnail
- ViewOnDrawExecutor executor = new ViewOnDrawExecutor() {
- @Override
- public void onViewDetachedFromWindow(View v) {
- if (!isCompleted()) {
- runAllTasks();
- }
- }
- };
- executor.attachTo(mLauncher, taskView,
- false /* waitForLoadAnimation */);
- executor.execute(finishTransitionRunnable);
+ mActivityControlHelper.executeOnNextDraw(mActivity, taskView,
+ finishTransitionRunnable);
finishTransitionPosted = true;
}
}
@@ -843,8 +789,7 @@
}
private void setupLauncherUiAfterSwipeUpAnimation() {
- // Re apply state in case we did something funky during the transition.
- mLauncher.getStateManager().reapplyState();
+ mActivityControlHelper.onSwipeUpComplete(mActivity);
// Animate the first icon.
mRecentsView.setFirstTaskIconScaledDown(false /* isScaledDown */, true /* animate */);
diff --git a/quickstep/src/com/android/quickstep/LauncherLayoutListener.java b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
similarity index 83%
rename from quickstep/src/com/android/quickstep/LauncherLayoutListener.java
rename to quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
index fbdbe7a..6b7143d 100644
--- a/quickstep/src/com/android/quickstep/LauncherLayoutListener.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
@@ -13,7 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.quickstep;
+package com.android.quickstep.views;
+
+import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
import android.graphics.Rect;
import android.view.MotionEvent;
@@ -21,11 +23,14 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
+import com.android.quickstep.ActivityControlHelper.LayoutListener;
+import com.android.quickstep.WindowTransformSwipeHandler;
/**
* Floating view which shows the task snapshot allowing it to be dragged and placed.
*/
-public class LauncherLayoutListener extends AbstractFloatingView implements Insettable {
+public class LauncherLayoutListener extends AbstractFloatingView
+ implements Insettable, LayoutListener {
private final Launcher mLauncher;
private WindowTransformSwipeHandler mHandler;
@@ -36,6 +41,7 @@
setVisibility(INVISIBLE);
}
+ @Override
public void setHandler(WindowTransformSwipeHandler handler) {
mHandler = handler;
}
@@ -65,6 +71,7 @@
}
}
+ @Override
public void open() {
if (!mIsOpen) {
mLauncher.getDragLayer().addView(this);
@@ -86,4 +93,11 @@
protected boolean isOfType(int type) {
return (type & TYPE_QUICKSTEP_PREVIEW) != 0;
}
+
+ @Override
+ public void finish() {
+ setHandler(null);
+ close(false);
+ mLauncher.getRotationHelper().setStateHandlerRequest(REQUEST_NONE);
+ }
}
diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml
index 91baf7a..eec57a5 100644
--- a/res/layout/widgets_list_row_view.xml
+++ b/res/layout/widgets_list_row_view.xml
@@ -31,7 +31,6 @@
android:layout_height="@dimen/widget_section_height"
android:background="?android:attr/colorPrimary"
android:drawablePadding="@dimen/widget_section_horizontal_padding"
- android:ellipsize="end"
android:focusable="true"
android:gravity="start|center_vertical"
android:paddingBottom="@dimen/widget_section_vertical_padding"
diff --git a/res/values/styles.xml b/res/values/styles.xml
index ac6a6b1..8076c80 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -112,7 +112,6 @@
<item name="android:focusable">true</item>
<item name="android:gravity">center_horizontal</item>
<item name="android:singleLine">true</item>
- <item name="android:ellipsize">marquee</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:fontFamily">sans-serif-condensed</item>
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 35edaf4..458f7b2 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -55,6 +55,8 @@
private ActionMode mCurrentActionMode;
protected boolean mIsSafeModeEnabled;
+ private OnStartCallback mOnStartCallback;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -85,6 +87,8 @@
public abstract <T extends View> T getOverviewPanel();
+ public abstract View getRootView();
+
public abstract BadgeInfo getBadgeInfoForItem(ItemInfo info);
public abstract void invalidateParent(ItemInfo info);
@@ -188,4 +192,26 @@
protected boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
return false;
}
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ if (mOnStartCallback != null) {
+ mOnStartCallback.onActivityStart(this);
+ mOnStartCallback = null;
+ }
+ }
+
+ public <T extends BaseDraggingActivity> void setOnStartCallback(OnStartCallback<T> callback) {
+ mOnStartCallback = callback;
+ }
+
+ /**
+ * Callback for listening for onStart
+ */
+ public interface OnStartCallback<T extends BaseDraggingActivity> {
+
+ void onActivityStart(T activity);
+ }
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index fc61155..4fd39b0 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -28,6 +28,7 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.v4.graphics.ColorUtils;
+import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.Property;
import android.util.TypedValue;
@@ -163,10 +164,18 @@
mLongPressHelper = new CheckLongPressHelper(this);
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
+ setEllipsize(TruncateAt.END);
setAccessibilityDelegate(mActivity.getAccessibilityDelegate());
}
+ @Override
+ protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+ // Disable marques when not focused to that, so that updating text does not cause relayout.
+ setEllipsize(focused ? TruncateAt.MARQUEE : TruncateAt.END);
+ super.onFocusChanged(focused, direction, previouslyFocusedRect);
+ }
+
/**
* Resets the view so it can be recycled.
*/
@@ -521,31 +530,30 @@
* Sets the icon for this view based on the layout direction.
*/
private void setIcon(Drawable icon) {
- mIcon = icon;
- mIcon.setBounds(0, 0, mIconSize, mIconSize);
if (mIsIconVisible) {
- applyCompoundDrawables(mIcon);
+ applyCompoundDrawables(icon);
}
+ mIcon = icon;
}
public void setIconVisible(boolean visible) {
mIsIconVisible = visible;
- mDisableRelayout = true;
- Drawable icon = mIcon;
- if (!visible) {
- icon = new ColorDrawable(Color.TRANSPARENT);
- icon.setBounds(0, 0, mIconSize, mIconSize);
- }
+ Drawable icon = visible ? mIcon : new ColorDrawable(Color.TRANSPARENT);
applyCompoundDrawables(icon);
- mDisableRelayout = false;
}
protected void applyCompoundDrawables(Drawable icon) {
+ // If we had already set an icon before, disable relayout as the icon size is the
+ // same as before.
+ mDisableRelayout = mIcon != null;
+
+ icon.setBounds(0, 0, mIconSize, mIconSize);
if (mLayoutHorizontal) {
setCompoundDrawablesRelative(icon, null, null, null);
} else {
setCompoundDrawables(null, icon, null, null);
}
+ mDisableRelayout = false;
}
@Override
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index a38ce07..9a3e8a2 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -209,7 +209,6 @@
@Thunk boolean mWorkspaceLoading = true;
- private OnStartCallback mOnStartCallback;
private OnResumeCallback mOnResumeCallback;
private ViewOnDrawExecutor mPendingExecutor;
@@ -401,10 +400,6 @@
return mStateManager;
}
- public LauncherAppTransitionManager getAppTransitionManager() {
- return mAppTransitionManager;
- }
-
protected void overrideTheme(boolean isDark, boolean supportsDarkText) {
if (isDark) {
setTheme(R.style.LauncherThemeDark);
@@ -767,10 +762,6 @@
super.onStart();
FirstFrameAnimatorHelper.setIsVisible(true);
- if (mOnStartCallback != null) {
- mOnStartCallback.onLauncherStart(this);
- mOnStartCallback = null;
- }
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onStart();
}
@@ -1177,6 +1168,7 @@
return mAllAppsController;
}
+ @Override
public LauncherRootView getRootView() {
return (LauncherRootView) mLauncherView;
}
@@ -1258,7 +1250,11 @@
// In all these cases, only animate if we're already on home
AbstractFloatingView.closeAllOpenViews(this, isStarted());
- mStateManager.goToState(NORMAL);
+ if (!isInState(NORMAL)) {
+ // Only change state, if not already the same. This prevents cancelling any
+ // animations running as part of resume
+ mStateManager.goToState(NORMAL);
+ }
// Reset the apps view
if (!alreadyOnHome && mAppsView != null) {
@@ -1775,10 +1771,6 @@
mOnResumeCallback = callback;
}
- public void setOnStartCallback(OnStartCallback callback) {
- mOnStartCallback = callback;
- }
-
/**
* Implementation of the method from LauncherModel.Callbacks.
*/
@@ -2450,12 +2442,4 @@
void onLauncherResume();
}
-
- /**
- * Callback for listening for onStart
- */
- public interface OnStartCallback {
-
- void onLauncherStart(Launcher launcher);
- }
}
diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java
index 19fa3d4..04f9b3a 100644
--- a/src/com/android/launcher3/LauncherAppTransitionManager.java
+++ b/src/com/android/launcher3/LauncherAppTransitionManager.java
@@ -62,13 +62,4 @@
public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
return getDefaultActivityLaunchOptions(launcher, v);
}
-
- /** Cancels the current Launcher transition animation */
- public void finishLauncherAnimation() {
- }
-
- public boolean isAnimating() {
- // We don't know when the activity options are being used.
- return false;
- }
}
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 950a8ac..0463bb1 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -183,7 +183,6 @@
mConfig.reset();
if (!animated) {
- preOnStateTransitionStart();
onStateTransitionStart(state);
for (StateHandler handler : getStateHandlers()) {
handler.setState(state);
@@ -237,7 +236,6 @@
protected AnimatorSet createAnimationToNewWorkspaceInternal(final LauncherState state,
AnimatorSetBuilder builder, final Runnable onCompleteRunnable) {
- preOnStateTransitionStart();
for (StateHandler handler : getStateHandlers()) {
builder.startTag(handler);
@@ -277,15 +275,6 @@
return mConfig.mCurrentAnimation;
}
- private void preOnStateTransitionStart() {
- // If we are still animating to launcher from an app,
- // finish it and let this state animation take over.
- LauncherAppTransitionManager transitionManager = mLauncher.getAppTransitionManager();
- if (transitionManager != null) {
- transitionManager.finishLauncherAnimation();
- }
- }
-
private void onStateTransitionStart(LauncherState state) {
mState.onStateDisabled(mLauncher);
mState = state;
@@ -351,6 +340,15 @@
mConfig.reset();
}
+ /**
+ * Sets the animation as the current state animation, i.e., canceled when
+ * starting another animation and may block some launcher interactions while running.
+ */
+ public void setCurrentAnimation(AnimatorSet anim) {
+ cancelAnimation();
+ mConfig.setAnimation(anim);
+ }
+
private class StartAnimRunnable implements Runnable {
private final AnimatorSet mAnim;
diff --git a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
index 01b63be..a11a8c5 100644
--- a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
+++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
@@ -20,7 +20,6 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.Region;
import android.support.v4.graphics.ColorUtils;
import android.util.AttributeSet;
import android.widget.TextView;