Merge "[Partial Screensharing] Implement loading of recent tasks, thumbnails and icons" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
8504f8c843
@@ -484,12 +484,14 @@ public abstract class WMShellBaseModule {
|
||||
ShellInit shellInit,
|
||||
ShellCommandHandler shellCommandHandler,
|
||||
TaskStackListenerImpl taskStackListener,
|
||||
ActivityTaskManager activityTaskManager,
|
||||
Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
|
||||
@ShellMainThread ShellExecutor mainExecutor
|
||||
) {
|
||||
return Optional.ofNullable(
|
||||
RecentTasksController.create(context, shellInit, shellCommandHandler,
|
||||
taskStackListener, desktopModeTaskRepository, mainExecutor));
|
||||
taskStackListener, activityTaskManager, desktopModeTaskRepository,
|
||||
mainExecutor));
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
package com.android.wm.shell.recents;
|
||||
|
||||
import com.android.wm.shell.common.annotations.ExternalThread;
|
||||
import com.android.wm.shell.util.GroupedRecentTaskInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Interface for interacting with the recent tasks.
|
||||
@@ -29,4 +34,11 @@ public interface RecentTasks {
|
||||
default IRecentTasks createExternalInterface() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of recent tasks.
|
||||
*/
|
||||
default void getRecentTasks(int maxNum, int flags, int userId, Executor callbackExecutor,
|
||||
Consumer<List<GroupedRecentTaskInfo>> callback) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Manages the recent task list from the system, caching it as necessary.
|
||||
@@ -72,6 +74,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
|
||||
private final ShellExecutor mMainExecutor;
|
||||
private final TaskStackListenerImpl mTaskStackListener;
|
||||
private final RecentTasks mImpl = new RecentTasksImpl();
|
||||
private final ActivityTaskManager mActivityTaskManager;
|
||||
private IRecentTasksListener mListener;
|
||||
private final boolean mIsDesktopMode;
|
||||
|
||||
@@ -96,6 +99,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
|
||||
ShellInit shellInit,
|
||||
ShellCommandHandler shellCommandHandler,
|
||||
TaskStackListenerImpl taskStackListener,
|
||||
ActivityTaskManager activityTaskManager,
|
||||
Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
|
||||
@ShellMainThread ShellExecutor mainExecutor
|
||||
) {
|
||||
@@ -103,17 +107,19 @@ public class RecentTasksController implements TaskStackListenerCallback,
|
||||
return null;
|
||||
}
|
||||
return new RecentTasksController(context, shellInit, shellCommandHandler, taskStackListener,
|
||||
desktopModeTaskRepository, mainExecutor);
|
||||
activityTaskManager, desktopModeTaskRepository, mainExecutor);
|
||||
}
|
||||
|
||||
RecentTasksController(Context context,
|
||||
ShellInit shellInit,
|
||||
ShellCommandHandler shellCommandHandler,
|
||||
TaskStackListenerImpl taskStackListener,
|
||||
ActivityTaskManager activityTaskManager,
|
||||
Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
|
||||
ShellExecutor mainExecutor) {
|
||||
mContext = context;
|
||||
mShellCommandHandler = shellCommandHandler;
|
||||
mActivityTaskManager = activityTaskManager;
|
||||
mIsDesktopMode = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
|
||||
mTaskStackListener = taskStackListener;
|
||||
mDesktopModeTaskRepository = desktopModeTaskRepository;
|
||||
@@ -269,16 +275,11 @@ public class RecentTasksController implements TaskStackListenerCallback,
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<ActivityManager.RecentTaskInfo> getRawRecentTasks(int maxNum, int flags, int userId) {
|
||||
return ActivityTaskManager.getInstance().getRecentTasks(maxNum, flags, userId);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
ArrayList<GroupedRecentTaskInfo> getRecentTasks(int maxNum, int flags, int userId) {
|
||||
// Note: the returned task list is from the most-recent to least-recent order
|
||||
final List<ActivityManager.RecentTaskInfo> rawList = getRawRecentTasks(maxNum, flags,
|
||||
userId);
|
||||
final List<ActivityManager.RecentTaskInfo> rawList = mActivityTaskManager.getRecentTasks(
|
||||
maxNum, flags, userId);
|
||||
|
||||
// Make a mapping of task id -> task info
|
||||
final SparseArray<ActivityManager.RecentTaskInfo> rawMapping = new SparseArray<>();
|
||||
@@ -335,8 +336,9 @@ public class RecentTasksController implements TaskStackListenerCallback,
|
||||
if (componentName == null) {
|
||||
return null;
|
||||
}
|
||||
List<ActivityManager.RecentTaskInfo> tasks = getRawRecentTasks(Integer.MAX_VALUE,
|
||||
ActivityManager.RECENT_IGNORE_UNAVAILABLE, ActivityManager.getCurrentUser());
|
||||
List<ActivityManager.RecentTaskInfo> tasks = mActivityTaskManager.getRecentTasks(
|
||||
Integer.MAX_VALUE, ActivityManager.RECENT_IGNORE_UNAVAILABLE,
|
||||
ActivityManager.getCurrentUser());
|
||||
for (int i = 0; i < tasks.size(); i++) {
|
||||
final ActivityManager.RecentTaskInfo task = tasks.get(i);
|
||||
if (task.isVisible) {
|
||||
@@ -374,6 +376,16 @@ public class RecentTasksController implements TaskStackListenerCallback,
|
||||
mIRecentTasks = new IRecentTasksImpl(RecentTasksController.this);
|
||||
return mIRecentTasks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getRecentTasks(int maxNum, int flags, int userId, Executor executor,
|
||||
Consumer<List<GroupedRecentTaskInfo>> callback) {
|
||||
mMainExecutor.execute(() -> {
|
||||
List<GroupedRecentTaskInfo> tasks =
|
||||
RecentTasksController.this.getRecentTasks(maxNum, flags, userId);
|
||||
executor.execute(() -> callback.accept(tasks));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import static org.mockito.Mockito.when;
|
||||
import static java.lang.Integer.MAX_VALUE;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Rect;
|
||||
@@ -52,7 +53,6 @@ import com.android.dx.mockito.inline.extended.StaticMockitoSession;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.ShellTestCase;
|
||||
import com.android.wm.shell.TestShellExecutor;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.TaskStackListenerImpl;
|
||||
import com.android.wm.shell.desktopmode.DesktopModeStatus;
|
||||
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
|
||||
@@ -68,7 +68,9 @@ import org.mockito.Mock;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Tests for {@link RecentTasksController}.
|
||||
@@ -85,11 +87,13 @@ public class RecentTasksControllerTest extends ShellTestCase {
|
||||
private ShellCommandHandler mShellCommandHandler;
|
||||
@Mock
|
||||
private DesktopModeTaskRepository mDesktopModeTaskRepository;
|
||||
@Mock
|
||||
private ActivityTaskManager mActivityTaskManager;
|
||||
|
||||
private ShellTaskOrganizer mShellTaskOrganizer;
|
||||
private RecentTasksController mRecentTasksController;
|
||||
private ShellInit mShellInit;
|
||||
private ShellExecutor mMainExecutor;
|
||||
private TestShellExecutor mMainExecutor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -97,8 +101,8 @@ public class RecentTasksControllerTest extends ShellTestCase {
|
||||
when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
|
||||
mShellInit = spy(new ShellInit(mMainExecutor));
|
||||
mRecentTasksController = spy(new RecentTasksController(mContext, mShellInit,
|
||||
mShellCommandHandler, mTaskStackListener, Optional.of(mDesktopModeTaskRepository),
|
||||
mMainExecutor));
|
||||
mShellCommandHandler, mTaskStackListener, mActivityTaskManager,
|
||||
Optional.of(mDesktopModeTaskRepository), mMainExecutor));
|
||||
mShellTaskOrganizer = new ShellTaskOrganizer(mShellInit, mShellCommandHandler,
|
||||
null /* sizeCompatUI */, Optional.empty(), Optional.of(mRecentTasksController),
|
||||
mMainExecutor);
|
||||
@@ -187,6 +191,37 @@ public class RecentTasksControllerTest extends ShellTestCase {
|
||||
t6.taskId, -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRecentTasks_ReturnsRecentTasksAsynchronously() {
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<GroupedRecentTaskInfo>[] recentTasks = new List[1];
|
||||
Consumer<List<GroupedRecentTaskInfo>> consumer = argument -> recentTasks[0] = argument;
|
||||
ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
|
||||
ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
|
||||
ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
|
||||
ActivityManager.RecentTaskInfo t4 = makeTaskInfo(4);
|
||||
ActivityManager.RecentTaskInfo t5 = makeTaskInfo(5);
|
||||
ActivityManager.RecentTaskInfo t6 = makeTaskInfo(6);
|
||||
setRawList(t1, t2, t3, t4, t5, t6);
|
||||
|
||||
// Mark a couple pairs [t2, t4], [t3, t5]
|
||||
SplitBounds pair1Bounds = new SplitBounds(new Rect(), new Rect(), 2, 4);
|
||||
SplitBounds pair2Bounds = new SplitBounds(new Rect(), new Rect(), 3, 5);
|
||||
|
||||
mRecentTasksController.addSplitPair(t2.taskId, t4.taskId, pair1Bounds);
|
||||
mRecentTasksController.addSplitPair(t3.taskId, t5.taskId, pair2Bounds);
|
||||
|
||||
mRecentTasksController.asRecentTasks()
|
||||
.getRecentTasks(MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0, Runnable::run, consumer);
|
||||
mMainExecutor.flushAll();
|
||||
|
||||
assertGroupedTasksListEquals(recentTasks[0],
|
||||
t1.taskId, -1,
|
||||
t2.taskId, t4.taskId,
|
||||
t3.taskId, t5.taskId,
|
||||
t6.taskId, -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRecentTasks_groupActiveFreeformTasks() {
|
||||
StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
|
||||
@@ -296,7 +331,7 @@ public class RecentTasksControllerTest extends ShellTestCase {
|
||||
for (ActivityManager.RecentTaskInfo task : tasks) {
|
||||
rawList.add(task);
|
||||
}
|
||||
doReturn(rawList).when(mRecentTasksController).getRawRecentTasks(anyInt(), anyInt(),
|
||||
doReturn(rawList).when(mActivityTaskManager).getRecentTasks(anyInt(), anyInt(),
|
||||
anyInt());
|
||||
return rawList;
|
||||
}
|
||||
@@ -307,7 +342,7 @@ public class RecentTasksControllerTest extends ShellTestCase {
|
||||
* @param expectedTaskIds list of task ids that map to the flattened task ids of the tasks in
|
||||
* the grouped task list
|
||||
*/
|
||||
private void assertGroupedTasksListEquals(ArrayList<GroupedRecentTaskInfo> recentTasks,
|
||||
private void assertGroupedTasksListEquals(List<GroupedRecentTaskInfo> recentTasks,
|
||||
int... expectedTaskIds) {
|
||||
int[] flattenedTaskIds = new int[recentTasks.size() * 2];
|
||||
for (int i = 0; i < recentTasks.size(); i++) {
|
||||
|
||||
@@ -42,7 +42,7 @@ class MediaProjectionAppSelectorController(
|
||||
}
|
||||
|
||||
private fun List<RecentTask>.sortTasks(): List<RecentTask> =
|
||||
asReversed().sortedBy {
|
||||
sortedBy {
|
||||
// Show normal tasks first and only then tasks with opened app selector
|
||||
it.topActivityComponent == appSelectorComponentName
|
||||
}
|
||||
|
||||
@@ -17,11 +17,17 @@
|
||||
package com.android.systemui.mediaprojection.appselector.data
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.ComponentInfoFlags
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.UserHandle
|
||||
import com.android.launcher3.icons.BaseIconFactory.IconOptions
|
||||
import com.android.launcher3.icons.IconFactory
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
interface AppIconLoader {
|
||||
suspend fun loadIcon(userId: Int, component: ComponentName): Drawable?
|
||||
@@ -31,11 +37,20 @@ class IconLoaderLibAppIconLoader
|
||||
@Inject
|
||||
constructor(
|
||||
@Background private val backgroundDispatcher: CoroutineDispatcher,
|
||||
private val context: Context,
|
||||
private val packageManager: PackageManager
|
||||
) : AppIconLoader {
|
||||
|
||||
override suspend fun loadIcon(userId: Int, component: ComponentName): Drawable? =
|
||||
withContext(backgroundDispatcher) {
|
||||
// TODO(b/240924731): add a blocking call to load an icon using iconloaderlib
|
||||
null
|
||||
IconFactory.obtain(context).use<IconFactory, Drawable?> { iconFactory ->
|
||||
val activityInfo = packageManager
|
||||
.getActivityInfo(component, ComponentInfoFlags.of(0))
|
||||
val icon = activityInfo.loadIcon(packageManager) ?: return@withContext null
|
||||
val userHandler = UserHandle.of(userId)
|
||||
val options = IconOptions().apply { setUser(userHandler) }
|
||||
val badgedIcon = iconFactory.createBadgedIconBitmap(icon, options)
|
||||
badgedIcon.newIcon(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
package com.android.systemui.mediaprojection.appselector.data
|
||||
|
||||
import android.annotation.ColorInt
|
||||
import android.content.ComponentName
|
||||
|
||||
data class RecentTask(
|
||||
val taskId: Int,
|
||||
val userId: Int,
|
||||
val topActivityComponent: ComponentName?,
|
||||
val baseIntentComponent: ComponentName?
|
||||
val baseIntentComponent: ComponentName?,
|
||||
@ColorInt val colorBackground: Int?
|
||||
)
|
||||
|
||||
@@ -16,23 +16,61 @@
|
||||
|
||||
package com.android.systemui.mediaprojection.appselector.data
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.util.kotlin.getOrNull
|
||||
import com.android.wm.shell.recents.RecentTasks
|
||||
import com.android.wm.shell.util.GroupedRecentTaskInfo
|
||||
import java.util.Optional
|
||||
import javax.inject.Inject
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
interface RecentTaskListProvider {
|
||||
/** Loads recent tasks, the returned task list is from the most-recent to least-recent order */
|
||||
suspend fun loadRecentTasks(): List<RecentTask>
|
||||
}
|
||||
|
||||
class ShellRecentTaskListProvider
|
||||
@Inject
|
||||
constructor(@Background private val coroutineDispatcher: CoroutineDispatcher) :
|
||||
RecentTaskListProvider {
|
||||
constructor(
|
||||
@Background private val coroutineDispatcher: CoroutineDispatcher,
|
||||
@Background private val backgroundExecutor: Executor,
|
||||
private val recentTasks: Optional<RecentTasks>
|
||||
) : RecentTaskListProvider {
|
||||
|
||||
private val recents by lazy { recentTasks.getOrNull() }
|
||||
|
||||
override suspend fun loadRecentTasks(): List<RecentTask> =
|
||||
withContext(coroutineDispatcher) {
|
||||
// TODO(b/240924731): add blocking call to load the recents
|
||||
emptyList()
|
||||
val rawRecentTasks: List<GroupedRecentTaskInfo> = recents?.getTasks() ?: emptyList()
|
||||
|
||||
rawRecentTasks
|
||||
.flatMap { listOfNotNull(it.taskInfo1, it.taskInfo2) }
|
||||
.map {
|
||||
RecentTask(
|
||||
it.taskId,
|
||||
it.userId,
|
||||
it.topActivity,
|
||||
it.baseIntent?.component,
|
||||
it.taskDescription?.backgroundColor
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun RecentTasks.getTasks(): List<GroupedRecentTaskInfo> =
|
||||
suspendCoroutine { continuation ->
|
||||
getRecentTasks(
|
||||
Integer.MAX_VALUE,
|
||||
RECENT_IGNORE_UNAVAILABLE,
|
||||
ActivityManager.getCurrentUser(),
|
||||
backgroundExecutor
|
||||
) { tasks ->
|
||||
continuation.resume(tasks)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.systemui.mediaprojection.appselector.data
|
||||
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -30,12 +31,13 @@ class ActivityTaskManagerThumbnailLoader
|
||||
@Inject
|
||||
constructor(
|
||||
@Background private val coroutineDispatcher: CoroutineDispatcher,
|
||||
) :
|
||||
RecentTaskThumbnailLoader {
|
||||
private val activityManager: ActivityManagerWrapper
|
||||
) : RecentTaskThumbnailLoader {
|
||||
|
||||
override suspend fun loadThumbnail(taskId: Int): ThumbnailData? =
|
||||
withContext(coroutineDispatcher) {
|
||||
// TODO(b/240924731): add blocking call to load a thumbnail
|
||||
null
|
||||
val thumbnailData =
|
||||
activityManager.getTaskThumbnail(taskId, /* isLowResolution= */ false)
|
||||
if (thumbnailData.thumbnail == null) null else thumbnailData
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ class MediaProjectionAppSelectorControllerTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun initMultipleRecentTasksWithoutAppSelectorTask_bindsListInReverse() {
|
||||
fun initMultipleRecentTasksWithoutAppSelectorTask_bindsListInTheSameOrder() {
|
||||
val tasks = listOf(
|
||||
createRecentTask(taskId = 1),
|
||||
createRecentTask(taskId = 2),
|
||||
@@ -66,15 +66,15 @@ class MediaProjectionAppSelectorControllerTest : SysuiTestCase() {
|
||||
|
||||
verify(view).bind(
|
||||
listOf(
|
||||
createRecentTask(taskId = 3),
|
||||
createRecentTask(taskId = 2),
|
||||
createRecentTask(taskId = 1),
|
||||
createRecentTask(taskId = 2),
|
||||
createRecentTask(taskId = 3),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun initRecentTasksWithAppSelectorTasks_bindsListInReverseAndAppSelectorTasksAtTheEnd() {
|
||||
fun initRecentTasksWithAppSelectorTasks_bindsAppSelectorTasksAtTheEnd() {
|
||||
val tasks = listOf(
|
||||
createRecentTask(taskId = 1),
|
||||
createRecentTask(taskId = 2, topActivityComponent = appSelectorComponentName),
|
||||
@@ -88,11 +88,11 @@ class MediaProjectionAppSelectorControllerTest : SysuiTestCase() {
|
||||
|
||||
verify(view).bind(
|
||||
listOf(
|
||||
createRecentTask(taskId = 5),
|
||||
createRecentTask(taskId = 3),
|
||||
createRecentTask(taskId = 1),
|
||||
createRecentTask(taskId = 4, topActivityComponent = appSelectorComponentName),
|
||||
createRecentTask(taskId = 3),
|
||||
createRecentTask(taskId = 5),
|
||||
createRecentTask(taskId = 2, topActivityComponent = appSelectorComponentName),
|
||||
createRecentTask(taskId = 4, topActivityComponent = appSelectorComponentName),
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -105,7 +105,8 @@ class MediaProjectionAppSelectorControllerTest : SysuiTestCase() {
|
||||
taskId = taskId,
|
||||
topActivityComponent = topActivityComponent,
|
||||
baseIntentComponent = ComponentName("com", "Test"),
|
||||
userId = 0
|
||||
userId = 0,
|
||||
colorBackground = 0
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.android.systemui.mediaprojection.appselector.data
|
||||
|
||||
import android.app.ActivityManager.RecentTaskInfo
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.android.wm.shell.recents.RecentTasks
|
||||
import com.android.wm.shell.util.GroupedRecentTaskInfo
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import java.util.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.function.Consumer
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@SmallTest
|
||||
class ShellRecentTaskListProviderTest : SysuiTestCase() {
|
||||
|
||||
private val dispatcher = Dispatchers.Unconfined
|
||||
private val recentTasks: RecentTasks = mock()
|
||||
private val recentTaskListProvider =
|
||||
ShellRecentTaskListProvider(dispatcher, Runnable::run, Optional.of(recentTasks))
|
||||
|
||||
@Test
|
||||
fun loadRecentTasks_oneTask_returnsTheSameTask() {
|
||||
givenRecentTasks(createSingleTask(taskId = 1))
|
||||
|
||||
val result = runBlocking { recentTaskListProvider.loadRecentTasks() }
|
||||
|
||||
assertThat(result).containsExactly(createRecentTask(taskId = 1))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun loadRecentTasks_multipleTasks_returnsTheSameTasks() {
|
||||
givenRecentTasks(
|
||||
createSingleTask(taskId = 1),
|
||||
createSingleTask(taskId = 2),
|
||||
createSingleTask(taskId = 3),
|
||||
)
|
||||
|
||||
val result = runBlocking { recentTaskListProvider.loadRecentTasks() }
|
||||
|
||||
assertThat(result)
|
||||
.containsExactly(
|
||||
createRecentTask(taskId = 1),
|
||||
createRecentTask(taskId = 2),
|
||||
createRecentTask(taskId = 3),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun loadRecentTasks_groupedTask_returnsUngroupedTasks() {
|
||||
givenRecentTasks(createTaskPair(taskId1 = 1, taskId2 = 2))
|
||||
|
||||
val result = runBlocking { recentTaskListProvider.loadRecentTasks() }
|
||||
|
||||
assertThat(result)
|
||||
.containsExactly(createRecentTask(taskId = 1), createRecentTask(taskId = 2))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun loadRecentTasks_mixedSingleAndGroupedTask_returnsUngroupedTasks() {
|
||||
givenRecentTasks(
|
||||
createSingleTask(taskId = 1),
|
||||
createTaskPair(taskId1 = 2, taskId2 = 3),
|
||||
createSingleTask(taskId = 4),
|
||||
createTaskPair(taskId1 = 5, taskId2 = 6),
|
||||
)
|
||||
|
||||
val result = runBlocking { recentTaskListProvider.loadRecentTasks() }
|
||||
|
||||
assertThat(result)
|
||||
.containsExactly(
|
||||
createRecentTask(taskId = 1),
|
||||
createRecentTask(taskId = 2),
|
||||
createRecentTask(taskId = 3),
|
||||
createRecentTask(taskId = 4),
|
||||
createRecentTask(taskId = 5),
|
||||
createRecentTask(taskId = 6),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun givenRecentTasks(vararg tasks: GroupedRecentTaskInfo) {
|
||||
whenever(recentTasks.getRecentTasks(any(), any(), any(), any(), any())).thenAnswer {
|
||||
val consumer = it.arguments.last() as Consumer<List<GroupedRecentTaskInfo>>
|
||||
consumer.accept(tasks.toList())
|
||||
}
|
||||
}
|
||||
|
||||
private fun createRecentTask(taskId: Int): RecentTask =
|
||||
RecentTask(
|
||||
taskId = taskId,
|
||||
userId = 0,
|
||||
topActivityComponent = null,
|
||||
baseIntentComponent = null,
|
||||
colorBackground = null
|
||||
)
|
||||
|
||||
private fun createSingleTask(taskId: Int): GroupedRecentTaskInfo =
|
||||
GroupedRecentTaskInfo.forSingleTask(createTaskInfo(taskId))
|
||||
|
||||
private fun createTaskPair(taskId1: Int, taskId2: Int): GroupedRecentTaskInfo =
|
||||
GroupedRecentTaskInfo.forSplitTasks(createTaskInfo(taskId1), createTaskInfo(taskId2), null)
|
||||
|
||||
private fun createTaskInfo(taskId: Int) = RecentTaskInfo().apply { this.taskId = taskId }
|
||||
}
|
||||
Reference in New Issue
Block a user