Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 215a1f76 authored by Matt Pietal's avatar Matt Pietal
Browse files

[DO NOT MERGE] Rewire dozing for clock events

Continuing exploration of moving all doze events to flowables,
including both isDozing and the dozeAmount animations. At the moment,
the source of these events still comes from StatusBarStateController,
which informs the KeyguardRepository. Next up is to create a parallel
way to drive these animations that is solely based on repository
information.

Bug: 242853098
Test: atest ClockEventControllerTest KeyguardClockSwitchControllerTest
Change-Id: I8c40076ad7e716093f602e5bbf5d9f03871ac679
parent ed74a53d
Loading
Loading
Loading
Loading
+58 −28
Original line number Diff line number Diff line
@@ -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(parent: View) {
        if (isRegistered) {
            return
        }

    fun registerListeners() {
        dozeAmount = statusBarStateController.dozeAmount
        isDozing = statusBarStateController.isDozing || dozeAmount != 0f
        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
            }
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -164,7 +164,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
    protected void onViewAttached() {
        mClockRegistry.registerClockChangeListener(mClockChangedListener);
        setClock(mClockRegistry.createCurrentClock());
        mClockEventController.registerListeners();
        mClockEventController.registerListeners(mView);
        mKeyguardClockTopMargin =
                mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);

+68 −80
Original line number Diff line number Diff line
@@ -17,11 +17,14 @@ package com.android.keyguard

import android.content.BroadcastReceiver
import android.testing.AndroidTestingRunner
import android.view.View
import android.widget.TextView
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ClockAnimations
import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.ClockEvents
@@ -37,6 +40,9 @@ import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import java.util.TimeZone
import java.util.concurrent.Executor
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.yield
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
@@ -57,7 +63,7 @@ import org.mockito.junit.MockitoJUnit
class ClockEventControllerTest : SysuiTestCase() {

    @JvmField @Rule val mockito = MockitoJUnit.rule()
    @Mock private lateinit var statusBarStateController: StatusBarStateController
    @Mock private lateinit var keyguardInteractor: KeyguardInteractor
    @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
    @Mock private lateinit var batteryController: BatteryController
    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@@ -72,8 +78,10 @@ class ClockEventControllerTest : SysuiTestCase() {
    @Mock private lateinit var largeClockController: ClockFaceController
    @Mock private lateinit var smallClockEvents: ClockFaceEvents
    @Mock private lateinit var largeClockEvents: ClockFaceEvents
    @Mock private lateinit var parentView: View
    private lateinit var repository: FakeKeyguardRepository

    private lateinit var clockEventController: ClockEventController
    private lateinit var underTest: ClockEventController

    @Before
    fun setUp() {
@@ -86,8 +94,10 @@ class ClockEventControllerTest : SysuiTestCase() {
        whenever(clock.events).thenReturn(events)
        whenever(clock.animations).thenReturn(animations)

        clockEventController = ClockEventController(
            statusBarStateController,
        repository = FakeKeyguardRepository()

        underTest = ClockEventController(
            KeyguardInteractor(repository = repository),
            broadcastDispatcher,
            batteryController,
            keyguardUpdateMonitor,
@@ -98,31 +108,34 @@ class ClockEventControllerTest : SysuiTestCase() {
            bgExecutor,
            featureFlags
        )
        underTest.clock = clock

        runBlocking(IMMEDIATE) {
            underTest.registerListeners(parentView)

            repository.setDozing(true)
            repository.setDozeAmount(1f)
        }
    }

    @Test
    fun clockSet_validateInitialization() {
        clockEventController.clock = clock

        verify(clock).initialize(any(), anyFloat(), anyFloat())
    }

    @Test
    fun clockUnset_validateState() {
        clockEventController.clock = clock
        clockEventController.clock = null
        underTest.clock = null

        assertEquals(clockEventController.clock, null)
        assertEquals(underTest.clock, null)
    }

    @Test
    fun themeChanged_verifyClockPaletteUpdated() {
    fun themeChanged_verifyClockPaletteUpdated() = runBlocking(IMMEDIATE) {
        clockEventController.clock = clock
        verify(smallClockEvents).onRegionDarknessChanged(anyBoolean())
        verify(largeClockEvents).onRegionDarknessChanged(anyBoolean())

        clockEventController.registerListeners()

        val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
        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<ConfigurationController.ConfigurationListener>()
        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<BatteryController.BatteryStateChangeCallback>()
        verify(batteryController).addCallback(capture(batteryCaptor))
        val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
@@ -161,10 +169,8 @@ class ClockEventControllerTest : SysuiTestCase() {
    }

    @Test
    fun batteryCallback_keyguardShowingCharging_Duplicate_verifyChargeAnimation() {
        clockEventController.clock = clock
        clockEventController.registerListeners()

    fun batteryCallback_keyguardShowingCharging_Duplicate_verifyChargeAnimation() =
        runBlocking(IMMEDIATE) {
            val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
            verify(batteryController).addCallback(capture(batteryCaptor))
            val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
@@ -177,10 +183,7 @@ class ClockEventControllerTest : SysuiTestCase() {
        }

    @Test
    fun batteryCallback_keyguardHiddenCharging_verifyChargeAnimation() {
        clockEventController.clock = clock
        clockEventController.registerListeners()

    fun batteryCallback_keyguardHiddenCharging_verifyChargeAnimation() = runBlocking(IMMEDIATE) {
        val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
        verify(batteryController).addCallback(capture(batteryCaptor))
        val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
@@ -192,10 +195,8 @@ class ClockEventControllerTest : SysuiTestCase() {
    }

    @Test
    fun batteryCallback_keyguardShowingNotCharging_verifyChargeAnimation() {
        clockEventController.clock = clock
        clockEventController.registerListeners()

    fun batteryCallback_keyguardShowingNotCharging_verifyChargeAnimation() =
        runBlocking(IMMEDIATE) {
            val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
            verify(batteryController).addCallback(capture(batteryCaptor))
            val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
@@ -207,10 +208,7 @@ class ClockEventControllerTest : SysuiTestCase() {
        }

    @Test
    fun localeCallback_verifyClockNotified() {
        clockEventController.clock = clock
        clockEventController.registerListeners()

    fun localeCallback_verifyClockNotified() = runBlocking(IMMEDIATE) {
        val captor = argumentCaptor<BroadcastReceiver>()
        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<KeyguardUpdateMonitorCallback>()
        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<KeyguardUpdateMonitorCallback>()
        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<TimeZone>()
        clockEventController.clock = clock
        clockEventController.registerListeners()

        val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
        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<KeyguardUpdateMonitorCallback>()
        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<StatusBarStateController.StateListener>()
        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
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -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);
    }
}