Theming and Customization

Last edit: 2023.07.27

Introduction

TomTom Digital Cockpit supports theming of the UI. This enables IVI systems built on top of TomTom Digital Cockpit to have a customized look and feel which is aligned with the branding, make or model of the vehicle and which is consistent across the entire system. It also allows the system to support runtime theme switching, enabling the possibility of allowing the end-user to change the look of their UI while they are using their IVI system.

A theme is composed of styles which are divided into theme categories. Each category focuses on an aspect of the visual user interface such as colors or spacing between UI components. This page describes how to add themable UI controls and the theming system in detail.

How to Implement a Themable UI

TomTom's Digital Cockpit's theming mechanism makes use of Android's stylable XML attributes and Android styles. The rest of this guide assumes a basic understanding of these concepts.

A theme is divided into theme categories, each of which consists of a list of Android XML attributes which can be used to set the styling of a specific aspect of the UI, such as the color of some text. When implementing the UI, the developer can select attributes from the appropriate category instead of hardcoding a value into their layout XML.

Examples of the built-in theme categories include:

  • TtThemeCategoryColors contains the possible common theme colors. This can be used to ensure similar parts of the UI such as the backgrounds of all panels of a certain type are the same color.
  • TtThemeCategoryDimensSpacing contains the common spacing values in the theme. This can be used to ensure that all of the margin and padding values around similar UI controls such as the padding inside OK buttons is always the same.
  • TtThemeCategoryDimensTextSize contains the common text sizes in the theme. This can be used to ensure that for example, all titles have the same size.

For example, inside TtThemeCategoryColors, there is

1...
2<!-- Used inside UI elements which require the most attention. -->
3<attr name="tt_surface_content_color_emphasis_high" format="color" />
4...
5<!-- Used to indicate something is wrong. E.g., an error message in a text field. -->
6<attr name="tt_surface_content_color_critical" format="color" />

As described by its documentation, the tt_surface_content_color_emphasis_high attribute should be used when styling a UI content whose color should indicate to the user that it is important. This attribute can be used as the value of android:textColor when styling a TtTextView. More detailed information on how colors are organized in the theming system is available in the Color System section.

For example, if we were adding an important title to the UI, this attribute could be used to set the text color:

1<com.tomtom.tools.android.api.uicontrols.textview.TtTextView
2 android:id="@+id/importantTitle"
3 android:layout_width="wrap_content"
4 android:layout_height="wrap_content"
5 android:text="Important Title"
6 android:textAppearance="?attr/tt_display_text_style_l"
7 android:textColor="?attr/tt_surface_content_color_emphasis_high" />

Alternatively, to style multiple buttons in the same way, the attribute can be used in an Android style:

1<style name="ImportantTextViewStyle">
2 <item name="android:textColor">?attr/tt_surface_content_color_emphasis_high</item>
3</style>
4
5<style name="ImportantButtonStyle">
6 <item name="android:textColor">?attr/tt_surface_content_color_emphasis_high</item>
7</style>

The use of these attributes is core to ensuring that the entire UI of the IVI system is consistent and changes consistently when the end-user changes the UI theme at runtime.

To change the actual values of these attributes (and hence the look of the UI), see the section Customizing the Built-In Themes

TomTom Digital Cockpit also provides a UI controls library consisting of a number of UI controls that extend what is available by default in Android. These also help with producing a themable UI and it is advised to use them where possible.

Theme Attribute Naming Convention

The built-in Digital Cockpit themes are made up of a large number of styleable XML attributes. These theme attributes follow a naming convention which help inform the developer of where they should be used. The naming convention of theme attributes follows the prefix_what_where_which_quality_quantity format. Taking color attributes as an example, the attribute names consist of:

  • prefix for all attributes defined in core_theme this is tt. The prefix for TomTom Digital Cockpit specific component attributes, which are defined in platform_theming_api_common_attributes is ttivi.
  • what determines the background color.
  • where determines the place where it is used. Optional.
  • which for all color attributes is color.
  • quality represents the type of emphasis. Optional.
  • quantity determines the level of emphasis. Optional.

