Google released Android 12L to improve the Android feel and experience on foldables, tablets, Chrome OS devices and in general, large screens. This release comes at a time when large screens are growing in reach, thus increasing the need to scale app UI to support a wide range of screen sizes.
Android 12L introduced many improvements, from multitasking and split-screen features to UI optimization and polishing. It was also accompanied by developer tools and APIs to make building, designing and testing on large screens easier.
This post goes over
Activity embedding, an addition to Android 12L that brings support for multi-pane layouts in
Activity based apps. The post goes over how
Activity embedding impacts app behavior on both small and large aspects of screens, how to add support for it in your app, and how to configure it and control such as
Activity launch and back navigation.
The code samples used in this post can be found here.
Activity embedding was recently introduced in Jetpack WindowManager. It’s available for large screen devices with Android 12L. It brings support for multi-pane layouts to
Activity based apps, allowing developers to provide an improved user experience on large screens without significant refactoring/migration to
Fragments or Jetpack Compose.
Activity embedding splits the task window into 2 containers, a primary container and a secondary one. On large screens, primary and secondary
Activities are laid out side by side, whereas on small screens, secondary activities are stacked on top of primary ones. The system handles this behavior depending on the configuration the app defines.
Use Case: List/Details Pattern
The list/details pattern is commonly used in apps. On small screens, the list and details screens are each shown on their own. On large screens though, showing the list and details screens side by side can make better use of the available real estate on the screen and provide a better user experience.
Let’s assume we have an app where the list and details screens are defined in
DetailsActivity respectively. This is how they would look on small and large screens.
List/Details with Activity Embedding
Adding support for
Activity embedding in this app can be achieved in 3 simple steps.
- Add the
WindowManagerdependency to the app’s
Activityembedding was introduced in
version 1.0.0-beta03so make sure to use a version as recent as this one at minimum.
2. Create a configuration file in the folder
res/xml. In it, you’ll provide rules to define how and which
Activities should be split. The system will later use them to decide how to handle embedding them. The following is the minimum required configuration.
SplitController. This has to be done before the app loads and starts its
Activities. One option is to perform this initialization on app launch inside the
Application class, another is to use the Jetpack Startup library.
DetailsActivity will now be displayed side by side on large screens. On small screens though, the app will continue to behave the same, that is, when
DetailsActivity is launched, it is stacked on top of
Adding a Placeholder
Activity embedding provides a way to display a placeholder
Activity in the secondary container until there’s content to show in it. This is useful in the list/details use case for when the user hasn’t selected an item from the list yet.
Activity is only shown when there is enough space for a split. It stays displayed until there is content to show, in which case it is dismissed.
Setting a placeholder
DetailsPlaceholderActivity as a placeholder until a list item is selected is quite simple. Just define a rule for it in the split configuration file.
This results in a placeholder
Activity being displayed initially on large screens before an item from the list has been selected.
When navigating back using gesture navigation or the back button, the back event is sent to the focused
Activitythat is the
Activity that was last touched or last launched. The system then finishes it. By default, finishing all
Activities in one container results in the other container filling the entire space of the screen.
Activity embedding provides 2 options to control how
Activities in the primary and secondary container are finished.
finishPrimaryWithSecondary: When set to
truethe system finishes the
Activity in the primary container when all
Activities in the secondary container are finished. By default it’s set to
finishSecondaryWithPrimary: When set to
truethe system finishes
Activities in the secondary container when all
Activities in the primary container are finished. By default it’s set to
Going back to our example, we’d like
ListActivity to finish when
DetailsActivity finishes, and vice versa,
DetailsActivity should finish when
ListActivity finishes. This is achieved using the following configuration.
Testing this code on a large screen doesn’t result in the expected behavior though. This might be due to a bug in the library.
DetailsActivity is displayed in the secondary container. If it were to launch another
ShareActivitythe latter would be stacked at the top of this container.
Besides this default launch behavior,
Activity embedding provides the option to shift splits sideways when launching an
Activity from the secondary container. That means that
DetailsActivity would move to the primary container, and
ShareActivity would be launched in the secondary container.
To support this behavior, you need to define the corresponding split rule for
The above configuration specifies that
DetailsActivity should launch in the secondary container when it’s started by
ListActivityand should display in the primary container when it launches
ShareActivity. The system handles animation
DetailsActivity as it moves between containers.
Split Rule Configuration Options
Activity embedding provides a couple of options to configure split rules:
splitRatio: A float that defines the ratio of the primary container to the secondary container. By default it’s set to 0.5, meaning that each container occupies half the available screen width. It appears that this parameter is mandatory, failing to set it results in splits not working.
splitMinWidth: A dimension that defines the minimum window width to trigger a split. If the window width is smaller than this value,
Activities in the secondary container will be stacked on top of
Activities in the primary one. By default, it’s set to
splitMinSmallestWidth: similar to
splitMinWidthexcept that it takes into account both the window’s width and height.
clearTop: A boolean that defines whether to clear all
Activities in the secondary container when launching an
Activity in a split with the same primary container. By default, it’s set to
Listening to Split Events
Activity embedding provides an API to receive notifications about split changes, allowing the app to react to them.
A split listener is registered using
SplitController.addSplitListener(). This method takes an
Activity as an argument, which ensures the listener only receives updates about active splits the
Activity is part of. It also accepts an
Executor on which updates are received.
A split listener should be unregistered using
This split listener is a
Consumer that receives a list of
SplitInfo on each update, each including information about
Activities in the primary and secondary containers, as well as the split ratio.
A common scenario for using a split listener is to update the UI. An example is showing or hiding a
FloatingActionButton (FAB) depending on the state of the split. Using our list/details app, imagine the FAB is part of
ListActivity. On a large screen where
DetailsActivity are displayed side by side,
ListActivity should hide the FAB, whereas
DetailsActivity should show it. On small screens though,
ListActivity should be the one to show the FAB.
You can find the code for this example here in the code sample.
Activity embedding is supported on large screen devices running API levels 32 or higher. Some devices with earlier versions may support it though, this depends on the OEM and whether they retroactively add support for it.
When running on Android 12L, large screen emulators and the resizable emulator included in Android Studio Chipmunk also support
You can check if a device supports
Activity embedding or not at runtime as follows.
Activityembedding in your
Activitybased app to support multi-pane layouts, allowing your users to see/do/experience more on large screens by making use of the extra screen real estate.
- Provide a split configuration file that defines the split rules the system uses to handle embedding
Activitiesin your app.
- Define how embedded
Activitiesshould launch other
Activitiesand control how the system finishes them.
- Customize split rules by using the supported options which include
- Register a split listener to receive updates on active splits. Don’t forget to unregister it!
- Check for split support on devices at runtime using
Notes worth mentioning from testing:
Activityembedding only works if the split rule defines
finishSecondaryWithPrimaryseemingly has no effect on the finishing behavior of
Activitiesin the primary and secondary containers. (Potential bug)
Activitiesthat support embedding are run in a task that belongs to another app, then embedding will not work for them.
Want to learn more about
Activity embedding on Android? Check out: