1 /* <lambda>null2 * 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.systemui.mediarouter.data.repository 18 19 import android.media.projection.StopReason 20 import com.android.systemui.dagger.SysUISingleton 21 import com.android.systemui.dagger.qualifiers.Application 22 import com.android.systemui.log.LogBuffer 23 import com.android.systemui.log.core.LogLevel 24 import com.android.systemui.mediarouter.MediaRouterLog 25 import com.android.systemui.statusbar.policy.CastController 26 import com.android.systemui.statusbar.policy.CastDevice 27 import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow 28 import javax.inject.Inject 29 import kotlinx.coroutines.CoroutineScope 30 import kotlinx.coroutines.channels.awaitClose 31 import kotlinx.coroutines.flow.SharingStarted 32 import kotlinx.coroutines.flow.StateFlow 33 import kotlinx.coroutines.flow.distinctUntilChanged 34 import kotlinx.coroutines.flow.map 35 import kotlinx.coroutines.flow.onEach 36 import kotlinx.coroutines.flow.stateIn 37 38 /** A repository for data coming from MediaRouter APIs. */ 39 interface MediaRouterRepository { 40 /** A list of the cast devices that MediaRouter is currently aware of. */ 41 val castDevices: StateFlow<List<CastDevice>> 42 43 /** Stops the cast to the given device. */ 44 fun stopCasting(device: CastDevice, @StopReason stopReason: Int) 45 } 46 47 @SysUISingleton 48 class MediaRouterRepositoryImpl 49 @Inject 50 constructor( 51 @Application private val scope: CoroutineScope, 52 private val castController: CastController, 53 @MediaRouterLog private val logger: LogBuffer, 54 ) : MediaRouterRepository { 55 override val castDevices: StateFlow<List<CastDevice>> = <lambda>null56 conflatedCallbackFlow { 57 val callback = CastController.Callback { trySend(castController.castDevices) } 58 castController.addCallback(callback) 59 awaitClose { castController.removeCallback(callback) } 60 } 61 // The CastController.Callback is pretty noisy and sends the same values multiple times 62 // in a row, so use a distinctUntilChanged before logging. 63 .distinctUntilChanged() allDevicesnull64 .onEach { allDevices -> 65 val logString = allDevices.map { it.shortLogString }.toString() 66 logger.log(TAG, LogLevel.INFO, { str1 = logString }, { "All cast devices: $str1" }) 67 } <lambda>null68 .map { it.filter { device -> device.origin == CastDevice.CastOrigin.MediaRouter } } 69 .stateIn(scope, SharingStarted.WhileSubscribed(), emptyList()) 70 stopCastingnull71 override fun stopCasting(device: CastDevice, @StopReason stopReason: Int) { 72 castController.stopCasting(device, stopReason) 73 } 74 75 companion object { 76 private const val TAG = "MediaRouterRepo" 77 } 78 } 79