Convert ViewTreeViewModelStoreOwner to Kotlin

Part of the kotlin conversion process for the Lifecycle library.

RelNote: "`ViewTreeViewModelStoreOwner` is now in Kotlin.
This is a source-incompatible change and usages written in
Kotlin for `ViewTreeViewModelStoreOwner.set()` and
`ViewTreeViewModelStoreOwner.get()` should be replaced
with `View.setViewTreeViewModelStoreOwner()` and
`View.findViewTreeViewModelStoreOwner()`, respectively."
Test: ./gradlew checkApi
Bug: 240298691

Change-Id: Ia06d830b263c0f7f1193c5b3ead1587533ca1b0c
diff --git a/lifecycle/lifecycle-viewmodel/api/current.txt b/lifecycle/lifecycle-viewmodel/api/current.txt
index 577a5be..2b5e267 100644
--- a/lifecycle/lifecycle-viewmodel/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/current.txt
@@ -83,12 +83,12 @@
   }
 
   public final class ViewTreeViewModelKt {
-    method public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View);
+    method public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View view);
   }
 
-  public class ViewTreeViewModelStoreOwner {
+  public final class ViewTreeViewModelStoreOwner {
     method public static androidx.lifecycle.ViewModelStoreOwner? get(android.view.View);
-    method public static void set(android.view.View, androidx.lifecycle.ViewModelStoreOwner?);
+    method public static void set(android.view.View, androidx.lifecycle.ViewModelStoreOwner? viewModelStoreOwner);
   }
 
 }
diff --git a/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt b/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt
index 577a5be..2b5e267 100644
--- a/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt
@@ -83,12 +83,12 @@
   }
 
   public final class ViewTreeViewModelKt {
-    method public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View);
+    method public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View view);
   }
 
-  public class ViewTreeViewModelStoreOwner {
+  public final class ViewTreeViewModelStoreOwner {
     method public static androidx.lifecycle.ViewModelStoreOwner? get(android.view.View);
-    method public static void set(android.view.View, androidx.lifecycle.ViewModelStoreOwner?);
+    method public static void set(android.view.View, androidx.lifecycle.ViewModelStoreOwner? viewModelStoreOwner);
   }
 
 }
diff --git a/lifecycle/lifecycle-viewmodel/api/restricted_current.txt b/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
index 577a5be..2b5e267 100644
--- a/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
@@ -83,12 +83,12 @@
   }
 
   public final class ViewTreeViewModelKt {
-    method public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View);
+    method public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View view);
   }
 
-  public class ViewTreeViewModelStoreOwner {
+  public final class ViewTreeViewModelStoreOwner {
     method public static androidx.lifecycle.ViewModelStoreOwner? get(android.view.View);
-    method public static void set(android.view.View, androidx.lifecycle.ViewModelStoreOwner?);
+    method public static void set(android.view.View, androidx.lifecycle.ViewModelStoreOwner? viewModelStoreOwner);
   }
 
 }
diff --git a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewTreeViewModel.kt b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewTreeViewModel.kt
index 48a3877b..92285d8 100644
--- a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewTreeViewModel.kt
+++ b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewTreeViewModel.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2023 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.
@@ -22,5 +22,5 @@
  * Locates the [ViewModelStoreOwner] associated with this [View], if present.
  * This may be used to retain state associated with this view across configuration changes.
  */
-public fun View.findViewTreeViewModelStoreOwner(): ViewModelStoreOwner? =
-    ViewTreeViewModelStoreOwner.get(this)
+public fun findViewTreeViewModelStoreOwner(view: View): ViewModelStoreOwner? =
+    view.findViewTreeViewModelStoreOwner()
diff --git a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewTreeViewModelStoreOwner.kt b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewTreeViewModelStoreOwner.kt
index ccf8720..7239652 100644
--- a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewTreeViewModelStoreOwner.kt
+++ b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewTreeViewModelStoreOwner.kt
@@ -13,62 +13,43 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+@file:JvmName("ViewTreeViewModelStoreOwner")
 
