1# Dagger 2 in SystemUI 2*Dagger 2 is a dependency injection framework that compiles annotations to code 3to create dependencies without reflection* 4 5## Recommended reading 6 7Go read about Dagger 2. 8 9 - [User's guide](https://google.github.io/dagger/users-guide) 10 11TODO: Add some links. 12 13## State of the world 14 15Dagger 2 has been turned on for SystemUI and a early first pass has been taken 16for converting everything in [Dependency.java](packages/systemui/src/com/android/systemui/Dependency.java) 17to use Dagger. Since a lot of SystemUI depends on Dependency, stubs have been added to Dependency 18to proxy any gets through to the instances provided by dagger, this will allow migration of SystemUI 19through a number of CLs. 20 21### How it works in SystemUI 22 23For the classes that we're using in Dependency and are switching to dagger, the 24equivalent dagger version is using `@Singleton` and therefore only has one instance. 25To have the single instance span all of SystemUI and be easily accessible for 26other components, there is a single root `@Component` that exists that generates 27these. The component lives in [SystemUIFactory](packages/systemui/src/com/android/systemui/SystemUIFactory.java) 28and is called `SystemUIRootComponent`. 29 30```java 31 32@Singleton 33@Component(modules = {SystemUIFactory.class, DependencyProvider.class, DependencyBinder.class, 34 ContextHolder.class}) 35public interface SystemUIRootComponent { 36 @Singleton 37 Dependency.DependencyInjector createDependency(); 38} 39``` 40 41The root component is composed of root modules, which in turn provide the global singleton 42dependencies across all of SystemUI. 43 44- `SystemUIFactory` `@Provides` dependencies that need to be overridden by SystemUI 45variants (like other form factors e.g. Car). 46 47- `DependencyBinder` creates the mapping from interfaces to implementation classes. 48 49- `DependencyProvider` provides or binds any remaining depedencies required. 50 51### Adding injection to a new SystemUI object 52 53SystemUI object are made injectable by adding an entry in `SystemUIBinder`. SystemUIApplication uses 54information in that file to locate and construct an instance of the requested SystemUI class. 55 56### Adding a new injectable object 57 58First tag the constructor with `@Inject`. Also tag it with `@Singleton` if only one 59instance should be created. 60 61```java 62@Singleton 63public class SomethingController { 64 @Inject 65 public SomethingController(Context context, 66 @Named(MAIN_HANDLER_NAME) Handler mainHandler) { 67 // context and mainHandler will be automatically populated. 68 } 69} 70``` 71 72If you have an interface class and an implementation class, dagger needs to know 73how to map it. The simplest way to do this is to add an `@Provides` method to 74DependencyProvider. The type of the return value tells dagger which dependency it's providing. 75 76```java 77public class DependencyProvider { 78 //... 79 @Singleton 80 @Provides 81 public SomethingController provideSomethingController(Context context, 82 @Named(MAIN_HANDLER_NAME) Handler mainHandler) { 83 return new SomethingControllerImpl(context, mainHandler); 84 } 85} 86``` 87 88If you need to access this from Dependency#get, then add an adapter to Dependency 89that maps to the instance provided by Dagger. The changes should be similar 90to the following diff. 91 92```java 93public class Dependency { 94 //... 95 @Inject Lazy<SomethingController> mSomethingController; 96 //... 97 public void start() { 98 //... 99 mProviders.put(SomethingController.class, mSomethingController::get); 100 } 101} 102``` 103 104### Using injection with Fragments 105 106Fragments are created as part of the FragmentManager, so they need to be 107setup so the manager knows how to create them. To do that, add a method 108to com.android.systemui.fragments.FragmentService$FragmentCreator that 109returns your fragment class. Thats all thats required, once the method 110exists, FragmentService will automatically pick it up and use injection 111whenever your fragment needs to be created. 112 113```java 114public interface FragmentCreator { 115 NavigationBarFragment createNavigationBar(); 116} 117``` 118 119If you need to create your fragment (i.e. for the add or replace transaction), 120then the FragmentHostManager can do this for you. 121 122```java 123FragmentHostManager.get(view).create(NavigationBarFragment.class); 124``` 125 126### Using injection with Views 127 128DO NOT ADD NEW VIEW INJECTION. VIEW INJECTION IS BEING ACTIVELY DEPRECATED. 129 130Needing to inject objects into your View's constructor generally implies you 131are doing more work in your presentation layer than is advisable. 132Instead, create an injected controller for you view, inject into the 133controller, and then attach the view to the controller after inflation. 134 135View injection generally causes headaches while testing, as inflating a view 136(which may in turn inflate other views) implicitly causes a Dagger graph to 137be stood up, which may or may not contain the appropriately 138faked/mocked/stubbed objects. It is a hard to control process. 139 140## Updating Dagger2 141 142We depend on the Dagger source found in external/dagger2. We should automatically pick up on updates 143when that repository is updated. 144 145*Deprecated:* 146 147Binaries can be downloaded from https://repo1.maven.org/maven2/com/google/dagger/ and then loaded 148into 149[/prebuilts/tools/common/m2/repository/com/google/dagger/](http://cs/android/prebuilts/tools/common/m2/repository/com/google/dagger/) 150 151The following commands should work, substituting in the version that you are looking for: 152 153```` 154cd prebuilts/tools/common/m2/repository/com/google/dagger/ 155 156wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger/2.28.1/ 157 158wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-compiler/2.28.1/ 159 160wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-spi/2.28.1/ 161 162wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-producers/2.28.1/ 163```` 164 165Then update `prebuilts/tools/common/m2/Android.bp` to point at your new jars. 166 167## TODO List 168 169 - Eliminate usages of Dependency#get 170 - Add links in above TODO 171