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

Commit bfc1ae36 authored by Hawkwood Glazier's avatar Hawkwood Glazier
Browse files

Seperate Picker configuration from controller's clock config

Bug: 352049256
Test: Manually checked the behavior
Flag: EXEMPT library code; callsites flagged
Change-Id: Icf418f851c3aea5af0df04186db4d01ebe11e5a4
parent c5384e10
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -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
@@ -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
@@ -341,6 +341,7 @@ open class ClockRegistry(
    }

    private var isClockChanged = AtomicBoolean(false)

    private fun triggerOnCurrentClockChanged() {
        val shouldSchedule = isClockChanged.compareAndSet(false, true)
        if (!shouldSchedule) {
@@ -355,6 +356,7 @@ open class ClockRegistry(
    }

    private var isClockListChanged = AtomicBoolean(false)

    private fun triggerOnAvailableClocksChanged() {
        val shouldSchedule = isClockListChanged.compareAndSet(false, true)
        if (!shouldSchedule) {
@@ -458,6 +460,7 @@ open class ClockRegistry(
    }

    private var isQueued = AtomicBoolean(false)

    fun verifyLoadedProviders() {
        val shouldSchedule = isQueued.compareAndSet(false, true)
        if (!shouldSchedule) {
@@ -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)

+9 −4
Original line number Diff line number Diff line
@@ -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

@@ -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),
        )
    }
}
+23 −3
Original line number Diff line number Diff line
@@ -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 */
@@ -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(
@@ -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,
@@ -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. */
+26 −14
Original line number Diff line number Diff line
@@ -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
@@ -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 {
@@ -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!!
        }
    }

@@ -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
        }
    }
@@ -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>>()
@@ -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()
@@ -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()
    }
+5 −1
Original line number Diff line number Diff line
@@ -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))
@@ -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))
        }
    }