1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.mediaprojection.appselector.data
18 
19 import android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE
20 import com.android.systemui.dagger.qualifiers.Background
21 import com.android.systemui.settings.UserTracker
22 import com.android.systemui.util.kotlin.getOrNull
23 import com.android.wm.shell.recents.RecentTasks
24 import com.android.wm.shell.util.GroupedRecentTaskInfo
25 import java.util.Optional
26 import java.util.concurrent.Executor
27 import javax.inject.Inject
28 import kotlin.coroutines.resume
29 import kotlin.coroutines.suspendCoroutine
30 import kotlinx.coroutines.CoroutineDispatcher
31 import kotlinx.coroutines.withContext
32 
33 interface RecentTaskListProvider {
34     /** Loads recent tasks, the returned task list is from the most-recent to least-recent order */
35     suspend fun loadRecentTasks(): List<RecentTask>
36 }
37 
38 class ShellRecentTaskListProvider
39 @Inject
40 constructor(
41     @Background private val coroutineDispatcher: CoroutineDispatcher,
42     @Background private val backgroundExecutor: Executor,
43     private val recentTasks: Optional<RecentTasks>,
44     private val userTracker: UserTracker
45 ) : RecentTaskListProvider {
46 
47     private val recents by lazy { recentTasks.getOrNull() }
48 
49     override suspend fun loadRecentTasks(): List<RecentTask> =
50         withContext(coroutineDispatcher) {
51             val rawRecentTasks: List<GroupedRecentTaskInfo> = recents?.getTasks() ?: emptyList()
52 
53             rawRecentTasks
54                 .flatMap { listOfNotNull(it.taskInfo1, it.taskInfo2) }
55                 .map {
56                     RecentTask(
57                         it.taskId,
58                         it.userId,
59                         it.topActivity,
60                         it.baseIntent?.component,
61                         it.taskDescription?.backgroundColor
62                     )
63                 }
64         }
65 
66     private suspend fun RecentTasks.getTasks(): List<GroupedRecentTaskInfo> =
67         suspendCoroutine { continuation ->
68             getRecentTasks(
69                 Integer.MAX_VALUE,
70                 RECENT_IGNORE_UNAVAILABLE,
71                 userTracker.userId,
72                 backgroundExecutor
73             ) { tasks ->
74                 continuation.resume(tasks)
75             }
76         }
77 }
78