Settings Framework

Last edit: 2024.01.02

The settings framework allows cross-application settings to be shared between TomTom Digital Cockpit services and frontends in TomTom Digital Cockpit. TomTom Digital Cockpit components can store them persistently and change their values.

Modules access settings via setting services that offer type-safe and domain-specific interfaces to the generic settings management service.

Overview

The settings framework consists of a settings management service, that provides a SettingsManagementService API to store setting values in the persistent key-value storage. It provides settings services that offer a type-safe and domain-specific interface to a settings management service.

The off-the-shelf or stock IVI frontends and IVI services use settings services to manage their settings.

Settings framework high-level overview image

Settings management service

The settings management service SettingsManagementService provides an API to store settings values in persistent key-value storage in a type-safe manner.

A client of a settings management service should create a setting before use. A client specifies:

  • An identifier IviServiceId of the service that owns the setting. Only the owning service can create the same setting multiple times, which may happen if the owning service has been restarted.
  • A unique setting key.
  • A default setting value.
  • An update strategy SettingUpdateStrategy that specifies what happens to the existing setting value.

The type of a setting key is a subtype of the SettingKey, and declares the type of a setting value. Available setting key subtypes are:

A setting key consists of a setting scope SettingScope and a setting identifier. The setting scope defines whether a setting has a value per user profile, see User Profiles for details regarding user profiles, or is relevant to the entire application, regardless of the active user profile, for more details regarding user profiles.

Note: If the settings management service restarts, then all settings must be created again by the settings service that owns them. The restart may be detected by observing the availability of the settings management service.

A client may get the current value of the created setting, or update the value, or reset the setting to the default value.

A settings management service publishes a session token that identifies the state of settings visible to clients. It changes when the settings have been modified by a settings management service, due to user profile switching, factory reset, or other reasons that are not caused by settings services. Clients must observe the session token and use it to modify settings.

See the API reference documentation for the SettingsManagementService interface.

Settings service

A settings service offers a type-safe and domain-specific interface to a settings management service.

A settings service is a special case of a IVI service that only has properties. Properties can be either read-only or writable. See the IviSetting annotation for details.

Properties of a settings service may be of any type supported by the IVI service framework, and are not mandatorily bound to settings. Thus a property may have a value merged from a few settings or several properties may use the same setting, or parts of it.

During initialization, a settings service creates all required settings, and reads stored setting values. If there is no stored value for a setting, then the default value of a setting is used.

A setting schema has a version that is defined by a settings service, and is stored persistently. A settings service reads the stored version before creating the setting. If the stored version differs from the current version, that is defined by the settings service, then the settings service must update the stored settings to the current scheme.

Initialization of a settings service

Using the Configuration framework, it is possible to further control the setting values and configure their default values.

For more information, see the following Settings service advanced configuration topic.

Settings service declaration

Like any IVI service, a settings service implements an IVI service interface; see IviService. The difference is that the interface only contains properties annotated with the @IviSetting annotation. Clients may access the service using the service API instance, created with <interface>.createApi().

Settings service implementation

The <Interface>Base class, generated from the settings service interface, inherits the IviSettingsServiceBase class, and contains methods to manage settings that may be overridden for specific cases.

For settings of types supported by the settings management API, that is, which can be passed to the API without transformation, the methods have a default-generating implementation. For such a setting, the implementation only has to define the configuration key and the setting key. These keys are used to load default values and update information from dynamic configurations, and to perform initialization of a setting.

Settings of other types require the implementation of a few methods.

The base class IviSettingsServiceBase calls the init<Property>() method, giving the version of a setting stored in persistent storage. If versions mismatch, the implementation of the method must manage the update from the given version to the latest, specified with the IviSettingsServiceBase.settingsVersion property.

The default implementation creates a setting, applying value entries of the dynamic configuration value consecutively. The value of the current version is written to persistent storage when all settings are initialized.

