blob: ee388ec8e5c5ec72e5ff1d5fed51b188e526a3b1 [file] [log] [blame] [view]
# Quick Settings Tiles (almost all there is to know about them)
[TOC]
## About this document
This document is a more or less comprehensive summary of the state and infrastructure used by Quick
Settings tiles. It provides descriptions about the lifecycle of a tile, how to create new tiles and
how SystemUI manages and displays tiles, among other topics.
## What are Quick Settings Tiles?
Quick Settings (from now on, QS) is the expanded panel that contains shortcuts for the user to
toggle many settings. This is opened by expanding the notification drawer twice (or once when phone
is locked). Quick Quick Settings (QQS) is the smaller panel that appears on top of the notifications
before expanding twice and contains some of the toggles with no secondary line.
Each of these toggles that appear either in QS or QQS are called Quick Settings Tiles (or tiles for
short). They allow the user to enable or disable settings quickly and sometimes provides access to
more comprehensive settings pages.
The following image shows QQS on the left and QS on the right, with the tiles highlighted.
![QQS on the left, QS on the right](QS-QQS.png)
QS Tiles usually depend on one or more Controllers that bind the tile with the necessary service.
Controllers are obtained by the backend and used for communication between the user and the device.
### A note on multi-user support
All the classes described in this document that live inside SystemUI are only instantiated in the
process of user 0. The different controllers that back the QS Tiles (also instantiated just in user
0) are user aware and provide an illusion of different instances for different users.
For an example on this,
see [`RotationLockController`](/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java).
This controller for the `RotationLockTile` listens to changes in all users.
## What are tiles made of?
### Tile backend
QS Tiles are composed of the following backend classes.
* [`QSTile`](/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java): Interface
providing common behavior for all Tiles. This class also contains some useful utility classes
needed for the tiles.
* `Icon`: Defines the basic interface for an icon as used by the tiles.
* `State`: Encapsulates the state of the Tile in order to communicate between the backend and
the UI.
* [`QSTileImpl`](/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java): Abstract
implementation of `QSTile`, providing basic common behavior for all tiles. Also implements
extensions for different types of `Icon`. All tiles currently defined in SystemUI subclass from
this implementation.
* [`SystemUI/src/com/android/systemui/qs/tiles`](/packages/SystemUI/src/com/android/systemui/qs/tiles):
Each tile from SystemUI is defined here by a class that extends `QSTileImpl`. These
implementations connect to corresponding controllers. The controllers serve two purposes:
* track the state of the device and notify the tile when a change has occurred (for example,
bluetooth connected to a device)
* accept actions from the tiles to modify the state of the phone (for example, enablind and
disabling wifi).
* [`CustomTile`](/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java):
Equivalent to the tiles in the previous item, but used for 3rd party tiles. In depth information
to be found in [`CustomTile`](#customtile)
All the elements in SystemUI that work with tiles operate on `QSTile` or the interfaces defined in
it. However, all the current implementations of tiles in SystemUI subclass from `QSTileImpl`, as it
takes care of many common situations. Throughout this document, we will focus on `QSTileImpl` as
examples of tiles.
The interfaces in `QSTile` as well as other interfaces described in this document can be used to
implement plugins to add additional tiles or different behavior. For more information,
see [plugins.md](plugins.md)
#### Tile State
Each tile has an associated `State` object that is used to communicate information to the
corresponding view. The base class `State` has (among others) the following fields:
* **`state`**: one of `Tile#STATE_UNAVAILABLE`, `Tile#STATE_ACTIVE`, `Tile#STATE_INACTIVE`.
* **`icon`**; icon to display. It may depend on the current state.
* **`label`**: usually the name of the tile.
* **`secondaryLabel`**: text to display in a second line. Usually extra state information.
* **`contentDescription`**
* **`expandedAccessibilityClassName`**: usually `Switch.class.getName()` for boolean Tiles. This
will make screen readers read the current state of the tile as well as the new state when it's
toggled. For this, the Tile has to use `BooleanState`.
* **`handlesLongClick`**: whether the Tile will handle long click. If it won't, it should be set
to `false` so it will not be announced for accessibility.
Setting any of these fields during `QSTileImpl#handleUpdateState` will update the UI after it.
Additionally. `BooleanState` has a `value` boolean field that usually would be set
to `state == Tile#STATE_ACTIVE`. This is used by accessibility services along
with `expandedAccessibilityClassName`.
#### SystemUI tiles
Each tile defined in SystemUI extends `QSTileImpl`. This abstract class implements some common
functions and leaves others to be implemented by each tile, in particular those that determine how
to handle different events (refresh, click, etc.).
For more information on how to implement a tile in SystemUI,
see [Implementing a SystemUI tile](#implementing-a-systemui-tile).
### Tile views
Each Tile has a couple of associated views for displaying it in QS and QQS. These views are updated
after the backend updates the `State` using `QSTileImpl#handleUpdateState`.
* **[`QSTileView`](/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java)**:
Abstract class that provides basic Tile functionality. These allows
external [Factories](#qsfactory) to create Tiles.
* **[`QSTileViewImpl`](/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.java)**:
Implementation of `QSTileView`. It takes care of the following:
* Holding the icon
* Background color and shape
* Ripple
* Click listening
* Labels
* **[`QSIconView`](/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSIconView.java)**
* **[`QSIconViewImpl`](/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java)**
#### QSIconView and QSIconViewImpl
`QSIconView` is an interface that define the basic actions that icons have to respond to. Its base
implementation in SystemUI is `QSIconViewImpl` and it and its subclasses are used by all QS tiles.
This `ViewGroup` is a container for the icon used in each tile. It has methods to apply the
current `State` of the tile, modifying the icon (color and animations). Classes that inherit from
this can add other details that are modified when the `State` changes.
Each `QSTileImpl` can specify that they use a particular implementation of this class when creating
an icon.
### How are the backend and the views related?
The backend of the tiles (all the implementations of `QSTileImpl`) communicate with the views by
using a `State`. The backend populates the state, and then the view maps the state to a visual
representation.
It's important to notice that the state of the tile (internal or visual) is not directly modified by
a user action like clicking on the tile. Instead, acting on a tile produces internal state changes
on the device, and those trigger the changes on the tile state and UI.
When a container for tiles (`QuickQSPanel` or `QSPanel`) has to display tiles, they create
a [`TileRecord`](/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java). This associates the
corresponding `QSTile` with its `QSTileView`, doing the following:
* Create the corresponding `QSTileView` to display in that container.
* Create a callback for `QSTile` to call when its state changes. Note that a single tile will
normally have up to two callbacks: one for QS and one for QQS.
#### Life of a tile click
This is a brief run-down of what happens when a user clicks on a tile. Internal changes on the
device (for example, changes from Settings) will trigger this process starting in step 3. Throughout
this section, we assume that we are dealing with a `QSTileImpl`.
1. User clicks on tile. The following calls happen in sequence:
1. `QSTileViewImpl#onClickListener`.
2. `QSTile#click`.
3. `QSTileImpl#handleClick`. This last call sets the new state for the device by using the
associated controller.
2. State in the device changes. This is normally outside of SystemUI's control.
3. Controller receives a callback (or `Intent`) indicating the change in the device. The following
calls happen:
1. `QSTileImpl#refreshState`, maybe passing an object with necessary information regarding the
new state.
2. `QSTileImpl#handleRefreshState`
4. `QSTileImpl#handleUpdateState` is called to update the state with the new information. This
information can be obtained both from the `Object` passed to `refreshState` as well as from the
controller.
5. If the state has changed (in at least one element), `QSTileImpl#handleStateChanged` is called.
This will trigger a call to all the associated `QSTile.Callback#onStateChanged`, passing the
new `State`.
6. `QSTileView#onStateChanged` is called and this calls `QSTileView#handleStateChanged`. This method
maps the state into the view:
* The tile colors change to match the new state.
* `QSIconView.setIcon` is called to apply the correct state to the icon and the correct icon to
the view.
* The tile labels change to match the new state.
## Third party tiles (TileService)
A third party tile is any Quick Settings tile that is provided by an app (that's not SystemUI). This
is implemented by developers
subclassing [`TileService`](/core/java/android/service/quicksettings/TileService.java) and
interacting with its API.
### API classes
The classes that define the public API are
in [core/java/android/service/quicksettings](/core/java/android/service/quicksettings).
#### Tile
Parcelable class used to communicate information about the state between the external app and
SystemUI. The class supports the following fields:
* Label
* Subtitle
* Icon
* State (`Tile#STATE_ACTIVE`, `Tile#STATE_INACTIVE`, `Tile#STATE_UNAVAILABLE`)
* Content description
Additionally, it provides a method to notify SystemUI that the information may have changed and the
tile should be refreshed.
#### TileService
This is an abstract Service that needs to be implemented by the developer. The Service manifest must
have the permission `android.permission.BIND_QUICK_SETTINGS_TILE` and must respond to the
action `android.service.quicksettings.action.QS_TILE`. This will allow SystemUI to find the
available tiles and display them to the user.
The implementer is responsible for creating the methods that will respond to the following calls
from SystemUI:
* **`onTileAdded`**: called when the tile is added to QS.
* **`onTileRemoved`**: called when the tile is removed from QS.
* **`onStartListening`**: called when QS is opened and the tile is showing. This marks the start of
the window when calling `getQSTile` is safe and will provide the correct object.
* **`onStopListening`**: called when QS is closed or the tile is no longer visible by the user. This
marks the end of the window described in `onStartListening`.
* **`onClick`**: called when the user clicks on the tile.
Additionally, the following final methods are provided:
* ```java
public final Tile getQsTile()
```
Provides the tile object that can be modified. This should only be called in the window
between `onStartListening` and `onStopListening`.
* ```java
public final boolean isLocked()
public final boolean isSecure()
```
Provide information about the secure state of the device. This can be used by the tile to accept
or reject actions on the tile.
* ```java
public final void unlockAndRun(Runnable)
```
May prompt the user to unlock the device if locked. Once the device is unlocked, it runs the
given `Runnable`.
* ```java
public final void showDialog(Dialog)
```
Shows the provided dialog.
##### Binding
When the Service is bound, a callback Binder is provided by SystemUI for all the callbacks, as well
as an identifier token (`Binder`). This token is used in the callbacks to identify
this `TileService` and match it to the corresponding tile.
The tiles are bound once immediately on creation. After that, the tile is bound whenever it should
start listening. When the panels are closed, and the tile is set to stop listening, it will be
unbound after a delay of `TileServiceManager#UNBIND_DELAY` (30s), if it's not set to listening
again.
##### Active tile
A `TileService` can be declared as an active tile by adding specific meta-data to its manifest (
see [TileService#META_DATA_ACTIVE_TILE](https://developer.android.com/reference/android/service/quicksettings/TileService#META_DATA_ACTIVE_TILE)).
In this case, it won't receive a call of `onStartListening` when QS is opened. Instead, the tile
must request listening status by making a call to `TileService#requestListeningState` with its
component name. This will initiate a window that will last until the tile is updated.
The tile will also be granted listening status if it's clicked by the user.
### SystemUI classes
The following sections describe the classes that live in SystemUI to support third party tiles.
These classes live
in [SystemUI/src/com/android/systemui/qs/external](/packages/SystemUI/src/com/android/systemui/qs/external/)
#### CustomTile
This class is an subclass of `QSTileImpl` to be used with third party tiles. It provides similar
behavior to SystemUI tiles as well as handling exclusive behavior like lifting default icons and
labels from the application manifest.
#### TileServices
This class is the central controller for all tile services that are currently in Quick Settings as
well as provides the support for starting new ones. It is also an implementation of the `Binder`
that receives all calls from current `TileService` components and dispatches them to SystemUI or the
corresponding `CustomTile`.
Whenever a binder call is made to this class, it matches the corresponding token assigned to
the `TileService` with the `ComponentName` and verifies that the call comes from the right UID to
prevent spoofing.
As this class is the only one that's aware of every `TileService` that's currently bound, it is also
in charge of requesting some to be unbound whenever there is a low memory situation.
#### TileLifecycleManager
This class is in charge of binding and unbinding to a particular `TileService` when necessary, as
well as sending the corresponding binder calls. It does not decide whether the tile should be bound
or unbound, unless it's requested to process a message. It additionally handles errors in
the `Binder` as well as changes in the corresponding component (like updates and enable/disable).
The class has a queue that stores requests while the service is not bound, to be processed as soon
as the service is bound.
Each `TileService` gets assigned an exclusive `TileLifecycleManager` when its corresponding tile is
added to the set of current ones and kept as long as the tile is available to the user.
#### TileServiceManager
Each instance of this class is an intermediary between the `TileServices` controller and
a `TileLifecycleManager` corresponding to a particular `TileService`.
This class handles management of the service, including:
* Deciding when to bind and unbind, requesting it to the `TileLifecycleManager`.
* Relaying messages to the `TileService` through the `TileLifecycleManager`.
* Determining the service's bind priority (to deal with OOM situations).
* Detecting when the package/component has been removed in order to remove the tile and references
to it.
## How are tiles created/instantiated?
This section describes the classes that aid in the creation of each tile as well as the complete
lifecycle of a tile. The current system makes use of flows to propagate information downstream.
First we describe three important interfaces/classes.
### TileSpecRepository (and UserTileSpecRepository)
These classes keep track of the current tiles for each user, as a list of Tile specs. While the
device is running, this is the source of truth of tiles for that user.
The list is persisted to `Settings.Secure` every time it changes so it will be available upon
restart or backup. In particular, any changes in the secure setting while this repository is
tracking the list of tiles will be reverted.
The class provides a `Flow<List<TileSpec>>` for each user that can be collected to keep track of the
current list of tiles.
#### Tile specs
Each single tile is identified by a spec, which is a unique String for that type of tile. The
current tiles are stored as a Setting string of comma separated values of these specs. Additionally,
the default tiles (that appear on a fresh system) configuration value is stored likewise.
SystemUI tile specs are usually a single simple word identifying the tile (like `wifi`
or `battery`). Custom tile specs are always a string of the form `custom(...)` where the ellipsis is
a flattened String representing the `ComponentName` for the corresponding `TileService`.
We represent these internally using a `TileSpec` class that can distinguish between platform tiles
and custom tiles.
### CurrentTilesInteractor
This class consumes the lists of specs provided by `TileSpecRepository` and produces a
`Flow<List<Pair<TileSpec, QSTile>>>` with the current tiles for the current user.
Internally, whenever the list of tiles changes, the following operation is performed:
* Properly dispose of tiles that are no longer in the current list.
* Properly dispose of tiles that are no longer available.
* If the user has changed, relay the new user to the platform tiles and destroy any custom tiles.
* Create new tiles as needed, disposing those that are not available or when the corresponding
service does not exist.
* Reorder the tiles.
Also, when this is completed, we pass the final list back to the repository so it matches the
correct list of tiles.
### QSFactory
This interface provides a way of creating tiles and views from a spec. It can be used in plugins to
provide different definitions for tiles.
In SystemUI there is only one implementation of this factory and that is the default
factory (`QSFactoryImpl`) in `CurrentTilesInteractorImpl`.
#### QSFactoryImpl
This class implements the following method as specified in the `QSFactory` interface:
* ```java
public QSTile createTile(String)
```
Creates a tile (backend) from a given spec. The factory has a map with providers for all of the
SystemUI tiles, returning one when the correct spec is used.
If the spec is not recognized but it has the `custom(` prefix, the factory tries to create
a `CustomTile` for the component in the spec.
As part of filtering not valid tiles, custom tiles that don't have a corresponding valid service
component are never instantiated.
### Lifecycle of a Tile
We describe first the parts of the lifecycle that are common to SystemUI tiles and third party
tiles. Following that, there will be a section with the steps that are exclusive to third party
tiles.
1. The tile is added through the QS customizer by the user. This will send the new list of tiles to
`TileSpecRepository` which will update its internal state and also store the new value in the
secure setting `sysui_qs_tiles`. This step could also happen if `StatusBar` adds tiles (either
through adb, or through its service interface as with the `DevelopmentTiles`).
2. This updates the flow that `CurrentTilesInteractor` is collecting from, triggering the process
described above.
3. `CurrentTilesInteractor` calls the available `QSFactory` classes in order to find one that will
be able to create a tile with that spec. Assuming that `QSFactoryImpl` managed to create the
tile, which is some implementation of `QSTile` (either a SystemUI subclass
of `QSTileImpl` or a `CustomTile`) it will be added to the current list.
If the tile is available, it's stored in a map and things proceed forward.
4. `CurrentTilesInteractor` updates its flow and classes collecting from it will be notified of the
change. In particular, `QSPanel` and `QuickQSPanel` receive this call with the full list of
tiles. We will focus on these two classes.
5. For each tile in this list, a `QSTileView` is created (collapsed or expanded) and attached to
a `TileRecord` containing the tile backend and the view. Additionally:
* a callback is attached to the tile to communicate between the backend and the view or the
panel.
* the click listeners in the tile are attached to those of the view.
6. The tile view is added to the corresponding layout.
When the tile is removed from the list of current tiles, all these classes are properly disposed
including removing the callbacks and making sure that the backends remove themselves from the
controllers they were listening to.
#### Lifecycle of a CustomTile
In step 3 of the previous process, when a `CustomTile` is created, additional steps are taken to
ensure the proper binding to the service as described
in [Third party tiles (TileService)](#third-party-tiles-tileservice).
1. The `CustomTile` obtains the `TileServices` class from the `QSTileHost` and request the creation
of a `TileServiceManager` with its token. As the spec for the `CustomTile` contains
the `ComponentName` of the associated service, this can be used to bind to it.
2. The `TileServiceManager` creates its own `TileLifecycleManager` to take care of binding to the
service.
3. `TileServices` creates maps between the token, the `CustomTile`, the `TileServiceManager`, the
token and the `ComponentName`.
## Implementing a tile
This section describes necessary and recommended steps when implementing a Quick Settings tile. Some
of them are optional and depend on the requirements of the tile.
### Implementing a SystemUI tile
1. Create a class (preferably
in [`SystemUI/src/com/android/systemui/qs/tiles`](/packages/SystemUI/src/com/android/systemui/qs/tiles))
implementing `QSTileImpl` with a particular type of `State` as a parameter.
2. Create an injectable constructor taking a `QSHost` and whichever classes are needed for the
tile's operation. Normally this would be other SystemUI controllers.
3. Implement the methods described
in [Abstract methods in QSTileImpl](#abstract-methods-in-qstileimpl). Look at other tiles for
help. Some considerations to have in mind:
* If the tile will not support long click (like the `FlashlightTile`),
set `state.handlesLongClick` to `false` (maybe in `newTileState`).
* Changes to the tile state (either from controllers or from clicks) should call `refreshState`.
* Use only `handleUpdateState` to modify the values of the state to the new ones. This can be
done by polling controllers or through the `arg` parameter.
* If the controller is not a `CallbackController`, respond to `handleSetListening` by
attaching/dettaching from controllers.
* Implement `isAvailable` so the tile will not be created when it's not necessary.
4. Either create a new feature module or find an existing related feature module and add the
following binding method:
* ```kotlin
@Binds
@IntoMap
@StringKey(YourNewTile.TILE_SPEC) // A unique word that will map to YourNewTile
fun bindYourNewTile(yourNewTile: YourNewTile): QSTileImpl<*>
```
5. In [SystemUI/res/values/config.xml](/packages/SystemUI/res/values/config.xml),
modify `quick_settings_tiles_stock` and add the spec defined in the previous step. If necessary,
add it also to `quick_settings_tiles_default`. The first one contains a list of all the tiles
that SystemUI knows how to create (to show to the user in the customization screen). The second
one contains only the default tiles that the user will experience on a fresh boot or after they
reset their tiles.
6. In [SystemUI/res/values/tiles_states_strings.xml](/packages/SystemUI/res/values/tiles_states_strings.xml),
add a new array for your tile. The name has to be `tile_states_<spec>`. Use a good description to
help the translators.
7. In [`SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt`](/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt),
add a new element to the map in `SubtitleArrayMapping` corresponding to the resource created in the
previous step.
#### Abstract methods in QSTileImpl
Following are methods that need to be implemented when creating a new SystemUI tile. `TState` is a
type variable of type `State`.
* ```java
public TState newTileState()
```
Creates a new `State` for this tile to use. Each time the state changes, it is copied into a new
one and the corresponding fields are modified. The framework provides `State`, `BooleanState` (has
an on and off state and provides this as a content description), `SignalState` (`BooleanState`
with `activityIn` and `activityOut`), and `SlashState` (can be rotated or slashed through).
If a tile has special behavior (no long click, no ripple), it can be set in its state here.
* ```java
public void handleSetListening(boolean)
```
Initiates or terminates listening behavior, like listening to Callbacks from controllers. This
gets triggered when QS is expanded or collapsed (i.e., when the tile is visible and actionable).
Most tiles (like `WifiTile`) do not implement this. Instead, Tiles are LifecycleOwner and are
marked as `RESUMED` or `DESTROYED` in `QSTileImpl#handleListening` and handled as part of the
lifecycle
of [CallbackController](/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java)
* ```java
public QSIconView createTileView(Context)
```
Allows a Tile to use a `QSIconView` different from `QSIconViewImpl` (
see [Tile views](#tile-views)), which is the default defined in `QSTileImpl`
* ```java
public Intent getLongClickIntent()
```
Determines the `Intent` launched when the Tile is long pressed.
* ```java
protected void handleClick()
protected void handleSecondaryClick()
protected void handleLongClick()
```
Handles what to do when the Tile is clicked. In general, a Tile will make calls to its controller
here and maybe update its state immediately (by calling `QSTileImpl#refreshState`). A Tile can
also decide to ignore the click here, if it's `Tile#STATE_UNAVAILABLE`.
By default long click redirects to click and long click launches the intent defined
in `getLongClickIntent`.
* ```java
protected void handleUpdateState(TState, Object)
```
Updates the `State` of the Tile based on the state of the device as provided by the respective
controller. It will be called every time the Tile becomes visible, is interacted with
or `QSTileImpl#refreshState` is called. After this is done, the updated state will be reflected in
the UI.
* ```java
@Deprecated
public int getMetricsCategory()
```
~~Identifier for this Tile, as defined
in [proto/src/metrics_constants/metrics_constants.proto](/proto/src/metrics_constants/metrics_constants.proto).
This is used to log events related to this Tile.~~
This is now deprecated in favor of `UiEvent` that use the tile spec.
* ```java
public boolean isAvailable()
```
Determines if a Tile is available to be used (for example, disable `WifiTile` in devices with no
Wifi support). If this is false, the Tile will be destroyed upon creation.
* ```java
public CharSequence getTileLabel()
```
Provides a default label for this Tile. Used by the QS Panel customizer to show a name next to
each available tile.
### Implementing a third party tile
For information about this, use the Android Developer documentation
for [TileService](https://developer.android.com/reference/android/service/quicksettings/TileService).
## AutoAddable tiles
AutoAddable tiles are tiles that are not part of the default set, but will be automatically added
for the user, when the user enabled a feature for the first time. For example:
* When the user creates a work profile, the work profile tile is automatically added.
* When the user sets up a hotspot for the first time, the hotspot tile is automatically added.
In order to declare a tile as auto-addable, there are two ways:
* If the tile can be tied to a secure setting such that the tile should be auto added after that
setting has changed to a non-zero value for the first time, a new line can be added to the
string-array `config_quickSettingsAutoAdd` in [config.xml](/packages/SystemUI/res/values/config.xml).
* If more specific behavior is needed, a new
[AutoAddable](/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddable.kt)
can be added in the `autoaddables` package. This can have custom logic that produces a flow of
signals on when the tile should be auto-added (or auto-removed in special cases).
*Special case: If the data comes from a `CallbackController`, a special
`CallbackControllerAutoAddable` can be created instead that handles a lot of the common code.*
### AutoAddRepository (and UserAutoAddRepository)
These classes keep track of tiles that have been auto-added for each user, as a list of Tile specs.
While the device is running, this is the source of truth of already auto-added tiles for that user.
The list is persisted to `Settings.Secure` every time it changes so it will be available upon
restart or backup. In particular, any changes in the secure setting while this repository is
tracking the list of tiles will be reverted.
The class provides a `Flow<Set<TileSpec>>` for each user that can be collected to keep track of the
set of already auto added tiles.
### AutoAddInteractor
This class collects all registered (through Dagger) `AutoAddables` and merges all the signals for
the current user. It will add/remove tiles as necessary and mark them as such in the
`AutoAddRepository`.
## Backup and restore
It's important to point out that B&R of Quick Settings tiles only concerns itself with restoring,
for each user, the list of current tiles and their order. The state of the tiles (or other things
that can be accessed from them like list of WiFi networks) is the concern of each feature team and
out of the scope of Quick Settings.
In order to provide better support to restoring Quick Settings tiles and prevent overwritten or
inconsistent data, the system has the following steps:
1. When `Settings.Secure.SYSUI_QS_TILES` and `Settings.Secure.QS_AUTO_TILES` are restored, a
broadcast is sent to SystemUI. This is handled by
[SettingsHelper](/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java).
The broadcasts are received by [QSSettingsRestoredRepository](/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt)
and grouped by user into a data object. As described above, the change performed by the restore in
settings is overriden by the corresponding repositories.
2. Once both settings have been restored, the data is reconciled with the current data, to account
for tiles that may have been auto-added between the start of SystemUI and the time the restore
happened. The guiding principles for the reconciliation are as follows:
* We assume that the user expects the restored tiles to be the ones to be present after restore,
so those are taken as the basis for the reconciliation.
* Any tile that was auto-added before the restore, but had not been auto-added in the source
device, is auto-added again (preferably in a similar position).
* Any tile that was auto-added before the restore, and it was also auto-added in the source
device, but not present in the restored tiles, is considered removed by the user and therefore
not restored.
* Every tile that was marked as auto-added (all tiles in source + tiles added before restore)
are set as auto-added.
## Logs for debugging
The following log buffers are used for Quick Settings debugging purposes:
### QSLog
Logs events in the individual tiles, like listening state, clicks, and status updates.
### QSTileListLog
Logs changes in the current set of tiles for each user, including when tiles are created or
destroyed, and the reason for that. It also logs what operation caused the tiles to change
(add, remove, change, restore).
### QSAutoAddLog
Logs operations of auto-add (or auto-remove) of tiles.
### QSRestoreLog
Logs the data obtained after a successful restore of the settings. This is the data that will be
used for reconciliation.