From 773050d228287b42e4a1beec2b89c6533e65c251 Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Mon, 22 Mar 2021 19:47:46 -0700 Subject: [PATCH] Fix a memory leak Currently we pass a callback from AbsSwipeUpHandler to TaskAnimationManager to render task view launch animation, exposing the launcher activity to the static TouchInteractionService, which causes the leak. To not only fix the leak, but consider a better place for this functionality semantically, RecentsView is a better home. Fixes: 183458638 Test: Run presubmit Change-Id: Id35d0ad22005003d2516c34515a5cb338605be0b --- .../android/quickstep/AbsSwipeUpHandler.java | 108 ++---------------- .../quickstep/RecentsAnimationTargets.java | 9 -- .../quickstep/TaskAnimationManager.java | 49 +++++--- .../quickstep/util/InputConsumerProxy.java | 28 +++-- .../util/InputProxyHandlerFactory.java | 53 +++++++++ .../android/quickstep/views/RecentsView.java | 75 ++++++++++++ 6 files changed, 187 insertions(+), 135 deletions(-) create mode 100644 quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index f4ef1f7e47..c91fa9fd5c 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -22,7 +22,6 @@ import static android.widget.Toast.LENGTH_SHORT; import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER; import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS; -import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION; import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; @@ -97,8 +96,8 @@ import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.util.InputConsumerProxy; +import com.android.quickstep.util.InputProxyHandlerFactory; import com.android.quickstep.util.MotionPauseDetector; -import com.android.quickstep.util.MultiValueUpdateListener; import com.android.quickstep.util.ProtoTracer; import com.android.quickstep.util.RecentsOrientedState; import com.android.quickstep.util.RectFSpringAnim; @@ -113,12 +112,10 @@ import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import com.android.systemui.shared.system.LatencyTrackerCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; import com.android.systemui.shared.system.TaskInfoCompat; import com.android.systemui.shared.system.TaskStackChangeListener; import java.util.ArrayList; -import java.util.Arrays; import java.util.function.Consumer; /** @@ -255,7 +252,10 @@ public abstract class AbsSwipeUpHandler, mActivityInterface = gestureState.getActivityInterface(); mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit); mInputConsumerProxy = - new InputConsumerProxy(inputConsumer, this::createNewInputProxyHandler); + new InputConsumerProxy(inputConsumer, () -> { + endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */); + endLauncherTransitionController(); + }, new InputProxyHandlerFactory(mActivityInterface, mGestureState)); mTaskAnimationManager = taskAnimationManager; mTouchTimeMs = touchTimeMs; mContinuingLastGesture = continuingLastGesture; @@ -783,19 +783,6 @@ public abstract class AbsSwipeUpHandler, handleNormalGestureEnd(endVelocity, isFling, velocity, false /* isCancel */); } - /** - * Called to create a input proxy for the running task - */ - @UiThread - protected InputConsumer createNewInputProxyHandler() { - endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */); - endLauncherTransitionController(); - - StatefulActivity activity = mActivityInterface.getCreatedActivity(); - return activity == null ? InputConsumer.NO_OP - : new OverviewInputConsumer(mGestureState, activity, null, true); - } - private void endRunningWindowAnim(boolean cancel) { if (mRunningWindowAnim != null) { if (cancel) { @@ -1338,6 +1325,7 @@ public abstract class AbsSwipeUpHandler, mInputConsumerProxy.destroy(); mTaskAnimationManager.setLiveTileCleanUpHandler(null); } + mInputConsumerProxy.unregisterCallback(); endRunningWindowAnim(false /* cancel */); if (mGestureEndCallback != null) { @@ -1502,36 +1490,13 @@ public abstract class AbsSwipeUpHandler, protected abstract void finishRecentsControllerToHome(Runnable callback); - private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() { - @Override - public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, - boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) { - if (mRecentsView.getRunningTaskIndex() != -1 - && mRecentsView.getRunningTaskId() == task.taskId - && mRecentsAnimationTargets.hasTask(task.taskId)) { - launchOtherTaskInLiveTileMode(task.taskId, mRecentsAnimationTargets.apps); - } - ActivityManagerWrapper.getInstance().unregisterTaskStackListener( - mLiveTileRestartListener); - } - }; - private void setupLauncherUiAfterSwipeUpToRecentsAnimation() { endLauncherTransitionController(); mActivityInterface.onSwipeUpToRecentsComplete(); mRecentsView.onSwipeUpAnimationSuccess(); if (LIVE_TILE.get()) { - mTaskAnimationManager.setLaunchOtherTaskInLiveTileModeHandler( - appearedTaskTarget -> { - RemoteAnimationTargetCompat[] apps = Arrays.copyOf( - mRecentsAnimationTargets.apps, - mRecentsAnimationTargets.apps.length + 1); - apps[apps.length - 1] = appearedTaskTarget; - launchOtherTaskInLiveTileMode(appearedTaskTarget.taskId, apps); - }); mTaskAnimationManager.setLiveTileCleanUpHandler(mInputConsumerProxy::destroy); - ActivityManagerWrapper.getInstance().registerTaskStackListener( - mLiveTileRestartListener); + mTaskAnimationManager.enableLiveTileRestartListener(); } SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG); @@ -1539,65 +1504,6 @@ public abstract class AbsSwipeUpHandler, reset(); } - private void launchOtherTaskInLiveTileMode(int taskId, RemoteAnimationTargetCompat[] apps) { - AnimatorSet anim = new AnimatorSet(); - TaskView taskView = mRecentsView.getTaskView(taskId); - if (taskView == null || !mRecentsView.isTaskViewVisible(taskView)) { - // TODO: Refine this animation. - SurfaceTransactionApplier surfaceApplier = - new SurfaceTransactionApplier(mActivity.getDragLayer()); - ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); - appAnimator.setDuration(RECENTS_LAUNCH_DURATION); - appAnimator.setInterpolator(ACCEL_DEACCEL); - appAnimator.addUpdateListener(new MultiValueUpdateListener() { - @Override - public void onUpdate(float percent) { - SurfaceParams.Builder builder = new SurfaceParams.Builder( - apps[apps.length - 1].leash); - Matrix matrix = new Matrix(); - matrix.postScale(percent, percent); - matrix.postTranslate(mDp.widthPx * (1 - percent) / 2, - mDp.heightPx * (1 - percent) / 2); - builder.withAlpha(percent).withMatrix(matrix); - surfaceApplier.scheduleApply(builder.build()); - } - }); - anim.play(appAnimator); - } else { - TaskViewUtils.composeRecentsLaunchAnimator( - anim, taskView, apps, - mRecentsAnimationTargets.wallpapers, true /* launcherClosing */, - mActivity.getStateManager(), mRecentsView, - mActivityInterface.getDepthController()); - } - anim.addListener(new AnimatorListenerAdapter(){ - - @Override - public void onAnimationEnd(Animator animator) { - cleanUp(false); - } - - @Override - public void onAnimationCancel(Animator animator) { - cleanUp(true); - } - - private void cleanUp(boolean canceled) { - if (mRecentsAnimationController != null) { - mRecentsAnimationController.finish(false /* toRecents */, - null /* onFinishComplete */); - if (canceled) { - mRecentsAnimationController = null; - } else { - mActivityInterface.onLaunchTaskSuccess(); - } - ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false); - } - } - }); - anim.start(); - } - private static boolean isNotInRecents(RemoteAnimationTargetCompat app) { return app.isNotInRecents || app.activityType == ACTIVITY_TYPE_HOME; diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java index da0a66431e..718c5baa2c 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java @@ -41,13 +41,4 @@ public class RecentsAnimationTargets extends RemoteAnimationTargets { public boolean hasTargets() { return unfilteredApps.length != 0; } - - public boolean hasTask(int taskId) { - for (RemoteAnimationTargetCompat target : unfilteredApps) { - if (target.taskId == taskId) { - return true; - } - } - return false; - } } diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index 9a454f2bd7..b6dad2d385 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -17,10 +17,11 @@ package com.android.quickstep; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; -import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS; import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED; import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED; +import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE; +import android.app.ActivityManager; import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -31,13 +32,13 @@ import androidx.annotation.UiThread; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; +import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.RemoteTransitionCompat; - -import java.util.function.Consumer; +import com.android.systemui.shared.system.TaskStackChangeListener; public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener { public static final boolean ENABLE_SHELL_TRANSITIONS = @@ -49,10 +50,24 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn // Temporary until we can hook into gesture state events private GestureState mLastGestureState; private RemoteAnimationTargetCompat mLastAppearedTaskTarget; - private Consumer mLaunchOtherTaskHandler; private Runnable mLiveTileCleanUpHandler; private Context mCtx; + private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() { + @Override + public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, + boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) { + BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface(); + if (LIVE_TILE.get() && activityInterface.isInLiveTileMode() + && activityInterface.getCreatedActivity() != null) { + RecentsView recentsView = activityInterface.getCreatedActivity().getOverviewPanel(); + recentsView.launchSideTaskInLiveTileModeForRestartedApp(task.taskId); + ActivityManagerWrapper.getInstance().unregisterTaskStackListener( + mLiveTileRestartListener); + } + } + }; + TaskAnimationManager(Context ctx) { mCtx = ctx; } @@ -114,9 +129,14 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn @Override public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) { - if (mLaunchOtherTaskHandler != null - && mLastGestureState.getEndTarget() == RECENTS) { - mLaunchOtherTaskHandler.accept(appearedTaskTarget); + BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface(); + if (LIVE_TILE.get() && activityInterface.isInLiveTileMode() + && activityInterface.getCreatedActivity() != null) { + RecentsView recentsView = + activityInterface.getCreatedActivity().getOverviewPanel(); + RemoteAnimationTargetCompat[] apps = new RemoteAnimationTargetCompat[1]; + apps[0] = appearedTaskTarget; + recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId, apps); return; } if (mController != null) { @@ -161,17 +181,12 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn return mCallbacks; } - /** - * The passed-in handler is used to render side task launch animation in recents in live tile - * mode. - */ - public void setLaunchOtherTaskInLiveTileModeHandler( - Consumer handler) { - mLaunchOtherTaskHandler = handler; + public void setLiveTileCleanUpHandler(Runnable cleanUpHandler) { + mLiveTileCleanUpHandler = cleanUpHandler; } - public void setLiveTileCleanUpHandler(Runnable runnable) { - mLiveTileCleanUpHandler = runnable; + public void enableLiveTileRestartListener() { + ActivityManagerWrapper.getInstance().registerTaskStackListener(mLiveTileRestartListener); } /** @@ -215,6 +230,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn mLiveTileCleanUpHandler.run(); mLiveTileCleanUpHandler = null; } + ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mLiveTileRestartListener); // Release all the target leashes if (mTargets != null) { @@ -231,7 +247,6 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn mTargets = null; mLastGestureState = null; mLastAppearedTaskTarget = null; - mLaunchOtherTaskHandler = null; } public void dump() { diff --git a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java index 3e87f48f02..2e5b33ae24 100644 --- a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java +++ b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java @@ -38,7 +38,8 @@ public class InputConsumerProxy { private static final String TAG = "InputConsumerProxy"; private final InputConsumerController mInputConsumerController; - private final Supplier mConsumerSupplier; + private Runnable mCallback; + private Supplier mConsumerSupplier; // The consumer is created lazily on demand. private InputConsumer mInputConsumer; @@ -48,8 +49,9 @@ public class InputConsumerProxy { private boolean mDestroyPending = false; public InputConsumerProxy(InputConsumerController inputConsumerController, - Supplier consumerSupplier) { + Runnable callback, Supplier consumerSupplier) { mInputConsumerController = inputConsumerController; + mCallback = callback; mConsumerSupplier = consumerSupplier; } @@ -64,9 +66,7 @@ public class InputConsumerProxy { if (ev instanceof MotionEvent) { onInputConsumerMotionEvent((MotionEvent) ev); } else if (ev instanceof KeyEvent) { - if (mInputConsumer == null) { - mInputConsumer = mConsumerSupplier.get(); - } + initInputConsumerIfNeeded(); mInputConsumer.onKeyEvent((KeyEvent) ev); return true; } @@ -89,9 +89,7 @@ public class InputConsumerProxy { if (action == ACTION_DOWN) { mTouchInProgress = true; - if (mInputConsumer == null) { - mInputConsumer = mConsumerSupplier.get(); - } + initInputConsumerIfNeeded(); } else if (action == ACTION_CANCEL || action == ACTION_UP) { // Finish any pending actions mTouchInProgress = false; @@ -115,4 +113,18 @@ public class InputConsumerProxy { mDestroyed = true; mInputConsumerController.setInputListener(null); } + + public void unregisterCallback() { + mCallback = null; + } + + private void initInputConsumerIfNeeded() { + if (mInputConsumer == null) { + if (mCallback != null) { + mCallback.run(); + } + mInputConsumer = mConsumerSupplier.get(); + mConsumerSupplier = null; + } + } } diff --git a/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java new file mode 100644 index 0000000000..8209c09304 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.util; + +import androidx.annotation.UiThread; + +import com.android.launcher3.statemanager.StatefulActivity; +import com.android.quickstep.BaseActivityInterface; +import com.android.quickstep.GestureState; +import com.android.quickstep.InputConsumer; +import com.android.quickstep.inputconsumers.OverviewInputConsumer; + +import java.util.function.Supplier; + +/** + * A factory that creates a input consumer for + * {@link com.android.quickstep.util.InputConsumerProxy}. + */ +public class InputProxyHandlerFactory implements Supplier { + + private final BaseActivityInterface mActivityInterface; + private final GestureState mGestureState; + + @UiThread + public InputProxyHandlerFactory(BaseActivityInterface activityInterface, + GestureState gestureState) { + mActivityInterface = activityInterface; + mGestureState = gestureState; + } + + /** + * Called to create a input proxy for the running task + */ + @Override + public InputConsumer get() { + StatefulActivity activity = mActivityInterface.getCreatedActivity(); + return activity == null ? InputConsumer.NO_OP + : new OverviewInputConsumer(mGestureState, activity, null, true); + } +} diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index d357ebead0..769344080a 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -27,6 +27,7 @@ import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA; import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK; import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT; +import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION; import static com.android.launcher3.Utilities.EDGE_NAV_BAR; import static com.android.launcher3.Utilities.mapToRange; import static com.android.launcher3.Utilities.squaredHypot; @@ -34,6 +35,7 @@ import static com.android.launcher3.Utilities.squaredTouchSlop; import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.ACCEL_0_75; import static com.android.launcher3.anim.Interpolators.ACCEL_2; +import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL; @@ -50,6 +52,7 @@ import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_RECENTS; import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.LayoutTransition; import android.animation.LayoutTransition.TransitionListener; @@ -61,6 +64,7 @@ import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; import android.content.res.Configuration; import android.graphics.Canvas; +import android.graphics.Matrix; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; @@ -129,8 +133,11 @@ import com.android.quickstep.RecentsModel.TaskVisualsChangeListener; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TaskOverlayFactory; import com.android.quickstep.TaskThumbnailCache; +import com.android.quickstep.TaskViewUtils; import com.android.quickstep.ViewUtils; +import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.LayoutUtils; +import com.android.quickstep.util.MultiValueUpdateListener; import com.android.quickstep.util.RecentsOrientedState; import com.android.quickstep.util.SplitScreenBounds; import com.android.quickstep.util.SurfaceTransactionApplier; @@ -142,6 +149,8 @@ import com.android.systemui.shared.recents.model.Task.TaskKey; import com.android.systemui.shared.recents.model.ThumbnailData; 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.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.wm.shell.pip.IPipAnimationListener; @@ -715,6 +724,72 @@ public abstract class RecentsView extends PagedView super.draw(canvas); } + public void launchSideTaskInLiveTileModeForRestartedApp(int taskId) { + if (mRunningTaskId != -1 && mRunningTaskId == taskId && + getLiveTileParams().getTargetSet().findTask(taskId) != null) { + launchSideTaskInLiveTileMode(taskId, getLiveTileParams().getTargetSet().apps); + } + } + + public void launchSideTaskInLiveTileMode(int taskId, RemoteAnimationTargetCompat[] apps) { + AnimatorSet anim = new AnimatorSet(); + TaskView taskView = getTaskView(taskId); + if (taskView == null || !isTaskViewVisible(taskView)) { + // TODO: Refine this animation. + SurfaceTransactionApplier surfaceApplier = + new SurfaceTransactionApplier(mActivity.getDragLayer()); + ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); + appAnimator.setDuration(RECENTS_LAUNCH_DURATION); + appAnimator.setInterpolator(ACCEL_DEACCEL); + appAnimator.addUpdateListener(new MultiValueUpdateListener() { + @Override + public void onUpdate(float percent) { + SurfaceParams.Builder builder = new SurfaceParams.Builder( + apps[apps.length - 1].leash); + Matrix matrix = new Matrix(); + matrix.postScale(percent, percent); + matrix.postTranslate(mActivity.getDeviceProfile().widthPx * (1 - percent) / 2, + mActivity.getDeviceProfile().heightPx * (1 - percent) / 2); + builder.withAlpha(percent).withMatrix(matrix); + surfaceApplier.scheduleApply(builder.build()); + } + }); + anim.play(appAnimator); + } else { + TaskViewUtils.composeRecentsLaunchAnimator( + anim, taskView, apps, + mLiveTileParams.getTargetSet().wallpapers, true /* launcherClosing */, + mActivity.getStateManager(), this, + getDepthController()); + } + anim.addListener(new AnimatorListenerAdapter(){ + + @Override + public void onAnimationEnd(Animator animator) { + cleanUp(false); + } + + @Override + public void onAnimationCancel(Animator animator) { + cleanUp(true); + } + + private void cleanUp(boolean canceled) { + if (mRecentsAnimationController != null) { + mRecentsAnimationController.finish(false /* toRecents */, + null /* onFinishComplete */); + if (canceled) { + mRecentsAnimationController = null; + } else { + mSizeStrategy.onLaunchTaskSuccess(); + } + ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false); + } + } + }); + anim.start(); + } + private void updateTaskStartIndex(View affectingView) { if (!(affectingView instanceof TaskView) && !(affectingView instanceof ClearAllButton)) { int childCount = getChildCount();