Loading quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java +44 −0 Original line number Original line Diff line number Diff line Loading @@ -15,14 +15,23 @@ */ */ package com.android.launcher3.popup; package com.android.launcher3.popup; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.util.Log; import android.view.View; import android.view.View; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; import com.android.quickstep.views.RecentsView; public interface QuickstepSystemShortcut { public interface QuickstepSystemShortcut { String TAG = QuickstepSystemShortcut.class.getSimpleName(); static SystemShortcut.Factory<BaseQuickstepLauncher> getSplitSelectShortcutByPosition( static SystemShortcut.Factory<BaseQuickstepLauncher> getSplitSelectShortcutByPosition( SplitPositionOption position) { SplitPositionOption position) { return (activity, itemInfo) -> new QuickstepSystemShortcut.SplitSelectSystemShortcut( return (activity, itemInfo) -> new QuickstepSystemShortcut.SplitSelectSystemShortcut( Loading @@ -46,6 +55,41 @@ public interface QuickstepSystemShortcut { @Override @Override public void onClick(View view) { public void onClick(View view) { Bitmap bitmap; Intent intent; if (mItemInfo instanceof WorkspaceItemInfo) { final WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) mItemInfo; bitmap = workspaceItemInfo.bitmap.icon; intent = workspaceItemInfo.intent; } else if (mItemInfo instanceof com.android.launcher3.model.data.AppInfo) { final com.android.launcher3.model.data.AppInfo appInfo = (com.android.launcher3.model.data.AppInfo) mItemInfo; bitmap = appInfo.bitmap.icon; intent = appInfo.intent; } else { Log.e(TAG, "unknown item type"); return; } RecentsView recentsView = mLauncher.getOverviewPanel(); recentsView.initiateSplitSelect( new SplitSelectSource(view, new BitmapDrawable(bitmap), intent, mPosition)); } } class SplitSelectSource { public final View view; public final Drawable drawable; public final Intent intent; public final SplitPositionOption position; public SplitSelectSource(View view, Drawable drawable, Intent intent, SplitPositionOption position) { this.view = view; this.drawable = drawable; this.intent = intent; this.position = position; } } } } } } quickstep/src/com/android/quickstep/SystemUiProxy.java +15 −0 Original line number Original line Diff line number Diff line Loading @@ -608,6 +608,21 @@ public class SystemUiProxy implements ISystemUiProxy, } } } } public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent, int taskId, boolean intentFirst, Bundle mainOptions, Bundle sideOptions, @SplitConfigurationOptions.StagePosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) { if (mSystemUiProxy != null) { try { mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, fillInIntent, taskId, intentFirst, mainOptions, sideOptions, sidePosition, splitRatio, adapter); } catch (RemoteException e) { Log.w(TAG, "Failed call startTasksWithLegacyTransition"); } } } public void startShortcut(String packageName, String shortcutId, int position, public void startShortcut(String packageName, String shortcutId, int position, Bundle options, UserHandle user) { Bundle options, UserHandle user) { if (mSplitScreen != null) { if (mSplitScreen != null) { Loading quickstep/src/com/android/quickstep/TaskViewUtils.java +30 −16 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ */ package com.android.quickstep; package com.android.quickstep; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.TRANSIT_TO_FRONT; Loading Loading @@ -46,6 +47,7 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.annotation.TargetApi; import android.app.PendingIntent; import android.content.ComponentName; import android.content.ComponentName; import android.content.Context; import android.content.Context; import android.graphics.Matrix; import android.graphics.Matrix; Loading Loading @@ -389,18 +391,20 @@ public final class TaskViewUtils { * device is considered in multiWindowMode and things like insets and stuff change * device is considered in multiWindowMode and things like insets and stuff change * and calculations have to be adjusted in the animations for that * and calculations have to be adjusted in the animations for that */ */ public static void composeRecentsSplitLaunchAnimator(@NonNull Task initalTask, public static void composeRecentsSplitLaunchAnimator(int initialTaskId, @NonNull Task secondTask, @NonNull TransitionInfo transitionInfo, @Nullable PendingIntent initialTaskPendingIntent, int secondTaskId, SurfaceControl.Transaction t, @NonNull Runnable finishCallback) { @NonNull TransitionInfo transitionInfo, SurfaceControl.Transaction t, @NonNull Runnable finishCallback) { final TransitionInfo.Change[] splitRoots = new TransitionInfo.Change[2]; // TODO: consider initialTaskPendingIntent TransitionInfo.Change splitRoot1 = null; TransitionInfo.Change splitRoot2 = null; for (int i = 0; i < transitionInfo.getChanges().size(); ++i) { for (int i = 0; i < transitionInfo.getChanges().size(); ++i) { final TransitionInfo.Change change = transitionInfo.getChanges().get(i); final TransitionInfo.Change change = transitionInfo.getChanges().get(i); final int taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1; final int taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1; final int mode = change.getMode(); final int mode = change.getMode(); // Find the target tasks' root tasks since those are the split stages that need to // Find the target tasks' root tasks since those are the split stages that need to // be animated (the tasks themselves are children and thus inherit animation). // be animated (the tasks themselves are children and thus inherit animation). if (taskId == initalTask.key.id || taskId == secondTask.key.id) { if (taskId == initialTaskId || taskId == secondTaskId) { if (!(mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) { if (!(mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) { throw new IllegalStateException( throw new IllegalStateException( "Expected task to be showing, but it is " + mode); "Expected task to be showing, but it is " + mode); Loading @@ -409,16 +413,18 @@ public final class TaskViewUtils { throw new IllegalStateException("Initiating multi-split launch but the split" throw new IllegalStateException("Initiating multi-split launch but the split" + "root of " + taskId + " is already visible or has broken hierarchy."); + "root of " + taskId + " is already visible or has broken hierarchy."); } } splitRoots[taskId == initalTask.key.id ? 0 : 1] = } transitionInfo.getChange(change.getParent()); if (taskId == initialTaskId && initialTaskId != INVALID_TASK_ID) { splitRoot1 = transitionInfo.getChange(change.getParent()); } if (taskId == secondTaskId) { splitRoot2 = transitionInfo.getChange(change.getParent()); } } } } // This is where we should animate the split roots. For now, though, just make them visible. // This is where we should animate the split roots. For now, though, just make them visible. for (int i = 0; i < 2; ++i) { animateSplitRoot(t, splitRoot1); t.show(splitRoots[i].getLeash()); animateSplitRoot(t, splitRoot2); t.setAlpha(splitRoots[i].getLeash(), 1.f); } // This contains the initial state (before animation), so apply this at the beginning of // This contains the initial state (before animation), so apply this at the beginning of // the animation. // the animation. Loading @@ -428,6 +434,14 @@ public final class TaskViewUtils { finishCallback.run(); finishCallback.run(); } } private static void animateSplitRoot(SurfaceControl.Transaction t, TransitionInfo.Change splitRoot) { if (splitRoot != null) { t.show(splitRoot.getLeash()); t.setAlpha(splitRoot.getLeash(), 1.f); } } /** /** * Legacy version (until shell transitions are enabled) * Legacy version (until shell transitions are enabled) * * Loading @@ -440,9 +454,9 @@ public final class TaskViewUtils { * If it is null, then it will simply fade in the starting apps and fade out launcher (for the * 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) */ * case where launcher handles animating starting split tasks from app icon) */ public static void composeRecentsSplitLaunchAnimatorLegacy( public static void composeRecentsSplitLaunchAnimatorLegacy( @Nullable GroupedTaskView launchingTaskView, @Nullable GroupedTaskView launchingTaskView, int initialTaskId, @NonNull Task initialTask, @Nullable PendingIntent initialTaskPendingIntent, int secondTaskId, @NonNull Task secondTask, @NonNull RemoteAnimationTargetCompat[] appTargets, @NonNull RemoteAnimationTargetCompat[] appTargets, @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, @NonNull RemoteAnimationTargetCompat[] nonAppTargets, @NonNull RemoteAnimationTargetCompat[] nonAppTargets, @NonNull StateManager stateManager, @NonNull StateManager stateManager, Loading Loading @@ -478,7 +492,7 @@ public final class TaskViewUtils { if (mode == MODE_OPENING) { if (mode == MODE_OPENING) { openingTargets.add(leash); openingTargets.add(leash); } else if (taskId == initialTask.key.id || taskId == secondTask.key.id) { } else if (taskId == initialTaskId || taskId == secondTaskId) { throw new IllegalStateException("Expected task to be opening, but it is " + mode); throw new IllegalStateException("Expected task to be opening, but it is " + mode); } else if (mode == MODE_CLOSING) { } else if (mode == MODE_CLOSING) { closingTargets.add(leash); closingTargets.add(leash); Loading quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.popup.QuickstepSystemShortcut; import com.android.launcher3.statemanager.StateManager.StateListener; import com.android.launcher3.statemanager.StateManager.StateListener; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.quickstep.FallbackActivityInterface; import com.android.quickstep.FallbackActivityInterface; Loading Loading @@ -254,4 +255,10 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsSta // Do not let touch escape to siblings below this view. // Do not let touch escape to siblings below this view. return result || mActivity.getStateManager().getState().overviewUi(); return result || mActivity.getStateManager().getState().overviewUi(); } } @Override public void initiateSplitSelect(QuickstepSystemShortcut.SplitSelectSource splitSelectSource) { super.initiateSplitSelect(splitSelectSource); mActivity.getStateManager().goToState(OVERVIEW_SPLIT_SELECT); } } } quickstep/src/com/android/quickstep/util/SplitSelectStateController.java +69 −41 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.quickstep.util; package com.android.quickstep.util; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static com.android.launcher3.Utilities.postAsyncCallback; import static com.android.launcher3.Utilities.postAsyncCallback; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO; import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO; Loading @@ -24,7 +26,8 @@ import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITIO import android.app.ActivityOptions; import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.ActivityThread; import android.graphics.Rect; import android.app.PendingIntent; import android.content.Intent; import android.os.Handler; import android.os.Handler; import android.os.IBinder; import android.os.IBinder; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationAdapter; Loading @@ -42,7 +45,6 @@ import com.android.quickstep.TaskAnimationManager; import com.android.quickstep.TaskViewUtils; import com.android.quickstep.TaskViewUtils; import com.android.quickstep.views.GroupedTaskView; import com.android.quickstep.views.GroupedTaskView; import com.android.quickstep.views.TaskView; 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.RemoteAnimationAdapterCompat; import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; Loading @@ -62,16 +64,16 @@ public class SplitSelectStateController { private final StateManager mStateManager; private final StateManager mStateManager; private final DepthController mDepthController; private final DepthController mDepthController; private @StagePosition int mStagePosition; private @StagePosition int mStagePosition; private Task mInitialTask; private PendingIntent mInitialTaskPendingIntent; private Task mSecondTask; private int mInitialTaskId = INVALID_TASK_ID; private int mSecondTaskId = INVALID_TASK_ID; private boolean mRecentsAnimationRunning; private boolean mRecentsAnimationRunning; /** If not null, this is the TaskView we want to launch from */ /** If not null, this is the TaskView we want to launch from */ @Nullable @Nullable private GroupedTaskView mLaunchingTaskView; private GroupedTaskView mLaunchingTaskView; public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy, public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy, StateManager stateManager, StateManager stateManager, DepthController depthController) { DepthController depthController) { mHandler = handler; mHandler = handler; mSystemUiProxy = systemUiProxy; mSystemUiProxy = systemUiProxy; mStateManager = stateManager; mStateManager = stateManager; Loading @@ -81,19 +83,26 @@ public class SplitSelectStateController { /** /** * To be called after first task selected * To be called after first task selected */ */ public void setInitialTaskSelect(Task task, @StagePosition int stagePosition, public void setInitialTaskSelect(int taskId, @StagePosition int stagePosition) { Rect initialBounds) { mInitialTaskId = taskId; mInitialTask = task; mStagePosition = stagePosition; mInitialTaskPendingIntent = null; } public void setInitialTaskSelect(PendingIntent pendingIntent, @StagePosition int stagePosition) { mInitialTaskPendingIntent = pendingIntent; mStagePosition = stagePosition; mStagePosition = stagePosition; mInitialTaskId = INVALID_TASK_ID; } } /** /** * To be called after second task selected * To be called after second task selected */ */ public void setSecondTaskId(Task task, Consumer<Boolean> callback) { public void setSecondTaskId(int taskId, Consumer<Boolean> callback) { mSecondTask = task; mSecondTaskId = taskId; launchTasks(mInitialTask, mSecondTask, mStagePosition, callback, launchTasks(mInitialTaskId, mInitialTaskPendingIntent, mSecondTaskId, mStagePosition, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO); callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO); } } /** /** Loading @@ -104,7 +113,8 @@ public class SplitSelectStateController { mLaunchingTaskView = groupedTaskView; mLaunchingTaskView = groupedTaskView; TaskView.TaskIdAttributeContainer[] taskIdAttributeContainers = TaskView.TaskIdAttributeContainer[] taskIdAttributeContainers = groupedTaskView.getTaskIdAttributeContainers(); groupedTaskView.getTaskIdAttributeContainers(); launchTasks(taskIdAttributeContainers[0].getTask(), taskIdAttributeContainers[1].getTask(), launchTasks(taskIdAttributeContainers[0].getTask().key.id, null, taskIdAttributeContainers[1].getTask().key.id, taskIdAttributeContainers[0].getStagePosition(), callback, freezeTaskList, taskIdAttributeContainers[0].getStagePosition(), callback, freezeTaskList, groupedTaskView.getSplitRatio()); groupedTaskView.getSplitRatio()); } } Loading @@ -112,22 +122,25 @@ public class SplitSelectStateController { /** /** * @param stagePosition representing location of task1 * @param stagePosition representing location of task1 */ */ public void launchTasks(Task task1, Task task2, @StagePosition int stagePosition, public void launchTasks(int taskId1, @Nullable PendingIntent taskPendingIntent, Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) { int taskId2, @StagePosition int stagePosition, Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) { // Assume initial task is for top/left part of screen // Assume initial task is for top/left part of screen final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT ? new int[]{task1.key.id, task2.key.id} ? new int[]{taskId1, taskId2} : new int[]{task2.key.id, task1.key.id}; : new int[]{taskId2, taskId1}; if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) { if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) { RemoteSplitLaunchTransitionRunner animationRunner = RemoteSplitLaunchTransitionRunner animationRunner = new RemoteSplitLaunchTransitionRunner(task1, task2); new RemoteSplitLaunchTransitionRunner(taskId1, taskPendingIntent, taskId2); mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1], mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, splitRatio, null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, splitRatio, new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR, new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR, ActivityThread.currentActivityThread().getApplicationThread())); ActivityThread.currentActivityThread().getApplicationThread())); // TODO: handle intent + task with shell transition } else { } else { RemoteSplitLaunchAnimationRunner animationRunner = RemoteSplitLaunchAnimationRunner animationRunner = new RemoteSplitLaunchAnimationRunner(task1, task2, callback); new RemoteSplitLaunchAnimationRunner(taskId1, taskPendingIntent, taskId2, callback); final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( RemoteAnimationAdapterCompat.wrapRemoteAnimationRunner(animationRunner), RemoteAnimationAdapterCompat.wrapRemoteAnimationRunner(animationRunner), 300, 150, 300, 150, Loading @@ -137,9 +150,16 @@ public class SplitSelectStateController { if (freezeTaskList) { if (freezeTaskList) { mainOpts.setFreezeRecentTasksReordering(); mainOpts.setFreezeRecentTasksReordering(); } } if (taskPendingIntent == null) { mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], mainOpts.toBundle(), mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], mainOpts.toBundle(), taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, splitRatio, adapter); splitRatio, adapter); } else { mSystemUiProxy.startIntentAndTaskWithLegacyTransition(taskPendingIntent, new Intent(), taskId2, stagePosition == STAGE_POSITION_TOP_OR_LEFT, mainOpts.toBundle(), null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, splitRatio, adapter); } } } } } Loading @@ -156,19 +176,22 @@ public class SplitSelectStateController { */ */ private class RemoteSplitLaunchTransitionRunner implements RemoteTransitionRunner { private class RemoteSplitLaunchTransitionRunner implements RemoteTransitionRunner { private final Task mInitialTask; private final int mInitialTaskId; private final Task mSecondTask; private final PendingIntent mInitialTaskPendingIntent; private final int mSecondTaskId; RemoteSplitLaunchTransitionRunner(Task initialTask, Task secondTask) { RemoteSplitLaunchTransitionRunner(int initialTaskId, PendingIntent initialTaskPendingIntent, mInitialTask = initialTask; int secondTaskId) { mSecondTask = secondTask; mInitialTaskId = initialTaskId; mInitialTaskPendingIntent = initialTaskPendingIntent; mSecondTaskId = secondTaskId; } } @Override @Override public void startAnimation(IBinder transition, TransitionInfo info, public void startAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t, Runnable finishCallback) { SurfaceControl.Transaction t, Runnable finishCallback) { TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTask, TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTaskId, mSecondTask, info, t, finishCallback); mInitialTaskPendingIntent, mSecondTaskId, info, t, finishCallback); // After successful launch, call resetState // After successful launch, call resetState resetState(); resetState(); } } Loading @@ -180,14 +203,16 @@ public class SplitSelectStateController { */ */ private class RemoteSplitLaunchAnimationRunner implements RemoteAnimationRunnerCompat { private class RemoteSplitLaunchAnimationRunner implements RemoteAnimationRunnerCompat { private final Task mInitialTask; private final int mInitialTaskId; private final Task mSecondTask; private final PendingIntent mInitialTaskPendingIntent; private final int mSecondTaskId; private final Consumer<Boolean> mSuccessCallback; private final Consumer<Boolean> mSuccessCallback; RemoteSplitLaunchAnimationRunner(Task initialTask, Task secondTask, RemoteSplitLaunchAnimationRunner(int initialTaskId, PendingIntent initialTaskPendingIntent, Consumer<Boolean> successCallback) { int secondTaskId, Consumer<Boolean> successCallback) { mInitialTask = initialTask; mInitialTaskId = initialTaskId; mSecondTask = secondTask; mInitialTaskPendingIntent = initialTaskPendingIntent; mSecondTaskId = secondTaskId; mSuccessCallback = successCallback; mSuccessCallback = successCallback; } } Loading @@ -197,8 +222,9 @@ public class SplitSelectStateController { Runnable finishedCallback) { Runnable finishedCallback) { postAsyncCallback(mHandler, postAsyncCallback(mHandler, () -> TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy( () -> TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy( mLaunchingTaskView, mInitialTask, mSecondTask, apps, wallpapers, mLaunchingTaskView, mInitialTaskId, mInitialTaskPendingIntent, nonApps, mStateManager, mDepthController, () -> { mSecondTaskId, apps, wallpapers, nonApps, mStateManager, mDepthController, () -> { finishedCallback.run(); finishedCallback.run(); if (mSuccessCallback != null) { if (mSuccessCallback != null) { mSuccessCallback.accept(true); mSuccessCallback.accept(true); Loading @@ -224,8 +250,9 @@ public class SplitSelectStateController { * To be called if split select was cancelled * To be called if split select was cancelled */ */ public void resetState() { public void resetState() { mInitialTask = null; mInitialTaskId = INVALID_TASK_ID; mSecondTask = null; mInitialTaskPendingIntent = null; mSecondTaskId = INVALID_TASK_ID; mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED; mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED; mRecentsAnimationRunning = false; mRecentsAnimationRunning = false; mLaunchingTaskView = null; mLaunchingTaskView = null; Loading @@ -236,6 +263,7 @@ public class SplitSelectStateController { * chosen * chosen */ */ public boolean isSplitSelectActive() { public boolean isSplitSelectActive() { return mInitialTask != null && mSecondTask == null; return (mInitialTaskId != INVALID_TASK_ID || mInitialTaskPendingIntent != null) && mSecondTaskId == INVALID_TASK_ID; } } } } Loading
quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java +44 −0 Original line number Original line Diff line number Diff line Loading @@ -15,14 +15,23 @@ */ */ package com.android.launcher3.popup; package com.android.launcher3.popup; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.util.Log; import android.view.View; import android.view.View; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; import com.android.quickstep.views.RecentsView; public interface QuickstepSystemShortcut { public interface QuickstepSystemShortcut { String TAG = QuickstepSystemShortcut.class.getSimpleName(); static SystemShortcut.Factory<BaseQuickstepLauncher> getSplitSelectShortcutByPosition( static SystemShortcut.Factory<BaseQuickstepLauncher> getSplitSelectShortcutByPosition( SplitPositionOption position) { SplitPositionOption position) { return (activity, itemInfo) -> new QuickstepSystemShortcut.SplitSelectSystemShortcut( return (activity, itemInfo) -> new QuickstepSystemShortcut.SplitSelectSystemShortcut( Loading @@ -46,6 +55,41 @@ public interface QuickstepSystemShortcut { @Override @Override public void onClick(View view) { public void onClick(View view) { Bitmap bitmap; Intent intent; if (mItemInfo instanceof WorkspaceItemInfo) { final WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) mItemInfo; bitmap = workspaceItemInfo.bitmap.icon; intent = workspaceItemInfo.intent; } else if (mItemInfo instanceof com.android.launcher3.model.data.AppInfo) { final com.android.launcher3.model.data.AppInfo appInfo = (com.android.launcher3.model.data.AppInfo) mItemInfo; bitmap = appInfo.bitmap.icon; intent = appInfo.intent; } else { Log.e(TAG, "unknown item type"); return; } RecentsView recentsView = mLauncher.getOverviewPanel(); recentsView.initiateSplitSelect( new SplitSelectSource(view, new BitmapDrawable(bitmap), intent, mPosition)); } } class SplitSelectSource { public final View view; public final Drawable drawable; public final Intent intent; public final SplitPositionOption position; public SplitSelectSource(View view, Drawable drawable, Intent intent, SplitPositionOption position) { this.view = view; this.drawable = drawable; this.intent = intent; this.position = position; } } } } } }
quickstep/src/com/android/quickstep/SystemUiProxy.java +15 −0 Original line number Original line Diff line number Diff line Loading @@ -608,6 +608,21 @@ public class SystemUiProxy implements ISystemUiProxy, } } } } public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent, int taskId, boolean intentFirst, Bundle mainOptions, Bundle sideOptions, @SplitConfigurationOptions.StagePosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) { if (mSystemUiProxy != null) { try { mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, fillInIntent, taskId, intentFirst, mainOptions, sideOptions, sidePosition, splitRatio, adapter); } catch (RemoteException e) { Log.w(TAG, "Failed call startTasksWithLegacyTransition"); } } } public void startShortcut(String packageName, String shortcutId, int position, public void startShortcut(String packageName, String shortcutId, int position, Bundle options, UserHandle user) { Bundle options, UserHandle user) { if (mSplitScreen != null) { if (mSplitScreen != null) { Loading
quickstep/src/com/android/quickstep/TaskViewUtils.java +30 −16 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ */ package com.android.quickstep; package com.android.quickstep; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.TRANSIT_TO_FRONT; Loading Loading @@ -46,6 +47,7 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.annotation.TargetApi; import android.app.PendingIntent; import android.content.ComponentName; import android.content.ComponentName; import android.content.Context; import android.content.Context; import android.graphics.Matrix; import android.graphics.Matrix; Loading Loading @@ -389,18 +391,20 @@ public final class TaskViewUtils { * device is considered in multiWindowMode and things like insets and stuff change * device is considered in multiWindowMode and things like insets and stuff change * and calculations have to be adjusted in the animations for that * and calculations have to be adjusted in the animations for that */ */ public static void composeRecentsSplitLaunchAnimator(@NonNull Task initalTask, public static void composeRecentsSplitLaunchAnimator(int initialTaskId, @NonNull Task secondTask, @NonNull TransitionInfo transitionInfo, @Nullable PendingIntent initialTaskPendingIntent, int secondTaskId, SurfaceControl.Transaction t, @NonNull Runnable finishCallback) { @NonNull TransitionInfo transitionInfo, SurfaceControl.Transaction t, @NonNull Runnable finishCallback) { final TransitionInfo.Change[] splitRoots = new TransitionInfo.Change[2]; // TODO: consider initialTaskPendingIntent TransitionInfo.Change splitRoot1 = null; TransitionInfo.Change splitRoot2 = null; for (int i = 0; i < transitionInfo.getChanges().size(); ++i) { for (int i = 0; i < transitionInfo.getChanges().size(); ++i) { final TransitionInfo.Change change = transitionInfo.getChanges().get(i); final TransitionInfo.Change change = transitionInfo.getChanges().get(i); final int taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1; final int taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1; final int mode = change.getMode(); final int mode = change.getMode(); // Find the target tasks' root tasks since those are the split stages that need to // Find the target tasks' root tasks since those are the split stages that need to // be animated (the tasks themselves are children and thus inherit animation). // be animated (the tasks themselves are children and thus inherit animation). if (taskId == initalTask.key.id || taskId == secondTask.key.id) { if (taskId == initialTaskId || taskId == secondTaskId) { if (!(mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) { if (!(mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) { throw new IllegalStateException( throw new IllegalStateException( "Expected task to be showing, but it is " + mode); "Expected task to be showing, but it is " + mode); Loading @@ -409,16 +413,18 @@ public final class TaskViewUtils { throw new IllegalStateException("Initiating multi-split launch but the split" throw new IllegalStateException("Initiating multi-split launch but the split" + "root of " + taskId + " is already visible or has broken hierarchy."); + "root of " + taskId + " is already visible or has broken hierarchy."); } } splitRoots[taskId == initalTask.key.id ? 0 : 1] = } transitionInfo.getChange(change.getParent()); if (taskId == initialTaskId && initialTaskId != INVALID_TASK_ID) { splitRoot1 = transitionInfo.getChange(change.getParent()); } if (taskId == secondTaskId) { splitRoot2 = transitionInfo.getChange(change.getParent()); } } } } // This is where we should animate the split roots. For now, though, just make them visible. // This is where we should animate the split roots. For now, though, just make them visible. for (int i = 0; i < 2; ++i) { animateSplitRoot(t, splitRoot1); t.show(splitRoots[i].getLeash()); animateSplitRoot(t, splitRoot2); t.setAlpha(splitRoots[i].getLeash(), 1.f); } // This contains the initial state (before animation), so apply this at the beginning of // This contains the initial state (before animation), so apply this at the beginning of // the animation. // the animation. Loading @@ -428,6 +434,14 @@ public final class TaskViewUtils { finishCallback.run(); finishCallback.run(); } } private static void animateSplitRoot(SurfaceControl.Transaction t, TransitionInfo.Change splitRoot) { if (splitRoot != null) { t.show(splitRoot.getLeash()); t.setAlpha(splitRoot.getLeash(), 1.f); } } /** /** * Legacy version (until shell transitions are enabled) * Legacy version (until shell transitions are enabled) * * Loading @@ -440,9 +454,9 @@ public final class TaskViewUtils { * If it is null, then it will simply fade in the starting apps and fade out launcher (for the * 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) */ * case where launcher handles animating starting split tasks from app icon) */ public static void composeRecentsSplitLaunchAnimatorLegacy( public static void composeRecentsSplitLaunchAnimatorLegacy( @Nullable GroupedTaskView launchingTaskView, @Nullable GroupedTaskView launchingTaskView, int initialTaskId, @NonNull Task initialTask, @Nullable PendingIntent initialTaskPendingIntent, int secondTaskId, @NonNull Task secondTask, @NonNull RemoteAnimationTargetCompat[] appTargets, @NonNull RemoteAnimationTargetCompat[] appTargets, @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, @NonNull RemoteAnimationTargetCompat[] nonAppTargets, @NonNull RemoteAnimationTargetCompat[] nonAppTargets, @NonNull StateManager stateManager, @NonNull StateManager stateManager, Loading Loading @@ -478,7 +492,7 @@ public final class TaskViewUtils { if (mode == MODE_OPENING) { if (mode == MODE_OPENING) { openingTargets.add(leash); openingTargets.add(leash); } else if (taskId == initialTask.key.id || taskId == secondTask.key.id) { } else if (taskId == initialTaskId || taskId == secondTaskId) { throw new IllegalStateException("Expected task to be opening, but it is " + mode); throw new IllegalStateException("Expected task to be opening, but it is " + mode); } else if (mode == MODE_CLOSING) { } else if (mode == MODE_CLOSING) { closingTargets.add(leash); closingTargets.add(leash); Loading
quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.popup.QuickstepSystemShortcut; import com.android.launcher3.statemanager.StateManager.StateListener; import com.android.launcher3.statemanager.StateManager.StateListener; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.quickstep.FallbackActivityInterface; import com.android.quickstep.FallbackActivityInterface; Loading Loading @@ -254,4 +255,10 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsSta // Do not let touch escape to siblings below this view. // Do not let touch escape to siblings below this view. return result || mActivity.getStateManager().getState().overviewUi(); return result || mActivity.getStateManager().getState().overviewUi(); } } @Override public void initiateSplitSelect(QuickstepSystemShortcut.SplitSelectSource splitSelectSource) { super.initiateSplitSelect(splitSelectSource); mActivity.getStateManager().goToState(OVERVIEW_SPLIT_SELECT); } } }
quickstep/src/com/android/quickstep/util/SplitSelectStateController.java +69 −41 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.quickstep.util; package com.android.quickstep.util; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static com.android.launcher3.Utilities.postAsyncCallback; import static com.android.launcher3.Utilities.postAsyncCallback; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO; import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO; Loading @@ -24,7 +26,8 @@ import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITIO import android.app.ActivityOptions; import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.ActivityThread; import android.graphics.Rect; import android.app.PendingIntent; import android.content.Intent; import android.os.Handler; import android.os.Handler; import android.os.IBinder; import android.os.IBinder; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationAdapter; Loading @@ -42,7 +45,6 @@ import com.android.quickstep.TaskAnimationManager; import com.android.quickstep.TaskViewUtils; import com.android.quickstep.TaskViewUtils; import com.android.quickstep.views.GroupedTaskView; import com.android.quickstep.views.GroupedTaskView; import com.android.quickstep.views.TaskView; 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.RemoteAnimationAdapterCompat; import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; Loading @@ -62,16 +64,16 @@ public class SplitSelectStateController { private final StateManager mStateManager; private final StateManager mStateManager; private final DepthController mDepthController; private final DepthController mDepthController; private @StagePosition int mStagePosition; private @StagePosition int mStagePosition; private Task mInitialTask; private PendingIntent mInitialTaskPendingIntent; private Task mSecondTask; private int mInitialTaskId = INVALID_TASK_ID; private int mSecondTaskId = INVALID_TASK_ID; private boolean mRecentsAnimationRunning; private boolean mRecentsAnimationRunning; /** If not null, this is the TaskView we want to launch from */ /** If not null, this is the TaskView we want to launch from */ @Nullable @Nullable private GroupedTaskView mLaunchingTaskView; private GroupedTaskView mLaunchingTaskView; public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy, public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy, StateManager stateManager, StateManager stateManager, DepthController depthController) { DepthController depthController) { mHandler = handler; mHandler = handler; mSystemUiProxy = systemUiProxy; mSystemUiProxy = systemUiProxy; mStateManager = stateManager; mStateManager = stateManager; Loading @@ -81,19 +83,26 @@ public class SplitSelectStateController { /** /** * To be called after first task selected * To be called after first task selected */ */ public void setInitialTaskSelect(Task task, @StagePosition int stagePosition, public void setInitialTaskSelect(int taskId, @StagePosition int stagePosition) { Rect initialBounds) { mInitialTaskId = taskId; mInitialTask = task; mStagePosition = stagePosition; mInitialTaskPendingIntent = null; } public void setInitialTaskSelect(PendingIntent pendingIntent, @StagePosition int stagePosition) { mInitialTaskPendingIntent = pendingIntent; mStagePosition = stagePosition; mStagePosition = stagePosition; mInitialTaskId = INVALID_TASK_ID; } } /** /** * To be called after second task selected * To be called after second task selected */ */ public void setSecondTaskId(Task task, Consumer<Boolean> callback) { public void setSecondTaskId(int taskId, Consumer<Boolean> callback) { mSecondTask = task; mSecondTaskId = taskId; launchTasks(mInitialTask, mSecondTask, mStagePosition, callback, launchTasks(mInitialTaskId, mInitialTaskPendingIntent, mSecondTaskId, mStagePosition, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO); callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO); } } /** /** Loading @@ -104,7 +113,8 @@ public class SplitSelectStateController { mLaunchingTaskView = groupedTaskView; mLaunchingTaskView = groupedTaskView; TaskView.TaskIdAttributeContainer[] taskIdAttributeContainers = TaskView.TaskIdAttributeContainer[] taskIdAttributeContainers = groupedTaskView.getTaskIdAttributeContainers(); groupedTaskView.getTaskIdAttributeContainers(); launchTasks(taskIdAttributeContainers[0].getTask(), taskIdAttributeContainers[1].getTask(), launchTasks(taskIdAttributeContainers[0].getTask().key.id, null, taskIdAttributeContainers[1].getTask().key.id, taskIdAttributeContainers[0].getStagePosition(), callback, freezeTaskList, taskIdAttributeContainers[0].getStagePosition(), callback, freezeTaskList, groupedTaskView.getSplitRatio()); groupedTaskView.getSplitRatio()); } } Loading @@ -112,22 +122,25 @@ public class SplitSelectStateController { /** /** * @param stagePosition representing location of task1 * @param stagePosition representing location of task1 */ */ public void launchTasks(Task task1, Task task2, @StagePosition int stagePosition, public void launchTasks(int taskId1, @Nullable PendingIntent taskPendingIntent, Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) { int taskId2, @StagePosition int stagePosition, Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) { // Assume initial task is for top/left part of screen // Assume initial task is for top/left part of screen final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT ? new int[]{task1.key.id, task2.key.id} ? new int[]{taskId1, taskId2} : new int[]{task2.key.id, task1.key.id}; : new int[]{taskId2, taskId1}; if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) { if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) { RemoteSplitLaunchTransitionRunner animationRunner = RemoteSplitLaunchTransitionRunner animationRunner = new RemoteSplitLaunchTransitionRunner(task1, task2); new RemoteSplitLaunchTransitionRunner(taskId1, taskPendingIntent, taskId2); mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1], mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, splitRatio, null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, splitRatio, new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR, new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR, ActivityThread.currentActivityThread().getApplicationThread())); ActivityThread.currentActivityThread().getApplicationThread())); // TODO: handle intent + task with shell transition } else { } else { RemoteSplitLaunchAnimationRunner animationRunner = RemoteSplitLaunchAnimationRunner animationRunner = new RemoteSplitLaunchAnimationRunner(task1, task2, callback); new RemoteSplitLaunchAnimationRunner(taskId1, taskPendingIntent, taskId2, callback); final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( RemoteAnimationAdapterCompat.wrapRemoteAnimationRunner(animationRunner), RemoteAnimationAdapterCompat.wrapRemoteAnimationRunner(animationRunner), 300, 150, 300, 150, Loading @@ -137,9 +150,16 @@ public class SplitSelectStateController { if (freezeTaskList) { if (freezeTaskList) { mainOpts.setFreezeRecentTasksReordering(); mainOpts.setFreezeRecentTasksReordering(); } } if (taskPendingIntent == null) { mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], mainOpts.toBundle(), mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], mainOpts.toBundle(), taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, splitRatio, adapter); splitRatio, adapter); } else { mSystemUiProxy.startIntentAndTaskWithLegacyTransition(taskPendingIntent, new Intent(), taskId2, stagePosition == STAGE_POSITION_TOP_OR_LEFT, mainOpts.toBundle(), null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, splitRatio, adapter); } } } } } Loading @@ -156,19 +176,22 @@ public class SplitSelectStateController { */ */ private class RemoteSplitLaunchTransitionRunner implements RemoteTransitionRunner { private class RemoteSplitLaunchTransitionRunner implements RemoteTransitionRunner { private final Task mInitialTask; private final int mInitialTaskId; private final Task mSecondTask; private final PendingIntent mInitialTaskPendingIntent; private final int mSecondTaskId; RemoteSplitLaunchTransitionRunner(Task initialTask, Task secondTask) { RemoteSplitLaunchTransitionRunner(int initialTaskId, PendingIntent initialTaskPendingIntent, mInitialTask = initialTask; int secondTaskId) { mSecondTask = secondTask; mInitialTaskId = initialTaskId; mInitialTaskPendingIntent = initialTaskPendingIntent; mSecondTaskId = secondTaskId; } } @Override @Override public void startAnimation(IBinder transition, TransitionInfo info, public void startAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t, Runnable finishCallback) { SurfaceControl.Transaction t, Runnable finishCallback) { TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTask, TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTaskId, mSecondTask, info, t, finishCallback); mInitialTaskPendingIntent, mSecondTaskId, info, t, finishCallback); // After successful launch, call resetState // After successful launch, call resetState resetState(); resetState(); } } Loading @@ -180,14 +203,16 @@ public class SplitSelectStateController { */ */ private class RemoteSplitLaunchAnimationRunner implements RemoteAnimationRunnerCompat { private class RemoteSplitLaunchAnimationRunner implements RemoteAnimationRunnerCompat { private final Task mInitialTask; private final int mInitialTaskId; private final Task mSecondTask; private final PendingIntent mInitialTaskPendingIntent; private final int mSecondTaskId; private final Consumer<Boolean> mSuccessCallback; private final Consumer<Boolean> mSuccessCallback; RemoteSplitLaunchAnimationRunner(Task initialTask, Task secondTask, RemoteSplitLaunchAnimationRunner(int initialTaskId, PendingIntent initialTaskPendingIntent, Consumer<Boolean> successCallback) { int secondTaskId, Consumer<Boolean> successCallback) { mInitialTask = initialTask; mInitialTaskId = initialTaskId; mSecondTask = secondTask; mInitialTaskPendingIntent = initialTaskPendingIntent; mSecondTaskId = secondTaskId; mSuccessCallback = successCallback; mSuccessCallback = successCallback; } } Loading @@ -197,8 +222,9 @@ public class SplitSelectStateController { Runnable finishedCallback) { Runnable finishedCallback) { postAsyncCallback(mHandler, postAsyncCallback(mHandler, () -> TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy( () -> TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy( mLaunchingTaskView, mInitialTask, mSecondTask, apps, wallpapers, mLaunchingTaskView, mInitialTaskId, mInitialTaskPendingIntent, nonApps, mStateManager, mDepthController, () -> { mSecondTaskId, apps, wallpapers, nonApps, mStateManager, mDepthController, () -> { finishedCallback.run(); finishedCallback.run(); if (mSuccessCallback != null) { if (mSuccessCallback != null) { mSuccessCallback.accept(true); mSuccessCallback.accept(true); Loading @@ -224,8 +250,9 @@ public class SplitSelectStateController { * To be called if split select was cancelled * To be called if split select was cancelled */ */ public void resetState() { public void resetState() { mInitialTask = null; mInitialTaskId = INVALID_TASK_ID; mSecondTask = null; mInitialTaskPendingIntent = null; mSecondTaskId = INVALID_TASK_ID; mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED; mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED; mRecentsAnimationRunning = false; mRecentsAnimationRunning = false; mLaunchingTaskView = null; mLaunchingTaskView = null; Loading @@ -236,6 +263,7 @@ public class SplitSelectStateController { * chosen * chosen */ */ public boolean isSplitSelectActive() { public boolean isSplitSelectActive() { return mInitialTask != null && mSecondTask == null; return (mInitialTaskId != INVALID_TASK_ID || mInitialTaskPendingIntent != null) && mSecondTaskId == INVALID_TASK_ID; } } } }