diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt index cafdc86761733..4889dbd239133 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt @@ -61,7 +61,11 @@ interface Clock { /** Initializes various rendering parameters. If never called, provides reasonable defaults. */ fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) { - events.onColorPaletteChanged(resources) + events.onColorPaletteChanged( + resources, + ClockDarkness.DEFAULT, + ClockDarkness.DEFAULT + ) animations.doze(dozeFraction) animations.fold(foldFraction) events.onTimeTick() @@ -89,7 +93,11 @@ interface ClockEvents { fun onFontSettingChanged() { } /** Call whenever the color palette should update */ - fun onColorPaletteChanged(resources: Resources) { } + fun onColorPaletteChanged( + resources: Resources, + smallClockIsDark: ClockDarkness, + largeClockIsDark: ClockDarkness + ) { } } /** Methods which trigger various clock animations */ @@ -112,3 +120,12 @@ data class ClockMetadata( val clockId: ClockId, val name: String ) + +/** + * Enum for whether clock region is dark or light. + */ +enum class ClockDarkness(val isDark: Boolean) { + DEFAULT(true), + DARK(true), + LIGHT(false) +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt index 1d8abe3fdf420..b95e52dce2087 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt @@ -22,6 +22,7 @@ import android.view.LayoutInflater import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.Clock import com.android.systemui.plugins.ClockAnimations +import com.android.systemui.plugins.ClockDarkness import com.android.systemui.plugins.ClockEvents import com.android.systemui.plugins.ClockId import com.android.systemui.plugins.ClockMetadata @@ -68,8 +69,8 @@ class DefaultClockProvider @Inject constructor( * AnimatableClockView used by the existing lockscreen clock. */ class DefaultClock( - private val layoutInflater: LayoutInflater, - private val resources: Resources + private val layoutInflater: LayoutInflater, + private val resources: Resources ) : Clock { override val smallClock = layoutInflater.inflate(R.layout.clock_default_small, null) as AnimatableClockView @@ -83,6 +84,16 @@ class DefaultClock( resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale_burmese) private val defaultLineSpacing = resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale) + private fun updateClockColor(clock: AnimatableClockView, darkValue: ClockDarkness) { + val color = if (darkValue.isDark) { + resources.getColor(android.R.color.system_accent2_600) + } else { + resources.getColor(android.R.color.system_accent1_100) + } + clock.setColors(DOZE_COLOR, color) + clock.animateAppearOnLockscreen() + } + override val events = object : ClockEvents { override fun onTimeTick() = clocks.forEach { it.refreshTime() } @@ -104,9 +115,13 @@ class DefaultClock( recomputePadding() } - override fun onColorPaletteChanged(resources: Resources) { - val color = resources.getColor(android.R.color.system_accent1_100) - clocks.forEach { it.setColors(DOZE_COLOR, color) } + override fun onColorPaletteChanged( + resources: Resources, + smallClockIsDark: ClockDarkness, + largeClockIsDark: ClockDarkness + ) { + updateClockColor(smallClock, smallClockIsDark) + updateClockColor(largeClock, largeClockIsDark) } override fun onLocaleChanged(locale: Locale) { @@ -187,7 +202,11 @@ class DefaultClock( override fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) { recomputePadding() animations = DefaultClockAnimations(dozeFraction, foldFraction) - events.onColorPaletteChanged(resources) + events.onColorPaletteChanged( + resources, + ClockDarkness.DEFAULT, + ClockDarkness.DEFAULT + ) events.onTimeTick() } diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index efd7bcf10cd21..1e62b9c3abb39 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -20,17 +20,24 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.content.res.Resources +import android.graphics.Rect import android.text.format.DateFormat +import android.view.View 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.Clock +import com.android.systemui.plugins.ClockDarkness import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.shared.navigationbar.RegionSamplingHelper import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback import com.android.systemui.statusbar.policy.ConfigurationController import java.io.PrintWriter import java.util.Locale import java.util.TimeZone +import java.util.concurrent.Executor import javax.inject.Inject /** @@ -38,13 +45,16 @@ import javax.inject.Inject * [KeyguardClockSwitchController]. Functionality is forked from [AnimatableClockController]. */ class ClockEventController @Inject constructor( - private val statusBarStateController: StatusBarStateController, - private val broadcastDispatcher: BroadcastDispatcher, - private val batteryController: BatteryController, - private val keyguardUpdateMonitor: KeyguardUpdateMonitor, - private val configurationController: ConfigurationController, - @Main private val resources: Resources, - private val context: Context + private val statusBarStateController: StatusBarStateController, + private val broadcastDispatcher: BroadcastDispatcher, + private val batteryController: BatteryController, + private val keyguardUpdateMonitor: KeyguardUpdateMonitor, + private val configurationController: ConfigurationController, + @Main private val resources: Resources, + private val context: Context, + @Main private val mainExecutor: Executor, + @Background private val bgExecutor: Executor, + private val featureFlags: FeatureFlags ) { var clock: Clock? = null set(value) { @@ -61,9 +71,94 @@ class ClockEventController @Inject constructor( private var dozeAmount = 0f private var isKeyguardShowing = false + private var smallClockIsDark = ClockDarkness.DEFAULT + private var largeClockIsDark = ClockDarkness.DEFAULT + private var smallSamplingBounds = Rect() + private var largeSamplingBounds = Rect() + + private val regionSamplingEnabled = + featureFlags.isEnabled(com.android.systemui.flags.Flags.REGION_SAMPLING) + + private fun setClockDarkness(isRegionDark: Boolean): ClockDarkness { + return if (isRegionDark) { + ClockDarkness.DARK + } else { + ClockDarkness.LIGHT + } + } + + // TODO: Abstract out the creation of RegionSampler and its fields + var smallRegionSampling: RegionSamplingHelper? = + if (!regionSamplingEnabled || clock == null) { + null + } else { + RegionSamplingHelper(clock?.smallClock, + object : RegionSamplingHelper.SamplingCallback { + override fun onRegionDarknessChanged(isRegionDark: Boolean) { + smallClockIsDark = setClockDarkness(isRegionDark) + clock?.events?.onColorPaletteChanged( + resources, + smallClockIsDark, + largeClockIsDark + ) + } + + override fun getSampledRegion(sampledView: View): Rect { + smallSamplingBounds = Rect( + sampledView.left, + sampledView.top, + sampledView.right, + sampledView.bottom + ) + return smallSamplingBounds + } + + override fun isSamplingEnabled(): Boolean { + return regionSamplingEnabled + } + }, + mainExecutor, bgExecutor) + } + + var largeRegionSampling: RegionSamplingHelper? = + if (!regionSamplingEnabled || clock == null) { + null + } else { + RegionSamplingHelper(clock?.largeClock, + object : RegionSamplingHelper.SamplingCallback { + override fun onRegionDarknessChanged(isRegionDark: Boolean) { + largeClockIsDark = setClockDarkness(isRegionDark) + clock?.events?.onColorPaletteChanged( + resources, + smallClockIsDark, + largeClockIsDark + ) + } + + override fun getSampledRegion(sampledView: View): Rect { + largeSamplingBounds = Rect( + sampledView.left, + sampledView.top, + sampledView.right, + sampledView.bottom + ) + return largeSamplingBounds + } + + override fun isSamplingEnabled(): Boolean { + return regionSamplingEnabled + } + }, + mainExecutor, bgExecutor) + } + private val configListener = object : ConfigurationController.ConfigurationListener { override fun onThemeChanged() { - clock?.events?.onColorPaletteChanged(resources) + clock?.events?.onColorPaletteChanged( + resources, + smallClockIsDark, + largeClockIsDark + ) } } @@ -114,6 +209,9 @@ class ClockEventController @Inject constructor( init { isDozing = statusBarStateController.isDozing + smallRegionSampling?.setWindowVisible(true) + largeRegionSampling?.setWindowVisible(true) + clock?.events?.onColorPaletteChanged(resources, smallClockIsDark, largeClockIsDark) } fun registerListeners() { @@ -128,6 +226,8 @@ class ClockEventController @Inject constructor( batteryController.addCallback(batteryCallback) keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback) statusBarStateController.addCallback(statusBarStateListener) + smallRegionSampling?.start(smallSamplingBounds) + largeRegionSampling?.start(largeSamplingBounds) } fun unregisterListeners() { @@ -136,6 +236,8 @@ class ClockEventController @Inject constructor( batteryController.removeCallback(batteryCallback) keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback) statusBarStateController.removeCallback(statusBarStateListener) + smallRegionSampling?.stop() + largeRegionSampling?.stop() } /** @@ -144,6 +246,8 @@ class ClockEventController @Inject constructor( fun dump(pw: PrintWriter) { pw.println(this) clock?.dump(pw) + smallRegionSampling?.dump(pw) + largeRegionSampling?.dump(pw) } companion object { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt index 4f3995252b544..802194464b62c 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt @@ -21,6 +21,7 @@ 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.plugins.Clock import com.android.systemui.plugins.ClockAnimations import com.android.systemui.plugins.ClockEvents @@ -33,6 +34,7 @@ import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import java.util.TimeZone +import java.util.concurrent.Executor import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Rule @@ -60,6 +62,9 @@ class ClockEventControllerTest : SysuiTestCase() { @Mock private lateinit var animations: ClockAnimations @Mock private lateinit var events: ClockEvents @Mock private lateinit var clock: Clock + @Mock private lateinit var mainExecutor: Executor + @Mock private lateinit var bgExecutor: Executor + @Mock private lateinit var featureFlags: FeatureFlags private lateinit var clockEventController: ClockEventController @@ -77,7 +82,10 @@ class ClockEventControllerTest : SysuiTestCase() { keyguardUpdateMonitor, configurationController, context.resources, - context + context, + mainExecutor, + bgExecutor, + featureFlags ) } @@ -105,7 +113,7 @@ class ClockEventControllerTest : SysuiTestCase() { verify(configurationController).addCallback(capture(captor)) captor.value.onThemeChanged() - verify(events).onColorPaletteChanged(any()) + verify(events).onColorPaletteChanged(any(), any(), any()) } @Test