Use disposable like pattern in SaveableStateRegistry

Relnote: SaveableStateRegistry's unregisterProvider was removed. Instead registerProvider() now returns SaveableStateRegistry.Entry object which you can use to unregister
Fixes: 178583739
Test: RememberSaveableTest, SaveableStateRegistryTest
Change-Id: Ic42741cecc67ce93cc097f01f7196110e2fff09d
diff --git a/compose/runtime/runtime-saveable/api/current.txt b/compose/runtime/runtime-saveable/api/current.txt
index bb252f1..0aedbbf 100644
--- a/compose/runtime/runtime-saveable/api/current.txt
+++ b/compose/runtime/runtime-saveable/api/current.txt
@@ -26,8 +26,11 @@
     method public boolean canBeSaved(Object value);
     method public Object? consumeRestored(String key);
     method public java.util.Map<java.lang.String,java.util.List<java.lang.Object>> performSave();
-    method public void registerProvider(String key, kotlin.jvm.functions.Function0<?> valueProvider);
-    method public void unregisterProvider(String key, kotlin.jvm.functions.Function0<?> valueProvider);
+    method public androidx.compose.runtime.saveable.SaveableStateRegistry.Entry registerProvider(String key, kotlin.jvm.functions.Function0<?> valueProvider);
+  }
+
+  public static interface SaveableStateRegistry.Entry {
+    method public void unregister();
   }
 
   public final class SaveableStateRegistryKt {
diff --git a/compose/runtime/runtime-saveable/api/public_plus_experimental_current.txt b/compose/runtime/runtime-saveable/api/public_plus_experimental_current.txt
index bb252f1..0aedbbf 100644
--- a/compose/runtime/runtime-saveable/api/public_plus_experimental_current.txt
+++ b/compose/runtime/runtime-saveable/api/public_plus_experimental_current.txt
@@ -26,8 +26,11 @@
     method public boolean canBeSaved(Object value);
     method public Object? consumeRestored(String key);
     method public java.util.Map<java.lang.String,java.util.List<java.lang.Object>> performSave();
-    method public void registerProvider(String key, kotlin.jvm.functions.Function0<?> valueProvider);
-    method public void unregisterProvider(String key, kotlin.jvm.functions.Function0<?> valueProvider);
+    method public androidx.compose.runtime.saveable.SaveableStateRegistry.Entry registerProvider(String key, kotlin.jvm.functions.Function0<?> valueProvider);
+  }
+
+  public static interface SaveableStateRegistry.Entry {
+    method public void unregister();
   }
 
   public final class SaveableStateRegistryKt {
diff --git a/compose/runtime/runtime-saveable/api/restricted_current.txt b/compose/runtime/runtime-saveable/api/restricted_current.txt
index bb252f1..0aedbbf 100644
--- a/compose/runtime/runtime-saveable/api/restricted_current.txt
+++ b/compose/runtime/runtime-saveable/api/restricted_current.txt
@@ -26,8 +26,11 @@
     method public boolean canBeSaved(Object value);
     method public Object? consumeRestored(String key);
     method public java.util.Map<java.lang.String,java.util.List<java.lang.Object>> performSave();
-    method public void registerProvider(String key, kotlin.jvm.functions.Function0<?> valueProvider);
-    method public void unregisterProvider(String key, kotlin.jvm.functions.Function0<?> valueProvider);
+    method public androidx.compose.runtime.saveable.SaveableStateRegistry.Entry registerProvider(String key, kotlin.jvm.functions.Function0<?> valueProvider);
+  }
+
+  public static interface SaveableStateRegistry.Entry {
+    method public void unregister();
   }
 
   public final class SaveableStateRegistryKt {
diff --git a/compose/runtime/runtime-saveable/src/androidAndroidTest/kotlin/androidx/compose/runtime/saveable/RememberSaveableTest.kt b/compose/runtime/runtime-saveable/src/androidAndroidTest/kotlin/androidx/compose/runtime/saveable/RememberSaveableTest.kt
index 706b0e3..25bcd69 100644
--- a/compose/runtime/runtime-saveable/src/androidAndroidTest/kotlin/androidx/compose/runtime/saveable/RememberSaveableTest.kt
+++ b/compose/runtime/runtime-saveable/src/androidAndroidTest/kotlin/androidx/compose/runtime/saveable/RememberSaveableTest.kt
@@ -120,9 +120,12 @@
             WrapRegistry(
                 wrap = {
                     object : DelegateRegistry(it) {
-                        override fun registerProvider(key: String, valueProvider: () -> Any?) {
+                        override fun registerProvider(
+                            key: String,
+                            valueProvider: () -> Any?
+                        ): SaveableStateRegistry.Entry {
                             provider = valueProvider
-                            super.registerProvider(key, valueProvider)
+                            return super.registerProvider(key, valueProvider)
                         }
                     }
                 }
@@ -145,9 +148,12 @@
             WrapRegistry(
                 wrap = {
                     object : DelegateRegistry(it) {
-                        override fun registerProvider(key: String, valueProvider: () -> Any?) {
+                        override fun registerProvider(
+                            key: String,
+                            valueProvider: () -> Any?
+                        ): SaveableStateRegistry.Entry {
                             provider = valueProvider
-                            super.registerProvider(key, valueProvider)
+                            return super.registerProvider(key, valueProvider)
                         }
                     }
                 }
@@ -167,9 +173,17 @@
         var registryFactory by mutableStateOf<(SaveableStateRegistry) -> SaveableStateRegistry>(
             value = {
                 object : DelegateRegistry(it) {
-                    override fun unregisterProvider(key: String, valueProvider: () -> Any?) {
-                        unregisterCalledForKey = key
-                        super.unregisterProvider(key, valueProvider)
+                    override fun registerProvider(
+                        key: String,
+                        valueProvider: () -> Any?
+                    ): SaveableStateRegistry.Entry {
+                        val entry = super.registerProvider(key, valueProvider)
+                        return object : SaveableStateRegistry.Entry {
+                            override fun unregister() {
+                                unregisterCalledForKey = key
+                                entry.unregister()
+                            }
+                        }
                     }
                 }
             }
@@ -191,12 +205,16 @@
         rule.runOnUiThread {
             registryFactory = {
                 object : DelegateRegistry(it) {
-                    override fun registerProvider(key: String, valueProvider: () -> Any?) {
-                        super.registerProvider(key, valueProvider)
+                    override fun registerProvider(
+                        key: String,
+                        valueProvider: () -> Any?
+                    ): SaveableStateRegistry.Entry {
+                        val result = super.registerProvider(key, valueProvider)
                         // asserts that we unregistered from the previous registry and then
                         // registered with the same key
                         assertThat(key).isEqualTo(unregisterCalledForKey)
                         registerCalled = true
+                        return result
                     }
                 }
             }
@@ -215,15 +233,19 @@
             WrapRegistry(
                 wrap = {
                     object : DelegateRegistry(it) {
-                        override fun registerProvider(key: String, valueProvider: () -> Any?) {
-                            super.registerProvider(key, valueProvider)
+                        override fun registerProvider(
+                            key: String,
+                            valueProvider: () -> Any?
+                        ): SaveableStateRegistry.Entry {
+                            val entry = super.registerProvider(key, valueProvider)
                             registeredKeys.add(key)
                             registerCalled++
-                        }
-
-                        override fun unregisterProvider(key: String, valueProvider: () -> Any?) {
-                            super.unregisterProvider(key, valueProvider)
-                            registeredKeys.remove(key)
+                            return object : SaveableStateRegistry.Entry {
+                                override fun unregister() {
+                                    registeredKeys.remove(key)
+                                    entry.unregister()
+                                }
+                            }
                         }
                     }
                 }
@@ -280,9 +302,17 @@
             WrapRegistry(
                 wrap = {
                     object : DelegateRegistry(it) {
-                        override fun unregisterProvider(key: String, valueProvider: () -> Any?) {
-                            onUnregisterCalled = true
-                            super.unregisterProvider(key, valueProvider)
+                        override fun registerProvider(
+                            key: String,
+                            valueProvider: () -> Any?
+                        ): SaveableStateRegistry.Entry {
+                            val entry = super.registerProvider(key, valueProvider)
+                            return object : SaveableStateRegistry.Entry {
+                                override fun unregister() {
+                                    onUnregisterCalled = true
+                                    entry.unregister()
+                                }
+                            }
                         }
                     }
                 }
@@ -310,9 +340,12 @@
             WrapRegistry(
                 wrap = {
                     object : DelegateRegistry(it) {
-                        override fun registerProvider(key: String, valueProvider: () -> Any?) {
+                        override fun registerProvider(
+                            key: String,
+                            valueProvider: () -> Any?
+                        ): SaveableStateRegistry.Entry {
                             actualKey = key
-                            super.registerProvider(key, valueProvider)
+                            return super.registerProvider(key, valueProvider)
                         }
                     }
                 }
@@ -332,9 +365,12 @@
             WrapRegistry(
                 wrap = {
                     object : DelegateRegistry(it) {
-                        override fun registerProvider(key: String, valueProvider: () -> Any?) {
+                        override fun registerProvider(
+                            key: String,
+                            valueProvider: () -> Any?
+                        ): SaveableStateRegistry.Entry {
                             actualKey = key
-                            super.registerProvider(key, valueProvider)
+                            return super.registerProvider(key, valueProvider)
                         }
                     }
                 }
diff --git a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/RememberSaveable.kt b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/RememberSaveable.kt
index 22f3585..fa0fe95 100644
--- a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/RememberSaveable.kt
+++ b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/RememberSaveable.kt
@@ -89,9 +89,9 @@
                 with(saverHolder.value) { SaverScope { registry.canBeSaved(it) }.save(value) }
             }
             registry.requireCanBeSaved(valueProvider())
-            registry.registerProvider(finalKey, valueProvider)
+            val entry = registry.registerProvider(finalKey, valueProvider)
             onDispose {
-                registry.unregisterProvider(finalKey, valueProvider)
+                entry.unregister()
             }
         }
     }
diff --git a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistry.kt b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistry.kt
index 4a971f5..4821841 100644
--- a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistry.kt
+++ b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistry.kt
@@ -16,6 +16,7 @@
 
 package androidx.compose.runtime.saveable
 
+import androidx.compose.runtime.saveable.SaveableStateRegistry.Entry
 import androidx.compose.runtime.staticAmbientOf
 
 /**
@@ -44,16 +45,9 @@
      * @param key Key to use for storing the value
      * @param valueProvider Provides the current value, to be executed when [performSave]
      * will be triggered to collect all the registered values
+     * @return the registry entry which you can use to unregister the provider
      */
-    fun registerProvider(key: String, valueProvider: () -> Any?)
-
-    /**
-     * Unregisters the value provider previously registered via [registerProvider].
-     *
-     * @param key Key of the value which shouldn't be saved anymore
-     * @param valueProvider The provider previously passed to [registerProvider]
-     */
-    fun unregisterProvider(key: String, valueProvider: () -> Any?)
+    fun registerProvider(key: String, valueProvider: () -> Any?): Entry
 
     /**
      * Returns true if the value can be saved using this Registry.
@@ -68,6 +62,16 @@
      * a list of values for each key as it is allowed to have multiple providers for the same key.
      */
     fun performSave(): Map<String, List<Any?>>
+
+    /**
+     * The registry entry which you get when you use [registerProvider].
+     */
+    interface Entry {
+        /**
+         * Unregister previously registered entry.
+         */
+        fun unregister()
+    }
 }
 
 /**
@@ -109,21 +113,19 @@
         }
     }
 
-    override fun registerProvider(key: String, valueProvider: () -> Any?) {
+    override fun registerProvider(key: String, valueProvider: () -> Any?): Entry {
         require(key.isNotBlank()) { "Registered key is empty or blank" }
         @Suppress("UNCHECKED_CAST")
         valueProviders.getOrPut(key) { mutableListOf() }.add(valueProvider)
-    }
-
-    override fun unregisterProvider(key: String, valueProvider: () -> Any?) {
-        val list = valueProviders.remove(key)
-        val found = list?.remove(valueProvider)
-        require(found == true) {
-            "The given key $key , valueProvider pair wasn't previously registered"
-        }
-        if (list.isNotEmpty()) {
-            // if there are other providers for this key return list back to the map
-            valueProviders[key] = list
+        return object : Entry {
+            override fun unregister() {
+                val list = valueProviders.remove(key)
+                list?.remove(valueProvider)
+                if (list != null && list.isNotEmpty()) {
+                    // if there are other providers for this key return list back to the map
+                    valueProviders[key] = list
+                }
+            }
         }
     }
 
diff --git a/compose/runtime/runtime-saveable/src/test/java/androidx/compose/runtime/saveable/SaveableStateRegistryTest.kt b/compose/runtime/runtime-saveable/src/test/java/androidx/compose/runtime/saveable/SaveableStateRegistryTest.kt
index bf3ec29..1dbda70 100644
--- a/compose/runtime/runtime-saveable/src/test/java/androidx/compose/runtime/saveable/SaveableStateRegistryTest.kt
+++ b/compose/runtime/runtime-saveable/src/test/java/androidx/compose/runtime/saveable/SaveableStateRegistryTest.kt
@@ -40,8 +40,8 @@
         val registry = createRegistry()
 
         val provider = { 10 }
-        registry.registerProvider("key", provider)
-        registry.unregisterProvider("key", provider)
+        val entry = registry.registerProvider("key", provider)
+        entry.unregister()
 
         registry.performSave().apply {
             assertThat(containsKey("key")).isFalse()
@@ -53,8 +53,8 @@
         val registry = createRegistry()
 
         val provider1 = { "value1" }
-        registry.registerProvider("key", provider1)
-        registry.unregisterProvider("key", provider1)
+        val entry = registry.registerProvider("key", provider1)
+        entry.unregister()
         registry.registerProvider("key") { "value2" }
 
         registry.performSave().apply {
@@ -68,10 +68,10 @@
 
         registry.registerProvider("key1") { 100L }
         val provider2 = { 100 }
-        registry.registerProvider("key2", provider2)
+        val entry = registry.registerProvider("key2", provider2)
         registry.registerProvider("key3") { "value" }
         registry.registerProvider("key4") { listOf("item") }
-        registry.unregisterProvider("key2", provider2)
+        entry.unregister()
 
         registry.performSave().apply {
             assertThat(get("key1")).isEqualTo(listOf(100L))
@@ -180,10 +180,9 @@
         val registry = createRegistry()
 
         registry.registerProvider("key") { 1L }
-        val provider2 = { 2 }
-        registry.registerProvider("key", provider2)
-        registry.registerProvider("key") { 3 }
-        registry.unregisterProvider("key", provider2)
+        val entry = registry.registerProvider("key") { 2L }
+        registry.registerProvider("key") { 3L }
+        entry.unregister()
 
         val restoredRegistry = createRegistry(registry.performSave())
         assertThat(restoredRegistry.consumeRestored("key")).isEqualTo(1L)
diff --git a/compose/ui/ui-test-junit4/src/androidMain/kotlin/androidx/compose/ui/test/junit4/StateRestorationTester.kt b/compose/ui/ui-test-junit4/src/androidMain/kotlin/androidx/compose/ui/test/junit4/StateRestorationTester.kt
index cbbb360..90e1c1a 100644
--- a/compose/ui/ui-test-junit4/src/androidMain/kotlin/androidx/compose/ui/test/junit4/StateRestorationTester.kt
+++ b/compose/ui/ui-test-junit4/src/androidMain/kotlin/androidx/compose/ui/test/junit4/StateRestorationTester.kt
@@ -116,9 +116,6 @@
         override fun registerProvider(key: String, valueProvider: () -> Any?) =
             currentRegistry.registerProvider(key, valueProvider)
 
-        override fun unregisterProvider(key: String, valueProvider: () -> Any?) =
-            currentRegistry.unregisterProvider(key, valueProvider)
-
         override fun canBeSaved(value: Any) = currentRegistry.canBeSaved(value)
 
         override fun performSave() = currentRegistry.performSave()