1 /* 2 * 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.settingslib.volume.data.repository 18 19 import android.media.session.MediaController 20 import android.media.session.MediaSessionManager 21 import com.android.settingslib.bluetooth.LocalBluetoothManager 22 import com.android.settingslib.bluetooth.headsetAudioModeChanges 23 import com.android.settingslib.media.session.activeMediaChanges 24 import com.android.settingslib.media.session.defaultRemoteSessionChanged 25 import com.android.settingslib.volume.shared.AudioManagerEventsReceiver 26 import com.android.settingslib.volume.shared.model.AudioManagerEvent 27 import kotlin.coroutines.CoroutineContext 28 import kotlinx.coroutines.CoroutineScope 29 import kotlinx.coroutines.flow.SharingStarted 30 import kotlinx.coroutines.flow.StateFlow 31 import kotlinx.coroutines.flow.emptyFlow 32 import kotlinx.coroutines.flow.filterIsInstance 33 import kotlinx.coroutines.flow.filterNotNull 34 import kotlinx.coroutines.flow.flowOn 35 import kotlinx.coroutines.flow.map 36 import kotlinx.coroutines.flow.merge 37 import kotlinx.coroutines.flow.onStart 38 import kotlinx.coroutines.flow.stateIn 39 40 /** Provides controllers for currently active device media sessions. */ 41 interface MediaControllerRepository { 42 43 /** 44 * Get a list of controllers for all ongoing sessions. The controllers will be provided in 45 * priority order with the most important controller at index 0. 46 * 47 * This requires the [android.Manifest.permission.MEDIA_CONTENT_CONTROL] permission be held by 48 * the calling app. 49 */ 50 val activeSessions: StateFlow<List<MediaController>> 51 } 52 53 class MediaControllerRepositoryImpl( 54 audioManagerEventsReceiver: AudioManagerEventsReceiver, 55 private val mediaSessionManager: MediaSessionManager, 56 localBluetoothManager: LocalBluetoothManager?, 57 coroutineScope: CoroutineScope, 58 backgroundContext: CoroutineContext, 59 ) : MediaControllerRepository { 60 61 override val activeSessions: StateFlow<List<MediaController>> = 62 merge( <lambda>null63 mediaSessionManager.defaultRemoteSessionChanged.map { 64 mediaSessionManager.getActiveSessions(null) 65 }, 66 mediaSessionManager.activeMediaChanges.filterNotNull(), <lambda>null67 localBluetoothManager?.headsetAudioModeChanges?.map { 68 mediaSessionManager.getActiveSessions(null) 69 } ?: emptyFlow(), 70 audioManagerEventsReceiver.events 71 .filterIsInstance(AudioManagerEvent.StreamDevicesChanged::class) <lambda>null72 .map { mediaSessionManager.getActiveSessions(null) }, 73 ) <lambda>null74 .onStart { emit(mediaSessionManager.getActiveSessions(null)) } 75 .flowOn(backgroundContext) 76 .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), emptyList()) 77 } 78