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.fragment 18 19 import android.content.Context 20 import android.util.AttributeSet 21 import androidx.core.content.withStyledAttributes 22 import androidx.fragment.app.FragmentManager 23 import androidx.navigation.NavBackStackEntry 24 import androidx.navigation.NavOptions 25 import androidx.navigation.Navigator 26 import androidx.navigation.NavigatorProvider 27 import androidx.navigation.dynamicfeatures.DynamicExtras 28 import androidx.navigation.dynamicfeatures.DynamicInstallManager 29 import androidx.navigation.fragment.FragmentNavigator 30 31 /** The [Navigator] that enables navigating to destinations within dynamic feature modules. */ 32 @Navigator.Name("fragment") 33 public class DynamicFragmentNavigator( 34 context: Context, 35 manager: FragmentManager, 36 containerId: Int, 37 private val installManager: DynamicInstallManager 38 ) : FragmentNavigator(context, manager, containerId) { 39 createDestinationnull40 override fun createDestination(): Destination = Destination(this) 41 42 override fun navigate( 43 entries: List<NavBackStackEntry>, 44 navOptions: NavOptions?, 45 navigatorExtras: Navigator.Extras? 46 ) { 47 for (entry in entries) { 48 navigate(entry, navOptions, navigatorExtras) 49 } 50 } 51 navigatenull52 private fun navigate( 53 entry: NavBackStackEntry, 54 navOptions: NavOptions?, 55 navigatorExtras: Navigator.Extras? 56 ) { 57 val destination = entry.destination 58 val extras = navigatorExtras as? DynamicExtras 59 if (destination is Destination) { 60 val moduleName = destination.moduleName 61 if (moduleName != null && installManager.needsInstall(moduleName)) { 62 installManager.performInstall(entry, extras, moduleName) 63 return 64 } 65 } 66 super.navigate( 67 listOf(entry), 68 navOptions, 69 if (extras != null) extras.destinationExtras else navigatorExtras 70 ) 71 } 72 73 /** Destination for dynamic feature navigator. */ 74 public class Destination : FragmentNavigator.Destination { 75 public var moduleName: String? = null 76 77 @Suppress("unused") 78 public constructor(navigatorProvider: NavigatorProvider) : super(navigatorProvider) 79 80 public constructor( 81 fragmentNavigator: Navigator<out FragmentNavigator.Destination> 82 ) : super(fragmentNavigator) 83 onInflatenull84 override fun onInflate(context: Context, attrs: AttributeSet) { 85 super.onInflate(context, attrs) 86 context.withStyledAttributes(attrs, R.styleable.DynamicFragmentNavigator) { 87 moduleName = getString(R.styleable.DynamicFragmentNavigator_moduleName) 88 } 89 } 90 equalsnull91 override fun equals(other: Any?): Boolean { 92 if (this === other) return true 93 if (other == null || other !is Destination) return false 94 return super.equals(other) && moduleName == other.moduleName 95 } 96 hashCodenull97 override fun hashCode(): Int { 98 var result = super.hashCode() 99 result = 31 * result + moduleName.hashCode() 100 return result 101 } 102 } 103 } 104