/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.systemui.shared.clocks import android.content.Context import android.content.res.Resources import android.graphics.Color import android.graphics.drawable.Drawable import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.util.TypedValue import android.view.LayoutInflater import android.widget.FrameLayout import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.customization.R import com.android.systemui.plugins.keyguard.ui.clocks.ClockId import com.android.systemui.plugins.keyguard.ui.clocks.ClockSettings import com.android.systemui.plugins.keyguard.ui.clocks.ThemeConfig import com.android.systemui.plugins.keyguard.ui.clocks.TimeFormatKind import com.android.systemui.shared.Flags import com.android.systemui.shared.clocks.DefaultClockController.Companion.DOZE_COLOR import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import java.util.Locale 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.anyBoolean import org.mockito.ArgumentMatchers.anyFloat import org.mockito.ArgumentMatchers.notNull import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.junit.MockitoJUnit private fun DefaultClockProvider.createClock( context: Context, id: ClockId, ): DefaultClockController { return createClock(context, ClockSettings(id, null)) as DefaultClockController } @RunWith(AndroidJUnit4::class) @SmallTest class DefaultClockProviderTest : SysuiTestCase() { @JvmField @Rule val mockito = MockitoJUnit.rule() @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 private lateinit var provider: DefaultClockProvider @Before fun setUp() { whenever(layoutInflater.inflate(eq(R.layout.clock_default_small), any(), anyBoolean())) .thenReturn(mockSmallClockView) whenever(layoutInflater.inflate(eq(R.layout.clock_default_large), any(), anyBoolean())) .thenReturn(mockLargeClockView) whenever(resources.getString(R.string.clock_default_name)).thenReturn("DEFAULT_CLOCK_NAME") whenever(resources.getString(R.string.clock_default_description)) .thenReturn("DEFAULT_CLOCK_DESC") whenever(resources.getDrawable(R.drawable.clock_default_thumbnail, null)) .thenReturn(mockClockThumbnail) whenever(mockSmallClockView.getLayoutParams()).thenReturn(FrameLayout.LayoutParams(10, 10)) whenever(mockLargeClockView.getLayoutParams()).thenReturn(FrameLayout.LayoutParams(10, 10)) provider = DefaultClockProvider(layoutInflater, resources, vibrator = null) } @Test fun providedClocks_matchesFactory() { // All providers need to provide clocks & thumbnails for exposed clocks for (metadata in provider.getClocks()) { assertNotNull(provider.createClock(context, metadata.clockId)) assertNotNull(provider.getClockPickerConfig(ClockSettings(metadata.clockId))) } } @Test fun defaultClock_alwaysProvided() { // Default clock provider must always provide the default clock val clock = provider.createClock(context, DEFAULT_CLOCK_ID) assertNotNull(clock) assertEquals(mockSmallClockView, clock.smallClock.view) assertEquals(mockLargeClockView, clock.largeClock.view) } @Test @DisableFlags(Flags.FLAG_AMBIENT_AOD) fun defaultClock_initialize_flagOff() { val clock = provider.createClock(context, DEFAULT_CLOCK_ID) verify(mockSmallClockView).setColors(DOZE_COLOR, Color.MAGENTA) verify(mockLargeClockView).setColors(DOZE_COLOR, Color.MAGENTA) clock.initialize(true, 0f, 0f) // This is the default darkTheme color val expectedColor = context.resources.getColor(android.R.color.system_accent1_100) verify(mockSmallClockView).setColors(DOZE_COLOR, expectedColor) verify(mockLargeClockView).setColors(DOZE_COLOR, expectedColor) verify(mockSmallClockView).onTimeZoneChanged(notNull()) verify(mockLargeClockView).onTimeZoneChanged(notNull()) verify(mockSmallClockView).refreshTime() verify(mockLargeClockView).refreshTime() } @Test @EnableFlags(Flags.FLAG_AMBIENT_AOD) fun defaultClock_initialize() { val expectedAodColor = context.resources.getColor(android.R.color.system_accent1_100) val clock = provider.createClock(context, DEFAULT_CLOCK_ID) verify(mockSmallClockView).setColors(expectedAodColor, Color.MAGENTA) verify(mockLargeClockView).setColors(expectedAodColor, Color.MAGENTA) clock.initialize(true, 0f, 0f) val expectedColor = Color.MAGENTA verify(mockSmallClockView).setColors(expectedAodColor, expectedColor) verify(mockLargeClockView).setColors(expectedAodColor, expectedColor) verify(mockSmallClockView).onTimeZoneChanged(notNull()) verify(mockLargeClockView).onTimeZoneChanged(notNull()) verify(mockSmallClockView).refreshTime() verify(mockLargeClockView).refreshTime() } @Test fun defaultClock_events_onTimeTick() { val clock = provider.createClock(context, DEFAULT_CLOCK_ID) clock.smallClock.events.onTimeTick() clock.largeClock.events.onTimeTick() verify(mockSmallClockView).refreshTime() verify(mockLargeClockView).refreshTime() } @Test fun defaultClock_events_onTimeFormatChanged() { val clock = provider.createClock(context, DEFAULT_CLOCK_ID) clock.events.onTimeFormatChanged(TimeFormatKind.FULL_DAY) verify(mockSmallClockView).refreshFormat(true) verify(mockLargeClockView).refreshFormat(true) } @Test fun defaultSmallClock_events_onFontSettingChanged() { val clock = provider.createClock(context, DEFAULT_CLOCK_ID) clock.smallClock.events.onFontSettingChanged(100f) verify(mockSmallClockView).setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), eq(100f)) } @Test fun defaultLargeClock_events_onFontSettingChanged() { val clock = provider.createClock(context, DEFAULT_CLOCK_ID) clock.largeClock.events.onFontSettingChanged(200f) verify(mockLargeClockView).setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), eq(200f)) } @Test @DisableFlags(Flags.FLAG_AMBIENT_AOD) fun defaultClock_events_onThemeChanged_noSeed_flagOff() { // This is the default darkTheme color val expectedColor = context.resources.getColor(android.R.color.system_accent1_100) val clock = provider.createClock(context, DEFAULT_CLOCK_ID) verify(mockSmallClockView).setColors(DOZE_COLOR, Color.MAGENTA) verify(mockLargeClockView).setColors(DOZE_COLOR, Color.MAGENTA) clock.smallClock.events.onThemeChanged(ThemeConfig(true, null)) clock.largeClock.events.onThemeChanged(ThemeConfig(true, null)) verify(mockSmallClockView).setColors(DOZE_COLOR, expectedColor) verify(mockLargeClockView).setColors(DOZE_COLOR, expectedColor) } @Test @EnableFlags(Flags.FLAG_AMBIENT_AOD) fun defaultClock_events_onThemeChanged_noSeedn() { val expectedColor = Color.TRANSPARENT val clock = provider.createClock(context, DEFAULT_CLOCK_ID) val expectedAodColor = context.resources.getColor(android.R.color.system_accent1_100) verify(mockSmallClockView).setColors(expectedAodColor, Color.MAGENTA) verify(mockLargeClockView).setColors(expectedAodColor, Color.MAGENTA) clock.smallClock.events.onThemeChanged(ThemeConfig(true, null)) clock.largeClock.events.onThemeChanged(ThemeConfig(true, null)) verify(mockSmallClockView).setColors(expectedAodColor, Color.MAGENTA) verify(mockLargeClockView).setColors(expectedAodColor, Color.MAGENTA) } @Test @DisableFlags(Flags.FLAG_AMBIENT_AOD) fun defaultClock_events_onThemeChanged_newSeed_flagOff() { val initSeedColor = 10 val newSeedColor = 20 val clock = provider.createClock(context, ClockSettings(DEFAULT_CLOCK_ID, initSeedColor)) verify(mockSmallClockView).setColors(DOZE_COLOR, initSeedColor) verify(mockLargeClockView).setColors(DOZE_COLOR, initSeedColor) clock.smallClock.events.onThemeChanged(ThemeConfig(true, newSeedColor)) clock.largeClock.events.onThemeChanged(ThemeConfig(true, newSeedColor)) verify(mockSmallClockView).setColors(DOZE_COLOR, newSeedColor) verify(mockLargeClockView).setColors(DOZE_COLOR, newSeedColor) } @Test @EnableFlags(Flags.FLAG_AMBIENT_AOD) fun defaultClock_events_onThemeChanged_newSeed() { val initSeedColor = 10 val newSeedColor = 20 val clock = provider.createClock(context, ClockSettings(DEFAULT_CLOCK_ID, initSeedColor)) val expectedAodColor = context.resources.getColor(android.R.color.system_accent1_100) verify(mockSmallClockView).setColors(expectedAodColor, initSeedColor) verify(mockLargeClockView).setColors(expectedAodColor, initSeedColor) clock.smallClock.events.onThemeChanged(ThemeConfig(true, newSeedColor)) clock.largeClock.events.onThemeChanged(ThemeConfig(true, newSeedColor)) verify(mockSmallClockView).setColors(expectedAodColor, newSeedColor) verify(mockLargeClockView).setColors(expectedAodColor, newSeedColor) } @Test fun defaultClock_events_onLocaleChanged() { val clock = provider.createClock(context, 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() } @Test fun test_aodClock_always_whiteColor() { val clock = provider.createClock(context, DEFAULT_CLOCK_ID) clock.smallClock.animations.doze(0.9f) // set AOD mode to active clock.smallClock.events.onThemeChanged(ThemeConfig(true, null)) verify((clock.smallClock.view as AnimatableClockView), never()).animateAppearOnLockscreen() } }