Launch GroupedTaskView from thumbnails

* Previously when starting the remote animation
we were relying on SplitPlaceholderViews to
animate into the proper place since we weren't
launching from the TaskView itself
* Now when launching from a GroupedTaskView,
we use the existing animation that handles that
animation in addition to showing the new split tasks

Fixes: 206608786
Test: Thumbnails animate from home -> overview -> launch
Change-Id: I1499ead7d90cd41e285ed0f4df66ea31f0dfbc95
This commit is contained in:
Vinit Nayak 2021-11-17 17:34:25 -08:00
parent 8c8e2a22da
commit 788821ec4e
5 changed files with 86 additions and 19 deletions

View File

@ -301,7 +301,8 @@ public abstract class BaseQuickstepLauncher extends Launcher
mActionsView = findViewById(R.id.overview_actions_view);
RecentsView overviewPanel = (RecentsView) getOverviewPanel();
SplitSelectStateController controller =
new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this));
new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this),
getStateManager(), getDepthController());
overviewPanel.init(mActionsView, controller);
mActionsView.setDp(getDeviceProfile());
mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));

View File

@ -128,7 +128,8 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
SYSUI_PROGRESS.set(getRootView().getSysUiScrim(), 0f);
SplitSelectStateController controller =
new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this));
new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this),
getStateManager(), null /*depthController*/);
mDragLayer.recreateControllers();
mFallbackRecentsView.init(mActionsView, controller);

View File

