Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 24b1890c authored by Jeremy Sim's avatar Jeremy Sim Committed by Android (Google) Code Review
Browse files

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

parents fc45621b e35d1126
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -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 =
+8 −4
Original line number Diff line number Diff line
@@ -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);
+5 −1
Original line number Diff line number Diff line
@@ -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
+7 −6
Original line number Diff line number Diff line
@@ -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();
    }

    /**
+137 −3
Original line number Diff line number Diff line
@@ -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(
                    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)
        )
    }
}