To customize system bars, use a combination of XML configurations and Dagger modules to the UI components.
Define system bar behavior
To define a system bar, use the <SystemBar> tag in an XML file to define the
appearance and animation. This XML file is part of a runtime resource overlay
(RRO).
SystemBar tag attributes
The root element for a system bar configuration is <SystemBar>, which supports
these attributes:
| Attribute | Status | Description |
|---|---|---|
id |
Required | Unique resource ID for the system bar. For example,
@id/my_custom_status_bar |
type |
Required | Specifies the type of system bar, which is either
status or navigation |
barZOrder |
Required | Integer to represent the Z-order of the system bar. Higher values indicate the system draws the bar on top of others. Must be a positive integer. These rules apply:
|
defaultVariant |
Required | ID of the <Variant> that applies by default when
the system bar is initialized |
displayId |
Optional | ID of the <Variant> that applies by default when
the system bar is initialized |
hideForKeyboard |
Optional |
Boolean value of When this attribute is |
dragOpenNotification |
Optional |
Boolean value of |
dragCloseNotification |
Optional |
Boolean value of |
System bar IDs and types
Avoid using TopCarSystemBar, BottomCarSystemBar, LeftCarSystemBar, and
RightCarSystemBar as id values. The system reserves these IDs for backward
compatibility, and their use might lead to unexpected behavior.
For basic top status bar and bottom navigation bar configurations, use status
and nav, respectively, as the type attribute values.
If you use these IDs, you can skip the section entitled Provide a system bar UI with Dagger.
<Variant>- Defines visual states. To learn more, see Use a variant to
design a visual state. In the
<SystemBar>tag, define one or more<Variant>tags. Each variant represents a distinct visual state and contains properties that control the appearance of the system bar in that state. <Visibility isVisible="true|false">- Controls the visibility of the system bar. The
isVisibleboolean signals whether the system bar is visible or not. <Alpha alpha="float_value">- Controls the transparency of the system bar. The value for
alphafloats between0.0(fully transparent) and1.0(fully opaque). <Bounds .../>Defines the position and size of the system bar. For
<SystemBar>elements, the bounds must touch at least one edge of the display (left, top, right, or bottom). Attributes are:left,top,right,bottom: Absolute coordinates.width,height: Dimensions.leftOffset,topOffset,rightOffset,bottomOffset: Offsets towards center of the rectangle.
<Corner radius="dimen"/>Defines the corner radius of the system bar. For
radius, enter the dimension of the corner radius.<Insets .../>Defines insets for the system bar. Attributes are
left,top,right, andbottom. For each attribute, enter a dimension value for the insets.<Gravity .../>Defines the gravity of the system bar's content. To learn more, see
HunTagXmlParserKt.GRAVITY_TAGin the source code.- When you omit a value for gravity, the system calculates it internally.
- Supported values are combinations of
TOP,BOTTOM,LEFT,RIGHT,CENTER,CENTER_HORIZONTAL,CENTER_VERTICAL, andFILL_HORIZONTAL, each separated by a|character.
Dimension units
Specify dimensions with px, dp (or dip), %, or references to
dimension, integer, fraction, string, or attribute resources.
Transitions: Animate between variants
To learn more, see Configure a transition. Use the <Transitions> block to
define how the system bar animates between different variants:
| Item | Tag attribute |
|---|---|
<Transition> |
fromVariant, toVariant, onEvent, onEventTokens, animator, duration, delay, interpolator |
<Transitions> |
defaultDuration, defaultInterpolator |
Scalable UI supports transitions in system bars only when you define them for non-immersive mode use cases. This means that immersive mode doesn't trigger Scalable UI windowing transitions for system bars when it hides (or shows) a system bar.
Scalable UI continues to send events for hiding (or showing) a system bar so
that other panels can respond as needed while transitions for hiding and showing
system bars must be provided for proper functioning of the hideForKeyboard
attribute. Consider this sample XML structure:
<SystemBar id="@id/my_custom_status_bar" type="status" barZOrder="0" defaultVariant="@id/default_variant" hideForKeyboard="true">
<Variant id="@+id/default_variant">
<Bounds top="0px" left="0px" right="100%" height="100px"/>
<Visibility isVisible="true"/>
</Variant>
<Variant id="@+id/hidden_variant" parent="@id/default_variant">
<Visibility isVisible="false"/>
</Variant>
<Transitions>
<Transition onEvent="_System_Show_Panel" onEventTokens="panelId= my_custom_status_bar" toVariant="@id/default_variant"/>
<Transition onEvent="_System_Hide_Panel" onEventTokens="panelId= my_custom_status_bar" toVariant="@id/hidden_variant"/>
</Transitions>
</SystemBar>
Provide a system bar UI with Dagger
After you define the system bar in XML, provide the actual View and Window.
To do so, apply an application override to the default Dagger module,
CarSystemBarModule.java. For example:
import com.android.systemui.car.systembar.CarSystemBarViewSupplier;
import com.android.systemui.car.systembar.CarSystemBarWindowSupplier;
import com.android.systemui.car.systembar.CarSystemBarWindowSupplierUsingLayout;
import com.example.R;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
@Module
public abstract class MySystemBarModule extends CarSystemBarModule {
@Provides
@IntoMap
@StringKey("my_custom_status_bar") // Matches the <SystemBar> id
static CarSystemBarViewSupplier bindMyCustomStatusBarViewSupplier() {
return new CarSystemBarViewSupplierUsingLayout(
R.layout.my_custom_status_bar, // provisioned layout
R.layout.my_custom_status_bar_unprovisioned // unprovisioned layout
);
}
@Provides
@IntoMap
@StringKey("my_custom_status_bar") // Matches the <SystemBar> id
static CarSystemBarWindowSupplier bindMyCustomStatusBarWindowSupplier() {
return new CarSystemBarWindowSupplierUsingLayout(
R.layout.my_navigation_bar_window, // Can reuse existing window layouts
R.id.my_custom_bar_window // The ID that will be assigned to the window
);
}
}
Create a Dagger module in a SystemUI override
To inflate your custom layout resources, use the
CarSystemBarViewSupplierUsingLayout and
CarSystemBarWindowSupplierUsingLayout classes.
Create a Dagger module to provide your custom suppliers. The @StringKey must
match the id in your <SystemBar> XML tag.
To override CarSystemBarModule, see this code sample:
import com.android.systemui.car.systembar.CarSystemBarViewSupplier;
import com.android.systemui.car.systembar.CarSystemBarWindowSupplier;
import com.android.systemui.car.systembar.CarSystemBarWindowSupplierUsingLayout;
import com.example.R;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
@Module
public abstract class MySystemBarModule extends CarSystemBarModule {
@Provides
@IntoMap
@StringKey("my_custom_status_bar") // Matches the <SystemBar> id
static CarSystemBarViewSupplier bindMyCustomStatusBarViewSupplier() {
return new CarSystemBarViewSupplierUsingLayout(
R.layout.my_custom_status_bar, // provisioned layout
R.layout.my_custom_status_bar_unprovisioned // unprovisioned layout
);
}
@Provides
@IntoMap
@StringKey("my_custom_status_bar") // Matches the <SystemBar> id
static CarSystemBarWindowSupplier bindMyCustomStatusBarWindowSupplier() {
return new CarSystemBarWindowSupplierUsingLayout(
R.layout.my_navigation_bar_window, // Can reuse existing window layouts
R.id.my_custom_bar_window // The ID that will be assigned to the window
);
}
}
Use an RRO to create a system-level configuration
Set several system-level configurations that affect system bars in the
res/values/config.xml file in your RRO.
Disable legacy system bars
To prevent conflicts with Scalable UI, disable the legacy system bar
configurations by setting the following flags to false:
<resources>
<bool name="config_enableTopSystemBar">false</bool>
<bool name="config_enableBottomSystemBar">false</bool>
<bool name="config_enableLeftSystemBar">false</bool>
<bool name="config_enableRightSystemBar">false</bool>
</resources>
Privacy indicator location
The config_privacyIndicatorLocation string resource specifies which system bar
hosts privacy indicators. The value must be the id name of a <SystemBar>.
<resources>
<!-- "my_custom_status_bar" corresponds to the android:id name of a SystemBar -->
<string name="config_privacyIndicatorLocation">my_custom_status_bar</string>
</resources>
Drag event listeners
These configurations specify which system bars listen for drag events (for example, to swipe down to open the notification panel). Starting in Android Automotive OS with Scalable UI, use XML attributes as the default instead of instead of driven discovery resource arrays to define these capabilities.
Recommended: XML-driven discovery (Scalable UI)
Use the dragOpenNotification and dragCloseNotification attributes directly
in your <SystemBar> tag inside your overlay XML:
<SystemBar id="@id/my_custom_status_bar" type="status" barZOrder="0" defaultVariant="@id/default_variant" dragOpenNotification="true">
<Variant id="@+id/default_variant">
<Bounds top="0px" left="0px" right="100%" height="100px"/>
<Visibility isVisible="true"/>
</Variant>
</SystemBar>
Legacy: Resource array (fallback)
If you're maintaining a non-Scalable UI build or need to specify listeners for
backward-compatible devices, use the legacy string-array approach in
res/values/config.xml in your RRO. These string-array resources specify
which system bars listen for drag events. For example, to open the notification
panel. Each <item> is the id name of a system bar.
config_registerHvacDragCloseListenerconfig_notificationDragOpenListenerconfig_notificationDragCloseListener
For example:
<resources>
<string-array name="config_notificationDragOpenListener" translatable="false">
<item>my_custom_status_bar</item>
</string-array>
</resources>
Build and deploy
To build and deploy a status bar:
Flash the device with your modified SystemUI override application.
Use the Android build system (
m) to compile your RRO project.Deploy the generated RRO APK to your Android Automotive device. Use
adb installor flash a full build that includes your RRO.