Introduce CreationExtras

It also passes key associated with ViewModel
as an extra.

Metalava incorrectly says that this is a breaking change: b/188691010

Relnote: "ViewModelProvider.CreationExtras were introduced.
This API will simplify passing an additional information to ViewModelProvider.Factory"
bug: 188541057
Test: ViewModelProviderTest

Change-Id: Ia73439cb2282609a9a1eaebf8ba79b9cc93feb7c
diff --git a/lifecycle/lifecycle-viewmodel-compose/build.gradle b/lifecycle/lifecycle-viewmodel-compose/build.gradle
index d389e76..30a05a0 100644
--- a/lifecycle/lifecycle-viewmodel-compose/build.gradle
+++ b/lifecycle/lifecycle-viewmodel-compose/build.gradle
@@ -17,6 +17,7 @@
 import androidx.build.LibraryGroups
 import androidx.build.Publish
 import androidx.build.RunApiTasks
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -53,3 +54,15 @@
     description = "Compose integration with Lifecycle ViewModel"
     runApiTasks = new RunApiTasks.Yes()
 }
+
+// needed only while https://youtrack.jetbrains.com/issue/KT-47000 isn't resolved which is
+// targeted to 1.6
+if (project.hasProperty("androidx.useMaxDepVersions")){
+    tasks.withType(KotlinCompile).configureEach {
+        kotlinOptions {
+            freeCompilerArgs += [
+                    "-Xjvm-default=enable",
+            ]
+        }
+    }
+}
\ No newline at end of file
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/api/current.ignore b/lifecycle/lifecycle-viewmodel-savedstate/api/current.ignore
new file mode 100644
index 0000000..be07271
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-savedstate/api/current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+RemovedMethod: androidx.lifecycle.SavedStateViewModelFactory#create(Class<T>):
+    Removed method androidx.lifecycle.SavedStateViewModelFactory.create(Class<T>)
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt b/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt
index f830aba..1447260 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt
@@ -25,7 +25,6 @@
     ctor public SavedStateViewModelFactory(android.app.Application?, androidx.savedstate.SavedStateRegistryOwner);
     ctor public SavedStateViewModelFactory(android.app.Application?, androidx.savedstate.SavedStateRegistryOwner, android.os.Bundle?);
     method public <T extends androidx.lifecycle.ViewModel> T create(String, Class<T!>);
-    method public <T extends androidx.lifecycle.ViewModel> T create(Class<T!>);
   }
 
 }
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/api/public_plus_experimental_current.txt b/lifecycle/lifecycle-viewmodel-savedstate/api/public_plus_experimental_current.txt
index f830aba..1447260 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/api/public_plus_experimental_current.txt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/api/public_plus_experimental_current.txt
@@ -25,7 +25,6 @@
     ctor public SavedStateViewModelFactory(android.app.Application?, androidx.savedstate.SavedStateRegistryOwner);
     ctor public SavedStateViewModelFactory(android.app.Application?, androidx.savedstate.SavedStateRegistryOwner, android.os.Bundle?);
     method public <T extends androidx.lifecycle.ViewModel> T create(String, Class<T!>);
-    method public <T extends androidx.lifecycle.ViewModel> T create(Class<T!>);
   }
 
 }
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/build.gradle b/lifecycle/lifecycle-viewmodel-savedstate/build.gradle
index 85e49e0..7f9470d 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/build.gradle
+++ b/lifecycle/lifecycle-viewmodel-savedstate/build.gradle
@@ -38,18 +38,8 @@
 
     androidTestImplementation projectOrArtifact(":lifecycle:lifecycle-runtime")
     androidTestImplementation projectOrArtifact(":lifecycle:lifecycle-livedata-core")
-    androidTestImplementation ("androidx.fragment:fragment:1.3.0") {
-        exclude group: "androidx.lifecycle", module: "lifecycle-runtime"
-        exclude group: "androidx.lifecycle", module: "lifecycle-livedata-core"
-        exclude group: "androidx.lifecycle", module: "lifecycle-viewmodel-savedstate"
-        exclude group: "androidx.lifecycle", module: "lifecycle-viewmodel"
-    }
-    androidTestImplementation project(":internal-testutils-runtime"), {
-        exclude group: "androidx.lifecycle", module: "lifecycle-runtime"
-        exclude group: "androidx.lifecycle", module: "lifecycle-livedata-core"
-        exclude group: "androidx.lifecycle", module: "lifecycle-viewmodel-savedstate"
-        exclude group: "androidx.lifecycle", module: "lifecycle-viewmodel"
-    }
+    androidTestImplementation ("androidx.fragment:fragment:1.3.0")
+    androidTestImplementation project(":internal-testutils-runtime")
     androidTestImplementation(libs.truth)
     androidTestImplementation(libs.kotlinStdlib)
     androidTestImplementation(libs.testExtJunit)
diff --git a/lifecycle/lifecycle-viewmodel/api/current.txt b/lifecycle/lifecycle-viewmodel/api/current.txt
index b2a64d8..d63c190 100644
--- a/lifecycle/lifecycle-viewmodel/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/current.txt
@@ -41,13 +41,14 @@
   }
 
   public static interface ViewModelProvider.Factory {
-    method public <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass);
+    method public default <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass);
+    method public default <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass, androidx.lifecycle.viewmodel.CreationExtras extras);
   }
 
   public static class ViewModelProvider.NewInstanceFactory implements androidx.lifecycle.ViewModelProvider.Factory {
     ctor public ViewModelProvider.NewInstanceFactory();
-    method public <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass);
     field public static final androidx.lifecycle.ViewModelProvider.NewInstanceFactory.Companion Companion;
+    field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<java.lang.String> VIEW_MODEL_KEY;
   }
 
   public static final class ViewModelProvider.NewInstanceFactory.Companion {
@@ -77,3 +78,20 @@
 
 }
 
+package androidx.lifecycle.viewmodel {
+
+  public interface CreationExtras {
+    method public operator <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
+  }
+
+  public static interface CreationExtras.Key<T> {
+  }
+
+  public final class MutableCreationExtras implements androidx.lifecycle.viewmodel.CreationExtras {
+    ctor public MutableCreationExtras();
+    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/public_plus_experimental_current.txt b/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt
index b2a64d8..d63c190 100644
--- a/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt
@@ -41,13 +41,14 @@
   }
 
   public static interface ViewModelProvider.Factory {
-    method public <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass);
+    method public default <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass);
+    method public default <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass, androidx.lifecycle.viewmodel.CreationExtras extras);
   }
 
   public static class ViewModelProvider.NewInstanceFactory implements androidx.lifecycle.ViewModelProvider.Factory {
     ctor public ViewModelProvider.NewInstanceFactory();
-    method public <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass);
     field public static final androidx.lifecycle.ViewModelProvider.NewInstanceFactory.Companion Companion;
+    field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<java.lang.String> VIEW_MODEL_KEY;
   }
 
   public static final class ViewModelProvider.NewInstanceFactory.Companion {
@@ -77,3 +78,20 @@
 
 }
 
+package androidx.lifecycle.viewmodel {
+
+  public interface CreationExtras {
+    method public operator <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
+  }
+
+  public static interface CreationExtras.Key<T> {
+  }
+
+  public final class MutableCreationExtras implements androidx.lifecycle.viewmodel.CreationExtras {
+    ctor public MutableCreationExtras();
+    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 b2a64d8..d63c190 100644
--- a/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
@@ -41,13 +41,14 @@
   }
 
   public static interface ViewModelProvider.Factory {
-    method public <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass);
+    method public default <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass);
+    method public default <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass, androidx.lifecycle.viewmodel.CreationExtras extras);
   }
 
   public static class ViewModelProvider.NewInstanceFactory implements androidx.lifecycle.ViewModelProvider.Factory {
     ctor public ViewModelProvider.NewInstanceFactory();
-    method public <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass);
     field public static final androidx.lifecycle.ViewModelProvider.NewInstanceFactory.Companion Companion;
+    field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<java.lang.String> VIEW_MODEL_KEY;
   }
 
   public static final class ViewModelProvider.NewInstanceFactory.Companion {
@@ -77,3 +78,20 @@
 
 }
 
