Improve custom AndroidViewModel parameter error message

When implementing a custom AndroidViewModel, the order of the parameters
must match the order in the super class or there will be an error.

We should improve the error message so that developers know that they
need to reorder their parameters.

RelNote: "The error message when custom `AndroidViewModel` classes have
parameters in the wrong order has been improved."
Test: SavedStateFactoryTest
Bug: 177667711

Change-Id: I340f7696bbf90e331e0b727e9195210cf1dadd0a
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/SavedStateFactoryTest.kt b/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/SavedStateFactoryTest.kt
index a39c427..5bff9f1 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/SavedStateFactoryTest.kt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/SavedStateFactoryTest.kt
@@ -74,6 +74,26 @@
 
     @UiThreadTest
     @Test
+    fun testCreateAndroidVMWrongParameterOrder() {
+        val savedStateVMFactory = SavedStateViewModelFactory()
+        val component = TestComponent()
+        component.enableSavedStateHandles()
+        val extras = component.extras
+        extras[APPLICATION_KEY] = activityRule.activity.application
+        val vm = ViewModelProvider(component.viewModelStore, savedStateVMFactory, extras)
+        try {
+            assertThat(vm[WrongOrderAndroidViewModel::class.java].handle).isNotNull()
+            fail()
+        } catch (e: UnsupportedOperationException) {
+            assertThat(e).hasMessageThat().isEqualTo(
+                "Class WrongOrderAndroidViewModel must have parameters in the proper order: " +
+                    "[class android.app.Application, class androidx.lifecycle.SavedStateHandle]"
+            )
+        }
+    }
+
+    @UiThreadTest
+    @Test
     fun testLegacyCreateFailAndroidVM() {
         val savedStateVMFactory = SavedStateViewModelFactory(
             null,
@@ -160,6 +180,9 @@
     internal class MyAndroidViewModel(app: Application, val handle: SavedStateHandle) :
         AndroidViewModel(app)
 
+    internal class WrongOrderAndroidViewModel(val handle: SavedStateHandle, app: Application) :
+        AndroidViewModel(app)
+
     internal class MyViewModel(val handle: SavedStateHandle) : ViewModel()
 
     class MyActivity : FragmentActivity()
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateViewModelFactory.kt b/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateViewModelFactory.kt
index 66ea62a..891f8e1 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateViewModelFactory.kt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateViewModelFactory.kt
@@ -220,24 +220,30 @@
     }
 }
 
-private val ANDROID_VIEWMODEL_SIGNATURE = arrayOf(
+private val ANDROID_VIEWMODEL_SIGNATURE = listOf<Class<*>>(
     Application::class.java,
     SavedStateHandle::class.java
 )
-private val VIEWMODEL_SIGNATURE = arrayOf<Class<*>>(SavedStateHandle::class.java)
+private val VIEWMODEL_SIGNATURE = listOf<Class<*>>(SavedStateHandle::class.java)
 
 // it is done instead of getConstructor(), because getConstructor() throws an exception
 // if there is no such constructor, which is expensive
 internal fun <T> findMatchingConstructor(
     modelClass: Class<T>,
-    signature: Array<Class<*>>
+    signature: List<Class<*>>
 ): Constructor<T>? {
     for (constructor in modelClass.constructors) {
-        val parameterTypes = constructor.parameterTypes
-        if (signature.contentEquals(parameterTypes)) {
+        val parameterTypes = constructor.parameterTypes.toList()
+        if (signature == parameterTypes) {
             @Suppress("UNCHECKED_CAST")
             return constructor as Constructor<T>
         }
+        if (signature.size == parameterTypes.size && parameterTypes.containsAll(signature)) {
+            throw UnsupportedOperationException(
+                "Class ${modelClass.simpleName} must have parameters in the proper " +
+                    "order: $signature"
+            )
+        }
     }
     return null
 }