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