1 /* 2 * Copyright (C) 2023 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.taskswitcher.data.repository 18 19 import android.app.ActivityManager.RunningTaskInfo 20 import android.app.ActivityTaskManager 21 import android.app.TaskStackListener 22 import android.os.IBinder 23 import android.util.Log 24 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging 25 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow 26 import com.android.systemui.dagger.SysUISingleton 27 import com.android.systemui.dagger.qualifiers.Application 28 import com.android.systemui.dagger.qualifiers.Background 29 import javax.inject.Inject 30 import kotlinx.coroutines.CoroutineDispatcher 31 import kotlinx.coroutines.CoroutineScope 32 import kotlinx.coroutines.channels.awaitClose 33 import kotlinx.coroutines.flow.Flow 34 import kotlinx.coroutines.flow.SharingStarted 35 import kotlinx.coroutines.flow.shareIn 36 import kotlinx.coroutines.withContext 37 38 /** Implementation of [TasksRepository] that uses [ActivityTaskManager] as the data source. */ 39 @SysUISingleton 40 class ActivityTaskManagerTasksRepository 41 @Inject 42 constructor( 43 private val activityTaskManager: ActivityTaskManager, 44 @Application private val applicationScope: CoroutineScope, 45 @Background private val backgroundDispatcher: CoroutineDispatcher, 46 ) : TasksRepository { 47 48 override suspend fun findRunningTaskFromWindowContainerToken( 49 windowContainerToken: IBinder 50 ): RunningTaskInfo? = 51 getRunningTasks().firstOrNull { taskInfo -> 52 taskInfo.token.asBinder() == windowContainerToken 53 } 54 55 private suspend fun getRunningTasks(): List<RunningTaskInfo> = 56 withContext(backgroundDispatcher) { activityTaskManager.getTasks(Integer.MAX_VALUE) } 57 58 override val foregroundTask: Flow<RunningTaskInfo> = 59 conflatedCallbackFlow { 60 val listener = 61 object : TaskStackListener() { 62 override fun onTaskMovedToFront(taskInfo: RunningTaskInfo) { 63 Log.d(TAG, "onTaskMovedToFront: $taskInfo") 64 trySendWithFailureLogging(taskInfo, TAG) 65 } 66 } 67 activityTaskManager.registerTaskStackListener(listener) 68 awaitClose { activityTaskManager.unregisterTaskStackListener(listener) } 69 } 70 .shareIn(applicationScope, SharingStarted.Lazily, replay = 1) 71 72 companion object { 73 private const val TAG = "TasksRepository" 74 } 75 } 76