Merge "Multiuser support in ClockRegistry" into tm-qpr-dev

This commit is contained in:
Hawkwood Glazier
2023-02-10 20:31:34 +00:00
committed by Android (Google) Code Review
5 changed files with 235 additions and 98 deletions

View File

@@ -13,11 +13,13 @@
*/ */
package com.android.systemui.shared.clocks package com.android.systemui.shared.clocks
import android.app.ActivityManager
import android.app.UserSwitchObserver
import android.content.Context import android.content.Context
import android.database.ContentObserver import android.database.ContentObserver
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.net.Uri import android.net.Uri
import android.os.Handler import android.os.UserHandle
import android.provider.Settings import android.provider.Settings
import android.util.Log import android.util.Log
import androidx.annotation.OpenForTesting import androidx.annotation.OpenForTesting
@@ -29,17 +31,23 @@ import com.android.systemui.plugins.ClockProviderPlugin
import com.android.systemui.plugins.ClockSettings import com.android.systemui.plugins.ClockSettings
import com.android.systemui.plugins.PluginListener import com.android.systemui.plugins.PluginListener
import com.android.systemui.plugins.PluginManager import com.android.systemui.plugins.PluginManager
import com.android.systemui.util.Assert
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
private val TAG = ClockRegistry::class.simpleName private val TAG = ClockRegistry::class.simpleName!!
private const val DEBUG = true private const val DEBUG = true
/** ClockRegistry aggregates providers and plugins */ /** ClockRegistry aggregates providers and plugins */
open class ClockRegistry( open class ClockRegistry(
val context: Context, val context: Context,
val pluginManager: PluginManager, val pluginManager: PluginManager,
val handler: Handler, val scope: CoroutineScope,
val mainDispatcher: CoroutineDispatcher,
val bgDispatcher: CoroutineDispatcher,
val isEnabled: Boolean, val isEnabled: Boolean,
userHandle: Int, val handleAllUsers: Boolean,
defaultClockProvider: ClockProvider, defaultClockProvider: ClockProvider,
val fallbackClockId: ClockId = DEFAULT_CLOCK_ID, val fallbackClockId: ClockId = DEFAULT_CLOCK_ID,
) { ) {
@@ -50,66 +58,132 @@ open class ClockRegistry(
private val availableClocks = mutableMapOf<ClockId, ClockInfo>() private val availableClocks = mutableMapOf<ClockId, ClockInfo>()
private val clockChangeListeners = mutableListOf<ClockChangeListener>() private val clockChangeListeners = mutableListOf<ClockChangeListener>()
private val settingObserver = object : ContentObserver(handler) { private val settingObserver =
override fun onChange(selfChange: Boolean, uris: Collection<Uri>, flags: Int, userId: Int) = object : ContentObserver(null) {
clockChangeListeners.forEach { it.onClockChanged() } override fun onChange(
} selfChange: Boolean,
uris: Collection<Uri>,
flags: Int,
userId: Int
) {
scope.launch(bgDispatcher) { querySettings() }
}
}
private val pluginListener = object : PluginListener<ClockProviderPlugin> { private val pluginListener =
override fun onPluginConnected(plugin: ClockProviderPlugin, context: Context) = object : PluginListener<ClockProviderPlugin> {
connectClocks(plugin) override fun onPluginConnected(plugin: ClockProviderPlugin, context: Context) =
connectClocks(plugin)
override fun onPluginDisconnected(plugin: ClockProviderPlugin) = override fun onPluginDisconnected(plugin: ClockProviderPlugin) =
disconnectClocks(plugin) disconnectClocks(plugin)
} }
open var settings: ClockSettings? private val userSwitchObserver =
get() { object : UserSwitchObserver() {
override fun onUserSwitchComplete(newUserId: Int) {
scope.launch(bgDispatcher) { querySettings() }
}
}
// TODO(b/267372164): Migrate to flows
var settings: ClockSettings? = null
get() = field
protected set(value) {
if (field != value) {
field = value
scope.launch(mainDispatcher) { onClockChanged() }
}
}
var isRegistered: Boolean = false
private set
@OpenForTesting
open fun querySettings() {
assertNotMainThread()
val result =
try { try {
val json = Settings.Secure.getString( val json =
context.contentResolver, if (handleAllUsers) {
Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE Settings.Secure.getStringForUser(
) context.contentResolver,
if (json == null || json.isEmpty()) { Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
return null ActivityManager.getCurrentUser()
} )
return ClockSettings.deserialize(json) } else {
Settings.Secure.getString(
context.contentResolver,
Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE
)
}
ClockSettings.deserialize(json)
} catch (ex: Exception) { } catch (ex: Exception) {
Log.e(TAG, "Failed to parse clock settings", ex) Log.e(TAG, "Failed to parse clock settings", ex)
return null null
} }
} settings = result
protected set(value) { }
try {
val json = if (value != null) {
value._applied_timestamp = System.currentTimeMillis()
ClockSettings.serialize(value)
} else {
""
}
@OpenForTesting
open fun applySettings(value: ClockSettings?) {
assertNotMainThread()
try {
value?._applied_timestamp = System.currentTimeMillis()
val json = ClockSettings.serialize(value)
if (handleAllUsers) {
Settings.Secure.putStringForUser(
context.contentResolver,
Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
json,
ActivityManager.getCurrentUser()
)
} else {
Settings.Secure.putString( Settings.Secure.putString(
context.contentResolver, context.contentResolver,
Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, json Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
json
) )
} catch (ex: Exception) {
Log.e(TAG, "Failed to set clock settings", ex)
} }
} catch (ex: Exception) {
Log.e(TAG, "Failed to set clock settings", ex)
} }
settings = value
}
private fun mutateSetting(mutator: (ClockSettings) -> Unit) { @OpenForTesting
val settings = this.settings ?: ClockSettings() protected open fun assertMainThread() {
mutator(settings) Assert.isMainThread()
this.settings = settings }
@OpenForTesting
protected open fun assertNotMainThread() {
Assert.isNotMainThread()
}
private fun onClockChanged() {
assertMainThread()
clockChangeListeners.forEach { it.onClockChanged() }
}
private fun mutateSetting(mutator: (ClockSettings) -> ClockSettings) {
scope.launch(bgDispatcher) { applySettings(mutator(settings ?: ClockSettings())) }
} }
var currentClockId: ClockId var currentClockId: ClockId
get() = settings?.clockId ?: fallbackClockId get() = settings?.clockId ?: fallbackClockId
set(value) { mutateSetting { it.clockId = value } } set(value) {
mutateSetting { it.copy(clockId = value) }
}
var seedColor: Int? var seedColor: Int?
get() = settings?.seedColor get() = settings?.seedColor
set(value) { mutateSetting { it.seedColor = value } } set(value) {
mutateSetting { it.copy(seedColor = value) }
}
init { init {
connectClocks(defaultClockProvider) connectClocks(defaultClockProvider)
@@ -118,19 +192,51 @@ open class ClockRegistry(
"$defaultClockProvider did not register clock at $DEFAULT_CLOCK_ID" "$defaultClockProvider did not register clock at $DEFAULT_CLOCK_ID"
) )
} }
}
if (isEnabled) { fun registerListeners() {
pluginManager.addPluginListener( if (!isEnabled || isRegistered) {
pluginListener, return
ClockProviderPlugin::class.java, }
/*allowMultiple=*/ true
) isRegistered = true
pluginManager.addPluginListener(
pluginListener,
ClockProviderPlugin::class.java,
/*allowMultiple=*/ true
)
scope.launch(bgDispatcher) { querySettings() }
if (handleAllUsers) {
context.contentResolver.registerContentObserver( context.contentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE), Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
/*notifyForDescendants=*/ false, /*notifyForDescendants=*/ false,
settingObserver, settingObserver,
userHandle UserHandle.USER_ALL
) )
ActivityManager.getService().registerUserSwitchObserver(userSwitchObserver, TAG)
} else {
context.contentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
/*notifyForDescendants=*/ false,
settingObserver
)
}
}
fun unregisterListeners() {
if (!isRegistered) {
return
}
isRegistered = false
pluginManager.removePluginListener(pluginListener)
context.contentResolver.unregisterContentObserver(settingObserver)
if (handleAllUsers) {
ActivityManager.getService().unregisterUserSwitchObserver(userSwitchObserver)
} }
} }
@@ -157,7 +263,7 @@ open class ClockRegistry(
if (DEBUG) { if (DEBUG) {
Log.i(TAG, "Current clock ($currentId) was connected") Log.i(TAG, "Current clock ($currentId) was connected")
} }
clockChangeListeners.forEach { it.onClockChanged() } onClockChanged()
} }
} }
} }
@@ -172,13 +278,12 @@ open class ClockRegistry(
if (currentId == clock.clockId) { if (currentId == clock.clockId) {
Log.w(TAG, "Current clock ($currentId) was disconnected") Log.w(TAG, "Current clock ($currentId) was disconnected")
clockChangeListeners.forEach { it.onClockChanged() } onClockChanged()
} }
} }
} }
@OpenForTesting fun getClocks(): List<ClockMetadata> {
open fun getClocks(): List<ClockMetadata> {
if (!isEnabled) { if (!isEnabled) {
return listOf(availableClocks[DEFAULT_CLOCK_ID]!!.metadata) return listOf(availableClocks[DEFAULT_CLOCK_ID]!!.metadata)
} }
@@ -213,16 +318,16 @@ open class ClockRegistry(
return createClock(DEFAULT_CLOCK_ID)!! return createClock(DEFAULT_CLOCK_ID)!!
} }
private fun createClock(clockId: ClockId): ClockController? { private fun createClock(targetClockId: ClockId): ClockController? {
val settings = this.settings ?: ClockSettings() var settings = this.settings ?: ClockSettings()
if (clockId != settings.clockId) { if (targetClockId != settings.clockId) {
settings.clockId = clockId settings = settings.copy(clockId = targetClockId)
} }
return availableClocks[clockId]?.provider?.createClock(settings) return availableClocks[targetClockId]?.provider?.createClock(settings)
} }
private data class ClockInfo( private data class ClockInfo(
val metadata: ClockMetadata, val metadata: ClockMetadata,
val provider: ClockProvider val provider: ClockProvider,
) )
} }

