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.systemui.volume.panel.component.mediaoutput.domain.interactor 18 19 import android.media.MediaMetadata 20 import android.media.session.MediaController 21 import android.media.session.MediaSession 22 import android.media.session.PlaybackState 23 import android.os.Bundle 24 import android.os.Handler 25 import com.android.systemui.dagger.SysUISingleton 26 import com.android.systemui.dagger.qualifiers.Background 27 import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow 28 import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaControllerChangeModel 29 import javax.inject.Inject 30 import kotlinx.coroutines.channels.ProducerScope 31 import kotlinx.coroutines.channels.awaitClose 32 import kotlinx.coroutines.flow.Flow 33 import kotlinx.coroutines.launch 34 35 interface MediaControllerInteractor { 36 37 /** [MediaController.Callback] flow representation. */ stateChangesnull38 fun stateChanges(mediaController: MediaController): Flow<MediaControllerChangeModel> 39 } 40 41 @SysUISingleton 42 class MediaControllerInteractorImpl 43 @Inject 44 constructor( 45 @Background private val backgroundHandler: Handler, 46 ) : MediaControllerInteractor { 47 48 override fun stateChanges(mediaController: MediaController): Flow<MediaControllerChangeModel> { 49 return conflatedCallbackFlow { 50 val callback = MediaControllerCallbackProducer(this) 51 mediaController.registerCallback(callback, backgroundHandler) 52 awaitClose { mediaController.unregisterCallback(callback) } 53 } 54 } 55 } 56 57 private class MediaControllerCallbackProducer( 58 private val producingScope: ProducerScope<MediaControllerChangeModel> 59 ) : MediaController.Callback() { 60 onSessionDestroyednull61 override fun onSessionDestroyed() { 62 send(MediaControllerChangeModel.SessionDestroyed) 63 } 64 onSessionEventnull65 override fun onSessionEvent(event: String, extras: Bundle?) { 66 send(MediaControllerChangeModel.SessionEvent(event, extras)) 67 } 68 onPlaybackStateChangednull69 override fun onPlaybackStateChanged(state: PlaybackState?) { 70 send(MediaControllerChangeModel.PlaybackStateChanged(state)) 71 } 72 onMetadataChangednull73 override fun onMetadataChanged(metadata: MediaMetadata?) { 74 send(MediaControllerChangeModel.MetadataChanged(metadata)) 75 } 76 onQueueChangednull77 override fun onQueueChanged(queue: MutableList<MediaSession.QueueItem>?) { 78 send(MediaControllerChangeModel.QueueChanged(queue)) 79 } 80 onQueueTitleChangednull81 override fun onQueueTitleChanged(title: CharSequence?) { 82 send(MediaControllerChangeModel.QueueTitleChanged(title)) 83 } 84 onExtrasChangednull85 override fun onExtrasChanged(extras: Bundle?) { 86 send(MediaControllerChangeModel.ExtrasChanged(extras)) 87 } 88 onAudioInfoChangednull89 override fun onAudioInfoChanged(info: MediaController.PlaybackInfo) { 90 send(MediaControllerChangeModel.AudioInfoChanged(info)) 91 } 92 sendnull93 private fun send(change: MediaControllerChangeModel) { 94 producingScope.launch { producingScope.send(change) } 95 } 96 } 97