mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-20 03:08:19 +00:00
Merge "Fix bug with Taskbar not differentiating between user profiles" into tm-qpr-dev
This commit is contained in:
@@ -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 =
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user