1 /* 2 * Copyright 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.navigation.dynamicfeatures 18 19 import android.content.Context 20 import android.util.AttributeSet 21 import androidx.core.content.withStyledAttributes 22 import androidx.navigation.ActivityNavigator 23 import androidx.navigation.NavBackStackEntry 24 import androidx.navigation.NavOptions 25 import androidx.navigation.Navigator 26 import androidx.navigation.NavigatorProvider 27 28 /** Dynamic feature navigator for Activity destinations. */ 29 @Navigator.Name("activity") 30 public class DynamicActivityNavigator( 31 context: Context, 32 private val installManager: DynamicInstallManager 33 ) : ActivityNavigator(context) { 34 35 internal val packageName: String = context.packageName 36 navigatenull37 override fun navigate( 38 entries: List<NavBackStackEntry>, 39 navOptions: NavOptions?, 40 navigatorExtras: Navigator.Extras? 41 ) { 42 for (entry in entries) { 43 navigate(entry, navOptions, navigatorExtras) 44 } 45 } 46 navigatenull47 private fun navigate( 48 entry: NavBackStackEntry, 49 navOptions: NavOptions?, 50 navigatorExtras: Navigator.Extras? 51 ) { 52 val destination = entry.destination 53 val extras = navigatorExtras as? DynamicExtras 54 if (destination is Destination) { 55 val moduleName = destination.moduleName 56 if (moduleName != null && installManager.needsInstall(moduleName)) { 57 installManager.performInstall(entry, extras, moduleName) 58 return 59 } 60 } 61 super.navigate( 62 listOf(entry), 63 navOptions, 64 if (extras != null) extras.destinationExtras else navigatorExtras 65 ) 66 } 67 createDestinationnull68 override fun createDestination(): Destination = Destination(this) 69 70 /** Destination for [DynamicActivityNavigator]. */ 71 public class Destination : ActivityNavigator.Destination { 72 /** 73 * The module name of this [Destination]'s dynamic feature module. This has to be the same 74 * as defined in the dynamic feature module's AndroidManifest.xml file. 75 */ 76 public var moduleName: String? = null 77 78 /** 79 * Create a new [Destination] with a [NavigatorProvider]. 80 * 81 * @see ActivityNavigator.Destination 82 */ 83 public constructor(navigatorProvider: NavigatorProvider) : super(navigatorProvider) 84 85 /** 86 * Create a new [Destination] with an [ActivityNavigator.Destination]. 87 * 88 * @param activityNavigator The Navigator to use for this [Destination]. 89 */ 90 public constructor( 91 activityNavigator: Navigator<out ActivityNavigator.Destination> 92 ) : super(activityNavigator) 93 94 override fun onInflate(context: Context, attrs: AttributeSet) { 95 super.onInflate(context, attrs) 96 context.withStyledAttributes(attrs, R.styleable.DynamicActivityNavigator) { 97 moduleName = getString(R.styleable.DynamicActivityNavigator_moduleName) 98 } 99 } 100 101 override fun equals(other: Any?): Boolean { 102 if (this === other) return true 103 if (other == null || other !is Destination) return false 104 return super.equals(other) && moduleName == other.moduleName 105 } 106 107 override fun hashCode(): Int { 108 var result = super.hashCode() 109 result = 31 * result + moduleName.hashCode() 110 return result 111 } 112 } 113 } 114