• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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