Merge "Run ./gradlew updateAbi" into androidx-main
diff --git a/lifecycle/lifecycle-viewmodel/api/current.txt b/lifecycle/lifecycle-viewmodel/api/current.txt
index f4d093f..7181574 100644
--- a/lifecycle/lifecycle-viewmodel/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/current.txt
@@ -124,6 +124,11 @@
public abstract class CreationExtras {
method public abstract operator <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Companion Companion;
+ }
+
+ public static final class CreationExtras.Companion {
+ method public inline <reified T> androidx.lifecycle.viewmodel.CreationExtras.Key<T> Key();
}
public static final class CreationExtras.Empty extends androidx.lifecycle.viewmodel.CreationExtras {
@@ -134,6 +139,12 @@
public static interface CreationExtras.Key<T> {
}
+ public final class CreationExtrasKt {
+ method public static operator boolean contains(androidx.lifecycle.viewmodel.CreationExtras, androidx.lifecycle.viewmodel.CreationExtras.Key<? extends java.lang.Object?> key);
+ method public static operator androidx.lifecycle.viewmodel.MutableCreationExtras plus(androidx.lifecycle.viewmodel.CreationExtras, androidx.lifecycle.viewmodel.CreationExtras creationExtras);
+ method public static operator void plusAssign(androidx.lifecycle.viewmodel.MutableCreationExtras, androidx.lifecycle.viewmodel.CreationExtras creationExtras);
+ }
+
@androidx.lifecycle.viewmodel.ViewModelFactoryDsl public final class InitializerViewModelFactoryBuilder {
ctor public InitializerViewModelFactoryBuilder();
method public <T extends androidx.lifecycle.ViewModel> void addInitializer(kotlin.reflect.KClass<T> clazz, kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.CreationExtras,? extends T> initializer);
@@ -146,6 +157,7 @@
}
public final class MutableCreationExtras extends androidx.lifecycle.viewmodel.CreationExtras {
+ ctor public MutableCreationExtras();
ctor public MutableCreationExtras(optional androidx.lifecycle.viewmodel.CreationExtras initialExtras);
method public <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
method public operator <T> void set(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key, T t);
diff --git a/lifecycle/lifecycle-viewmodel/api/restricted_current.txt b/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
index f4d093f..7181574 100644
--- a/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
@@ -124,6 +124,11 @@
public abstract class CreationExtras {
method public abstract operator <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Companion Companion;
+ }
+
+ public static final class CreationExtras.Companion {
+ method public inline <reified T> androidx.lifecycle.viewmodel.CreationExtras.Key<T> Key();
}
public static final class CreationExtras.Empty extends androidx.lifecycle.viewmodel.CreationExtras {
@@ -134,6 +139,12 @@
public static interface CreationExtras.Key<T> {
}
+ public final class CreationExtrasKt {
+ method public static operator boolean contains(androidx.lifecycle.viewmodel.CreationExtras, androidx.lifecycle.viewmodel.CreationExtras.Key<? extends java.lang.Object?> key);
+ method public static operator androidx.lifecycle.viewmodel.MutableCreationExtras plus(androidx.lifecycle.viewmodel.CreationExtras, androidx.lifecycle.viewmodel.CreationExtras creationExtras);
+ method public static operator void plusAssign(androidx.lifecycle.viewmodel.MutableCreationExtras, androidx.lifecycle.viewmodel.CreationExtras creationExtras);
+ }
+
@androidx.lifecycle.viewmodel.ViewModelFactoryDsl public final class InitializerViewModelFactoryBuilder {
ctor public InitializerViewModelFactoryBuilder();
method public <T extends androidx.lifecycle.ViewModel> void addInitializer(kotlin.reflect.KClass<T> clazz, kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.CreationExtras,? extends T> initializer);
@@ -146,6 +157,7 @@
}
public final class MutableCreationExtras extends androidx.lifecycle.viewmodel.CreationExtras {
+ ctor public MutableCreationExtras();
ctor public MutableCreationExtras(optional androidx.lifecycle.viewmodel.CreationExtras initialExtras);
method public <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
method public operator <T> void set(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key, T t);
diff --git a/lifecycle/lifecycle-viewmodel/bcv/native/current.txt b/lifecycle/lifecycle-viewmodel/bcv/native/current.txt
index 6570006..c22e7d4 100644
--- a/lifecycle/lifecycle-viewmodel/bcv/native/current.txt
+++ b/lifecycle/lifecycle-viewmodel/bcv/native/current.txt
@@ -9,9 +9,15 @@
abstract class androidx.lifecycle.viewmodel/CreationExtras { // androidx.lifecycle.viewmodel/CreationExtras|null[0]
abstract fun <#A1: kotlin/Any?> get(androidx.lifecycle.viewmodel/CreationExtras.Key<#A1>): #A1? // androidx.lifecycle.viewmodel/CreationExtras.get|get(androidx.lifecycle.viewmodel.CreationExtras.Key<0:0>){0§<kotlin.Any?>}[0]
abstract interface <#A1: kotlin/Any?> Key // androidx.lifecycle.viewmodel/CreationExtras.Key|null[0]
+ final object Companion { // androidx.lifecycle.viewmodel/CreationExtras.Companion|null[0]
+ final inline fun <#A2: reified kotlin/Any?> Key(): androidx.lifecycle.viewmodel/CreationExtras.Key<#A2> // androidx.lifecycle.viewmodel/CreationExtras.Companion.Key|Key(){0§<kotlin.Any?>}[0]
+ }
final object Empty : androidx.lifecycle.viewmodel/CreationExtras { // androidx.lifecycle.viewmodel/CreationExtras.Empty|null[0]
final fun <#A2: kotlin/Any?> get(androidx.lifecycle.viewmodel/CreationExtras.Key<#A2>): #A2? // androidx.lifecycle.viewmodel/CreationExtras.Empty.get|get(androidx.lifecycle.viewmodel.CreationExtras.Key<0:0>){0§<kotlin.Any?>}[0]
}
+ open fun equals(kotlin/Any?): kotlin/Boolean // androidx.lifecycle.viewmodel/CreationExtras.equals|equals(kotlin.Any?){}[0]
+ open fun hashCode(): kotlin/Int // androidx.lifecycle.viewmodel/CreationExtras.hashCode|hashCode(){}[0]
+ open fun toString(): kotlin/String // androidx.lifecycle.viewmodel/CreationExtras.toString|toString(){}[0]
}
abstract class androidx.lifecycle/ViewModel { // androidx.lifecycle/ViewModel|null[0]
constructor <init>() // androidx.lifecycle/ViewModel.<init>|<init>(){}[0]
@@ -69,6 +75,9 @@
open fun onRequery(androidx.lifecycle/ViewModel) // androidx.lifecycle/ViewModelProvider.OnRequeryFactory.onRequery|onRequery(androidx.lifecycle.ViewModel){}[0]
}
}
+final fun (androidx.lifecycle.viewmodel/CreationExtras).androidx.lifecycle.viewmodel/contains(androidx.lifecycle.viewmodel/CreationExtras.Key<*>): kotlin/Boolean // androidx.lifecycle.viewmodel/contains|[email protected](androidx.lifecycle.viewmodel.CreationExtras.Key<*>){}[0]
+final fun (androidx.lifecycle.viewmodel/CreationExtras).androidx.lifecycle.viewmodel/plus(androidx.lifecycle.viewmodel/CreationExtras): androidx.lifecycle.viewmodel/MutableCreationExtras // androidx.lifecycle.viewmodel/plus|[email protected](androidx.lifecycle.viewmodel.CreationExtras){}[0]
+final fun (androidx.lifecycle.viewmodel/MutableCreationExtras).androidx.lifecycle.viewmodel/plusAssign(androidx.lifecycle.viewmodel/CreationExtras) // androidx.lifecycle.viewmodel/plusAssign|[email protected](androidx.lifecycle.viewmodel.CreationExtras){}[0]
final inline fun <#A: reified androidx.lifecycle/ViewModel> (androidx.lifecycle.viewmodel/InitializerViewModelFactoryBuilder).androidx.lifecycle.viewmodel/initializer(noinline kotlin/Function1<androidx.lifecycle.viewmodel/CreationExtras, #A>) // androidx.lifecycle.viewmodel/initializer|initializer@androidx.lifecycle.viewmodel.InitializerViewModelFactoryBuilder(kotlin.Function1<androidx.lifecycle.viewmodel.CreationExtras,0:0>){0§<androidx.lifecycle.ViewModel>}[0]
final inline fun <#A: reified androidx.lifecycle/ViewModel> (androidx.lifecycle/ViewModelProvider).androidx.lifecycle/get(): #A // androidx.lifecycle/get|[email protected](){0§<androidx.lifecycle.ViewModel>}[0]
final inline fun androidx.lifecycle.viewmodel/viewModelFactory(kotlin/Function1<androidx.lifecycle.viewmodel/InitializerViewModelFactoryBuilder, kotlin/Unit>): androidx.lifecycle/ViewModelProvider.Factory // androidx.lifecycle.viewmodel/viewModelFactory|viewModelFactory(kotlin.Function1<androidx.lifecycle.viewmodel.InitializerViewModelFactoryBuilder,kotlin.Unit>){}[0]
diff --git a/lifecycle/lifecycle-viewmodel/src/androidInstrumentedTest/kotlin/androidx/lifecycle/CreationExtrasTest.kt b/lifecycle/lifecycle-viewmodel/src/androidInstrumentedTest/kotlin/androidx/lifecycle/CreationExtrasTest.kt
index ef58257..f64b119 100644
--- a/lifecycle/lifecycle-viewmodel/src/androidInstrumentedTest/kotlin/androidx/lifecycle/CreationExtrasTest.kt
+++ b/lifecycle/lifecycle-viewmodel/src/androidInstrumentedTest/kotlin/androidx/lifecycle/CreationExtrasTest.kt
@@ -16,26 +16,115 @@
package androidx.lifecycle
-import android.os.Bundle
-import androidx.core.os.bundleOf
import androidx.kruth.assertThat
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.MutableCreationExtras
+import androidx.lifecycle.viewmodel.contains
+import androidx.lifecycle.viewmodel.plus
+import androidx.lifecycle.viewmodel.plusAssign
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import org.junit.Test
import org.junit.runner.RunWith
+private val STRING_KEY_1 = CreationExtras.Key<String>()
+private val STRING_KEY_2 = CreationExtras.Key<String>()
+
@RunWith(AndroidJUnit4::class)
@SmallTest
class CreationExtrasTest {
+
@Test
- fun testInitialCreationExtras() {
- val initial = MutableCreationExtras()
- val key = object : CreationExtras.Key<Bundle> {}
- initial[key] = bundleOf("value" to "initial")
- val mutable = MutableCreationExtras(initial)
- initial[key] = bundleOf("value" to "overridden")
- assertThat(mutable[key]?.getString("value")).isEqualTo("initial")
+ fun keyFactory_returnsDistinctInstances() {
+ val key1 = CreationExtras.Key<String>()
+ val key2 = CreationExtras.Key<String>()
+
+ assertThat(key1).isNotEqualTo(key2)
+ }
+
+ @Test
+ fun initialExtras_originalModifiedAfterCopy_copyRemainsUnchanged() {
+ val otherExtras = MutableCreationExtras().apply { this[STRING_KEY_1] = "value1" }
+ val underTest = MutableCreationExtras(initialExtras = otherExtras)
+ otherExtras[STRING_KEY_1] = "value2"
+
+ assertThat(otherExtras[STRING_KEY_1]).isEqualTo("value2")
+ assertThat(underTest[STRING_KEY_1]).isEqualTo("value1")
+ }
+
+ @Test
+ fun equals_sameValues_isEqual() {
+ val underTest = MutableCreationExtras().apply { this[STRING_KEY_1] = "value1" }
+ val otherExtras = MutableCreationExtras().apply { this[STRING_KEY_1] = "value1" }
+
+ assertThat(underTest).isEqualTo(otherExtras)
+ }
+
+ @Test
+ fun equals_differentValues_isNotEqual() {
+ val underTest = MutableCreationExtras().apply { this[STRING_KEY_1] = "value1" }
+ val otherExtras = MutableCreationExtras().apply { this[STRING_KEY_1] = "value2" }
+
+ assertThat(underTest).isNotEqualTo(otherExtras)
+ }
+
+ @Test
+ fun contains_returnsTrueForExistingKey() {
+ val underTest = MutableCreationExtras().apply { this[STRING_KEY_1] = "value1" }
+
+ val result = STRING_KEY_1 in underTest
+
+ assertThat(result).isTrue()
+ }
+
+ @Test
+ fun contains_returnsFalseForNonExistingKey() {
+ val underTest = MutableCreationExtras().apply { this[STRING_KEY_1] = "value1" }
+
+ val result = STRING_KEY_2 in underTest
+
+ assertThat(result).isFalse()
+ }
+
+ @Test
+ fun plus_addedTogetherWithUniqueKeys_combinesValues() {
+ val extras1 = MutableCreationExtras().apply { this[STRING_KEY_1] = "value1" }
+ val extras2 = MutableCreationExtras().apply { this[STRING_KEY_2] = "value2" }
+
+ val underTest = extras1 + extras2
+
+ assertThat(underTest[STRING_KEY_1]).isEqualTo(extras1[STRING_KEY_1])
+ assertThat(underTest[STRING_KEY_2]).isEqualTo(extras2[STRING_KEY_2])
+ }
+
+ @Test
+ fun plus_addedTogetherWithConflictingKeys_overridesFirstValue() {
+ val extras1 = MutableCreationExtras().apply { this[STRING_KEY_1] = "value1" }
+ val extras2 = MutableCreationExtras().apply { this[STRING_KEY_1] = "value2" }
+
+ val underTest = extras1 + extras2
+
+ assertThat(underTest[STRING_KEY_1]).isEqualTo(extras2[STRING_KEY_1])
+ }
+
+ @Test
+ fun plusAssign_addedTogetherWithUniqueKeys_combinesValues() {
+ val underTest = MutableCreationExtras().apply { this[STRING_KEY_1] = "value1" }
+ val otherExtras = MutableCreationExtras().apply { this[STRING_KEY_2] = "value2" }
+
+ underTest += otherExtras
+
+ assertThat(underTest[STRING_KEY_1]).isEqualTo(underTest[STRING_KEY_1])
+ assertThat(underTest[STRING_KEY_2]).isEqualTo(otherExtras[STRING_KEY_2])
+ }
+
+ @Test
+ fun plusAssign_addedTogetherWithConflictingKeys_overridesFirstValue() {
+ val underTest = MutableCreationExtras().apply { this[STRING_KEY_1] = "value1" }
+ val otherExtras = MutableCreationExtras().apply { this[STRING_KEY_1] = "value2" }
+
+ underTest += otherExtras
+
+ assertThat(underTest[STRING_KEY_1]).isEqualTo(otherExtras[STRING_KEY_1])
}
}
diff --git a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/CreationExtras.kt b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/CreationExtras.kt
index 3592b35..f7dfc9e 100644
--- a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/CreationExtras.kt
+++ b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/CreationExtras.kt
@@ -15,45 +15,120 @@
*/
package androidx.lifecycle.viewmodel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.ViewModelProvider.Factory
+import androidx.lifecycle.viewmodel.CreationExtras.Key
+import kotlin.jvm.JvmOverloads
+import kotlin.jvm.JvmStatic
+
/**
- * Simple map-like object that passed in [ViewModelProvider.Factory.create] to provide an additional
- * information to a factory.
+ * A map-like object holding pairs of [CreationExtras.Key] and [Any], enabling efficient value
+ * retrieval for each key. Each key in [CreationExtras] is unique, storing only one value per key.
*
- * It allows making `Factory` implementations stateless, which makes an injection of factories
- * easier because don't require all information be available at construction time.
+ * [CreationExtras] is used in [ViewModelProvider.Factory.create] to provide extra information to
+ * the [Factory]. This makes [Factory] implementations stateless, simplifying factory injection by
+ * not requiring all information at construction time.
+ *
+ * This abstract class supports read-only access; use [MutableCreationExtras] for read-write access.
*/
public abstract class CreationExtras internal constructor() {
- internal val map: MutableMap<Key<*>, Any?> = mutableMapOf()
+ internal val extras: MutableMap<Key<*>, Any?> = mutableMapOf()
- /** Key for the elements of [CreationExtras]. [T] is a type of an element with this key. */
+ /**
+ * Key for the elements of [CreationExtras]. [T] represents the type of element associated with
+ * this key.
+ */
public interface Key<T>
- /** Returns an element associated with the given [key] */
+ /**
+ * Returns the value to which the specified [key] is associated, or null if this
+ * [CreationExtras] contains no mapping for the key.
+ */
public abstract operator fun <T> get(key: Key<T>): T?
- /** Empty [CreationExtras] */
+ /** Compares the specified object with this [CreationExtras] for equality. */
+ override fun equals(other: Any?): Boolean = other is CreationExtras && extras == other.extras
+
+ /** Returns the hash code value for this [CreationExtras]. */
+ override fun hashCode(): Int = extras.hashCode()
+
+ /**
+ * Returns a string representation of this [CreationExtras]. The string representation consists
+ * of a list of key-value mappings in the order returned by the [CreationExtras]'s iterator.
+ */
+ override fun toString(): String = "CreationExtras(extras=$extras)"
+
+ /** An empty read-only [CreationExtras]. */
public object Empty : CreationExtras() {
override fun <T> get(key: Key<T>): T? = null
}
+
+ public companion object {
+ /** Returns an unique [Key] to be associated with an extra. */
+ @JvmStatic public inline fun <reified T> Key(): Key<T> = object : Key<T> {}
+ }
}
/**
- * Mutable implementation of [CreationExtras]
+ * A modifiable [CreationExtras] that holds pairs of [CreationExtras.Key] and [Any], allowing
+ * efficient value retrieval for each key.
*
- * @param initialExtras extras that will be filled into the resulting MutableCreationExtras
+ * Each key in [CreationExtras] is unique, storing only one value per key.
+ *
+ * @see [CreationExtras]
*/
-public class MutableCreationExtras(initialExtras: CreationExtras = Empty) : CreationExtras() {
+public class MutableCreationExtras
+/**
+ * Constructs a [MutableCreationExtras] containing the elements of the specified `initialExtras`, in
+ * the order they are returned by the [Map]'s iterator.
+ */
+internal constructor(initialExtras: Map<Key<*>, Any?>) : CreationExtras() {
+
+ /**
+ * Constructs a [MutableCreationExtras] containing the elements of the specified
+ * [initialExtras], in the order they are returned by the [CreationExtras]'s iterator.
+ */
+ @JvmOverloads
+ public constructor(initialExtras: CreationExtras = Empty) : this(initialExtras.extras)
init {
- map.putAll(initialExtras.map)
+ extras += initialExtras
}
- /** Associates the given [key] with [t] */
+ /** Associates the specified [t] with the specified [key] in this [CreationExtras]. */
public operator fun <T> set(key: Key<T>, t: T) {
- map[key] = t
+ extras[key] = t
}
- public override fun <T> get(key: Key<T>): T? {
- @Suppress("UNCHECKED_CAST") return map[key] as T?
- }
+ /**
+ * Returns the value to which the specified [key] is associated, or null if this
+ * [CreationExtras] contains no mapping for the key.
+ */
+ @Suppress("UNCHECKED_CAST") public override fun <T> get(key: Key<T>): T? = extras[key] as T?
+}
+
+/**
+ * Checks if the [CreationExtras] contains the given [key].
+ *
+ * This method allows to use the `key in creationExtras` syntax for checking whether an [key] is
+ * contained in the [CreationExtras].
+ */
+public operator fun CreationExtras.contains(key: Key<*>): Boolean = key in extras
+
+/**
+ * Creates a new read-only [CreationExtras] by replacing or adding entries to [this] extras from
+ * another [creationExtras].
+ *
+ * The returned [CreationExtras] preserves the entry iteration order of the original
+ * [CreationExtras].
+ *
+ * Those entries of another [creationExtras] that are missing in [this] extras are iterated in the
+ * end in the order of that [creationExtras].
+ */
+public operator fun CreationExtras.plus(creationExtras: CreationExtras): MutableCreationExtras =
+ MutableCreationExtras(initialExtras = extras + creationExtras.extras)
+
+/** Appends or replaces all entries from the given [creationExtras] in [this] mutable extras. */
+public operator fun MutableCreationExtras.plusAssign(creationExtras: CreationExtras) {
+ extras += creationExtras.extras
}