From a724e0b753f710aef22c786bb089d3c8f7d7970a Mon Sep 17 00:00:00 2001 From: Grace Date: Mon, 11 Jul 2022 21:03:24 +0000 Subject: [PATCH 1/4] [DO NOT MERGE] Update DefaultClockProvider colors This is largely a cherry-pick of change I6b32776dac1853eeab87c2a65da69478e4da5b75 but with some notable changes to accomadate existing code differences in tm-qpr-dev. - We use a boolean instead of an enum for clock region darkness as the enum is in a different place in tm-qpr-dev. - We clean up some of the initialization code in ClockEventController to prevent testing issues and provide a dependency injection point to the screenshot test. - Pull the clock color setting from the theme when region sampling is disabled instead of defaulting to always dark. Test: Manually validated colors matched reference images on light and dark backgrounds with the region sampling feature both enabled and disabled. Bug: 229771520 Change-Id: I7906850b5de7f512f55e47e1122dfaacbc9c9406 --- .../systemui/plugins/ClockProviderPlugin.kt | 19 +-- .../shared/clocks/DefaultClockProvider.kt | 23 +-- .../android/keyguard/ClockEventController.kt | 148 ++++++++---------- .../keyguard/ClockEventControllerTest.kt | 5 +- 4 files changed, 81 insertions(+), 114 deletions(-) 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 4889dbd239133..01e5d86549ebd 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt @@ -61,11 +61,7 @@ interface Clock { /** Initializes various rendering parameters. If never called, provides reasonable defaults. */ fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) { - events.onColorPaletteChanged( - resources, - ClockDarkness.DEFAULT, - ClockDarkness.DEFAULT - ) + events.onColorPaletteChanged(resources, true, true) animations.doze(dozeFraction) animations.fold(foldFraction) events.onTimeTick() @@ -95,8 +91,8 @@ interface ClockEvents { /** Call whenever the color palette should update */ fun onColorPaletteChanged( resources: Resources, - smallClockIsDark: ClockDarkness, - largeClockIsDark: ClockDarkness + smallClockIsDark: Boolean, + largeClockIsDark: Boolean ) { } } @@ -120,12 +116,3 @@ 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 b95e52dce2087..d881cd1e24154 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,7 +22,6 @@ 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 @@ -84,11 +83,11 @@ 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 { + private fun updateClockColor(clock: AnimatableClockView, isRegionDark: Boolean) { + val color = if (isRegionDark) { resources.getColor(android.R.color.system_accent1_100) + } else { + resources.getColor(android.R.color.system_accent2_600) } clock.setColors(DOZE_COLOR, color) clock.animateAppearOnLockscreen() @@ -117,8 +116,8 @@ class DefaultClock( override fun onColorPaletteChanged( resources: Resources, - smallClockIsDark: ClockDarkness, - largeClockIsDark: ClockDarkness + smallClockIsDark: Boolean, + largeClockIsDark: Boolean ) { updateClockColor(smallClock, smallClockIsDark) updateClockColor(largeClock, largeClockIsDark) @@ -199,13 +198,17 @@ class DefaultClock( clocks.forEach { it.setColors(DOZE_COLOR, DOZE_COLOR) } } - override fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) { + override fun initialize( + resources: Resources, + dozeFraction: Float, + foldFraction: Float + ) { recomputePadding() animations = DefaultClockAnimations(dozeFraction, foldFraction) events.onColorPaletteChanged( resources, - ClockDarkness.DEFAULT, - ClockDarkness.DEFAULT + true, + true ) events.onTimeTick() } diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index 1e62b9c3abb39..0e1e0cb2adcf0 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -20,17 +20,16 @@ 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.util.TypedValue 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.shared.regionsampling.RegionSamplingInstance import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback import com.android.systemui.statusbar.policy.ConfigurationController @@ -44,7 +43,7 @@ import javax.inject.Inject * Controller for a Clock provided by the registry and used on the keyguard. Instantiated by * [KeyguardClockSwitchController]. Functionality is forked from [AnimatableClockController]. */ -class ClockEventController @Inject constructor( +open class ClockEventController @Inject constructor( private val statusBarStateController: StatusBarStateController, private val broadcastDispatcher: BroadcastDispatcher, private val batteryController: BatteryController, @@ -61,6 +60,7 @@ class ClockEventController @Inject constructor( field = value if (value != null) { value.initialize(resources, dozeAmount, 0f) + updateRegionSamplers(value) } } @@ -71,94 +71,71 @@ 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 + private val updateFun = object : RegionSamplingInstance.UpdateColorCallback { + override fun updateColors() { + if (regionSamplingEnabled) { + smallClockIsDark = smallRegionSamplingInstance.currentRegionDarkness().isDark + largeClockIsDark = largeRegionSamplingInstance.currentRegionDarkness().isDark + } else { + val isLightTheme = TypedValue() + context.theme.resolveAttribute(android.R.attr.isLightTheme, isLightTheme, true) + smallClockIsDark = isLightTheme.data == 0 + largeClockIsDark = isLightTheme.data == 0 + } + clock?.events?.onColorPaletteChanged(resources, smallClockIsDark, largeClockIsDark) } } - // 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 - ) - } + fun updateRegionSamplers(currentClock: Clock?) { + smallRegionSamplingInstance = createRegionSampler( + currentClock?.smallClock, + mainExecutor, + bgExecutor, + regionSamplingEnabled, + updateFun + ) - override fun getSampledRegion(sampledView: View): Rect { - smallSamplingBounds = Rect( - sampledView.left, - sampledView.top, - sampledView.right, - sampledView.bottom - ) - return smallSamplingBounds - } + largeRegionSamplingInstance = createRegionSampler( + currentClock?.largeClock, + mainExecutor, + bgExecutor, + regionSamplingEnabled, + updateFun + ) - override fun isSamplingEnabled(): Boolean { - return regionSamplingEnabled - } - }, - mainExecutor, bgExecutor) - } + smallRegionSamplingInstance.startRegionSampler() + largeRegionSamplingInstance.startRegionSampler() - 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 - ) - } + updateFun.updateColors() + } - override fun getSampledRegion(sampledView: View): Rect { - largeSamplingBounds = Rect( - sampledView.left, - sampledView.top, - sampledView.right, - sampledView.bottom - ) - return largeSamplingBounds - } + protected open fun createRegionSampler( + sampledView: View?, + mainExecutor: Executor?, + bgExecutor: Executor?, + regionSamplingEnabled: Boolean, + updateFun: RegionSamplingInstance.UpdateColorCallback + ): RegionSamplingInstance { + return RegionSamplingInstance( + sampledView, + mainExecutor, + bgExecutor, + regionSamplingEnabled, + updateFun) + } - override fun isSamplingEnabled(): Boolean { - return regionSamplingEnabled - } - }, - mainExecutor, bgExecutor) - } + lateinit var smallRegionSamplingInstance: RegionSamplingInstance + lateinit var largeRegionSamplingInstance: RegionSamplingInstance + + private var smallClockIsDark = true + private var largeClockIsDark = true private val configListener = object : ConfigurationController.ConfigurationListener { override fun onThemeChanged() { - clock?.events?.onColorPaletteChanged( - resources, - smallClockIsDark, - largeClockIsDark - ) + updateFun.updateColors() } } @@ -209,9 +186,6 @@ class ClockEventController @Inject constructor( init { isDozing = statusBarStateController.isDozing - smallRegionSampling?.setWindowVisible(true) - largeRegionSampling?.setWindowVisible(true) - clock?.events?.onColorPaletteChanged(resources, smallClockIsDark, largeClockIsDark) } fun registerListeners() { @@ -226,8 +200,8 @@ class ClockEventController @Inject constructor( batteryController.addCallback(batteryCallback) keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback) statusBarStateController.addCallback(statusBarStateListener) - smallRegionSampling?.start(smallSamplingBounds) - largeRegionSampling?.start(largeSamplingBounds) + smallRegionSamplingInstance.startRegionSampler() + largeRegionSamplingInstance.startRegionSampler() } fun unregisterListeners() { @@ -236,8 +210,8 @@ class ClockEventController @Inject constructor( batteryController.removeCallback(batteryCallback) keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback) statusBarStateController.removeCallback(statusBarStateListener) - smallRegionSampling?.stop() - largeRegionSampling?.stop() + smallRegionSamplingInstance.stopRegionSampler() + largeRegionSamplingInstance.stopRegionSampler() } /** @@ -246,8 +220,8 @@ class ClockEventController @Inject constructor( fun dump(pw: PrintWriter) { pw.println(this) clock?.dump(pw) - smallRegionSampling?.dump(pw) - largeRegionSampling?.dump(pw) + smallRegionSamplingInstance.dump(pw) + largeRegionSamplingInstance.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 802194464b62c..914d94522e83f 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt @@ -107,13 +107,15 @@ class ClockEventControllerTest : SysuiTestCase() { @Test fun themeChanged_verifyClockPaletteUpdated() { clockEventController.clock = clock + verify(events).onColorPaletteChanged(any(), any(), any()) + clockEventController.registerListeners() val captor = argumentCaptor() verify(configurationController).addCallback(capture(captor)) captor.value.onThemeChanged() - verify(events).onColorPaletteChanged(any(), any(), any()) + verify(events, times(2)).onColorPaletteChanged(any(), any(), any()) } @Test @@ -257,6 +259,7 @@ class ClockEventControllerTest : SysuiTestCase() { @Test fun unregisterListeners_validate() { + clockEventController.clock = clock clockEventController.unregisterListeners() verify(broadcastDispatcher).unregisterReceiver(any()) verify(configurationController).removeCallback(any()) From a823b466cc4f69446eb070303a1ee735d40c0c73 Mon Sep 17 00:00:00 2001 From: Hawkwood Glazier Date: Wed, 24 Aug 2022 16:24:18 +0000 Subject: [PATCH 2/4] [DO NOT MERGE] Additional Tests for DefaultClock DefaultClock needed additional units as coverage of much of that class was too low. This additionally adds an animation disable flag into AnimatableClockView for use by the screenshot test. Bug: 229771520 Test: atest DefaultClockProviderTest Change-Id: I7d585cedb9b43ac0fb6405e36bec99ee8a246a61 --- .../shared/clocks/AnimatableClockView.kt | 22 ++--- .../shared/clocks/DefaultClockProvider.kt | 3 +- .../shared/clocks/DefaultClockProviderTest.kt | 90 +++++++++++++++++-- 3 files changed, 99 insertions(+), 16 deletions(-) diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt index 580d45375afb2..b3b75f68e71e8 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt @@ -29,6 +29,7 @@ import android.util.AttributeSet import android.widget.TextView import com.android.internal.R.attr.contentDescription import com.android.internal.R.attr.format +import com.android.internal.annotations.VisibleForTesting import com.android.systemui.animation.GlyphCallback import com.android.systemui.animation.Interpolators import com.android.systemui.animation.TextAnimator @@ -77,7 +78,8 @@ class AnimatableClockView @JvmOverloads constructor( private var textAnimator: TextAnimator? = null private var onTextAnimatorInitialized: Runnable? = null - var timeOverrideInMillis: Long? = null + @VisibleForTesting var isAnimationEnabled: Boolean = true + @VisibleForTesting var timeOverrideInMillis: Long? = null val dozingWeight: Int get() = if (useBoldedVersion()) dozingWeightInternal + 100 else dozingWeightInternal @@ -218,7 +220,7 @@ class AnimatableClockView @JvmOverloads constructor( } fun animateAppearOnLockscreen() { - if (textAnimator == null) { + if (isAnimationEnabled && textAnimator == null) { return } setTextStyle( @@ -234,7 +236,7 @@ class AnimatableClockView @JvmOverloads constructor( weight = lockScreenWeight, textSize = -1f, color = lockScreenColor, - animate = true, + animate = isAnimationEnabled, duration = APPEAR_ANIM_DURATION, delay = 0, onAnimationEnd = null @@ -242,7 +244,7 @@ class AnimatableClockView @JvmOverloads constructor( } fun animateFoldAppear(animate: Boolean = true) { - if (textAnimator == null) { + if (isAnimationEnabled && textAnimator == null) { return } setTextStyle( @@ -258,7 +260,7 @@ class AnimatableClockView @JvmOverloads constructor( weight = dozingWeightInternal, textSize = -1f, color = dozingColor, - animate = animate, + animate = animate && isAnimationEnabled, interpolator = Interpolators.EMPHASIZED_DECELERATE, duration = ANIMATION_DURATION_FOLD_TO_AOD.toLong(), delay = 0, @@ -276,7 +278,7 @@ class AnimatableClockView @JvmOverloads constructor( weight = if (isDozing()) dozingWeight else lockScreenWeight, textSize = -1f, color = null, - animate = true, + animate = isAnimationEnabled, duration = CHARGE_ANIM_DURATION_PHASE_1, delay = 0, onAnimationEnd = null @@ -286,7 +288,7 @@ class AnimatableClockView @JvmOverloads constructor( weight = if (isDozing()) lockScreenWeight else dozingWeight, textSize = -1f, color = null, - animate = true, + animate = isAnimationEnabled, duration = CHARGE_ANIM_DURATION_PHASE_0, delay = chargeAnimationDelay.toLong(), onAnimationEnd = startAnimPhase2 @@ -298,7 +300,7 @@ class AnimatableClockView @JvmOverloads constructor( weight = if (isDozing) dozingWeight else lockScreenWeight, textSize = -1f, color = if (isDozing) dozingColor else lockScreenColor, - animate = animate, + animate = animate && isAnimationEnabled, duration = DOZE_ANIM_DURATION, delay = 0, onAnimationEnd = null @@ -332,7 +334,7 @@ class AnimatableClockView @JvmOverloads constructor( weight = weight, textSize = textSize, color = color, - animate = animate, + animate = animate && isAnimationEnabled, duration = duration, interpolator = interpolator, delay = delay, @@ -370,7 +372,7 @@ class AnimatableClockView @JvmOverloads constructor( weight = weight, textSize = textSize, color = color, - animate = animate, + animate = animate && isAnimationEnabled, interpolator = null, duration = duration, delay = delay, 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 d881cd1e24154..2099f165b0792 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 @@ -19,6 +19,7 @@ import android.graphics.drawable.Drawable import android.icu.text.NumberFormat import android.util.TypedValue import android.view.LayoutInflater +import com.android.internal.annotations.VisibleForTesting import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.Clock import com.android.systemui.plugins.ClockAnimations @@ -221,7 +222,7 @@ class DefaultClock( override fun dump(pw: PrintWriter) = clocks.forEach { it.dump(pw) } companion object { - private const val DOZE_COLOR = Color.WHITE + @VisibleForTesting const val DOZE_COLOR = Color.WHITE private const val FORMAT_NUMBER = 1234567890 } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt index 78694480ad5b6..2f22455f8fe05 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt @@ -19,17 +19,27 @@ package com.android.systemui.shared.clocks import android.content.res.Resources import android.graphics.drawable.Drawable import android.testing.AndroidTestingRunner +import android.util.TypedValue import android.view.LayoutInflater import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.shared.clocks.DefaultClock.Companion.DOZE_COLOR +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.mock +import java.util.Locale +import java.util.TimeZone import junit.framework.Assert.assertEquals import junit.framework.Assert.assertNotNull import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyFloat +import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock +import org.mockito.Mockito.times +import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.junit.MockitoJUnit @@ -39,7 +49,8 @@ class DefaultClockProviderTest : SysuiTestCase() { @JvmField @Rule val mockito = MockitoJUnit.rule() - @Mock private lateinit var mockClockView: AnimatableClockView + @Mock private lateinit var mockSmallClockView: AnimatableClockView + @Mock private lateinit var mockLargeClockView: AnimatableClockView @Mock private lateinit var layoutInflater: LayoutInflater @Mock private lateinit var mockClockThumbnail: Drawable @Mock private lateinit var resources: Resources @@ -48,9 +59,9 @@ class DefaultClockProviderTest : SysuiTestCase() { @Before fun setUp() { whenever(layoutInflater.inflate(R.layout.clock_default_small, null)) - .thenReturn(mockClockView) + .thenReturn(mockSmallClockView) whenever(layoutInflater.inflate(R.layout.clock_default_large, null)) - .thenReturn(mockClockView) + .thenReturn(mockLargeClockView) whenever(resources.getDrawable(R.drawable.clock_default_thumbnail, null)) .thenReturn(mockClockThumbnail) @@ -71,7 +82,76 @@ class DefaultClockProviderTest : SysuiTestCase() { // Default clock provider must always provide the default clock val clock = provider.createClock(DEFAULT_CLOCK_ID) assertNotNull(clock) - assertEquals(clock.smallClock, mockClockView) - assertEquals(clock.largeClock, mockClockView) + assertEquals(clock.smallClock, mockSmallClockView) + assertEquals(clock.largeClock, mockLargeClockView) + } + + @Test + fun defaultClock_initialize() { + val clock = provider.createClock(DEFAULT_CLOCK_ID) + clock.initialize(resources, 0f, 0f) + + verify(mockSmallClockView, times(2)).setColors(eq(DOZE_COLOR), anyInt()) + verify(mockLargeClockView, times(2)).setColors(eq(DOZE_COLOR), anyInt()) + verify(mockSmallClockView).refreshTime() + verify(mockLargeClockView).refreshTime() + } + + @Test + fun defaultClock_events_onTimeTick() { + val clock = provider.createClock(DEFAULT_CLOCK_ID) + clock.events.onTimeTick() + + verify(mockSmallClockView).refreshTime() + verify(mockLargeClockView).refreshTime() + } + + @Test + fun defaultClock_events_onTimeFormatChanged() { + val clock = provider.createClock(DEFAULT_CLOCK_ID) + clock.events.onTimeFormatChanged(true) + + verify(mockSmallClockView).refreshFormat(true) + verify(mockLargeClockView).refreshFormat(true) + } + + @Test + fun defaultClock_events_onTimeZoneChanged() { + val timeZone = mock() + val clock = provider.createClock(DEFAULT_CLOCK_ID) + clock.events.onTimeZoneChanged(timeZone) + + verify(mockSmallClockView).onTimeZoneChanged(timeZone) + verify(mockLargeClockView).onTimeZoneChanged(timeZone) + } + + @Test + fun defaultClock_events_onFontSettingChanged() { + val clock = provider.createClock(DEFAULT_CLOCK_ID) + clock.events.onFontSettingChanged() + + verify(mockSmallClockView).setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), anyFloat()) + verify(mockLargeClockView).setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), anyFloat()) + verify(mockLargeClockView).setPadding(eq(0), anyInt(), eq(0), eq(0)) + } + + @Test + fun defaultClock_events_onColorPaletteChanged() { + val clock = provider.createClock(DEFAULT_CLOCK_ID) + clock.events.onColorPaletteChanged(resources, true, true) + + verify(mockSmallClockView, times(2)).setColors(eq(DOZE_COLOR), anyInt()) + verify(mockLargeClockView, times(2)).setColors(eq(DOZE_COLOR), anyInt()) + } + + @Test + fun defaultClock_events_onLocaleChanged() { + val clock = provider.createClock(DEFAULT_CLOCK_ID) + clock.events.onLocaleChanged(Locale.getDefault()) + + verify(mockSmallClockView, times(2)).setLineSpacingScale(anyFloat()) + verify(mockLargeClockView, times(2)).setLineSpacingScale(anyFloat()) + verify(mockSmallClockView, times(2)).refreshFormat() + verify(mockLargeClockView, times(2)).refreshFormat() } } From 6a62f99b50598bc0c4d3383cd1ec0982489b73ba Mon Sep 17 00:00:00 2001 From: Hawkwood Glazier Date: Tue, 2 Aug 2022 16:49:33 +0000 Subject: [PATCH 3/4] [DO NOT MERGE] Correct large clock position This corrects the large clock positioning error that was introduced with Ia053aaec6987e00de980388a6c024d8bcf5203a2. It does this by rearranging the layout slightly to get back to the same position. Of note: - Previously the margin for the large clock was computed dynamically and applied to the large clock frame from a static resource and dynamic value based on the font. Now the static portion is applied directly from the resource to the clock frame in the layout resource. The dynamic portion is applied to the AnimatableClockView directly instead of it's parent as before. - ChildClipping has been disabled on the parent view as the dynamic portion of this margin moves the AnimatableClockView outside of it's parent's bounds. - The margin that is now applied to the AnimatableClockView is scaled by 0.5 to account produce the ccorrect placement after center-aligning the view in it's parent. Before the full value was applied to the parent, creating an equivalent effect. This also fixes the clock translation issue when the splitshade appears and disappears. They were both fundamentally layout issues with the refactored clock code. This change was manually tested by flashing each device and comparing the clock position in every configuration against a refenece image from a dogfood build. Additionally the motion of the clock was validated when the splitshade appears and disappears on a tablet in landscape. Test: Manual validated screenshots from several devices against reference images from a known good build. Additionally validated with a screenshot test, although golden images had to be updated. Bug: 229771520 Fixes: 241083568 Fixes: 241084042 Change-Id: I273c2996ff67c7b5f77c6bafb292d53275c7bc47 --- .../layout/keyguard_clock_switch.xml | 10 +- packages/SystemUI/res/values/dimens.xml | 2 +- .../shared/res/layout/clock_default_small.xml | 2 +- .../shared/clocks/DefaultClockProvider.kt | 91 +++++++++++-------- .../android/keyguard/KeyguardClockSwitch.java | 7 +- .../KeyguardClockSwitchController.java | 5 +- .../shared/clocks/DefaultClockProviderTest.kt | 14 ++- 7 files changed, 72 insertions(+), 59 deletions(-) diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml index 8b8ebf00e190d..3ad7c8c4369ca 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml @@ -23,6 +23,7 @@ android:id="@+id/keyguard_clock_container" android:layout_width="match_parent" android:layout_height="wrap_content" + android:clipChildren="false" android:layout_gravity="center_horizontal|top"> - + android:paddingStart="@dimen/clock_padding_start" /> - + android:layout_marginTop="@dimen/keyguard_large_clock_top_margin" + android:visibility="gone" /> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index a77575418e5f2..e3be36503c873 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -669,7 +669,7 @@ 12dp - 100dp + -60dp 32dp diff --git a/packages/SystemUI/shared/res/layout/clock_default_small.xml b/packages/SystemUI/shared/res/layout/clock_default_small.xml index 390ff5e3ff787..ff6d7f9e22403 100644 --- a/packages/SystemUI/shared/res/layout/clock_default_small.xml +++ b/packages/SystemUI/shared/res/layout/clock_default_small.xml @@ -18,7 +18,7 @@ --> Date: Wed, 24 Aug 2022 16:01:45 +0000 Subject: [PATCH 4/4] [DO NOT MERGE] Initialize TimeZone during DefaultClockProvider init This is a duplication of Ie8b08bec36bccfda5a1f1eb20c91a040c1f688ab for the refactored clock code. It's validated via unit test as it has proved somewhat tricky to reproduce manually. Test: atest DefaultClockProviderTest Fixes: 241729527 Change-Id: I0c664750190572790e71f6095a1ac8c4995c83ca --- .../com/android/systemui/shared/clocks/DefaultClockProvider.kt | 1 + .../android/systemui/shared/clocks/DefaultClockProviderTest.kt | 3 +++ 2 files changed, 4 insertions(+) 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 5c20b691b9910..b5e57667fbb83 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 @@ -118,6 +118,7 @@ class DefaultClock( recomputePadding() animations = DefaultClockAnimations(dozeFraction, foldFraction) events.onColorPaletteChanged(resources, true, true) + events.onTimeZoneChanged(TimeZone.getDefault()) events.onTimeTick() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt index a978294c98eca..2b4a109282ce1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt @@ -40,6 +40,7 @@ import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyFloat import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.notNull import org.mockito.Mock import org.mockito.Mockito.times import org.mockito.Mockito.verify @@ -98,6 +99,8 @@ class DefaultClockProviderTest : SysuiTestCase() { verify(mockSmallClockView, times(2)).setColors(eq(DOZE_COLOR), anyInt()) verify(mockLargeClockView, times(2)).setColors(eq(DOZE_COLOR), anyInt()) + verify(mockSmallClockView).onTimeZoneChanged(notNull()) + verify(mockLargeClockView).onTimeZoneChanged(notNull()) verify(mockSmallClockView).refreshTime() verify(mockLargeClockView).refreshTime() verify(mockLargeClockView).setLayoutParams(any())