Use the Configuration Framework
Important note:The TomTom Digital Cockpit SDK is not available for general use. Please contact us for more information.
TomTom Digital Cockpit supports customization on many levels, from configuration of functional features to theming of the user interface. One form of customization is achieved through the use of the TomTom Digital Cockpit configuration framework which can be used to specify, for example, API keys or configuration feature flags to toggle features on or off and other values that a component in the IVI system can use to configure itself at runtime.
A component such as an IVI service can use the configuration framework to define a configuration. A configuration may be either static or dynamic.
Static configurations are loaded once at startup and have constant values that do not change at runtime. This type of configuration is suitable for specifying, for example: URLs, authentication keys, or certificates.
Dynamic configurations can change at runtime. They start off with initial values (factory defaults) and their values can change while the system is running. For example, they can store user preferences which the user can set to a different value while using the system. Dynamic configurations keep hold of the full history of default values. This allows an existing setting value to be updated from any previous version to the latest suitable value in a compatible way.
Every module may use static configurations directly via a static configuration provider, or access settings via settings services. Dynamic configurations can only be used by settings services.
This document describes how to create static and dynamic configurations using the configuration generator and how to use these configurations in the application.
Overview of the example application
The example application adds the account frontend to the default TomTom Digital Cockpit application. The
account frontend adds new panels to show account information or a login page, which can be invoked
by a menu item. The account status is managed by the accounts service. When the user is
authenticated, the user name is stored in persistent storage by the accounts settings service, so
the user does not need to log in again after a restart of the application.
The source code for the frontend and service can be found in the
examples/plugin
directory. See also
Create an IVI service
and the @IviService
annotation.
To demonstrate usage of different configurations, the accounts service will use a static configuration to get the URL of the online API endpoint to authenticate the user. The login will be stored for a limited time. The accounts settings service will provide the time, as specified by a dynamic configuration. For that, you need to perform the following steps:
- Create configuration files.
- Enable the configuration generator.
- Access the configurations via configuration providers.
Create configuration files
Static and dynamic configurations are defined in JSON files located in the configurations/static
and configurations/dynamic
directories of the source set.
For example: <moduleRoot>/src/main/configurations/static
.
The JSON file schema is fully documented in the API reference documentation of
IviConfigurationGeneratorConfig
.
Static configuration file
To create a static configuration for the accounts service, create a JSON file in the
configurations/static
directory:
examples/plugin/service/src/main/configurations/static/com.example.ivi.example.plugin.service.json
1{2 "packageName": "com.example.ivi.example.plugin.service",3 "keys": [4 {5 "name": "onlineAccountEndpointConfigKey",6 "description": "The URI of the endpoint of the online account API",7 "type": "String",8 "value": "https://www.example.com/account/"9 }10 ]11}
This file defines a string configuration item with a key "onlineAccountEndpointConfigKey"
that
belongs to the package com.example.ivi.example.plugin.service
.
The configuration contains the URL of the online API endpoint, as specified by the "value"
field.
Note: The "name"
field must have a ConfigKey
suffix, and be suitable for use as a
Kotlin property name.
Note: The "description"
field is optional. It is used as KDoc for the generated configuration
keys.
Dynamic configuration file
To create a dynamic configuration for the accounts settings service, create a JSON file in the
configurations/dynamic
directory:
1{2 "version": 2,3 "packageName": "com.example.ivi.example.plugin.service",4 "keys": [5 {6 "name": "onlineLoginValidPeriodInDaysConfigKey",7 "description": "Number of days that an online login stays valid.",8 "type": "Long",9 "values": [10 {11 "value": 1,12 "fromVersion": 1,13 "updateStrategy": "always"14 },15 {16 "value": 30,17 "fromVersion": 2,18 "updateStrategy": "always"19 }20 ]21 }22 ]23}
This file defines a long number configuration with an
"onlineLoginValidPeriodInDaysConfigKey"
key that belongs to the package
com.example.ivi.example.plugin.service
.
Note: The "name"
field must have a ConfigKey
suffix, and be suitable for use as a
Kotlin property name.
Note: The "description"
field is optional. It is used as KDoc for the generated configuration
keys.
The "version"
field specifies the revision number of the configuration file. It must be increased
with any change to the configuration. The configuration keeps values for previous versions. These
are used for updating old values in the device's persistent storage to the current version.
The configuration version is 2
, so the current value is 30
. The "updateStrategy"
field
defines how old values are updated. In the example, it defines that old values are overridden with
the new values. See the API reference documentation for
ConfigurationUpdateStrategy
.
The latest configuration version will be stored on the device, and will remain unchanged until a
configuration file with a newer version is loaded.
Enable the configuration generator
The configuration JSON files are suitable for human editing but not yet ready to be used in the application. To make the configurations available in the application, they need to be processed by the configuration generator.
The configuration generator looks for JSON files and processes them into:
- Kotlin source files with configuration keys that can be used by the application. Generated keys
are wrapped into
StaticConfigurationKey
orDynamicConfigurationKey
objects. - Resource files with static configuration values.
- Android asset files with dynamic configuration values.
To enable the configuration generator, add following Gradle configuration into Gradle build
configurations of modules that contains the configuration.
For the given example, these are the accounts service module
examples/plugin/service/build.gradle.kts
and the accounts settings service module
examples/plugin/settingsservice/build.gradle.kts
:
1ivi {2 configurationGenerator {3 enabled = true4 }5 // The configuration framework is an experimental feature, and has to be explicitly opted in.6 optInToExperimentalApis = true7}
Use the menu item of Android Studio to run the configuration generator for the current project: navigate to Build > Run Generate Sources Gradle Tasks.
Note: The configuration generation tasks are variant specific and also are a dependency of the
respective variant specific AGP task, so they are executed automatically during
assemble<BuildVariant>
or build
tasks. For example, you can run these Gradle tasks to get the
configuration generator to process the input files:
1# Either generate configurations for all projects.2./gradlew generateDebugConfigurations34# Or generate configurations and assemble `Debug` variant for all projects.5./gradlew assembleDebug67# Or generate configurations for services projects only.8./gradlew examples_plugin_settingsservice:generateDebugConfigurations examples_plugin_service:generateDebugConfigurations910# Or generate configurations and assemble `Debug` variant for services projects only.11./gradlew examples_plugin_settingsservice:assembleDebug examples_plugin_service:assembleDebug
Access the configurations via configuration providers
Static configuration value
Static configurations are provided by the static configuration provider that is in the context of
IVI service IviServiceHostContext.staticConfigurationProvider
.
To get the configuration value of the StockAccountsService
, use the
StaticConfiguration.onlineAccountEndpointConfigKey
variable.
src/main/kotlin/com/example/ivi/example/plugin/service/StockAccountsService.kt
1import com.example.ivi.example.plugin.service.StaticConfiguration.onlineAccountEndpointConfigKey23class StockAccountsService(iviServiceHostContext: IviServiceHostContext) :4 AccountsServiceBase(iviServiceHostContext) {56 private val onlineAccountEndpoint =7 iviServiceHostContext.staticConfigurationProvider[onlineAccountEndpointConfigKey]8}
The onlineAccountEndpoint
is a string with the configuration value that is used during user log
in. The logIn
method calls logInOnline()
to authenticate the user. The latter does not make a
real network query but only does simple validation.
src/main/kotlin/com/example/ivi/example/plugin/service/StockAccountsService.kt
1private fun logInOnline(username: String, password: SensitiveString): Account? =2 takeIf { isValidUsername(username) && isValidPassword(password.value) }?.run {3 println("Pretend making an online request to '$onlineAccountEndpoint'.")4 Account(username)5 }
Dynamic configuration value
Dynamic configurations are used by settings services to initialize settings.
First, add a new setting onlineLoginValidPeriodInDays
to the accounts settings service that holds
the number of days the user may stay logged in.
src/main/kotlin/com/example/ivi/example/plugin/settingsserviceapi/AccountSettingsService.kt
1interface AccountSettingsService {2 @IviSetting(accessMode = IviSettingAccessMode.READ_ONLY)3 val onlineLoginValidPeriodInDays: Long4}
By default, the settings service initializes properties with values from dynamic configurations. The service implementation only needs to set the configuration key and the setting key. The latter can be easily made from the former.
src/main/kotlin/com/example/ivi/example/plugin/settingsservice/StockAccountSettingsService.kt
1// Both variables are generated by the configuration generator.2import com.example.ivi.example.plugin.service.DynamicConfiguration.settingKeyPrefix3import com.example.ivi.example.plugin.service.DynamicConfiguration.onlineLoginValidPeriodInDaysConfigKey45class StockAccountSettingsService(iviServiceHostContext: IviServiceHostContext) :6 AccountSettingsServiceBase(iviServiceHostContext) {78 // The `onlineLoginValidPeriodInDays` setting has default values provided by the dynamic9 // configuration key.10 // All methods for this setting have default implementation.11 override val onlineLoginValidPeriodInDaysConfigurationKey: LongDynamicConfigurationKey =12 onlineLoginValidPeriodInDaysConfigKey1314 // This key is used to load and store the setting value in the persistent storage on the device.15 override val onlineLoginValidPeriodInDaysSettingKey: LongSettingKey =16 onlineLoginValidPeriodInDaysConfigurationKey.toSettingKey(17 // The setting is application-wide, regardless of the currently selected user profile.18 SettingScope.APPLICATION,19 settingKeyPrefix20 )21}
Then the accounts service can use the onlineLoginValidPeriodInDays
settings to validate the
logged in account when it is needed.