-package androidx.lifecycle;
+package androidx.lifecycle
 
-import android.view.View;
-import android.view.ViewParent;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.lifecycle.viewmodel.R;
+import android.view.View
+import androidx.lifecycle.viewmodel.R
 
 /**
- * Accessors for finding a view tree-local {@link ViewModelStoreOwner} that allows access to a
- * {@link ViewModelStore} for the given view.
+ * Set the [ViewModelStoreOwner] associated with the given [View].
+ * Calls to [get] from this view or descendants will return
+ * `viewModelStoreOwner`.
+ *
+ * This should only be called by constructs such as activities or fragments that manage
+ * a view tree and retain state through a [ViewModelStoreOwner]. Callers
+ * should only set a [ViewModelStoreOwner] that will be *stable.* The associated
+ * [ViewModelStore] should be cleared if the view tree is removed and is not
+ * guaranteed to later become reattached to a window.
+ *
+ * @param viewModelStoreOwner ViewModelStoreOwner associated with the given view
  */
-public class ViewTreeViewModelStoreOwner {
-    private ViewTreeViewModelStoreOwner() {
-        // No instances
-    }
-
-    /**
-     * Set the {@link ViewModelStoreOwner} associated with the given {@link View}.
-     * Calls to {@link #get(View)} from this view or descendants will return
-     * {@code viewModelStoreOwner}.
-     *
-     * <p>This should only be called by constructs such as activities or fragments that manage
-     * a view tree and retain state through a {@link ViewModelStoreOwner}. Callers
-     * should only set a {@link ViewModelStoreOwner} that will be <em>stable.</em> The associated
-     * {@link ViewModelStore} should be cleared if the view tree is removed and is not
-     * guaranteed to later become reattached to a window.</p>
-     *
-     * @param view Root view associated with the viewModelStoreOwner
-     * @param viewModelStoreOwner ViewModelStoreOwner associated with the given view
-     */
-    public static void set(@NonNull View view, @Nullable ViewModelStoreOwner viewModelStoreOwner) {
-        view.setTag(R.id.view_tree_view_model_store_owner, viewModelStoreOwner);
-    }
-
-    /**
-     * Retrieve the {@link ViewModelStoreOwner} associated with the given {@link View}.
-     * This may be used to retain state associated with this view across configuration changes.
-     *
-     * @param view View to fetch a {@link ViewModelStoreOwner} for
-     * @return The {@link ViewModelStoreOwner} associated with this view and/or some subset
-     *         of its ancestors
-     */
-    @Nullable
-    public static ViewModelStoreOwner get(@NonNull View view) {
-        ViewModelStoreOwner found = (ViewModelStoreOwner) view.getTag(
-                R.id.view_tree_view_model_store_owner);
-        if (found != null) return found;
-        ViewParent parent = view.getParent();
-        while (found == null && parent instanceof View) {
-            final View parentView = (View) parent;
-            found = (ViewModelStoreOwner) parentView.getTag(R.id.view_tree_view_model_store_owner);
-            parent = parentView.getParent();
-        }
-        return found;
-    }
+@JvmName("set")
+fun View.setViewTreeViewModelStoreOwner(viewModelStoreOwner: ViewModelStoreOwner?) {
+    setTag(R.id.view_tree_view_model_store_owner, viewModelStoreOwner)
 }
+
+/**
+ * Retrieve the [ViewModelStoreOwner] associated with the given [View].
+ * This may be used to retain state associated with this view across configuration changes.
+ *
+ * @return The [ViewModelStoreOwner] associated with this view and/or some subset
+ * of its ancestors
+ */
+@JvmName("get")
+fun View.findViewTreeViewModelStoreOwner(): ViewModelStoreOwner? {
+    return generateSequence(this) { view ->
+        view.parent as? View
+    }.mapNotNull { view ->
+        view.getTag(R.id.view_tree_view_model_store_owner) as? ViewModelStoreOwner
+    }.firstOrNull()
+}
\ No newline at end of file