Loading packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt +4 −0 Original line number Original line Diff line number Diff line Loading @@ -74,6 +74,10 @@ class FakeZenModeRepository : ZenModeRepository { mutableModesFlow.value = mutableModesFlow.value.filter { it.id != id } mutableModesFlow.value = mutableModesFlow.value.filter { it.id != id } } } fun replaceMode(modeId: String, mode: ZenMode) { mutableModesFlow.value = (mutableModesFlow.value.filter { it.id != modeId }) + mode } fun getMode(id: String): ZenMode? { fun getMode(id: String): ZenMode? { return mutableModesFlow.value.find { it.id == id } return mutableModesFlow.value.find { it.id == id } } } Loading packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +59 −25 Original line number Original line Diff line number Diff line Loading @@ -15,12 +15,15 @@ */ */ package com.android.keyguard package com.android.keyguard import android.app.NotificationManager.zenModeFromInterruptionFilter import android.content.BroadcastReceiver import android.content.BroadcastReceiver import android.content.Context import android.content.Context import android.content.Intent import android.content.Intent import android.content.IntentFilter import android.content.IntentFilter import android.content.res.Resources import android.content.res.Resources import android.os.Trace import android.os.Trace import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS import android.provider.Settings.Global.ZEN_MODE_OFF import android.text.format.DateFormat import android.text.format.DateFormat import android.util.Log import android.util.Log import android.util.TypedValue import android.util.TypedValue Loading Loading @@ -49,6 +52,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.log.core.Logger import com.android.systemui.log.core.Logger import com.android.systemui.modes.shared.ModesUi import com.android.systemui.plugins.clocks.AlarmData import com.android.systemui.plugins.clocks.AlarmData import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockFaceController import com.android.systemui.plugins.clocks.ClockFaceController Loading @@ -63,6 +67,7 @@ import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ZenModeController import com.android.systemui.statusbar.policy.ZenModeController import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.DelayableExecutor import java.util.Locale import java.util.Locale import java.util.TimeZone import java.util.TimeZone Loading Loading @@ -97,12 +102,13 @@ constructor( private val clockBuffers: ClockMessageBuffers, private val clockBuffers: ClockMessageBuffers, private val featureFlags: FeatureFlagsClassic, private val featureFlags: FeatureFlagsClassic, private val zenModeController: ZenModeController, private val zenModeController: ZenModeController, private val zenModeInteractor: ZenModeInteractor, ) { ) { var loggers = var loggers = listOf( listOf( clockBuffers.infraMessageBuffer, clockBuffers.infraMessageBuffer, clockBuffers.smallClockMessageBuffer, clockBuffers.smallClockMessageBuffer, clockBuffers.largeClockMessageBuffer clockBuffers.largeClockMessageBuffer, ) ) .map { Logger(it, TAG) } .map { Logger(it, TAG) } Loading Loading @@ -146,7 +152,7 @@ constructor( bgExecutor, bgExecutor, regionSamplingEnabled, regionSamplingEnabled, isLockscreen = true, isLockscreen = true, ::updateColors ::updateColors, ) ) .apply { startRegionSampler() } .apply { startRegionSampler() } Loading @@ -157,7 +163,7 @@ constructor( bgExecutor, bgExecutor, regionSamplingEnabled, regionSamplingEnabled, isLockscreen = true, isLockscreen = true, ::updateColors ::updateColors, ) ) .apply { startRegionSampler() } .apply { startRegionSampler() } Loading Loading @@ -271,7 +277,7 @@ constructor( bgExecutor: Executor?, bgExecutor: Executor?, regionSamplingEnabled: Boolean, regionSamplingEnabled: Boolean, isLockscreen: Boolean, isLockscreen: Boolean, updateColors: () -> Unit updateColors: () -> Unit, ): RegionSampler { ): RegionSampler { return RegionSampler( return RegionSampler( sampledView, sampledView, Loading Loading @@ -384,23 +390,29 @@ constructor( } } } } @VisibleForTesting internal fun listenForDnd(scope: CoroutineScope): Job { ModesUi.assertInNewMode() return scope.launch { zenModeInteractor.dndMode.collect { val zenMode = if (it != null && it.isActive) zenModeFromInterruptionFilter( it.interruptionFilter, ZEN_MODE_IMPORTANT_INTERRUPTIONS, ) else ZEN_MODE_OFF handleZenMode(zenMode) } } } private val zenModeCallback = private val zenModeCallback = object : ZenModeController.Callback { object : ZenModeController.Callback { override fun onZenChanged(zen: Int) { override fun onZenChanged(zen: Int) { var mode = ZenMode.fromInt(zen) if (!ModesUi.isEnabled) { if (mode == null) { handleZenMode(zen) Log.e(TAG, "Failed to get zen mode from int: $zen") return } zenData = ZenData( mode, if (mode == ZenMode.OFF) SysuiR.string::dnd_is_off.name else SysuiR.string::dnd_is_on.name ) .also { data -> mainExecutor.execute { clock?.run { events.onZenDataChanged(data) } } } } } } Loading @@ -409,7 +421,7 @@ constructor( alarmData = alarmData = AlarmData( AlarmData( if (nextAlarmMillis > 0) nextAlarmMillis else null, if (nextAlarmMillis > 0) nextAlarmMillis else null, SysuiR.string::status_bar_alarm.name SysuiR.string::status_bar_alarm.name, ) ) .also { data -> .also { data -> mainExecutor.execute { clock?.run { events.onAlarmDataChanged(data) } } mainExecutor.execute { clock?.run { events.onAlarmDataChanged(data) } } Loading @@ -417,6 +429,24 @@ constructor( } } } } private fun handleZenMode(zen: Int) { val mode = ZenMode.fromInt(zen) if (mode == null) { Log.e(TAG, "Failed to get zen mode from int: $zen") return } zenData = ZenData( mode, if (mode == ZenMode.OFF) SysuiR.string::dnd_is_off.name else SysuiR.string::dnd_is_on.name, ) .also { data -> mainExecutor.execute { clock?.run { events.onZenDataChanged(data) } } } } fun registerListeners(parent: View) { fun registerListeners(parent: View) { if (isRegistered) { if (isRegistered) { return return Loading @@ -424,7 +454,7 @@ constructor( isRegistered = true isRegistered = true broadcastDispatcher.registerReceiver( broadcastDispatcher.registerReceiver( localeBroadcastReceiver, localeBroadcastReceiver, IntentFilter(Intent.ACTION_LOCALE_CHANGED) IntentFilter(Intent.ACTION_LOCALE_CHANGED), ) ) configurationController.addCallback(configListener) configurationController.addCallback(configListener) batteryController.addCallback(batteryCallback) batteryController.addCallback(batteryCallback) Loading @@ -434,6 +464,9 @@ constructor( parent.repeatWhenAttached { parent.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { repeatOnLifecycle(Lifecycle.State.CREATED) { listenForDozing(this) listenForDozing(this) if (ModesUi.isEnabled) { listenForDnd(this) } if (MigrateClocksToBlueprint.isEnabled) { if (MigrateClocksToBlueprint.isEnabled) { listenForDozeAmountTransition(this) listenForDozeAmountTransition(this) listenForAnyStateToAodTransition(this) listenForAnyStateToAodTransition(this) Loading @@ -449,7 +482,9 @@ constructor( bgExecutor.execute { bgExecutor.execute { // Query ZenMode data // Query ZenMode data if (!ModesUi.isEnabled) { zenModeCallback.onZenChanged(zenModeController.zen) zenModeCallback.onZenChanged(zenModeController.zen) } zenModeCallback.onNextAlarmChanged() zenModeCallback.onNextAlarmChanged() } } } } Loading Loading @@ -605,10 +640,9 @@ constructor( @VisibleForTesting @VisibleForTesting internal fun listenForDozing(scope: CoroutineScope): Job { internal fun listenForDozing(scope: CoroutineScope): Job { return scope.launch { return scope.launch { combine( combine(keyguardInteractor.dozeAmount, keyguardInteractor.isDozing) { keyguardInteractor.dozeAmount, localDozeAmount, keyguardInteractor.isDozing, localIsDozing -> ) { localDozeAmount, localIsDozing -> localDozeAmount > dozeAmount || localIsDozing localDozeAmount > dozeAmount || localIsDozing } } .collect { localIsDozing -> isDozing = localIsDozing } .collect { localIsDozing -> isDozing = localIsDozing } Loading packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +95 −27 Original line number Original line Diff line number Diff line Loading @@ -17,11 +17,16 @@ package com.android.keyguard import android.content.BroadcastReceiver import android.content.BroadcastReceiver import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.provider.Settings import android.view.View import android.view.View import android.view.ViewTreeObserver import android.view.ViewTreeObserver import android.widget.FrameLayout import android.widget.FrameLayout import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest import com.android.settingslib.notification.modes.TestModeBuilder.MANUAL_DND_ACTIVE import com.android.settingslib.notification.modes.TestModeBuilder.MANUAL_DND_INACTIVE import com.android.systemui.Flags as AConfigFlags import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.flags.Flags import com.android.systemui.flags.Flags Loading @@ -36,6 +41,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope import com.android.systemui.log.core.LogLevel import com.android.systemui.log.core.LogLevel import com.android.systemui.log.core.LogcatOnlyMessageBuffer import com.android.systemui.log.core.LogcatOnlyMessageBuffer import com.android.systemui.plugins.clocks.ClockAnimations import com.android.systemui.plugins.clocks.ClockAnimations Loading @@ -46,9 +52,15 @@ import com.android.systemui.plugins.clocks.ClockFaceController import com.android.systemui.plugins.clocks.ClockFaceEvents import com.android.systemui.plugins.clocks.ClockFaceEvents import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockTickRate import com.android.systemui.plugins.clocks.ClockTickRate import com.android.systemui.plugins.clocks.ZenData import com.android.systemui.plugins.clocks.ZenData.ZenMode import com.android.systemui.res.R import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ZenModeController import com.android.systemui.statusbar.policy.ZenModeController import com.android.systemui.statusbar.policy.data.repository.fakeZenModeRepository import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor import com.android.systemui.testKosmos import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.argumentCaptor Loading @@ -57,9 +69,12 @@ import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock import java.util.TimeZone import java.util.TimeZone import java.util.concurrent.Executor import java.util.concurrent.Executor import java.util.concurrent.TimeUnit import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import kotlinx.coroutines.yield import kotlinx.coroutines.yield import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Before Loading @@ -73,15 +88,26 @@ import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit import com.android.systemui.Flags as AConfigFlags import org.mockito.Mockito.`when` as whenever import org.mockito.Mockito.`when` as whenever import org.mockito.junit.MockitoJUnit @RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class) @SmallTest @SmallTest @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) class ClockEventControllerTest : SysuiTestCase() { class ClockEventControllerTest : SysuiTestCase() { private val kosmos = testKosmos() private val zenModeRepository = kosmos.fakeZenModeRepository private val testScope = kosmos.testScope @JvmField @Rule val mockito = MockitoJUnit.rule() @JvmField @Rule val mockito = MockitoJUnit.rule() private val mainExecutor = ImmediateExecutor() private lateinit var repository: FakeKeyguardRepository private val messageBuffer = LogcatOnlyMessageBuffer(LogLevel.DEBUG) private val clockBuffers = ClockMessageBuffers(messageBuffer, messageBuffer, messageBuffer) private lateinit var underTest: ClockEventController @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher @Mock private lateinit var batteryController: BatteryController @Mock private lateinit var batteryController: BatteryController @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor Loading @@ -89,7 +115,6 @@ class ClockEventControllerTest : SysuiTestCase() { @Mock private lateinit var animations: ClockAnimations @Mock private lateinit var animations: ClockAnimations @Mock private lateinit var events: ClockEvents @Mock private lateinit var events: ClockEvents @Mock private lateinit var clock: ClockController @Mock private lateinit var clock: ClockController @Mock private lateinit var mainExecutor: DelayableExecutor @Mock private lateinit var bgExecutor: Executor @Mock private lateinit var bgExecutor: Executor @Mock private lateinit var smallClockController: ClockFaceController @Mock private lateinit var smallClockController: ClockFaceController @Mock private lateinit var smallClockView: View @Mock private lateinit var smallClockView: View Loading @@ -102,12 +127,10 @@ class ClockEventControllerTest : SysuiTestCase() { @Mock private lateinit var smallClockEvents: ClockFaceEvents @Mock private lateinit var smallClockEvents: ClockFaceEvents @Mock private lateinit var largeClockEvents: ClockFaceEvents @Mock private lateinit var largeClockEvents: ClockFaceEvents @Mock private lateinit var parentView: View @Mock private lateinit var parentView: View private lateinit var repository: FakeKeyguardRepository @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor private val messageBuffer = LogcatOnlyMessageBuffer(LogLevel.DEBUG) private val clockBuffers = ClockMessageBuffers(messageBuffer, messageBuffer, messageBuffer) private lateinit var underTest: ClockEventController @Mock private lateinit var zenModeController: ZenModeController @Mock private lateinit var zenModeController: ZenModeController private var zenModeControllerCallback: ZenModeController.Callback? = null @Before @Before fun setUp() { fun setUp() { Loading @@ -129,12 +152,11 @@ class ClockEventControllerTest : SysuiTestCase() { whenever(largeClockController.config) whenever(largeClockController.config) .thenReturn(ClockFaceConfig(tickRate = ClockTickRate.PER_MINUTE)) .thenReturn(ClockFaceConfig(tickRate = ClockTickRate.PER_MINUTE)) zenModeRepository.addMode(MANUAL_DND_INACTIVE) repository = FakeKeyguardRepository() repository = FakeKeyguardRepository() val withDeps = val withDeps = KeyguardInteractorFactory.create(repository = repository) KeyguardInteractorFactory.create( repository = repository, ) withDeps.featureFlags.apply { set(Flags.REGION_SAMPLING, false) } withDeps.featureFlags.apply { set(Flags.REGION_SAMPLING, false) } underTest = underTest = Loading @@ -151,7 +173,8 @@ class ClockEventControllerTest : SysuiTestCase() { bgExecutor, bgExecutor, clockBuffers, clockBuffers, withDeps.featureFlags, withDeps.featureFlags, zenModeController zenModeController, kosmos.zenModeInteractor, ) ) underTest.clock = clock underTest.clock = clock Loading @@ -161,6 +184,10 @@ class ClockEventControllerTest : SysuiTestCase() { repository.setIsDozing(true) repository.setIsDozing(true) repository.setDozeAmount(1f) repository.setDozeAmount(1f) } } val zenCallbackCaptor = argumentCaptor<ZenModeController.Callback>() verify(zenModeController).addCallback(zenCallbackCaptor.capture()) zenModeControllerCallback = zenCallbackCaptor.value } } @Test @Test Loading Loading @@ -349,17 +376,12 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForTransitionToAodFromGone_updatesClockDozeAmountToOne() = fun listenForTransitionToAodFromGone_updatesClockDozeAmountToOne() = runBlocking(IMMEDIATE) { runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) val transitionStep = MutableStateFlow(TransitionStep()) whenever(keyguardTransitionInteractor whenever(keyguardTransitionInteractor.transition(Edge.create(to = AOD))) .transition(Edge.create(to = AOD))) .thenReturn(transitionStep) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToAodTransition(this) val job = underTest.listenForAnyStateToAodTransition(this) transitionStep.value = transitionStep.value = TransitionStep( TransitionStep(from = GONE, to = AOD, transitionState = TransitionState.STARTED) from = GONE, to = AOD, transitionState = TransitionState.STARTED, ) yield() yield() verify(animations, times(2)).doze(1f) verify(animations, times(2)).doze(1f) Loading @@ -371,8 +393,7 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForTransitionToLSFromOccluded_updatesClockDozeAmountToZero() = fun listenForTransitionToLSFromOccluded_updatesClockDozeAmountToZero() = runBlocking(IMMEDIATE) { runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) val transitionStep = MutableStateFlow(TransitionStep()) whenever(keyguardTransitionInteractor whenever(keyguardTransitionInteractor.transition(Edge.create(to = LOCKSCREEN))) .transition(Edge.create(to = LOCKSCREEN))) .thenReturn(transitionStep) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToLockscreenTransition(this) val job = underTest.listenForAnyStateToLockscreenTransition(this) Loading @@ -393,8 +414,7 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForTransitionToAodFromLockscreen_neverUpdatesClockDozeAmount() = fun listenForTransitionToAodFromLockscreen_neverUpdatesClockDozeAmount() = runBlocking(IMMEDIATE) { runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) val transitionStep = MutableStateFlow(TransitionStep()) whenever(keyguardTransitionInteractor whenever(keyguardTransitionInteractor.transition(Edge.create(to = AOD))) .transition(Edge.create(to = AOD))) .thenReturn(transitionStep) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToAodTransition(this) val job = underTest.listenForAnyStateToAodTransition(this) Loading @@ -415,8 +435,7 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForAnyStateToLockscreenTransition_neverUpdatesClockDozeAmount() = fun listenForAnyStateToLockscreenTransition_neverUpdatesClockDozeAmount() = runBlocking(IMMEDIATE) { runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) val transitionStep = MutableStateFlow(TransitionStep()) whenever(keyguardTransitionInteractor whenever(keyguardTransitionInteractor.transition(Edge.create(to = LOCKSCREEN))) .transition(Edge.create(to = LOCKSCREEN))) .thenReturn(transitionStep) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToLockscreenTransition(this) val job = underTest.listenForAnyStateToLockscreenTransition(this) Loading @@ -437,8 +456,7 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForAnyStateToDozingTransition_UpdatesClockDozeAmountToOne() = fun listenForAnyStateToDozingTransition_UpdatesClockDozeAmountToOne() = runBlocking(IMMEDIATE) { runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) val transitionStep = MutableStateFlow(TransitionStep()) whenever(keyguardTransitionInteractor whenever(keyguardTransitionInteractor.transition(Edge.create(to = DOZING))) .transition(Edge.create(to = DOZING))) .thenReturn(transitionStep) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToDozingTransition(this) val job = underTest.listenForAnyStateToDozingTransition(this) Loading Loading @@ -498,7 +516,57 @@ class ClockEventControllerTest : SysuiTestCase() { verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any()) verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any()) } } @Test @EnableFlags(android.app.Flags.FLAG_MODES_UI) fun listenForDnd_onDndChange_updatesClockZenMode() = testScope.runTest { underTest.listenForDnd(testScope.backgroundScope) zenModeRepository.replaceMode(MANUAL_DND_INACTIVE.id, MANUAL_DND_ACTIVE) runCurrent() verify(events) .onZenDataChanged( eq(ZenData(ZenMode.IMPORTANT_INTERRUPTIONS, R.string::dnd_is_on.name)) ) zenModeRepository.replaceMode(MANUAL_DND_ACTIVE.id, MANUAL_DND_INACTIVE) runCurrent() verify(events).onZenDataChanged(eq(ZenData(ZenMode.OFF, R.string::dnd_is_off.name))) } @Test @DisableFlags(android.app.Flags.FLAG_MODES_UI) fun zenModeControllerCallback_onDndChange_updatesClockZenMode() = runBlocking(IMMEDIATE) { zenModeControllerCallback!!.onZenChanged( Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS ) verify(events) .onZenDataChanged( eq(ZenData(ZenMode.IMPORTANT_INTERRUPTIONS, R.string::dnd_is_on.name)) ) zenModeControllerCallback!!.onZenChanged(Settings.Global.ZEN_MODE_OFF) verify(events).onZenDataChanged(eq(ZenData(ZenMode.OFF, R.string::dnd_is_off.name))) } companion object { companion object { private val IMMEDIATE = Dispatchers.Main.immediate private val IMMEDIATE = Dispatchers.Main.immediate } } } } private class ImmediateExecutor : DelayableExecutor { override fun execute(runnable: Runnable) { runnable.run() } override fun executeDelayed(runnable: Runnable, delay: Long, unit: TimeUnit) = runnable.apply { run() } override fun executeAtTime(runnable: Runnable, uptimeMillis: Long, unit: TimeUnit) = runnable.apply { run() } } Loading
packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt +4 −0 Original line number Original line Diff line number Diff line Loading @@ -74,6 +74,10 @@ class FakeZenModeRepository : ZenModeRepository { mutableModesFlow.value = mutableModesFlow.value.filter { it.id != id } mutableModesFlow.value = mutableModesFlow.value.filter { it.id != id } } } fun replaceMode(modeId: String, mode: ZenMode) { mutableModesFlow.value = (mutableModesFlow.value.filter { it.id != modeId }) + mode } fun getMode(id: String): ZenMode? { fun getMode(id: String): ZenMode? { return mutableModesFlow.value.find { it.id == id } return mutableModesFlow.value.find { it.id == id } } } Loading
packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +59 −25 Original line number Original line Diff line number Diff line Loading @@ -15,12 +15,15 @@ */ */ package com.android.keyguard package com.android.keyguard import android.app.NotificationManager.zenModeFromInterruptionFilter import android.content.BroadcastReceiver import android.content.BroadcastReceiver import android.content.Context import android.content.Context import android.content.Intent import android.content.Intent import android.content.IntentFilter import android.content.IntentFilter import android.content.res.Resources import android.content.res.Resources import android.os.Trace import android.os.Trace import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS import android.provider.Settings.Global.ZEN_MODE_OFF import android.text.format.DateFormat import android.text.format.DateFormat import android.util.Log import android.util.Log import android.util.TypedValue import android.util.TypedValue Loading Loading @@ -49,6 +52,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.log.core.Logger import com.android.systemui.log.core.Logger import com.android.systemui.modes.shared.ModesUi import com.android.systemui.plugins.clocks.AlarmData import com.android.systemui.plugins.clocks.AlarmData import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockFaceController import com.android.systemui.plugins.clocks.ClockFaceController Loading @@ -63,6 +67,7 @@ import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ZenModeController import com.android.systemui.statusbar.policy.ZenModeController import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.DelayableExecutor import java.util.Locale import java.util.Locale import java.util.TimeZone import java.util.TimeZone Loading Loading @@ -97,12 +102,13 @@ constructor( private val clockBuffers: ClockMessageBuffers, private val clockBuffers: ClockMessageBuffers, private val featureFlags: FeatureFlagsClassic, private val featureFlags: FeatureFlagsClassic, private val zenModeController: ZenModeController, private val zenModeController: ZenModeController, private val zenModeInteractor: ZenModeInteractor, ) { ) { var loggers = var loggers = listOf( listOf( clockBuffers.infraMessageBuffer, clockBuffers.infraMessageBuffer, clockBuffers.smallClockMessageBuffer, clockBuffers.smallClockMessageBuffer, clockBuffers.largeClockMessageBuffer clockBuffers.largeClockMessageBuffer, ) ) .map { Logger(it, TAG) } .map { Logger(it, TAG) } Loading Loading @@ -146,7 +152,7 @@ constructor( bgExecutor, bgExecutor, regionSamplingEnabled, regionSamplingEnabled, isLockscreen = true, isLockscreen = true, ::updateColors ::updateColors, ) ) .apply { startRegionSampler() } .apply { startRegionSampler() } Loading @@ -157,7 +163,7 @@ constructor( bgExecutor, bgExecutor, regionSamplingEnabled, regionSamplingEnabled, isLockscreen = true, isLockscreen = true, ::updateColors ::updateColors, ) ) .apply { startRegionSampler() } .apply { startRegionSampler() } Loading Loading @@ -271,7 +277,7 @@ constructor( bgExecutor: Executor?, bgExecutor: Executor?, regionSamplingEnabled: Boolean, regionSamplingEnabled: Boolean, isLockscreen: Boolean, isLockscreen: Boolean, updateColors: () -> Unit updateColors: () -> Unit, ): RegionSampler { ): RegionSampler { return RegionSampler( return RegionSampler( sampledView, sampledView, Loading Loading @@ -384,23 +390,29 @@ constructor( } } } } @VisibleForTesting internal fun listenForDnd(scope: CoroutineScope): Job { ModesUi.assertInNewMode() return scope.launch { zenModeInteractor.dndMode.collect { val zenMode = if (it != null && it.isActive) zenModeFromInterruptionFilter( it.interruptionFilter, ZEN_MODE_IMPORTANT_INTERRUPTIONS, ) else ZEN_MODE_OFF handleZenMode(zenMode) } } } private val zenModeCallback = private val zenModeCallback = object : ZenModeController.Callback { object : ZenModeController.Callback { override fun onZenChanged(zen: Int) { override fun onZenChanged(zen: Int) { var mode = ZenMode.fromInt(zen) if (!ModesUi.isEnabled) { if (mode == null) { handleZenMode(zen) Log.e(TAG, "Failed to get zen mode from int: $zen") return } zenData = ZenData( mode, if (mode == ZenMode.OFF) SysuiR.string::dnd_is_off.name else SysuiR.string::dnd_is_on.name ) .also { data -> mainExecutor.execute { clock?.run { events.onZenDataChanged(data) } } } } } } Loading @@ -409,7 +421,7 @@ constructor( alarmData = alarmData = AlarmData( AlarmData( if (nextAlarmMillis > 0) nextAlarmMillis else null, if (nextAlarmMillis > 0) nextAlarmMillis else null, SysuiR.string::status_bar_alarm.name SysuiR.string::status_bar_alarm.name, ) ) .also { data -> .also { data -> mainExecutor.execute { clock?.run { events.onAlarmDataChanged(data) } } mainExecutor.execute { clock?.run { events.onAlarmDataChanged(data) } } Loading @@ -417,6 +429,24 @@ constructor( } } } } private fun handleZenMode(zen: Int) { val mode = ZenMode.fromInt(zen) if (mode == null) { Log.e(TAG, "Failed to get zen mode from int: $zen") return } zenData = ZenData( mode, if (mode == ZenMode.OFF) SysuiR.string::dnd_is_off.name else SysuiR.string::dnd_is_on.name, ) .also { data -> mainExecutor.execute { clock?.run { events.onZenDataChanged(data) } } } } fun registerListeners(parent: View) { fun registerListeners(parent: View) { if (isRegistered) { if (isRegistered) { return return Loading @@ -424,7 +454,7 @@ constructor( isRegistered = true isRegistered = true broadcastDispatcher.registerReceiver( broadcastDispatcher.registerReceiver( localeBroadcastReceiver, localeBroadcastReceiver, IntentFilter(Intent.ACTION_LOCALE_CHANGED) IntentFilter(Intent.ACTION_LOCALE_CHANGED), ) ) configurationController.addCallback(configListener) configurationController.addCallback(configListener) batteryController.addCallback(batteryCallback) batteryController.addCallback(batteryCallback) Loading @@ -434,6 +464,9 @@ constructor( parent.repeatWhenAttached { parent.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { repeatOnLifecycle(Lifecycle.State.CREATED) { listenForDozing(this) listenForDozing(this) if (ModesUi.isEnabled) { listenForDnd(this) } if (MigrateClocksToBlueprint.isEnabled) { if (MigrateClocksToBlueprint.isEnabled) { listenForDozeAmountTransition(this) listenForDozeAmountTransition(this) listenForAnyStateToAodTransition(this) listenForAnyStateToAodTransition(this) Loading @@ -449,7 +482,9 @@ constructor( bgExecutor.execute { bgExecutor.execute { // Query ZenMode data // Query ZenMode data if (!ModesUi.isEnabled) { zenModeCallback.onZenChanged(zenModeController.zen) zenModeCallback.onZenChanged(zenModeController.zen) } zenModeCallback.onNextAlarmChanged() zenModeCallback.onNextAlarmChanged() } } } } Loading Loading @@ -605,10 +640,9 @@ constructor( @VisibleForTesting @VisibleForTesting internal fun listenForDozing(scope: CoroutineScope): Job { internal fun listenForDozing(scope: CoroutineScope): Job { return scope.launch { return scope.launch { combine( combine(keyguardInteractor.dozeAmount, keyguardInteractor.isDozing) { keyguardInteractor.dozeAmount, localDozeAmount, keyguardInteractor.isDozing, localIsDozing -> ) { localDozeAmount, localIsDozing -> localDozeAmount > dozeAmount || localIsDozing localDozeAmount > dozeAmount || localIsDozing } } .collect { localIsDozing -> isDozing = localIsDozing } .collect { localIsDozing -> isDozing = localIsDozing } Loading
packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +95 −27 Original line number Original line Diff line number Diff line Loading @@ -17,11 +17,16 @@ package com.android.keyguard import android.content.BroadcastReceiver import android.content.BroadcastReceiver import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.provider.Settings import android.view.View import android.view.View import android.view.ViewTreeObserver import android.view.ViewTreeObserver import android.widget.FrameLayout import android.widget.FrameLayout import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest import com.android.settingslib.notification.modes.TestModeBuilder.MANUAL_DND_ACTIVE import com.android.settingslib.notification.modes.TestModeBuilder.MANUAL_DND_INACTIVE import com.android.systemui.Flags as AConfigFlags import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.flags.Flags import com.android.systemui.flags.Flags Loading @@ -36,6 +41,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope import com.android.systemui.log.core.LogLevel import com.android.systemui.log.core.LogLevel import com.android.systemui.log.core.LogcatOnlyMessageBuffer import com.android.systemui.log.core.LogcatOnlyMessageBuffer import com.android.systemui.plugins.clocks.ClockAnimations import com.android.systemui.plugins.clocks.ClockAnimations Loading @@ -46,9 +52,15 @@ import com.android.systemui.plugins.clocks.ClockFaceController import com.android.systemui.plugins.clocks.ClockFaceEvents import com.android.systemui.plugins.clocks.ClockFaceEvents import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockTickRate import com.android.systemui.plugins.clocks.ClockTickRate import com.android.systemui.plugins.clocks.ZenData import com.android.systemui.plugins.clocks.ZenData.ZenMode import com.android.systemui.res.R import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ZenModeController import com.android.systemui.statusbar.policy.ZenModeController import com.android.systemui.statusbar.policy.data.repository.fakeZenModeRepository import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor import com.android.systemui.testKosmos import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.argumentCaptor Loading @@ -57,9 +69,12 @@ import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock import java.util.TimeZone import java.util.TimeZone import java.util.concurrent.Executor import java.util.concurrent.Executor import java.util.concurrent.TimeUnit import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import kotlinx.coroutines.yield import kotlinx.coroutines.yield import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Before Loading @@ -73,15 +88,26 @@ import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit import com.android.systemui.Flags as AConfigFlags import org.mockito.Mockito.`when` as whenever import org.mockito.Mockito.`when` as whenever import org.mockito.junit.MockitoJUnit @RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class) @SmallTest @SmallTest @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) class ClockEventControllerTest : SysuiTestCase() { class ClockEventControllerTest : SysuiTestCase() { private val kosmos = testKosmos() private val zenModeRepository = kosmos.fakeZenModeRepository private val testScope = kosmos.testScope @JvmField @Rule val mockito = MockitoJUnit.rule() @JvmField @Rule val mockito = MockitoJUnit.rule() private val mainExecutor = ImmediateExecutor() private lateinit var repository: FakeKeyguardRepository private val messageBuffer = LogcatOnlyMessageBuffer(LogLevel.DEBUG) private val clockBuffers = ClockMessageBuffers(messageBuffer, messageBuffer, messageBuffer) private lateinit var underTest: ClockEventController @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher @Mock private lateinit var batteryController: BatteryController @Mock private lateinit var batteryController: BatteryController @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor Loading @@ -89,7 +115,6 @@ class ClockEventControllerTest : SysuiTestCase() { @Mock private lateinit var animations: ClockAnimations @Mock private lateinit var animations: ClockAnimations @Mock private lateinit var events: ClockEvents @Mock private lateinit var events: ClockEvents @Mock private lateinit var clock: ClockController @Mock private lateinit var clock: ClockController @Mock private lateinit var mainExecutor: DelayableExecutor @Mock private lateinit var bgExecutor: Executor @Mock private lateinit var bgExecutor: Executor @Mock private lateinit var smallClockController: ClockFaceController @Mock private lateinit var smallClockController: ClockFaceController @Mock private lateinit var smallClockView: View @Mock private lateinit var smallClockView: View Loading @@ -102,12 +127,10 @@ class ClockEventControllerTest : SysuiTestCase() { @Mock private lateinit var smallClockEvents: ClockFaceEvents @Mock private lateinit var smallClockEvents: ClockFaceEvents @Mock private lateinit var largeClockEvents: ClockFaceEvents @Mock private lateinit var largeClockEvents: ClockFaceEvents @Mock private lateinit var parentView: View @Mock private lateinit var parentView: View private lateinit var repository: FakeKeyguardRepository @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor private val messageBuffer = LogcatOnlyMessageBuffer(LogLevel.DEBUG) private val clockBuffers = ClockMessageBuffers(messageBuffer, messageBuffer, messageBuffer) private lateinit var underTest: ClockEventController @Mock private lateinit var zenModeController: ZenModeController @Mock private lateinit var zenModeController: ZenModeController private var zenModeControllerCallback: ZenModeController.Callback? = null @Before @Before fun setUp() { fun setUp() { Loading @@ -129,12 +152,11 @@ class ClockEventControllerTest : SysuiTestCase() { whenever(largeClockController.config) whenever(largeClockController.config) .thenReturn(ClockFaceConfig(tickRate = ClockTickRate.PER_MINUTE)) .thenReturn(ClockFaceConfig(tickRate = ClockTickRate.PER_MINUTE)) zenModeRepository.addMode(MANUAL_DND_INACTIVE) repository = FakeKeyguardRepository() repository = FakeKeyguardRepository() val withDeps = val withDeps = KeyguardInteractorFactory.create(repository = repository) KeyguardInteractorFactory.create( repository = repository, ) withDeps.featureFlags.apply { set(Flags.REGION_SAMPLING, false) } withDeps.featureFlags.apply { set(Flags.REGION_SAMPLING, false) } underTest = underTest = Loading @@ -151,7 +173,8 @@ class ClockEventControllerTest : SysuiTestCase() { bgExecutor, bgExecutor, clockBuffers, clockBuffers, withDeps.featureFlags, withDeps.featureFlags, zenModeController zenModeController, kosmos.zenModeInteractor, ) ) underTest.clock = clock underTest.clock = clock Loading @@ -161,6 +184,10 @@ class ClockEventControllerTest : SysuiTestCase() { repository.setIsDozing(true) repository.setIsDozing(true) repository.setDozeAmount(1f) repository.setDozeAmount(1f) } } val zenCallbackCaptor = argumentCaptor<ZenModeController.Callback>() verify(zenModeController).addCallback(zenCallbackCaptor.capture()) zenModeControllerCallback = zenCallbackCaptor.value } } @Test @Test Loading Loading @@ -349,17 +376,12 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForTransitionToAodFromGone_updatesClockDozeAmountToOne() = fun listenForTransitionToAodFromGone_updatesClockDozeAmountToOne() = runBlocking(IMMEDIATE) { runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) val transitionStep = MutableStateFlow(TransitionStep()) whenever(keyguardTransitionInteractor whenever(keyguardTransitionInteractor.transition(Edge.create(to = AOD))) .transition(Edge.create(to = AOD))) .thenReturn(transitionStep) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToAodTransition(this) val job = underTest.listenForAnyStateToAodTransition(this) transitionStep.value = transitionStep.value = TransitionStep( TransitionStep(from = GONE, to = AOD, transitionState = TransitionState.STARTED) from = GONE, to = AOD, transitionState = TransitionState.STARTED, ) yield() yield() verify(animations, times(2)).doze(1f) verify(animations, times(2)).doze(1f) Loading @@ -371,8 +393,7 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForTransitionToLSFromOccluded_updatesClockDozeAmountToZero() = fun listenForTransitionToLSFromOccluded_updatesClockDozeAmountToZero() = runBlocking(IMMEDIATE) { runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) val transitionStep = MutableStateFlow(TransitionStep()) whenever(keyguardTransitionInteractor whenever(keyguardTransitionInteractor.transition(Edge.create(to = LOCKSCREEN))) .transition(Edge.create(to = LOCKSCREEN))) .thenReturn(transitionStep) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToLockscreenTransition(this) val job = underTest.listenForAnyStateToLockscreenTransition(this) Loading @@ -393,8 +414,7 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForTransitionToAodFromLockscreen_neverUpdatesClockDozeAmount() = fun listenForTransitionToAodFromLockscreen_neverUpdatesClockDozeAmount() = runBlocking(IMMEDIATE) { runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) val transitionStep = MutableStateFlow(TransitionStep()) whenever(keyguardTransitionInteractor whenever(keyguardTransitionInteractor.transition(Edge.create(to = AOD))) .transition(Edge.create(to = AOD))) .thenReturn(transitionStep) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToAodTransition(this) val job = underTest.listenForAnyStateToAodTransition(this) Loading @@ -415,8 +435,7 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForAnyStateToLockscreenTransition_neverUpdatesClockDozeAmount() = fun listenForAnyStateToLockscreenTransition_neverUpdatesClockDozeAmount() = runBlocking(IMMEDIATE) { runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) val transitionStep = MutableStateFlow(TransitionStep()) whenever(keyguardTransitionInteractor whenever(keyguardTransitionInteractor.transition(Edge.create(to = LOCKSCREEN))) .transition(Edge.create(to = LOCKSCREEN))) .thenReturn(transitionStep) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToLockscreenTransition(this) val job = underTest.listenForAnyStateToLockscreenTransition(this) Loading @@ -437,8 +456,7 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForAnyStateToDozingTransition_UpdatesClockDozeAmountToOne() = fun listenForAnyStateToDozingTransition_UpdatesClockDozeAmountToOne() = runBlocking(IMMEDIATE) { runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) val transitionStep = MutableStateFlow(TransitionStep()) whenever(keyguardTransitionInteractor whenever(keyguardTransitionInteractor.transition(Edge.create(to = DOZING))) .transition(Edge.create(to = DOZING))) .thenReturn(transitionStep) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToDozingTransition(this) val job = underTest.listenForAnyStateToDozingTransition(this) Loading Loading @@ -498,7 +516,57 @@ class ClockEventControllerTest : SysuiTestCase() { verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any()) verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any()) } } @Test @EnableFlags(android.app.Flags.FLAG_MODES_UI) fun listenForDnd_onDndChange_updatesClockZenMode() = testScope.runTest { underTest.listenForDnd(testScope.backgroundScope) zenModeRepository.replaceMode(MANUAL_DND_INACTIVE.id, MANUAL_DND_ACTIVE) runCurrent() verify(events) .onZenDataChanged( eq(ZenData(ZenMode.IMPORTANT_INTERRUPTIONS, R.string::dnd_is_on.name)) ) zenModeRepository.replaceMode(MANUAL_DND_ACTIVE.id, MANUAL_DND_INACTIVE) runCurrent() verify(events).onZenDataChanged(eq(ZenData(ZenMode.OFF, R.string::dnd_is_off.name))) } @Test @DisableFlags(android.app.Flags.FLAG_MODES_UI) fun zenModeControllerCallback_onDndChange_updatesClockZenMode() = runBlocking(IMMEDIATE) { zenModeControllerCallback!!.onZenChanged( Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS ) verify(events) .onZenDataChanged( eq(ZenData(ZenMode.IMPORTANT_INTERRUPTIONS, R.string::dnd_is_on.name)) ) zenModeControllerCallback!!.onZenChanged(Settings.Global.ZEN_MODE_OFF) verify(events).onZenDataChanged(eq(ZenData(ZenMode.OFF, R.string::dnd_is_off.name))) } companion object { companion object { private val IMMEDIATE = Dispatchers.Main.immediate private val IMMEDIATE = Dispatchers.Main.immediate } } } } private class ImmediateExecutor : DelayableExecutor { override fun execute(runnable: Runnable) { runnable.run() } override fun executeDelayed(runnable: Runnable, delay: Long, unit: TimeUnit) = runnable.apply { run() } override fun executeAtTime(runnable: Runnable, uptimeMillis: Long, unit: TimeUnit) = runnable.apply { run() } }