@ -56,6 +56,7 @@ import android.view.View;
import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
@ -72,6 +73,7 @@ import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskThumbnailView;
import com.android.quickstep.views.TaskView;
@ -149,10 +151,12 @@ public final class TaskViewUtils {
return taskView;
}
public static void createRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
RemoteAnimationTargetCompat[] nonAppTargets, DepthController depthController,
public static void createRecentsWindowAnimator(
@NonNull TaskView v, boolean skipViewChanges,
@NonNull RemoteAnimationTargetCompat[] appTargets,
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
@NonNull RemoteAnimationTargetCompat[] nonAppTargets,
@Nullable DepthController depthController,
PendingAnimation out) {
RecentsView recentsView = v.getRecentsView();
boolean isQuickSwitch = v.isEndQuickswitchCuj();
@ -418,15 +422,46 @@ public final class TaskViewUtils {
finishCallback.run();
}
/** Legacy version (until shell transitions are enabled) */
public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull Task initialTask,
/**
* Legacy version (until shell transitions are enabled)
*
* If {@param launchingTaskView} is not null, then this will play the tasks launch animation
* from the position of the GroupedTaskView (when user taps on the TaskView to start it).
* Technically this case should be taken care of by
* {@link #composeRecentsSplitLaunchAnimatorLegacy()} below, but the way we launch tasks whether
* it's a single task or multiple tasks results in different entry-points.
*
* If it is null, then it will simply fade in the starting apps and fade out launcher (for the
* case where launcher handles animating starting split tasks from app icon) */
public static void composeRecentsSplitLaunchAnimatorLegacy(
@Nullable GroupedTaskView launchingTaskView,
@NonNull Task initialTask,
@NonNull Task secondTask, @NonNull RemoteAnimationTargetCompat[] appTargets,
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
@NonNull RemoteAnimationTargetCompat[] nonAppTargets,
@NonNull StateManager stateManager,
@Nullable DepthController depthController,
@NonNull Runnable finishCallback) {
if (launchingTaskView != null) {
AnimatorSet animatorSet = new AnimatorSet();
RecentsView recentsView = launchingTaskView.getRecentsView();
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
finishCallback.run();
}
});
composeRecentsLaunchAnimator(animatorSet, launchingTaskView,
appTargets, wallpaperTargets, nonAppTargets,
true, stateManager,
recentsView, depthController);
animatorSet.start();
return;
}
final ArrayList<SurfaceControl> openingTargets = new ArrayList<>();
final ArrayList<SurfaceControl> closingTargets = new ArrayList<>();
for (RemoteAnimationTargetCompat appTarget : appTargets) {
final int taskId = appTarget.taskInfo != null ? appTarget.taskInfo.taskId : -1;
final int mode = appTarget.mode;
@ -490,7 +525,7 @@ public final class TaskViewUtils {
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
@NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing,
@NonNull StateManager stateManager, @NonNull RecentsView recentsView,
@NonNull DepthController depthController) {
@Nullable DepthController depthController) {
boolean skipLauncherChanges = !launcherClosing;
TaskView taskView = findTaskViewToLaunch(recentsView, v, appTargets);

View File

@ -30,11 +30,18 @@ import android.view.RemoteAnimationAdapter;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import androidx.annotation.Nullable;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
@ -52,23 +59,32 @@ public class SplitSelectStateController {
private final Handler mHandler;
private final SystemUiProxy mSystemUiProxy;
private final StateManager mStateManager;
private final DepthController mDepthController;
private @StagePosition int mStagePosition;
private Task mInitialTask;
private Task mSecondTask;
private Rect mInitialBounds;
private boolean mRecentsAnimationRunning;
/** If not null, this is the TaskView we want to launch from */
@Nullable
private GroupedTaskView mLaunchingTaskView;
public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) {
public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy,
StateManager stateManager,
DepthController depthController) {
mHandler = handler;
mSystemUiProxy = systemUiProxy;
mStateManager = stateManager;
mDepthController = depthController;
}
/**
* To be called after first task selected
*/
public void setInitialTaskSelect(Task taskView, @StagePosition int stagePosition,
public void setInitialTaskSelect(Task task, @StagePosition int stagePosition,
Rect initialBounds) {
mInitialTask = taskView;
mInitialTask = task;
mStagePosition = stagePosition;
mInitialBounds = initialBounds;
}
@ -76,12 +92,24 @@ public class SplitSelectStateController {
/**
* To be called after second task selected
*/
public void setSecondTaskId(Task taskView, Consumer<Boolean> callback) {
mSecondTask = taskView;
public void setSecondTaskId(Task task, Consumer<Boolean> callback) {
mSecondTask = task;
launchTasks(mInitialTask, mSecondTask, mStagePosition, callback,
false /* freezeTaskList */);
}
/**
* To be called when we want to launch split pairs from an existing GroupedTaskView.
*/
public void launchTasks(GroupedTaskView groupedTaskView,
Consumer<Boolean> callback, boolean freezeTaskList) {
mLaunchingTaskView = groupedTaskView;
TaskView.TaskIdAttributeContainer[] taskIdAttributeContainers =
groupedTaskView.getTaskIdAttributeContainers();
launchTasks(taskIdAttributeContainers[0].getTask(), taskIdAttributeContainers[1].getTask(),
taskIdAttributeContainers[0].getStagePosition(), callback, freezeTaskList);
}
/**
* @param stagePosition representing location of task1
*/
@ -169,8 +197,9 @@ public class SplitSelectStateController {
RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
Runnable finishedCallback) {
postAsyncCallback(mHandler,
() -> TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTask,
mSecondTask, apps, wallpapers, nonApps, () -> {
() -> TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(
mLaunchingTaskView, mInitialTask, mSecondTask, apps, wallpapers,
nonApps, mStateManager, mDepthController, () -> {
finishedCallback.run();
if (mSuccessCallback != null) {
mSuccessCallback.accept(true);
@ -201,6 +230,7 @@ public class SplitSelectStateController {
mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
mInitialBounds = null;
mRecentsAnimationRunning = false;
mLaunchingTaskView = null;
}
/**

View File

@ -156,8 +156,8 @@ public class GroupedTaskView extends TaskView {
@Nullable
@Override
public RunnableList launchTaskAnimated() {
getRecentsView().getSplitPlaceholder().launchTasks(mTask, mSecondaryTask,
STAGE_POSITION_TOP_OR_LEFT, null /*callback*/,
getRecentsView().getSplitPlaceholder().launchTasks(this /*groupedTaskView*/,
null /*callback*/,
false /* freezeTaskList */);
return null;
}