Create a Frontend Plugin
For an introduction to frontend plugins in the TomTom Digital Cockpit platform, see (Frontend Plugins)
Introduction
In this example, we will create a new frontend for managing an account on the device. It will provide a login screen where you can enter a username and a password to login, and if the user is logged in, you have the option to logout again. We will also add a menu item to the main menu that will be associated to the new frontend. The final step will be to let the new frontend replace TomTom Digital Cockpit's user profile frontend.
The source for this example can be found in the following directories in the examples source:
Creating a frontend and the menu item consists of a number of steps:
- Creating the frontend class
- Creating the frontend-builder class
- Creating the panel
- Creating a menu item
- Defining the frontend and menu item build config
- Registering the frontend and menu item build config
- More information
All the code snippets in this guide can also be found in the TomTom Digital Cockpit example application.
Creating the frontend class
Create a new frontend by deriving the Frontend
framework class.
src/main/kotlin/com/example/ivi/example/plugin/frontend/AccountFrontend.kt
1import com.tomtom.ivi.platform.frontend.api.common.frontend.Frontend2import com.tomtom.ivi.platform.frontend.api.common.frontend.FrontendContext34internal class AccountFrontend(frontendContext: FrontendContext) : Frontend(frontendContext) {5 // ...6}
There are no abstract methods in the Frontend
class, but some methods, like
the lifecycle ones (see the following methods), are good to consider implementing.
Frontend lifecycle methods
onCreate
- callback when the frontend is created.onDestroy
- callback when the frontend is about to get destroyed.
Showing panels on the screen
There are two callbacks when an event is triggered to show a TaskPanel
on the screen.
createMainTaskPanel
- override it to display a singleTaskPanel
when the UI is shown.openTaskPanels
- override it when more control is needed over which panels should be shown.
Note: A frontend class must override only one of these two methods.
Creating the frontend-builder class
Add an AccountFrontendBuilder
class, derived from the FrontendBuilder
class. Override the build()
method in the class and return a new instance of the AccountFrontend
class.
src/main/kotlin/com/example/ivi/example/plugin/frontend/AccountFrontendBuilder.kt
1import com.tomtom.ivi.platform.frontend.api.common.frontend.Frontend2import com.tomtom.ivi.platform.frontend.api.common.frontend.FrontendBuilder3import com.tomtom.ivi.platform.frontend.api.common.frontend.FrontendContext45class AccountFrontendBuilder: FrontendBuilder() {67 override fun build(frontendContext: FrontendContext): Frontend =8 AccountFrontend(frontendContext)9}
The builder class must follow a specific naming convention. It must have a "FrontendBuilder" suffix and must start with an upper case character.
Creating the panel
There are a number of specialized Panel
classes that can be used in the platform, see the package
com.tomtom.ivi.platform.frontend.api.common.frontend.panels
).
For this example we will create a Panel
class that inherits from the
TaskPanel
class.
A TaskPanel
is typically launched by tapping one of the menu items, like
opening Contacts; or some other UI event, like opening the Climate panel. It encapsulates a task
that the user may perform, typically away from the map, going back to the map when the task is
finished.
Derive from the TaskPanel
class, and override the
createInitialFragmentInitializer()
method, which should return a new instance of the
IviFragment
class (described further down).
src/main/kotlin/com/example/ivi/example/plugin/frontend/login/AccountLoginPanel.kt
1internal class AccountLoginPanel(frontendContext: FrontendContext) :2 TaskPanel(frontendContext) {34 override fun createInitialFragmentInitializer() =5 IviFragment.Initializer(AccountLoginFragment(), this)6}
Also create a ViewModel
class, derived from the FrontendViewModel
class.
The ViewModel
is the ViewModel in the Model-View-ViewModel (MVVM) pattern, whose role is to
expose streams of data relevant to the view and streams of events to the model.
src/main/kotlin/com/example/ivi/example/plugin/frontend/login/AccountLoginViewModel.kt
1internal class AccountLoginViewModel(panel: AccountLoginPanel) :2 FrontendViewModel<AccountLoginPanel>(panel) {34 val username = MutableLiveData("")5 val password = MutableLiveData("")6 // ...78 fun onLoginClick() {9 // ...10 }11}
Finally create a Fragment
class derived from IviFragment
and using the
newly created Panel
and ViewModel
classes, overriding the viewFactory
property. The
TomTom Digital Cockpit platform is designed to work well with the MVVM pattern, and this is used in the
onCreateView
callback as a convenience to inflate a data binding layout and use that in the
fragment. If an onCreateView
custom implementation is preferred, the viewFactory
property
can be left as null instead.
src/main/kotlin/com/example/ivi/example/plugin/frontend/login/AccountLoginFragment.kt
1internal class AccountLoginFragment :2 IviFragment<AccountLoginPanel, AccountLoginViewModel>(AccountLoginViewModel::class) {34 override val viewFactory = ViewFactory(TtiviAccountLoginFragmentBinding::inflate)5}
See this expressions page for more information on how data-binding works in Android and how the
ViewModel
class binds to the XML layout. It also explains how theTtiviAccountLoginFragmentBinding
class that you pass to theViewFactory
is auto-generated.
Creating a menu item
In this tutorial a menu item is added to the main menu that will open the main task panel of the
AccountFrontend
. To add the menu item to the main menu we need a MenuItem
instance.
Create an AccountMenuItem.kt
file, add a property in the file, and assign it a
MenuItem
instance. The name of the property must follow a specific naming
convention. It must have a "MenuItem" suffix and start with a lowercase character.
src/main/kotlin/com/example/ivi/example/plugin/frontend/AccountMenuItem.kt
1val accountMenuItem = MenuItem(2 AccountFrontend::class.qualifiedName!!,3 R.drawable.ttivi_account_menuitem,4 R.string.ttivi_account_menuitem_name5)
The MenuItem
constructor takes a unique ID, a DrawableResolver
, and a
StringResolver
. The latter two resolve the icon and the name of the menu item. In the above
example the resolvers are defined as Android resources.
Defining the frontend and menu item build config
Create the frontend and menu item build configurations. These configurations will be used to register the frontend and the menu item to the framework at build time.
Define a frontend implementation and a menu item implementation. These can also be defined in a
top-level Gradle file (for example frontends-and-menuitems.gradle.kts
) so it can be used in a
multi-project build, including the tests.
Create an
examples/plugin/app/build.gradle.kts
file:
1import com.tomtom.ivi.buildsrc.dependencies.ExampleModuleReference2import com.tomtom.ivi.platform.gradle.api.common.iviapplication.config.FrontendCreationPolicy3import com.tomtom.ivi.platform.gradle.api.common.iviapplication.config.FrontendConfig45/**6 * Defines the implementation and the configuration of the account frontend.7 */8val accountFrontend = FrontendConfig(9 // Needs to match with the name of the builder class.10 frontendBuilderName = "AccountFrontendBuilder",11 // The module containing the frontend implementation.12 implementationModule = ExampleModuleReference("examples_plugin_frontend"),13 // Create the frontend on demand. It will be created when the menu item is selected.14 creationPolicy = FrontendCreationPolicy.CREATE_ON_DEMAND15)1617// We can use `FrontendConfig.toMenuItem()` as the menu item is defined in the same module as18// the frontend implementation. The argument given needs to match with the property that19// was created earlier in the tutorial.20val accountMenuItem = accountFrontend.toMenuItem("accountMenuItem")
The above build configurations use the ExampleModuleReference
to resolve a module name into
the full-qualified package. It is defined once and used for all configurations. See
Integrate TomTom Digital Cockpit into a Gradle Project
for details.
Registering the frontend and menu item build config
The last step is to register the frontend and the menu item to build configurations in the main application's build script.
Modify the
examples/plugin/app/build.gradle.kts
file:
1import com.tomtom.ivi.buildsrc.dependencies.ExampleModuleReference2import com.tomtom.ivi.platform.gradle.api.common.iviapplication.config.FrontendConfig3import com.tomtom.ivi.platform.gradle.api.common.iviapplication.config.FrontendCreationPolicy4import com.tomtom.ivi.platform.gradle.api.common.iviapplication.config.IviInstanceIdentifier5import com.tomtom.ivi.platform.gradle.api.common.iviapplication.config.MenuItemConfig6import com.tomtom.ivi.platform.gradle.api.framework.config.ivi78plugins {9 // Apply the plugin to use default frontends and services from the TomTom Digital Cockpit10 // Platform and from all TomTom Digital Cockpit Applications (from appsuite).11 id("com.tomtom.ivi.product.defaults.core")12}1314// Create `accountFrontend` and `accountMenuItem`15val accountFrontend = FrontendConfig(16 // Needs to match with the name of the builder class.17 frontendBuilderName = "AccountFrontendBuilder",18 // The module containing the frontend implementation.19 implementationModule = ExampleModuleReference("examples_plugin_frontend"),20 // Create the frontend on demand. It will be created when the menu item is selected.21 creationPolicy = FrontendCreationPolicy.CREATE_ON_DEMAND22)2324// We can use `FrontendConfig.toMenuItem()` as the menu item is defined in the same module as25// the frontend implementation. The argument given needs to match with the property that26// was created earlier in the tutorial.27val accountMenuItem = accountFrontend.toMenuItem("accountMenuItem")2829ivi {30 application {31 enabled = true32 iviInstances {33 create(IviInstanceIdentifier.default) {34 // Use the default frontends and menu items as defined by the plugin applied above:35 // `com.tomtom.ivi.product.defaults.core`.36 applyGroups {37 includeDefaultPlatformGroups()38 includeDefaultAppsuiteGroups()39 }40 frontends {41 // Register the `accountFrontend`.42 add(accountFrontend)43 }44 menuItems {45 // Register the `accountMenuItem` and associate it with the `accountFrontend`.46 addLast(accountMenuItem to accountFrontend)47 }48 }49 }50 }51}5253// The rest of the build script, dependencies, etc.
The above example adds the accountFrontend
and the accountMenuItem
to the default IVI
instance. A vehicle may have multiple infotainment screens. Each infotainment screen is an IVI
instance. See
Configure the Runtime Deployment of the IVI System
for more details about IVI instance configurations.
The final step is to let the new frontend replace TomTom Digital Cockpit's user profile frontend. For this
we have to use replace
instead of add
. The same applies for the user profile menu item.
Modify the
examples/plugin/app/build.gradle.kts
file:
1import com.tomtom.ivi.platform.gradle.api.common.iviapplication.config.FrontendConfig2import com.tomtom.ivi.platform.gradle.api.common.iviapplication.config.IviInstanceIdentifier3import com.tomtom.ivi.platform.gradle.api.common.iviapplication.config.MenuItemConfig4import com.tomtom.ivi.platform.gradle.api.plugin.defaultsplatform.userProfileFrontend5import com.tomtom.ivi.platform.gradle.api.plugin.defaultsplatform.userProfileMenuItem6import com.tomtom.ivi.platform.gradle.api.framework.config.ivi78plugins {9 // Apply the Gradle plugin to define the default frontends, menu items and services from10 // the TomTom Digital Cockpit Platform and from all TomTom Digital Cockpit Applications (from11 // the appsuite). The default frontends, menu items, and services are defined in groups. The12 // groups are applied to the following IVI application configuration.13 id("com.tomtom.ivi.product.defaults.core")14}1516// Create `accountFrontend` and `accountMenuItem`.17val accountFrontend = FrontendConfig(18 frontendBuilderName = "AccountFrontendBuilder",19 implementationModule = ExampleModuleReference("examples_plugin_frontend"),20 creationPolicy = FrontendCreationPolicy.CREATE_ON_DEMAND21)22val accountMenuItem = accountFrontend.toMenuItem("accountMenuItem")2324ivi {25 application {26 enabled = true27 iviInstances {28 create(IviInstanceIdentifier.default) {29 // Configure all frontends and menu items from all groups that do not require an30 // explicit opt-in. The groups are defined by the31 // `com.tomtom.ivi.platform.defaults.core` Gradle plugin.32 applyGroups {33 includeDefaultPlatformGroups()34 includeDefaultAppsuiteGroups()35 }3637 // Replace TomTom Digital Cockpit's user profile frontend with the `accountFrontend`.38 frontends {39 replace(userProfileFrontend, accountFrontend)40 }4142 // Replace TomTom Digital Cockpit's user profile menu item with the `accountMenuItem`43 // and associate it with the `accountFrontend`.44 menuItems {45 replace(userProfileMenuItem, accountMenuItem to accountFrontend)46 }47 }48 }49 }50}5152// The rest of the build script, dependencies, etc.
The above example replaces the userProfileFrontend
with the accountFrontend
and replaces
the userProfileMenuItem
with the accountMenuItem
.
More information
For information on how to call the @IviServiceApi
members from
Frontend Plugins
refer to the section
Calling service methods.