Replace the Stock Android App Support

Last edit: 2023.07.27

The TomTom Digital Cockpit app launcher provides stock implementations for providing the list of Android apps to show in the app launcher panel and for launching the Android apps when they are selected.

The stock Android app source provider will provide the list of Android apps which are present on the device, and that were not installed as part of the TomTom Digital Cockpit system image or subsequent TomTom Digital Cockpit updates. If there is a requirement to show or filter apps based on different criteria then this can be done by overriding the stock app source provider.

An example of an alternative Android app source implementation could be one which returns a fixed list of pre-installed apps.

TomTom Digital Cockpit provides stock implementations for launching "launchable" Android apps (that is, standard Android apps with a launcher activity) and Android media apps (that is, media source apps that can be launched in a media player). Launch handling for these two Android app types can be overridden individually with separate implementations or both can be overridden together with a single combined implementation.

An example of an alternative "launchable" Android app launch handler implementation could be one which launches a separate standalone app rather than the stock behaviour of launching the app within a panel.

This section shows how to:

Replace the stock Android app source support

The stock Android app source provider implementation can be overridden by creating your own AppSourceProviderService implementation and returning the AndroidApp class as the value of the AppSourceProviderService.supportedAppClass.

The following steps describe how to override the implementation of the stock AndroidApp source provider:

Create the replacement app source provider module

First add the app store common module and AppSourceProviderService dependency to the /build-logic/libraries.versions.toml file:

iviAppsuiteAppstoreApiCommonModel = { module = "com.tomtom.ivi.appsuite:appsuite_appstore_api_common_model", version.ref = "iviPlatform" }
iviAppsuiteAppstoreApiServiceAppsourceprovider = { module = "com.tomtom.ivi.appsuite:appsuite_appstore_api_service_appsourceprovider", version.ref = "iviPlatform" }

Create a module for the AppSourceProviderService implementation under examples/applauncher/services (for example examples/applauncher/services/androidappsourceprovider) and add a Gradle build script.

Create a build.gradle.kts file:

1import com.tomtom.ivi.platform.gradle.api.framework.config.ivi
2
3ivi {
4 // The AppSourceProviderService API is currently an experimental feature, and has to be
5 // explicitly opted in.
6 optInToExperimentalApis = true
7}
8dependencies {
9 implementation(libraries.iviAppsuiteAppstoreApiCommonModel)
10 implementation(libraries.iviAppsuiteAppstoreApiServiceAppsourceprovider)
11}

The app source provider service module is an Android module, so it must also have an AndroidManifest.xml file.

Create a src/main/AndroidManifest.xml file:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.example.ivi.example.applauncher.services.androidappsourceprovider" />

Implement the replacement app source provider service

The app source provider service can be implemented by defining a class (for example, AndroidAppSourceProviderService) that inherits from the abstract AppSourceProviderServiceBase base class and implements the methods defined in the AppSourceProviderService interface.

The service implementation needs to set a number of properties for configuring itself with the TomTom Digital Cockpit platform. Please refer to the AppSourceProviderService API reference documentation for detailed information on these properties.

The properties can be set by overriding the onCreate() method.

Create src/main/kotlin/com/example/ivi/example/applauncher/services/androidappsourceprovider/AndroidAppSourceProviderService.kt

1import com.tomtom.ivi.appsuite.appstore.api.common.model.ParcelableAppClass
2import com.tomtom.ivi.appsuite.appstore.api.common.model.androidapptypes.AndroidApp
3import com.tomtom.ivi.appsuite.appstore.api.common.model.androidapptypes.LaunchableAndroidApp
4import com.tomtom.ivi.appsuite.appstore.api.service.appsourceprovider.AppSourceProviderServiceBase
5import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviDiscoverableServiceIdProvider
6import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviServiceHostContext
7
8class AndroidAppSourceProviderService(
9 iviServiceHostContext: IviServiceHostContext,
10 serviceIdProvider: IviDiscoverableServiceIdProvider
11) : AppSourceProviderServiceBase(iviServiceHostContext, serviceIdProvider) {
12
13 override fun onCreate() {
14 super.onCreate()
15
16 appStore = null
17
18 // An IVI service interface can use only [Parcelable] types, so the [supportedAppClass] must
19 // be returned inside a [Parcelable] wrapper class.
20 supportedAppClass = ParcelableAppClass(AndroidApp::class.java)
21
22 // The value of [launchablePackageName] should match the package name of an Android app
23 // known to be installed on the device, otherwise the app will not appear in the app
24 // launcher.
25 installedApps = listOf(
26 LaunchableAndroidApp(
27 launchablePackageName = "com.android.example"
28 )
29 )
30 }
31
32 override fun onRequiredPropertiesInitialized() {
33 serviceReady = true
34 }
35}

