Merge "Update README.md and dagger.md." into tm-qpr-dev
This commit is contained in:
@@ -5,46 +5,72 @@
|
|||||||
SystemUI is a persistent process that provides UI for the system but outside
|
SystemUI is a persistent process that provides UI for the system but outside
|
||||||
of the system_server process.
|
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
|
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
|
through IStatusBar. Outputs from sysui are through a variety of private APIs to
|
||||||
the android platform all over.
|
the android platform all over.
|
||||||
|
|
||||||
## SystemUIApplication
|
## SystemUIApplication
|
||||||
|
|
||||||
When SystemUIApplication starts up, it will start up the services listed in
|
When SystemUIApplication starts up, it instantiates a Dagger graph from which
|
||||||
config_systemUIServiceComponents or config_systemUIServiceComponentsPerUser.
|
various pieces of the application are built.
|
||||||
|
|
||||||
Each of these services extend SystemUI. SystemUI provides them with a Context
|
To support customization, SystemUIApplication relies on the AndroidManifest.xml
|
||||||
and gives them callbacks for onConfigurationChanged (this historically was
|
having an `android.app.AppComponentFactory` specified. Specifically, it relies
|
||||||
the main path for onConfigurationChanged, now also happens through
|
on an `AppComponentFactory` that subclases `SystemUIAppComponentFactoryBase`.
|
||||||
ConfigurationController). They also receive a callback for onBootCompleted
|
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`.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## Dagger / Dependency Injection
|
||||||
|
|
||||||
|
See [dagger.md](docs/dagger.md) and https://dagger.dev/.
|
||||||
|
|
||||||
|
## CoreStartable
|
||||||
|
|
||||||
|
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.
|
since these objects may be started before the device has finished booting.
|
||||||
|
|
||||||
Each SystemUI service is expected to be a major part of system ui and the
|
`CoreStartable` is an ideal place to add new features and functionality
|
||||||
goal is to minimize communication between them. So in general they should be
|
that does not belong directly under the umbrella of an existing feature.
|
||||||
relatively silo'd.
|
It is better to define a new `CoreStartable` than to stick unrelated
|
||||||
|
initialization code together in catch-all methods.
|
||||||
|
|
||||||
## Dependencies
|
CoreStartables are tied to application startup via Dagger:
|
||||||
|
|
||||||
The first SystemUI service that is started should always be Dependency.
|
```kotlin
|
||||||
Dependency provides a static method for getting a hold of dependencies that
|
class FeatureStartable
|
||||||
have a lifecycle that spans sysui. Dependency has code for how to create all
|
@Inject
|
||||||
dependencies manually added. SystemUIFactory is also capable of
|
constructor(
|
||||||
adding/replacing these dependencies.
|
/* ... */
|
||||||
|
) : CoreStartable {
|
||||||
|
override fun start() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Dependencies are lazily initialized, so if a Dependency is never referenced at
|
@Module
|
||||||
runtime, it will never be created.
|
abstract class FeatureModule {
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ClassKey(FeatureStartable::class)
|
||||||
|
abstract fun bind(impl: FeatureStartable): CoreStartable
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
If an instantiated dependency implements Dumpable it will be included in dumps
|
Including `FeatureModule` in the Dagger graph such as this will ensure that
|
||||||
of sysui (and bug reports), allowing it to include current state information.
|
`FeatureStartable` gets constructed and that its `#start` method is called.
|
||||||
This is how \*Controllers dump state to bug reports.
|
|
||||||
|
|
||||||
If an instantiated dependency implements ConfigurationChangeReceiver it will
|
|
||||||
receive onConfigurationChange callbacks when the configuration changes.
|
|
||||||
|
|
||||||
## IStatusBar
|
## 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
|
This is generally used a shortcut to directly trigger CommandQueue rather than
|
||||||
calling StatusManager and waiting for the call to come back to IStatusBar.
|
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)
|
### [com.android.systemui.util.NotificationChannels](/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java)
|
||||||
|
|
||||||
Creates/initializes the channels sysui uses when posting notifications.
|
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
|
Registers all the callbacks/listeners required to show the Volume dialog when
|
||||||
it should be shown.
|
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.
|
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
|
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.
|
to receive notification callbacks.
|
||||||
|
|
||||||
### [com.android.systemui.usb.StorageNotification](/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java)
|
### [com.android.systemui.usb.StorageNotification](/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java)
|
||||||
|
|||||||
@@ -8,105 +8,110 @@ Go read about Dagger 2.
|
|||||||
|
|
||||||
- [User's guide](https://google.github.io/dagger/users-guide)
|
- [User's guide](https://google.github.io/dagger/users-guide)
|
||||||
|
|
||||||
TODO: Add some links.
|
|
||||||
|
|
||||||
## State of the world
|
## State of the world
|
||||||
|
|
||||||
Dagger 2 has been turned on for SystemUI and a early first pass has been taken
|
Dagger 2 has been turned on for SystemUI and much of
|
||||||
for converting everything in [Dependency.java](packages/systemui/src/com/android/systemui/Dependency.java)
|
[Dependency.java](../src/com/android/systemui/Dependency.java)
|
||||||
to use Dagger. Since a lot of SystemUI depends on Dependency, stubs have been added to Dependency
|
has been converted to use Dagger. Since a lot of SystemUI depends on Dependency,
|
||||||
to proxy any gets through to the instances provided by dagger, this will allow migration of SystemUI
|
stubs have been added to Dependency to proxy any gets through to the instances
|
||||||
through a number of CLs.
|
provided by dagger, this will allow migration of SystemUI through a number of CLs.
|
||||||
|
|
||||||
### How it works in SystemUI
|
### 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
|
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.
|
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
|
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
|
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)
|
these. The component lives in
|
||||||
and is called `SystemUIRootComponent`.
|
[ReferenceGlobalRootComponent.java](../src/com/android/systemui/dagger/ReferenceGlobalRootComponent.java).
|
||||||
|
|
||||||
```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.
|
|
||||||
|
|
||||||
### Adding a new injectable object
|
### Adding a new injectable object
|
||||||
|
|
||||||
First tag the constructor with `@Inject`. Also tag it with `@Singleton` if only one
|
First annotate the constructor with `@Inject`. Also annotate it with
|
||||||
instance should be created.
|
`@SysUISingleton` if only one instance should be created.
|
||||||
|
|
||||||
```java
|
```kotlin
|
||||||
@Singleton
|
@SysUISingleton
|
||||||
public class SomethingController {
|
class FeatureStartable
|
||||||
@Inject
|
@Inject
|
||||||
public SomethingController(Context context,
|
constructor(
|
||||||
@Named(MAIN_HANDLER_NAME) Handler mainHandler) {
|
/* ... */
|
||||||
// context and mainHandler will be automatically populated.
|
) {
|
||||||
}
|
// ...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If you have an interface class and an implementation class, dagger needs to know
|
If you have an interface class and an implementation class, Dagger needs to
|
||||||
how to map it. The simplest way to do this is to add an `@Provides` method to
|
know how to map it. The simplest way to do this is to add an `@Binds` method
|
||||||
DependencyProvider. The type of the return value tells dagger which dependency it's providing.
|
in a module. The type of the return value tells dagger which dependency it's
|
||||||
|
providing:
|
||||||
|
|
||||||
```java
|
```kotlin
|
||||||
public class DependencyProvider {
|
@Module
|
||||||
//...
|
abstract class FeatureModule {
|
||||||
@Singleton
|
@Binds
|
||||||
@Provides
|
abstract fun bindsFeature(impl: FeatureImpl): Feature
|
||||||
public SomethingController provideSomethingController(Context context,
|
|
||||||
@Named(MAIN_HANDLER_NAME) Handler mainHandler) {
|
|
||||||
return new SomethingControllerImpl(context, mainHandler);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If you need to access this from Dependency#get, then add an adapter to Dependency
|
If you have a class that you want to make injectable that has can not
|
||||||
that maps to the instance provided by Dagger. The changes should be similar
|
be easily constructed by Dagger, write a `@Provides` method for it:
|
||||||
to the following diff.
|
|
||||||
|
|
||||||
```java
|
```kotlin
|
||||||
public class Dependency {
|
@Module
|
||||||
//...
|
abstract class FeatureModule {
|
||||||
@Inject Lazy<SomethingController> mSomethingController;
|
@Module
|
||||||
//...
|
companion object {
|
||||||
public void start() {
|
@Provides
|
||||||
//...
|
fun providesFeature(ctx: Context): Feature {
|
||||||
mProviders.put(SomethingController.class, mSomethingController::get);
|
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
|
### Using injection with Fragments
|
||||||
|
|
||||||
Fragments are created as part of the FragmentManager, so they need to be
|
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
|
setup so the manager knows how to create them. To do that, add a method
|
||||||
to com.android.systemui.fragments.FragmentService$FragmentCreator that
|
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
|
exists, FragmentService will automatically pick it up and use injection
|
||||||
whenever your fragment needs to be created.
|
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);
|
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
|
## Updating Dagger2
|
||||||
|
|
||||||
We depend on the Dagger source found in external/dagger2. We should automatically pick up on updates
|
We depend on the Dagger source found in external/dagger2. We should automatically pick up on updates
|
||||||
when that repository is updated.
|
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
|
## TODO List
|
||||||
|
|
||||||
- Eliminate usages of Dependency#get
|
- Eliminate usages of Dependency#get: http://b/hotlists/3940788
|
||||||
- Add links in above TODO
|
|
||||||
|
|||||||
Reference in New Issue
Block a user