Loading packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt +6 −3 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ import android.app.ActivityManager import android.app.UserSwitchObserver import android.content.Context import android.database.ContentObserver import android.graphics.drawable.Drawable import android.net.Uri import android.os.UserHandle import android.provider.Settings Loading @@ -33,6 +32,7 @@ import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockId import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockMetadata import com.android.systemui.plugins.clocks.ClockPickerConfig import com.android.systemui.plugins.clocks.ClockProvider import com.android.systemui.plugins.clocks.ClockProviderPlugin import com.android.systemui.plugins.clocks.ClockSettings Loading Loading @@ -341,6 +341,7 @@ open class ClockRegistry( } private var isClockChanged = AtomicBoolean(false) private fun triggerOnCurrentClockChanged() { val shouldSchedule = isClockChanged.compareAndSet(false, true) if (!shouldSchedule) { Loading @@ -355,6 +356,7 @@ open class ClockRegistry( } private var isClockListChanged = AtomicBoolean(false) private fun triggerOnAvailableClocksChanged() { val shouldSchedule = isClockListChanged.compareAndSet(false, true) if (!shouldSchedule) { Loading Loading @@ -458,6 +460,7 @@ open class ClockRegistry( } private var isQueued = AtomicBoolean(false) fun verifyLoadedProviders() { val shouldSchedule = isQueued.compareAndSet(false, true) if (!shouldSchedule) { Loading Loading @@ -565,8 +568,8 @@ open class ClockRegistry( return availableClocks.map { (_, clock) -> clock.metadata } } fun getClockThumbnail(clockId: ClockId): Drawable? = availableClocks[clockId]?.provider?.getClockThumbnail(clockId) fun getClockPickerConfig(clockId: ClockId): ClockPickerConfig? = availableClocks[clockId]?.provider?.getClockPickerConfig(clockId) fun createExampleClock(clockId: ClockId): ClockController? = createClock(clockId) Loading packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt +9 −4 Original line number Diff line number Diff line Loading @@ -15,13 +15,13 @@ package com.android.systemui.shared.clocks import android.content.Context import android.content.res.Resources import android.graphics.drawable.Drawable import android.view.LayoutInflater import com.android.systemui.customization.R import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockId import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockMetadata import com.android.systemui.plugins.clocks.ClockPickerConfig import com.android.systemui.plugins.clocks.ClockProvider import com.android.systemui.plugins.clocks.ClockSettings Loading Loading @@ -60,12 +60,17 @@ class DefaultClockProvider( ) } override fun getClockThumbnail(id: ClockId): Drawable? { override fun getClockPickerConfig(id: ClockId): ClockPickerConfig { if (id != DEFAULT_CLOCK_ID) { throw IllegalArgumentException("$id is unsupported by $TAG") } return ClockPickerConfig( DEFAULT_CLOCK_ID, resources.getString(R.string.clock_default_name), resources.getString(R.string.clock_default_description), // TODO(b/352049256): Update placeholder to actual resource return resources.getDrawable(R.drawable.clock_default_thumbnail, null) resources.getDrawable(R.drawable.clock_default_thumbnail, null), ) } } packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt +23 −3 Original line number Diff line number Diff line Loading @@ -50,8 +50,8 @@ interface ClockProvider { /** Initializes and returns the target clock design */ fun createClock(settings: ClockSettings): ClockController /** A static thumbnail for rendering in some examples */ fun getClockThumbnail(id: ClockId): Drawable? /** Settings configuration parameters for the clock */ fun getClockPickerConfig(id: ClockId): ClockPickerConfig } /** Interface for controlling an active clock */ Loading Loading @@ -133,6 +133,7 @@ class DefaultClockFaceLayout(val view: View) : ClockFaceLayout { // both small and large clock should have a container (RelativeLayout in // SimpleClockFaceController) override val views = listOf(view) override fun applyConstraints(constraints: ConstraintSet): ConstraintSet { if (views.size != 1) { throw IllegalArgumentException( Loading Loading @@ -267,6 +268,25 @@ data class ClockMetadata( val clockId: ClockId, ) data class ClockPickerConfig( val id: String, /** Localized name of the clock */ val name: String, /** Localized accessibility description for the clock */ val description: String, /* Static & lightweight thumbnail version of the clock */ val thumbnail: Drawable, /** True if the clock will react to tone changes in the seed color */ val isReactiveToTone: Boolean = true, /** True if the clock is capable of chagning style in reaction to touches */ val isReactiveToTouch: Boolean = false, ) /** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */ data class ClockConfig( val id: String, Loading @@ -280,7 +300,7 @@ data class ClockConfig( /** Transition to AOD should move smartspace like large clock instead of small clock */ val useAlternateSmartspaceAODTransition: Boolean = false, /** True if the clock will react to tone changes in the seed color. */ @Deprecated("TODO(b/352049256): Remove") val isReactiveToTone: Boolean = true, /** True if the clock is large frame clock, which will use weather in compose. */ Loading packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +26 −14 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockId import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockMetadata import com.android.systemui.plugins.clocks.ClockPickerConfig import com.android.systemui.plugins.clocks.ClockProviderPlugin import com.android.systemui.plugins.clocks.ClockSettings import com.android.systemui.plugins.PluginLifecycleManager Loading Loading @@ -74,6 +75,7 @@ class ClockRegistryTest : SysuiTestCase() { private lateinit var fakeDefaultProvider: FakeClockPlugin private lateinit var pluginListener: PluginListener<ClockProviderPlugin> private lateinit var registry: ClockRegistry private lateinit var pickerConfig: ClockPickerConfig private val featureFlags = FakeFeatureFlags() companion object { Loading @@ -82,9 +84,9 @@ class ClockRegistryTest : SysuiTestCase() { return null!! } private fun failThumbnail(clockId: ClockId): Drawable? { fail("Unexpected call to getThumbnail: $clockId") return null private fun failPickerConfig(clockId: ClockId): ClockPickerConfig { fail("Unexpected call to getClockPickerConfig: $clockId") return null!! } } Loading Loading @@ -123,22 +125,31 @@ class ClockRegistryTest : SysuiTestCase() { private class FakeClockPlugin : ClockProviderPlugin { private val metadata = mutableListOf<ClockMetadata>() private val createCallbacks = mutableMapOf<ClockId, (ClockId) -> ClockController>() private val thumbnailCallbacks = mutableMapOf<ClockId, (ClockId) -> Drawable?>() private val pickerConfigs = mutableMapOf<ClockId, (ClockId) -> ClockPickerConfig>() override fun getClocks() = metadata override fun createClock(settings: ClockSettings): ClockController = createCallbacks[settings.clockId!!]!!(settings.clockId!!) override fun getClockThumbnail(id: ClockId): Drawable? = thumbnailCallbacks[id]!!(id) override fun createClock(settings: ClockSettings): ClockController { val clockId = settings.clockId ?: throw IllegalArgumentException("No clockId specified") return createCallbacks[clockId]?.invoke(clockId) ?: throw NotImplementedError("No callback for '$clockId'") } override fun getClockPickerConfig(clockId: ClockId): ClockPickerConfig { return pickerConfigs[clockId]?.invoke(clockId) ?: throw NotImplementedError("No picker config for '$clockId'") } override fun initialize(buffers: ClockMessageBuffers?) { } fun addClock( id: ClockId, create: (ClockId) -> ClockController = ::failFactory, getThumbnail: (ClockId) -> Drawable? = ::failThumbnail getPickerConfig: (ClockId) -> ClockPickerConfig = ::failPickerConfig ): FakeClockPlugin { metadata.add(ClockMetadata(id)) createCallbacks[id] = create thumbnailCallbacks[id] = getThumbnail pickerConfigs[id] = getPickerConfig return this } } Loading @@ -148,9 +159,10 @@ class ClockRegistryTest : SysuiTestCase() { scheduler = TestCoroutineScheduler() dispatcher = StandardTestDispatcher(scheduler) scope = TestScope(dispatcher) pickerConfig = ClockPickerConfig("CLOCK_ID", "NAME", "DESC", mockThumbnail) fakeDefaultProvider = FakeClockPlugin() .addClock(DEFAULT_CLOCK_ID, { mockDefaultClock }, { mockThumbnail }) .addClock(DEFAULT_CLOCK_ID, { mockDefaultClock }, { pickerConfig }) whenever(mockContext.contentResolver).thenReturn(mockContentResolver) val captor = argumentCaptor<PluginListener<ClockProviderPlugin>>() Loading Loading @@ -215,8 +227,8 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun clockIdConflict_ErrorWithoutCrash_unloadDuplicate() { val plugin1 = FakeClockPlugin() .addClock("clock_1", { mockClock }, { mockThumbnail }) .addClock("clock_2", { mockClock }, { mockThumbnail }) .addClock("clock_1", { mockClock }, { pickerConfig }) .addClock("clock_2", { mockClock }, { pickerConfig }) val lifecycle1 = spy(FakeLifecycle("1", plugin1)) val plugin2 = FakeClockPlugin() Loading @@ -238,8 +250,8 @@ class ClockRegistryTest : SysuiTestCase() { assertEquals(registry.createExampleClock("clock_1"), mockClock) assertEquals(registry.createExampleClock("clock_2"), mockClock) assertEquals(registry.getClockThumbnail("clock_1"), mockThumbnail) assertEquals(registry.getClockThumbnail("clock_2"), mockThumbnail) assertEquals(registry.getClockPickerConfig("clock_1"), pickerConfig) assertEquals(registry.getClockPickerConfig("clock_2"), pickerConfig) verify(lifecycle1, never()).unloadPlugin() verify(lifecycle2, times(2)).unloadPlugin() } Loading packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt +5 −1 Original line number Diff line number Diff line Loading @@ -72,6 +72,10 @@ class DefaultClockProviderTest : SysuiTestCase() { .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)) Loading @@ -85,7 +89,7 @@ class DefaultClockProviderTest : SysuiTestCase() { // All providers need to provide clocks & thumbnails for exposed clocks for (metadata in provider.getClocks()) { assertNotNull(provider.createClock(metadata.clockId)) assertNotNull(provider.getClockThumbnail(metadata.clockId)) assertNotNull(provider.getClockPickerConfig(metadata.clockId)) } } Loading Loading
packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt +6 −3 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ import android.app.ActivityManager import android.app.UserSwitchObserver import android.content.Context import android.database.ContentObserver import android.graphics.drawable.Drawable import android.net.Uri import android.os.UserHandle import android.provider.Settings Loading @@ -33,6 +32,7 @@ import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockId import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockMetadata import com.android.systemui.plugins.clocks.ClockPickerConfig import com.android.systemui.plugins.clocks.ClockProvider import com.android.systemui.plugins.clocks.ClockProviderPlugin import com.android.systemui.plugins.clocks.ClockSettings Loading Loading @@ -341,6 +341,7 @@ open class ClockRegistry( } private var isClockChanged = AtomicBoolean(false) private fun triggerOnCurrentClockChanged() { val shouldSchedule = isClockChanged.compareAndSet(false, true) if (!shouldSchedule) { Loading @@ -355,6 +356,7 @@ open class ClockRegistry( } private var isClockListChanged = AtomicBoolean(false) private fun triggerOnAvailableClocksChanged() { val shouldSchedule = isClockListChanged.compareAndSet(false, true) if (!shouldSchedule) { Loading Loading @@ -458,6 +460,7 @@ open class ClockRegistry( } private var isQueued = AtomicBoolean(false) fun verifyLoadedProviders() { val shouldSchedule = isQueued.compareAndSet(false, true) if (!shouldSchedule) { Loading Loading @@ -565,8 +568,8 @@ open class ClockRegistry( return availableClocks.map { (_, clock) -> clock.metadata } } fun getClockThumbnail(clockId: ClockId): Drawable? = availableClocks[clockId]?.provider?.getClockThumbnail(clockId) fun getClockPickerConfig(clockId: ClockId): ClockPickerConfig? = availableClocks[clockId]?.provider?.getClockPickerConfig(clockId) fun createExampleClock(clockId: ClockId): ClockController? = createClock(clockId) Loading
packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt +9 −4 Original line number Diff line number Diff line Loading @@ -15,13 +15,13 @@ package com.android.systemui.shared.clocks import android.content.Context import android.content.res.Resources import android.graphics.drawable.Drawable import android.view.LayoutInflater import com.android.systemui.customization.R import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockId import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockMetadata import com.android.systemui.plugins.clocks.ClockPickerConfig import com.android.systemui.plugins.clocks.ClockProvider import com.android.systemui.plugins.clocks.ClockSettings Loading Loading @@ -60,12 +60,17 @@ class DefaultClockProvider( ) } override fun getClockThumbnail(id: ClockId): Drawable? { override fun getClockPickerConfig(id: ClockId): ClockPickerConfig { if (id != DEFAULT_CLOCK_ID) { throw IllegalArgumentException("$id is unsupported by $TAG") } return ClockPickerConfig( DEFAULT_CLOCK_ID, resources.getString(R.string.clock_default_name), resources.getString(R.string.clock_default_description), // TODO(b/352049256): Update placeholder to actual resource return resources.getDrawable(R.drawable.clock_default_thumbnail, null) resources.getDrawable(R.drawable.clock_default_thumbnail, null), ) } }
packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt +23 −3 Original line number Diff line number Diff line Loading @@ -50,8 +50,8 @@ interface ClockProvider { /** Initializes and returns the target clock design */ fun createClock(settings: ClockSettings): ClockController /** A static thumbnail for rendering in some examples */ fun getClockThumbnail(id: ClockId): Drawable? /** Settings configuration parameters for the clock */ fun getClockPickerConfig(id: ClockId): ClockPickerConfig } /** Interface for controlling an active clock */ Loading Loading @@ -133,6 +133,7 @@ class DefaultClockFaceLayout(val view: View) : ClockFaceLayout { // both small and large clock should have a container (RelativeLayout in // SimpleClockFaceController) override val views = listOf(view) override fun applyConstraints(constraints: ConstraintSet): ConstraintSet { if (views.size != 1) { throw IllegalArgumentException( Loading Loading @@ -267,6 +268,25 @@ data class ClockMetadata( val clockId: ClockId, ) data class ClockPickerConfig( val id: String, /** Localized name of the clock */ val name: String, /** Localized accessibility description for the clock */ val description: String, /* Static & lightweight thumbnail version of the clock */ val thumbnail: Drawable, /** True if the clock will react to tone changes in the seed color */ val isReactiveToTone: Boolean = true, /** True if the clock is capable of chagning style in reaction to touches */ val isReactiveToTouch: Boolean = false, ) /** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */ data class ClockConfig( val id: String, Loading @@ -280,7 +300,7 @@ data class ClockConfig( /** Transition to AOD should move smartspace like large clock instead of small clock */ val useAlternateSmartspaceAODTransition: Boolean = false, /** True if the clock will react to tone changes in the seed color. */ @Deprecated("TODO(b/352049256): Remove") val isReactiveToTone: Boolean = true, /** True if the clock is large frame clock, which will use weather in compose. */ Loading
packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +26 −14 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockId import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockMetadata import com.android.systemui.plugins.clocks.ClockPickerConfig import com.android.systemui.plugins.clocks.ClockProviderPlugin import com.android.systemui.plugins.clocks.ClockSettings import com.android.systemui.plugins.PluginLifecycleManager Loading Loading @@ -74,6 +75,7 @@ class ClockRegistryTest : SysuiTestCase() { private lateinit var fakeDefaultProvider: FakeClockPlugin private lateinit var pluginListener: PluginListener<ClockProviderPlugin> private lateinit var registry: ClockRegistry private lateinit var pickerConfig: ClockPickerConfig private val featureFlags = FakeFeatureFlags() companion object { Loading @@ -82,9 +84,9 @@ class ClockRegistryTest : SysuiTestCase() { return null!! } private fun failThumbnail(clockId: ClockId): Drawable? { fail("Unexpected call to getThumbnail: $clockId") return null private fun failPickerConfig(clockId: ClockId): ClockPickerConfig { fail("Unexpected call to getClockPickerConfig: $clockId") return null!! } } Loading Loading @@ -123,22 +125,31 @@ class ClockRegistryTest : SysuiTestCase() { private class FakeClockPlugin : ClockProviderPlugin { private val metadata = mutableListOf<ClockMetadata>() private val createCallbacks = mutableMapOf<ClockId, (ClockId) -> ClockController>() private val thumbnailCallbacks = mutableMapOf<ClockId, (ClockId) -> Drawable?>() private val pickerConfigs = mutableMapOf<ClockId, (ClockId) -> ClockPickerConfig>() override fun getClocks() = metadata override fun createClock(settings: ClockSettings): ClockController = createCallbacks[settings.clockId!!]!!(settings.clockId!!) override fun getClockThumbnail(id: ClockId): Drawable? = thumbnailCallbacks[id]!!(id) override fun createClock(settings: ClockSettings): ClockController { val clockId = settings.clockId ?: throw IllegalArgumentException("No clockId specified") return createCallbacks[clockId]?.invoke(clockId) ?: throw NotImplementedError("No callback for '$clockId'") } override fun getClockPickerConfig(clockId: ClockId): ClockPickerConfig { return pickerConfigs[clockId]?.invoke(clockId) ?: throw NotImplementedError("No picker config for '$clockId'") } override fun initialize(buffers: ClockMessageBuffers?) { } fun addClock( id: ClockId, create: (ClockId) -> ClockController = ::failFactory, getThumbnail: (ClockId) -> Drawable? = ::failThumbnail getPickerConfig: (ClockId) -> ClockPickerConfig = ::failPickerConfig ): FakeClockPlugin { metadata.add(ClockMetadata(id)) createCallbacks[id] = create thumbnailCallbacks[id] = getThumbnail pickerConfigs[id] = getPickerConfig return this } } Loading @@ -148,9 +159,10 @@ class ClockRegistryTest : SysuiTestCase() { scheduler = TestCoroutineScheduler() dispatcher = StandardTestDispatcher(scheduler) scope = TestScope(dispatcher) pickerConfig = ClockPickerConfig("CLOCK_ID", "NAME", "DESC", mockThumbnail) fakeDefaultProvider = FakeClockPlugin() .addClock(DEFAULT_CLOCK_ID, { mockDefaultClock }, { mockThumbnail }) .addClock(DEFAULT_CLOCK_ID, { mockDefaultClock }, { pickerConfig }) whenever(mockContext.contentResolver).thenReturn(mockContentResolver) val captor = argumentCaptor<PluginListener<ClockProviderPlugin>>() Loading Loading @@ -215,8 +227,8 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun clockIdConflict_ErrorWithoutCrash_unloadDuplicate() { val plugin1 = FakeClockPlugin() .addClock("clock_1", { mockClock }, { mockThumbnail }) .addClock("clock_2", { mockClock }, { mockThumbnail }) .addClock("clock_1", { mockClock }, { pickerConfig }) .addClock("clock_2", { mockClock }, { pickerConfig }) val lifecycle1 = spy(FakeLifecycle("1", plugin1)) val plugin2 = FakeClockPlugin() Loading @@ -238,8 +250,8 @@ class ClockRegistryTest : SysuiTestCase() { assertEquals(registry.createExampleClock("clock_1"), mockClock) assertEquals(registry.createExampleClock("clock_2"), mockClock) assertEquals(registry.getClockThumbnail("clock_1"), mockThumbnail) assertEquals(registry.getClockThumbnail("clock_2"), mockThumbnail) assertEquals(registry.getClockPickerConfig("clock_1"), pickerConfig) assertEquals(registry.getClockPickerConfig("clock_2"), pickerConfig) verify(lifecycle1, never()).unloadPlugin() verify(lifecycle2, times(2)).unloadPlugin() } Loading
packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt +5 −1 Original line number Diff line number Diff line Loading @@ -72,6 +72,10 @@ class DefaultClockProviderTest : SysuiTestCase() { .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)) Loading @@ -85,7 +89,7 @@ class DefaultClockProviderTest : SysuiTestCase() { // All providers need to provide clocks & thumbnails for exposed clocks for (metadata in provider.getClocks()) { assertNotNull(provider.createClock(metadata.clockId)) assertNotNull(provider.getClockThumbnail(metadata.clockId)) assertNotNull(provider.getClockPickerConfig(metadata.clockId)) } } Loading