In the Color System section we'll explain how TomTom Digital Cockpit classifies background colors and emphasis, among other things, to achieve a coherent UI design.

Some examples for color attributes are:

PrefixWhatWhereWhichQualityQuantity
tt_primary_color
tt_primary_content_color_emphasis_high
tt_primary_content_color_emphasis_medium
tt_primary_content_color_emphasis_low
tt_primary_content_color_subdued
tt_primary_content_color_highlight
ttivi_mainmenu_content_color_emphasis_high

Note: All attributes defined within the same prefix_what_where_... are called a group.

Global tokens

Most theme attributes refer to a very specific aspect of the UI such as the color of the content in a panel. However, some of the attributes in a theme have more of a global scope and refer to a general part of the UI. These attributes are referred to as global tokens or global attributes.

For certain global attributes the naming convention is based on a baseline value. The baseline value is specified as the suffix of the attribute name, for example, it is the _1 in tt_size_1.

The naming convention is composed of the following parts:

  • Prefix for all attributes defined in core_theme is _tt_.
  • Category represents the global category.
  • Scale indicates the factor that the baseline value should be multiplied by to get to the final value. When the baseline value for the radius tt_radius_1 is 4dp, the tt_radius_23 is therefore 4 * 23 = 92dp.

The common naming convention is applied for the following categories in the built-in themes:

PrefixCategoryScaleExample
tt_size_1tt_size_1
tt_spacing_0.5tt_spacing_0.5
tt_radius_23tt_radius_23
tt_icon_size_2tt_icon_size_2

Customizing the Built-In Themes

TomTom Digital Cockpit comes with some pre-defined themes including a dark and a light theme. The theme can be customized by deriving a new theme from the existing one and overriding the existing values of these attributes in the new theme.

For example, to create new light and dark themes which are based on the build-in TomTom Digital Cockpit themes, the following XML can be used:

1<resources>
2 <style name="MyProductLightTheme" parent="TtiviThemeColorLight">
3 <!-- Define a new high emphasis content color for the light theme -->
4 <item name="tt_surface_content_color_emphasis_high">@color/product_palette_blue</item>
5 </style>
6
7 <style name="MyProductDarkTheme" parent="TtiviThemeColorDark">
8 <!-- Define a new high emphasis content color for the dark theme -->
9 <item name="tt_surface_content_color_emphasis_high">@color/product_palette_red</item>
10 </style>

All UI controls which use these attributes will get the defined value when the theme is changed.

The Theming System

TomTom Digital Cockpit's theming mechanism is heavily based on Android's theming approach, while additionally providing a means to switch themes at runtime through a service. The Android styles within the theme are applied to the context of the system UI. All the fragments hosted in the system UI will get that context with the correct styles applied. Similarly, when a theme changes at run-time, like when switching between light and dark mode themes, all views are created with a new context that has the new styles applied.

The theme is provided by the ThemingService. This service is responsible for deciding which theme should be used by the system UI. It loads the styles that themes can use from all discoverable ThemeComponentProviderService instances. (You can read more on discoverable services in the documentation on IviDiscoverableServiceIdProvider.) You can add your own instances, or replace the default one with custom instances that provide alternative styles.

Note: The ThemingService works with IviThemes, which are explained in detail in the Customization section.

The styles must provide values for all attributes within their respective categories. Failing to do so will result in unexpected behavior as the views are missing some of their attributes. The available attributes are defined within the platform_theming_api_common_attributes and core_theme modules.

The core_theme is a TomTomAndroidTools module which defines common theme attributes that can be used in various projects. The platform_theming_api_common_attributes module, which extends core_theme, also defines extra theme attributes for TomTom Digital Cockpit. You can customize the visual appearance of your product by providing the desired values of these attributes.

Theming high-level diagram

If you want a look based on the TomTom UX design specification, you can use the platform_theming_api_stock_theme. This theme supports a light and a dark mode. The dark mode is the default one for TomTom Digital Cockpit.

If you want a customized theme, you must add your own ThemeComponentProviderService to provide the extra styles for the ThemingService to discover. In that implementation you can override the values of the platform_theming_api_stock_theme to suit your look, or replace the platform_theming_api_stock_theme entirely.

