Split ChangeReason and decouple it from Observer
Observer is flexible to be used for other scenarios.
Bug: 325144964
Test: atest SettingsLibDataStoreTest
Change-Id: I8a8ce690edee37bdb1ba20ce06a508fbdddb2c15
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorageManager.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorageManager.kt
index 8242347..b4a9172 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorageManager.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorageManager.kt
@@ -138,7 +138,7 @@
private fun notifyBackupManager(key: Any?, reason: Int) {
val name = storage.name
// prefer not triggering backup immediately after restore
- if (reason == ChangeReason.RESTORE) {
+ if (reason == DataChangeReason.RESTORE) {
Log.d(
LOG_TAG,
"Notify BackupManager dataChanged ignored for restore: storage=$name key=$key"
@@ -161,8 +161,8 @@
fun notifyRestoreFinished() {
when (storage) {
- is KeyedObservable<*> -> storage.notifyChange(ChangeReason.RESTORE)
- is Observable -> storage.notifyChange(ChangeReason.RESTORE)
+ is KeyedObservable<*> -> storage.notifyChange(DataChangeReason.RESTORE)
+ is Observable -> storage.notifyChange(DataChangeReason.RESTORE)
}
}
}
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/DataChangeReason.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/DataChangeReason.kt
new file mode 100644
index 0000000..145fabe
--- /dev/null
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/DataChangeReason.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 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.settingslib.datastore
+
+import androidx.annotation.IntDef
+
+/** The reason of data change. */
+@IntDef(
+ DataChangeReason.UNKNOWN,
+ DataChangeReason.UPDATE,
+ DataChangeReason.DELETE,
+ DataChangeReason.RESTORE,
+ DataChangeReason.SYNC_ACROSS_PROFILES,
+)
+@Retention(AnnotationRetention.SOURCE)
+annotation class DataChangeReason {
+ companion object {
+ /** Unknown reason of the change. */
+ const val UNKNOWN = 0
+ /** Data is updated. */
+ const val UPDATE = 1
+ /** Data is deleted. */
+ const val DELETE = 2
+ /** Data is restored from backup/restore framework. */
+ const val RESTORE = 3
+ /** Data is synced from another profile (e.g. personal profile to work profile). */
+ const val SYNC_ACROSS_PROFILES = 4
+ }
+}
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt
index 3ed4d46..ede7c63d 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt
@@ -37,7 +37,7 @@
* @param reason the reason of change
* @see KeyedObservable.addObserver
*/
- fun onKeyChanged(key: K, @ChangeReason reason: Int)
+ fun onKeyChanged(key: K, reason: Int)
}
/**
@@ -89,7 +89,7 @@
*
* @param reason reason of the change
*/
- fun notifyChange(@ChangeReason reason: Int)
+ fun notifyChange(reason: Int)
/**
* Notifies observers that a change occurs on given key.
@@ -99,7 +99,7 @@
* @param key key of the change
* @param reason reason of the change
*/
- fun notifyChange(key: K, @ChangeReason reason: Int)
+ fun notifyChange(key: K, reason: Int)
}
/** A thread safe implementation of [KeyedObservable]. */
@@ -141,7 +141,7 @@
}
}
- override fun notifyChange(@ChangeReason reason: Int) {
+ override fun notifyChange(reason: Int) {
// make a copy to avoid potential ConcurrentModificationException
val observers = synchronized(observers) { observers.entries.toTypedArray() }
val keyedObservers = synchronized(keyedObservers) { keyedObservers.copy() }
@@ -165,7 +165,7 @@
return result
}
- override fun notifyChange(key: K, @ChangeReason reason: Int) {
+ override fun notifyChange(key: K, reason: Int) {
// make a copy to avoid potential ConcurrentModificationException
val observers = synchronized(observers) { observers.entries.toTypedArray() }
val keyedObservers =
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/Observer.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/Observer.kt
index 6d0ca669..98d0f6e 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/Observer.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/Observer.kt
@@ -18,34 +18,9 @@
import androidx.annotation.AnyThread
import androidx.annotation.GuardedBy
-import androidx.annotation.IntDef
import java.util.WeakHashMap
import java.util.concurrent.Executor
-/** The reason of a change. */
-@IntDef(
- ChangeReason.UNKNOWN,
- ChangeReason.UPDATE,
- ChangeReason.DELETE,
- ChangeReason.RESTORE,
- ChangeReason.SYNC_ACROSS_PROFILES,
-)
-@Retention(AnnotationRetention.SOURCE)
-annotation class ChangeReason {
- companion object {
- /** Unknown reason of the change. */
- const val UNKNOWN = 0
- /** Data is updated. */
- const val UPDATE = 1
- /** Data is deleted. */
- const val DELETE = 2
- /** Data is restored from backup/restore framework. */
- const val RESTORE = 3
- /** Data is synced from another profile (e.g. personal profile to work profile). */
- const val SYNC_ACROSS_PROFILES = 4
- }
-}
-
/**
* Callback to be informed of changes in [Observable] object.
*
@@ -60,7 +35,7 @@
* @param reason the reason of change
* @see [Observable.addObserver] for the notices.
*/
- fun onChanged(@ChangeReason reason: Int)
+ fun onChanged(reason: Int)
}
/** An observable object allows to observe change with [Observer]. */
@@ -90,7 +65,7 @@
*
* @param reason reason of the change
*/
- fun notifyChange(@ChangeReason reason: Int)
+ fun notifyChange(reason: Int)
}
/** A thread safe implementation of [Observable]. */
@@ -110,7 +85,7 @@
synchronized(observers) { observers.remove(observer) }
}
- override fun notifyChange(@ChangeReason reason: Int) {
+ override fun notifyChange(reason: Int) {
// make a copy to avoid potential ConcurrentModificationException
val entries = synchronized(observers) { observers.entries.toTypedArray() }
for (entry in entries) {
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesStorage.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesStorage.kt
index 9f9c0d8..20a95d7 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesStorage.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesStorage.kt
@@ -83,10 +83,10 @@
private val sharedPreferencesListener =
SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
if (key != null) {
- notifyChange(key, ChangeReason.UPDATE)
+ notifyChange(key, DataChangeReason.UPDATE)
} else {
// On Android >= R, SharedPreferences.Editor.clear() will trigger this case
- notifyChange(ChangeReason.DELETE)
+ notifyChange(DataChangeReason.DELETE)
}
}
diff --git a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/BackupRestoreStorageManagerTest.kt b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/BackupRestoreStorageManagerTest.kt
index d8f5028..19c574a 100644
--- a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/BackupRestoreStorageManagerTest.kt
+++ b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/BackupRestoreStorageManagerTest.kt
@@ -157,9 +157,9 @@
manager.onRestoreFinished()
- verify(keyedObserver).onKeyChanged("key", ChangeReason.RESTORE)
- verify(anyKeyObserver).onKeyChanged(null, ChangeReason.RESTORE)
- verify(observer).onChanged(ChangeReason.RESTORE)
+ verify(keyedObserver).onKeyChanged("key", DataChangeReason.RESTORE)
+ verify(anyKeyObserver).onKeyChanged(null, DataChangeReason.RESTORE)
+ verify(observer).onChanged(DataChangeReason.RESTORE)
if (isRobolectric()) {
Shadows.shadowOf(BackupManager(application)).apply {
assertThat(isDataChanged).isFalse()
@@ -186,8 +186,8 @@
assertThat(dataChangedCount).isEqualTo(0)
}
- fileStorage.notifyChange(ChangeReason.UPDATE)
- verify(observer).onChanged(ChangeReason.UPDATE)
+ fileStorage.notifyChange(DataChangeReason.UPDATE)
+ verify(observer).onChanged(DataChangeReason.UPDATE)
verify(keyedObserver, never()).onKeyChanged(any(), any())
verify(anyKeyObserver, never()).onKeyChanged(any(), any())
reset(observer)
@@ -196,10 +196,10 @@
assertThat(dataChangedCount).isEqualTo(1)
}
- keyedStorage.notifyChange("key", ChangeReason.DELETE)
+ keyedStorage.notifyChange("key", DataChangeReason.DELETE)
verify(observer, never()).onChanged(any())
- verify(keyedObserver).onKeyChanged("key", ChangeReason.DELETE)
- verify(anyKeyObserver).onKeyChanged("key", ChangeReason.DELETE)
+ verify(keyedObserver).onKeyChanged("key", DataChangeReason.DELETE)
+ verify(anyKeyObserver).onKeyChanged("key", DataChangeReason.DELETE)
backupManager?.apply {
assertThat(isDataChanged).isTrue()
assertThat(dataChangedCount).isEqualTo(2)
@@ -207,11 +207,11 @@
reset(keyedObserver)
// backup manager is not notified for restore event
- fileStorage.notifyChange(ChangeReason.RESTORE)
- keyedStorage.notifyChange("key", ChangeReason.RESTORE)
- verify(observer).onChanged(ChangeReason.RESTORE)
- verify(keyedObserver).onKeyChanged("key", ChangeReason.RESTORE)
- verify(anyKeyObserver).onKeyChanged("key", ChangeReason.RESTORE)
+ fileStorage.notifyChange(DataChangeReason.RESTORE)
+ keyedStorage.notifyChange("key", DataChangeReason.RESTORE)
+ verify(observer).onChanged(DataChangeReason.RESTORE)
+ verify(keyedObserver).onKeyChanged("key", DataChangeReason.RESTORE)
+ verify(anyKeyObserver).onKeyChanged("key", DataChangeReason.RESTORE)
backupManager?.apply {
assertThat(isDataChanged).isTrue()
assertThat(dataChangedCount).isEqualTo(2)
diff --git a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/KeyedObserverTest.kt b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/KeyedObserverTest.kt
index 8638b2f..0fdecb0 100644
--- a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/KeyedObserverTest.kt
+++ b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/KeyedObserverTest.kt
@@ -77,7 +77,7 @@
var observer: KeyedObserver<Any?>? = KeyedObserver { _, _ -> counter.incrementAndGet() }
keyedObservable.addObserver(observer!!, executor1)
- keyedObservable.notifyChange(ChangeReason.UPDATE)
+ keyedObservable.notifyChange(DataChangeReason.UPDATE)
assertThat(counter.get()).isEqualTo(1)
// trigger GC, the observer callback should not be invoked
@@ -85,7 +85,7 @@
System.gc()
System.runFinalization()
- keyedObservable.notifyChange(ChangeReason.UPDATE)
+ keyedObservable.notifyChange(DataChangeReason.UPDATE)
assertThat(counter.get()).isEqualTo(1)
}
@@ -95,7 +95,7 @@
var keyObserver: KeyedObserver<Any>? = KeyedObserver { _, _ -> counter.incrementAndGet() }
keyedObservable.addObserver(key1, keyObserver!!, executor1)
- keyedObservable.notifyChange(key1, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(key1, DataChangeReason.UPDATE)
assertThat(counter.get()).isEqualTo(1)
// trigger GC, the observer callback should not be invoked
@@ -103,7 +103,7 @@
System.gc()
System.runFinalization()
- keyedObservable.notifyChange(key1, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(key1, DataChangeReason.UPDATE)
assertThat(counter.get()).isEqualTo(1)
}
@@ -112,16 +112,16 @@
keyedObservable.addObserver(observer1, executor1)
keyedObservable.addObserver(observer2, executor2)
- keyedObservable.notifyChange(ChangeReason.UPDATE)
- verify(observer1).onKeyChanged(null, ChangeReason.UPDATE)
- verify(observer2).onKeyChanged(null, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(DataChangeReason.UPDATE)
+ verify(observer1).onKeyChanged(null, DataChangeReason.UPDATE)
+ verify(observer2).onKeyChanged(null, DataChangeReason.UPDATE)
reset(observer1, observer2)
keyedObservable.removeObserver(observer2)
- keyedObservable.notifyChange(ChangeReason.DELETE)
- verify(observer1).onKeyChanged(null, ChangeReason.DELETE)
- verify(observer2, never()).onKeyChanged(null, ChangeReason.DELETE)
+ keyedObservable.notifyChange(DataChangeReason.DELETE)
+ verify(observer1).onKeyChanged(null, DataChangeReason.DELETE)
+ verify(observer2, never()).onKeyChanged(null, DataChangeReason.DELETE)
}
@Test
@@ -129,16 +129,16 @@
keyedObservable.addObserver(key1, keyedObserver1, executor1)
keyedObservable.addObserver(key2, keyedObserver2, executor2)
- keyedObservable.notifyChange(key1, ChangeReason.UPDATE)
- verify(keyedObserver1).onKeyChanged(key1, ChangeReason.UPDATE)
- verify(keyedObserver2, never()).onKeyChanged(key2, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(key1, DataChangeReason.UPDATE)
+ verify(keyedObserver1).onKeyChanged(key1, DataChangeReason.UPDATE)
+ verify(keyedObserver2, never()).onKeyChanged(key2, DataChangeReason.UPDATE)
reset(keyedObserver1, keyedObserver2)
keyedObservable.removeObserver(key1, keyedObserver1)
- keyedObservable.notifyChange(key1, ChangeReason.DELETE)
- verify(keyedObserver1, never()).onKeyChanged(key1, ChangeReason.DELETE)
- verify(keyedObserver2, never()).onKeyChanged(key2, ChangeReason.DELETE)
+ keyedObservable.notifyChange(key1, DataChangeReason.DELETE)
+ verify(keyedObserver1, never()).onKeyChanged(key1, DataChangeReason.DELETE)
+ verify(keyedObserver2, never()).onKeyChanged(key2, DataChangeReason.DELETE)
}
@Test
@@ -147,24 +147,24 @@
keyedObservable.addObserver(key1, keyedObserver1, executor1)
keyedObservable.addObserver(key2, keyedObserver2, executor1)
- keyedObservable.notifyChange(ChangeReason.UPDATE)
- verify(observer1).onKeyChanged(null, ChangeReason.UPDATE)
- verify(keyedObserver1).onKeyChanged(key1, ChangeReason.UPDATE)
- verify(keyedObserver2).onKeyChanged(key2, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(DataChangeReason.UPDATE)
+ verify(observer1).onKeyChanged(null, DataChangeReason.UPDATE)
+ verify(keyedObserver1).onKeyChanged(key1, DataChangeReason.UPDATE)
+ verify(keyedObserver2).onKeyChanged(key2, DataChangeReason.UPDATE)
reset(observer1, keyedObserver1, keyedObserver2)
- keyedObservable.notifyChange(key1, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(key1, DataChangeReason.UPDATE)
- verify(observer1).onKeyChanged(key1, ChangeReason.UPDATE)
- verify(keyedObserver1).onKeyChanged(key1, ChangeReason.UPDATE)
- verify(keyedObserver2, never()).onKeyChanged(key1, ChangeReason.UPDATE)
+ verify(observer1).onKeyChanged(key1, DataChangeReason.UPDATE)
+ verify(keyedObserver1).onKeyChanged(key1, DataChangeReason.UPDATE)
+ verify(keyedObserver2, never()).onKeyChanged(key1, DataChangeReason.UPDATE)
reset(observer1, keyedObserver1, keyedObserver2)
- keyedObservable.notifyChange(key2, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(key2, DataChangeReason.UPDATE)
- verify(observer1).onKeyChanged(key2, ChangeReason.UPDATE)
- verify(keyedObserver1, never()).onKeyChanged(key2, ChangeReason.UPDATE)
- verify(keyedObserver2).onKeyChanged(key2, ChangeReason.UPDATE)
+ verify(observer1).onKeyChanged(key2, DataChangeReason.UPDATE)
+ verify(keyedObserver1, never()).onKeyChanged(key2, DataChangeReason.UPDATE)
+ verify(keyedObserver2).onKeyChanged(key2, DataChangeReason.UPDATE)
}
@Test
@@ -176,7 +176,7 @@
keyedObservable.addObserver(observer, executor1)
- keyedObservable.notifyChange(ChangeReason.UPDATE)
+ keyedObservable.notifyChange(DataChangeReason.UPDATE)
keyedObservable.removeObserver(observer)
}
@@ -189,7 +189,7 @@
keyedObservable.addObserver(key1, keyObserver, executor1)
- keyedObservable.notifyChange(key1, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(key1, DataChangeReason.UPDATE)
keyedObservable.removeObserver(key1, keyObserver)
}
}
diff --git a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/ObserverTest.kt b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/ObserverTest.kt
index 173c2b1..5d0303c 100644
--- a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/ObserverTest.kt
+++ b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/ObserverTest.kt
@@ -58,7 +58,7 @@
var observer: Observer? = Observer { counter.incrementAndGet() }
observable.addObserver(observer!!, executor1)
- observable.notifyChange(ChangeReason.UPDATE)
+ observable.notifyChange(DataChangeReason.UPDATE)
assertThat(counter.get()).isEqualTo(1)
// trigger GC, the observer callback should not be invoked
@@ -66,7 +66,7 @@
System.gc()
System.runFinalization()
- observable.notifyChange(ChangeReason.UPDATE)
+ observable.notifyChange(DataChangeReason.UPDATE)
assertThat(counter.get()).isEqualTo(1)
}
@@ -75,17 +75,17 @@
observable.addObserver(observer1, executor1)
observable.addObserver(observer2, executor2)
- observable.notifyChange(ChangeReason.DELETE)
+ observable.notifyChange(DataChangeReason.DELETE)
- verify(observer1).onChanged(ChangeReason.DELETE)
- verify(observer2).onChanged(ChangeReason.DELETE)
+ verify(observer1).onChanged(DataChangeReason.DELETE)
+ verify(observer2).onChanged(DataChangeReason.DELETE)
reset(observer1, observer2)
observable.removeObserver(observer2)
- observable.notifyChange(ChangeReason.UPDATE)
- verify(observer1).onChanged(ChangeReason.UPDATE)
- verify(observer2, never()).onChanged(ChangeReason.UPDATE)
+ observable.notifyChange(DataChangeReason.UPDATE)
+ verify(observer1).onChanged(DataChangeReason.UPDATE)
+ verify(observer2, never()).onChanged(DataChangeReason.UPDATE)
}
@Test
@@ -93,7 +93,7 @@
// ConcurrentModificationException is raised if it is not implemented correctly
val observer = Observer { observable.addObserver(observer1, executor1) }
observable.addObserver(observer, executor1)
- observable.notifyChange(ChangeReason.UPDATE)
+ observable.notifyChange(DataChangeReason.UPDATE)
observable.removeObserver(observer)
}
}
diff --git a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/SharedPreferencesStorageTest.kt b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/SharedPreferencesStorageTest.kt
index fec7d75..a135d77 100644
--- a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/SharedPreferencesStorageTest.kt
+++ b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/SharedPreferencesStorageTest.kt
@@ -80,13 +80,13 @@
storage.addObserver("key", keyedObserver, executor)
storage.sharedPreferences.edit().putString("key", "string").applySync()
- verify(observer).onKeyChanged("key", ChangeReason.UPDATE)
- verify(keyedObserver).onKeyChanged("key", ChangeReason.UPDATE)
+ verify(observer).onKeyChanged("key", DataChangeReason.UPDATE)
+ verify(keyedObserver).onKeyChanged("key", DataChangeReason.UPDATE)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
storage.sharedPreferences.edit().clear().applySync()
- verify(observer).onKeyChanged(null, ChangeReason.DELETE)
- verify(keyedObserver).onKeyChanged("key", ChangeReason.DELETE)
+ verify(observer).onKeyChanged(null, DataChangeReason.DELETE)
+ verify(keyedObserver).onKeyChanged("key", DataChangeReason.DELETE)
}
}