Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt +10 −1 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay import com.android.systemui.privacy.PrivacyItemController import com.android.systemui.statusbar.featurepods.vc.domain.interactor.AvControlsChipInteractor import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.util.mockito.any import com.android.systemui.util.time.FakeSystemClock Loading Loading @@ -50,9 +51,11 @@ class SystemEventCoordinatorTest : SysuiTestCase() { @Mock lateinit var batteryController: BatteryController @Mock lateinit var privacyController: PrivacyItemController @Mock lateinit var avControlsChipInteractor: AvControlsChipInteractor @Mock lateinit var scheduler: SystemStatusAnimationScheduler private lateinit var systemEventCoordinator: SystemEventCoordinator @Before fun setup() { MockitoAnnotations.initMocks(this) Loading @@ -61,9 +64,10 @@ class SystemEventCoordinatorTest : SysuiTestCase() { fakeSystemClock, batteryController, privacyController, avControlsChipInteractor, context, TestScope(UnconfinedTestDispatcher()), connectedDisplayInteractor connectedDisplayInteractor, ) .apply { attachScheduler(scheduler) } } Loading Loading @@ -97,13 +101,18 @@ class SystemEventCoordinatorTest : SysuiTestCase() { class FakeConnectedDisplayInteractor : ConnectedDisplayInteractor { private val flow = MutableSharedFlow<Unit>() suspend fun emit() = flow.emit(Unit) override val connectedDisplayState: Flow<ConnectedDisplayInteractor.State> get() = MutableSharedFlow<ConnectedDisplayInteractor.State>() override val connectedDisplayAddition: Flow<Unit> get() = flow override val pendingDisplay: Flow<PendingDisplay?> get() = MutableSharedFlow<PendingDisplay>() override val concurrentDisplaysInProgress: Flow<Boolean> get() = TODO("Not yet implemented") } Loading packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt +78 −67 Original line number Diff line number Diff line Loading @@ -20,14 +20,14 @@ import android.annotation.IntRange import android.content.Context import android.provider.DeviceConfig import android.provider.DeviceConfig.NAMESPACE_PRIVACY import com.android.systemui.res.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State import com.android.systemui.privacy.PrivacyChipBuilder import com.android.systemui.privacy.PrivacyItem import com.android.systemui.privacy.PrivacyItemController import com.android.systemui.res.R import com.android.systemui.statusbar.featurepods.vc.domain.interactor.AvControlsChipInteractor import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.util.time.SystemClock import javax.inject.Inject Loading @@ -47,12 +47,12 @@ constructor( private val systemClock: SystemClock, private val batteryController: BatteryController, private val privacyController: PrivacyItemController, private val avControlsChipInteractor: AvControlsChipInteractor, private val context: Context, @Application private val appScope: CoroutineScope, connectedDisplayInteractor: ConnectedDisplayInteractor connectedDisplayInteractor: ConnectedDisplayInteractor, ) { private val onDisplayConnectedFlow = connectedDisplayInteractor.connectedDisplayAddition private val onDisplayConnectedFlow = connectedDisplayInteractor.connectedDisplayAddition private var connectedDisplayCollectionJob: Job? = null private lateinit var scheduler: SystemStatusAnimationScheduler Loading Loading @@ -82,18 +82,21 @@ constructor( } fun notifyPrivacyItemsChanged(showAnimation: Boolean = true) { val event = PrivacyEvent(showAnimation) // Disabling animation in case that the privacy indicator is implemented as a status bar // chip val shouldShowAnimation = showAnimation && !avControlsChipInteractor.isEnabled.value val event = PrivacyEvent(shouldShowAnimation) event.privacyItems = privacyStateListener.currentPrivacyItems event.contentDescription = run { val items = PrivacyChipBuilder(context, event.privacyItems).joinTypes() context.getString( R.string.ongoing_privacy_chip_content_multiple_apps, items) context.getString(R.string.ongoing_privacy_chip_content_multiple_apps, items) } scheduler.onStatusEvent(event) } private fun startConnectedDisplayCollection() { val connectedDisplayEvent = ConnectedDisplayEvent().apply { val connectedDisplayEvent = ConnectedDisplayEvent().apply { contentDescription = context.getString(R.string.connected_display_icon_desc) } connectedDisplayCollectionJob = Loading @@ -102,9 +105,11 @@ constructor( .launchIn(appScope) } private val batteryStateListener = object : BatteryController.BatteryStateChangeCallback { private val batteryStateListener = object : BatteryController.BatteryStateChangeCallback { private var plugged = false private var stateKnown = false override fun onBatteryLevelChanged(level: Int, pluggedIn: Boolean, charging: Boolean) { if (!stateKnown) { stateKnown = true Loading @@ -125,7 +130,8 @@ constructor( } } private val privacyStateListener = object : PrivacyItemController.Callback { private val privacyStateListener = object : PrivacyItemController.Callback { var currentPrivacyItems = listOf<PrivacyItem>() var previousPrivacyItems = listOf<PrivacyItem>() var timeLastEmpty = systemClock.elapsedRealtime() Loading @@ -146,7 +152,8 @@ constructor( if (currentPrivacyItems.isEmpty()) { notifyPrivacyItemsEmpty() } else { val showAnimation = isChipAnimationEnabled() && val showAnimation = isChipAnimationEnabled() && (!uniqueItemsMatch(currentPrivacyItems, previousPrivacyItems) || systemClock.elapsedRealtime() - timeLastEmpty >= DEBOUNCE_TIME) notifyPrivacyItemsChanged(showAnimation) Loading @@ -162,7 +169,11 @@ constructor( private fun isChipAnimationEnabled(): Boolean { val defaultValue = context.resources.getBoolean(R.bool.config_enablePrivacyChipAnimation) return DeviceConfig.getBoolean(NAMESPACE_PRIVACY, CHIP_ANIMATION_ENABLED, defaultValue) return DeviceConfig.getBoolean( NAMESPACE_PRIVACY, CHIP_ANIMATION_ENABLED, defaultValue, ) } } } Loading packages/SystemUI/src/com/android/systemui/statusbar/featurepods/av/domain/interactor/AvControlsChipInteractor.kt +4 −3 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import com.android.systemui.statusbar.featurepods.vc.shared.model.AvControlsChip import com.android.systemui.statusbar.featurepods.vc.shared.model.SensorActivityModel import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine /** Loading @@ -37,8 +38,8 @@ import kotlinx.coroutines.flow.combine */ @SysUISingleton class AvControlsChipInteractor @Inject constructor(privacyChipRepository: PrivacyChipRepository) { private val isEnabled = MutableStateFlow(false) private val _isEnabled = MutableStateFlow(false) val isEnabled = _isEnabled.asStateFlow() val model = combine(isEnabled, privacyChipRepository.privacyItems) { isEnabled, privacyItems -> if (isEnabled) createModel(privacyItems) Loading Loading @@ -75,6 +76,6 @@ class AvControlsChipInteractor @Inject constructor(privacyChipRepository: Privac * factors should initialize the interactor. This must be called from a CoreStartable. */ fun initialize() { isEnabled.value = Flags.expandedPrivacyIndicatorsOnLargeScreen() _isEnabled.value = Flags.expandedPrivacyIndicatorsOnLargeScreen() } } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt +10 −1 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay import com.android.systemui.privacy.PrivacyItemController import com.android.systemui.statusbar.featurepods.vc.domain.interactor.AvControlsChipInteractor import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.util.mockito.any import com.android.systemui.util.time.FakeSystemClock Loading Loading @@ -50,9 +51,11 @@ class SystemEventCoordinatorTest : SysuiTestCase() { @Mock lateinit var batteryController: BatteryController @Mock lateinit var privacyController: PrivacyItemController @Mock lateinit var avControlsChipInteractor: AvControlsChipInteractor @Mock lateinit var scheduler: SystemStatusAnimationScheduler private lateinit var systemEventCoordinator: SystemEventCoordinator @Before fun setup() { MockitoAnnotations.initMocks(this) Loading @@ -61,9 +64,10 @@ class SystemEventCoordinatorTest : SysuiTestCase() { fakeSystemClock, batteryController, privacyController, avControlsChipInteractor, context, TestScope(UnconfinedTestDispatcher()), connectedDisplayInteractor connectedDisplayInteractor, ) .apply { attachScheduler(scheduler) } } Loading Loading @@ -97,13 +101,18 @@ class SystemEventCoordinatorTest : SysuiTestCase() { class FakeConnectedDisplayInteractor : ConnectedDisplayInteractor { private val flow = MutableSharedFlow<Unit>() suspend fun emit() = flow.emit(Unit) override val connectedDisplayState: Flow<ConnectedDisplayInteractor.State> get() = MutableSharedFlow<ConnectedDisplayInteractor.State>() override val connectedDisplayAddition: Flow<Unit> get() = flow override val pendingDisplay: Flow<PendingDisplay?> get() = MutableSharedFlow<PendingDisplay>() override val concurrentDisplaysInProgress: Flow<Boolean> get() = TODO("Not yet implemented") } Loading
packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt +78 −67 Original line number Diff line number Diff line Loading @@ -20,14 +20,14 @@ import android.annotation.IntRange import android.content.Context import android.provider.DeviceConfig import android.provider.DeviceConfig.NAMESPACE_PRIVACY import com.android.systemui.res.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State import com.android.systemui.privacy.PrivacyChipBuilder import com.android.systemui.privacy.PrivacyItem import com.android.systemui.privacy.PrivacyItemController import com.android.systemui.res.R import com.android.systemui.statusbar.featurepods.vc.domain.interactor.AvControlsChipInteractor import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.util.time.SystemClock import javax.inject.Inject Loading @@ -47,12 +47,12 @@ constructor( private val systemClock: SystemClock, private val batteryController: BatteryController, private val privacyController: PrivacyItemController, private val avControlsChipInteractor: AvControlsChipInteractor, private val context: Context, @Application private val appScope: CoroutineScope, connectedDisplayInteractor: ConnectedDisplayInteractor connectedDisplayInteractor: ConnectedDisplayInteractor, ) { private val onDisplayConnectedFlow = connectedDisplayInteractor.connectedDisplayAddition private val onDisplayConnectedFlow = connectedDisplayInteractor.connectedDisplayAddition private var connectedDisplayCollectionJob: Job? = null private lateinit var scheduler: SystemStatusAnimationScheduler Loading Loading @@ -82,18 +82,21 @@ constructor( } fun notifyPrivacyItemsChanged(showAnimation: Boolean = true) { val event = PrivacyEvent(showAnimation) // Disabling animation in case that the privacy indicator is implemented as a status bar // chip val shouldShowAnimation = showAnimation && !avControlsChipInteractor.isEnabled.value val event = PrivacyEvent(shouldShowAnimation) event.privacyItems = privacyStateListener.currentPrivacyItems event.contentDescription = run { val items = PrivacyChipBuilder(context, event.privacyItems).joinTypes() context.getString( R.string.ongoing_privacy_chip_content_multiple_apps, items) context.getString(R.string.ongoing_privacy_chip_content_multiple_apps, items) } scheduler.onStatusEvent(event) } private fun startConnectedDisplayCollection() { val connectedDisplayEvent = ConnectedDisplayEvent().apply { val connectedDisplayEvent = ConnectedDisplayEvent().apply { contentDescription = context.getString(R.string.connected_display_icon_desc) } connectedDisplayCollectionJob = Loading @@ -102,9 +105,11 @@ constructor( .launchIn(appScope) } private val batteryStateListener = object : BatteryController.BatteryStateChangeCallback { private val batteryStateListener = object : BatteryController.BatteryStateChangeCallback { private var plugged = false private var stateKnown = false override fun onBatteryLevelChanged(level: Int, pluggedIn: Boolean, charging: Boolean) { if (!stateKnown) { stateKnown = true Loading @@ -125,7 +130,8 @@ constructor( } } private val privacyStateListener = object : PrivacyItemController.Callback { private val privacyStateListener = object : PrivacyItemController.Callback { var currentPrivacyItems = listOf<PrivacyItem>() var previousPrivacyItems = listOf<PrivacyItem>() var timeLastEmpty = systemClock.elapsedRealtime() Loading @@ -146,7 +152,8 @@ constructor( if (currentPrivacyItems.isEmpty()) { notifyPrivacyItemsEmpty() } else { val showAnimation = isChipAnimationEnabled() && val showAnimation = isChipAnimationEnabled() && (!uniqueItemsMatch(currentPrivacyItems, previousPrivacyItems) || systemClock.elapsedRealtime() - timeLastEmpty >= DEBOUNCE_TIME) notifyPrivacyItemsChanged(showAnimation) Loading @@ -162,7 +169,11 @@ constructor( private fun isChipAnimationEnabled(): Boolean { val defaultValue = context.resources.getBoolean(R.bool.config_enablePrivacyChipAnimation) return DeviceConfig.getBoolean(NAMESPACE_PRIVACY, CHIP_ANIMATION_ENABLED, defaultValue) return DeviceConfig.getBoolean( NAMESPACE_PRIVACY, CHIP_ANIMATION_ENABLED, defaultValue, ) } } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/featurepods/av/domain/interactor/AvControlsChipInteractor.kt +4 −3 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import com.android.systemui.statusbar.featurepods.vc.shared.model.AvControlsChip import com.android.systemui.statusbar.featurepods.vc.shared.model.SensorActivityModel import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine /** Loading @@ -37,8 +38,8 @@ import kotlinx.coroutines.flow.combine */ @SysUISingleton class AvControlsChipInteractor @Inject constructor(privacyChipRepository: PrivacyChipRepository) { private val isEnabled = MutableStateFlow(false) private val _isEnabled = MutableStateFlow(false) val isEnabled = _isEnabled.asStateFlow() val model = combine(isEnabled, privacyChipRepository.privacyItems) { isEnabled, privacyItems -> if (isEnabled) createModel(privacyItems) Loading Loading @@ -75,6 +76,6 @@ class AvControlsChipInteractor @Inject constructor(privacyChipRepository: Privac * factors should initialize the interactor. This must be called from a CoreStartable. */ fun initialize() { isEnabled.value = Flags.expandedPrivacyIndicatorsOnLargeScreen() _isEnabled.value = Flags.expandedPrivacyIndicatorsOnLargeScreen() } }