diff options
author | 2023-01-17 22:09:31 +0000 | |
---|---|---|
committer | 2023-01-18 15:16:21 +0000 | |
commit | b7c598633b48eb75fa47866d99e971d44b24da93 (patch) | |
tree | b32b1829084c0d1447035cafd4e879ba20d4dd12 | |
parent | 9ed2b6e46efe60618da1a75befa55f2d87322cea (diff) |
Update README.md and dagger.md.
Fixes: 265002579
Test: proofread.
Change-Id: Idb62423960d350ce6688b9c55bd0706a72fb855f
-rw-r--r-- | packages/SystemUI/README.md | 90 | ||||
-rw-r--r-- | packages/SystemUI/docs/dagger.md | 186 |
2 files changed, 132 insertions, 144 deletions
diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md index ee8d02301d5d..2910bba71341 100644 --- a/packages/SystemUI/README.md +++ b/packages/SystemUI/README.md @@ -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 @@ -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. @@ -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) diff --git a/packages/SystemUI/docs/dagger.md b/packages/SystemUI/docs/dagger.md index 89170139e21c..9b4c21efb27f 100644 --- a/packages/SystemUI/docs/dagger.md +++ b/packages/SystemUI/docs/dagger.md @@ -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`. +these. The component lives in +[ReferenceGlobalRootComponent.java](../src/com/android/systemui/dagger/ReferenceGlobalRootComponent.java). -```java +### Adding a new injectable object -@Singleton -@Component(modules = {SystemUIFactory.class, DependencyProvider.class, DependencyBinder.class, - ContextHolder.class}) -public interface SystemUIRootComponent { - @Singleton - Dependency.DependencyInjector createDependency(); +First annotate the constructor with `@Inject`. Also annotate it with +`@SysUISingleton` if only one instance should be created. + +```kotlin +@SysUISingleton +class FeatureStartable +@Inject +constructor( +/* ... */ +) { + // ... } ``` -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. +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: -- `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. - -### Adding a new injectable object - -First tag the constructor with `@Inject`. Also tag it with `@Singleton` if only one -instance should be created. - -```java -@Singleton -public class SomethingController { - @Inject - public SomethingController(Context context, - @Named(MAIN_HANDLER_NAME) Handler mainHandler) { - // context and mainHandler will be automatically populated. - } +```kotlin +@Module +abstract class FeatureModule { + @Binds + abstract fun bindsFeature(impl: FeatureImpl): Feature } ``` -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. - -```java -public class DependencyProvider { - //... - @Singleton - @Provides - public SomethingController provideSomethingController(Context context, - @Named(MAIN_HANDLER_NAME) Handler mainHandler) { - return new SomethingControllerImpl(context, mainHandler); - } +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) + } + } } ``` -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. +### Module Organization -```java -public class Dependency { - //... - @Inject Lazy<SomethingController> mSomethingController; - //... - public void start() { - //... - mProviders.put(SomethingController.class, mSomethingController::get); - } -} -``` +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. @@ -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 |