Theming Design Concepts

Theme Categories

The appearance of the UI is determined by colors, margins, font types, etc. A theme is divided into categories for each of these aspects of the UI. To reduce duplication when creating a new theme and to be able to apply styles independently, these attributes are defined in categories like color, spacing, and font. Each category represents a set of attributes for the theme.

By having categories of theming attributes, you can create a slightly different theme based on any other theme. For example, you can create a new look by keeping all categories unchanged, except the color category. This way you do not need to duplicate all the attributes, but only attributes that you want to change.

The theme attributes are defined using the standard Android declare-styleable. Some examples of how categories are defined, and which categories attributes belong to, are:

1<!-- attrs_dimens_spacing.xml -->
2<resources>
3 <declare-styleable name="TtiviThemeCategoryDimensSpacing">
4 <attr name="tt_spacing_1" format="dimension" />
5 <attr name="tt_spacing_2" format="dimension" />
6 <attr name="tt_spacing_3" format="dimension" />
7 </declare-styleable>
8</resources>
9
10<!-- attrs.xml -->
11<resources>
12 <declare-styleable name="TtiviThemeCategoryStyles">
13 <attr name="ttivi_navigation_search_input_text_appearance_style" format="reference" />
14 </declare-styleable>
15</resources>
16
17<!-- attrs_colors.xml -->
18<resources>
19 <declare-styleable name="TtiviThemeCategoryColors">
20 <attr name="tt_surface_content_color_emphasis_high" format="color" />
21 </declare-styleable>
22</resources>

Color System

The color system helps you to apply colors to your UI, including your brand colors. Colors provide a hierarchy of information, give the correct meaning to UI elements, and meet legibility and contrast standards.

The TomTom Digital Cockpit color system is designed with a focus on: hierarchy, background colors, content colors, and emphasis.

Hierarchy

UI colors are based on the role they play in the interface. For example, the color of the surface will determine if the UI as a whole is light or dark.

By defining which colors can go on top of each other, you can ensure enough contrast to distinguish UI elements.

Background Colors

Background colors

The background colors are classified into:

  • Surface colors that affect the background of the components. The surface is the background of all panels, notifications, the process panel, etc.
  • Primary colors that are used for primary actions like primary buttons.
  • Secondary colors that are used for secondary actions like secondary buttons, the background of segmented controls, etc.
  • Destructive and acceptance colors that are used for events that require immediate action or a decision of the user.
  • Overlay color that is used for components that come on top of the surfaces such as overlays, pop-overs, etc.
  • Main menu colors that are used for the active app icon, inactive icons, labels, and the background of the main menu.
  • Control center colors that are used for elements in the control bar, and the background and system icons on top of it.

Content Colors

Content colors

Content colors refer to the color of elements that are displayed on top of the background colors. Whenever UI elements such as texts or icons appear on top of these colors, they will have a different emphasis to create an order between them.

If there is selected content on the surface like a toggle button, then that selected state is part of a content color group.

Emphasis

Emphasis Emphasis alert

A UI consists of many components. The fewer components, the easier it will be to understand what is being communicated. However, sometimes it cannot be avoided to have more components and then emphasis is used to make some of them stand out and become the focus of the user.

For important information and actions, a high emphasis color should be used. This prevents distractions from less important components in the UI, like a separation line. Those less important components could use a low emphasis color instead.

Emphasis is classified into:

  • High emphasis which commands the most attention. High emphasis components may be accompanied by medium and low emphasis components that perform a less important role.
  • Subdued state which is advised for a component that is not interactive, and as such should be de-emphasized. For example: dividers.
  • Highlight state which communicates when a user has highlighted a component. It is usually combined with another, usually primary color. For example: a focused search view.
  • Accent color which is used to indicate that some action is needed from the user, usually in combination with a highlight color. For example: an active state in a search view.
  • Critical and success states which indicate errors and successful actions. For example: an invalid text in a text field.
  • Alert, warning and caution which are used to raise the user’s attention. For example: a traffic warning on the planned route.

Customization

Here we'll dive deeper into the way you can customize your product using the tools that theming provides.

