|
|
|
@@ -0,0 +1,212 @@
|
|
|
|
|
/*
|
|
|
|
|
* 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
|
|
|
|
|
))
|
|
|
|
|
}
|
|
|
|
|
}
|