View File

@@ -45,7 +45,7 @@ interface ClockProvider {
/** Initializes and returns the target clock design */ /** Initializes and returns the target clock design */
@Deprecated("Use overload with ClockSettings") @Deprecated("Use overload with ClockSettings")
fun createClock(id: ClockId): ClockController { fun createClock(id: ClockId): ClockController {
return createClock(ClockSettings(id, null, null)) return createClock(ClockSettings(id, null))
} }
/** Initializes and returns the target clock design */ /** Initializes and returns the target clock design */
@@ -186,16 +186,21 @@ data class ClockMetadata(
/** Structure for keeping clock-specific settings */ /** Structure for keeping clock-specific settings */
@Keep @Keep
data class ClockSettings( data class ClockSettings(
var clockId: ClockId? = null, val clockId: ClockId? = null,
var seedColor: Int? = null, val seedColor: Int? = null,
var _applied_timestamp: Long? = null,
) { ) {
var _applied_timestamp: Long? = null
companion object { companion object {
private val KEY_CLOCK_ID = "clockId" private val KEY_CLOCK_ID = "clockId"
private val KEY_SEED_COLOR = "seedColor" private val KEY_SEED_COLOR = "seedColor"
private val KEY_TIMESTAMP = "_applied_timestamp" private val KEY_TIMESTAMP = "_applied_timestamp"
fun serialize(setting: ClockSettings): String { fun serialize(setting: ClockSettings?): String {
if (setting == null) {
return ""
}
return JSONObject() return JSONObject()
.put(KEY_CLOCK_ID, setting.clockId) .put(KEY_CLOCK_ID, setting.clockId)
.put(KEY_SEED_COLOR, setting.seedColor) .put(KEY_SEED_COLOR, setting.seedColor)
@@ -203,13 +208,21 @@ data class ClockSettings(
.toString() .toString()
} }
fun deserialize(jsonStr: String): ClockSettings { fun deserialize(jsonStr: String?): ClockSettings? {
if (jsonStr.isNullOrEmpty()) {
return null
}
val json = JSONObject(jsonStr) val json = JSONObject(jsonStr)
return ClockSettings( val result =
json.getString(KEY_CLOCK_ID), ClockSettings(
if (!json.isNull(KEY_SEED_COLOR)) json.getInt(KEY_SEED_COLOR) else null, json.getString(KEY_CLOCK_ID),
if (!json.isNull(KEY_TIMESTAMP)) json.getLong(KEY_TIMESTAMP) else null if (!json.isNull(KEY_SEED_COLOR)) json.getInt(KEY_SEED_COLOR) else null
) )
if (!json.isNull(KEY_TIMESTAMP)) {
result._applied_timestamp = json.getLong(KEY_TIMESTAMP)
}
return result
} }
} }
} }

View File

@@ -18,13 +18,12 @@ package com.android.keyguard.dagger;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Handler;
import android.os.UserHandle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Application; import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags; import com.android.systemui.flags.Flags;
@@ -34,6 +33,8 @@ import com.android.systemui.shared.clocks.DefaultClockProvider;
import dagger.Module; import dagger.Module;
import dagger.Provides; import dagger.Provides;
import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.CoroutineScope;
/** Dagger Module for clocks. */ /** Dagger Module for clocks. */
@Module @Module
@@ -44,17 +45,23 @@ public abstract class ClockRegistryModule {
public static ClockRegistry getClockRegistry( public static ClockRegistry getClockRegistry(
@Application Context context, @Application Context context,
PluginManager pluginManager, PluginManager pluginManager,
@Main Handler handler, @Application CoroutineScope scope,
@Main CoroutineDispatcher mainDispatcher,
@Background CoroutineDispatcher bgDispatcher,
FeatureFlags featureFlags, FeatureFlags featureFlags,
@Main Resources resources, @Main Resources resources,
LayoutInflater layoutInflater) { LayoutInflater layoutInflater) {
return new ClockRegistry( ClockRegistry registry = new ClockRegistry(
context, context,
pluginManager, pluginManager,
handler, scope,
mainDispatcher,
bgDispatcher,
featureFlags.isEnabled(Flags.LOCKSCREEN_CUSTOM_CLOCKS), featureFlags.isEnabled(Flags.LOCKSCREEN_CUSTOM_CLOCKS),
UserHandle.USER_ALL, /* handleAllUsers= */ true,
new DefaultClockProvider(context, layoutInflater, resources), new DefaultClockProvider(context, layoutInflater, resources),
context.getString(R.string.lockscreen_clock_id_fallback)); context.getString(R.string.lockscreen_clock_id_fallback));
registry.registerListeners();
return registry;
} }
} }

View File

@@ -18,8 +18,6 @@ package com.android.systemui.shared.clocks
import android.content.ContentResolver import android.content.ContentResolver
import android.content.Context import android.content.Context
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.Handler
import android.os.UserHandle
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
@@ -34,6 +32,9 @@ import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.eq
import junit.framework.Assert.assertEquals import junit.framework.Assert.assertEquals
import junit.framework.Assert.fail import junit.framework.Assert.fail
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import org.json.JSONException import org.json.JSONException
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
@@ -49,19 +50,19 @@ import org.mockito.junit.MockitoJUnit
class ClockRegistryTest : SysuiTestCase() { class ClockRegistryTest : SysuiTestCase() {
@JvmField @Rule val mockito = MockitoJUnit.rule() @JvmField @Rule val mockito = MockitoJUnit.rule()
private lateinit var dispatcher: CoroutineDispatcher
private lateinit var scope: TestScope
@Mock private lateinit var mockContext: Context @Mock private lateinit var mockContext: Context
@Mock private lateinit var mockPluginManager: PluginManager @Mock private lateinit var mockPluginManager: PluginManager
@Mock private lateinit var mockClock: ClockController @Mock private lateinit var mockClock: ClockController
@Mock private lateinit var mockDefaultClock: ClockController @Mock private lateinit var mockDefaultClock: ClockController
@Mock private lateinit var mockThumbnail: Drawable @Mock private lateinit var mockThumbnail: Drawable
@Mock private lateinit var mockHandler: Handler
@Mock private lateinit var mockContentResolver: ContentResolver @Mock private lateinit var mockContentResolver: ContentResolver
private lateinit var fakeDefaultProvider: FakeClockPlugin private lateinit var fakeDefaultProvider: FakeClockPlugin
private lateinit var pluginListener: PluginListener<ClockProviderPlugin> private lateinit var pluginListener: PluginListener<ClockProviderPlugin>
private lateinit var registry: ClockRegistry private lateinit var registry: ClockRegistry
private var settingValue: ClockSettings? = null
companion object { companion object {
private fun failFactory(): ClockController { private fun failFactory(): ClockController {
fail("Unexpected call to createClock") fail("Unexpected call to createClock")
@@ -99,6 +100,9 @@ class ClockRegistryTest : SysuiTestCase() {
@Before @Before
fun setUp() { fun setUp() {
dispatcher = StandardTestDispatcher()
scope = TestScope(dispatcher)
fakeDefaultProvider = FakeClockPlugin() fakeDefaultProvider = FakeClockPlugin()
.addClock(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME, { mockDefaultClock }, { mockThumbnail }) .addClock(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME, { mockDefaultClock }, { mockThumbnail })
whenever(mockContext.contentResolver).thenReturn(mockContentResolver) whenever(mockContext.contentResolver).thenReturn(mockContentResolver)
@@ -107,15 +111,22 @@ class ClockRegistryTest : SysuiTestCase() {
registry = object : ClockRegistry( registry = object : ClockRegistry(
mockContext, mockContext,
mockPluginManager, mockPluginManager,
mockHandler, scope = scope.backgroundScope,
mainDispatcher = dispatcher,
bgDispatcher = dispatcher,
isEnabled = true, isEnabled = true,
userHandle = UserHandle.USER_ALL, handleAllUsers = true,
defaultClockProvider = fakeDefaultProvider defaultClockProvider = fakeDefaultProvider,
) { ) {
override var settings: ClockSettings? override fun querySettings() { }
get() = settingValue override fun applySettings(value: ClockSettings?) {
set(value) { settingValue = value } settings = value
}
// Unit Test does not validate threading
override fun assertMainThread() {}
override fun assertNotMainThread() {}
} }
registry.registerListeners()
verify(mockPluginManager) verify(mockPluginManager)
.addPluginListener(captor.capture(), eq(ClockProviderPlugin::class.java), eq(true)) .addPluginListener(captor.capture(), eq(ClockProviderPlugin::class.java), eq(true))
@@ -187,16 +198,16 @@ class ClockRegistryTest : SysuiTestCase() {
.addClock("clock_1", "clock 1") .addClock("clock_1", "clock 1")
.addClock("clock_2", "clock 2") .addClock("clock_2", "clock 2")
settingValue = ClockSettings("clock_3", null, null)
val plugin2 = FakeClockPlugin() val plugin2 = FakeClockPlugin()
.addClock("clock_3", "clock 3", { mockClock }) .addClock("clock_3", "clock 3", { mockClock })
.addClock("clock_4", "clock 4") .addClock("clock_4", "clock 4")
registry.applySettings(ClockSettings("clock_3", null))
pluginListener.onPluginConnected(plugin1, mockContext) pluginListener.onPluginConnected(plugin1, mockContext)
pluginListener.onPluginConnected(plugin2, mockContext) pluginListener.onPluginConnected(plugin2, mockContext)
val clock = registry.createCurrentClock() val clock = registry.createCurrentClock()
assertEquals(clock, mockClock) assertEquals(mockClock, clock)
} }
@Test @Test
@@ -205,11 +216,11 @@ class ClockRegistryTest : SysuiTestCase() {
.addClock("clock_1", "clock 1") .addClock("clock_1", "clock 1")
.addClock("clock_2", "clock 2") .addClock("clock_2", "clock 2")
settingValue = ClockSettings("clock_3", null, null)
val plugin2 = FakeClockPlugin() val plugin2 = FakeClockPlugin()
.addClock("clock_3", "clock 3") .addClock("clock_3", "clock 3")
.addClock("clock_4", "clock 4") .addClock("clock_4", "clock 4")
registry.applySettings(ClockSettings("clock_3", null))
pluginListener.onPluginConnected(plugin1, mockContext) pluginListener.onPluginConnected(plugin1, mockContext)
pluginListener.onPluginConnected(plugin2, mockContext) pluginListener.onPluginConnected(plugin2, mockContext)
pluginListener.onPluginDisconnected(plugin2) pluginListener.onPluginDisconnected(plugin2)
@@ -224,11 +235,11 @@ class ClockRegistryTest : SysuiTestCase() {
.addClock("clock_1", "clock 1") .addClock("clock_1", "clock 1")
.addClock("clock_2", "clock 2") .addClock("clock_2", "clock 2")
settingValue = ClockSettings("clock_3", null, null)
val plugin2 = FakeClockPlugin() val plugin2 = FakeClockPlugin()
.addClock("clock_3", "clock 3", { mockClock }) .addClock("clock_3", "clock 3", { mockClock })
.addClock("clock_4", "clock 4") .addClock("clock_4", "clock 4")
registry.applySettings(ClockSettings("clock_3", null))
pluginListener.onPluginConnected(plugin1, mockContext) pluginListener.onPluginConnected(plugin1, mockContext)
pluginListener.onPluginConnected(plugin2, mockContext) pluginListener.onPluginConnected(plugin2, mockContext)
@@ -244,7 +255,7 @@ class ClockRegistryTest : SysuiTestCase() {
@Test @Test
fun jsonDeserialization_gotExpectedObject() { fun jsonDeserialization_gotExpectedObject() {
val expected = ClockSettings("ID", null, 500) val expected = ClockSettings("ID", null).apply { _applied_timestamp = 500 }
val actual = ClockSettings.deserialize("""{ val actual = ClockSettings.deserialize("""{
"clockId":"ID", "clockId":"ID",
"_applied_timestamp":500 "_applied_timestamp":500
@@ -254,14 +265,14 @@ class ClockRegistryTest : SysuiTestCase() {
@Test @Test
fun jsonDeserialization_noTimestamp_gotExpectedObject() { fun jsonDeserialization_noTimestamp_gotExpectedObject() {
val expected = ClockSettings("ID", null, null) val expected = ClockSettings("ID", null)
val actual = ClockSettings.deserialize("{\"clockId\":\"ID\"}") val actual = ClockSettings.deserialize("{\"clockId\":\"ID\"}")
assertEquals(expected, actual) assertEquals(expected, actual)
} }
@Test @Test
fun jsonDeserialization_nullTimestamp_gotExpectedObject() { fun jsonDeserialization_nullTimestamp_gotExpectedObject() {
val expected = ClockSettings("ID", null, null) val expected = ClockSettings("ID", null)
val actual = ClockSettings.deserialize("""{ val actual = ClockSettings.deserialize("""{
"clockId":"ID", "clockId":"ID",
"_applied_timestamp":null "_applied_timestamp":null
@@ -271,7 +282,7 @@ class ClockRegistryTest : SysuiTestCase() {
@Test(expected = JSONException::class) @Test(expected = JSONException::class)
fun jsonDeserialization_noId_threwException() { fun jsonDeserialization_noId_threwException() {
val expected = ClockSettings("ID", null, 500) val expected = ClockSettings(null, null).apply { _applied_timestamp = 500 }
val actual = ClockSettings.deserialize("{\"_applied_timestamp\":500}") val actual = ClockSettings.deserialize("{\"_applied_timestamp\":500}")
assertEquals(expected, actual) assertEquals(expected, actual)
} }
@@ -279,14 +290,15 @@ class ClockRegistryTest : SysuiTestCase() {
@Test @Test
fun jsonSerialization_gotExpectedString() { fun jsonSerialization_gotExpectedString() {
val expected = "{\"clockId\":\"ID\",\"_applied_timestamp\":500}" val expected = "{\"clockId\":\"ID\",\"_applied_timestamp\":500}"
val actual = ClockSettings.serialize(ClockSettings("ID", null, 500)) val actual = ClockSettings.serialize(ClockSettings("ID", null)
.apply { _applied_timestamp = 500 })
assertEquals(expected, actual) assertEquals(expected, actual)
} }
@Test @Test
fun jsonSerialization_noTimestamp_gotExpectedString() { fun jsonSerialization_noTimestamp_gotExpectedString() {
val expected = "{\"clockId\":\"ID\"}" val expected = "{\"clockId\":\"ID\"}"
val actual = ClockSettings.serialize(ClockSettings("ID", null, null)) val actual = ClockSettings.serialize(ClockSettings("ID", null))
assertEquals(expected, actual) assertEquals(expected, actual)
} }
} }