• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.recents.data
18 
19 import android.os.UserHandle
20 import android.util.Log
21 import com.android.quickstep.HighResLoadingState.HighResLoadingStateChangedCallback
22 import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskIconChangedCallback
23 import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskThumbnailChangedCallback
24 import com.android.quickstep.util.TaskVisualsChangeListener
25 import com.android.systemui.shared.recents.model.Task
26 import com.android.systemui.shared.recents.model.ThumbnailData
27 import java.util.concurrent.ConcurrentHashMap
28 
29 /** Delegates the checking of task visuals (thumbnails, high res changes, icons) */
30 interface TaskVisualsChangedDelegate :
31     TaskVisualsChangeListener, HighResLoadingStateChangedCallback {
32     /** Registers a callback for visuals relating to icons */
33     fun registerTaskIconChangedCallback(
34         taskKey: Task.TaskKey,
35         taskIconChangedCallback: TaskIconChangedCallback,
36     )
37 
38     /** Unregisters a callback for visuals relating to icons */
39     fun unregisterTaskIconChangedCallback(taskKey: Task.TaskKey)
40 
41     /** Registers a callback for visuals relating to thumbnails */
42     fun registerTaskThumbnailChangedCallback(
43         taskKey: Task.TaskKey,
44         taskThumbnailChangedCallback: TaskThumbnailChangedCallback,
45     )
46 
47     /** Unregisters a callback for visuals relating to thumbnails */
48     fun unregisterTaskThumbnailChangedCallback(taskKey: Task.TaskKey)
49 
50     /** A callback for task icon changes */
51     interface TaskIconChangedCallback {
52         /** Informs the listener that the task icon has changed */
53         fun onTaskIconChanged()
54     }
55 
56     /** A callback for task thumbnail changes */
57     interface TaskThumbnailChangedCallback {
58         /** Informs the listener that the task thumbnail data has changed to [thumbnailData] */
59         fun onTaskThumbnailChanged(thumbnailData: ThumbnailData?)
60 
61         /** Informs the listener that the default resolution for loading thumbnails has changed */
62         fun onHighResLoadingStateChanged(highResEnabled: Boolean)
63     }
64 }
65 
66 class TaskVisualsChangedDelegateImpl(
67     private val taskVisualsChangeNotifier: TaskVisualsChangeNotifier,
68     private val highResLoadingStateNotifier: HighResLoadingStateNotifier,
69 ) : TaskVisualsChangedDelegate {
70     private val taskIconChangedCallbacks =
71         ConcurrentHashMap<Int, Pair<Task.TaskKey, TaskIconChangedCallback>>()
72     private val taskThumbnailChangedCallbacks =
73         ConcurrentHashMap<Int, Pair<Task.TaskKey, TaskThumbnailChangedCallback>>()
74 
onTaskIconChangednull75     override fun onTaskIconChanged(taskId: Int) {
76         taskIconChangedCallbacks[taskId]?.let { (_, callback) -> callback.onTaskIconChanged() }
77     }
78 
onTaskIconChangednull79     override fun onTaskIconChanged(pkg: String, user: UserHandle) {
80         taskIconChangedCallbacks.values
81             .filter { (taskKey, _) ->
82                 pkg == taskKey.packageName && user.identifier == taskKey.userId
83             }
84             .forEach { (_, callback) -> callback.onTaskIconChanged() }
85     }
86 
onTaskThumbnailChangednull87     override fun onTaskThumbnailChanged(taskId: Int, thumbnailData: ThumbnailData?): Task? {
88         taskThumbnailChangedCallbacks[taskId]?.let { (_, callback) ->
89             callback.onTaskThumbnailChanged(thumbnailData)
90         }
91         return null
92     }
93 
onHighResLoadingStateChangednull94     override fun onHighResLoadingStateChanged(enabled: Boolean) {
95         Log.d(TAG, "onHighResLoadingStateChanged(enabled = $enabled)")
96         taskThumbnailChangedCallbacks.values.forEach { (_, callback) ->
97             callback.onHighResLoadingStateChanged(enabled)
98         }
99     }
100 
registerTaskIconChangedCallbacknull101     override fun registerTaskIconChangedCallback(
102         taskKey: Task.TaskKey,
103         taskIconChangedCallback: TaskIconChangedCallback,
104     ) {
105         updateCallbacks {
106             taskIconChangedCallbacks[taskKey.id] = taskKey to taskIconChangedCallback
107         }
108     }
109 
unregisterTaskIconChangedCallbacknull110     override fun unregisterTaskIconChangedCallback(taskKey: Task.TaskKey) {
111         updateCallbacks { taskIconChangedCallbacks.remove(taskKey.id) }
112     }
113 
registerTaskThumbnailChangedCallbacknull114     override fun registerTaskThumbnailChangedCallback(
115         taskKey: Task.TaskKey,
116         taskThumbnailChangedCallback: TaskThumbnailChangedCallback,
117     ) {
118         updateCallbacks {
119             taskThumbnailChangedCallbacks[taskKey.id] = taskKey to taskThumbnailChangedCallback
120         }
121     }
122 
unregisterTaskThumbnailChangedCallbacknull123     override fun unregisterTaskThumbnailChangedCallback(taskKey: Task.TaskKey) {
124         updateCallbacks { taskThumbnailChangedCallbacks.remove(taskKey.id) }
125     }
126 
127     @Synchronized
updateCallbacksnull128     private fun updateCallbacks(callbackModifier: () -> Unit) {
129         val prevHasCallbacks =
130             taskIconChangedCallbacks.size + taskThumbnailChangedCallbacks.size > 0
131         callbackModifier()
132 
133         val currHasCallbacks =
134             taskIconChangedCallbacks.size + taskThumbnailChangedCallbacks.size > 0
135 
136         when {
137             prevHasCallbacks && !currHasCallbacks -> {
138                 taskVisualsChangeNotifier.removeThumbnailChangeListener(this)
139                 highResLoadingStateNotifier.removeCallback(this)
140             }
141             !prevHasCallbacks && currHasCallbacks -> {
142                 taskVisualsChangeNotifier.addThumbnailChangeListener(this)
143                 highResLoadingStateNotifier.addCallback(this)
144             }
145         }
146     }
147 
148     companion object {
149         const val TAG = "TaskVisualsChangedDelegateImpl"
150     }
151 }
152