| # Dagger 2 in SystemUI |
| *Dagger 2 is a dependency injection framework that compiles annotations to code |
| to create dependencies without reflection* |
| |
| ## Recommended reading |
| |
| Go read about Dagger 2. |
| |
| - [User's guide](https://google.github.io/dagger/users-guide) |
| |
| ## State of the world |
| |
| Dagger 2 has been turned on for SystemUI and much of |
| [Dependency.java](../src/com/android/systemui/Dependency.java) |
| has been converted to use Dagger. Since a lot of SystemUI depends on Dependency, |
| stubs have been added to Dependency to proxy any gets through to the instances |
| provided by dagger, this will allow migration of SystemUI through a number of CLs. |
| |
| ### How it works in SystemUI |
| |
| There are three high level "scopes" of concern in SystemUI. They all represent |
| singleton scopes, but serve different purposes. |
| |
| * `@Singleton` - Instances that are shared everywhere. There isn't a lot of |
| code in this scope. Things like the main thread, and Android Framework |
| provided instances mostly. |
| * `@WMShell` - WindowManager related code in the SystemUI process. We don't |
| want this code relying on the rest of SystemUI, and we don't want the rest |
| of SystemUI peeking into its internals, so it runs in its own Subcomponent. |
| * `@SysUISingleton` - Most of what would be considered "SystemUI". Most feature |
| work by SystemUI developers goes into this scope. Useful interfaces from |
| WindowManager are made available inside this Subcomponent. |
| |
| The root dagger graph is created by an instance of `SystemUIInitializer`. |
| See [README.md](../README.md) for more details. |
| For the classes that we're using in Dependency and are switching to dagger, the |
| equivalent dagger version is using `@Singleton` and therefore only has one instance. |
| To have the single instance span all of SystemUI and be easily accessible for |
| other components, there is a single root `@Component` that exists that generates |
| these. The component lives in |
| [ReferenceGlobalRootComponent.java](../src/com/android/systemui/dagger/ReferenceGlobalRootComponent.java). |
| |
| ### Adding a new injectable object |
| |
| First annotate the constructor with `@Inject`. Also annotate it with |
| `@SysUISingleton` if only one instance should be created. |
| |
| ```kotlin |
| @SysUISingleton |
| class FeatureStartable |
| @Inject |
| constructor( |
| /* ... */ |
| ) { |
| // ... |
| } |
| ``` |
| |
| If you have an interface class and an implementation class, Dagger needs to |
| know how to map it. The simplest way to do this is to add an `@Binds` method |
| in a module. The type of the return value tells dagger which dependency it's |
| providing: |
| |
| ```kotlin |
| @Module |
| abstract class FeatureModule { |
| @Binds |
| abstract fun bindsFeature(impl: FeatureImpl): Feature |
| } |
| ``` |
| |
| If you have a class that you want to make injectable that has can not |
| be easily constructed by Dagger, write a `@Provides` method for it: |
| |
| ```kotlin |
| @Module |
| abstract class FeatureModule { |
| @Module |
| companion object { |
| @Provides |
| fun providesFeature(ctx: Context): Feature { |
| return FeatureImpl.constructFromContext(ctx) |
| } |
| } |
| } |
| ``` |
| |
| ### Module Organization |
| |
| Please define your modules on _at least_ per-package level. If the scope of a |
| package grows to encompass a great number of features, create per-feature |
| modules. |
| |
| **Do not create catch-all modules.** Those quickly grow unwieldy and |
| unmaintainable. Any that exist today should be refactored into obsolescence. |
| |
| You can then include your module in one of three places: |
| |
| 1) Within another module that depends on it. Ideally, this creates a clean |
| dependency graph between features and utilities. |
| 2) For features that should exist in all versions of SystemUI (AOSP and |
| any variants), include the module in |
| [SystemUIModule.java](../src/com/android/systemui/dagger/SystemUIModule.java). |
| 3) For features that should exist only in AOSP, include the module in |
| [ReferenceSystemUIModule.java](../src/com/android/systemui/dagger/ReferenceSystemUIModule.java). |
| Similarly, if you are working on a custom version of SystemUI and have code |
| specific to your version, include it in a module specific to your version. |
| |
| ### Using injection with Fragments |
| |
| Fragments are created as part of the FragmentManager, so injectable Fragments need to be registered |
| so the manager knows how to create them. This is done via |
| [FragmentService#addFragmentInstantiationProvider](../src/com/android/systemui/fragments/FragmentService.java). |
| Pass it the class of your fragment and a `Provider` for your fragment at some time before your |
| Fragment is accessed. |
| |
| When you need to create your fragment (i.e. for the add or replace transaction), |
| then the FragmentHostManager can do this for you. |
| |
| ```java |
| FragmentHostManager.get(view).create(NavigationBarFragment.class); |
| ``` |
| |
| ## Updating Dagger2 |
| |
| We depend on the Dagger source found in external/dagger2. We should automatically pick up on updates |
| when that repository is updated. |
| |
| ## TODO List |
| |
| - Eliminate usages of Dependency#get: http://b/hotlists/3940788 |