An IviThemeComponent contains the necessary style information and it belongs to a single IviThemeCategory. The theme component styles are defined as Android style resources. For example, a Noto Sans font style is defined as:

1<resources>
2 <style name="TtiviThemeFontNotoSans">
3 <item name="tt_font_thin">@font/noto_sans_regular</item>
4 <item name="tt_font_medium">@font/noto_sans_semi_bold</item>
5 <item name="tt_font_bold">@font/noto_sans_bold</item>
6 </style>
7</resource>

A theme category, like color or font, is represented by an IviThemeCategory. They may contain multiple IviThemeComponents. For example, a font IviThemeCategory can have several font IviThemeComponents, each for a different font.

An IviTheme is a collection of IviThemeComponents.

A TtiviThemeCategoryPreset is a pre-defined set of IviThemeCategorys.

An IviTheme must contain at least one IviThemeComponent for each IviThemeCategory listed in the TtiviThemeCategoryPreset. The ThemingService has the responsibility to check this.

Customization class diagram

First you need to define styleable attributes for a category. Next you can define a style for it, which will be used by an IviThemeComponent later.

Let's use an example to demonstrate the creation of a custom theme. TomTom Digital Cockpit extends color attributes like tt_surface_content_color_emphasis_high which are defined in stock_theme. It is defined like this:

1<resources>
2 <declare-styleable name="TtThemeCategoryColors">
3 <attr name="tt_surface_content_color_emphasis_high" format="color" />
4 </declare-styleable>
5</resources>

And there is a default value for that color attribute in stock_theme as well:

1<resources>
2 <style name="TtThemeColorLight">
3 <item name="tt_surface_content_color_emphasis_high">#2E3841</item>
4 </style>
5</resources>

The TomTom Digital Cockpit style TtiviThemeColorStock inherits from the style TtThemeColorLight and there you can define the value you want for your theme:

1<resources>
2 <style name="TtiviThemeColorStock" parent="TtThemeColorLight">
3 <item name="tt_surface_content_color_emphasis_high">#A7B290</item>
4 </style>
5</resources>

Note: You can have multiple styles for the same theme category. For example, it is common to provide light and dark modes as user options. So you can define a light and a dark color theme, and let the user choose.

You can define a different value for the same attribute in another theme:

1<resources>
2 <style name="TtiviThemeColorDark" parent="TtThemeColorDark">
3 <item name="tt_surface_content_color_emphasis_high">#FFFFFF</item>
4 </style>
5</resources>

In code, the color category is defined as:

1enum class TtiviThemeCategoryPreset(val category: IviThemeCategory) {
2 COLOR(IviThemeCategory("COLOR", StaticStringResolver("Color")))
3}

Then the corresponding IviThemeComponents are created and provided by a ThemeComponentProviderService:

1class StockThemeComponentProviderService(
2 iviServiceHostContext: IviServiceHostContext,
3 serviceIdProvider: IviDiscoverableServiceIdProvider,
4) : ThemeComponentProviderServiceBase(iviServiceHostContext, serviceIdProvider) {
5
6 init {
7 availableThemeComponents = listOf(
8 with(TtiviThemeCategoryPreset.COLOR) {
9 IviThemeComponent("Id", category, R.style.TtiviThemeColorStock, "Stock")
10 },
11 // Adding additional theme category flavors.
12 with(TtiviThemeCategoryPreset.COLOR) {
13 "Dark".let {
14 IviThemeComponent("Id", category, R.style.TtiviThemeColorDark, it)
15 }
16 }
17 )
18 }
19}

Finally an IviTheme is created from the ThemeComponentProviderService:

1class StockThemingService(iviServiceHostContext: IviServiceHostContext) :
2 ThemingServiceBase(iviServiceHostContext) {
3 override fun onCreate() {
4 super.onCreate()
5 activeTheme = IviTheme(themeComponentProviderService.availableThemeComponents)
6 }
7}

If you want to slightly change the look, then you can change individual attribute values. If you need to change the look dramatically, then you can create your own theme categories and attributes and provide your own ThemeComponentProviderService to the ThemeService.