Merge "Fix a memory leak" into sc-dev am: 29c1e8437e

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/13961425

Change-Id: Ibe9df851507b75b835ac9cd37d5352e6443ea767
This commit is contained in:
Tracy Zhou
2021-03-25 17:18:55 +00:00
committed by Automerger Merge Worker
6 changed files with 187 additions and 135 deletions
@@ -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<T extends StatefulActivity<S>,
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<T extends StatefulActivity<S>,
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<T extends StatefulActivity<S>,
mInputConsumerProxy.destroy();
mTaskAnimationManager.setLiveTileCleanUpHandler(null);
}
mInputConsumerProxy.unregisterCallback();
endRunningWindowAnim(false /* cancel */);
if (mGestureEndCallback != null) {
@@ -1502,36 +1490,13 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
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<T extends StatefulActivity<S>,
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;
@@ -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;
}
}
@@ -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<RemoteAnimationTargetCompat> 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<RemoteAnimationTargetCompat> 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() {
@@ -38,7 +38,8 @@ public class InputConsumerProxy {
private static final String TAG = "InputConsumerProxy";
private final InputConsumerController mInputConsumerController;
private final Supplier<InputConsumer> mConsumerSupplier;
private Runnable mCallback;
private Supplier<InputConsumer> 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<InputConsumer> consumerSupplier) {
Runnable callback, Supplier<InputConsumer> 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;
}
}
}
@@ -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<InputConsumer> {
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);
}
}
@@ -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<T extends StatefulActivity> 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();