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.view
18 
19 import android.graphics.Rect
20 import android.view.View
21 import android.view.ViewGroup
22 import android.widget.ImageView
23 import androidx.recyclerview.widget.RecyclerView.ViewHolder
24 import com.android.systemui.R
25 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelector
26 import com.android.systemui.mediaprojection.appselector.data.AppIconLoader
27 import com.android.systemui.mediaprojection.appselector.data.RecentTask
28 import com.android.systemui.mediaprojection.appselector.data.RecentTaskLabelLoader
29 import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader
30 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
31 import dagger.assisted.Assisted
32 import dagger.assisted.AssistedFactory
33 import dagger.assisted.AssistedInject
34 import kotlinx.coroutines.CoroutineScope
35 import kotlinx.coroutines.Job
36 import kotlinx.coroutines.launch
37 
38 class RecentTaskViewHolder
39 @AssistedInject
40 constructor(
41     @Assisted private val root: ViewGroup,
42     private val iconLoader: AppIconLoader,
43     private val thumbnailLoader: RecentTaskThumbnailLoader,
44     private val labelLoader: RecentTaskLabelLoader,
45     private val taskViewSizeProvider: TaskPreviewSizeProvider,
46     @MediaProjectionAppSelector private val scope: CoroutineScope
47 ) : ViewHolder(root), ConfigurationListener, TaskPreviewSizeProvider.TaskPreviewSizeListener {
48 
49     val thumbnailView: MediaProjectionTaskView = root.requireViewById(R.id.task_thumbnail)
50     private val iconView: ImageView = root.requireViewById(R.id.task_icon)
51 
52     private var job: Job? = null
53 
54     init {
55         updateThumbnailSize()
56     }
57 
58     fun bind(task: RecentTask, onClick: (View) -> Unit) {
59         taskViewSizeProvider.addCallback(this)
60         job?.cancel()
61 
62         job =
63             scope.launch {
64                 task.baseIntentComponent?.let { component ->
65                     launch {
66                         val icon = iconLoader.loadIcon(task.userId, component)
67                         iconView.setImageDrawable(icon)
68                     }
69                     launch {
70                         val label = labelLoader.loadLabel(task.userId, component)
71                         root.contentDescription = label ?: root.context.getString(R.string.unknown)
72                     }
73                 }
74                 launch {
75                     val thumbnail = thumbnailLoader.loadThumbnail(task.taskId)
76                     thumbnailView.bindTask(task, thumbnail)
77                 }
78             }
79 
80         root.setOnClickListener(onClick)
81     }
82 
83     fun onRecycled() {
84         taskViewSizeProvider.removeCallback(this)
85         iconView.setImageDrawable(null)
86         thumbnailView.bindTask(null, null)
87         job?.cancel()
88         job = null
89     }
90 
91     override fun onTaskSizeChanged(size: Rect) {
92         updateThumbnailSize()
93     }
94 
95     private fun updateThumbnailSize() {
96         thumbnailView.layoutParams =
97             thumbnailView.layoutParams.apply {
98                 width = taskViewSizeProvider.size.width()
99                 height = taskViewSizeProvider.size.height()
100             }
101     }
102 
103     @AssistedFactory
104     fun interface Factory {
105         fun create(root: ViewGroup): RecentTaskViewHolder
106     }
107 }
108