Loading packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +20 −0 Original line number Diff line number Diff line Loading @@ -155,6 +155,26 @@ public class ActivityManagerWrapper { } } /** * Requests for a new snapshot to be taken for the given task, stores it in the cache, and * returns a {@link ThumbnailData} with the result. */ @NonNull public ThumbnailData takeTaskThumbnail(int taskId) { TaskSnapshot snapshot = null; try { snapshot = getService().takeTaskSnapshot(taskId, /* updateCache= */ true); } catch (RemoteException e) { Log.w(TAG, "Failed to take task snapshot", e); } if (snapshot != null) { return new ThumbnailData(snapshot); } else { return new ThumbnailData(); } } /** * Removes the outdated snapshot of home task. * Loading packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt +22 −1 Original line number Diff line number Diff line Loading @@ -20,10 +20,15 @@ import android.content.ComponentName import android.os.UserHandle import com.android.systemui.mediaprojection.appselector.data.RecentTask import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver import com.android.systemui.shared.recents.model.ThumbnailData import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Deferred import kotlinx.coroutines.async import kotlinx.coroutines.cancel import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch @MediaProjectionAppSelectorScope Loading @@ -36,7 +41,8 @@ constructor( @HostUserHandle private val hostUserHandle: UserHandle, @MediaProjectionAppSelector private val scope: CoroutineScope, @MediaProjectionAppSelector private val appSelectorComponentName: ComponentName, @MediaProjectionAppSelector private val callerPackageName: String? @MediaProjectionAppSelector private val callerPackageName: String?, private val thumbnailLoader: RecentTaskThumbnailLoader, ) { fun init() { Loading @@ -46,6 +52,11 @@ constructor( val tasks = recentTasks.filterDevicePolicyRestrictedTasks().filterAppSelector().sortedTasks() // Thumbnails are not fresh for the foreground task(s). They are only refreshed at // launch, going to home, or going to overview. // For this reason, we need to refresh them here. refreshForegroundTaskThumbnails(tasks) view.bind(tasks) } } Loading @@ -54,6 +65,16 @@ constructor( scope.cancel() } private suspend fun refreshForegroundTaskThumbnails(tasks: List<RecentTask>) { coroutineScope { val thumbnails: List<Deferred<ThumbnailData?>> = tasks .filter { it.isForegroundTask } .map { async { thumbnailLoader.captureThumbnail(it.taskId) } } thumbnails.forEach { thumbnail -> thumbnail.await() } } } /** Removes all recent tasks that should be blocked according to the policy */ private fun List<RecentTask>.filterDevicePolicyRestrictedTasks(): List<RecentTask> = filter { devicePolicyResolver.isScreenCaptureAllowed( Loading packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt +2 −1 Original line number Diff line number Diff line Loading @@ -25,5 +25,6 @@ data class RecentTask( @UserIdInt val userId: Int, val topActivityComponent: ComponentName?, val baseIntentComponent: ComponentName?, @ColorInt val colorBackground: Int? @ColorInt val colorBackground: Int?, val isForegroundTask: Boolean, ) packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt +10 −4 Original line number Diff line number Diff line Loading @@ -48,9 +48,14 @@ constructor( override suspend fun loadRecentTasks(): List<RecentTask> = withContext(coroutineDispatcher) { val rawRecentTasks: List<GroupedRecentTaskInfo> = recents?.getTasks() ?: emptyList() rawRecentTasks val groupedTasks: List<GroupedRecentTaskInfo> = recents?.getTasks() ?: emptyList() // Note: the returned task list is from the most-recent to least-recent order. // The last foreground task is at index 1, because at index 0 will be our app selector. val foregroundGroup = groupedTasks.elementAtOrNull(1) val foregroundTaskId1 = foregroundGroup?.taskInfo1?.taskId val foregroundTaskId2 = foregroundGroup?.taskInfo2?.taskId val foregroundTaskIds = listOfNotNull(foregroundTaskId1, foregroundTaskId2) groupedTasks .flatMap { listOfNotNull(it.taskInfo1, it.taskInfo2) } .map { RecentTask( Loading @@ -58,7 +63,8 @@ constructor( it.userId, it.topActivity, it.baseIntent?.component, it.taskDescription?.backgroundColor it.taskDescription?.backgroundColor, isForegroundTask = it.taskId in foregroundTaskIds ) } } Loading packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskThumbnailLoader.kt +10 −3 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ import kotlinx.coroutines.withContext interface RecentTaskThumbnailLoader { suspend fun loadThumbnail(taskId: Int): ThumbnailData? suspend fun captureThumbnail(taskId: Int): ThumbnailData? } class ActivityTaskManagerThumbnailLoader Loading @@ -36,8 +38,13 @@ constructor( override suspend fun loadThumbnail(taskId: Int): ThumbnailData? = withContext(coroutineDispatcher) { val thumbnailData = activityManager.getTaskThumbnail(taskId, /* isLowResolution= */ false) if (thumbnailData.thumbnail == null) null else thumbnailData activityManager.getTaskThumbnail(taskId, /* isLowResolution= */ false).takeIf { it.thumbnail != null } } override suspend fun captureThumbnail(taskId: Int): ThumbnailData? = withContext(coroutineDispatcher) { activityManager.takeTaskThumbnail(taskId).takeIf { it.thumbnail != null } } } Loading
packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +20 −0 Original line number Diff line number Diff line Loading @@ -155,6 +155,26 @@ public class ActivityManagerWrapper { } } /** * Requests for a new snapshot to be taken for the given task, stores it in the cache, and * returns a {@link ThumbnailData} with the result. */ @NonNull public ThumbnailData takeTaskThumbnail(int taskId) { TaskSnapshot snapshot = null; try { snapshot = getService().takeTaskSnapshot(taskId, /* updateCache= */ true); } catch (RemoteException e) { Log.w(TAG, "Failed to take task snapshot", e); } if (snapshot != null) { return new ThumbnailData(snapshot); } else { return new ThumbnailData(); } } /** * Removes the outdated snapshot of home task. * Loading
packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt +22 −1 Original line number Diff line number Diff line Loading @@ -20,10 +20,15 @@ import android.content.ComponentName import android.os.UserHandle import com.android.systemui.mediaprojection.appselector.data.RecentTask import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver import com.android.systemui.shared.recents.model.ThumbnailData import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Deferred import kotlinx.coroutines.async import kotlinx.coroutines.cancel import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch @MediaProjectionAppSelectorScope Loading @@ -36,7 +41,8 @@ constructor( @HostUserHandle private val hostUserHandle: UserHandle, @MediaProjectionAppSelector private val scope: CoroutineScope, @MediaProjectionAppSelector private val appSelectorComponentName: ComponentName, @MediaProjectionAppSelector private val callerPackageName: String? @MediaProjectionAppSelector private val callerPackageName: String?, private val thumbnailLoader: RecentTaskThumbnailLoader, ) { fun init() { Loading @@ -46,6 +52,11 @@ constructor( val tasks = recentTasks.filterDevicePolicyRestrictedTasks().filterAppSelector().sortedTasks() // Thumbnails are not fresh for the foreground task(s). They are only refreshed at // launch, going to home, or going to overview. // For this reason, we need to refresh them here. refreshForegroundTaskThumbnails(tasks) view.bind(tasks) } } Loading @@ -54,6 +65,16 @@ constructor( scope.cancel() } private suspend fun refreshForegroundTaskThumbnails(tasks: List<RecentTask>) { coroutineScope { val thumbnails: List<Deferred<ThumbnailData?>> = tasks .filter { it.isForegroundTask } .map { async { thumbnailLoader.captureThumbnail(it.taskId) } } thumbnails.forEach { thumbnail -> thumbnail.await() } } } /** Removes all recent tasks that should be blocked according to the policy */ private fun List<RecentTask>.filterDevicePolicyRestrictedTasks(): List<RecentTask> = filter { devicePolicyResolver.isScreenCaptureAllowed( Loading
packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt +2 −1 Original line number Diff line number Diff line Loading @@ -25,5 +25,6 @@ data class RecentTask( @UserIdInt val userId: Int, val topActivityComponent: ComponentName?, val baseIntentComponent: ComponentName?, @ColorInt val colorBackground: Int? @ColorInt val colorBackground: Int?, val isForegroundTask: Boolean, )
packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt +10 −4 Original line number Diff line number Diff line Loading @@ -48,9 +48,14 @@ constructor( override suspend fun loadRecentTasks(): List<RecentTask> = withContext(coroutineDispatcher) { val rawRecentTasks: List<GroupedRecentTaskInfo> = recents?.getTasks() ?: emptyList() rawRecentTasks val groupedTasks: List<GroupedRecentTaskInfo> = recents?.getTasks() ?: emptyList() // Note: the returned task list is from the most-recent to least-recent order. // The last foreground task is at index 1, because at index 0 will be our app selector. val foregroundGroup = groupedTasks.elementAtOrNull(1) val foregroundTaskId1 = foregroundGroup?.taskInfo1?.taskId val foregroundTaskId2 = foregroundGroup?.taskInfo2?.taskId val foregroundTaskIds = listOfNotNull(foregroundTaskId1, foregroundTaskId2) groupedTasks .flatMap { listOfNotNull(it.taskInfo1, it.taskInfo2) } .map { RecentTask( Loading @@ -58,7 +63,8 @@ constructor( it.userId, it.topActivity, it.baseIntent?.component, it.taskDescription?.backgroundColor it.taskDescription?.backgroundColor, isForegroundTask = it.taskId in foregroundTaskIds ) } } Loading
packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskThumbnailLoader.kt +10 −3 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ import kotlinx.coroutines.withContext interface RecentTaskThumbnailLoader { suspend fun loadThumbnail(taskId: Int): ThumbnailData? suspend fun captureThumbnail(taskId: Int): ThumbnailData? } class ActivityTaskManagerThumbnailLoader Loading @@ -36,8 +38,13 @@ constructor( override suspend fun loadThumbnail(taskId: Int): ThumbnailData? = withContext(coroutineDispatcher) { val thumbnailData = activityManager.getTaskThumbnail(taskId, /* isLowResolution= */ false) if (thumbnailData.thumbnail == null) null else thumbnailData activityManager.getTaskThumbnail(taskId, /* isLowResolution= */ false).takeIf { it.thumbnail != null } } override suspend fun captureThumbnail(taskId: Int): ThumbnailData? = withContext(coroutineDispatcher) { activityManager.takeTaskThumbnail(taskId).takeIf { it.thumbnail != null } } }