Merge "Fix bug with Taskbar not differentiating between user profiles" into tm-qpr-dev am: 24b1890c4b

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

Change-Id: Ibec09110f5b5829d4412a7081e3ef4645dec6c41
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Jeremy Sim
2023-03-02 03:34:59 +00:00
committed by Automerger Merge Worker
5 changed files with 160 additions and 16 deletions

View File

@@ -88,6 +88,7 @@ import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemClickHandler.ItemClickProxy;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.PackageManagerHelper;
@@ -105,7 +106,6 @@ import com.android.systemui.unfold.updates.RotationChangeProvider;
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
import java.io.PrintWriter;
import java.util.function.Consumer;
/**
* The {@link ActivityContext} with which we inflate Taskbar-related Views. This allows UI elements
@@ -877,8 +877,9 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
* (potentially breaking a split pair).
*/
private void launchFromTaskbarPreservingSplitIfVisible(RecentsView recents, ItemInfo info) {
ComponentKey componentToBeLaunched = new ComponentKey(info.getTargetComponent(), info.user);
recents.getSplitSelectController().findLastActiveTaskAndRunCallback(
info.getTargetComponent(),
componentToBeLaunched,
foundTask -> {
if (foundTask != null) {
TaskView foundTaskView =

View File

@@ -30,16 +30,15 @@ import androidx.annotation.Nullable;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
import com.android.systemui.shared.recents.model.Task;
import java.io.PrintWriter;
import java.util.function.Consumer;
/**
* Base class for providing different taskbar UI
@@ -189,8 +188,12 @@ public class TaskbarUIController {
if (recentsView == null) {
return;
}
ComponentKey componentToBeStaged = new ComponentKey(
splitSelectSource.itemInfo.getTargetComponent(),
splitSelectSource.itemInfo.user);
recentsView.getSplitSelectController().findLastActiveTaskAndRunCallback(
splitSelectSource.intent.getComponent(),
componentToBeStaged,
foundTask -> {
splitSelectSource.alreadyRunningTaskId = foundTask == null
? INVALID_TASK_ID
@@ -206,8 +209,9 @@ public class TaskbarUIController {
*/
public void triggerSecondAppForSplit(ItemInfoWithIcon info, Intent intent, View startingView) {
RecentsView recents = getRecentsView();
ComponentKey secondAppComponent = new ComponentKey(info.getTargetComponent(), info.user);
recents.getSplitSelectController().findLastActiveTaskAndRunCallback(
info.getTargetComponent(),
secondAppComponent,
foundTask -> {
if (foundTask != null) {
TaskView foundTaskView = recents.getTaskViewByTaskId(foundTask.key.id);

View File

@@ -136,6 +136,7 @@ import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchControlle
import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.NavigationMode;
@@ -574,10 +575,13 @@ public class QuickstepLauncher extends Launcher {
@Override
public void startSplitSelection(SplitSelectSource splitSelectSource) {
RecentsView recentsView = getOverviewPanel();
ComponentKey componentToBeStaged = new ComponentKey(
splitSelectSource.itemInfo.getTargetComponent(),
splitSelectSource.itemInfo.user);
// Check if there is already an instance of this app running, if so, initiate the split
// using that.
mSplitSelectStateController.findLastActiveTaskAndRunCallback(
splitSelectSource.intent.getComponent(),
componentToBeStaged,
foundTask -> {
splitSelectSource.alreadyRunningTaskId = foundTask == null
? INVALID_TASK_ID

View File

@@ -29,7 +29,6 @@ import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -58,6 +57,7 @@ import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import com.android.quickstep.RecentsModel;
@@ -162,7 +162,7 @@ public class SplitSelectStateController {
* Used in various task-switching or splitscreen operations when we need to check if there is a
* currently running Task of a certain type and use the most recent one.
*/
public void findLastActiveTaskAndRunCallback(ComponentName componentName,
public void findLastActiveTaskAndRunCallback(ComponentKey componentKey,
Consumer<Task> callback) {
mRecentTasksModel.getTasks(taskGroups -> {
Task lastActiveTask = null;
@@ -170,12 +170,12 @@ public class SplitSelectStateController {
for (int i = taskGroups.size() - 1; i >= 0; i--) {
GroupTask groupTask = taskGroups.get(i);
Task task1 = groupTask.task1;
if (isInstanceOfComponent(task1, componentName)) {
if (isInstanceOfComponent(task1, componentKey)) {
lastActiveTask = task1;
break;
}
Task task2 = groupTask.task2;
if (isInstanceOfComponent(task2, componentName)) {
if (isInstanceOfComponent(task2, componentKey)) {
lastActiveTask = task2;
break;
}
@@ -189,13 +189,14 @@ public class SplitSelectStateController {
* Checks if a given Task is the most recently-active Task of type componentName. Used for
* selecting already-running Tasks for splitscreen.
*/
public boolean isInstanceOfComponent(@Nullable Task task, ComponentName componentName) {
public boolean isInstanceOfComponent(@Nullable Task task, ComponentKey componentKey) {
// Exclude the task that is already staged
if (task == null || task.key.id == mInitialTaskId) {
return false;
}
return task.key.baseIntent.getComponent().equals(componentName);
return task.key.baseIntent.getComponent().equals(componentKey.componentName)
&& task.key.userId == componentKey.user.getIdentifier();
}
/**

View File

@@ -23,12 +23,14 @@ import android.content.Context
import android.content.Intent
import android.graphics.Rect
import android.os.Handler
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.launcher3.LauncherState
import com.android.launcher3.logging.StatsLogManager
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.statehandlers.DepthController
import com.android.launcher3.statemanager.StateManager
import com.android.launcher3.util.ComponentKey
import com.android.launcher3.util.SplitConfigurationOptions
import com.android.launcher3.util.withArgCaptor
import com.android.quickstep.RecentsModel
@@ -60,6 +62,9 @@ class SplitSelectStateControllerTest {
lateinit var splitSelectStateController: SplitSelectStateController
private val primaryUserHandle = UserHandle(ActivityManager.RunningTaskInfo().userId)
private val nonPrimaryUserHandle = UserHandle(ActivityManager.RunningTaskInfo().userId + 10)
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
@@ -77,6 +82,7 @@ class SplitSelectStateControllerTest {
@Test
fun activeTasks_noMatchingTasks() {
val nonMatchingComponent = ComponentKey(ComponentName("no", "match"), primaryUserHandle)
val groupTask1 =
generateGroupTask(
ComponentName("pomegranate", "juice"),
@@ -100,7 +106,7 @@ class SplitSelectStateControllerTest {
val consumer =
withArgCaptor<Consumer<ArrayList<GroupTask>>> {
splitSelectStateController.findLastActiveTaskAndRunCallback(
ComponentName("no", "match"),
nonMatchingComponent,
taskConsumer
)
verify(recentsModel).getTasks(capture())
@@ -114,6 +120,8 @@ class SplitSelectStateControllerTest {
fun activeTasks_singleMatchingTask() {
val matchingPackage = "hotdog"
val matchingClass = "juice"
val matchingComponent =
ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
val groupTask1 =
generateGroupTask(
ComponentName(matchingPackage, matchingClass),
@@ -149,7 +157,100 @@ class SplitSelectStateControllerTest {
val consumer =
withArgCaptor<Consumer<ArrayList<GroupTask>>> {
splitSelectStateController.findLastActiveTaskAndRunCallback(
ComponentName(matchingPackage, matchingClass),
matchingComponent,
taskConsumer
)
verify(recentsModel).getTasks(capture())
}
// Send our mocked tasks
consumer.accept(tasks)
}
@Test
fun activeTasks_skipTaskWithDifferentUser() {
val matchingPackage = "hotdog"
val matchingClass = "juice"
val nonPrimaryUserComponent =
ComponentKey(ComponentName(matchingPackage, matchingClass), nonPrimaryUserHandle)
val groupTask1 =
generateGroupTask(
ComponentName(matchingPackage, matchingClass),
ComponentName("pomegranate", "juice")
)
val groupTask2 =
generateGroupTask(
ComponentName("pumpkin", "pie"),
ComponentName("personal", "computer")
)
val tasks: ArrayList<GroupTask> = ArrayList()
tasks.add(groupTask1)
tasks.add(groupTask2)
// Assertions happen in the callback we get from what we pass into
// #findLastActiveTaskAndRunCallback
val taskConsumer =
Consumer<Task> { assertNull("No tasks should have matched", it /*task*/) }
// Capture callback from recentsModel#getTasks()
val consumer =
withArgCaptor<Consumer<ArrayList<GroupTask>>> {
splitSelectStateController.findLastActiveTaskAndRunCallback(
nonPrimaryUserComponent,
taskConsumer
)
verify(recentsModel).getTasks(capture())
}
// Send our mocked tasks
consumer.accept(tasks)
}
@Test
fun activeTasks_findTaskAsNonPrimaryUser() {
val matchingPackage = "hotdog"
val matchingClass = "juice"
val nonPrimaryUserComponent =
ComponentKey(ComponentName(matchingPackage, matchingClass), nonPrimaryUserHandle)
val groupTask1 =
generateGroupTask(
ComponentName(matchingPackage, matchingClass),
nonPrimaryUserHandle,
ComponentName("pomegranate", "juice"),
nonPrimaryUserHandle
)
val groupTask2 =
generateGroupTask(
ComponentName("pumpkin", "pie"),
ComponentName("personal", "computer")
)
val tasks: ArrayList<GroupTask> = ArrayList()
tasks.add(groupTask1)
tasks.add(groupTask2)
// Assertions happen in the callback we get from what we pass into
// #findLastActiveTaskAndRunCallback
val taskConsumer =
Consumer<Task> {
assertEquals(
"ComponentName package mismatched",
it.key.baseIntent.component.packageName,
matchingPackage
)
assertEquals(
"ComponentName class mismatched",
it.key.baseIntent.component.className,
matchingClass
)
assertEquals("userId mismatched", it.key.userId, nonPrimaryUserHandle.identifier)
assertEquals(it, groupTask1.task1)
}
// Capture callback from recentsModel#getTasks()
val consumer =
withArgCaptor<Consumer<ArrayList<GroupTask>>> {
splitSelectStateController.findLastActiveTaskAndRunCallback(
nonPrimaryUserComponent,
taskConsumer
)
verify(recentsModel).getTasks(capture())
@@ -163,6 +264,8 @@ class SplitSelectStateControllerTest {
fun activeTasks_multipleMatchMostRecentTask() {
val matchingPackage = "hotdog"
val matchingClass = "juice"
val matchingComponent =
ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
val groupTask1 =
generateGroupTask(
ComponentName(matchingPackage, matchingClass),
@@ -198,7 +301,7 @@ class SplitSelectStateControllerTest {
val consumer =
withArgCaptor<Consumer<ArrayList<GroupTask>>> {
splitSelectStateController.findLastActiveTaskAndRunCallback(
ComponentName(matchingPackage, matchingClass),
matchingComponent,
taskConsumer
)
verify(recentsModel).getTasks(capture())
@@ -245,6 +348,7 @@ class SplitSelectStateControllerTest {
assertFalse(splitSelectStateController.isSplitSelectActive)
}
// Generate GroupTask with default userId.
private fun generateGroupTask(
task1ComponentName: ComponentName,
task2ComponentName: ComponentName
@@ -268,4 +372,34 @@ class SplitSelectStateControllerTest {
SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1)
)
}
// Generate GroupTask with custom user handles.
private fun generateGroupTask(
task1ComponentName: ComponentName,
userHandle1: UserHandle,
task2ComponentName: ComponentName,
userHandle2: UserHandle
): GroupTask {
val task1 = Task()
var taskInfo = ActivityManager.RunningTaskInfo()
// Apply custom userHandle1
taskInfo.userId = userHandle1.identifier
var intent = Intent()
intent.component = task1ComponentName
taskInfo.baseIntent = intent
task1.key = Task.TaskKey(taskInfo)
val task2 = Task()
taskInfo = ActivityManager.RunningTaskInfo()
// Apply custom userHandle2
taskInfo.userId = userHandle2.identifier
intent = Intent()
intent.component = task2ComponentName
taskInfo.baseIntent = intent
task2.key = Task.TaskKey(taskInfo)
return GroupTask(
task1,
task2,
SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1)
)
}
}