Loading quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +2 −1 Original line number Diff line number Diff line Loading @@ -235,7 +235,8 @@ public class QuickstepLauncher extends Launcher { RecentsView overviewPanel = getOverviewPanel(); mSplitSelectStateController = new SplitSelectStateController(this, mHandler, getStateManager(), getDepthController(), getStatsLogManager()); getDepthController(), getStatsLogManager(), SystemUiProxy.INSTANCE.get(this), RecentsModel.INSTANCE.get(this)); overviewPanel.init(mActionsView, mSplitSelectStateController); mSplitWithKeyboardShortcutController = new SplitWithKeyboardShortcutController(this, mSplitSelectStateController); Loading quickstep/src/com/android/quickstep/RecentsActivity.java +2 −1 Original line number Diff line number Diff line Loading @@ -134,7 +134,8 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> { SplitSelectStateController controller = new SplitSelectStateController(this, mHandler, getStateManager(), /* depthController */ null, getStatsLogManager()); null /* depthController */, getStatsLogManager(), SystemUiProxy.INSTANCE.get(this), RecentsModel.INSTANCE.get(this)); mDragLayer.recreateControllers(); mFallbackRecentsView.init(mActionsView, controller); Loading quickstep/src/com/android/quickstep/util/SplitSelectStateController.java +4 −3 Original line number Diff line number Diff line Loading @@ -107,14 +107,15 @@ public class SplitSelectStateController { private FloatingTaskView mFirstFloatingTaskView; public SplitSelectStateController(Context context, Handler handler, StateManager stateManager, DepthController depthController, StatsLogManager statsLogManager) { DepthController depthController, StatsLogManager statsLogManager, SystemUiProxy systemUiProxy, RecentsModel recentsModel) { mContext = context; mHandler = handler; mStatsLogManager = statsLogManager; mSystemUiProxy = SystemUiProxy.INSTANCE.get(mContext); mSystemUiProxy = systemUiProxy; mStateManager = stateManager; mDepthController = depthController; mRecentTasksModel = RecentsModel.INSTANCE.get(context); mRecentTasksModel = recentsModel; } /** Loading quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt 0 → 100644 +212 −0 Original line number Diff line number Diff line /* * 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.app.ActivityManager import android.content.ComponentName import android.content.Context import android.content.Intent import android.graphics.Rect import android.os.Handler 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.SplitConfigurationOptions import com.android.launcher3.util.withArgCaptor import com.android.quickstep.RecentsModel import com.android.quickstep.SystemUiProxy import com.android.systemui.shared.recents.model.Task import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import java.util.ArrayList import java.util.function.Consumer @RunWith(AndroidJUnit4::class) class SplitSelectStateControllerTest { @Mock lateinit var systemUiProxy: SystemUiProxy @Mock lateinit var depthController: DepthController @Mock lateinit var statsLogManager: StatsLogManager @Mock lateinit var stateManager: StateManager<LauncherState> @Mock lateinit var handler: Handler @Mock lateinit var context: Context @Mock lateinit var recentsModel: RecentsModel lateinit var splitSelectStateController: SplitSelectStateController @Before fun setup() { MockitoAnnotations.initMocks(this) splitSelectStateController = SplitSelectStateController(context, handler, stateManager, depthController, statsLogManager, systemUiProxy, recentsModel) } @Test fun activeTasks_noMatchingTasks() { val groupTask1 = generateGroupTask( ComponentName("pomegranate", "juice"), ComponentName("pumpkin", "pie")) val groupTask2 = generateGroupTask( ComponentName("hotdog", "juice"), 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( ComponentName("no", "match"), taskConsumer) verify(recentsModel).getTasks(capture()) } // Send our mocked tasks consumer.accept(tasks) } @Test fun activeTasks_singleMatchingTask() { val matchingPackage = "hotdog" val matchingClass = "juice" 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> { assertEquals("ComponentName package mismatched", it.key.baseIntent.component.packageName, matchingPackage) assertEquals("ComponentName class mismatched", it.key.baseIntent.component.className, matchingClass) assertEquals(it, groupTask1.task1) } // Capture callback from recentsModel#getTasks() val consumer = withArgCaptor<Consumer<ArrayList<GroupTask>>> { splitSelectStateController.findLastActiveTaskAndRunCallback( ComponentName(matchingPackage, matchingClass), taskConsumer) verify(recentsModel).getTasks(capture()) } // Send our mocked tasks consumer.accept(tasks) } @Test fun activeTasks_multipleMatchMostRecentTask() { val matchingPackage = "hotdog" val matchingClass = "juice" val groupTask1 = generateGroupTask( ComponentName(matchingPackage, matchingClass), ComponentName("pumpkin", "pie")) val groupTask2 = generateGroupTask( ComponentName("pomegranate", "juice"), ComponentName(matchingPackage, matchingClass)) val tasks: ArrayList<GroupTask> = ArrayList() tasks.add(groupTask2) tasks.add(groupTask1) // 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(it, groupTask2.task2) } // Capture callback from recentsModel#getTasks() val consumer = withArgCaptor<Consumer<ArrayList<GroupTask>>> { splitSelectStateController.findLastActiveTaskAndRunCallback( ComponentName(matchingPackage, matchingClass), taskConsumer) verify(recentsModel).getTasks(capture()) } // Send our mocked tasks consumer.accept(tasks) } @Test fun setInitialApp_withTaskId() { splitSelectStateController.setInitialTaskSelect(null /*intent*/, -1 /*stagePosition*/, ItemInfo(), null /*splitEvent*/, 10 /*alreadyRunningTask*/) assertTrue(splitSelectStateController.isSplitSelectActive) } @Test fun setInitialApp_withIntent() { splitSelectStateController.setInitialTaskSelect(Intent() /*intent*/, -1 /*stagePosition*/, ItemInfo(), null /*splitEvent*/, -1 /*alreadyRunningTask*/) assertTrue(splitSelectStateController.isSplitSelectActive) } @Test fun resetAfterInitial() { splitSelectStateController.setInitialTaskSelect(Intent() /*intent*/, -1 /*stagePosition*/, ItemInfo(), null /*splitEvent*/, -1) splitSelectStateController.resetState() assertFalse(splitSelectStateController.isSplitSelectActive) } private fun generateGroupTask(task1ComponentName: ComponentName, task2ComponentName: ComponentName): GroupTask { val task1 = Task() var taskInfo = ActivityManager.RunningTaskInfo() var intent = Intent() intent.component = task1ComponentName taskInfo.baseIntent = intent task1.key = Task.TaskKey(taskInfo) val task2 = Task() taskInfo = ActivityManager.RunningTaskInfo() intent = Intent() intent.component = task2ComponentName taskInfo.baseIntent = intent task2.key = Task.TaskKey(taskInfo) return GroupTask(task1, task2, SplitConfigurationOptions.SplitBounds( Rect(), Rect(), -1, -1 )) } } No newline at end of file Loading
quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +2 −1 Original line number Diff line number Diff line Loading @@ -235,7 +235,8 @@ public class QuickstepLauncher extends Launcher { RecentsView overviewPanel = getOverviewPanel(); mSplitSelectStateController = new SplitSelectStateController(this, mHandler, getStateManager(), getDepthController(), getStatsLogManager()); getDepthController(), getStatsLogManager(), SystemUiProxy.INSTANCE.get(this), RecentsModel.INSTANCE.get(this)); overviewPanel.init(mActionsView, mSplitSelectStateController); mSplitWithKeyboardShortcutController = new SplitWithKeyboardShortcutController(this, mSplitSelectStateController); Loading
quickstep/src/com/android/quickstep/RecentsActivity.java +2 −1 Original line number Diff line number Diff line Loading @@ -134,7 +134,8 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> { SplitSelectStateController controller = new SplitSelectStateController(this, mHandler, getStateManager(), /* depthController */ null, getStatsLogManager()); null /* depthController */, getStatsLogManager(), SystemUiProxy.INSTANCE.get(this), RecentsModel.INSTANCE.get(this)); mDragLayer.recreateControllers(); mFallbackRecentsView.init(mActionsView, controller); Loading
quickstep/src/com/android/quickstep/util/SplitSelectStateController.java +4 −3 Original line number Diff line number Diff line Loading @@ -107,14 +107,15 @@ public class SplitSelectStateController { private FloatingTaskView mFirstFloatingTaskView; public SplitSelectStateController(Context context, Handler handler, StateManager stateManager, DepthController depthController, StatsLogManager statsLogManager) { DepthController depthController, StatsLogManager statsLogManager, SystemUiProxy systemUiProxy, RecentsModel recentsModel) { mContext = context; mHandler = handler; mStatsLogManager = statsLogManager; mSystemUiProxy = SystemUiProxy.INSTANCE.get(mContext); mSystemUiProxy = systemUiProxy; mStateManager = stateManager; mDepthController = depthController; mRecentTasksModel = RecentsModel.INSTANCE.get(context); mRecentTasksModel = recentsModel; } /** Loading
quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt 0 → 100644 +212 −0 Original line number Diff line number Diff line /* * 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.app.ActivityManager import android.content.ComponentName import android.content.Context import android.content.Intent import android.graphics.Rect import android.os.Handler 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.SplitConfigurationOptions import com.android.launcher3.util.withArgCaptor import com.android.quickstep.RecentsModel import com.android.quickstep.SystemUiProxy import com.android.systemui.shared.recents.model.Task import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import java.util.ArrayList import java.util.function.Consumer @RunWith(AndroidJUnit4::class) class SplitSelectStateControllerTest { @Mock lateinit var systemUiProxy: SystemUiProxy @Mock lateinit var depthController: DepthController @Mock lateinit var statsLogManager: StatsLogManager @Mock lateinit var stateManager: StateManager<LauncherState> @Mock lateinit var handler: Handler @Mock lateinit var context: Context @Mock lateinit var recentsModel: RecentsModel lateinit var splitSelectStateController: SplitSelectStateController @Before fun setup() { MockitoAnnotations.initMocks(this) splitSelectStateController = SplitSelectStateController(context, handler, stateManager, depthController, statsLogManager, systemUiProxy, recentsModel) } @Test fun activeTasks_noMatchingTasks() { val groupTask1 = generateGroupTask( ComponentName("pomegranate", "juice"), ComponentName("pumpkin", "pie")) val groupTask2 = generateGroupTask( ComponentName("hotdog", "juice"), 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( ComponentName("no", "match"), taskConsumer) verify(recentsModel).getTasks(capture()) } // Send our mocked tasks consumer.accept(tasks) } @Test fun activeTasks_singleMatchingTask() { val matchingPackage = "hotdog" val matchingClass = "juice" 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> { assertEquals("ComponentName package mismatched", it.key.baseIntent.component.packageName, matchingPackage) assertEquals("ComponentName class mismatched", it.key.baseIntent.component.className, matchingClass) assertEquals(it, groupTask1.task1) } // Capture callback from recentsModel#getTasks() val consumer = withArgCaptor<Consumer<ArrayList<GroupTask>>> { splitSelectStateController.findLastActiveTaskAndRunCallback( ComponentName(matchingPackage, matchingClass), taskConsumer) verify(recentsModel).getTasks(capture()) } // Send our mocked tasks consumer.accept(tasks) } @Test fun activeTasks_multipleMatchMostRecentTask() { val matchingPackage = "hotdog" val matchingClass = "juice" val groupTask1 = generateGroupTask( ComponentName(matchingPackage, matchingClass), ComponentName("pumpkin", "pie")) val groupTask2 = generateGroupTask( ComponentName("pomegranate", "juice"), ComponentName(matchingPackage, matchingClass)) val tasks: ArrayList<GroupTask> = ArrayList() tasks.add(groupTask2) tasks.add(groupTask1) // 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(it, groupTask2.task2) } // Capture callback from recentsModel#getTasks() val consumer = withArgCaptor<Consumer<ArrayList<GroupTask>>> { splitSelectStateController.findLastActiveTaskAndRunCallback( ComponentName(matchingPackage, matchingClass), taskConsumer) verify(recentsModel).getTasks(capture()) } // Send our mocked tasks consumer.accept(tasks) } @Test fun setInitialApp_withTaskId() { splitSelectStateController.setInitialTaskSelect(null /*intent*/, -1 /*stagePosition*/, ItemInfo(), null /*splitEvent*/, 10 /*alreadyRunningTask*/) assertTrue(splitSelectStateController.isSplitSelectActive) } @Test fun setInitialApp_withIntent() { splitSelectStateController.setInitialTaskSelect(Intent() /*intent*/, -1 /*stagePosition*/, ItemInfo(), null /*splitEvent*/, -1 /*alreadyRunningTask*/) assertTrue(splitSelectStateController.isSplitSelectActive) } @Test fun resetAfterInitial() { splitSelectStateController.setInitialTaskSelect(Intent() /*intent*/, -1 /*stagePosition*/, ItemInfo(), null /*splitEvent*/, -1) splitSelectStateController.resetState() assertFalse(splitSelectStateController.isSplitSelectActive) } private fun generateGroupTask(task1ComponentName: ComponentName, task2ComponentName: ComponentName): GroupTask { val task1 = Task() var taskInfo = ActivityManager.RunningTaskInfo() var intent = Intent() intent.component = task1ComponentName taskInfo.baseIntent = intent task1.key = Task.TaskKey(taskInfo) val task2 = Task() taskInfo = ActivityManager.RunningTaskInfo() intent = Intent() intent.component = task2ComponentName taskInfo.baseIntent = intent task2.key = Task.TaskKey(taskInfo) return GroupTask(task1, task2, SplitConfigurationOptions.SplitBounds( Rect(), Rect(), -1, -1 )) } } No newline at end of file