# Technical Documentation: LawnchairLauncher/lawnchair

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/LawnchairLauncher/lawnchair)

### Overview (README.md)

# Lawnchair 16

[](https://github.com/LawnchairLauncher/lawnchair/actions/workflows/ci.yml)
[](https://github.com/LawnchairLauncher/lawnchair/actions/workflows/release_update.yml)
[](https://lawnchair.crowdin.com/lawnchair)
[](https://opencollective.com/lawnchair)
[](https://t.me/lccommunity)
[](https://discord.gg/3x8qNWxgGZ)
[](https://github.com/LawnchairLauncher/lawnchair/releases)
[](https://play.google.com/store/apps/details?id=app.lawnchair.play)

<picture>
    
    <source media="(prefers-color-scheme: dark)" srcset="docs/assets/device-frame-dark.webp" width="250px">
    <img alt="Smartphone home screen shown in day and night themes, featuring Android Material You dynamic color styling across the wallpaper, clock widget, and app icons." src="docs/assets/device-frame-light.webp" width="250px">
</picture>

Lawnchair is a free, open-source home app for Android. Taking Launcher3—Android’s default home app—as a starting point, it ports Pixel Launcher features and introduces rich customization options.

This branch houses the codebase of Lawnchair 16, which is currently in development and is based on Launcher3 from Android 16. For Lawnchair 9 to 15, see the branches with the `9-` to `15-` prefixes, respectively.

## Features

- Material 3 Expressive theming that follows your wallpaper and system colors.
- At a Glance widget support, with integration for [Smartspacer](https://github.com/KieronQuinn/Smartspacer).
- QuickSwitch support for Android Recents integration on Android 15-16 (root required).
- Global search for apps, contacts, and web results from the home screen.
- Customization options for icon packs, fonts, and color settings.

## Download

<p align="left">
  <a href="https://play.google.com/store/apps/details?id=app.lawnchair.play">
    <picture>
      
      <source media="(prefers-color-scheme: dark)" srcset="docs/assets/badge-google-play.webp" height="60">
      <img alt="Get it on Google Play" src="docs/assets/badge-google-play.webp" height="60">
    </picture>
  </a>
  <a href="https://apt.izzysoft.de/fdroid/index/apk/app.lawnchair">
    <picture>
      <source media="(prefers-color-scheme: dark)" srcset="docs/assets/badge-izzyondroid.webp" height="60">
      <img alt="Get it on IzzyOnDroid" src="docs/assets/badge-izzyondroid.webp" height="60">
    </picture>
  </a>
  <a href="https://apps.obtainium.imranr.dev/redirect?r=obtainium://add/https://github.com/LawnchairLauncher/lawnchair/">
    <picture>
      <source media="(prefers-color-scheme: dark)" srcset="docs/assets/badge-obtainium.webp" height="60">
      <img alt="Get it on Obtainium" src="docs/assets/badge-obtainium.webp" height="60">
    </picture>
  </a>
    <a href="https://github.com/LawnchairLauncher/lawnchair/releases">
    <picture>
      <source media="(prefers-color-scheme: dark)" srcset="docs/assets/badge-github.webp" height="60">
      <img alt="Get it on GitHub" src="docs/assets/badge-github.webp" height="60">
    </picture>
  </a>
</p>

Lawnchair on Play Store will install as a different app compared to other sources. Features may be restricted to comply with Google Play’s publishing rules.

You can also [verify your installation](https://docs.lawnchair.app/getting-started/install-and-setup/verify) to check if you have installed an official build.

### Development builds

Interested in keeping yourself up-to-date with every Lawnchair development? Try our development builds!

These builds offer the latest features and bug fixes at a cost of performance and additional issues. Make backups before installing.

Download: [Obtainium][Obtainium link] • [GitHub][GitHub link] • [nightly.link][Nightly link]

## Sponsors

<p align="left">
  <a href="https://coderabbit.link/lawnchair">
    <picture>
      <source media="(prefers-color-scheme: dark)" srcset="docs/assets/sponsor-coderabbit-dark.svg" width="300">
      <img alt="CodeRabbit" src="docs/assets/sponsor-coderabbit-light.svg" width="300">
    </picture>
  </a>
</p>

[CodeRabbit](https://coderabbit.link/lawnchair) is an AI-powered code review platform that integrates directly into pull-request workflows and IDEs, examining code changes in context and suggesting improvements.

## Support Lawnchair

If you love what we do, consider [supporting us on Open Collective](https://opencollective.com/lawnchair)! Your contributions help keep Lawnchair independent and enable us to develop faster.

A huge thank you to our Core Backers ($5+):
*(These backers directly fund our Project Velocity Fund)*

[](https://opencollective.com/lawnchair)

[Become a supporter](https://opencollective.com/lawnchair) to help us cover our operational costs, or become a Core Backer to be featured here!

## Contribute

Visit the [Lawnchair contributing guidelines](CONTRIBUTING.md) for information and tips on contributing to Lawnchair.

## Quick links

- [Website](https://lawnchair.app)
- [Documentation](https://docs.lawnchair.app/)
- [News on Telegram](https://t.me/lawnchairci)
- [Discord](https://discord.com/invite/3x8qNWxgGZ)
- [X (formerly Twitter)](https://x.com/lawnchairapp)
- [_XDA_ thread](https://xdaforums.com/t/lawnchair-customizable-pixel-launcher.3627137/)


[Nightly link]: https://nightly.link/LawnchairLauncher/lawnchair/workflows/ci/16-dev
[Obtainium link]: https://apps.obtainium.imranr.dev/redirect?r=obtainium://app/%7B%22id%22%3A%22app.lawnchair.nightly%22%2C%22url%22%3A%22https%3A%2F%2Fgithub.com%2Flawnchairlauncher%2Flawnchair%22%2C%22author%22%3A%22Lawnchair%20Launcher%22%2C%22name%22%3A%22Lawnchair%20(Debug)%22%2C%22preferredApkIndex%22%3A0%2C%22additionalSettings%22%3A%22%7B%5C%22includePrereleases%5C%22%3Atrue%2C%5C%22fallbackToOlderReleases%5C%22%3Afalse%2C%5C%22filterReleaseTitlesByRegEx%5C%22%3A%5C%22Lawnchair%20Nightly%5C%22%2C%5C%22filterReleaseNotesByRegEx%5C%22%3A%5C%22%5C%22%2C%5C%22verifyLatestTag%5C%22%3Afalse%2C%5C%22dontSortReleasesList%5C%22%3Afalse%2C%5C%22useLatestAssetDateAsReleaseDate%5C%22%3Afalse%2C%5C%22trackOnly%5C%22%3Afalse%2C%5C%22versionExtractionRegEx%5C%22%3A%5C%22%5C%22%2C%5C%22matchGroupToUse%5C%22%3A%5C%22%5C%22%2C%5C%22versionDetection%5C%22%3Afalse%2C%5C%22releaseDateAsVersion%5C%22%3Atrue%2C%5C%22useVersionCodeAsOSVersion%5C%22%3Afalse%2C%5C%22apkFilterRegEx%5C%22%3A%5C%22%5C%22%2C%5C%22invertAPKFilter%5C%22%3Afalse%2C%5C%22autoApkFilterByArch%5C%22%3Atrue%2C%5C%22appName%5C%22%3A%5C%22%5C%22%2C%5C%22shizukuPretendToBeGooglePlay%5C%22%3Afalse%2C%5C%22exemptFromBackgroundUpdates%5C%22%3Afalse%2C%5C%22skipUpdateNotifications%5C%22%3Afalse%2C%5C%22about%5C%22%3A%5C%22Lawnchair%20is%20a%20free%2C%20open-source%20home%20app%20for%20Android.%20(NOTE%3A%20This%20is%20the%20debug%20version%20of%20Lawnchair%2C%20for%20the%20beta%2Fstable%20versions%20see%20%5C%5C%5C%22Lawnchair%5C%5C%5C%22)%5C%22%7D%22%7D
[GitHub link]: https://github.com/LawnchairLauncher/lawnchair/releases/tag/nightly

---

### Wmshell Src Com Android Wm Shell Docs README (`wmshell/src/com/android/wm/shell/docs/README.md`)

# Window Manager Shell Readme

go/wmshell

The following docs present more detail about the implementation of the WMShell library (in no
particular order):

1) [What is the Shell](overview.md)
2) [Integration with SystemUI & Launcher](sysui.md)
3) [Usage of Dagger](dagger.md)
4) [Threading model in the Shell](threading.md)
5) [Making changes in the Shell](changes.md)
6) [Extending the Shell for Products/OEMs](extending.md)
6) [Shell transitions](transitions.md)
7) [Debugging in the Shell](debugging.md)
8) [Testing in the Shell](testing.md)

Todo
- Per-feature docs
- Feature flagging
- Best practices & patterns

---

### Wmshell Src Com Android Wm Shell Docs Overview (`wmshell/src/com/android/wm/shell/docs/overview.md`)

# What is the WindowManager Shell
[Back to home](README.md)

---

## Motivation

The primary motivation for the WindowManager Shell (WMShell) library is to effectively scale
WindowManager by making it easy&trade; and safe to create windowing features to fit the needs of
various Android products and form factors.

To achieve this, WindowManager separates the policy of managing windows (WMCore) from the
presentation of surfaces (WMShell) and provides a minimal interface boundary for the two to
communicate.

## Who is using the library?

Currently, the WMShell library is used to drive the windowing experience on handheld
(phones & tablets), TV, Auto, Arc++, and Wear to varying degrees.

## Where does the code live

The core WMShell library code is currently located in the [frameworks/base/libs/WindowManager/Shell](/libs/WindowManager/Shell)
directory and is included as a part dependency of the host SystemUI apk.

## How do I build the Shell library

The library can be built directly by running:
```shell
m WindowManager-Shell
```
But this is mainly useful for inspecting the contents of the library or verifying it builds. The
various targets can be found in the Shell library's [Android.bp](/libs/WindowManager/Shell/Android.bp)
file.

Normally, you would build it as a part of the host SystemUI, for example via commandline:
```shell
# Phone SystemUI variant
m SystemUI
adevice update
```

Or preferably, if you are making WMShell/SysUI only changes (no other framework changes), then
building via [go/sysui-studio](http://go/sysui-studio) allows for very quick iteration (one click
build and push of SysUI in < 30s).

If you are making framework changes and are using `aidegen` to set up your platform IDE, make sure
to include the appropriate directories to build, for example:
```shell
# frameworks/base will include base/libs/WindowManager/Shell and base/packages/SystemUI
aidegen frameworks/base \
    vendor/<oem>/packages/SystemUI \
    ...
```

## Other useful links
- [go/o-o-summit-20](go/o-o-summit-20) (Video presentations from the WM team)
- [go/o-o-summit-21](go/o-o-summit-21)

---

### Wmshell Src Com Android Wm Shell Docs Changes (`wmshell/src/com/android/wm/shell/docs/changes.md`)

# Making changes in the Shell
[Back to home](README.md)

---

## Code reviews

In addition to the individual reviewers who are most familiar with the changes you are making,
please also add [wm-code-reviewers@google.com](http://g/wm-code-reviewers) to keep other WM folks
in the loop.

## Adding new code

### Internal Shell utility classes
If the new component is used only within the WMShell library, then there are no special
considerations, go ahead and add it (in the `com.android.wm.shell.common` package for example)
and make sure the appropriate [unit tests](testing.md) are added.

### Internal Shell components
If the new component is to be used by other components/features within the Shell library, then
you can create an appropriate package for this component to add your new code. The current
pattern is to have a single `<Component name>Controller` that handles the initialization of the
component.

As mentioned in the [Dagger usage](dagger.md) docs, you need to determine whether it should go into:
- `WMShellBaseModule` for components that other base & product components will depend on
- or `WMShellModule`, `TvWmShellModule`, etc. for product specific components that no base
  components depend on

### SysUI accessible components
In addition to doing the above, you will also need to provide an interface for calling to SysUI
from the Shell and vice versa.  The current pattern is to have a parallel `Optional<Component name>`
interface that the `<Component name>Controller` implements and handles on the main Shell thread
(see [SysUI/Shell threading](threading.md)).

In addition, because components accessible to SysUI injection are explicitly listed, you'll have to
add an appropriate method in `WMComponent` to get the interface and update the `Builder` in
`SysUIComponent` to take the interface so it can be injected in SysUI code.  The binding between
the two is done in `SystemUIFactory#init()` which will need to be updated as well.

Specifically, to support calling into a controller from an external process (like Launcher):
- Create an implementation of the external interface within the controller
- Have all incoming calls post to the main shell thread (inject @ShellMainThread Executor into the
  controller if needed)
- Note that callbacks into SysUI should take an associated executor to call back on

### Launcher accessible components
Because Launcher is not a part of SystemUI and is a separate process, exposing controllers to
Launcher requires a new AIDL interface to be created and implemented by the controller.  The
implementation of the stub interface in the controller otherwise behaves similar to the interface
to SysUI where it posts the work to the main Shell thread.

Specifically, to support calling into a controller from an external process (like Launcher):
- Create an implementation of the interface binder's `Stub` class within the controller, have it
  extend `ExternalInterfaceBinder` and implement `invalidate()` to ensure it doesn't hold long
  references to the outer controller
- Make the controller implement `RemoteCallable<T>`, and have all incoming calls use one of
  the `executeRemoteCallWithTaskPermission()` calls to verify the caller's identity and ensure the
  call happens on the main shell thread and not the binder thread
- Inject `ShellController` and add the instance of the implementation as external interface
- In Launcher, update `TouchInteractionService` to pass the interface to `SystemUIProxy`, and then
  call the SystemUIProxy method as needed in that code

### Component initialization
To initialize the component:
- On the Shell side, you potentially need to do two things to initialize the component:
  - Inject `ShellInit` into your component and add an init callback
  - Ensure that your component is a part of the dagger dependency graph, either by:
    - Making this component a dependency of an existing component already exposed to SystemUI
    - Explicitly add this component to the WMShellBaseModule @ShellCreateTrigger provider or
      the @ShellCreateTriggerOverride provider for your product module to expose it explicitly 
      if it is a completely independent component
- On the SysUI side, update `WMShell` to setup any bindings for the component that depend on
  SysUI code

To verify that your component is being initialized at startup, you can enable the `WM_SHELL_INIT` 
protolog group and restart the SysUI process:
```shell
adb shell wm logging enable-text WM_SHELL_INIT
adb shell kill `pid com.android.systemui`
adb logcat *:S WindowManagerShell
```

### General Do's & Dont's
Do:
- Add unit tests for all new components
- Keep controllers simple and break them down as needed
- Any SysUI callbacks should also take an associated executor to run the callback on

Don't:
- **Don't** do initialization in the constructor, only do initialization in the init callbacks.
  Otherwise it complicates the building of the dependency graph.
- **Don't** create dependencies from base-module components on specific features (the base module
  is intended for use with all products)
  - Try adding a mechanism to register and listen for changes from the base module component instead
- **Don't** add blocking synchronous calls in the SysUI interface between Shell & SysUI
  - Try adding a push-mechanism to share data, or an async callback to request data

### Exposing shared code for use in Launcher
Launcher doesn't currently build against the Shell library, but needs to have access to some shared
AIDL interfaces and constants.  Currently, all AIDL files, and classes under the
`com.android.wm.shell.shared` package are automatically built into the `SystemUISharedLib` that
Launcher uses.

If the new code doesn't fall into those categories, they should be moved to the Shell shared
package (`com.android.wm.shell.shared`) under the `WindowManager-Shell-shared` library.

---

### Wmshell Src Com Android Wm Shell Docs Dagger (`wmshell/src/com/android/wm/shell/docs/dagger.md`)

# Usage of Dagger in the Shell library

[Back to home](README.md)

---

## Dependencies

Dagger is not required to use the Shell library, but it has a lot of obvious benefits:

- Not having to worry about how to instantiate all the dependencies of a class, especially as
  dependencies evolve (ie. product controller depends on base controller)
- Can create boundaries within the same app to encourage better code modularity

As such, the Shell also tries to provide some reasonable out-of-the-box modules for use with Dagger.

## Modules

All the Dagger related code in the Shell can be found in the `com.android.wm.shell.dagger` package,
this is intentional as it keeps the "magic" in a single location. The explicit nature of how
components in the shell are provided is as a result a bit more verbose, but it makes it easy for
developers to jump into a few select files and understand how different components are provided
(especially as products override components).

The module dependency tree looks a bit like:

- [WMShellConcurrencyModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java)
  (provides threading-related components)
    - [WMShellBaseModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java)
      (provides components that are common to many products, ie. DisplayController, Transactions,
      etc.)
        - [WMShellModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java)
          (phone/tablet specific components only)
        - [TvPipModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java)
          (PIP specific components for TV)
            - [TvWMShellModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java)
              (TV specific components only)
    - etc.

Ideally features could be abstracted out into their own modules and included as needed by each
product.

## Changing WMShellBaseModule

Because all products will include WMShellBaseModule, we don't want it to provide instances for
features that aren't used across multiple products (ie. Handheld, TV, Auto, Wear). This module
should generally only provide:

- Concrete implementations that are needed for startup
  (see `provideIndependentShellComponentsToCreate()`)
- Things used directly/indirectly by interfaces
  exposed to SysUI
  in [WMComponent.java](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMComponent.java).

For the latter, not every feature will be enabled on the SysUI form factor including the base
module, so the recommendation is to have an `@BindsOptionalOf` for the interface, and have the
actual implementation provided in the form-factor specific module (ie. `WMShellModule`).

## Overriding base components

In some rare cases, there are base components that can change behavior depending on which
product it runs on. If there are hooks that can be added to the component, that is the
preferable approach.

The alternative is to use
the [@DynamicOverride](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/DynamicOverride.java)
annotation to allow the product module to provide an implementation that the base module can
reference. This is most useful if the existence of the entire component is controlled by the
product and the override implementation is optional (there is a default implementation). More
details can be found in the class's javadoc.

## Starting up Shell components aren't dependencies for other components

With Dagger, objects are created in dependency order and individual components can register with
`ShellInit` (see [Component initialization](changes.md#component-initialization)) to initialize in
dependency order as well. However, if there is code that needs to run on startup but has nothing
dependent on it (imagine a background error detector for example), then
`provideIndependentShellComponentsToCreate()` can serve as the artificial dependent object (itself
a dependency for `ShellInterface`) to trigger creation of such a component.

This can be declared within each module, so if a product includes `WMShellModule`, all the
components in `provideIndependentShellComponentsToCreate()` for both it and `WMShellBaseModule` will
be created.

Note that long term we are looking to move to a `CoreStartable` like infrastructure.

---

### Wmshell Src Com Android Wm Shell Docs Debugging (`wmshell/src/com/android/wm/shell/docs/debugging.md`)

# Debugging in the Shell
[Back to home](README.md)

---

## Logging & ProtoLogs

The interactions in the Shell can be pretty complicated, so having good logging is crucial to
debugging problems that arise (especially in dogfood).  The Shell uses the same efficient Protolog
mechanism as WM Core, which can be enabled at runtime on debug devices.

**TLDR**&nbsp; Don’t use Logs or Slogs except for error cases, Protologs are much more flexible,
easy to add and easy to use

### Adding a new ProtoLog
Update `ShellProtoLogGroup` to include a new log group (ie. NEW_FEATURE) for the content you want to
log.  ProtoLog log calls mirror Log.v/d/e(), and take a format message and arguments:
```java
ProtoLog.v(NEW_FEATURE, "Test log w/ params: %d %s", 1, “a”)
```
This code itself will not compile by itself, but the `protologtool` will preprocess the file when
building to check the log state (is enabled) before printing the print format style log.

**Notes**
- ProtoLogs are only fully supported from soong builds (ie. via make/mp). In SysUI-studio it falls
  back to log via Logcat
- Non-text ProtoLogs are not currently supported with the Shell library (you can't view them with
  traces in Winscope)

### Kotlin
Kotlin protologging is supported, but with some differences compared to Java. The ProtoLog tool
currently does not process Kotlin code. This means that while ProtoLogs in Kotlin will still be
traced to Perfetto, they are not pre-processed to extract static strings like in Java. Consequently,
using ProtoLogging in Kotlin does not provide the same memory gains as in Java, and log calls may be
slightly less performant due to additional string interning at runtime.

### Enabling ProtoLog command line logging
Run these commands to enable protologs (in logcat) for WM Core ([list of all core groups](/core/java/com/android/internal/protolog/WmProtoLogGroups.java)) or WM Shell ([list of all shell groups](/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java)):
```shell
# Note: prior to 25Q2, you may need to use:
#   adb shell dumpsys activity service SystemUIService WMShell protolog enable-text TAG
adb shell cmd protolog_configuration logcat enable <group>
adb shell cmd protolog_configuration logcat disable <group>
```

Use these commands to print protolog groups and their status:
```shell
adb shell cmd protolog_configuration groups list
adb shell cmd protolog_configuration groups status <group>
```

### R8 optimizations & ProtoLog

If the APK that the Shell library is included into has R8 optimizations enabled, then you may need
to update the proguard flags to keep the generated protolog classes (ie. AOSP SystemUI's [proguard.flags](/packages/SystemUI/proguard_common.flags)).

## Winscope Tracing

The Winscope tool is extremely useful in determining what is happening on-screen in both
WindowManager and SurfaceFlinger.  Follow [go/winscope](http://go/winscope-help) to learn how to
use the tool.  This trace will contain all the information about the windows/activities/surfaces on
screen.

## WindowManager/SurfaceFlinger/InputDispatcher information

A quick way to view the WindowManager hierarchy without a winscope trace is via the wm dumps:
```shell
adb shell dumpsys activity containers
# The output lists the containers in the hierarchy from top -> bottom in z-order
```

To get more information about windows on the screen:
```shell
# All windows in WM
adb shell dumpsys window -a
# The windows are listed from top -> bottom in z-order

# Visible windows only
adb shell dumpsys window -a visible
```

Likewise, the SurfaceFlinger hierarchy can be dumped for inspection by running:
```shell
adb shell dumpsys SurfaceFlinger
# Search output for "Layer Hierarchy", the surfaces in the table are listed bottom -> top in z-order
```

And the visible input windows can be dumped via:
```shell
adb shell dumpsys input
# Search output for "Windows:", they are ordered top -> bottom in z-order
```

## Tracing global SurfaceControl transaction updates

While Winscope traces are very useful, it sometimes doesn't give you enough information about which
part of the code is initiating the transaction updates. In such cases, it can be helpful to get
stack traces when specific surface transaction calls are made (regardless of process), which is
possible by enabling the following system properties for example:
```shell
# Enabling
adb shell setprop persist.wm.debug.sc.tx.log_match_call setAlpha,setPosition  # matches the name of the SurfaceControlTransaction methods
adb shell setprop persist.wm.debug.sc.tx.log_match_name com.android.systemui # matches the name of the surface
adb reboot
adb logcat -s "SurfaceControlRegistry"

# Disabling logging
adb shell setprop persist.wm.debug.sc.tx.log_match_call \"\"
adb shell setprop persist.wm.debug.sc.tx.log_match_name \"\"
```

A reboot is required to enable the logging. Once enabled, reboot is not needed to update the
properties.

It is not necessary to set both `log_match_call` and `log_match_name`, but note logs can be quite
noisy if unfiltered.

### Tracing transaction merge & apply

Tracing the method calls on SurfaceControl.Transaction tells you where a change is requested, but
the changes are not actually committed until the transaction itself is applied.  And because
transactions can be passed across processes, or prepared in advance for later application (ie.
when restoring state after a Transition), the ordering of the change logs is not always clear
by itself.

In such cases, you can also enable the "merge" and "apply" calls to get additional information
about how/when transactions are respectively merged/applied:
```shell
# Enabling
adb shell setprop persist.wm.debug.sc.tx.log_match_call setAlpha,merge,apply  # apply will dump logs of each setAlpha or merge call on that tx
adb reboot
adb logcat -s "SurfaceControlRegistry"
```

Using those logs, you can first look at where the desired change is called, note the transaction
id, and then search the logs for where that transaction id is used.  If it is merged into another
transaction, you can continue the search using the merged transaction until you find the final
transaction which is applied.

## Tracing activity starts & finishes in the app process

It's sometimes useful to know when to see a stack trace of when an activity starts in the app code
or via a `WindowContainerTransaction` (ie. if you are repro'ing a bug related to activity starts).
You can enable this system property to get this trace:
```shell
# Enabling
adb shell setprop persist.wm.debug.start_activity true
adb reboot
adb logcat -s "Instrumentation"

# Disabling
adb shell setprop persist.wm.debug.start_activity \"\"
adb reboot
```

Likewise, to trace where a finish() call may be made in the app process, you can enable this system
property:
```shell
# Enabling
adb shell setprop persist.wm.debug.finish_activity true
adb reboot
adb logcat -s "Instrumentation"

# Disabling
adb shell setprop persist.wm.debug.finish_activity \"\"
adb reboot
```

## Tracing transition starts/finishes in the Shell

To trace where a new WM transition is started and finished in the Shell, you can enable these system
properties respectively:
```shell
# Enabling
adb shell setprop persist.wm.debug.start_shell_transition true
adb shell setprop persist.wm.debug.finish_shell_transition true
adb reboot
adb logcat -s "ShellTransitions"

# Disabling
adb shell setprop persist.wm.debug.start_shell_transition \"\"
adb shell setprop persist.wm.debug.finish_shell_transition \"\"
adb reboot
```


## Dumps

Because the Shell library is built as a part of SystemUI, dumping the state is currently done as a
part of dumping the SystemUI service.  Dumping the Shell specific data can be done by specifying the
WMShell SysUI service:

```shell
# Note: prior to 25Q2, you may need to use:
#   adb shell dumpsys activity service SystemUIService WMShell dump
adb shell wm shell dump
```

If information should be added to the dump, either:
- Update `WMShell` if you are dumping SysUI state
- Inject `ShellCommandHandler` into your Shell class, and add a dump callback

## Shell commands

It can be useful to add additional shell commands to drive and test specific interactions.

To add a new command for your feature, inject a `ShellCommandHandler` into your class and add a
shell command handler in your controller.

```shell
# List all available commands
# Note: prior to 25Q2, you may need to use:
#   adb shell dumpsys activity service SystemUIService WMShell help
adb shell wm shell help

# Run a specific command
# Note: prior to 25Q2, you may need to use:
#   adb shell dumpsys activity service SystemUIService WMShell <cmd> <args> ...
adb shell wm shell <cmd> <args> ...
```

## Debugging in Android Studio

If you are using the [go/sysui-studio](http://go/sysui-studio) project, then you can debug Shell
code directly from Android Studio like any other app.

---

### Wmshell Src Com Android Wm Shell Docs Extending (`wmshell/src/com/android/wm/shell/docs/extending.md`)

# Extending the Shell for Products/OEMs
[Back to home](README.md)

---

## General Do's & Dont's

Do:
- &nbsp;

Don't
- **Don't** override classes provided by WMShellBaseModule, it makes it difficult to make
  simple changes to the Shell library base modules which are shared by all products
  - If possible add mechanisms to modify the base class behavior

---

### Wmshell Src Com Android Wm Shell Docs Sysui (`wmshell/src/com/android/wm/shell/docs/sysui.md`)

# Shell & SystemUI
[Back to home](README.md)

---

## Setup

The SystemUI of various products depend on and build against the WM Shell library. To ensure
that we don't inadvertently build dependencies between the Shell library and one particular
product (ie. handheld SysUI), we deliberately separate the initialization of the WM Shell
component from the SysUI component when set up through Dagger.

**TLDR**&nbsp; Initialize everything as needed in the WM component scope and export only well
defined interfaces to SysUI.

## Initialization

There are more details in the Dagger docs, but the general overview of the SysUI/Shell
initialization flow is such:

1) SysUI Global scope is initialize (see `GlobalModule` and its included modules)
2) WM Shell scope is initialized, for example
   1) On phones: `WMComponent` includes `WMShellModule` which includes `WMShellBaseModule`
      (common to all SysUI)
   2) On TVs: `TvWMComponent` includes `TvWMShellModule` which includes `WMShellBaseModule`
   3) etc.
3) SysUI explicitly passes interfaces provided from the `WMComponent` to `SysUIComponent` via
   the `SysUIComponent#Builder`, then builds the SysUI scoped components
4) `WMShell` is the SystemUI “service” (in the SysUI scope) that initializes with the app after the
SystemUI part of the dependency graph has been created. It contains the binding code between the
interfaces provided by the Shell and the rest of SystemUI.
5) SysUI can inject the interfaces into its own components

More detail can be found in [go/wm-sysui-dagger](http://go/wm-sysui-dagger).

## Interfaces from SysUI to Shell components

Within the same process, the WM Shell components can be running on a different thread than the main
SysUI thread (disabled on certain products).  This introduces challenges where we have to be
careful about how SysUI calls into the Shell and vice versa.

As a result, we enforce explicit interfaces between SysUI and Shell components, and the
implementations of the interfaces on each side need to post to the right thread before it calls
into other code.

For example, you might have:
1) (Shell) ShellFeature interface to be used from SysUI
2) (Shell) ShellFeatureController handles logic, implements ShellFeature interface and posts to
   main Shell thread
3) SysUI application init injects Optional<ShellFeature> as an interface to SysUI to call
4) (SysUI) SysUIFeature depends on ShellFeature interface
5) (SysUI) SysUIFeature injects Optional<ShellFeature>, and sets up a callback for the Shell to
   call, and the callback posts to the main SysUI thread

Adding an interface to a Shell component may seem like a lot of boiler plate, but is currently
necessary to maintain proper threading and logic isolation.

## Listening for Configuration changes & other SysUI events

Aside from direct calls into Shell controllers for exposed features, the Shell also receives
common event callbacks from SysUI via the `ShellController`.  This includes things like:

- Configuration changes
- Keyguard events
- Shell init
- Shell dumps & commands

For other events which are specific to the Shell feature, then you can add callback methods on
the Shell feature interface.  Any such calls should <u>**never**</u> be synchronous calls as
they will need to post to the Shell main thread to run.

## Shell commands & Dumps

Since the Shell library is a part of the SysUI process, it relies on SysUI to trigger commands
on individual Shell components.

More detail can be found in [Debugging in the Shell](debugging.md#shell-commands) section.

---

### Wmshell Src Com Android Wm Shell Docs Testing (`wmshell/src/com/android/wm/shell/docs/testing.md`)

# Testing
[Back to home](README.md)

---

## Unit tests

New WM Shell unit tests can be added to the
[Shell/tests/unittest](/libs/WindowManager/Shell/tests/unittest) directory, and can
be run via command line using `atest`:
```shell
atest WMShellUnitTests
```

If you use the SysUI Studio project, you can run and debug tests directly in the source files
(click on the little arrows next to the test class or test method).

These unit tests are run as a part of WindowManager presubmit, and the dashboards for these unit
tests tests can be found at [go/wm-tests](http://go/wm-tests).

This [GCL file](http://go/wm-unit-tests-gcl) configures the tests being run on the server.

## Flicker tests

Flicker tests are tests that perform actions and make assertions on the state in Window Manager
and SurfaceFlinger traces captured during the run.

New WM Shell Flicker tests can be added to the
[Shell/tests/flicker](/libs/WindowManager/Shell/tests/flicker) directory, and can be run via command line using `atest`:
```shell
# Bubbles
atest WMShellFlickerTestsBubbles

# PIP
atest WMShellFlickerTestsPip1
atest WMShellFlickerTestsPip2
atest WMShellFlickerTestsPip3
atest WMShellFlickerTestsPipApps
atest WMShellFlickerTestsPipAppsCSuite

# Splitscreen
atest WMShellFlickerTestsSplitScreenGroup1
atest WMShellFlickerTestsSplitScreenGroup2

# Other
atest WMShellFlickerTestsOther
```

**Note**: Currently Flicker tests can only be run from the commandline and not via SysUI Studio

A subset of the flicker tests tests are run as a part of WindowManager presubmit, and the
dashboards for these tests tests can be found at [go/wm-tests-flicker](http://go/wm-tests-flicker).

## CTS tests

Some windowing features also have CTS tests to ensure consistent behavior across OEMs.  For example:
- Picture-in-Picture:
  [PinnedStackTests](cts/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java)
- etc.

These can also be run via commandline only using `atest`, for example:
```shell
atest PinnedStackTests
```

---

### Wmshell Src Com Android Wm Shell Docs Threading (`wmshell/src/com/android/wm/shell/docs/threading.md`)

# Threading
[Back to home](README.md)

---

## Boundaries

```text
                                    Thread boundary
                                          |
                                WM Shell  | SystemUI
                                          |
                                          |
FeatureController <-> FeatureInterface <--|--> WMShell <-> SysUI
       |          (^post to shell thread) |            (^post to main thread)
      ...                                 |
       |                                  |
 OtherControllers                         |
```

## Threads

We currently have multiple threads in use in the Shell library depending on the configuration by
the product.
- SysUI main thread (standard main thread)
- `ShellMainThread` (only used if the resource `config_enableShellMainThread` is set true
  (ie. phones))
  - This falls back to the SysUI main thread otherwise
  - **Note**:
    - This thread runs with `THREAD_PRIORITY_DISPLAY` priority since so many windowing-critical
      components depend on it
    - This is also the UI thread for almost all UI created by the Shell
    - The Shell main thread Handler (and the Executor that wraps it) is async, so
      messages/runnables used via this Handler are handled immediately if there is no sync
      messages prior to it in the queue.
- `ShellBackgroundThread` (for longer running tasks where we don't want to block the shell main
  thread)
  - This is always another thread even if config_enableShellMainThread is not set true
  - **Note**:
    - This thread runs with `THREAD_PRIORITY_BACKGROUND` priority but can be requested to be boosted
      to `THREAD_PRIORITY_FOREGROUND`
- `ShellAnimationThread` (currently only used for Transitions and Splitscreen, but potentially all
  animations could be offloaded here)
- `ShellSplashScreenThread` (only for use with splashscreens)

## Dagger setup

The threading-related components are provided by the [WMShellConcurrencyModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java),
for example, the Executors and Handlers for the various threads that are used.  You can request
an executor of the necessary type by using the appropriate annotation for each of the threads (ie.
`@ShellMainThread Executor`) when injecting into your Shell component.

To get the SysUI main thread, you can use the `@Main` annotation.

## Best practices

### Components
- Don't do initialization in the Shell component constructors
  - If the host SysUI is not careful, it may construct the WMComponent dependencies on the main
    thread, and this reduces the likelihood that components will intiailize on the wrong thread
    in such cases
- Be careful of using CountDownLatch and other blocking synchronization mechanisms in Shell code
  - If the Shell main thread is not a separate thread, this will cause a deadlock
- Callbacks, Observers, Listeners to any non-shell component should post onto main Shell thread
  - This includes Binder calls, SysUI calls, BroadcastReceivers, etc. Basically any API that
    takes a runnable should either be registered with the right Executor/Handler or posted to
    the main Shell thread manually
- Since everything in the Shell runs on the main Shell thread, you do **not** need to explicitly
  `synchronize` your code (unless you are trying to prevent reentrantcy, but that can also be
  done in other ways)

### Handlers/Executors
- You generally **never** need to create Handlers explicitly, instead inject `@ShellMainThread
  ShellExecutor` instead
  - This is a common pattern to defer logic in UI code, but the Handler created wraps the Looper
    that is currently running, which can be wrong (see above for initialization vs construction)
- That said, sometimes Handlers are necessary because Framework API only takes Handlers or you
  want to dedupe multiple messages
  - In such cases inject `@ShellMainThread Handler` or use view.getHandler() which should be OK
    assuming that the view root was initialized on the main Shell thread
- <u>**Never</u> use Looper.getMainLooper()**
  - It's likely going to be wrong, you can inject `@Main ShellExecutor` to get the SysUI main thread

### Testing
- You can use a `TestShellExecutor` to control the processing of messages

---

### Wmshell Src Com Android Wm Shell Docs Transitions (`wmshell/src/com/android/wm/shell/docs/transitions.md`)

# Shell transitions
[Back to home](README.md)

---

## General

General guides for using Shell Transitions can be found here:
- [Shell transitions animation guide](http://go/shell-transit-anim)
- [Hitchhiker's guide to transitions](http://go/transitions-book)

## Transient-launch transitions
<span style="color:orange">Use with care!</span>

Transient-launch transitions are a way to handle non-atomic (ie. gestural) transitions by allowing
WM Core to put participating activities into a transiently visible or hidden state for the duration
of the animation and adding the ability to cancel the transition.  

For example, if you are launching an activity normally, WM Core will be updated
at the start of the animation which includes pausing the previous activity and resuming the next
activity (and subsequently the transition will reconcile that state via an animation).

If you are transiently launching an activity though, WM Core will ensure that both the leaving 
activity and the incoming activity will be RESUMED for the duration of the transition duration. In
addition, WM Core will track the position of the transient-launch activity in the window hierarchy
prior to the launch, and allow Shell to restore it to that position if the transitions needs to be
canceled.

Starting a transient-launch transition can be done via the activity options (since the activity may
not have been started yet):
```kotlin
val opts = ActivityOptions.makeBasic().setTransientLaunch()
val wct = WindowContainerTransaction()
wct.sendPendingIntent(pendingIntent, new Intent(), opts.toBundle())
transitions.startTransition(TRANSIT_OPEN, wct, ...)
```

And restoring the transient order via a WCT:
```kotlin
val wct = WindowContainerTransaction()
wct.restoreTransientOrder(transientLaunchContainerToken)
transitions.startTransition(TRANSIT_RESTORE, wct, ...)
```

### <span style="color:orange">Considerations</span>

Usage of transient-launch transitions should be done with consideration, there are a few gotchas
that might result in subtle and hard-to-reproduce issues. 

#### Understanding the flow
When starting a transient-launch transition, there are several possible outcomes:
1) The transition finishes as normal: The user is committing the transition to the state requested
   at the start of the transition.  In such cases, you can simply finish the transition and the
   states of the transiently shown/hidden activities will be updated to match the original state
   that a non-transient transition would have (ie. closing activities will be stopped).

2) The transition is interrupted: A change in the system results in the window hierarchy changing
   in a way which may or may not affect the transient-launch activity.  eg. We transiently-launch
   home from app A, but then app B launches.  In this case, WM attempts to create a new transition
   reflecting the window hierarchy changes (ie. if B occludes Home in the above example, then the
   transition will have Home TO_BACK, and B TO_FRONT).

   At this point, the transition handler can choose to merge the incoming transition or not (to
   queue it after this current transition).  Take note of the next section for concerns re. bookend
   transitions.

3) The transition is canceled: The user is canceling the transition to the previous state.  In such
   cases, you need to store the `WindowContainerToken` for the task associated with the 
   transient-launch activity, and restore the transient order via the `WindowContainerTransaction`
   API above.  In some cases, if anything has been reordered since (ie. due to other merged 
   transitions), then you may also want to use `WindowContainerTransaction#reorder()` to place all
   the relevant containers to their original order (provided via the change-order in the initial
   launch transition).

#### Finishing the transient-launch transition
When restoring the transient order in the 3rd flow above, it is recommended to do it in a new 
transition and <span style="color:orange">**not**</span> via the WindowContainerTransaction in 
`TransitionFinishCallback#onTransitionFinished()` provided when starting the transition.

Changes to the window hierarchy via the finish transaction are not applied in sync with other 
transitions that are collecting and applying, and are also not observable in Shell in any way.
Starting a new transition instead ensures both.  (The finish transaction can still be used if there
are non-transition affecting properties (ie. container properties) that need to be updated as a part
of finishing the transient-launch transition).

So the general idea is when restoring is:

1) Start transient-launch transition START_T
2) ...
3) All done, start bookend transition END_T
4) Handler receives END_T, merges it and then finishes START_T

In practice it's not quite that simple, due to the ordering of transitions and extra care must be
taken when using a new transition to prevent deadlocking when merging transitions.

When a new transition arrives while a transient-launch transition is playing, the handler can
choose to handle/merge the transition into the ongoing one, or skip merging to queue it up to be
played after.  In the above flow, we can see how this might result in a deadlock:

Queueing END during merge:
1) Start transient-launch transition START_T
2) ...
3) Incoming transition OTHER_T, choose to cancel START_T -> start bookend transition END_T, but don't merge OTHER_T
3) Waiting for END_T... <span style="color:red">Deadlock!</span>