+package androidx.lifecycle.viewmodel {
+
+  public interface CreationExtras {
+    method public operator <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
+  }
+
+  public static interface CreationExtras.Key<T> {
+  }
+
+  public final class MutableCreationExtras implements androidx.lifecycle.viewmodel.CreationExtras {
+    ctor public MutableCreationExtras();
+    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/build.gradle b/lifecycle/lifecycle-viewmodel/build.gradle
index 575ce58..e48ccd6 100644
--- a/lifecycle/lifecycle-viewmodel/build.gradle
+++ b/lifecycle/lifecycle-viewmodel/build.gradle
@@ -17,6 +17,7 @@
 
 import androidx.build.LibraryGroups
 import androidx.build.Publish
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -52,3 +53,11 @@
     inceptionYear = "2017"
     description = "Android Lifecycle ViewModel"
 }
+
+tasks.withType(KotlinCompile).configureEach {
+    kotlinOptions {
+        freeCompilerArgs += [
+                "-Xjvm-default=all",
+        ]
+    }
+}
diff --git a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.kt b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.kt
index 82a33cc..f933a72 100644
--- a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.kt
+++ b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.kt
@@ -20,6 +20,10 @@
 import androidx.annotation.RestrictTo
 import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.DEFAULT_KEY
 import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.defaultFactory
+import androidx.lifecycle.viewmodel.CreationExtras.Key
+import androidx.lifecycle.ViewModelProvider.NewInstanceFactory.Companion.VIEW_MODEL_KEY
+import androidx.lifecycle.viewmodel.CreationExtras
+import androidx.lifecycle.viewmodel.MutableCreationExtras
 import java.lang.IllegalArgumentException
 import java.lang.RuntimeException
 import java.lang.UnsupportedOperationException
@@ -46,10 +50,27 @@
         /**
          * Creates a new instance of the given `Class`.
          *
+         * Default implementation throws [UnsupportedOperationException].
+         *
          * @param modelClass a `Class` whose instance is requested
          * @return a newly created ViewModel
          */
-        public fun <T : ViewModel> create(modelClass: Class<T>): T
+        public fun <T : ViewModel> create(modelClass: Class<T>): T {
+            throw UnsupportedOperationException(
+                "Factory.create(String) is unsupported.  This Factory requires " +
+                    "`CreationExtras` to be passed into `create` method."
+            )
+        }
+
+        /**
+         * Creates a new instance of the given `Class`.
+         *
+         * @param modelClass a `Class` whose instance is requested
+         * @param extras an additional information for this creation request
+         * @return a newly created ViewModel
+         */
+        public fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T =
+            create(modelClass)
     }
 
     /**
@@ -83,6 +104,10 @@
             modelClass: Class<T>
         ): T
 
+        override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
+            return create(extras[VIEW_MODEL_KEY]!!, modelClass)
+        }
+
         override fun <T : ViewModel> create(modelClass: Class<T>): T {
             throw UnsupportedOperationException(
                 "create(String, Class<?>) must be called on implementations of KeyedFactory"
@@ -155,7 +180,7 @@
     @Suppress("UNCHECKED_CAST")
     @MainThread
     public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
-        var viewModel = store[key]
+        val viewModel = store[key]
         if (modelClass.isInstance(viewModel)) {
             (factory as? OnRequeryFactory)?.onRequery(viewModel)
             return viewModel as T
@@ -165,13 +190,9 @@
                 // TODO: log a warning.
             }
         }
-        viewModel = if (factory is KeyedFactory) {
-            factory.create(key, modelClass)
-        } else {
-            factory.create(modelClass)
-        }
-        store.put(key, viewModel)
-        return viewModel
+        val extras = MutableCreationExtras()
+        extras[VIEW_MODEL_KEY] = key
+        return factory.create(modelClass, extras).also { store.put(key, it) }
     }
 
     /**
@@ -209,6 +230,19 @@
                     }
                     return sInstance!!
                 }
+
+            private object ViewModelKeyImpl : Key<String>
+            /**
+             * A [CreationExtras.Key] to get a key associated with a requested
+             * `ViewModel` from [CreationExtras]
+             *
+             *  `ViewModelProvider` automatically puts a key that was passed to
+             *  `ViewModelProvider.get(key, MyViewModel::class.java)`
+             *  or generated in `ViewModelProvider.get(MyViewModel::class.java)` to the `CreationExtras` that
+             *  are passed to [ViewModelProvider.Factory].
+             */
+            @JvmField
+            val VIEW_MODEL_KEY: Key<String> = ViewModelKeyImpl
         }
     }
 
diff --git a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/viewmodel/CreationExtras.kt b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/viewmodel/CreationExtras.kt
new file mode 100644
index 0000000..ceb94a4
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/viewmodel/CreationExtras.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2021 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 androidx.lifecycle.viewmodel
+
+/**
+ * Simple map-like object that passed in [ViewModelProvider.Factory.create]
+ * to provide an additional information to a factory.
+ *
+ * It allows making `Factory` implementations stateless, which makes an injection of factories
+ * easier because  don't require all information be available at construction time.
+ */
+public interface CreationExtras {
+    /**
+     * Key for the elements of [CreationExtras]. [T] is a type of an element with this key.
+     */
+    public interface Key<T>
+
+    /**
+     * Returns an element associated with the given [key]
+     */
+    public operator fun <T> get(key: Key<T>): T?
+}
+
+/**
+ * Mutable implementation of [CreationExtras]
+ */
+public class MutableCreationExtras : CreationExtras {
+    private val map = mutableMapOf<CreationExtras.Key<*>, Any?>()
+
+    /**
+     * Associates the given [key] with [t]
+     */
+    public operator fun <T> set(key: CreationExtras.Key<T>, t: T) {
+        map[key] = t
+    }
+
+    public override fun <T> get(key: CreationExtras.Key<T>): T? {
+        @Suppress("UNCHECKED_CAST")
+        return map[key] as T?
+    }
+}
diff --git a/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.java b/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.java
index 7e20deb3..349589f 100644
--- a/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.java
+++ b/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.java
@@ -16,12 +16,15 @@
 
 package androidx.lifecycle;
 
+import static androidx.lifecycle.ViewModelProvider.NewInstanceFactory.VIEW_MODEL_KEY;
+
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import androidx.annotation.NonNull;
 import androidx.lifecycle.ViewModelProvider.NewInstanceFactory;
+import androidx.lifecycle.viewmodel.CreationExtras;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -40,7 +43,7 @@
     }
 
     @Test
-    public void twoViewModelsWithSameKey() throws Throwable {
+    public void twoViewModelsWithSameKey() {
         String key = "the_key";
         ViewModel1 vm1 = mViewModelProvider.get(key, ViewModel1.class);
         assertThat(vm1.mCleared, is(false));
@@ -51,7 +54,7 @@
 
 
     @Test
-    public void localViewModel() throws Throwable {
+    public void localViewModel() {
         class VM extends ViewModel1 {
         }
         try {
@@ -72,13 +75,7 @@
     @Test
     public void testOwnedBy() {
         final ViewModelStore store = new ViewModelStore();
-        ViewModelStoreOwner owner = new ViewModelStoreOwner() {
-            @NonNull
-            @Override
-            public ViewModelStore getViewModelStore() {
-                return store;
-            }
-        };
+        ViewModelStoreOwner owner = () -> store;
         ViewModelProvider provider = new ViewModelProvider(owner, new NewInstanceFactory());
         ViewModel1 viewModel = provider.get(ViewModel1.class);
         assertThat(viewModel, is(provider.get(ViewModel1.class)));
@@ -98,25 +95,34 @@
     @Test
     public void testKeyedFactory() {
         final ViewModelStore store = new ViewModelStore();
-        ViewModelStoreOwner owner = new ViewModelStoreOwner() {
-            @NonNull
-            @Override
-            public ViewModelStore getViewModelStore() {
-                return store;
-            }
-        };
-        ViewModelProvider.KeyedFactory keyed = new ViewModelProvider.KeyedFactory() {
+        ViewModelStoreOwner owner = () -> store;
+        ViewModelProvider.Factory explicitlyKeyed = new ViewModelProvider.Factory() {
             @SuppressWarnings("unchecked")
             @NonNull
             @Override
-            public <T extends ViewModel> T create(@NonNull String key,
-                    @NonNull Class<T> modelClass) {
+            public <T extends ViewModel> T create(@NonNull Class<T> modelClass,
+                    @NonNull CreationExtras extras) {
+                String key = extras.get(VIEW_MODEL_KEY);
                 assertThat(key, is("customkey"));
                 return (T) new ViewModel1();
             }
         };
-        ViewModelProvider provider = new ViewModelProvider(owner, keyed);
+
+        ViewModelProvider provider = new ViewModelProvider(owner, explicitlyKeyed);
         provider.get("customkey", ViewModel1.class);
+
+        ViewModelProvider.Factory implicitlyKeyed = new ViewModelProvider.Factory() {
+            @SuppressWarnings("unchecked")
+            @NonNull
+            @Override
+            public <T extends ViewModel> T create(@NonNull Class<T> modelClass,
+                    @NonNull CreationExtras extras) {
+                String key = extras.get(VIEW_MODEL_KEY);
+                assertThat(key, is(notNullValue()));
+                return (T) new ViewModel1();
+            }
+        };
+        new ViewModelProvider(owner, implicitlyKeyed).get("customkey", ViewModel1.class);
     }
 
     public static class ViewModelStoreOwnerWithFactory implements