[go: nahoru, domu]

Make findDestination and matchDestination public

We should provide our internal NavigationUI helper methods so that is
easier for developers to write their own NavigationUI pieces.

RelNote: "`findDestination()` and `matchDestination()` are now public
and can be used to help implement custom NavigationUI"
Test: ./gradlew checkApi
Bug: 188183365

Change-Id: I2932fc4ddba6f381e5e353ee30d2233140e5a674
diff --git a/navigation/navigation-common/api/api_lint.ignore b/navigation/navigation-common/api/api_lint.ignore
index 8610f6c..3812c14 100644
--- a/navigation/navigation-common/api/api_lint.ignore
+++ b/navigation/navigation-common/api/api_lint.ignore
@@ -119,6 +119,8 @@
     androidx.navigation.NavOptions does not declare a `isLaunchSingleTop()` method matching method androidx.navigation.NavOptions.Builder.setLaunchSingleTop(boolean)
 
 
+MissingJvmstatic: androidx.navigation.NavDestination#hierarchy:
+    Companion object constants like hierarchy should be using @JvmField, not @JvmStatic; see https://developer.android.com/kotlin/interop#companion_constants
 MissingJvmstatic: androidx.navigation.NavOptionsBuilder#popUpTo(String, kotlin.jvm.functions.Function1<? super androidx.navigation.PopUpToBuilder,kotlin.Unit>):
     A Kotlin method with default parameter values should be annotated with @JvmOverloads for better Java interoperability; see https://android.github.io/kotlin-guides/interop.html#function-overloads-for-defaults
 MissingJvmstatic: androidx.navigation.NavOptionsBuilder#popUpTo(int, kotlin.jvm.functions.Function1<? super androidx.navigation.PopUpToBuilder,kotlin.Unit>):
diff --git a/navigation/navigation-common/api/current.txt b/navigation/navigation-common/api/current.txt
index afc02e9..dda39ab 100644
--- a/navigation/navigation-common/api/current.txt
+++ b/navigation/navigation-common/api/current.txt
@@ -188,6 +188,7 @@
     method public final void addDeepLink(androidx.navigation.NavDeepLink navDeepLink);
     method public final androidx.navigation.NavAction? getAction(@IdRes int id);
     method public final java.util.Map<java.lang.String,androidx.navigation.NavArgument> getArguments();
+    method public static final kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
     method @IdRes public final int getId();
     method public final CharSequence? getLabel();
     method public final String getNavigatorName();