Create a service host for the replacement app source provider

Your module will also need to define a service host where the service will be running, as well as provide a service host builder. This can be achieved by creating two classes.

  • An AndroidAppSourceProviderServiceHost class:

    src/main/kotlin/com/example/ivi/example/applauncher/services/androidappsourceprovider/AndroidAppSourceProviderServiceHost.kt

    1import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviDiscoverableServiceIdProvider
    2import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviServiceHostBase
    3import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviServiceHostContext
    4
    5class AndroidAppSourceProviderServiceHost(
    6 iviServiceHostContext: IviServiceHostContext,
    7 iviDiscoverableServiceIdProvider: IviDiscoverableServiceIdProvider
    8) : IviServiceHostBase(iviServiceHostContext) {
    9
    10 override val iviServices = setOf(
    11 AndroidAppSourceProviderService(
    12 iviServiceHostContext,
    13 iviDiscoverableServiceIdProvider
    14 )
    15 )
    16}
  • An AndroidAppSourceProviderServiceHostBuilder class:

    src/main/kotlin/com/example/ivi/example/applauncher/services/androidappsourceprovider/AndroidAppSourceProviderServiceHostBuilder.kt

    1import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviServiceHostBase
    2import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviServiceHostBuilder
    3import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviServiceHostContext
    4
    5class AndroidAppSourceProviderServiceHostBuilder : IviServiceHostBuilder() {
    6
    7 override fun build(iviServiceHostContext: IviServiceHostContext): IviServiceHostBase =
    8 AndroidAppSourceProviderServiceHost(iviServiceHostContext) {
    9 getDiscoverableServiceId(it)
    10 }
    11 companion object
    12}

Configure the service host deployment for the replacement app source provider

Note: Every service host needs to be configured and registered in your application. This is necessary to know which service should be started with which implementation when a client requires the access to a service api.

Define an IVI service host implementation in your gradle file. This can also be defined in a top-level gradle file (for example, iviservicehosts.gradle.kts) so it can be used in a multi-project build, including the tests.

Modify the examples/applauncher/iviservicehosts.gradle.kts file:

1/**
2 * Defines a configuration for the android app source provider service.
3 *
4 * The configuration specifies the service host implementation and the list of interfaces
5 * implemented by this service host.
6 */
7
8val androidAppSourceProviderServiceHost by extra {
9 IviServiceHostConfig(
10 serviceHostBuilderName = "AndroidAppSourceProviderServiceHostBuilder",
11 implementationModule = ExampleModuleReference("services_androidappsourceprovider"),
12 interfaces = listOf(
13 IviServiceInterfaceConfig(
14 serviceName = "AppSourceProviderService",
15 serviceId = "com.tomtom.ivi.example.service.androidappsourceprovider",
16 serviceApiModule = IviAppsuiteModuleReference("appsuite_appstore_api_service_appsourceprovider"),
17 multipleInstances = true
18 )
19 )
20 )
21}

Register the service host build configuration in the main application's build script.

Modify the examples/applauncher/app/build.gradle.kts file:

1apply(from = rootProject.file("examples/applauncher/iviservicehosts.gradle.kts"))
2
3val androidAppSourceProviderServiceHost: IviServiceHostConfig by project.extra
4
5ivi {
6 application {
7 enabled = true
8 services {
9 // Add the Android app source provider service host to the application.
10 addHost(androidAppSourceProviderServiceHost)
11 }
12 }
13}

