diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index 52db0017b8..d3b05763ff 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -27,7 +27,6 @@ import android.content.Context; import android.content.Intent; import android.graphics.Rect; import android.os.Handler; -import android.os.Looper; import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.view.View; @@ -40,15 +39,16 @@ 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.util.LayoutUtils; import com.android.quickstep.util.RemoteAnimationProvider; +import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.quickstep.views.LauncherLayoutListener; import com.android.quickstep.views.RecentsView; -import com.android.quickstep.views.TaskView; +import com.android.quickstep.views.RecentsViewContainer; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.function.BiPredicate; +import java.util.function.Consumer; /** * Utility class which abstracts out the logical differences between Launcher and RecentsActivity. @@ -67,19 +67,14 @@ public interface ActivityControlHelper { void executeOnWindowAvailable(T activity, Runnable action); - 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); + AnimationFactory prepareRecentsUI(T activity, boolean activityVisible, + Consumer callback); ActivityInitListener createActivityInitListener(BiPredicate onInitListener); @@ -130,20 +125,6 @@ public interface ActivityControlHelper { } } - @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) { LayoutUtils.calculateLauncherTaskSize(context, dp, outRect); @@ -169,7 +150,8 @@ public interface ActivityControlHelper { } @Override - public void prepareRecentsUI(Launcher activity, boolean activityVisible) { + public AnimationFactory prepareRecentsUI(Launcher activity, boolean activityVisible, + Consumer callback) { LauncherState startState = activity.getStateManager().getState(); if (startState.disableRestore) { startState = activity.getStateManager().getRestState(); @@ -185,37 +167,41 @@ public interface ActivityControlHelper { // Optimization, hide the all apps view to prevent layout while initializing activity.getAppsView().getContentView().setVisibility(View.GONE); } + + return (transitionLength) -> + createActivityController(activity, activityVisible, transitionLength, callback); } - @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); - } + private void createActivityController(Launcher activity, boolean wasVisible, + long transitionLength, Consumer callback) { + if (wasVisible) { + DeviceProfile dp = activity.getDeviceProfile(); + long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx); + callback.accept(activity.getStateManager() + .createAnimationToNewWorkspace(OVERVIEW, accuracy)); + return; + } + + if (activity.getDeviceProfile().isVerticalBarLayout()) { + return; + } - @Override - public AnimatorPlaybackController createControllerForHiddenActivity( - Launcher activity, int transitionLength) { AllAppsTransitionController controller = activity.getAllAppsController(); AnimatorSet anim = new AnimatorSet(); - if (activity.getDeviceProfile().isVerticalBarLayout()) { - // TODO: - } else { - float scrollRange = Math.max(controller.getShiftRange(), 1); - float progressDelta = (transitionLength / scrollRange); - float endProgress = OVERVIEW.getVerticalProgress(activity); - float startProgress = endProgress + progressDelta; - ObjectAnimator shiftAnim = ObjectAnimator.ofFloat( - controller, ALL_APPS_PROGRESS, startProgress, endProgress); - shiftAnim.setInterpolator(LINEAR); - anim.play(shiftAnim); - } + float scrollRange = Math.max(controller.getShiftRange(), 1); + float progressDelta = (transitionLength / scrollRange); + + float endProgress = OVERVIEW.getVerticalProgress(activity); + float startProgress = endProgress + progressDelta; + ObjectAnimator shiftAnim = ObjectAnimator.ofFloat( + controller, ALL_APPS_PROGRESS, startProgress, endProgress); + shiftAnim.setInterpolator(LINEAR); + anim.play(shiftAnim); anim.setDuration(transitionLength * 2); activity.getStateManager().setCurrentAnimation(anim); - return AnimatorPlaybackController.wrap(anim, transitionLength * 2); + callback.accept(AnimatorPlaybackController.wrap(anim, transitionLength * 2)); } @Override @@ -294,13 +280,6 @@ public interface ActivityControlHelper { action.run(); } - @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: @@ -324,23 +303,43 @@ public interface ActivityControlHelper { } @Override - public void prepareRecentsUI(RecentsActivity activity, boolean activityVisible) { - // TODO: - } + public AnimationFactory prepareRecentsUI(RecentsActivity activity, boolean activityVisible, + Consumer callback) { + if (activityVisible) { + return (transitionLength) -> { }; + } - @Override - public AnimatorPlaybackController createControllerForVisibleActivity( - RecentsActivity activity) { - DeviceProfile dp = activity.getDeviceProfile(); - return createControllerForHiddenActivity(activity, Math.max(dp.widthPx, dp.heightPx)); - } + RecentsViewContainer rv = activity.getOverviewPanelContainer(); + rv.setContentAlpha(0); - @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); + return new AnimationFactory() { + + boolean isAnimatingHome = false; + + @Override + public void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) { + isAnimatingHome = targets != null && targets.isAnimatingHome(); + if (!isAnimatingHome) { + rv.setContentAlpha(1); + } + createActivityController(getSwipeUpDestinationAndLength( + activity.getDeviceProfile(), activity, new Rect())); + } + + @Override + public void createActivityController(long transitionLength) { + if (!isAnimatingHome) { + return; + } + + ObjectAnimator anim = ObjectAnimator + .ofFloat(rv, RecentsViewContainer.CONTENT_ALPHA, 0, 1); + anim.setDuration(transitionLength).setInterpolator(LINEAR); + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.play(anim); + callback.accept(AnimatorPlaybackController.wrap(animatorSet, transitionLength)); + } + }; } @Override @@ -423,4 +422,11 @@ public interface ActivityControlHelper { void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider, Context context, Handler handler, long duration); } + + interface AnimationFactory { + + default void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) { } + + void createActivityController(long transitionLength); + } } diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index 663a005759..cac7606121 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -26,6 +26,7 @@ import static com.android.systemui.shared.system.PackageManagerWrapper .ACTION_PREFERRED_ACTIVITY_CHANGED; import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; +import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING; import android.animation.AnimatorSet; import android.animation.ValueAnimator; @@ -36,6 +37,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ResolveInfo; +import android.graphics.Matrix.ScaleToFit; import android.graphics.Rect; import android.os.Build; import android.os.PatternMatcher; @@ -49,6 +51,7 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.quickstep.ActivityControlHelper.ActivityInitListener; +import com.android.quickstep.ActivityControlHelper.AnimationFactory; import com.android.quickstep.ActivityControlHelper.FallbackActivityControllerHelper; import com.android.quickstep.ActivityControlHelper.LauncherActivityControllerHelper; import com.android.quickstep.util.ClipAnimationHelper; @@ -59,6 +62,7 @@ import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.PackageManagerWrapper; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import com.android.systemui.shared.system.TransactionCompat; import java.util.ArrayList; @@ -254,15 +258,17 @@ public class OverviewCommandHelper { private boolean onActivityReady(T activity, Boolean wasVisible) { activity.getOverviewPanel().setCurrentTask(mRunningTaskId); AbstractFloatingView.closeAllOpenViews(activity, wasVisible); - mHelper.prepareRecentsUI(activity, wasVisible); + AnimationFactory factory = mHelper.prepareRecentsUI(activity, wasVisible, + (controller) -> { + controller.dispatchOnStart(); + ValueAnimator anim = controller.getAnimationPlayer() + .setDuration(RECENTS_LAUNCH_DURATION); + anim.setInterpolator(FAST_OUT_SLOW_IN); + anim.start(); + }); + factory.onRemoteAnimationReceived(null); if (wasVisible) { - AnimatorPlaybackController controller = - mHelper.createControllerForVisibleActivity(activity); - controller.dispatchOnStart(); - ValueAnimator anim = - controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION); - anim.setInterpolator(FAST_OUT_SLOW_IN); - anim.start(); + factory.createActivityController(RECENTS_LAUNCH_DURATION); } mActivity = activity; return false; @@ -283,7 +289,6 @@ public class OverviewCommandHelper { RemoteAnimationTargetSet targetSet = new RemoteAnimationTargetSet(targetCompats, MODE_CLOSING); - // Use the top closing app to determine the insets for the animation RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mRunningTaskId); if (runningTaskTarget == null) { @@ -313,6 +318,22 @@ public class OverviewCommandHelper { valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); valueAnimator.addUpdateListener((v) -> clipHelper.applyTransform(targetSet, (float) v.getAnimatedValue())); + + if (targetSet.isAnimatingHome()) { + // If we are animating home, fade in the opening targets + RemoteAnimationTargetSet openingSet = + new RemoteAnimationTargetSet(targetCompats, MODE_OPENING); + + TransactionCompat transaction = new TransactionCompat(); + valueAnimator.addUpdateListener((v) -> { + for (RemoteAnimationTargetCompat app : openingSet.apps) { + transaction.setAlpha(app.leash, (float) v.getAnimatedValue()); + transaction.show(app.leash); + } + transaction.setEarlyWakeup(); + transaction.apply(); + }); + } anim.play(valueAnimator); return anim; } diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java index 551984aa4d..0185ab91d1 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/src/com/android/quickstep/RecentsActivity.java @@ -51,6 +51,7 @@ import com.android.launcher3.util.Themes; import com.android.launcher3.views.BaseDragLayer; import com.android.quickstep.fallback.FallbackRecentsView; import com.android.quickstep.fallback.RecentsRootView; +import com.android.quickstep.views.RecentsViewContainer; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; @@ -65,6 +66,7 @@ public class RecentsActivity extends BaseDraggingActivity { private Handler mUiHandler = new Handler(Looper.getMainLooper()); private RecentsRootView mRecentsRootView; private FallbackRecentsView mFallbackRecentsView; + private RecentsViewContainer mOverviewPanelContainer; private Configuration mOldConfig; @@ -78,6 +80,7 @@ public class RecentsActivity extends BaseDraggingActivity { setContentView(R.layout.fallback_recents_activity); mRecentsRootView = findViewById(R.id.drag_layer); mFallbackRecentsView = findViewById(R.id.overview_panel); + mOverviewPanelContainer = findViewById(R.id.overview_panel_container); mRecentsRootView.setup(); @@ -153,6 +156,10 @@ public class RecentsActivity extends BaseDraggingActivity { return (T) mFallbackRecentsView; } + public RecentsViewContainer getOverviewPanelContainer() { + return mOverviewPanelContainer; + } + @Override public BadgeInfo getBadgeInfoForItem(ItemInfo info) { return null; @@ -210,6 +217,9 @@ public class RecentsActivity extends BaseDraggingActivity { @Override protected void onStart() { + // Set the alpha to 1 before calling super, as it may get set back to 0 due to + // onActivityStart callback. + mFallbackRecentsView.setContentAlpha(1); super.onStart(); UiFactory.onStart(this); mFallbackRecentsView.resetTaskVisuals(); diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index 0944a7a26f..51848cc5cd 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -63,6 +63,7 @@ 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.quickstep.ActivityControlHelper.ActivityInitListener; +import com.android.quickstep.ActivityControlHelper.AnimationFactory; import com.android.quickstep.ActivityControlHelper.LayoutListener; import com.android.quickstep.TouchConsumer.InteractionType; import com.android.quickstep.util.ClipAnimationHelper; @@ -164,6 +165,7 @@ public class WindowTransformSwipeHandler { private LayoutListener mLayoutListener; private RecentsView mRecentsView; private QuickScrubController mQuickScrubController; + private AnimationFactory mAnimationFactory = (t) -> { }; private Runnable mLauncherDrawnCallback; @@ -212,11 +214,13 @@ public class WindowTransformSwipeHandler { mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN, this::launcherFrameDrawn); mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED, - this::onGestureStartedWithLauncher); + this::notifyGestureStartedAsync); mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_STARTED | STATE_GESTURE_CANCELLED, this::resetStateForAnimationCancel); + mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_APP_CONTROLLER_RECEIVED, + this::sendRemoteAnimationsToAnimationFactory); mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED | STATE_SCALED_CONTROLLER_APP, this::resumeLastTask); @@ -321,7 +325,8 @@ public class WindowTransformSwipeHandler { return; } - mActivityControlHelper.prepareRecentsUI(mActivity, mWasLauncherAlreadyVisible); + mAnimationFactory = mActivityControlHelper.prepareRecentsUI(mActivity, + mWasLauncherAlreadyVisible, this::onAnimatorPlaybackControllerCreated); AbstractFloatingView.closeAllOpenViews(activity, mWasLauncherAlreadyVisible); if (mWasLauncherAlreadyVisible) { @@ -377,9 +382,13 @@ public class WindowTransformSwipeHandler { mLauncherFrameDrawnTime = SystemClock.uptimeMillis(); } + private void sendRemoteAnimationsToAnimationFactory() { + mAnimationFactory.onRemoteAnimationReceived(mRecentsAnimationWrapper.targetSet); + } + private void initializeLauncherAnimationController() { mLayoutListener.setHandler(this); - onLauncherLayoutChanged(); + buildAnimationController(); final long transitionDelay = mLauncherFrameDrawnTime - mTouchTimeMs; SysuiEventLogger.writeDummyRecentsTransition(transitionDelay); @@ -418,15 +427,15 @@ public class WindowTransformSwipeHandler { /** * Called by {@link #mLayoutListener} when launcher layout changes */ - public void onLauncherLayoutChanged() { + public void buildAnimationController() { initTransitionEndpoints(mActivity.getDeviceProfile()); + mAnimationFactory.createActivityController(mTransitionDragLength); + } - if (!mWasLauncherAlreadyVisible) { - mLauncherTransitionController = mActivityControlHelper - .createControllerForHiddenActivity(mActivity, mTransitionDragLength); - mLauncherTransitionController.dispatchOnStart(); - mLauncherTransitionController.setPlayFraction(mCurrentShift.value); - } + private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) { + mLauncherTransitionController = anim; + mLauncherTransitionController.dispatchOnStart(); + mLauncherTransitionController.setPlayFraction(mCurrentShift.value); } @WorkerThread @@ -546,17 +555,6 @@ public class WindowTransformSwipeHandler { } } - private void onGestureStartedWithLauncher() { - notifyGestureStartedAsync(); - - if (mWasLauncherAlreadyVisible) { - mLauncherTransitionController = mActivityControlHelper - .createControllerForVisibleActivity(mActivity); - mLauncherTransitionController.dispatchOnStart(); - mLauncherTransitionController.setPlayFraction(mCurrentShift.value); - } - } - @WorkerThread public void onGestureEnded(float endVelocity) { Resources res = mContext.getResources(); diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java index 9dd83d20a6..20108ebb5e 100644 --- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java +++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java @@ -25,7 +25,6 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.views.BaseDragLayer; import com.android.quickstep.views.TaskThumbnailView; import com.android.systemui.shared.recents.utilities.RectFEvaluator; @@ -111,14 +110,17 @@ public class ClipAnimationHelper { mClipRect.bottom = (int) (mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress)); - mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL); - TransactionCompat transaction = new TransactionCompat(); for (RemoteAnimationTargetCompat app : targetSet.apps) { - mTmpMatrix.postTranslate(app.position.x, app.position.y); - transaction.setMatrix(app.leash, mTmpMatrix) - .setWindowCrop(app.leash, mClipRect); - if (app.isNotInRecents) { + if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { + mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL); + mTmpMatrix.postTranslate(app.position.x, app.position.y); + transaction.setMatrix(app.leash, mTmpMatrix) + .setWindowCrop(app.leash, mClipRect); + } + + if (app.isNotInRecents + || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { transaction.setAlpha(app.leash, 1 - progress); } transaction.show(app.leash); diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java index fc889e54e6..97d7fb9209 100644 --- a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java +++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java @@ -24,23 +24,18 @@ import java.util.ArrayList; */ public class RemoteAnimationTargetSet { - public final boolean allTransparent; public final RemoteAnimationTargetCompat[] apps; public RemoteAnimationTargetSet(RemoteAnimationTargetCompat[] apps, int targetMode) { - boolean allTransparent = true; - ArrayList filteredApps = new ArrayList<>(); if (apps != null) { for (RemoteAnimationTargetCompat target : apps) { if (target.mode == targetMode) { - allTransparent &= target.isTranslucent; filteredApps.add(target); } } } - this.allTransparent = allTransparent; this.apps = filteredApps.toArray(new RemoteAnimationTargetCompat[filteredApps.size()]); } @@ -52,4 +47,13 @@ public class RemoteAnimationTargetSet { } return null; } + + public boolean isAnimatingHome() { + for (RemoteAnimationTargetCompat target : apps) { + if (target.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { + return true; + } + } + return false; + } } diff --git a/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java index ac34d90b1d..c149de54f0 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java +++ b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java @@ -54,7 +54,7 @@ public class LauncherLayoutListener extends AbstractFloatingView @Override public void setInsets(Rect insets) { if (mHandler != null) { - mHandler.onLauncherLayoutChanged(); + mHandler.buildAnimationController(); } }