1 /* <lambda>null2 * 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 18 19 import android.content.ComponentName 20 import android.os.UserHandle 21 import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger 22 import com.android.systemui.mediaprojection.appselector.data.RecentTask 23 import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider 24 import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader 25 import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver 26 import com.android.systemui.shared.recents.model.ThumbnailData 27 import javax.inject.Inject 28 import kotlinx.coroutines.CoroutineScope 29 import kotlinx.coroutines.Deferred 30 import kotlinx.coroutines.async 31 import kotlinx.coroutines.cancel 32 import kotlinx.coroutines.coroutineScope 33 import kotlinx.coroutines.launch 34 35 @MediaProjectionAppSelectorScope 36 class MediaProjectionAppSelectorController 37 @Inject 38 constructor( 39 private val recentTaskListProvider: RecentTaskListProvider, 40 private val view: MediaProjectionAppSelectorView, 41 private val devicePolicyResolver: ScreenCaptureDevicePolicyResolver, 42 @HostUserHandle private val hostUserHandle: UserHandle, 43 @MediaProjectionAppSelector private val scope: CoroutineScope, 44 @MediaProjectionAppSelector private val appSelectorComponentName: ComponentName, 45 @MediaProjectionAppSelector private val callerPackageName: String?, 46 private val thumbnailLoader: RecentTaskThumbnailLoader, 47 @MediaProjectionAppSelector private val isFirstStart: Boolean, 48 private val logger: MediaProjectionMetricsLogger, 49 @HostUid private val hostUid: Int, 50 ) { 51 52 fun init() { 53 // Only log during the first start of the app selector. 54 // Don't log when the app selector restarts due to a config change. 55 if (isFirstStart) { 56 logger.notifyAppSelectorDisplayed(hostUid) 57 } 58 59 scope.launch { 60 val recentTasks = recentTaskListProvider.loadRecentTasks() 61 62 val tasks = 63 recentTasks.filterDevicePolicyRestrictedTasks().filterAppSelector().sortedTasks() 64 65 // Thumbnails are not fresh for the foreground task(s). They are only refreshed at 66 // launch, going to home, or going to overview. 67 // For this reason, we need to refresh them here. 68 refreshForegroundTaskThumbnails(tasks) 69 70 view.bind(tasks) 71 } 72 } 73 74 fun destroy() { 75 scope.cancel() 76 } 77 78 fun onSelectorDismissed() { 79 logger.notifyProjectionRequestCancelled(hostUid) 80 } 81 82 private suspend fun refreshForegroundTaskThumbnails(tasks: List<RecentTask>) { 83 coroutineScope { 84 val thumbnails: List<Deferred<ThumbnailData?>> = 85 tasks 86 .filter { it.isForegroundTask } 87 .map { async { thumbnailLoader.captureThumbnail(it.taskId) } } 88 thumbnails.forEach { thumbnail -> thumbnail.await() } 89 } 90 } 91 92 /** Removes all recent tasks that should be blocked according to the policy */ 93 private fun List<RecentTask>.filterDevicePolicyRestrictedTasks(): List<RecentTask> = filter { 94 devicePolicyResolver.isScreenCaptureAllowed( 95 targetAppUserHandle = UserHandle.of(it.userId), 96 hostAppUserHandle = hostUserHandle 97 ) 98 } 99 100 private fun List<RecentTask>.filterAppSelector(): List<RecentTask> = filter { 101 // Only take tasks that is not the app selector 102 it.topActivityComponent != appSelectorComponentName 103 } 104 105 private fun List<RecentTask>.sortedTasks(): List<RecentTask> = sortedBy { 106 // Show normal tasks first and only then tasks with opened app selector 107 it.topActivityComponent?.packageName == callerPackageName 108 } 109 } 110