Replace the stock launchable Android app launch support

The stock Android app launch handler implementation can be overridden by creating your own AppLaunchHandlerService implementation and returning either the LaunchableAndroidApp or MediaAndroidApp class as the value of the AppLaunchHandlerService.supportedAppClass.

In this example we will override the launching implementation for LaunchableAndroidApp.

The following steps describe how to override the implementation of the stock LaunchableAndroidApp launch handler:

Create the replacement app launch handler module

First add the app store common module and AppLaunchHandlerService dependency to the /build-logic/libraries.versions.toml file:

iviAppsuiteAppstoreApiCommonModel = { module = "com.tomtom.ivi.appsuite:appsuite_appstore_api_common_model", version.ref = "iviPlatform" }
iviAppsuiteAppstoreApiServiceApplaunchhandler = { module = "com.tomtom.ivi.appsuite:appsuite_appstore_api_service_applaunchhandler", version.ref = "iviPlatform" }

Create a module for the AppLaunchHandlerService implementation under examples/applauncher/services (for example examples/applauncher/services/launchableandroidapplaunchhandler) and add a Gradle build script.

Create a build.gradle.kts file:

1import com.tomtom.ivi.platform.gradle.api.framework.config.ivi
2
3ivi {
4 // The AppLaunchHandlerService API is currently an experimental feature, and has to be
5 // explicitly opted in.
6 optInToExperimentalApis = true
7}
8dependencies {
9 implementation(libraries.iviAppsuiteAppstoreApiCommonModel)
10 implementation(libraries.iviAppsuiteAppstoreApiServiceApplaunchhandler)
11}

The app launch handler service module is an Android module, so it must also have an AndroidManifest.xml file.

Create a src/main/AndroidManifest.xml file:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.example.ivi.example.applauncher.services.launchableandroidapplaunchhandler" />

Implement the replacement app launch handler service

The app launch handler service can be implemented by defining a class (for example, LaunchableAndroidAppLaunchHandlerService) that inherits from the abstract AppLaunchHandlerServiceBase class and implements the methods defined in the AppLaunchHandlerService interface.

The service implementation needs to set a number of properties for configuring itself with the TomTom Digital Cockpit platform. Please refer to the AppLaunchHandlerService API reference documentation for detailed information on these properties.

The properties can be set by overriding the onCreate() method.

Create src/main/kotlin/com/example/ivi/example/applauncher/services/launchableandroidapplaunchhandler/LaunchableAndroidAppLaunchHandlerService.kt

1import com.tomtom.ivi.appsuite.appstore.api.common.model.App
2import com.tomtom.ivi.appsuite.appstore.api.common.model.ParcelableAppClass
3import com.tomtom.ivi.appsuite.appstore.api.common.model.androidapptypes.LaunchableAndroidApp
4import com.tomtom.ivi.appsuite.appstore.api.service.applaunchhandler.AppLaunchHandlerServiceBase
5import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviDiscoverableServiceIdProvider
6import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviServiceHostContext
7
8class LaunchableAndroidAppLaunchHandlerService(
9 private val iviServiceHostContext: IviServiceHostContext,
10 serviceIdProvider: IviDiscoverableServiceIdProvider
11) : AppLaunchHandlerServiceBase(iviServiceHostContext, serviceIdProvider) {
12
13 override fun onCreate() {
14 super.onCreate()
15
16 // An IVI service interface can use only [Parcelable] types, so the [supportedAppClass] must
17 // be returned inside a [Parcelable] wrapper class.
18 supportedAppClass = ParcelableAppClass(LaunchableAndroidApp::class.java)
19 }
20
21 override fun onRequiredPropertiesInitialized() {
22 serviceReady = true
23 }
24
25 override suspend fun launchApp(app: App) {
26 require(app is LaunchableAndroidApp)
27 launchLaunchableAndroidApp(app)
28 }
29
30 private fun launchLaunchableAndroidApp(app: LaunchableAndroidApp) {
31 val launchIntent =
32 iviServiceHostContext.context.packageManager.getLaunchIntentForPackage(app.packageName);
33 iviServiceHostContext.context.startActivity(launchIntent)
34
35 }
36}

