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 com.android.systemui.dagger.SysUISingleton 20 import com.android.systemui.util.animation.MeasurementOutput 21 import javax.inject.Inject 22 23 /** 24 * A class responsible for managing all media host states of the various host locations and 25 * coordinating the heights among different players. This class can be used to get the most up to 26 * date state for any location. 27 */ 28 @SysUISingleton 29 class MediaHostStatesManager @Inject constructor() { 30 31 private val callbacks: MutableSet<Callback> = mutableSetOf() 32 private val controllers: MutableSet<MediaViewController> = mutableSetOf() 33 34 /** 35 * The overall sizes of the carousel. This is needed to make sure all players in the carousel 36 * have equal size. 37 */ 38 val carouselSizes: MutableMap<Int, MeasurementOutput> = mutableMapOf() 39 40 /** 41 * A map with all media states of all locations. 42 */ 43 val mediaHostStates: MutableMap<Int, MediaHostState> = mutableMapOf() 44 45 /** 46 * Notify that a media state for a given location has changed. Should only be called from 47 * Media hosts themselves. 48 */ updateHostStatenull49 fun updateHostState(@MediaLocation location: Int, hostState: MediaHostState) { 50 val currentState = mediaHostStates.get(location) 51 if (!hostState.equals(currentState)) { 52 val newState = hostState.copy() 53 mediaHostStates.put(location, newState) 54 updateCarouselDimensions(location, hostState) 55 // First update all the controllers to ensure they get the chance to measure 56 for (controller in controllers) { 57 controller.stateCallback.onHostStateChanged(location, newState) 58 } 59 60 // Then update all other callbacks which may depend on the controllers above 61 for (callback in callbacks) { 62 callback.onHostStateChanged(location, newState) 63 } 64 } 65 } 66 67 /** 68 * Get the dimensions of all players combined, which determines the overall height of the 69 * media carousel and the media hosts. 70 */ updateCarouselDimensionsnull71 fun updateCarouselDimensions( 72 @MediaLocation location: Int, 73 hostState: MediaHostState 74 ): MeasurementOutput { 75 val result = MeasurementOutput(0, 0) 76 for (controller in controllers) { 77 val measurement = controller.getMeasurementsForState(hostState) 78 measurement?.let { 79 if (it.measuredHeight > result.measuredHeight) { 80 result.measuredHeight = it.measuredHeight 81 } 82 if (it.measuredWidth > result.measuredWidth) { 83 result.measuredWidth = it.measuredWidth 84 } 85 } 86 } 87 carouselSizes[location] = result 88 return result 89 } 90 91 /** 92 * Add a callback to be called when a MediaState has updated 93 */ addCallbacknull94 fun addCallback(callback: Callback) { 95 callbacks.add(callback) 96 } 97 98 /** 99 * Remove a callback that listens to media states 100 */ removeCallbacknull101 fun removeCallback(callback: Callback) { 102 callbacks.remove(callback) 103 } 104 105 /** 106 * Register a controller that listens to media states and is used to determine the size of 107 * the media carousel 108 */ addControllernull109 fun addController(controller: MediaViewController) { 110 controllers.add(controller) 111 } 112 113 /** 114 * Notify the manager about the removal of a controller. 115 */ removeControllernull116 fun removeController(controller: MediaViewController) { 117 controllers.remove(controller) 118 } 119 120 interface Callback { 121 /** 122 * Notify the callbacks that a media state for a host has changed, and that the 123 * corresponding view states should be updated and applied 124 */ onHostStateChangednull125 fun onHostStateChanged(@MediaLocation location: Int, mediaHostState: MediaHostState) 126 } 127 } 128