Use @StringKey instead of @ViewModelKey.

Using string keys avoids unnecessary class loading.
Additionally provide a consuming optimization rule to keep
the class names of the @ViewModelInject annotated ViewModel
classes since the class canonical name is used for the
multibinding map of assisted factories.

Test: ./gradlew hilt:integration-tests:hilt-testapp-viewmodel:installRelease
Change-Id: I6286f2a2b25ae07f68c85230e3e7ec974964c6d3
diff --git a/hilt/integration-tests/viewmodelapp/build.gradle b/hilt/integration-tests/viewmodelapp/build.gradle
index 3319ac1..7177380 100644
--- a/hilt/integration-tests/viewmodelapp/build.gradle
+++ b/hilt/integration-tests/viewmodelapp/build.gradle
@@ -24,6 +24,15 @@
     id("dagger.hilt.android.plugin")
 }
 
+android {
+    buildTypes {
+        release {
+            minifyEnabled true
+            shrinkResources true
+        }
+    }
+}
+
 dependencies {
     implementation(project(":activity:activity"))
     implementation(project(":fragment:fragment-ktx"))
diff --git a/lifecycle/lifecycle-viewmodel-hilt-compiler/src/main/kotlin/androidx/lifecycle/hilt/ClassNames.kt b/lifecycle/lifecycle-viewmodel-hilt-compiler/src/main/kotlin/androidx/lifecycle/hilt/ClassNames.kt
index 9310102..71e537a 100644
--- a/lifecycle/lifecycle-viewmodel-hilt-compiler/src/main/kotlin/androidx/lifecycle/hilt/ClassNames.kt
+++ b/lifecycle/lifecycle-viewmodel-hilt-compiler/src/main/kotlin/androidx/lifecycle/hilt/ClassNames.kt
@@ -31,6 +31,6 @@
     val VIEW_MODEL_ASSISTED_FACTORY =
         ClassName.get("androidx.lifecycle.hilt", "ViewModelAssistedFactory")
     val VIEW_MODEL = ClassName.get("androidx.lifecycle", "ViewModel")
-    val VIEW_MODEL_KEY = ClassName.get("androidx.lifecycle.hilt", "ViewModelKey")
     val SAVED_STATE_HANDLE = ClassName.get("androidx.lifecycle", "SavedStateHandle")
+    val STRING_KEY = ClassName.get("dagger.multibindings", "StringKey")
 }
diff --git a/lifecycle/lifecycle-viewmodel-hilt-compiler/src/main/kotlin/androidx/lifecycle/hilt/HiltViewModelGenerator.kt b/lifecycle/lifecycle-viewmodel-hilt-compiler/src/main/kotlin/androidx/lifecycle/hilt/HiltViewModelGenerator.kt
index 6961686..0364e54 100644
--- a/lifecycle/lifecycle-viewmodel-hilt-compiler/src/main/kotlin/androidx/lifecycle/hilt/HiltViewModelGenerator.kt
+++ b/lifecycle/lifecycle-viewmodel-hilt-compiler/src/main/kotlin/androidx/lifecycle/hilt/HiltViewModelGenerator.kt
@@ -17,6 +17,7 @@
 package androidx.lifecycle.hilt
 
 import androidx.lifecycle.hilt.ext.L
+import androidx.lifecycle.hilt.ext.S
 import androidx.lifecycle.hilt.ext.T
 import androidx.lifecycle.hilt.ext.W
 import androidx.lifecycle.hilt.ext.addGeneratedAnnotation
@@ -42,7 +43,7 @@
  * public interface $_HiltModule {
  *   @Binds
  *   @IntoMap
- *   @ViewModelKey($.class)
+ *   @StringKey("pkg.$")
  *   ViewModelAssistedFactory<? extends ViewModel> bind($_AssistedFactory factory)
  * }
  * ```
@@ -101,8 +102,8 @@
                     .addAnnotation(ClassNames.BINDS)
                     .addAnnotation(ClassNames.INTO_MAP)
                     .addAnnotation(
-                        AnnotationSpec.builder(ClassNames.VIEW_MODEL_KEY)
-                            .addMember("value", "$T.class", viewModelElements.className)
+                        AnnotationSpec.builder(ClassNames.STRING_KEY)
+                            .addMember("value", S, viewModelElements.className.canonicalName())
                             .build())
                     .addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
                     .returns(
diff --git a/lifecycle/lifecycle-viewmodel-hilt-compiler/src/test/kotlin/androidx/lifecycle/hilt/HiltViewModelGeneratorTest.kt b/lifecycle/lifecycle-viewmodel-hilt-compiler/src/test/kotlin/androidx/lifecycle/hilt/HiltViewModelGeneratorTest.kt
index 851d483..0df260d 100644
--- a/lifecycle/lifecycle-viewmodel-hilt-compiler/src/test/kotlin/androidx/lifecycle/hilt/HiltViewModelGeneratorTest.kt
+++ b/lifecycle/lifecycle-viewmodel-hilt-compiler/src/test/kotlin/androidx/lifecycle/hilt/HiltViewModelGeneratorTest.kt
@@ -407,12 +407,12 @@
 
         import androidx.lifecycle.ViewModel;
         import androidx.lifecycle.hilt.ViewModelAssistedFactory;
-        import androidx.lifecycle.hilt.ViewModelKey;
         import dagger.Binds;
         import dagger.Module;
         import dagger.hilt.InstallIn;
         import dagger.hilt.android.components.ActivityRetainedComponent;
         import dagger.multibindings.IntoMap;
+        import dagger.multibindings.StringKey;
         import $GENERATED_TYPE;
 
         $GENERATED_ANNOTATION
@@ -421,7 +421,7 @@
         public interface MyViewModel_HiltModule {
             @Binds
             @IntoMap
-            @ViewModelKey(MyViewModel.class)
+            @StringKey("androidx.lifecycle.hilt.test.MyViewModel")
             ViewModelAssistedFactory<? extends ViewModel> bind(MyViewModel_AssistedFactory factory)
         }
         """.toJFO("androidx.lifecycle.hilt.test.MyViewModel_HiltModule")
@@ -480,12 +480,12 @@
 
         import androidx.lifecycle.ViewModel;
         import androidx.lifecycle.hilt.ViewModelAssistedFactory;
-        import androidx.lifecycle.hilt.ViewModelKey;
         import dagger.Binds;
         import dagger.Module;
         import dagger.hilt.InstallIn;
         import dagger.hilt.android.components.ActivityRetainedComponent;
         import dagger.multibindings.IntoMap;
+        import dagger.multibindings.StringKey;
         import $GENERATED_TYPE;
 
         $GENERATED_ANNOTATION
@@ -494,7 +494,7 @@
         public interface Outer_InnerViewModel_HiltModule {
             @Binds
             @IntoMap
-            @ViewModelKey(Outer.InnerViewModel.class)
+            @StringKey("androidx.lifecycle.hilt.test.Outer.InnerViewModel")
             ViewModelAssistedFactory<? extends ViewModel> bind(
                     Outer_InnerViewModel_AssistedFactory factory)
         }
diff --git a/lifecycle/lifecycle-viewmodel-hilt/build.gradle b/lifecycle/lifecycle-viewmodel-hilt/build.gradle
index 82aae8e..a8d80dc 100644
--- a/lifecycle/lifecycle-viewmodel-hilt/build.gradle
+++ b/lifecycle/lifecycle-viewmodel-hilt/build.gradle
@@ -26,6 +26,12 @@
     id("com.android.library")
 }
 
+android {
+    buildTypes.all {
+        consumerProguardFiles 'proguard-rules.pro'
+    }
+}
+
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
     api(project(":lifecycle:lifecycle-viewmodel-hilt-common"))
diff --git a/lifecycle/lifecycle-viewmodel-hilt/proguard-rules.pro b/lifecycle/lifecycle-viewmodel-hilt/proguard-rules.pro
new file mode 100644
index 0000000..01a9362
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-hilt/proguard-rules.pro
@@ -0,0 +1,5 @@
+# Keep class names of Hilt injected ViewModels since their name are used as a multibinding map key.
+-keepclasseswithmembernames class * extends androidx.lifecycle.ViewModel {
+    @androidx.lifecycle.hilt.ViewModelInject
+    <init>(...);
+}
\ No newline at end of file
diff --git a/lifecycle/lifecycle-viewmodel-hilt/src/main/java/androidx/lifecycle/hilt/ViewModelFactory.java b/lifecycle/lifecycle-viewmodel-hilt/src/main/java/androidx/lifecycle/hilt/ViewModelFactory.java
index 6a35805..9445cea 100644
--- a/lifecycle/lifecycle-viewmodel-hilt/src/main/java/androidx/lifecycle/hilt/ViewModelFactory.java
+++ b/lifecycle/lifecycle-viewmodel-hilt/src/main/java/androidx/lifecycle/hilt/ViewModelFactory.java
@@ -34,14 +34,13 @@
  */
 public final class ViewModelFactory extends AbstractSavedStateViewModelFactory {
 
-    private final Map<
-            Class<? extends ViewModel>,
+    private final Map<String,
             Provider<ViewModelAssistedFactory<? extends ViewModel>>> mViewModelFactories;
 
     ViewModelFactory(
             @NonNull SavedStateRegistryOwner owner,
             @Nullable Bundle defaultArgs,
-            @NonNull Map<Class<? extends ViewModel>,
+            @NonNull Map<String,
                     Provider<ViewModelAssistedFactory<? extends ViewModel>>> viewModelFactories) {
         super(owner, defaultArgs);
         this.mViewModelFactories = viewModelFactories;
@@ -53,7 +52,15 @@
     protected <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass,
             @NonNull SavedStateHandle handle) {
         // TODO(danysantiago): What to do with 'key' ???
-        // TODO(danysantiago): Better exception for missing class
-        return (T) mViewModelFactories.get(modelClass).get().create(handle);
+        Provider<ViewModelAssistedFactory<? extends ViewModel>> factoryProvider =
+                mViewModelFactories.get(modelClass.getCanonicalName());
+        if (factoryProvider == null) {
+            // TODO(danysantiago): Consider still creating those ViewModel that have a default
+            //  no-arg constructor.
+            throw new IllegalStateException("Unable to create the ViewModel class "
+                    + modelClass.getCanonicalName() + ". Did you forgot to annotate its "
+                    + "constructor with @ViewModelInject?");
+        }
+        return (T) factoryProvider.get().create(handle);
     }
 }
diff --git a/lifecycle/lifecycle-viewmodel-hilt/src/main/java/androidx/lifecycle/hilt/ViewModelFactoryModules.java b/lifecycle/lifecycle-viewmodel-hilt/src/main/java/androidx/lifecycle/hilt/ViewModelFactoryModules.java
index 74da3d7a..fc2b020 100644
--- a/lifecycle/lifecycle-viewmodel-hilt/src/main/java/androidx/lifecycle/hilt/ViewModelFactoryModules.java
+++ b/lifecycle/lifecycle-viewmodel-hilt/src/main/java/androidx/lifecycle/hilt/ViewModelFactoryModules.java
@@ -54,16 +54,14 @@
 
         @NonNull
         @Multibinds
-        abstract Map<Class<? extends ViewModel>,
-                ViewModelAssistedFactory<? extends ViewModel>> viewModelFactoriesMap();
+        abstract Map<String, ViewModelAssistedFactory<? extends ViewModel>> viewModelFactoriesMap();
 
         @Provides
         @NonNull
         @ActivityViewModelFactory
         static ViewModelFactory provideFactory(
                 @NonNull Activity activity,
-                @NonNull Map<Class<? extends ViewModel>,
-                        Provider<ViewModelAssistedFactory<? extends ViewModel>>>
+                @NonNull Map<String, Provider<ViewModelAssistedFactory<? extends ViewModel>>>
                         viewModelFactories) {
             // Hilt guarantees concrete activity is a subclass of ComponentActivity.
             SavedStateRegistryOwner owner = (ComponentActivity) activity;
@@ -84,8 +82,7 @@
         @FragmentViewModelFactory
         static ViewModelFactory provideFactory(
                 @NonNull Fragment fragment,
-                @NonNull Map<Class<? extends ViewModel>,
-                        Provider<ViewModelAssistedFactory<? extends ViewModel>>>
+                @NonNull Map<String, Provider<ViewModelAssistedFactory<? extends ViewModel>>>
                         viewModelFactories) {
             Bundle defaultArgs = fragment.getArguments();
             return new ViewModelFactory(fragment, defaultArgs, viewModelFactories);
diff --git a/lifecycle/lifecycle-viewmodel-hilt/src/main/java/androidx/lifecycle/hilt/ViewModelKey.java b/lifecycle/lifecycle-viewmodel-hilt/src/main/java/androidx/lifecycle/hilt/ViewModelKey.java
deleted file mode 100644
index 8f1ad82..0000000
--- a/lifecycle/lifecycle-viewmodel-hilt/src/main/java/androidx/lifecycle/hilt/ViewModelKey.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2020 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.hilt;
-
-import androidx.annotation.RestrictTo;
-import androidx.lifecycle.ViewModel;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-import dagger.MapKey;
-
-/**
- * Dagger multibinding key for ViewModels
- *
- * @hide
- */
-@MapKey
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public @interface ViewModelKey {
-    /**
-     * The ViewModel class used as key.
-     * @return the class.
-     */
-    // TODO(danysantiago): Change to use strings and add optimizer rule to avoid class loading.
-    Class<? extends ViewModel> value();
-}