@@ -219,7 +220,9 @@
   }
 
   public static final class NavDestination.Companion {
+    method public kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
     method protected <C> Class<? extends C> parseClassFromName(android.content.Context context, String name, Class<? extends C> expectedClassType);
+    property public final kotlin.sequences.Sequence<androidx.navigation.NavDestination> hierarchy;
   }
 
   @androidx.navigation.NavDestinationDsl public class NavDestinationBuilder<D extends androidx.navigation.NavDestination> {
@@ -260,6 +263,7 @@
     method public final void clear();
     method public final androidx.navigation.NavDestination? findNode(@IdRes int resId);
     method public final androidx.navigation.NavDestination? findNode(String? route);
+    method public static final androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
     method @Deprecated @IdRes public final int getStartDestination();
     method @IdRes public final int getStartDestinationId();
     method public final String? getStartDestinationRoute();
@@ -269,6 +273,11 @@
     method public final void setStartDestination(String startDestRoute);
     property @IdRes public final int startDestinationId;
     property public final String? startDestinationRoute;
+    field public static final androidx.navigation.NavGraph.Companion Companion;
+  }
+
+  public static final class NavGraph.Companion {
+    method public androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
   }
 
   @androidx.navigation.NavDestinationDsl public class NavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.NavGraph> {
diff --git a/navigation/navigation-common/api/public_plus_experimental_current.txt b/navigation/navigation-common/api/public_plus_experimental_current.txt
index 7c4b7c6..bd49a55 100644
--- a/navigation/navigation-common/api/public_plus_experimental_current.txt
+++ b/navigation/navigation-common/api/public_plus_experimental_current.txt
@@ -210,6 +210,7 @@
     method public final androidx.navigation.NavAction? getAction(@IdRes int id);
     method public final java.util.Map<java.lang.String,androidx.navigation.NavArgument> getArguments();
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public String getDisplayName();
+    method public static final kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
     method @IdRes public final int getId();
     method public final CharSequence? getLabel();
     method public final String getNavigatorName();
@@ -246,8 +247,10 @@
   }
 
   public static final class NavDestination.Companion {
+    method public kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
     method protected <C> Class<? extends C> parseClassFromName(android.content.Context context, String name, Class<? extends C> expectedClassType);
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public <C> Class<? extends C> parseClassFromNameInternal(android.content.Context context, String name, Class<? extends C> expectedClassType);
+    property public final kotlin.sequences.Sequence<androidx.navigation.NavDestination> hierarchy;
   }
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final class NavDestination.DeepLinkMatch implements java.lang.Comparable<androidx.navigation.NavDestination.DeepLinkMatch> {
@@ -297,6 +300,7 @@
     method public final void clear();
     method public final androidx.navigation.NavDestination? findNode(@IdRes int resId);
     method public final androidx.navigation.NavDestination? findNode(String? route);
+    method public static final androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final androidx.collection.SparseArrayCompat<androidx.navigation.NavDestination> getNodes();
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final String getStartDestDisplayName();
     method @Deprecated @IdRes public final int getStartDestination();
@@ -310,6 +314,11 @@
     property @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final String startDestDisplayName;
     property @IdRes public final int startDestinationId;
     property public final String? startDestinationRoute;
+    field public static final androidx.navigation.NavGraph.Companion Companion;
+  }
+
+  public static final class NavGraph.Companion {
+    method public androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
   }
 
   @androidx.navigation.NavDestinationDsl public class NavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.NavGraph> {
diff --git a/navigation/navigation-common/api/restricted_current.txt b/navigation/navigation-common/api/restricted_current.txt
index afc02e9..dda39ab 100644
--- a/navigation/navigation-common/api/restricted_current.txt
+++ b/navigation/navigation-common/api/restricted_current.txt
@@ -188,6 +188,7 @@
     method public final void addDeepLink(androidx.navigation.NavDeepLink navDeepLink);
     method public final androidx.navigation.NavAction? getAction(@IdRes int id);
     method public final java.util.Map<java.lang.String,androidx.navigation.NavArgument> getArguments();
+    method public static final kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
     method @IdRes public final int getId();
     method public final CharSequence? getLabel();
     method public final String getNavigatorName();
@@ -219,7 +220,9 @@
   }
 
   public static final class NavDestination.Companion {
+    method public kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
     method protected <C> Class<? extends C> parseClassFromName(android.content.Context context, String name, Class<? extends C> expectedClassType);
+    property public final kotlin.sequences.Sequence<androidx.navigation.NavDestination> hierarchy;
   }
 
   @androidx.navigation.NavDestinationDsl public class NavDestinationBuilder<D extends androidx.navigation.NavDestination> {
@@ -260,6 +263,7 @@
     method public final void clear();
     method public final androidx.navigation.NavDestination? findNode(@IdRes int resId);
     method public final androidx.navigation.NavDestination? findNode(String? route);
+    method public static final androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
     method @Deprecated @IdRes public final int getStartDestination();
     method @IdRes public final int getStartDestinationId();
     method public final String? getStartDestinationRoute();
@@ -269,6 +273,11 @@
     method public final void setStartDestination(String startDestRoute);
     property @IdRes public final int startDestinationId;
     property public final String? startDestinationRoute;
+    field public static final androidx.navigation.NavGraph.Companion Companion;
+  }
+
+  public static final class NavGraph.Companion {
+    method public androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
   }
 
   @androidx.navigation.NavDestinationDsl public class NavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.NavGraph> {
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavDestination.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavDestination.kt
index 6143ed8..dc72c88 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavDestination.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavDestination.kt
@@ -594,5 +594,14 @@
         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
         public fun createRoute(route: String?): String =
             if (route != null) "android-app://androidx.navigation/$route" else ""
+
+        /**
+         * Provides a sequence of the NavDestination's hierarchy. The hierarchy starts with this
+         * destination itself and is then followed by this destination's [NavDestination.parent], then that
+         * graph's parent, and up the hierarchy until you've reached the root navigation graph.
+         */
+        @JvmStatic
+        public val NavDestination.hierarchy: Sequence<NavDestination>
+            get() = generateSequence(this) { it.parent }
     }
 }
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt
index 4992475..594d969 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt
@@ -370,6 +370,24 @@
         }
         return sb.toString()
     }
+
+    public companion object {
+        /**
+         * Finds the actual start destination of the graph, handling cases where the graph's starting
+         * destination is itself a NavGraph.
+         *
+         * @return the actual startDestination of the given graph.
+         */
+        @JvmStatic
+        public fun NavGraph.findStartDestination(): NavDestination =
+            generateSequence(findNode(startDestinationId)) {
+                if (it is NavGraph) {
+                    it.findNode(it.startDestinationId)
+                } else {
+                    null
+                }
+            }.last()
+    }
 }
 
 /**
diff --git a/navigation/navigation-common/src/test/java/androidx/navigation/NavDestinationTest.kt b/navigation/navigation-common/src/test/java/androidx/navigation/NavDestinationTest.kt
index a0a0af1..b021a95 100644
--- a/navigation/navigation-common/src/test/java/androidx/navigation/NavDestinationTest.kt
+++ b/navigation/navigation-common/src/test/java/androidx/navigation/NavDestinationTest.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import androidx.annotation.IdRes
+import androidx.navigation.NavDestination.Companion.hierarchy
 import com.google.common.truth.Truth.assertThat
 import org.junit.Assert.fail
 import org.junit.Test
@@ -300,4 +301,20 @@
         assertThat(destination.arguments.size).isEqualTo(0)
         assertThat(destination.arguments["stringArg"]).isNull()
     }
+
+    @Test
+    fun hierarchy() {
+        val destination = NoOpNavigator().createDestination()
+        destination.id = DESTINATION_ID
+        val parentId = 2
+        val navGraphNavigator = NavGraphNavigator(mock(NavigatorProvider::class.java))
+        val parent = navGraphNavigator.createDestination().apply {
+            id = parentId
+            setStartDestination(DESTINATION_ID)
+        }
+        destination.parent = parent
+
+        val found = destination.hierarchy.any { it.id == 2 }
+        assertThat(found).isTrue()
+    }
 }