Merge "Refactor handling data launching split screen to separate class" into udc-dev
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index d67dbae..549c50b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -1317,5 +1317,8 @@
writer.println("\nQuickstepLauncher:");
writer.println(prefix + "\tmOrientationState: " + (recentsView == null ? "recentsNull" :
recentsView.getPagedViewOrientedState()));
+ if (recentsView != null) {
+ recentsView.getSplitSelectController().dump(prefix, writer);
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
new file mode 100644
index 0000000..ebea58c
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2023 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 android.annotation.IntDef
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.ActivityTaskManager.INVALID_TASK_ID
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.pm.ShortcutInfo
+import android.os.UserHandle
+import android.util.Log
+import com.android.internal.annotations.VisibleForTesting
+import com.android.launcher3.logging.StatsLogManager.EventEnum
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.shortcuts.ShortcutKey
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+import com.android.launcher3.util.SplitConfigurationOptions.StagePosition
+import com.android.launcher3.util.SplitConfigurationOptions.getOppositeStagePosition
+import com.android.quickstep.util.SplitSelectDataHolder.Companion.SplitLaunchType
+import java.io.PrintWriter
+
+/**
+ * Holds/transforms/signs/seals/delivers information for the transient state of the user
+ * selecting a first app to start split with and then choosing a second app.
+ * This class DOES NOT associate itself with drag-and-drop split screen starts because they come
+ * from the bad part of town.
+ *
+ * After setting the correct fields for initial/second.* variables, this converts them into the
+ * correct [PendingIntent] and [ShortcutInfo] objects where applicable and sends the necessary
+ * data back via [getSplitLaunchData].
+ * [SplitLaunchType] indicates the type of tasks/apps/intents being launched given the provided
+ * state
+ */
+class SplitSelectDataHolder(
+ val context: Context
+) {
+ val TAG = SplitSelectDataHolder::class.simpleName
+
+ /**
+ * Order of the constant indicates the order of which task/app was selected.
+ * Ex. SPLIT_TASK_SHORTCUT means primary split app identified by task, secondary is shortcut
+ * SPLIT_SHORTCUT_TASK means primary split app is determined by shortcut, secondary is task
+ */
+ companion object {
+ @IntDef(SPLIT_TASK_TASK, SPLIT_TASK_PENDINGINTENT, SPLIT_TASK_SHORTCUT,
+ SPLIT_PENDINGINTENT_TASK, SPLIT_PENDINGINTENT_PENDINGINTENT, SPLIT_SHORTCUT_TASK)
+ @Retention(AnnotationRetention.SOURCE)
+ annotation class SplitLaunchType
+
+ const val SPLIT_TASK_TASK = 0
+ const val SPLIT_TASK_PENDINGINTENT = 1
+ const val SPLIT_TASK_SHORTCUT = 2
+ const val SPLIT_PENDINGINTENT_TASK = 3
+ const val SPLIT_SHORTCUT_TASK = 4
+ const val SPLIT_PENDINGINTENT_PENDINGINTENT = 5
+ }
+
+
+ @StagePosition
+ private var initialStagePosition: Int = STAGE_POSITION_UNDEFINED
+ private var initialTaskId: Int = INVALID_TASK_ID
+ private var secondTaskId: Int = INVALID_TASK_ID
+ private var initialUser: UserHandle? = null
+ private var secondUser: UserHandle? = null
+ private var initialIntent: Intent? = null
+ private var secondIntent: Intent? = null
+ private var secondPendingIntent: PendingIntent? = null
+ private var itemInfo: ItemInfo? = null
+ private var splitEvent: EventEnum? = null
+ private var initialShortcut: ShortcutInfo? = null
+ private var secondShortcut: ShortcutInfo? = null
+ private var initialPendingIntent: PendingIntent? = null
+
+ /**
+ * @param alreadyRunningTask if set to [android.app.ActivityTaskManager.INVALID_TASK_ID]
+ * then @param intent will be used to launch the initial task
+ * @param intent will be ignored if @param alreadyRunningTask is set
+ */
+ fun setInitialTaskSelect(intent: Intent?, @StagePosition stagePosition: Int,
+ itemInfo: ItemInfo?, splitEvent: EventEnum?,
+ alreadyRunningTask: Int) {
+ if (alreadyRunningTask != INVALID_TASK_ID) {
+ initialTaskId = alreadyRunningTask
+ } else {
+ initialIntent = intent!!
+ initialUser = itemInfo!!.user
+ }
+ setInitialData(stagePosition, splitEvent, itemInfo)
+ }
+
+ /**
+ * To be called after first task selected from using a split shortcut from the fullscreen
+ * running app.
+ */
+ fun setInitialTaskSelect(info: RunningTaskInfo,
+ @StagePosition stagePosition: Int, itemInfo: ItemInfo?,
+ splitEvent: EventEnum?) {
+ initialTaskId = info.taskId
+ setInitialData(stagePosition, splitEvent, itemInfo)
+ }
+
+ private fun setInitialData(@StagePosition stagePosition: Int,
+ event: EventEnum?, item: ItemInfo?) {
+ itemInfo = item
+ initialStagePosition = stagePosition
+ splitEvent = event
+ }
+
+ /**
+ * To be called as soon as user selects the second task (even if animations aren't complete)
+ * @param taskId The second task that will be launched.
+ */
+ fun setSecondTask(taskId: Int) {
+ secondTaskId = taskId
+ }
+
+ /**
+ * To be called as soon as user selects the second app (even if animations aren't complete)
+ * @param intent The second intent that will be launched.
+ * @param user The user of that intent.
+ */
+ fun setSecondTask(intent: Intent, user: UserHandle) {
+ secondIntent = intent
+ secondUser = user
+ }
+
+ /**
+ * To be called as soon as user selects the second app (even if animations aren't complete)
+ * Sets [secondUser] from that of the pendingIntent
+ * @param pendingIntent The second PendingIntent that will be launched.
+ */
+ fun setSecondTask(pendingIntent: PendingIntent) {
+ secondPendingIntent = pendingIntent
+ secondUser = pendingIntent.creatorUserHandle!!
+ }
+
+ private fun getShortcutInfo(intent: Intent?, user: UserHandle?): ShortcutInfo? {
+ if (intent?.getPackage() == null) {
+ return null
+ }
+ val shortcutId = intent.getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID)
+ ?: return null
+ try {
+ val context: Context = context.createPackageContextAsUser(
+ intent.getPackage(), 0 /* flags */, user)
+ return ShortcutInfo.Builder(context, shortcutId).build()
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Failed to create a ShortcutInfo for " + intent.getPackage())
+ }
+ return null
+ }
+
+ /**
+ * Converts intents to pendingIntents, associating the [user] with the intent if provided
+ */
+ private fun getPendingIntent(intent: Intent?, user: UserHandle?): PendingIntent? {
+ if (intent != initialIntent && intent != secondIntent) {
+ throw IllegalStateException("Invalid intent to convert to PendingIntent")
+ }
+
+ return if (intent == null) {
+ null
+ } else if (user != null) {
+ PendingIntent.getActivityAsUser(context, 0, intent,
+ PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT,
+ null /* options */, user)
+ } else {
+ PendingIntent.getActivity(context, 0, intent,
+ PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT)
+ }
+ }
+
+ /**
+ * @return [SplitLaunchData] with the necessary fields populated as determined by
+ * [SplitLaunchData.splitLaunchType]
+ */
+ fun getSplitLaunchData() : SplitLaunchData {
+ // Convert all intents to shortcut infos to see if determine if we launch shortcut or intent
+ convertIntentsToFinalTypes()
+ val splitLaunchType = getSplitLaunchType()
+ if (splitLaunchType == SPLIT_TASK_PENDINGINTENT || splitLaunchType == SPLIT_TASK_SHORTCUT) {
+ // need to get opposite stage position
+ initialStagePosition = getOppositeStagePosition(initialStagePosition)
+ }
+
+ return SplitLaunchData(
+ splitLaunchType,
+ initialTaskId,
+ secondTaskId,
+ initialPendingIntent,
+ secondPendingIntent,
+ initialShortcut,
+ secondShortcut,
+ itemInfo,
+ splitEvent,
+ initialStagePosition)
+ }
+
+ /**
+ * Converts our [initialIntent] and [secondIntent] into shortcuts and pendingIntents, if
+ * possible.
+ *
+ * Note that both [initialIntent] and [secondIntent] will be nullified on method return
+ *
+ * One caveat is that if [secondPendingIntent] is set, we will use that and *not* attempt to
+ * convert [secondIntent]
+ */
+ private fun convertIntentsToFinalTypes() {
+ initialShortcut = getShortcutInfo(initialIntent, initialUser)
+ initialPendingIntent = getPendingIntent(initialIntent, initialUser)
+ initialIntent = null
+
+ // Only one of the two is currently allowed (secondPendingIntent directly set for widgets)
+ if (secondIntent != null && secondPendingIntent != null) {
+ throw IllegalStateException("Both secondIntent and secondPendingIntent non-null")
+ }
+ // If secondPendingIntent already set, no need to convert. Prioritize using that
+ if (secondPendingIntent != null) {
+ secondIntent = null
+ return
+ }
+
+ secondShortcut = getShortcutInfo(secondIntent, secondUser)
+ secondPendingIntent = getPendingIntent(secondIntent, secondUser)
+ secondIntent = null
+ }
+
+ /**
+ * Only valid data fields at this point should be tasks, shortcuts, or pendingIntents
+ * Intents need to be converted in [convertIntentsToFinalTypes] prior to calling this method
+ */
+ @VisibleForTesting
+ @SplitLaunchType
+ fun getSplitLaunchType(): Int {
+ if (initialIntent != null || secondIntent != null) {
+ throw IllegalStateException("Intents need to be converted")
+ }
+
+ // Prioritize task launches first
+ if (initialTaskId != INVALID_TASK_ID) {
+ if (secondTaskId != INVALID_TASK_ID) {
+ return SPLIT_TASK_TASK
+ }
+ if (secondShortcut != null) {
+ return SPLIT_TASK_SHORTCUT
+ }
+ if (secondPendingIntent != null) {
+ return SPLIT_TASK_PENDINGINTENT
+ }
+ }
+
+ if (secondTaskId != INVALID_TASK_ID) {
+ if (initialShortcut != null) {
+ return SPLIT_SHORTCUT_TASK
+ }
+ if (initialPendingIntent != null) {
+ return SPLIT_PENDINGINTENT_TASK
+ }
+ }
+
+ // All task+shortcut combinations are handled above, only launch left is with multiple
+ // intents (and respective shortcut infos, if necessary)
+ if (initialPendingIntent != null && secondPendingIntent != null) {
+ return SPLIT_PENDINGINTENT_PENDINGINTENT
+ }
+ throw IllegalStateException("Unidentified split launch type")
+ }
+
+ data class SplitLaunchData(
+ @SplitLaunchType
+ val splitLaunchType: Int,
+ var initialTaskId: Int = INVALID_TASK_ID,
+ var secondTaskId: Int = INVALID_TASK_ID,
+ var initialPendingIntent: PendingIntent? = null,
+ var secondPendingIntent: PendingIntent? = null,
+ var initialShortcut: ShortcutInfo? = null,
+ var secondShortcut: ShortcutInfo? = null,
+ var itemInfo: ItemInfo? = null,
+ var splitEvent: EventEnum? = null,
+ val initialStagePosition: Int = STAGE_POSITION_UNDEFINED
+ )
+
+ /**
+ * @return `true` if first task has been selected and waiting for the second task to be
+ * chosen
+ */
+ fun isSplitSelectActive(): Boolean {
+ return isInitialTaskIntentSet() && !isSecondTaskIntentSet()
+ }
+
+ /**
+ * @return `true` if the first and second task have been chosen and split is waiting to
+ * be launched
+ */
+ fun isBothSplitAppsConfirmed(): Boolean {
+ return isInitialTaskIntentSet() && isSecondTaskIntentSet()
+ }
+
+ private fun isInitialTaskIntentSet(): Boolean {
+ return initialTaskId != INVALID_TASK_ID || initialIntent != null
+ }
+
+ fun getInitialTaskId(): Int {
+ return initialTaskId
+ }
+
+ fun getSecondTaskId(): Int {
+ return secondTaskId
+ }
+
+ private fun isSecondTaskIntentSet(): Boolean {
+ return secondTaskId != INVALID_TASK_ID || secondIntent != null
+ || secondPendingIntent != null
+ }
+
+ fun resetState() {
+ initialStagePosition = STAGE_POSITION_UNDEFINED
+ initialTaskId = INVALID_TASK_ID
+ secondTaskId = INVALID_TASK_ID
+ initialUser = null
+ secondUser = null
+ initialIntent = null
+ secondIntent = null
+ secondPendingIntent = null
+ itemInfo = null
+ splitEvent = null
+ initialShortcut = null
+ secondShortcut = null
+ }
+
+ fun dump(prefix: String, writer: PrintWriter) {
+ writer.println("$prefix ${javaClass.simpleName}")
+ writer.println("$prefix\tinitialStagePosition= $initialStagePosition")
+ writer.println("$prefix\tinitialTaskId= $initialTaskId")
+ writer.println("$prefix\tsecondTaskId= $secondTaskId")
+ writer.println("$prefix\tinitialUser= $initialUser")
+ writer.println("$prefix\tsecondUser= $secondUser")
+ writer.println("$prefix\tinitialIntent= $initialIntent")
+ writer.println("$prefix\tsecondIntent= $secondIntent")
+ writer.println("$prefix\tsecondPendingIntent= $secondPendingIntent")
+ writer.println("$prefix\titemInfo= $itemInfo")
+ writer.println("$prefix\tsplitEvent= $splitEvent")
+ writer.println("$prefix\tinitialShortcut= $initialShortcut")
+ writer.println("$prefix\tsecondShortcut= $secondShortcut")
+ }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 8b21115..acc3ba1 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -24,6 +24,12 @@
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.getOppositeStagePosition;
+import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_PENDINGINTENT_PENDINGINTENT;
+import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_PENDINGINTENT_TASK;
+import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_SHORTCUT_TASK;
+import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_PENDINGINTENT;
+import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_SHORTCUT;
+import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_TASK;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -34,6 +40,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -51,6 +58,7 @@
import androidx.annotation.Nullable;
import com.android.internal.logging.InstanceId;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
@@ -71,6 +79,7 @@
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
+import java.io.PrintWriter;
import java.util.function.Consumer;
/**
@@ -85,6 +94,7 @@
private final RecentsModel mRecentTasksModel;
private final SplitAnimationController mSplitAnimationController;
private final AppPairsController mAppPairsController;
+ private final SplitSelectDataHolder mSplitSelectDataHolder;
private StatsLogManager mStatsLogManager;
private final SystemUiProxy mSystemUiProxy;
private final StateManager mStateManager;
@@ -137,6 +147,7 @@
mRecentTasksModel = recentsModel;
mSplitAnimationController = new SplitAnimationController(this);
mAppPairsController = new AppPairsController(context, this);
+ mSplitSelectDataHolder = new SplitSelectDataHolder(mContext);
}
/**
@@ -155,6 +166,11 @@
}
setInitialData(stagePosition, splitEvent, itemInfo);
+
+ if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
+ mSplitSelectDataHolder.setInitialTaskSelect(intent, stagePosition, itemInfo, splitEvent,
+ alreadyRunningTask);
+ }
}
/**
@@ -166,6 +182,10 @@
StatsLogManager.EventEnum splitEvent) {
mInitialTaskId = info.taskId;
setInitialData(stagePosition, splitEvent, itemInfo);
+
+ if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
+ mSplitSelectDataHolder.setInitialTaskSelect(info, stagePosition, itemInfo, splitEvent);
+ }
}
private void setInitialData(@StagePosition int stagePosition,
@@ -243,6 +263,10 @@
*/
public void setSecondTask(Task task) {
mSecondTaskId = task.key.id;
+
+ if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
+ mSplitSelectDataHolder.setSecondTask(task.key.id);
+ }
}
/**
@@ -253,6 +277,10 @@
public void setSecondTask(Intent intent, UserHandle user) {
mSecondTaskIntent = intent;
mSecondUser = user;
+
+ if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
+ mSplitSelectDataHolder.setSecondTask(intent, user);
+ }
}
/**
@@ -263,6 +291,10 @@
public void setSecondTask(PendingIntent pendingIntent) {
mSecondPendingIntent = pendingIntent;
mSecondUser = pendingIntent.getCreatorUserHandle();
+
+ if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
+ mSplitSelectDataHolder.setSecondTask(pendingIntent);
+ }
}
/**
@@ -285,6 +317,12 @@
*/
public void launchTasks(int taskId1, int taskId2, @StagePosition int stagePosition,
Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) {
+ if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
+ mSplitSelectDataHolder.setInitialTaskSelect(null /*intent*/,
+ stagePosition, null /*itemInfo*/, null /*splitEvent*/,
+ taskId1);
+ mSplitSelectDataHolder.setSecondTask(taskId2);
+ }
launchTasks(taskId1, null /* intent1 */, taskId2, null /* intent2 */, stagePosition,
callback, freezeTaskList, splitRatio, null);
}
@@ -305,6 +343,11 @@
@Nullable InstanceId shellInstanceId) {
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "launchSplitTasks");
+ if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
+ launchTasksRefactored(callback, freezeTaskList, splitRatio, shellInstanceId);
+ return;
+ }
+
final ActivityOptions options1 = ActivityOptions.makeBasic();
if (freezeTaskList) {
options1.setFreezeRecentTasksReordering();
@@ -367,6 +410,101 @@
}
}
+ private void launchTasksRefactored(Consumer<Boolean> callback, boolean freezeTaskList,
+ float splitRatio, @Nullable InstanceId shellInstanceId) {
+ final ActivityOptions options1 = ActivityOptions.makeBasic();
+ if (freezeTaskList) {
+ options1.setFreezeRecentTasksReordering();
+ }
+
+ SplitSelectDataHolder.SplitLaunchData launchData =
+ mSplitSelectDataHolder.getSplitLaunchData();
+ int firstTaskId = launchData.getInitialTaskId();
+ int secondTaskId = launchData.getSecondTaskId();
+ ShortcutInfo firstShortcut = launchData.getInitialShortcut();
+ ShortcutInfo secondShortcut = launchData.getSecondShortcut();
+ PendingIntent firstPI = launchData.getInitialPendingIntent();
+ PendingIntent secondPI = launchData.getSecondPendingIntent();
+ int initialStagePosition = launchData.getInitialStagePosition();
+ Bundle optionsBundle = options1.toBundle();
+
+ if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+ final RemoteSplitLaunchTransitionRunner animationRunner =
+ new RemoteSplitLaunchTransitionRunner(firstTaskId, secondTaskId, callback);
+ final RemoteTransition remoteTransition = new RemoteTransition(animationRunner,
+ ActivityThread.currentActivityThread().getApplicationThread(),
+ "LaunchSplitPair");
+ switch (launchData.getSplitLaunchType()) {
+ case SPLIT_TASK_TASK ->
+ mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId,
+ null /* options2 */, initialStagePosition, splitRatio,
+ remoteTransition, shellInstanceId);
+
+ case SPLIT_TASK_PENDINGINTENT ->
+ mSystemUiProxy.startIntentAndTask(secondPI, optionsBundle, firstTaskId,
+ null /*options2*/, initialStagePosition, splitRatio,
+ remoteTransition, shellInstanceId);
+
+ case SPLIT_TASK_SHORTCUT ->
+ mSystemUiProxy.startShortcutAndTask(secondShortcut, optionsBundle,
+ firstTaskId, null /*options2*/, initialStagePosition, splitRatio,
+ remoteTransition, shellInstanceId);
+
+ case SPLIT_PENDINGINTENT_TASK ->
+ mSystemUiProxy.startIntentAndTask(firstPI, optionsBundle, secondTaskId,
+ null /*options2*/, initialStagePosition, splitRatio,
+ remoteTransition, shellInstanceId);
+
+ case SPLIT_PENDINGINTENT_PENDINGINTENT ->
+ mSystemUiProxy.startIntents(firstPI, firstShortcut, optionsBundle, secondPI,
+ secondShortcut, null /*options2*/, initialStagePosition, splitRatio,
+ remoteTransition, shellInstanceId);
+
+ case SPLIT_SHORTCUT_TASK ->
+ mSystemUiProxy.startShortcutAndTask(firstShortcut, optionsBundle,
+ secondTaskId, null /*options2*/, initialStagePosition, splitRatio,
+ remoteTransition, shellInstanceId);
+ }
+ } else {
+ final RemoteSplitLaunchAnimationRunner animationRunner =
+ new RemoteSplitLaunchAnimationRunner(firstTaskId, secondTaskId, callback);
+ final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+ animationRunner, 300, 150,
+ ActivityThread.currentActivityThread().getApplicationThread());
+ switch (launchData.getSplitLaunchType()) {
+ case SPLIT_TASK_TASK ->
+ mSystemUiProxy.startTasksWithLegacyTransition(firstTaskId, optionsBundle,
+ secondTaskId, null /* options2 */, initialStagePosition,
+ splitRatio, adapter, shellInstanceId);
+
+ case SPLIT_TASK_PENDINGINTENT ->
+ mSystemUiProxy.startIntentAndTaskWithLegacyTransition(secondPI,
+ optionsBundle, firstTaskId, null /*options2*/, initialStagePosition,
+ splitRatio, adapter, shellInstanceId);
+
+ case SPLIT_TASK_SHORTCUT ->
+ mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(secondShortcut,
+ optionsBundle, firstTaskId, null /*options2*/, initialStagePosition,
+ splitRatio, adapter, shellInstanceId);
+
+ case SPLIT_PENDINGINTENT_TASK ->
+ mSystemUiProxy.startIntentAndTaskWithLegacyTransition(firstPI,
+ optionsBundle, secondTaskId, null /*options2*/,
+ initialStagePosition, splitRatio, adapter, shellInstanceId);
+
+ case SPLIT_PENDINGINTENT_PENDINGINTENT ->
+ mSystemUiProxy.startIntentsWithLegacyTransition(firstPI, firstShortcut,
+ optionsBundle, secondPI, secondShortcut, null /*options2*/,
+ initialStagePosition, splitRatio, adapter, shellInstanceId);
+
+ case SPLIT_SHORTCUT_TASK ->
+ mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(firstShortcut,
+ optionsBundle, secondTaskId, null /*options2*/,
+ initialStagePosition, splitRatio, adapter, shellInstanceId);
+ }
+ }
+ }
+
private void launchIntentOrShortcut(Intent intent, UserHandle user, ActivityOptions options1,
int taskId, @StagePosition int stagePosition, float splitRatio,
RemoteTransition remoteTransition, @Nullable InstanceId shellInstanceId) {
@@ -572,6 +710,9 @@
* To be called if split select was cancelled
*/
public void resetState() {
+ if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
+ mSplitSelectDataHolder.resetState();
+ }
mInitialTaskId = INVALID_TASK_ID;
mInitialTaskIntent = null;
mSecondTaskId = INVALID_TASK_ID;
@@ -593,7 +734,11 @@
* chosen
*/
public boolean isSplitSelectActive() {
- return isInitialTaskIntentSet() && !isSecondTaskIntentSet();
+ if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
+ return mSplitSelectDataHolder.isSplitSelectActive();
+ } else {
+ return isInitialTaskIntentSet() && !isSecondTaskIntentSet();
+ }
}
/**
@@ -601,7 +746,11 @@
* be launched
*/
public boolean isBothSplitAppsConfirmed() {
- return isInitialTaskIntentSet() && isSecondTaskIntentSet();
+ if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
+ return mSplitSelectDataHolder.isBothSplitAppsConfirmed();
+ } else {
+ return isInitialTaskIntentSet() && isSecondTaskIntentSet();
+ }
}
private boolean isInitialTaskIntentSet() {
@@ -609,11 +758,19 @@
}
public int getInitialTaskId() {
- return mInitialTaskId;
+ if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
+ return mSplitSelectDataHolder.getInitialTaskId();
+ } else {
+ return mInitialTaskId;
+ }
}
public int getSecondTaskId() {
- return mSecondTaskId;
+ if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
+ return mSplitSelectDataHolder.getSecondTaskId();
+ } else {
+ return mSecondTaskId;
+ }
}
private boolean isSecondTaskIntentSet() {
@@ -632,4 +789,10 @@
public AppPairsController getAppPairsController() {
return mAppPairsController;
}
+
+ public void dump(String prefix, PrintWriter writer) {
+ if (mSplitSelectDataHolder != null) {
+ mSplitSelectDataHolder.dump(prefix, writer);
+ }
+ }
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 2a3ad9a..331ae5d 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -407,7 +407,12 @@
"USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES", DISABLED,
"Use local overrides for search request timeout");
- // TODO(Block 31): Empty block
+ // TODO(Block 31)
+ public static final BooleanFlag ENABLE_SPLIT_LAUNCH_DATA_REFACTOR = getDebugFlag(279494325,
+ "ENABLE_SPLIT_LAUNCH_DATA_REFACTOR", DISABLED,
+ "Use refactored split launching code path");
+
+ // TODO(Block 32): Empty block
public static class BooleanFlag {