Interrupt while pending END:
1) Start transient-launch transition START_T
2) ...
3) All done, start bookend transition END_T
3) Incoming transition OTHER_T occurs before END_T, but don't merge OTHER_T
3) Waiting for END_T... <span style="color:red">Deadlock!</span>

This means that when using transient-launch transitions with a bookend transition
<span style="color:orange">requires</span> you to handle any incoming transitions if the bookend is 
ever queued (or already posted) after it.  You can do so by preempting the bookend transition
(finishing the transient-launch transition), or handling the merge of the new transition (so it 
doesn't queue).

#### Finish-transactions with bookend transitions
Another thing to keep in mind when using bookend transitions is the ordering of the finish \
transactions.  In particular, if cleanup of tasks is necessary, then you need to ensure that the
cleanup happens on the bookend's finish transaction and not the finish transaction provided when
starting the animation, otherwise properties on the tasks in the transition could be overwritten by
the default finish transaction created by Core (see `Transition#buildFinishTransaction()`).

ie.
1) Start START (Core builds finishT1 to reset state)
2) Start BOOKEND (Core builds finishT2 to reset state)
3) Merge BOOKEND into START
4) <<< Finish transaction properties should be updated here and not before 2)
5) Finish BOOKEND (Shell transitions applies finishT1 then finishT2 in order)

---

### Wmshell Src Com Android Wm Shell Docs Patterns TEMPLATE (`wmshell/src/com/android/wm/shell/docs/patterns/TEMPLATE.md`)

# Pattern (one line description)

### What this pattern solves

Give detailed information about the problem that this pattern addresses, include when it
should/should not be used.

### How it works

Give a high level overview of how this pattern works technically with sufficient links for the
relevant dependencies for folks to read more.

### Code examples

Explain how this pattern is used in code.

File.kt:
```kotlin
fun someFunction() {
    // Use this code
}
```

### Relevant links

Add relevant links to other files that implement this pattern, design docs, or other important
info.

Link 1: [More info](some_example_link) \
Link 2: [More info](some_example_link)

---

--- METRICS ---
- Files Extracted: 12
- Estimated Token Budget: ~11973 tokens
- Canonical Reference: https://codewiki.google/github.com/LawnchairLauncher/lawnchair
