1 /*
2  * Copyright (C) 2020 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.media
18 
19 import javax.inject.Inject
20 
21 /**
22  * Combines [MediaDataManager.Listener] events with [MediaDeviceManager.Listener] events.
23  */
24 class MediaDataCombineLatest @Inject constructor() : MediaDataManager.Listener,
25         MediaDeviceManager.Listener {
26 
27     private val listeners: MutableSet<MediaDataManager.Listener> = mutableSetOf()
28     private val entries: MutableMap<String, Pair<MediaData?, MediaDeviceData?>> = mutableMapOf()
29 
30     override fun onMediaDataLoaded(
31         key: String,
32         oldKey: String?,
33         data: MediaData,
34         immediately: Boolean,
35         receivedSmartspaceCardLatency: Int
36     ) {
37         if (oldKey != null && oldKey != key && entries.contains(oldKey)) {
38             entries[key] = data to entries.remove(oldKey)?.second
39             update(key, oldKey)
40         } else {
41             entries[key] = data to entries[key]?.second
42             update(key, key)
43         }
44     }
45 
46     override fun onSmartspaceMediaDataLoaded(
47         key: String,
48         data: SmartspaceMediaData,
49         shouldPrioritize: Boolean,
50         isSsReactivated: Boolean
51     ) {
52         listeners.toSet().forEach { it.onSmartspaceMediaDataLoaded(key, data) }
53     }
54 
55     override fun onMediaDataRemoved(key: String) {
56         remove(key)
57     }
58 
59     override fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean) {
60         listeners.toSet().forEach { it.onSmartspaceMediaDataRemoved(key, immediately) }
61     }
62 
63     override fun onMediaDeviceChanged(
64         key: String,
65         oldKey: String?,
66         data: MediaDeviceData?
67     ) {
68         if (oldKey != null && oldKey != key && entries.contains(oldKey)) {
69             entries[key] = entries.remove(oldKey)?.first to data
70             update(key, oldKey)
71         } else {
72             entries[key] = entries[key]?.first to data
73             update(key, key)
74         }
75     }
76 
77     override fun onKeyRemoved(key: String) {
78         remove(key)
79     }
80 
81     /**
82      * Add a listener for [MediaData] changes that has been combined with latest [MediaDeviceData].
83      */
84     fun addListener(listener: MediaDataManager.Listener) = listeners.add(listener)
85 
86     /**
87      * Remove a listener registered with addListener.
88      */
89     fun removeListener(listener: MediaDataManager.Listener) = listeners.remove(listener)
90 
91     private fun update(key: String, oldKey: String?) {
92         val (entry, device) = entries[key] ?: null to null
93         if (entry != null && device != null) {
94             val data = entry.copy(device = device)
95             val listenersCopy = listeners.toSet()
96             listenersCopy.forEach {
97                 it.onMediaDataLoaded(key, oldKey, data)
98             }
99         }
100     }
101 
102     private fun remove(key: String) {
103         entries.remove(key)?.let {
104             val listenersCopy = listeners.toSet()
105             listenersCopy.forEach {
106                 it.onMediaDataRemoved(key)
107             }
108         }
109     }
110 }
111