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()
+ }
}