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- `ContextHolder` is just a wrapper that provides a context.
45
46- `SystemUIFactory` `@Provides` dependencies that need to be overridden by SystemUI
47variants (like other form factors e.g. Car).
48
49- `DependencyBinder` creates the mapping from interfaces to implementation classes.
50
51- `DependencyProvider` provides or binds any remaining depedencies required.
52
53### Adding injection to a new SystemUI object
54
55Anything that depends on any `@Singleton` provider from SystemUIRootComponent
56should be declared as a `@Subcomponent` of the root component. This requires
57declaring your own interface for generating your own modules or just the
58object you need injected. The subcomponent also needs to be added to
59SystemUIRootComponent in SystemUIFactory so it can be acquired.
60
61```java
62public interface SystemUIRootComponent {
63+    @Singleton
64+    Dependency.DependencyInjector createDependency();
65}
66
67public class Dependency extends SystemUI {
68  //...
69+  @Subcomponent
70+  public interface DependencyInjector {
71+      Dependency createSystemUI();
72+  }
73}
74```
75
76For objects which extend SystemUI and require injection, you can define an
77injector that creates the injected object for you. This other class should
78be referenced in [@string/config_systemUIServiceComponents](packages/SystemUI/res/values/config.xml).
79
80```java
81public static class DependencyCreator implements Injector {
82    @Override
83    public SystemUI apply(Context context) {
84        return SystemUIFactory.getInstance().getRootComponent()
85                .createDependency()
86                .createSystemUI();
87    }
88}
89```
90
91### Adding a new injectable object
92
93First tag the constructor with `@Inject`. Also tag it with `@Singleton` if only one
94instance should be created.
95
96```java
97@Singleton
98public class SomethingController {
99  @Inject
100  public SomethingController(Context context,
101    @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
102      // context and mainHandler will be automatically populated.
103  }
104}
105```
106
107If you have an interface class and an implementation class, dagger needs to know
108how to map it. The simplest way to do this is to add an `@Provides` method to
109DependencyProvider. The type of the return value tells dagger which dependency it's providing.
110
111```java
112public class DependencyProvider {
113  //...
114  @Singleton
115  @Provides
116  public SomethingController provideSomethingController(Context context,
117      @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
118    return new SomethingControllerImpl(context, mainHandler);
119  }
120}
121```
122
123If you need to access this from Dependency#get, then add an adapter to Dependency
124that maps to the instance provided by Dagger. The changes should be similar
125to the following diff.
126
127```java
128public class Dependency {
129  //...
130  @Inject Lazy<SomethingController> mSomethingController;
131  //...
132  public void start() {
133    //...
134    mProviders.put(SomethingController.class, mSomethingController::get);
135  }
136}
137```
138
139### Using injection with Fragments
140
141Fragments are created as part of the FragmentManager, so they need to be
142setup so the manager knows how to create them. To do that, add a method
143to com.android.systemui.fragments.FragmentService$FragmentCreator that
144returns your fragment class. Thats all thats required, once the method
145exists, FragmentService will automatically pick it up and use injection
146whenever your fragment needs to be created.
147
148```java
149public interface FragmentCreator {
150+   NavigationBarFragment createNavigationBar();
151}
152```
153
154If you need to create your fragment (i.e. for the add or replace transaction),
155then the FragmentHostManager can do this for you.
156
157```java
158FragmentHostManager.get(view).create(NavigationBarFragment.class);
159```
160
161### Using injection with Views
162
163Generally, you shouldn't need to inject for a view, as the view should
164be relatively self contained and logic that requires injection should be
165moved to a higher level construct such as a Fragment or a top-level SystemUI
166component, see above for how to do injection for both of which.
167
168Still here? Yeah, ok, sysui has a lot of pre-existing views that contain a
169lot of code that could benefit from injection and will need to be migrated
170off from Dependency#get uses. Similar to how fragments are injected, the view
171needs to be added to the interface
172com.android.systemui.util.InjectionInflationController$ViewInstanceCreator.
173
174```java
175public interface ViewInstanceCreator {
176+   QuickStatusBarHeader createQsHeader();
177}
178```
179
180Presumably you need to inflate that view from XML (otherwise why do you
181need anything special? see earlier sections about generic injection). To obtain
182an inflater that supports injected objects, call InjectionInflationController#injectable,
183which will wrap the inflater it is passed in one that can create injected
184objects when needed.
185
186```java
187@Override
188public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
189        Bundle savedInstanceState) {
190    return mInjectionInflater.injectable(inflater).inflate(R.layout.my_layout, container, false);
191}
192```
193
194There is one other important thing to note about injecting with views. SysUI
195already has a Context in its global dagger component, so if you simply inject
196a Context, you will not get the one that the view should have with proper
197theming. Because of this, always ensure to tag views that have @Inject with
198the @Named view context.
199
200```java
201public CustomView(@Named(VIEW_CONTEXT) Context themedViewContext, AttributeSet attrs,
202        OtherCustomDependency something) {
203    //...
204}
205```
206
207## Updating Dagger2
208
209Binaries can be downloaded from https://repo1.maven.org/maven2/com/google/dagger/ and then loaded
210into
211[/prebuilts/tools/common/m2/repository/com/google/dagger/](http://cs/android/prebuilts/tools/common/m2/repository/com/google/dagger/)
212
213
214## TODO List
215
216 - Eliminate usages of Dependency#get
217 - Add links in above TODO
218