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