summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractorTest.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dagger/MediaDevicesModule.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaControllerInteractor.kt (renamed from packages/SettingsLib/src/com/android/settingslib/volume/data/repository/MediaControllerExt.kt)72
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaControllerChangeModel.kt45
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaOutputKosmos.kt7
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/FakeMediaControllerInteractor.kt34
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaControllerInteractorKosmos.kt24
9 files changed, 164 insertions, 65 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractorTest.kt
index 64c9429cbe25..46df0c227f1c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractorTest.kt
@@ -16,17 +16,16 @@
package com.android.systemui.volume.panel.component.mediaoutput.domain.interactor
-import android.os.Handler
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.android.systemui.volume.localMediaController
import com.android.systemui.volume.mediaControllerRepository
+import com.android.systemui.volume.mediaDeviceSessionInteractor
import com.android.systemui.volume.mediaOutputInteractor
import com.android.systemui.volume.panel.shared.model.filterData
import com.android.systemui.volume.remoteMediaController
@@ -55,12 +54,7 @@ class MediaDeviceSessionInteractorTest : SysuiTestCase() {
listOf(localMediaController, remoteMediaController)
)
- underTest =
- MediaDeviceSessionInteractor(
- testScope.testScheduler,
- Handler(TestableLooper.get(kosmos.testCase).looper),
- mediaControllerRepository,
- )
+ underTest = mediaDeviceSessionInteractor
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/MediaDevicesModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/MediaDevicesModule.kt
index 155102c9b9a7..369610882959 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/MediaDevicesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/MediaDevicesModule.kt
@@ -27,6 +27,8 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory
import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactoryImpl
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaControllerInteractor
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaControllerInteractorImpl
import dagger.Binds
import dagger.Module
import dagger.Provides
@@ -41,6 +43,11 @@ interface MediaDevicesModule {
impl: LocalMediaRepositoryFactoryImpl
): LocalMediaRepositoryFactory
+ @Binds
+ fun bindMediaControllerInteractor(
+ impl: MediaControllerInteractorImpl
+ ): MediaControllerInteractor
+
companion object {
@Provides
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/MediaControllerExt.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaControllerInteractor.kt
index 1f037c0280e3..4812765d4afe 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/MediaControllerExt.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaControllerInteractor.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settingslib.volume.data.repository
+package com.android.systemui.volume.panel.component.mediaoutput.domain.interactor
import android.media.MediaMetadata
import android.media.session.MediaController
@@ -22,79 +22,75 @@ import android.media.session.MediaSession
import android.media.session.PlaybackState
import android.os.Bundle
import android.os.Handler
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaControllerChangeModel
+import javax.inject.Inject
import kotlinx.coroutines.channels.ProducerScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.launch
-/** [MediaController.Callback] flow representation. */
-fun MediaController.stateChanges(handler: Handler): Flow<MediaControllerChange> {
- return callbackFlow {
- val callback = MediaControllerCallbackProducer(this)
- registerCallback(callback, handler)
- awaitClose { unregisterCallback(callback) }
- }
-}
-
-/** Models particular change event received by [MediaController.Callback]. */
-sealed interface MediaControllerChange {
-
- data object SessionDestroyed : MediaControllerChange
-
- data class SessionEvent(val event: String, val extras: Bundle?) : MediaControllerChange
-
- data class PlaybackStateChanged(val state: PlaybackState?) : MediaControllerChange
+interface MediaControllerInteractor {
- data class MetadataChanged(val metadata: MediaMetadata?) : MediaControllerChange
-
- data class QueueChanged(val queue: MutableList<MediaSession.QueueItem>?) :
- MediaControllerChange
-
- data class QueueTitleChanged(val title: CharSequence?) : MediaControllerChange
-
- data class ExtrasChanged(val extras: Bundle?) : MediaControllerChange
+ /** [MediaController.Callback] flow representation. */
+ fun stateChanges(mediaController: MediaController): Flow<MediaControllerChangeModel>
+}
- data class AudioInfoChanged(val info: MediaController.PlaybackInfo?) : MediaControllerChange
+@SysUISingleton
+class MediaControllerInteractorImpl
+@Inject
+constructor(
+ @Background private val backgroundHandler: Handler,
+) : MediaControllerInteractor {
+
+ override fun stateChanges(mediaController: MediaController): Flow<MediaControllerChangeModel> {
+ return conflatedCallbackFlow {
+ val callback = MediaControllerCallbackProducer(this)
+ mediaController.registerCallback(callback, backgroundHandler)
+ awaitClose { mediaController.unregisterCallback(callback) }
+ }
+ }
}
private class MediaControllerCallbackProducer(
- private val producingScope: ProducerScope<MediaControllerChange>
+ private val producingScope: ProducerScope<MediaControllerChangeModel>
) : MediaController.Callback() {
override fun onSessionDestroyed() {
- send(MediaControllerChange.SessionDestroyed)
+ send(MediaControllerChangeModel.SessionDestroyed)
}
override fun onSessionEvent(event: String, extras: Bundle?) {
- send(MediaControllerChange.SessionEvent(event, extras))
+ send(MediaControllerChangeModel.SessionEvent(event, extras))
}
override fun onPlaybackStateChanged(state: PlaybackState?) {
- send(MediaControllerChange.PlaybackStateChanged(state))
+ send(MediaControllerChangeModel.PlaybackStateChanged(state))
}
override fun onMetadataChanged(metadata: MediaMetadata?) {
- send(MediaControllerChange.MetadataChanged(metadata))
+ send(MediaControllerChangeModel.MetadataChanged(metadata))
}
override fun onQueueChanged(queue: MutableList<MediaSession.QueueItem>?) {
- send(MediaControllerChange.QueueChanged(queue))
+ send(MediaControllerChangeModel.QueueChanged(queue))
}
override fun onQueueTitleChanged(title: CharSequence?) {
- send(MediaControllerChange.QueueTitleChanged(title))
+ send(MediaControllerChangeModel.QueueTitleChanged(title))
}
override fun onExtrasChanged(extras: Bundle?) {
- send(MediaControllerChange.ExtrasChanged(extras))
+ send(MediaControllerChangeModel.ExtrasChanged(extras))
}
override fun onAudioInfoChanged(info: MediaController.PlaybackInfo?) {
- send(MediaControllerChange.AudioInfoChanged(info))
+ send(MediaControllerChangeModel.AudioInfoChanged(info))
}
- private fun send(change: MediaControllerChange) {
+ private fun send(change: MediaControllerChangeModel) {
producingScope.launch { producingScope.send(change) }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt
index dc73344fafe6..599bd73abb69 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt
@@ -18,11 +18,9 @@ package com.android.systemui.volume.panel.component.mediaoutput.domain.interacto
import android.media.session.MediaController
import android.media.session.PlaybackState
-import android.os.Handler
-import com.android.settingslib.volume.data.repository.MediaControllerChange
import com.android.settingslib.volume.data.repository.MediaControllerRepository
-import com.android.settingslib.volume.data.repository.stateChanges
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaControllerChangeModel
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import javax.inject.Inject
@@ -45,38 +43,39 @@ class MediaDeviceSessionInteractor
@Inject
constructor(
@Background private val backgroundCoroutineContext: CoroutineContext,
- @Background private val backgroundHandler: Handler,
+ private val mediaControllerInteractor: MediaControllerInteractor,
private val mediaControllerRepository: MediaControllerRepository,
) {
/** [PlaybackState] changes for the [MediaDeviceSession]. */
fun playbackState(session: MediaDeviceSession): Flow<PlaybackState?> {
return stateChanges(session) {
- emit(MediaControllerChange.PlaybackStateChanged(it.playbackState))
+ emit(MediaControllerChangeModel.PlaybackStateChanged(it.playbackState))
}
- .filterIsInstance(MediaControllerChange.PlaybackStateChanged::class)
+ .filterIsInstance(MediaControllerChangeModel.PlaybackStateChanged::class)
.map { it.state }
}
/** [MediaController.PlaybackInfo] changes for the [MediaDeviceSession]. */
fun playbackInfo(session: MediaDeviceSession): Flow<MediaController.PlaybackInfo?> {
return stateChanges(session) {
- emit(MediaControllerChange.AudioInfoChanged(it.playbackInfo))
+ emit(MediaControllerChangeModel.AudioInfoChanged(it.playbackInfo))
}
- .filterIsInstance(MediaControllerChange.AudioInfoChanged::class)
+ .filterIsInstance(MediaControllerChangeModel.AudioInfoChanged::class)
.map { it.info }
}
private fun stateChanges(
session: MediaDeviceSession,
- onStart: suspend FlowCollector<MediaControllerChange>.(controller: MediaController) -> Unit,
- ): Flow<MediaControllerChange?> =
+ onStart:
+ suspend FlowCollector<MediaControllerChangeModel>.(controller: MediaController) -> Unit,
+ ): Flow<MediaControllerChangeModel?> =
mediaControllerRepository.activeSessions
.flatMapLatest { controllers ->
val controller: MediaController =
findControllerForSession(controllers, session)
?: return@flatMapLatest flowOf(null)
- controller.stateChanges(backgroundHandler).onStart { onStart(controller) }
+ mediaControllerInteractor.stateChanges(controller).onStart { onStart(controller) }
}
.flowOn(backgroundCoroutineContext)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
index b00829e48404..9fbd79accf80 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
@@ -19,12 +19,10 @@ package com.android.systemui.volume.panel.component.mediaoutput.domain.interacto
import android.content.pm.PackageManager
import android.media.VolumeProvider
import android.media.session.MediaController
-import android.os.Handler
import android.util.Log
import com.android.settingslib.media.MediaDevice
import com.android.settingslib.volume.data.repository.LocalMediaRepository
import com.android.settingslib.volume.data.repository.MediaControllerRepository
-import com.android.settingslib.volume.data.repository.stateChanges
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory
import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSessions
@@ -61,7 +59,7 @@ constructor(
@VolumePanelScope private val coroutineScope: CoroutineScope,
@Background private val backgroundCoroutineContext: CoroutineContext,
mediaControllerRepository: MediaControllerRepository,
- @Background private val backgroundHandler: Handler,
+ private val mediaControllerInteractor: MediaControllerInteractor,
) {
private val activeMediaControllers: Flow<MediaControllers> =
@@ -194,7 +192,10 @@ constructor(
return flowOf(null)
}
- return stateChanges(backgroundHandler).map { this }.onStart { emit(this@stateChanges) }
+ return mediaControllerInteractor
+ .stateChanges(this)
+ .map { this }
+ .onStart { emit(this@stateChanges) }
}
private data class MediaControllers(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaControllerChangeModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaControllerChangeModel.kt
new file mode 100644
index 000000000000..ef5a44a7a2fd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaControllerChangeModel.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.mediaoutput.domain.model
+
+import android.media.MediaMetadata
+import android.media.session.MediaController
+import android.media.session.MediaSession
+import android.media.session.PlaybackState
+import android.os.Bundle
+
+/** Models particular change event received by [MediaController.Callback]. */
+sealed interface MediaControllerChangeModel {
+
+ data object SessionDestroyed : MediaControllerChangeModel
+
+ data class SessionEvent(val event: String, val extras: Bundle?) : MediaControllerChangeModel
+
+ data class PlaybackStateChanged(val state: PlaybackState?) : MediaControllerChangeModel
+
+ data class MetadataChanged(val metadata: MediaMetadata?) : MediaControllerChangeModel
+
+ data class QueueChanged(val queue: MutableList<MediaSession.QueueItem>?) :
+ MediaControllerChangeModel
+
+ data class QueueTitleChanged(val title: CharSequence?) : MediaControllerChangeModel
+
+ data class ExtrasChanged(val extras: Bundle?) : MediaControllerChangeModel
+
+ data class AudioInfoChanged(val info: MediaController.PlaybackInfo?) :
+ MediaControllerChangeModel
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaOutputKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaOutputKosmos.kt
index 59bbff171725..1b58582a806f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaOutputKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaOutputKosmos.kt
@@ -18,8 +18,6 @@ package com.android.systemui.volume
import android.content.packageManager
import android.content.pm.ApplicationInfo
-import android.os.Handler
-import android.os.looper
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.media.mediaOutputDialogManager
@@ -32,6 +30,7 @@ import com.android.systemui.volume.panel.component.mediaoutput.data.repository.F
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputActionsInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.mediaControllerInteractor
val Kosmos.localMediaRepository by Kosmos.Fixture { FakeLocalMediaRepository() }
val Kosmos.localMediaRepositoryFactory by
@@ -53,7 +52,7 @@ val Kosmos.mediaOutputInteractor by
testScope.backgroundScope,
testScope.testScheduler,
mediaControllerRepository,
- Handler(looper),
+ mediaControllerInteractor,
)
}
@@ -61,7 +60,7 @@ val Kosmos.mediaDeviceSessionInteractor by
Kosmos.Fixture {
MediaDeviceSessionInteractor(
testScope.testScheduler,
- Handler(looper),
+ mediaControllerInteractor,
mediaControllerRepository,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/FakeMediaControllerInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/FakeMediaControllerInteractor.kt
new file mode 100644
index 000000000000..f03ec01bd36f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/FakeMediaControllerInteractor.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.mediaoutput.domain.interactor
+
+import android.media.session.MediaController
+import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaControllerChangeModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+
+class FakeMediaControllerInteractor : MediaControllerInteractor {
+
+ private val stateChanges = MutableSharedFlow<MediaControllerChangeModel>(replay = 1)
+
+ override fun stateChanges(mediaController: MediaController): Flow<MediaControllerChangeModel> =
+ stateChanges
+
+ fun updateState(change: MediaControllerChangeModel) {
+ stateChanges.tryEmit(change)
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaControllerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaControllerInteractorKosmos.kt
new file mode 100644
index 000000000000..652b3ea984e7
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaControllerInteractorKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.mediaoutput.domain.interactor
+
+import android.os.Handler
+import android.os.looper
+import com.android.systemui.kosmos.Kosmos
+
+var Kosmos.mediaControllerInteractor: MediaControllerInteractor by
+ Kosmos.Fixture { MediaControllerInteractorImpl(Handler(looper)) }