1 /*
<lambda>null2  * Copyright (C) 2024 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.quickstep.task.thumbnail
18 
19 import android.annotation.ColorInt
20 import android.graphics.Rect
21 import androidx.core.graphics.ColorUtils
22 import com.android.quickstep.recents.data.RecentTasksRepository
23 import com.android.quickstep.recents.viewmodel.RecentsViewData
24 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
25 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
26 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
27 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
28 import com.android.quickstep.task.viewmodel.TaskViewData
29 import com.android.systemui.shared.recents.model.Task
30 import kotlinx.coroutines.ExperimentalCoroutinesApi
31 import kotlinx.coroutines.flow.Flow
32 import kotlinx.coroutines.flow.MutableStateFlow
33 import kotlinx.coroutines.flow.combine
34 import kotlinx.coroutines.flow.distinctUntilChanged
35 import kotlinx.coroutines.flow.flatMapLatest
36 import kotlinx.coroutines.flow.flowOf
37 import kotlinx.coroutines.flow.map
38 
39 @OptIn(ExperimentalCoroutinesApi::class)
40 class TaskThumbnailViewModel(
41     recentsViewData: RecentsViewData,
42     taskViewData: TaskViewData,
43     private val tasksRepository: RecentTasksRepository,
44 ) {
45     private val task = MutableStateFlow<Flow<Task?>>(flowOf(null))
46     private var boundTaskIsRunning = false
47 
48     val recentsFullscreenProgress = recentsViewData.fullscreenProgress
49     val inheritedScale =
50         combine(recentsViewData.scale, taskViewData.scale) { recentsScale, taskScale ->
51             recentsScale * taskScale
52         }
53     val uiState: Flow<TaskThumbnailUiState> =
54         task
55             .flatMapLatest { taskFlow ->
56                 taskFlow.map { taskVal ->
57                     when {
58                         taskVal == null -> Uninitialized
59                         boundTaskIsRunning -> LiveTile
60                         isBackgroundOnly(taskVal) ->
61                             BackgroundOnly(taskVal.colorBackground.removeAlpha())
62                         isSnapshotState(taskVal) -> {
63                             val bitmap = taskVal.thumbnail?.thumbnail!!
64                             Snapshot(
65                                 bitmap,
66                                 Rect(0, 0, bitmap.width, bitmap.height),
67                                 taskVal.colorBackground.removeAlpha()
68                             )
69                         }
70                         else -> Uninitialized
71                     }
72                 }
73             }
74             .distinctUntilChanged()
75 
76     fun bind(taskThumbnail: TaskThumbnail) {
77         boundTaskIsRunning = taskThumbnail.isRunning
78         task.value = tasksRepository.getTaskDataById(taskThumbnail.taskId)
79     }
80 
81     private fun isBackgroundOnly(task: Task): Boolean = task.isLocked || task.thumbnail == null
82 
83     private fun isSnapshotState(task: Task): Boolean {
84         val thumbnailPresent = task.thumbnail?.thumbnail != null
85         val taskLocked = task.isLocked
86 
87         return thumbnailPresent && !taskLocked
88     }
89 
90     @ColorInt private fun Int.removeAlpha(): Int = ColorUtils.setAlphaComponent(this, 0xff)
91 }
92