Create a service host for the replacement app launch handler

Your module will also need to define a service host where the service will be running, as well as provide a service host builder. This can be achieved by creating two classes.

  • A LaunchableAndroidAppLaunchHandlerServiceHost class:

    src/main/kotlin/com/example/ivi/example/applauncher/services/launchableandroidapplaunchhandler/LaunchableAndroidAppLaunchHandlerServiceHost.kt

    1import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviDiscoverableServiceIdProvider
    2import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviServiceHostBase
    3import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviServiceHostContext
    4
    5class LaunchableAndroidAppLaunchHandlerServiceHost(
    6 iviServiceHostContext: IviServiceHostContext,
    7 iviDiscoverableServiceIdProvider: IviDiscoverableServiceIdProvider
    8) : IviServiceHostBase(iviServiceHostContext) {
    9
    10 override val iviServices = setOf(
    11 LaunchableAndroidAppLaunchHandlerService(iviServiceHostContext, iviDiscoverableServiceIdProvider)
    12 )
    13}
  • A LaunchableAndroidAppLaunchHandlerServiceHostBuilder class:

    src/main/kotlin/com/example/ivi/example/applauncher/services/launchableandroidapplaunchhandler/LaunchableAndroidAppLaunchHandlerServiceHostBuilder.kt

    1import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviServiceHostBase
    2import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviServiceHostBuilder
    3import com.tomtom.ivi.platform.framework.api.ipc.iviservice.IviServiceHostContext
    4
    5class LaunchableAndroidAppLaunchHandlerServiceHostBuilder : IviServiceHostBuilder() {
    6
    7 override fun build(iviServiceHostContext: IviServiceHostContext): IviServiceHostBase =
    8 LaunchableAndroidAppLaunchHandlerServiceHost(iviServiceHostContext) {
    9 getDiscoverableServiceId(it)
    10 }
    11
    12 companion object
    13}

Configure the service host deployment for the replacement app launch handler

Note: Every service host needs to be configured and registered in your application. This is necessary to know which service should be started with which implementation when a client requires the access to a service api.

Define an IVI service host implementation, in your gradle file, This can also be defined in a top-level gradle file (for example, iviservicehosts.gradle.kts) so it can be used in a multi-project build, including the tests.

Modify the examples/applauncher/iviservicehosts.gradle.kts file:

1/**
2 * Defines a configuration for the launchable android app launch handler service.
3 *
4 * The configuration specifies the service host implementation and the list of interfaces
5 * implemented by this service host.
6 */
7val launchableAndroidAppLaunchHandlerServiceHost by extra {
8 IviServiceHostConfig(
9 serviceHostBuilderName = "LaunchableAndroidAppLaunchHandlerServiceHostBuilder",
10 implementationModule = ExampleModuleReference("services_launchableandroidapplaunchhandler"),
11 interfaces = listOf(
12 IviServiceInterfaceConfig(
13 serviceName = "AppLaunchHandlerService",
14 serviceId = "com.tomtom.ivi.example.service.launchableandroidapplaunchhandler",
15 serviceApiModule = IviAppsuiteModuleReference("appsuite_appstore_api_service_applaunchhandler"),
16 multipleInstances = true
17 )
18 )
19 )
20}

Register the service host build configuration in the main application's build script.

Modify the examples/applauncher/app/build.gradle.kts file:

1apply(from = rootProject.file("examples/applauncher/iviservicehosts.gradle.kts"))
2
3val launchableAndroidAppLaunchHandlerServiceHost: IviServiceHostConfig by project.extra
4
5ivi {
6 application {
7 enabled = true
8 services {
9 // Add the Android app launch handler service host to the application.
10 addHost(launchableAndroidAppLaunchHandlerServiceHost)
11 }
12 }
13}