Note: By default, a setting service waits for a settings management service to become available to initialize settings. That behavior can be changed by overriding the IviSettingsServiceBase.initSettingsService() method.

Example

The declaration of a setting service interface.

1@IviService(
2 serviceId = "org.example.services.foo"
3)
4interface FooSettingsService {
5 /**
6 * The read-only setting of the type supported by the settings management API.
7 */
8 @IviSetting(accessMode = IviSettingAccessMode.READ_ONLY)
9 val foo: Int
10
11 /**
12 * The writable setting of the type not supported by the settings management API.
13 */
14 @IviSetting(accessMode = IviSettingAccessMode.READ_WRITE)
15 val bar: SomeParcelableClass
16 }

From the given interface, the IVI service framework generates an API class for service clients, and a base class for a service implementation.

1// Generated code.
2class FooSettingsServiceApi {
3 val serviceAvailable: LiveData<Boolean>
4
5 val foo: LiveData<Int>
6 val bar: LiveData<SomeParcelableClass>
7
8 fun updateBarAsync(newValue: SomeParcelableClass, onResult: ...)
9 suspend fun coUpdateBar(newValue: SomeParcelableClass)
10}
1// Generated code.
2open class FooSettingsServiceBase {
3 // Properties for keys are generated because the type of [foo] property is supported by
4 // the settings management API.
5 protected abstract val fooConfigurationKey: IntDynamicConfigurationKey?
6 protected abstract val fooSettingKey: IntSettingKey?
7
8 /**
9 * Initializes the [foo] property.
10 */
11 protected open fun initFoo(storedSettingsVersion: Int) {
12 // Implementation is generated by the framework because the type of [foo] property is
13 // supported by the settings management API.
14 }
15
16 /**
17 * Reads the value of the [foo] property from the persistent storage.
18 */
19 protected open suspend fun readFooFromStorage(): Int {
20 // Implementation is generated by the framework because the type of [foo] property is
21 // supported by the settings management API.
22 }
23
24 /**
25 * Writes the value of the [foo] property to the persistent storage.
26 */
27 protected open suspend fun writeFooToStorage(newValue: Int) {
28 // Implementation is generated by the framework because the type of [foo] property is
29 // supported by the settings management API.
30 }
31
32 /**
33 * Initializes the [bar] property.
34 */
35 // It is an abstract method because the type of the property is not supported by the settings
36 // management API.
37 protected abstract fun initBar(storedSettingsVersion: Int)
38
39 /**
40 * Reads the value of the [bar] property from the persistent storage.
41 */
42 // It is an abstract method because the type of the property is not supported by the settings
43 // management API.
44 protected abstract suspend fun readBarFromStorage(): SomeParcelableClass
45
46 /**
47 * Writes the value of the [bar] property to the persistent storage.
48 */
49 // It is an abstract method because the type of the property is not supported by the settings
50 // management API.
51 protected abstract suspend fun writeBarToStorage(newValue: SomeParcelableClass)
52
53 /**
54 * Updates the value of the [bar] property.
55 */
56 override suspend fun updateBar(newValue: SomeParcelableClass) {
57 // The implementation is generated for writable properties of any type.
58 }
59}

Settings service deployment configuration

A settings service is deployed as a regular IVI service. It is worth adding a dependency to a settings service interface for a deployment configuration of an IVI service host that uses the settings service. To reduce IPC load, a settings service and the IVI service that uses it can be deployed together in the same process.

See the documentation for IVI service deployment for details.

Settings service advanced configuration

A settings service requires default values and update strategies to create or update settings over time. Those can be obtained using the dynamic configuration provider dynamicConfigurationProvider of the IviSettingsServiceBase class.

Note: A settings service may also use the static configuration provider staticConfigurationProvider.

Both configuration providers use JSON files to configure setting values. Their file format is described in the API reference documentation of IviConfigurationGeneratorConfig.

See the documentation of the Configuration framework to understand when to use a static or dynamic configuration provider.