Loading packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/CaptioningRepositoryTest.kt +27 −25 Original line number Diff line number Diff line Loading @@ -20,11 +20,15 @@ import android.view.accessibility.CaptioningManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectValues import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.userRepository import com.android.systemui.user.utils.FakeUserScopedService import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before Loading @@ -39,10 +43,11 @@ import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @Suppress("UnspecifiedRegisterReceiverFlag") @RunWith(AndroidJUnit4::class) class CaptioningRepositoryTest : SysuiTestCase() { private val kosmos = testKosmos() @Captor private lateinit var listenerCaptor: ArgumentCaptor<CaptioningManager.CaptioningChangeListener> Loading @@ -50,34 +55,33 @@ class CaptioningRepositoryTest : SysuiTestCase() { private lateinit var underTest: CaptioningRepository private val testScope = TestScope() @Before fun setup() { MockitoAnnotations.initMocks(this) underTest = with(kosmos) { CaptioningRepositoryImpl( captioningManager, FakeUserScopedService(captioningManager), userRepository, testScope.testScheduler, testScope.backgroundScope applicationCoroutineScope, ) } } @Test fun isSystemAudioCaptioningEnabled_change_repositoryEmits() { testScope.runTest { `when`(captioningManager.isEnabled).thenReturn(false) val isSystemAudioCaptioningEnabled = mutableListOf<Boolean>() underTest.isSystemAudioCaptioningEnabled .onEach { isSystemAudioCaptioningEnabled.add(it) } .launchIn(backgroundScope) kosmos.testScope.runTest { `when`(captioningManager.isSystemAudioCaptioningEnabled).thenReturn(false) val models by collectValues(underTest.captioningModel.filterNotNull()) runCurrent() `when`(captioningManager.isSystemAudioCaptioningEnabled).thenReturn(true) triggerOnSystemAudioCaptioningChange() runCurrent() assertThat(isSystemAudioCaptioningEnabled) assertThat(models.map { it.isSystemAudioCaptioningEnabled }) .containsExactlyElementsIn(listOf(false, true)) .inOrder() } Loading @@ -85,18 +89,16 @@ class CaptioningRepositoryTest : SysuiTestCase() { @Test fun isSystemAudioCaptioningUiEnabled_change_repositoryEmits() { testScope.runTest { `when`(captioningManager.isSystemAudioCaptioningUiEnabled).thenReturn(false) val isSystemAudioCaptioningUiEnabled = mutableListOf<Boolean>() underTest.isSystemAudioCaptioningUiEnabled .onEach { isSystemAudioCaptioningUiEnabled.add(it) } .launchIn(backgroundScope) kosmos.testScope.runTest { `when`(captioningManager.isEnabled).thenReturn(false) val models by collectValues(underTest.captioningModel.filterNotNull()) runCurrent() `when`(captioningManager.isSystemAudioCaptioningUiEnabled).thenReturn(true) triggerSystemAudioCaptioningUiChange() runCurrent() assertThat(isSystemAudioCaptioningUiEnabled) assertThat(models.map { it.isSystemAudioCaptioningUiEnabled }) .containsExactlyElementsIn(listOf(false, true)) .inOrder() } Loading packages/SystemUI/src/com/android/systemui/accessibility/data/model/CaptioningModel.kt 0 → 100644 +22 −0 Original line number Diff line number Diff line /* * 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.accessibility.data.model data class CaptioningModel( val isSystemAudioCaptioningUiEnabled: Boolean, val isSystemAudioCaptioningEnabled: Boolean, ) packages/SystemUI/src/com/android/systemui/accessibility/data/repository/CaptioningRepository.kt +59 −67 Original line number Diff line number Diff line Loading @@ -16,98 +16,90 @@ package com.android.systemui.accessibility.data.repository import android.annotation.SuppressLint import android.view.accessibility.CaptioningManager import com.android.systemui.accessibility.data.model.CaptioningModel import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.user.utils.UserScopedService import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import javax.inject.Inject import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.ProducerScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext interface CaptioningRepository { /** The system audio caption enabled state. */ val isSystemAudioCaptioningEnabled: StateFlow<Boolean> /** Current state of Live Captions. */ val captioningModel: StateFlow<CaptioningModel?> /** The system audio caption UI enabled state. */ val isSystemAudioCaptioningUiEnabled: StateFlow<Boolean> /** Sets [isSystemAudioCaptioningEnabled]. */ /** Sets [CaptioningModel.isSystemAudioCaptioningEnabled]. */ suspend fun setIsSystemAudioCaptioningEnabled(isEnabled: Boolean) } class CaptioningRepositoryImpl( private val captioningManager: CaptioningManager, private val backgroundCoroutineContext: CoroutineContext, coroutineScope: CoroutineScope, @OptIn(ExperimentalCoroutinesApi::class) class CaptioningRepositoryImpl @Inject constructor( private val userScopedCaptioningManagerProvider: UserScopedService<CaptioningManager>, userRepository: UserRepository, @Background private val backgroundCoroutineContext: CoroutineContext, @Application coroutineScope: CoroutineScope, ) : CaptioningRepository { private val captioningChanges: SharedFlow<CaptioningChange> = callbackFlow { val listener = CaptioningChangeProducingListener(this) captioningManager.addCaptioningChangeListener(listener) awaitClose { captioningManager.removeCaptioningChangeListener(listener) } } .shareIn(coroutineScope, SharingStarted.WhileSubscribed(), replay = 0) @SuppressLint("NonInjectedService") // this uses user-aware context private val captioningManager: StateFlow<CaptioningManager?> = userRepository.selectedUser .map { userScopedCaptioningManagerProvider.forUser(it.userInfo.userHandle) } .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), null) override val isSystemAudioCaptioningEnabled: StateFlow<Boolean> = captioningChanges .filterIsInstance(CaptioningChange.IsSystemAudioCaptioningEnabled::class) .map { it.isEnabled } .onStart { emit(captioningManager.isSystemAudioCaptioningEnabled) } .stateIn( coroutineScope, SharingStarted.WhileSubscribed(), captioningManager.isSystemAudioCaptioningEnabled, ) override val isSystemAudioCaptioningUiEnabled: StateFlow<Boolean> = captioningChanges .filterIsInstance(CaptioningChange.IsSystemUICaptioningEnabled::class) .map { it.isEnabled } .onStart { emit(captioningManager.isSystemAudioCaptioningUiEnabled) } .stateIn( coroutineScope, SharingStarted.WhileSubscribed(), captioningManager.isSystemAudioCaptioningUiEnabled, ) override val captioningModel: StateFlow<CaptioningModel?> = captioningManager .filterNotNull() .flatMapLatest { it.captioningModel() } .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), null) override suspend fun setIsSystemAudioCaptioningEnabled(isEnabled: Boolean) { withContext(backgroundCoroutineContext) { captioningManager.isSystemAudioCaptioningEnabled = isEnabled captioningManager.value?.isSystemAudioCaptioningEnabled = isEnabled } } private sealed interface CaptioningChange { data class IsSystemAudioCaptioningEnabled(val isEnabled: Boolean) : CaptioningChange data class IsSystemUICaptioningEnabled(val isEnabled: Boolean) : CaptioningChange } private class CaptioningChangeProducingListener( private val scope: ProducerScope<CaptioningChange> ) : CaptioningManager.CaptioningChangeListener() { private fun CaptioningManager.captioningModel(): Flow<CaptioningModel> { return conflatedCallbackFlow { val listener = object : CaptioningManager.CaptioningChangeListener() { override fun onSystemAudioCaptioningChanged(enabled: Boolean) { emitChange(CaptioningChange.IsSystemAudioCaptioningEnabled(enabled)) trySend(Unit) } override fun onSystemAudioCaptioningUiChanged(enabled: Boolean) { emitChange(CaptioningChange.IsSystemUICaptioningEnabled(enabled)) trySend(Unit) } private fun emitChange(change: CaptioningChange) { scope.launch { scope.send(change) } } addCaptioningChangeListener(listener) awaitClose { removeCaptioningChangeListener(listener) } } .onStart { emit(Unit) } .map { CaptioningModel( isSystemAudioCaptioningEnabled = isSystemAudioCaptioningEnabled, isSystemAudioCaptioningUiEnabled = isSystemAudioCaptioningUiEnabled, ) } .flowOn(backgroundCoroutineContext) } } packages/SystemUI/src/com/android/systemui/accessibility/domain/interactor/CaptioningInteractor.kt +13 −7 Original line number Diff line number Diff line Loading @@ -17,16 +17,22 @@ package com.android.systemui.accessibility.domain.interactor import com.android.systemui.accessibility.data.repository.CaptioningRepository import kotlinx.coroutines.flow.StateFlow import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map class CaptioningInteractor(private val repository: CaptioningRepository) { @SysUISingleton class CaptioningInteractor @Inject constructor(private val repository: CaptioningRepository) { val isSystemAudioCaptioningEnabled: StateFlow<Boolean> get() = repository.isSystemAudioCaptioningEnabled val isSystemAudioCaptioningEnabled: Flow<Boolean> = repository.captioningModel.filterNotNull().map { it.isSystemAudioCaptioningEnabled } val isSystemAudioCaptioningUiEnabled: StateFlow<Boolean> get() = repository.isSystemAudioCaptioningUiEnabled val isSystemAudioCaptioningUiEnabled: Flow<Boolean> = repository.captioningModel.filterNotNull().map { it.isSystemAudioCaptioningUiEnabled } suspend fun setIsSystemAudioCaptioningEnabled(enabled: Boolean) = suspend fun setIsSystemAudioCaptioningEnabled(enabled: Boolean) { repository.setIsSystemAudioCaptioningEnabled(enabled) } } packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java +7 −0 Original line number Diff line number Diff line Loading @@ -202,6 +202,13 @@ public class FrameworkServicesModule { return context.getSystemService(CaptioningManager.class); } @Provides @Singleton static UserScopedService<CaptioningManager> provideUserScopedCaptioningManager( Context context) { return new UserScopedServiceImpl<>(context, CaptioningManager.class); } /** */ @Provides @Singleton Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/CaptioningRepositoryTest.kt +27 −25 Original line number Diff line number Diff line Loading @@ -20,11 +20,15 @@ import android.view.accessibility.CaptioningManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectValues import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.userRepository import com.android.systemui.user.utils.FakeUserScopedService import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before Loading @@ -39,10 +43,11 @@ import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @Suppress("UnspecifiedRegisterReceiverFlag") @RunWith(AndroidJUnit4::class) class CaptioningRepositoryTest : SysuiTestCase() { private val kosmos = testKosmos() @Captor private lateinit var listenerCaptor: ArgumentCaptor<CaptioningManager.CaptioningChangeListener> Loading @@ -50,34 +55,33 @@ class CaptioningRepositoryTest : SysuiTestCase() { private lateinit var underTest: CaptioningRepository private val testScope = TestScope() @Before fun setup() { MockitoAnnotations.initMocks(this) underTest = with(kosmos) { CaptioningRepositoryImpl( captioningManager, FakeUserScopedService(captioningManager), userRepository, testScope.testScheduler, testScope.backgroundScope applicationCoroutineScope, ) } } @Test fun isSystemAudioCaptioningEnabled_change_repositoryEmits() { testScope.runTest { `when`(captioningManager.isEnabled).thenReturn(false) val isSystemAudioCaptioningEnabled = mutableListOf<Boolean>() underTest.isSystemAudioCaptioningEnabled .onEach { isSystemAudioCaptioningEnabled.add(it) } .launchIn(backgroundScope) kosmos.testScope.runTest { `when`(captioningManager.isSystemAudioCaptioningEnabled).thenReturn(false) val models by collectValues(underTest.captioningModel.filterNotNull()) runCurrent() `when`(captioningManager.isSystemAudioCaptioningEnabled).thenReturn(true) triggerOnSystemAudioCaptioningChange() runCurrent() assertThat(isSystemAudioCaptioningEnabled) assertThat(models.map { it.isSystemAudioCaptioningEnabled }) .containsExactlyElementsIn(listOf(false, true)) .inOrder() } Loading @@ -85,18 +89,16 @@ class CaptioningRepositoryTest : SysuiTestCase() { @Test fun isSystemAudioCaptioningUiEnabled_change_repositoryEmits() { testScope.runTest { `when`(captioningManager.isSystemAudioCaptioningUiEnabled).thenReturn(false) val isSystemAudioCaptioningUiEnabled = mutableListOf<Boolean>() underTest.isSystemAudioCaptioningUiEnabled .onEach { isSystemAudioCaptioningUiEnabled.add(it) } .launchIn(backgroundScope) kosmos.testScope.runTest { `when`(captioningManager.isEnabled).thenReturn(false) val models by collectValues(underTest.captioningModel.filterNotNull()) runCurrent() `when`(captioningManager.isSystemAudioCaptioningUiEnabled).thenReturn(true) triggerSystemAudioCaptioningUiChange() runCurrent() assertThat(isSystemAudioCaptioningUiEnabled) assertThat(models.map { it.isSystemAudioCaptioningUiEnabled }) .containsExactlyElementsIn(listOf(false, true)) .inOrder() } Loading
packages/SystemUI/src/com/android/systemui/accessibility/data/model/CaptioningModel.kt 0 → 100644 +22 −0 Original line number Diff line number Diff line /* * 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.accessibility.data.model data class CaptioningModel( val isSystemAudioCaptioningUiEnabled: Boolean, val isSystemAudioCaptioningEnabled: Boolean, )
packages/SystemUI/src/com/android/systemui/accessibility/data/repository/CaptioningRepository.kt +59 −67 Original line number Diff line number Diff line Loading @@ -16,98 +16,90 @@ package com.android.systemui.accessibility.data.repository import android.annotation.SuppressLint import android.view.accessibility.CaptioningManager import com.android.systemui.accessibility.data.model.CaptioningModel import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.user.utils.UserScopedService import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import javax.inject.Inject import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.ProducerScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext interface CaptioningRepository { /** The system audio caption enabled state. */ val isSystemAudioCaptioningEnabled: StateFlow<Boolean> /** Current state of Live Captions. */ val captioningModel: StateFlow<CaptioningModel?> /** The system audio caption UI enabled state. */ val isSystemAudioCaptioningUiEnabled: StateFlow<Boolean> /** Sets [isSystemAudioCaptioningEnabled]. */ /** Sets [CaptioningModel.isSystemAudioCaptioningEnabled]. */ suspend fun setIsSystemAudioCaptioningEnabled(isEnabled: Boolean) } class CaptioningRepositoryImpl( private val captioningManager: CaptioningManager, private val backgroundCoroutineContext: CoroutineContext, coroutineScope: CoroutineScope, @OptIn(ExperimentalCoroutinesApi::class) class CaptioningRepositoryImpl @Inject constructor( private val userScopedCaptioningManagerProvider: UserScopedService<CaptioningManager>, userRepository: UserRepository, @Background private val backgroundCoroutineContext: CoroutineContext, @Application coroutineScope: CoroutineScope, ) : CaptioningRepository { private val captioningChanges: SharedFlow<CaptioningChange> = callbackFlow { val listener = CaptioningChangeProducingListener(this) captioningManager.addCaptioningChangeListener(listener) awaitClose { captioningManager.removeCaptioningChangeListener(listener) } } .shareIn(coroutineScope, SharingStarted.WhileSubscribed(), replay = 0) @SuppressLint("NonInjectedService") // this uses user-aware context private val captioningManager: StateFlow<CaptioningManager?> = userRepository.selectedUser .map { userScopedCaptioningManagerProvider.forUser(it.userInfo.userHandle) } .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), null) override val isSystemAudioCaptioningEnabled: StateFlow<Boolean> = captioningChanges .filterIsInstance(CaptioningChange.IsSystemAudioCaptioningEnabled::class) .map { it.isEnabled } .onStart { emit(captioningManager.isSystemAudioCaptioningEnabled) } .stateIn( coroutineScope, SharingStarted.WhileSubscribed(), captioningManager.isSystemAudioCaptioningEnabled, ) override val isSystemAudioCaptioningUiEnabled: StateFlow<Boolean> = captioningChanges .filterIsInstance(CaptioningChange.IsSystemUICaptioningEnabled::class) .map { it.isEnabled } .onStart { emit(captioningManager.isSystemAudioCaptioningUiEnabled) } .stateIn( coroutineScope, SharingStarted.WhileSubscribed(), captioningManager.isSystemAudioCaptioningUiEnabled, ) override val captioningModel: StateFlow<CaptioningModel?> = captioningManager .filterNotNull() .flatMapLatest { it.captioningModel() } .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), null) override suspend fun setIsSystemAudioCaptioningEnabled(isEnabled: Boolean) { withContext(backgroundCoroutineContext) { captioningManager.isSystemAudioCaptioningEnabled = isEnabled captioningManager.value?.isSystemAudioCaptioningEnabled = isEnabled } } private sealed interface CaptioningChange { data class IsSystemAudioCaptioningEnabled(val isEnabled: Boolean) : CaptioningChange data class IsSystemUICaptioningEnabled(val isEnabled: Boolean) : CaptioningChange } private class CaptioningChangeProducingListener( private val scope: ProducerScope<CaptioningChange> ) : CaptioningManager.CaptioningChangeListener() { private fun CaptioningManager.captioningModel(): Flow<CaptioningModel> { return conflatedCallbackFlow { val listener = object : CaptioningManager.CaptioningChangeListener() { override fun onSystemAudioCaptioningChanged(enabled: Boolean) { emitChange(CaptioningChange.IsSystemAudioCaptioningEnabled(enabled)) trySend(Unit) } override fun onSystemAudioCaptioningUiChanged(enabled: Boolean) { emitChange(CaptioningChange.IsSystemUICaptioningEnabled(enabled)) trySend(Unit) } private fun emitChange(change: CaptioningChange) { scope.launch { scope.send(change) } } addCaptioningChangeListener(listener) awaitClose { removeCaptioningChangeListener(listener) } } .onStart { emit(Unit) } .map { CaptioningModel( isSystemAudioCaptioningEnabled = isSystemAudioCaptioningEnabled, isSystemAudioCaptioningUiEnabled = isSystemAudioCaptioningUiEnabled, ) } .flowOn(backgroundCoroutineContext) } }
packages/SystemUI/src/com/android/systemui/accessibility/domain/interactor/CaptioningInteractor.kt +13 −7 Original line number Diff line number Diff line Loading @@ -17,16 +17,22 @@ package com.android.systemui.accessibility.domain.interactor import com.android.systemui.accessibility.data.repository.CaptioningRepository import kotlinx.coroutines.flow.StateFlow import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map class CaptioningInteractor(private val repository: CaptioningRepository) { @SysUISingleton class CaptioningInteractor @Inject constructor(private val repository: CaptioningRepository) { val isSystemAudioCaptioningEnabled: StateFlow<Boolean> get() = repository.isSystemAudioCaptioningEnabled val isSystemAudioCaptioningEnabled: Flow<Boolean> = repository.captioningModel.filterNotNull().map { it.isSystemAudioCaptioningEnabled } val isSystemAudioCaptioningUiEnabled: StateFlow<Boolean> get() = repository.isSystemAudioCaptioningUiEnabled val isSystemAudioCaptioningUiEnabled: Flow<Boolean> = repository.captioningModel.filterNotNull().map { it.isSystemAudioCaptioningUiEnabled } suspend fun setIsSystemAudioCaptioningEnabled(enabled: Boolean) = suspend fun setIsSystemAudioCaptioningEnabled(enabled: Boolean) { repository.setIsSystemAudioCaptioningEnabled(enabled) } }
packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java +7 −0 Original line number Diff line number Diff line Loading @@ -202,6 +202,13 @@ public class FrameworkServicesModule { return context.getSystemService(CaptioningManager.class); } @Provides @Singleton static UserScopedService<CaptioningManager> provideUserScopedCaptioningManager( Context context) { return new UserScopedServiceImpl<>(context, CaptioningManager.class); } /** */ @Provides @Singleton Loading