Merge "Make recents animation work with fallback activity." into ub-launcher3-master

This commit is contained in:
Sunny Goyal
2018-04-04 21:53:03 +00:00
committed by Android (Google) Code Review
8 changed files with 201 additions and 68 deletions
@@ -106,6 +106,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
private DeviceProfile mDeviceProfile;
private View mFloatingView;
private RemoteAnimationRunnerCompat mRemoteAnimationOverride;
private final AnimatorListenerAdapter mReapplyStateListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -175,6 +177,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
return getDefaultActivityLaunchOptions(launcher, v);
}
public void setRemoteAnimationOverride(RemoteAnimationRunnerCompat remoteAnimationOverride) {
mRemoteAnimationOverride = remoteAnimationOverride;
}
/**
* Try to find a TaskView that corresponds with the component of the launched view.
*
@@ -635,6 +641,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
* Registers remote animations used when closing apps to home screen.
*/
private void registerRemoteAnimations() {
// Unregister this
if (hasControlRemoteAppTransitionPermission()) {
try {
RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat();
@@ -669,12 +676,36 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
private RemoteAnimationRunnerCompat getWallpaperOpenRunner() {
return new LauncherAnimationRunner(mHandler) {
@Override
public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
if (mLauncher.getStateManager().getState().overviewUi) {
// We use a separate transition for Overview mode.
return null;
public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats,
Runnable runnable) {
if (mLauncher.getStateManager().getState().overviewUi
&& mRemoteAnimationOverride != null) {
// This transition is only used for the fallback activity and should not be
// managed here (but necessary to implement here since the defined remote
// animation currently takes precendence over the one defined in the activity
// options).
mRemoteAnimationOverride.onAnimationStart(targetCompats, runnable);
return;
}
super.onAnimationStart(targetCompats, runnable);
}
@Override
public void onAnimationCancelled() {
if (mLauncher.getStateManager().getState().overviewUi
&& mRemoteAnimationOverride != null) {
// This transition is only used for the fallback activity and should not be
// managed here (but necessary to implement here since the defined remote
// animation currently takes precendence over the one defined in the activity
// options).
mRemoteAnimationOverride.onAnimationCancelled();
return;
}
super.onAnimationCancelled();
}
@Override
public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
AnimatorSet anim = new AnimatorSet();
anim.play(getClosingWindowAnimators(targetCompats));
@@ -36,8 +36,10 @@ import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppTransitionManagerImpl;
import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.util.ViewOnDrawExecutor;
@@ -80,7 +82,10 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
ActivityInitListener createActivityInitListener(BiPredicate<T, Boolean> onInitListener);
void startRecents(Context context, Intent intent, AssistDataReceiver assistDataReceiver,
void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
final RecentsAnimationListener remoteAnimationListener);
void startRecentsFromButton(Context context, Intent intent,
RecentsAnimationListener remoteAnimationListener);
@UiThread
@@ -203,21 +208,44 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
}
@Override
public void startRecents(Context context, Intent intent,
AssistDataReceiver assistDataReceiver,
RecentsAnimationListener remoteAnimationListener) {
public void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
final RecentsAnimationListener remoteAnimationListener) {
ActivityManagerWrapper.getInstance().startRecentsActivity(
intent, assistDataReceiver, remoteAnimationListener, null, null);
}
@Override
public void startRecentsFromButton(Context context, Intent intent,
RecentsAnimationListener remoteAnimationListener) {
// We should use the remove animation for the fallback activity recents button case,
// it works better with PiP. In Launcher, we have already registered the remote
// animation definition, which takes priority over explicitly defined remote
// animations in the provided activity options when starting the activity, so we
// just register a remote animation factory to get a callback to handle this.
LauncherAppTransitionManagerImpl appTransitionManager =
(LauncherAppTransitionManagerImpl) getLauncher().getAppTransitionManager();
appTransitionManager.setRemoteAnimationOverride(new RecentsAnimationActivityOptions(
remoteAnimationListener, () -> {
// Once the controller is finished, also reset the remote animation override
appTransitionManager.setRemoteAnimationOverride(null);
}));
context.startActivity(intent);
}
@Nullable
@UiThread
private Launcher getLauncher() {
LauncherAppState app = LauncherAppState.getInstanceNoCreate();
if (app == null) {
return null;
}
return (Launcher) app.getModel().getCallback();
}
@Nullable
@UiThread
private Launcher getVisibleLaucher() {
LauncherAppState app = LauncherAppState.getInstanceNoCreate();
if (app == null) {
return null;
}
Launcher launcher = (Launcher) app.getModel().getCallback();
Launcher launcher = getLauncher();
return (launcher != null) && launcher.isStarted() && launcher.hasWindowFocus() ?
launcher : null;
}
@@ -325,12 +353,23 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
}
@Override
public void startRecents(Context context, Intent intent,
AssistDataReceiver assistDataReceiver,
public void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
final RecentsAnimationListener remoteAnimationListener) {
ActivityOptions options =
ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
new FallbackActivityOptions(remoteAnimationListener), 10000, 10000));
// We can use the normal recents animation for swipe up
ActivityManagerWrapper.getInstance().startRecentsActivity(
intent, assistDataReceiver, remoteAnimationListener, null, null);
}
@Override
public void startRecentsFromButton(Context context, Intent intent,
RecentsAnimationListener remoteAnimationListener) {
// We should use the remove animation for the fallback activity recents button case,
// it works better with PiP. For the fallback activity, we should not have registered
// the launcher app transition manager, so we should just start the remote animation here.
ActivityOptions options = ActivityOptionsCompat.makeRemoteAnimation(
new RemoteAnimationAdapterCompat(
new RecentsAnimationActivityOptions(remoteAnimationListener, null),
10000, 10000));
context.startActivity(intent, options.toBundle());
}
@@ -218,7 +218,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
handler.initWhenReady();
TraceHelper.beginSection("RecentsController");
Runnable startActivity = () -> mActivityControlHelper.startRecents(this, mHomeIntent,
Runnable startActivity = () -> mActivityControlHelper.startRecentsFromSwipe(mHomeIntent,
new AssistDataReceiver() {
@Override
public void onHandleAssistData(Bundle bundle) {
@@ -53,6 +53,7 @@ import com.android.quickstep.ActivityControlHelper.LauncherActivityControllerHel
import com.android.quickstep.util.SysuiEventLogger;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
@@ -77,7 +78,7 @@ public class OverviewCommandHelper extends InternalStateHandler {
private static final int RID_CANCEL_CONTROLLER = 1;
private static final int RID_CANCEL_ZOOM_OUT_ANIMATION = 2;
private static final long RECENTS_LAUNCH_DURATION = 150;
private static final long RECENTS_LAUNCH_DURATION = 200;
private static final String TAG = "OverviewCommandHelper";
private static final boolean DEBUG_START_FALLBACK_ACTIVITY = false;
@@ -151,12 +152,13 @@ public class OverviewCommandHelper extends InternalStateHandler {
private void initSwipeHandler(ActivityControlHelper helper, long time,
Consumer<WindowTransformSwipeHandler> onAnimationInitCallback) {
final int commandId = mCurrentCommandId;
RunningTaskInfo taskInfo = ActivityManagerWrapper.getInstance().getRunningTask();
final RunningTaskInfo runningTask = ActivityManagerWrapper.getInstance().getRunningTask();
final int runningTaskId = runningTask.id;
final WindowTransformSwipeHandler handler =
new WindowTransformSwipeHandler(taskInfo, mContext, time, helper);
new WindowTransformSwipeHandler(runningTask, mContext, time, helper);
// Preload the plan
mRecentsModel.loadTasks(taskInfo.id, null);
mRecentsModel.loadTasks(runningTaskId, null);
mWindowTransformSwipeHandler = handler;
mTempTaskTargetRect.setEmpty();
@@ -172,13 +174,8 @@ public class OverviewCommandHelper extends InternalStateHandler {
addFinishCommand(commandId, RID_RESET_SWIPE_HANDLER, handler::reset);
TraceHelper.beginSection(TAG);
Runnable startActivity = () -> helper.startRecents(mContext, homeIntent,
new AssistDataReceiver() {
@Override
public void onHandleAssistData(Bundle bundle) {
mRecentsModel.preloadAssistData(taskInfo.id, bundle);
}
},
Runnable startActivity = () -> helper.startRecentsFromButton(mContext,
addToIntent(homeIntent),
new RecentsAnimationListener() {
public void onAnimationStart(
RecentsAnimationControllerCompat controller,
@@ -190,11 +187,17 @@ public class OverviewCommandHelper extends InternalStateHandler {
minimizedHomeBounds);
mTempTaskTargetRect.set(handler.getTargetRect(mWindowSize));
ThumbnailData thumbnail = mAM.getTaskThumbnail(runningTaskId,
true /* reducedResolution */);
mMainThreadExecutor.execute(() -> {
addFinishCommand(commandId,
RID_CANCEL_CONTROLLER, () -> controller.finish(true));
if (commandId == mCurrentCommandId) {
onAnimationInitCallback.accept(handler);
// The animation has started, which means the other activity
// should be paused, lets update the thumbnail
handler.switchToScreenshotImmediate(thumbnail);
}
});
} else {
@@ -230,7 +233,7 @@ public class OverviewCommandHelper extends InternalStateHandler {
});
handler.onGestureStarted();
anim.setDuration(RECENTS_LAUNCH_DURATION);
anim.setInterpolator(Interpolators.AGGRESSIVE_EASE);
anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
anim.start();
addFinishCommand(commandId, RID_CANCEL_ZOOM_OUT_ANIMATION, anim::cancel);
}
@@ -241,6 +244,7 @@ public class OverviewCommandHelper extends InternalStateHandler {
return;
}
ActivityManagerWrapper.getInstance().closeSystemWindows("recentapps");
long time = SystemClock.elapsedRealtime();
mMainThreadExecutor.execute(() -> {
long elapsedTime = time - mLastToggleTime;
@@ -248,40 +252,37 @@ public class OverviewCommandHelper extends InternalStateHandler {
mCurrentCommandId++;
mTempTaskTargetRect.round(mTaskTargetRect);
boolean isQuickTap = elapsedTime < ViewConfiguration.getDoubleTapTimeout();
int runnableCount = mCurrentCommandFinishRunnables.size();
if (runnableCount > 0) {
for (int i = 0; i < runnableCount; i++) {
mCurrentCommandFinishRunnables.valueAt(i).run();
}
mCurrentCommandFinishRunnables.clear();
isQuickTap = true;
}
// TODO: We need to fix this case with PIP, when an activity first enters PIP, it shows
// the menu activity which takes window focus, prevening the right condition from
// being run below
ActivityControlHelper helper = getActivityControlHelper();
RecentsView recents = helper.getVisibleRecentsView();
if (recents != null) {
int childCount = recents.getChildCount();
if (childCount != 0) {
((TaskView) recents.getChildAt(childCount >= 2 ? 1 : 0)).launchTask(true);
// Launch the next task
recents.showNextTask();
} else {
if (elapsedTime < ViewConfiguration.getDoubleTapTimeout()) {
// The user tried to launch back into overview too quickly, either after
// launching an app, or before overview has actually shown, just ignore for now
return;
}
// There are not enough tasks. Skip
return;
// Start overview
if (helper.switchToRecentsIfVisible()) {
SysuiEventLogger.writeDummyRecentsTransition(0);
// Do nothing
} else {
initSwipeHandler(helper, time, this::startZoomOutAnim);
}
}
if (isQuickTap) {
// Focus last task. Start is on background thread so that all ActivityManager calls
// are serialized
BackgroundExecutor.get().submit(this::startLastTask);
return;
}
if (helper.switchToRecentsIfVisible()) {
SysuiEventLogger.writeDummyRecentsTransition(0);
return;
}
initSwipeHandler(helper, time, this::startZoomOutAnim);
});
}
@@ -362,10 +363,6 @@ public class OverviewCommandHelper extends InternalStateHandler {
return false;
}
public boolean isUsingFallbackActivity() {
return DEBUG_START_FALLBACK_ACTIVITY;
}
public ActivityControlHelper getActivityControlHelper() {
if (DEBUG_START_FALLBACK_ACTIVITY) {
return new FallbackActivityControllerHelper();
@@ -24,24 +24,33 @@ import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.TransactionCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
import java.util.function.Consumer;
/**
* Temporary class to create activity options to emulate recents transition for fallback activtiy.
* Class to create activity options to emulate recents transition.
*/
public class FallbackActivityOptions implements RemoteAnimationRunnerCompat {
public class RecentsAnimationActivityOptions implements RemoteAnimationRunnerCompat {
private final RecentsAnimationListener mListener;
private final Runnable mFinishCallback;
public FallbackActivityOptions(RecentsAnimationListener listener) {
public RecentsAnimationActivityOptions(RecentsAnimationListener listener,
Runnable finishCallback) {
mListener = listener;
mFinishCallback = finishCallback;
}
@Override
public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats,
Runnable runnable) {
showOpeningTarget(targetCompats);
DummyRecentsAnimationControllerCompat dummyRecentsAnim =
new DummyRecentsAnimationControllerCompat(runnable);
RemoteRecentsAnimationControllerCompat dummyRecentsAnim =
new RemoteRecentsAnimationControllerCompat(() -> {
runnable.run();
if (mFinishCallback != null) {
mFinishCallback.run();
}
});
Rect insets = new Rect();
WindowManagerWrapper.getInstance().getStableInsets(insets);
@@ -54,23 +63,22 @@ public class FallbackActivityOptions implements RemoteAnimationRunnerCompat {
}
private void showOpeningTarget(RemoteAnimationTargetCompat[] targetCompats) {
TransactionCompat t = new TransactionCompat();
for (RemoteAnimationTargetCompat target : targetCompats) {
TransactionCompat t = new TransactionCompat();
int layer = target.mode == RemoteAnimationTargetCompat.MODE_CLOSING
? Integer.MAX_VALUE
: target.prefixOrderIndex;
t.setLayer(target.leash, layer);
t.show(target.leash);
t.apply();
}
t.apply();
}
private static class DummyRecentsAnimationControllerCompat
extends RecentsAnimationControllerCompat {
private class RemoteRecentsAnimationControllerCompat extends RecentsAnimationControllerCompat {
final Runnable mFinishCallback;
public DummyRecentsAnimationControllerCompat(Runnable finishCallback) {
public RemoteRecentsAnimationControllerCompat(Runnable finishCallback) {
mFinishCallback = finishCallback;
}
@@ -87,7 +95,8 @@ public class FallbackActivityOptions implements RemoteAnimationRunnerCompat {
@Override
public void finish(boolean toHome) {
if (toHome) {
// This should never be called with toHome == false
if (mFinishCallback != null) {
mFinishCallback.run();
}
}
@@ -158,6 +158,16 @@ public class RecentsModel extends TaskStackChangeListener {
return requestId;
}
@Override
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
mTaskChangeId++;
}
@Override
public void onActivityUnpinned() {
mTaskChangeId++;
}
@Override
public void onTaskStackChanged() {
mTaskChangeId++;
@@ -196,6 +196,10 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
private final long mTouchTimeMs;
private long mLauncherFrameDrawnTime;
// Only used with the recents activity, when the screenshot should be fetched at the beginning
// of the animation and not at the end when the activity is already paused
private boolean mSkipScreenshotAtEndOfTransition;
WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs,
ActivityControlHelper<T> controller) {
mContext = context;
@@ -582,7 +586,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
mSourceStackBounds.set(target.sourceContainerBounds);
initTransitionEndpoints(dp);
break;
}
}
}
@@ -725,8 +728,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
() -> setStateOnUiThread(STATE_SWITCH_TO_SCREENSHOT_COMPLETE));
}
};
synchronized (mRecentsAnimationWrapper) {
if (mRecentsAnimationWrapper.controller != null) {
if (mRecentsAnimationWrapper.controller != null && !mSkipScreenshotAtEndOfTransition) {
TransactionCompat transaction = new TransactionCompat();
for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
if (app.mode == MODE_CLOSING) {
@@ -753,6 +757,12 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
doLogGesture(true /* toLauncher */);
}
@UiThread
public void switchToScreenshotImmediate(ThumbnailData thumbnail) {
mRecentsView.updateThumbnail(mRunningTaskId, thumbnail);
mSkipScreenshotAtEndOfTransition = true;
}
private void setupLauncherUiAfterSwipeUpAnimation() {
if (mLauncherTransitionController != null) {
mLauncherTransitionController.getAnimationPlayer().end();
@@ -138,6 +138,26 @@ public abstract class RecentsView<T extends BaseActivity>
}
}
}
@Override
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
// Check this is for the right user
if (!checkCurrentUserId(userId, false /* debug */)) {
return;
}
// Remove the task immediately from the task list
TaskView taskView = getTaskView(taskId);
if (taskView != null) {
removeView(taskView);
}
}
@Override
public void onActivityUnpinned() {
// TODO: Re-enable layout transitions for addition of the unpinned task
reloadIfNeeded();
}
};
private int mLoadPlanId = -1;
@@ -595,6 +615,23 @@ public abstract class RecentsView<T extends BaseActivity>
}
}
public void showNextTask() {
TaskView runningTaskView = getTaskView(mRunningTaskId);
if (runningTaskView == null) {
// Launch the first task
if (getChildCount() > 0) {
((TaskView) getChildAt(0)).launchTask(true /* animate */);
}
} else {
// Get the next launch task
int runningTaskIndex = indexOfChild(runningTaskView);
int nextTaskIndex = Math.max(0, Math.min(getChildCount() - 1, runningTaskIndex + 1));
if (nextTaskIndex < getChildCount()) {
((TaskView) getChildAt(nextTaskIndex)).launchTask(true /* animate */);
}
}
}
public QuickScrubController getQuickScrubController() {
return mQuickScrubController;
}