diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index 9151238499dc3..55f8bea4d0569 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -23,12 +23,17 @@ import android.content.res.Resources import android.text.format.DateFormat import android.util.TypedValue import android.view.View +import androidx.annotation.VisibleForTesting +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlags -import com.android.systemui.plugins.ClockController -import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.flags.Flags.REGION_SAMPLING +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.plugins.Clock import com.android.systemui.shared.regionsampling.RegionSamplingInstance import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback @@ -38,13 +43,19 @@ import java.util.Locale import java.util.TimeZone import java.util.concurrent.Executor import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DisposableHandle +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.launch /** * Controller for a Clock provided by the registry and used on the keyguard. Instantiated by * [KeyguardClockSwitchController]. Functionality is forked from [AnimatableClockController]. */ open class ClockEventController @Inject constructor( - private val statusBarStateController: StatusBarStateController, + private val keyguardInteractor: KeyguardInteractor, private val broadcastDispatcher: BroadcastDispatcher, private val batteryController: BatteryController, private val keyguardUpdateMonitor: KeyguardUpdateMonitor, @@ -53,7 +64,7 @@ open class ClockEventController @Inject constructor( private val context: Context, @Main private val mainExecutor: Executor, @Background private val bgExecutor: Executor, - private val featureFlags: FeatureFlags, + private val featureFlags: FeatureFlags ) { var clock: ClockController? = null set(value) { @@ -70,9 +81,9 @@ open class ClockEventController @Inject constructor( private var isCharging = false private var dozeAmount = 0f private var isKeyguardVisible = false - - private val regionSamplingEnabled = - featureFlags.isEnabled(com.android.systemui.flags.Flags.REGION_SAMPLING) + private var isRegistered = false + private var disposableHandle: DisposableHandle? = null + private val regionSamplingEnabled = featureFlags.isEnabled(REGION_SAMPLING) private fun updateColors() { if (regionSamplingEnabled && smallRegionSampler != null && largeRegionSampler != null) { @@ -165,15 +176,6 @@ open class ClockEventController @Inject constructor( } } - private val statusBarStateListener = object : StatusBarStateController.StateListener { - override fun onDozeAmountChanged(linear: Float, eased: Float) { - clock?.animations?.doze(linear) - - isDozing = linear > dozeAmount - dozeAmount = linear - } - } - private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() { override fun onKeyguardVisibilityChanged(visible: Boolean) { isKeyguardVisible = visible @@ -195,13 +197,11 @@ open class ClockEventController @Inject constructor( } } - init { - isDozing = statusBarStateController.isDozing - } - - fun registerListeners() { - dozeAmount = statusBarStateController.dozeAmount - isDozing = statusBarStateController.isDozing || dozeAmount != 0f + fun registerListeners(parent: View) { + if (isRegistered) { + return + } + isRegistered = true broadcastDispatcher.registerReceiver( localeBroadcastReceiver, @@ -210,17 +210,27 @@ open class ClockEventController @Inject constructor( configurationController.addCallback(configListener) batteryController.addCallback(batteryCallback) keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback) - statusBarStateController.addCallback(statusBarStateListener) smallRegionSampler?.startRegionSampler() largeRegionSampler?.startRegionSampler() + disposableHandle = parent.repeatWhenAttached { + repeatOnLifecycle(Lifecycle.State.STARTED) { + listenForDozing(this) + listenForDozeAmount(this) + } + } } fun unregisterListeners() { + if (!isRegistered) { + return + } + isRegistered = false + + disposableHandle?.dispose() broadcastDispatcher.unregisterReceiver(localeBroadcastReceiver) configurationController.removeCallback(configListener) batteryController.removeCallback(batteryCallback) keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback) - statusBarStateController.removeCallback(statusBarStateListener) smallRegionSampler?.stopRegionSampler() largeRegionSampler?.stopRegionSampler() } @@ -235,8 +245,28 @@ open class ClockEventController @Inject constructor( largeRegionSampler?.dump(pw) } - companion object { - private val TAG = ClockEventController::class.simpleName - private const val FORMAT_NUMBER = 1234567890 + @VisibleForTesting + internal suspend fun listenForDozeAmount(scope: CoroutineScope): Job { + return scope.launch { + keyguardInteractor.dozeAmount.collect { + dozeAmount = it + clock?.animations?.doze(dozeAmount) + } + } + } + + @VisibleForTesting + internal suspend fun listenForDozing(scope: CoroutineScope): Job { + return scope.launch { + combine ( + keyguardInteractor.dozeAmount, + keyguardInteractor.isDozing, + ) { localDozeAmount, localIsDozing -> + localDozeAmount > dozeAmount || localIsDozing + } + .collect { localIsDozing -> + isDozing = localIsDozing + } + } } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index b450ec35db322..202134b699d7a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -164,7 +164,7 @@ public class KeyguardClockSwitchController extends ViewController() verify(configurationController).addCallback(capture(captor)) captor.value.onThemeChanged() @@ -131,13 +144,11 @@ class ClockEventControllerTest : SysuiTestCase() { } @Test - fun fontChanged_verifyFontSizeUpdated() { + fun fontChanged_verifyFontSizeUpdated() = runBlocking(IMMEDIATE) { clockEventController.clock = clock verify(smallClockEvents).onRegionDarknessChanged(anyBoolean()) verify(largeClockEvents).onRegionDarknessChanged(anyBoolean()) - clockEventController.registerListeners() - val captor = argumentCaptor() verify(configurationController).addCallback(capture(captor)) captor.value.onDensityOrFontScaleChanged() @@ -146,10 +157,7 @@ class ClockEventControllerTest : SysuiTestCase() { } @Test - fun batteryCallback_keyguardShowingCharging_verifyChargeAnimation() { - clockEventController.clock = clock - clockEventController.registerListeners() - + fun batteryCallback_keyguardShowingCharging_verifyChargeAnimation() = runBlocking(IMMEDIATE) { val batteryCaptor = argumentCaptor() verify(batteryController).addCallback(capture(batteryCaptor)) val keyguardCaptor = argumentCaptor() @@ -161,26 +169,21 @@ class ClockEventControllerTest : SysuiTestCase() { } @Test - fun batteryCallback_keyguardShowingCharging_Duplicate_verifyChargeAnimation() { - clockEventController.clock = clock - clockEventController.registerListeners() + fun batteryCallback_keyguardShowingCharging_Duplicate_verifyChargeAnimation() = + runBlocking(IMMEDIATE) { + val batteryCaptor = argumentCaptor() + verify(batteryController).addCallback(capture(batteryCaptor)) + val keyguardCaptor = argumentCaptor() + verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor)) + keyguardCaptor.value.onKeyguardVisibilityChanged(true) + batteryCaptor.value.onBatteryLevelChanged(10, false, true) + batteryCaptor.value.onBatteryLevelChanged(10, false, true) - val batteryCaptor = argumentCaptor() - verify(batteryController).addCallback(capture(batteryCaptor)) - val keyguardCaptor = argumentCaptor() - verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor)) - keyguardCaptor.value.onKeyguardVisibilityChanged(true) - batteryCaptor.value.onBatteryLevelChanged(10, false, true) - batteryCaptor.value.onBatteryLevelChanged(10, false, true) - - verify(animations, times(1)).charge() - } + verify(animations, times(1)).charge() + } @Test - fun batteryCallback_keyguardHiddenCharging_verifyChargeAnimation() { - clockEventController.clock = clock - clockEventController.registerListeners() - + fun batteryCallback_keyguardHiddenCharging_verifyChargeAnimation() = runBlocking(IMMEDIATE) { val batteryCaptor = argumentCaptor() verify(batteryController).addCallback(capture(batteryCaptor)) val keyguardCaptor = argumentCaptor() @@ -192,25 +195,20 @@ class ClockEventControllerTest : SysuiTestCase() { } @Test - fun batteryCallback_keyguardShowingNotCharging_verifyChargeAnimation() { - clockEventController.clock = clock - clockEventController.registerListeners() + fun batteryCallback_keyguardShowingNotCharging_verifyChargeAnimation() = + runBlocking(IMMEDIATE) { + val batteryCaptor = argumentCaptor() + verify(batteryController).addCallback(capture(batteryCaptor)) + val keyguardCaptor = argumentCaptor() + verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor)) + keyguardCaptor.value.onKeyguardVisibilityChanged(true) + batteryCaptor.value.onBatteryLevelChanged(10, false, false) - val batteryCaptor = argumentCaptor() - verify(batteryController).addCallback(capture(batteryCaptor)) - val keyguardCaptor = argumentCaptor() - verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor)) - keyguardCaptor.value.onKeyguardVisibilityChanged(true) - batteryCaptor.value.onBatteryLevelChanged(10, false, false) - - verify(animations, never()).charge() - } + verify(animations, never()).charge() + } @Test - fun localeCallback_verifyClockNotified() { - clockEventController.clock = clock - clockEventController.registerListeners() - + fun localeCallback_verifyClockNotified() = runBlocking(IMMEDIATE) { val captor = argumentCaptor() verify(broadcastDispatcher).registerReceiver( capture(captor), any(), eq(null), eq(null), anyInt(), eq(null) @@ -221,10 +219,7 @@ class ClockEventControllerTest : SysuiTestCase() { } @Test - fun keyguardCallback_visibilityChanged_clockDozeCalled() { - clockEventController.clock = clock - clockEventController.registerListeners() - + fun keyguardCallback_visibilityChanged_clockDozeCalled() = runBlocking(IMMEDIATE) { val captor = argumentCaptor() verify(keyguardUpdateMonitor).registerCallback(capture(captor)) @@ -236,10 +231,7 @@ class ClockEventControllerTest : SysuiTestCase() { } @Test - fun keyguardCallback_timeFormat_clockNotified() { - clockEventController.clock = clock - clockEventController.registerListeners() - + fun keyguardCallback_timeFormat_clockNotified() = runBlocking(IMMEDIATE) { val captor = argumentCaptor() verify(keyguardUpdateMonitor).registerCallback(capture(captor)) captor.value.onTimeFormatChanged("12h") @@ -248,11 +240,8 @@ class ClockEventControllerTest : SysuiTestCase() { } @Test - fun keyguardCallback_timezoneChanged_clockNotified() { + fun keyguardCallback_timezoneChanged_clockNotified() = runBlocking(IMMEDIATE) { val mockTimeZone = mock() - clockEventController.clock = clock - clockEventController.registerListeners() - val captor = argumentCaptor() verify(keyguardUpdateMonitor).registerCallback(capture(captor)) captor.value.onTimeZoneChanged(mockTimeZone) @@ -261,10 +250,7 @@ class ClockEventControllerTest : SysuiTestCase() { } @Test - fun keyguardCallback_userSwitched_clockNotified() { - clockEventController.clock = clock - clockEventController.registerListeners() - + fun keyguardCallback_userSwitched_clockNotified() = runBlocking(IMMEDIATE) { val captor = argumentCaptor() verify(keyguardUpdateMonitor).registerCallback(capture(captor)) captor.value.onUserSwitchComplete(10) @@ -273,25 +259,27 @@ class ClockEventControllerTest : SysuiTestCase() { } @Test - fun keyguardCallback_verifyKeyguardChanged() { - clockEventController.clock = clock - clockEventController.registerListeners() + fun keyguardCallback_verifyKeyguardChanged() = runBlocking(IMMEDIATE) { + val job = underTest.listenForDozeAmount(this) + repository.setDozeAmount(0.4f) - val captor = argumentCaptor() - verify(statusBarStateController).addCallback(capture(captor)) - captor.value.onDozeAmountChanged(0.4f, 0.6f) + yield() verify(animations).doze(0.4f) + + job.cancel() } @Test - fun unregisterListeners_validate() { - clockEventController.clock = clock - clockEventController.unregisterListeners() + fun unregisterListeners_validate() = runBlocking(IMMEDIATE) { + underTest.unregisterListeners() verify(broadcastDispatcher).unregisterReceiver(any()) verify(configurationController).removeCallback(any()) verify(batteryController).removeCallback(any()) verify(keyguardUpdateMonitor).removeCallback(any()) - verify(statusBarStateController).removeCallback(any()) + } + + companion object { + private val IMMEDIATE = Dispatchers.Main.immediate } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java index 400caa3a352a4..bb03a47e025c7 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java @@ -265,6 +265,6 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { private void verifyAttachment(VerificationMode times) { verify(mClockRegistry, times).registerClockChangeListener( any(ClockRegistry.ClockChangeListener.class)); - verify(mClockEventController, times).registerListeners(); + verify(mClockEventController, times).registerListeners(mView); } }