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.media.muteawait 18 19 import android.content.Context 20 import android.graphics.drawable.Drawable 21 import android.media.AudioAttributes.USAGE_MEDIA 22 import android.media.AudioDeviceAttributes 23 import android.media.AudioManager 24 import com.android.settingslib.media.DeviceIconUtil 25 import com.android.settingslib.media.LocalMediaManager 26 import com.android.systemui.dagger.qualifiers.Main 27 import java.util.concurrent.Executor 28 29 /** 30 * A class responsible for keeping track of devices that have muted audio playback until the device 31 * is connected. The device connection expected to happen imminently, so we'd like to display the 32 * device name in the media player. When the about-to-connect device changes, [localMediaManager] 33 * will be notified. 34 * 35 * See [AudioManager.muteAwaitConnection] and b/206614671 for more details. 36 */ 37 class MediaMuteAwaitConnectionManager constructor( 38 @Main private val mainExecutor: Executor, 39 private val localMediaManager: LocalMediaManager, 40 private val context: Context, 41 private val deviceIconUtil: DeviceIconUtil, 42 private val logger: MediaMuteAwaitLogger 43 ) { 44 var currentMutedDevice: AudioDeviceAttributes? = null 45 46 val audioManager: AudioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager 47 48 val muteAwaitConnectionChangeListener = object : AudioManager.MuteAwaitConnectionCallback() { onMutedUntilConnectionnull49 override fun onMutedUntilConnection(device: AudioDeviceAttributes, mutedUsages: IntArray) { 50 logger.logMutedDeviceAdded(device.address, device.name, mutedUsages.hasMedia()) 51 if (mutedUsages.hasMedia()) { 52 // There should only be one device that's mutedUntilConnection at a time, so we can 53 // safely override any previous value. 54 currentMutedDevice = device 55 localMediaManager.dispatchAboutToConnectDeviceAdded( 56 device.address, device.name, device.getIcon() 57 ) 58 } 59 } 60 onUnmutedEventnull61 override fun onUnmutedEvent( 62 @UnmuteEvent unmuteEvent: Int, 63 device: AudioDeviceAttributes, 64 mutedUsages: IntArray 65 ) { 66 val isMostRecentDevice = currentMutedDevice == device 67 logger.logMutedDeviceRemoved( 68 device.address, device.name, mutedUsages.hasMedia(), isMostRecentDevice 69 ) 70 if (isMostRecentDevice && mutedUsages.hasMedia()) { 71 currentMutedDevice = null 72 localMediaManager.dispatchAboutToConnectDeviceRemoved() 73 } 74 } 75 } 76 77 /** Start listening for mute await events. */ startListeningnull78 fun startListening() { 79 audioManager.registerMuteAwaitConnectionCallback( 80 mainExecutor, muteAwaitConnectionChangeListener 81 ) 82 val currentDevice = audioManager.mutingExpectedDevice 83 if (currentDevice != null) { 84 currentMutedDevice = currentDevice 85 localMediaManager.dispatchAboutToConnectDeviceAdded( 86 currentDevice.address, currentDevice.name, currentDevice.getIcon() 87 ) 88 } 89 } 90 91 /** Stop listening for mute await events. */ stopListeningnull92 fun stopListening() { 93 audioManager.unregisterMuteAwaitConnectionCallback(muteAwaitConnectionChangeListener) 94 } 95 AudioDeviceAttributesnull96 private fun AudioDeviceAttributes.getIcon(): Drawable { 97 return deviceIconUtil.getIconFromAudioDeviceType(this.type) 98 } 99 IntArraynull100 private fun IntArray.hasMedia() = USAGE_MEDIA in this 101 } 102