Loading packages/SystemUI/README.md +55 −35 Original line number Diff line number Diff line Loading @@ -5,46 +5,72 @@ SystemUI is a persistent process that provides UI for the system but outside of the system_server process. The starting point for most of sysui code is a list of services that extend SystemUI that are started up by SystemUIApplication. These services then depend on some custom dependency injection provided by Dependency. Inputs directed at sysui (as opposed to general listeners) generally come in through IStatusBar. Outputs from sysui are through a variety of private APIs to the android platform all over. ## SystemUIApplication When SystemUIApplication starts up, it will start up the services listed in config_systemUIServiceComponents or config_systemUIServiceComponentsPerUser. When SystemUIApplication starts up, it instantiates a Dagger graph from which various pieces of the application are built. Each of these services extend SystemUI. SystemUI provides them with a Context and gives them callbacks for onConfigurationChanged (this historically was the main path for onConfigurationChanged, now also happens through ConfigurationController). They also receive a callback for onBootCompleted since these objects may be started before the device has finished booting. To support customization, SystemUIApplication relies on the AndroidManifest.xml having an `android.app.AppComponentFactory` specified. Specifically, it relies on an `AppComponentFactory` that subclases `SystemUIAppComponentFactoryBase`. Implementations of this abstract base class must override `#createSystemUIInitializer(Context)` which returns a `SystemUIInitializer`. `SystemUIInitializer` primary job in turn is to intialize and return the Dagger root component back to the `SystemUIApplication`. Each SystemUI service is expected to be a major part of system ui and the goal is to minimize communication between them. So in general they should be relatively silo'd. Writing a custom `SystemUIAppComponentFactoryBase` and `SystemUIInitializer`, should be enough for most implementations to stand up a customized Dagger graph, and launch a custom version of SystemUI. ## Dependencies ## Dagger / Dependency Injection The first SystemUI service that is started should always be Dependency. Dependency provides a static method for getting a hold of dependencies that have a lifecycle that spans sysui. Dependency has code for how to create all dependencies manually added. SystemUIFactory is also capable of adding/replacing these dependencies. See [dagger.md](docs/dagger.md) and https://dagger.dev/. Dependencies are lazily initialized, so if a Dependency is never referenced at runtime, it will never be created. ## CoreStartable If an instantiated dependency implements Dumpable it will be included in dumps of sysui (and bug reports), allowing it to include current state information. This is how \*Controllers dump state to bug reports. The starting point for most of SystemUI code is a list of classes that implement `CoreStartable` that are started up by SystemUIApplication. CoreStartables are like miniature services. They have their `#start` method called after being instantiated, and a reference to them is stored inside SystemUIApplication. They are in charge of their own behavior beyond this, registering and unregistering with the rest of the system as needed. `CoreStartable` also receives a callback for `#onBootCompleted` since these objects may be started before the device has finished booting. If an instantiated dependency implements ConfigurationChangeReceiver it will receive onConfigurationChange callbacks when the configuration changes. `CoreStartable` is an ideal place to add new features and functionality that does not belong directly under the umbrella of an existing feature. It is better to define a new `CoreStartable` than to stick unrelated initialization code together in catch-all methods. CoreStartables are tied to application startup via Dagger: ```kotlin class FeatureStartable @Inject constructor( /* ... */ ) : CoreStartable { override fun start() { // ... } } @Module abstract class FeatureModule { @Binds @IntoMap @ClassKey(FeatureStartable::class) abstract fun bind(impl: FeatureStartable): CoreStartable } ``` Including `FeatureModule` in the Dagger graph such as this will ensure that `FeatureStartable` gets constructed and that its `#start` method is called. ## IStatusBar Loading @@ -64,12 +90,6 @@ across sysui. Such as when StatusBar calls CommandQueue#recomputeDisableFlags. This is generally used a shortcut to directly trigger CommandQueue rather than calling StatusManager and waiting for the call to come back to IStatusBar. ## Default SystemUI services list ### [com.android.systemui.Dependency](/packages/SystemUI/src/com/android/systemui/Dependency.java) Provides custom dependency injection. ### [com.android.systemui.util.NotificationChannels](/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java) Creates/initializes the channels sysui uses when posting notifications. Loading @@ -88,11 +108,11 @@ activity. It provides this cached data to RecentsActivity when it is started. Registers all the callbacks/listeners required to show the Volume dialog when it should be shown. ### [com.android.systemui.status.phone.StatusBar](/packages/SystemUI/src/com/android/systemui/status/phone/StatusBar.java) ### [com.android.systemui.status.phone.CentralSurfaces](/packages/SystemUI/src/com/android/systemui/status/phone/CentralSurfaces.java) This shows the UI for the status bar and the notification shade it contains. It also contains a significant amount of other UI that interacts with these surfaces (keyguard, AOD, etc.). StatusBar also contains a notification listener surfaces (keyguard, AOD, etc.). CentralSurfaces also contains a notification listener to receive notification callbacks. ### [com.android.systemui.usb.StorageNotification](/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java) Loading packages/SystemUI/docs/dagger.md +77 −109 Original line number Diff line number Diff line Loading @@ -8,105 +8,110 @@ Go read about Dagger 2. - [User's guide](https://google.github.io/dagger/users-guide) TODO: Add some links. ## State of the world Dagger 2 has been turned on for SystemUI and a early first pass has been taken for converting everything in [Dependency.java](packages/systemui/src/com/android/systemui/Dependency.java) 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. 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 [SystemUIFactory](packages/systemui/src/com/android/systemui/SystemUIFactory.java) and is called `SystemUIRootComponent`. ```java @Singleton @Component(modules = {SystemUIFactory.class, DependencyProvider.class, DependencyBinder.class, ContextHolder.class}) public interface SystemUIRootComponent { @Singleton Dependency.DependencyInjector createDependency(); } ``` The root component is composed of root modules, which in turn provide the global singleton dependencies across all of SystemUI. - `SystemUIFactory` `@Provides` dependencies that need to be overridden by SystemUI variants (like other form factors e.g. Car). - `DependencyBinder` creates the mapping from interfaces to implementation classes. - `DependencyProvider` provides or binds any remaining depedencies required. ### Adding injection to a new SystemUI object SystemUI object are made injectable by adding an entry in `SystemUIBinder`. SystemUIApplication uses information in that file to locate and construct an instance of the requested SystemUI class. these. The component lives in [ReferenceGlobalRootComponent.java](../src/com/android/systemui/dagger/ReferenceGlobalRootComponent.java). ### Adding a new injectable object First tag the constructor with `@Inject`. Also tag it with `@Singleton` if only one instance should be created. First annotate the constructor with `@Inject`. Also annotate it with `@SysUISingleton` if only one instance should be created. ```java @Singleton public class SomethingController { ```kotlin @SysUISingleton class FeatureStartable @Inject public SomethingController(Context context, @Named(MAIN_HANDLER_NAME) Handler mainHandler) { // context and mainHandler will be automatically populated. } 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 `@Provides` method to DependencyProvider. The type of the return value tells dagger which dependency it's providing. 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: ```java public class DependencyProvider { //... @Singleton @Provides public SomethingController provideSomethingController(Context context, @Named(MAIN_HANDLER_NAME) Handler mainHandler) { return new SomethingControllerImpl(context, mainHandler); } ```kotlin @Module abstract class FeatureModule { @Binds abstract fun bindsFeature(impl: FeatureImpl): Feature } ``` If you need to access this from Dependency#get, then add an adapter to Dependency that maps to the instance provided by Dagger. The changes should be similar to the following diff. 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: ```java public class Dependency { //... @Inject Lazy<SomethingController> mSomethingController; //... public void start() { //... mProviders.put(SomethingController.class, mSomethingController::get); ```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 they need to be setup so the manager knows how to create them. To do that, add a method to com.android.systemui.fragments.FragmentService$FragmentCreator that returns your fragment class. Thats all thats required, once the method returns your fragment class. That is all that is required, once the method exists, FragmentService will automatically pick it up and use injection whenever your fragment needs to be created. Loading @@ -123,48 +128,11 @@ then the FragmentHostManager can do this for you. FragmentHostManager.get(view).create(NavigationBarFragment.class); ``` ### Using injection with Views DO NOT ADD NEW VIEW INJECTION. VIEW INJECTION IS BEING ACTIVELY DEPRECATED. Needing to inject objects into your View's constructor generally implies you are doing more work in your presentation layer than is advisable. Instead, create an injected controller for you view, inject into the controller, and then attach the view to the controller after inflation. View injection generally causes headaches while testing, as inflating a view (which may in turn inflate other views) implicitly causes a Dagger graph to be stood up, which may or may not contain the appropriately faked/mocked/stubbed objects. It is a hard to control process. ## Updating Dagger2 We depend on the Dagger source found in external/dagger2. We should automatically pick up on updates when that repository is updated. *Deprecated:* Binaries can be downloaded from https://repo1.maven.org/maven2/com/google/dagger/ and then loaded into [/prebuilts/tools/common/m2/repository/com/google/dagger/](http://cs/android/prebuilts/tools/common/m2/repository/com/google/dagger/) The following commands should work, substituting in the version that you are looking for: ```` cd prebuilts/tools/common/m2/repository/com/google/dagger/ wget -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/ wget -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/ wget -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/ wget -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/ ```` Then update `prebuilts/tools/common/m2/Android.bp` to point at your new jars. ## TODO List - Eliminate usages of Dependency#get - Add links in above TODO - Eliminate usages of Dependency#get: http://b/hotlists/3940788 Loading
packages/SystemUI/README.md +55 −35 Original line number Diff line number Diff line Loading @@ -5,46 +5,72 @@ SystemUI is a persistent process that provides UI for the system but outside of the system_server process. The starting point for most of sysui code is a list of services that extend SystemUI that are started up by SystemUIApplication. These services then depend on some custom dependency injection provided by Dependency. Inputs directed at sysui (as opposed to general listeners) generally come in through IStatusBar. Outputs from sysui are through a variety of private APIs to the android platform all over. ## SystemUIApplication When SystemUIApplication starts up, it will start up the services listed in config_systemUIServiceComponents or config_systemUIServiceComponentsPerUser. When SystemUIApplication starts up, it instantiates a Dagger graph from which various pieces of the application are built. Each of these services extend SystemUI. SystemUI provides them with a Context and gives them callbacks for onConfigurationChanged (this historically was the main path for onConfigurationChanged, now also happens through ConfigurationController). They also receive a callback for onBootCompleted since these objects may be started before the device has finished booting. To support customization, SystemUIApplication relies on the AndroidManifest.xml having an `android.app.AppComponentFactory` specified. Specifically, it relies on an `AppComponentFactory` that subclases `SystemUIAppComponentFactoryBase`. Implementations of this abstract base class must override `#createSystemUIInitializer(Context)` which returns a `SystemUIInitializer`. `SystemUIInitializer` primary job in turn is to intialize and return the Dagger root component back to the `SystemUIApplication`. Each SystemUI service is expected to be a major part of system ui and the goal is to minimize communication between them. So in general they should be relatively silo'd. Writing a custom `SystemUIAppComponentFactoryBase` and `SystemUIInitializer`, should be enough for most implementations to stand up a customized Dagger graph, and launch a custom version of SystemUI. ## Dependencies ## Dagger / Dependency Injection The first SystemUI service that is started should always be Dependency. Dependency provides a static method for getting a hold of dependencies that have a lifecycle that spans sysui. Dependency has code for how to create all dependencies manually added. SystemUIFactory is also capable of adding/replacing these dependencies. See [dagger.md](docs/dagger.md) and https://dagger.dev/. Dependencies are lazily initialized, so if a Dependency is never referenced at runtime, it will never be created. ## CoreStartable If an instantiated dependency implements Dumpable it will be included in dumps of sysui (and bug reports), allowing it to include current state information. This is how \*Controllers dump state to bug reports. The starting point for most of SystemUI code is a list of classes that implement `CoreStartable` that are started up by SystemUIApplication. CoreStartables are like miniature services. They have their `#start` method called after being instantiated, and a reference to them is stored inside SystemUIApplication. They are in charge of their own behavior beyond this, registering and unregistering with the rest of the system as needed. `CoreStartable` also receives a callback for `#onBootCompleted` since these objects may be started before the device has finished booting. If an instantiated dependency implements ConfigurationChangeReceiver it will receive onConfigurationChange callbacks when the configuration changes. `CoreStartable` is an ideal place to add new features and functionality that does not belong directly under the umbrella of an existing feature. It is better to define a new `CoreStartable` than to stick unrelated initialization code together in catch-all methods. CoreStartables are tied to application startup via Dagger: ```kotlin class FeatureStartable @Inject constructor( /* ... */ ) : CoreStartable { override fun start() { // ... } } @Module abstract class FeatureModule { @Binds @IntoMap @ClassKey(FeatureStartable::class) abstract fun bind(impl: FeatureStartable): CoreStartable } ``` Including `FeatureModule` in the Dagger graph such as this will ensure that `FeatureStartable` gets constructed and that its `#start` method is called. ## IStatusBar Loading @@ -64,12 +90,6 @@ across sysui. Such as when StatusBar calls CommandQueue#recomputeDisableFlags. This is generally used a shortcut to directly trigger CommandQueue rather than calling StatusManager and waiting for the call to come back to IStatusBar. ## Default SystemUI services list ### [com.android.systemui.Dependency](/packages/SystemUI/src/com/android/systemui/Dependency.java) Provides custom dependency injection. ### [com.android.systemui.util.NotificationChannels](/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java) Creates/initializes the channels sysui uses when posting notifications. Loading @@ -88,11 +108,11 @@ activity. It provides this cached data to RecentsActivity when it is started. Registers all the callbacks/listeners required to show the Volume dialog when it should be shown. ### [com.android.systemui.status.phone.StatusBar](/packages/SystemUI/src/com/android/systemui/status/phone/StatusBar.java) ### [com.android.systemui.status.phone.CentralSurfaces](/packages/SystemUI/src/com/android/systemui/status/phone/CentralSurfaces.java) This shows the UI for the status bar and the notification shade it contains. It also contains a significant amount of other UI that interacts with these surfaces (keyguard, AOD, etc.). StatusBar also contains a notification listener surfaces (keyguard, AOD, etc.). CentralSurfaces also contains a notification listener to receive notification callbacks. ### [com.android.systemui.usb.StorageNotification](/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java) Loading
packages/SystemUI/docs/dagger.md +77 −109 Original line number Diff line number Diff line Loading @@ -8,105 +8,110 @@ Go read about Dagger 2. - [User's guide](https://google.github.io/dagger/users-guide) TODO: Add some links. ## State of the world Dagger 2 has been turned on for SystemUI and a early first pass has been taken for converting everything in [Dependency.java](packages/systemui/src/com/android/systemui/Dependency.java) 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. 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 [SystemUIFactory](packages/systemui/src/com/android/systemui/SystemUIFactory.java) and is called `SystemUIRootComponent`. ```java @Singleton @Component(modules = {SystemUIFactory.class, DependencyProvider.class, DependencyBinder.class, ContextHolder.class}) public interface SystemUIRootComponent { @Singleton Dependency.DependencyInjector createDependency(); } ``` The root component is composed of root modules, which in turn provide the global singleton dependencies across all of SystemUI. - `SystemUIFactory` `@Provides` dependencies that need to be overridden by SystemUI variants (like other form factors e.g. Car). - `DependencyBinder` creates the mapping from interfaces to implementation classes. - `DependencyProvider` provides or binds any remaining depedencies required. ### Adding injection to a new SystemUI object SystemUI object are made injectable by adding an entry in `SystemUIBinder`. SystemUIApplication uses information in that file to locate and construct an instance of the requested SystemUI class. these. The component lives in [ReferenceGlobalRootComponent.java](../src/com/android/systemui/dagger/ReferenceGlobalRootComponent.java). ### Adding a new injectable object First tag the constructor with `@Inject`. Also tag it with `@Singleton` if only one instance should be created. First annotate the constructor with `@Inject`. Also annotate it with `@SysUISingleton` if only one instance should be created. ```java @Singleton public class SomethingController { ```kotlin @SysUISingleton class FeatureStartable @Inject public SomethingController(Context context, @Named(MAIN_HANDLER_NAME) Handler mainHandler) { // context and mainHandler will be automatically populated. } 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 `@Provides` method to DependencyProvider. The type of the return value tells dagger which dependency it's providing. 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: ```java public class DependencyProvider { //... @Singleton @Provides public SomethingController provideSomethingController(Context context, @Named(MAIN_HANDLER_NAME) Handler mainHandler) { return new SomethingControllerImpl(context, mainHandler); } ```kotlin @Module abstract class FeatureModule { @Binds abstract fun bindsFeature(impl: FeatureImpl): Feature } ``` If you need to access this from Dependency#get, then add an adapter to Dependency that maps to the instance provided by Dagger. The changes should be similar to the following diff. 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: ```java public class Dependency { //... @Inject Lazy<SomethingController> mSomethingController; //... public void start() { //... mProviders.put(SomethingController.class, mSomethingController::get); ```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 they need to be setup so the manager knows how to create them. To do that, add a method to com.android.systemui.fragments.FragmentService$FragmentCreator that returns your fragment class. Thats all thats required, once the method returns your fragment class. That is all that is required, once the method exists, FragmentService will automatically pick it up and use injection whenever your fragment needs to be created. Loading @@ -123,48 +128,11 @@ then the FragmentHostManager can do this for you. FragmentHostManager.get(view).create(NavigationBarFragment.class); ``` ### Using injection with Views DO NOT ADD NEW VIEW INJECTION. VIEW INJECTION IS BEING ACTIVELY DEPRECATED. Needing to inject objects into your View's constructor generally implies you are doing more work in your presentation layer than is advisable. Instead, create an injected controller for you view, inject into the controller, and then attach the view to the controller after inflation. View injection generally causes headaches while testing, as inflating a view (which may in turn inflate other views) implicitly causes a Dagger graph to be stood up, which may or may not contain the appropriately faked/mocked/stubbed objects. It is a hard to control process. ## Updating Dagger2 We depend on the Dagger source found in external/dagger2. We should automatically pick up on updates when that repository is updated. *Deprecated:* Binaries can be downloaded from https://repo1.maven.org/maven2/com/google/dagger/ and then loaded into [/prebuilts/tools/common/m2/repository/com/google/dagger/](http://cs/android/prebuilts/tools/common/m2/repository/com/google/dagger/) The following commands should work, substituting in the version that you are looking for: ```` cd prebuilts/tools/common/m2/repository/com/google/dagger/ wget -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/ wget -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/ wget -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/ wget -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/ ```` Then update `prebuilts/tools/common/m2/Android.bp` to point at your new jars. ## TODO List - Eliminate usages of Dependency#get - Add links in above TODO - Eliminate usages of Dependency#get: http://b/hotlists/3940788