Table of Contents:
Introduction
The goal of this user interface customisation design document is to reduce app development time when porting between variants by abstracting the differences between variants into a UI library.
The goal of standardising this process is reduce the amount of code written or changed in customising a variant. It is understood that for system components, code might have to be altered for some requests, but code inside application bundles should remain as similar as possible and work in variant-specific ways automatically.
Terminology and Concepts
Vehicle
For the purposes of this document, a vehicle may be a car, car trailer, motorbike, bus, truck tractor, truck trailer, agricultural tractor, or agricultural trailer, amongst other things.
System
The system is the infotainment computer in its entirety in place inside the vehicle.
User
The user is the person using the system, be it the driver of the vehicle or a passenger in the vehicle.
Widget
A widget is a reusable part of the user interface which can be changed depending on location and function.
User Interface
The user interface is the group of all widgets in place in a certain layout to represent a specific use-case.
Roller
The roller is a list widget named after a cylinder which revolves around its central horizontal axis. As a result of being a cylinder it has no specific start and finish and appears endless.
Speller
The speller is a widget for text input.
Application Author
The application author is the developer tasked with writing an application using the widgets described in this document. They cannot modify the variant or the user interface library.
Variant
A variant is a customised version of the system by a particular system integrator. Usually variants are personalised with particular colour schemes and logos and potentially different widget behaviour.
View
A view is an page in an application with an independent purpose. Views move from one to another, and sometimes also back, to form the workflow of the application. For example, in a photo application the list of photos is one view and the highlight on one photo in particular, perhaps with more metadata from the photo, is another view.
Template
A template is a text-based representation of a set of widgets in a view. Templates are for allowing changes and extensions without having to rebuild the actual code.
UI prototyping
UI prototyping is the process of building a mock-up of a UI to evaluate how it looks, and how usable it is for different use cases — but without hooking up the UI to an application implementation or backing code. The idea is to be able to produce a representative UI as fast as possible, so designers and testers can evaluate its usability, and can produce further iterations of the design, without wasting time on implementing backing functionality in code until the design is finalised. At this point, a programmer can turn the prototype into a complete implementation in code.
The process of prototyping is not relevant to UI customisation, but is relevant to the process of using a UI toolkit.
Here is an example of some prototype UIs, made in Inkscape.
WYSIWYG UI editing
WYSIWYG UI editing is the process of using a UI editor, such as Glade, where the UI elements can be composed visually and interactively to build the UI, for example by dragging and dropping them together. The appearance of the UI in the designer is almost identical to its appearance when it is run in production.
Use Cases
A variety of use cases for UI customisation are given below.
Multiple Variants
Each system integrator wants to use the same user interface without having to rewrite from scratch (see Variant differences).
For example, in the speller, variant A wants to highlight the key on an on-screen-keyboard such that the key pops out of the keyboard, whereas variant B wants to highlight just the letter within the key with no pop out animation.
Another example, in the app launcher, variant A wants to use a cylinder animation for rolling whereas variant B wants to scroll the list of applications like a flat list.
Fixed Variants
A system integrator wants multiple variants to be installable concurrently on the system, but wants the variant in use to be fixed and not able to change after being set in a configuration option. The system integrator wants said configuration option to be changeable without rebuilding.
Templates
A system integrator wants to customise the user interface as easily as possible without recompilation of applications. The system integrator wants to be able to choose the widgets in use in a particular application user interface (from a list of available widgets) and have them work accordingly.
For example, in a photo viewing application with one photo selected, system integrator A might want to display the selected photo with nothing else displayed, while system integrator B might want to display the selected photo in the centre of the display, but also have the next and previous photos slightly visible at the sides.
Template Extension
A system integrator wants to use the majority of a provided template, but also wants to add their own variant-specific extensions. The system integrator wants to achieve this without copy and pasting provided templates to retain maintainability, and wants to add their own extension template which merely references the provided one.
For example, said system integrator wants to use an provided button widget, but wants to make it spin 360° when clicked. They want to just override the library widget, adding the spin code, and not have to touch any other code relating to the internal working of the widget already provided in the library.
Custom Widget Usage
A system integrator wants to implement custom widgets by writing actual code. The system integrator wants to be integrate the new custom widgets into the user interface and into the developer tooling.
Template Library
A system integrator wants to be able to add new templates to the system via over the air (OTA) updates. The system integrator does not want the template to be able to reload automatically after being updated.
Appearance Customisation
Each system integrator wants to customise the look and feel of applications by changing styling such as padding widths, border widths, colours, logos, and gradients. The system integrator wants to make said modifications with the minimum of modifications, especially to the source code.
Different Icon Themes
Each system integrator wants to be able to trivially change the icon theme in use across the user interface not only without recompilation, but also at runtime.
Different Fonts
Each system integrator wants to be able to trivially change the font in use across the user interface, and bundle new fonts in with variants.
OTA Updates
System integrators want to be able to add fonts using over the air (OTA) updates. For example, the system integrator wants to change the font in use across the user interface of the variant. They send the updated theme definition as well as the new font file via an update and want it to be registered automatically and be immediately useable.
Language
The user wants to change the language of the controls of the system to their preferred language such that every widget in the UI that contains text updates accordingly without having to restart the application.
Right-to-Left Scripts
As above, the user wants to change the language of the controls of the system, but to a language which is read from right-to-left (Arabic, Persian, Hebrew, etc.), instead of left-to-right. The user expects the workflow of the user interface to also change to right-to-left.
OTA Updates
A system integrator wants to be able to add and improve language support over over the air (OTA) updates. For example, the system integrator wants to add a new translation to the system. They send the translation via an update and want the new language to immediately appear as an option for the user to select.
Animations
A system integrator wants to customise animations for the system. For example, they want to be able to change the behaviour of list widgets by setting the visual response using kinetic scrolling and whether there’s an elastic effect when reaching the end of items. Another example is they also want to be able to customise the animation used when changing views in an application. Another example is the how button widgets react when pressed.
The system integrator then expects to see the changes apply across the entire system.
Prototyping
An application author wants to prototype a UI rapidly (see UI prototyping), using a WYSIWYG UI development tool (see WYSIWYG UI editing) with access to all the widgets in the library, including custom and vendor-specific widgets.
Day & Night Mode
A user is using the system when dark outside and wants the colour scheme of the display to change to accommodate for the darkness outside so not be too bright and dazzle the user. Requiring the user to adapt their eyes momentarily for the brightness of the system could be dangerous.
View Management
An application author has several views in their application and doesn’t want to have to write a system of managing said views. They want to be able to add a workflow and leave the view construction, show and hide animations, and view destruction up to the user interface library.
Display Orientation
A system integrator changes the orientation of the display. They expect the user interface to adapt and display normally, potentially using a different layout more suited to the orientation.
Note that the adaptation is only expected to be implemented if easy and is not expected to be instantaneous, and a restart of the system is acceptable.
Speed Lock
Laws require that when the vehicle is moving some features be disabled or certain behaviour modified.
Geographical Customisation
Different geographical regions have different laws regarding what features and behaviours need to be changed, so it must be customisable (only) by the system integrator when it is decided for which market the vehicle is destined.
System Enforcement
Due to restrictions being government laws, system integrators don’t want to rely on application authors to respect said restrictions, and instead want the system to enforce them automatically.
Non-Use Cases
A variety of non-use cases for UI customisation are given below.
Theming Custom Widgets
An application developer wants to write their own widget using a library directly. They understand that standard variant theming will not apply to any custom widget and any integration will have to be achieved manually.
Note that although unsupported directly by the user interface library, it is possible for application authors to implement this higher up in the application itself.
Multiple Monitors
A system integrator wants to connect two displays (for example, one via HDMI and one via LVDS) and show something on each one, for example when developing on a target board like the i.MX6. They understand this is not supported by Apertis.
DPI Independence
A system integrator uses a display with a different DPI. They understand that they should not expect that the user interface changes to display normally and not too big/small relative to the old DPI.
Display Size
A system integrator changes the resolution of the display. They understand that they should not expect the user interface to adapt and display normally, potentially using a different layout more suited to the new display size.
Dynamic Display Resolution Change
A system integrator wants to be able to change the resolution of the display or resize the user interface. They understand that a dynamic change in the user interface is not supported in Apertis.
Requirements
Variant set at Compile-Time
Multiple variants should be supported on the system but the variant in use should be decided at application compile-time such that it cannot be changed later (see Fixed variants).
CSS Styling
The basic appearance of the widgets should be stylable using CSS, changing the look and feel as much as possible with no modifications to the source code required (see Appearance customisation, Different icon themes).
The changes possible using CSS do not need to be incredibly intrusive and are limited to the basic core CSS properties. For example, changing colour scheme (background-color, color), icon theme & logos (background-image), fonts (font-family, font-size), and spacing (margin, padding).
More intrusive changes to the user interface should be achieved using templates (see Templates) instead of CSS changes.
For example, a system integrator wants to change the colour of text in buttons. This should be possible by changing some CSS.
Templates
CSS is appropriate for changing simple visual aspects of the user interface but does not extend to allow for structural modifications to applications (see CSS styling). Repositioning widgets or even changing which widgets are to be used is not possible with CSS and should be achieved using templates (see Templates).
There are multiple layers of widgets available for use in applications. Starting from the lowest, simplest, level and moving higher, encapsulating more with each step:
-
buttons, entries, labels, …
-
buttons with labels, radio buttons with labels, …
-
lists, tree view, …
-
complete views, or templates.
Templates are declarative representations of the layout of the user interface which are read at runtime by the application. Using templates it is possible to redesign the layout, look & feel, and controls of the application without recompilation.
The purpose of templates is to reduce the effort required by an application author to configure each widget, and to maintain the same look and feel across the system.
Catalogue of Templates
There should be a catalogue of templates provided by the library which system integrators can use to design their applications (see Template library). The layouts of applications should be limited to the main use cases.
For example, one system integrator could want the music application to be a simple list of albums to choose from, while another could want the same information represented in a grid. This simple difference should be possible by using different templates already provided by the user interface library.
Template Extension
In addition to picking layouts from user interface library-provided templates, it should also be possible to take existing templates and change them with the minimal of copy & pasting (see Template extension).
For example, a system integrator could want to change the order of labels in a track information view. The default order in the library-provided template could be track name and then artist name, but said system integrator wants the artist name first, followed by the track name. This kind of change is too fundamental to do in CSS so a template modification is required. The system integrator should be able to take the existing library-provided template and make minimal modifications and minimal copy & pasting to change the order.
Template Modularity
Templates should be as modular as possible in order to break up the parts of a design into smaller parts. This is useful for when changes are required by a system integrator (see Templates, Template extension). If the entire layout is in one template, it is difficult to make small changes without having to copy the entire original template.
Fine-grained modularity which leads to less copy & pasting is optimal because it makes the template more maintainable, as there’s only one place to change if a bug is discovered in the original library-provided template.
Custom Widgets in Templates
A system integrator should be able to use custom widgets they have written for the particular variant in the template format (see Custom widget usage). The responsibility of compatibility with the rest of the user interface of custom widgets is on the widget author.
Documentation
With a library of widgets and models available to the system integrator, the options of widgets and ways to interact with them should be well documented (see Template library). If signals, signal callbacks, and properties are provided these should all be listed in the documentation for the system integrator to connect to properly.
Widget Interfaces
When swapping a widget out for another one in a template it is important that the API matches so the change will work seamlessly. To ensure this, widgets should implement core interfaces (button, entry, combobox, etc.) so that when swapped out, views will continue to work as expected using the replacement widget. Applications should only use API which is defined on the interface, not on the widget implementation, if they wish for their widgets to be swappable for those in another variant.
As a result, system integrators swapping widgets out for replacements should check the API documentation to ensure that the interface implemented by the old widget is also implemented in the new widget. This will ensure compatibility.
GResources
If an application is loading a lot of templates from disk there could be
an overhead in the input/output operation in loading them. A way around
this is to use GResources. GResources are useful for storing
arbitrary data, such as templates, either packed together in one file,
or inside the binary as literal strings. It should be noted that if
linked into the binary itself, the binary will have to be rebuilt every
time the template changes. If this is not an option, saving the
templates in an external file using the glib-compile-resources
binary is
necessary.
The advantage of linking resources into the binary is that once the binary is loaded from disk there is no more disk access. The disadvantage of this is as mentioned before is that rebuilding is required every time resources change. The advantage of putting resources into a single file is that they are only required to be mapped in memory once and then can be shared among other applications.
MVC Separation
There should be a functional separation between data provider (model), the way in which it is displayed in the user interface (view), and the widgets for interaction and data manipulation (controller) (see example in Templates). The model should be a separate object not depending on any visual aspect of the widget.
Following on from the previous example (in Templates), the model would be the list of pictures on the system, and the two variants would use different widgets, but would attach the same model to each widget. This is the key behind being able to swap one widget for another without making code changes.
This separation would push the model and controller responsibility to the user interface library, and an application would only depend on the model in that it provides the data to fill said model.
Language Support
All widgets should be linked into a language translation system such that it is trivial not only for the user to change language (see Language), but also for new translations to be added and existing translations updated (see Ota updates).
Animations
Animations in use in widgets should be configurable by the system integrator (see Animations for examples). These animations should be used widely across the system to ensure a consistent experience. Applications should expose a fixed set of transitions which can be animated so system integrators can tell what can be customised.
Scripting Support
The widgets and templates should be usable from a UI design format, such as GtkBuilder. This includes custom widgets. This would enable application authors to quickly prototype applications (see Prototyping).
Day & Night Mode
The user interface should change between light and dark mode when outside the vehicle becomes dark in order to not shine too brightly and distract the user (see Day night mode).
View Management
A method of managing application views (see View) should be provided to application authors (see View management). On startup the application should provide its views to the view manager. From this point on the responsibility of constructing views, switching views, and showing view animations should be that of the view manager. The view manager should pre-empt the construction of views, but also be sensitive to memory usage so not load all views simultaneously.
Speed Lock
Some features and certain behaviour in the user interface should be disabled or modified respectively when the vehicle is moving (see Speed lock). It should be possible to customise whether each item listed below is disabled or not as it can depend on the target market of the vehicle (see Geographical customisation). Additionally, it should be up to the system to enforce the disabling of the following features and should not be left completely up to application authors (see System enforcement).
Scrolling Lists
The behaviour of gestures in scrolling lists should be altered to remove fast movements with many screen updates. Although still retaining similar functionality, gestures should cause far fewer visual changes. For example, swiping up would no longer start a kinetic scroll, but would move the page up one tabulation.
Text
Text displayed should either be masked or altered to remove the distraction of reading it while operating the vehicle, depending on the nature of the text.
-
SMS messages and emails can have dynamic content so they should be hidden or masked.
-
Help text or dialog messages should have alternate, shorter messages to be shown when the speed lock is active.
List Columns
Lists with columns should limit the number of columns visible to ensure superfluous information is not distracting. For example, in a contact list, instead of showing both name and telephone number, the list could should show only the name.
Keyboard
The keyboard should be visibly disabled and not usable.
Additionally, default values should be available so that operations can succeed without the use of a keyboard. For example when adding a bookmark when the vehicle is stationary the user will be able to choose a name for the new bookmark before saving it. When the vehicle is moving the bookmark will be automatically saved under a default name without the user being prompted for the name. The name (and other use cases of default values) should be modifiable later.
Pictures
Superfluous pictures used in applications as visual aids which could be distracting should be hidden. For example, in the music application, album covers should be hidden from the user.
Video Playback
Video playback must either be paused or the video masked (while the audio continues to sound).
Map Gestures
As with kinetic scrolling in lists (see Scrolling lists), the gestures in the map widget should make fewer visual changes and reduce the number of distractions for the user. Similar to the kinetic scroll example, the map view should move by a fixed distance instead of following the user’s input.
Web View
Any web view should be masked and not showing any content.
Insensitive Widgets
When aforementioned functionality is disabled by the speed lock, it should be made clear to the user what has been modified and why.
Approach
Templates
The goal of templates is to allow an application developer to change the user interface of their application without having to changing the source code. These are merely templates and have no way of implementing logic (if/else statements). If this is required, widget code customisation is required (see Custom widgets).
Properties, Signals, and Callbacks
The GObject properties that can be set, the signals that can be connected to, and the signal callbacks that can be used, should be listed clearly in the application documentation. This way, system integrators can customise the look and feel of the application using already-written tools.
When changing a template to use a different widget it might be necessary to change the signal callbacks. This largely depends on the nature of the change of widget but signals names and signatures should be as consistent as possible across widgets to enable changing as easily as possible. If custom callbacks are used in the code of an application, and the callback signature changes, recompilation will be necessary. The signals emitted by widgets and their type signatures are defined in their interfaces, documented in the API documentation.
Widget Factories
If a system integrator wants to replace a widget everywhere across the user interface, they can use a widget factory to replace all instances of said old widget with the new customised one.
For example, if a system integrator wants to stop using LightwoodButtons
and instead use the custom FancyButton
class, there are no changes
required to any template, but an entry is added to the widget factory to
produce a FancyButton
whenever a LightwoodButton
is requested. Templates
can continue referring to LightwoodButton
or can explicitly request a
FancyButton
but both will be created as FancyButtons
. If an
application truly needs the older LightwoodButton
, it needs to create a
subclass of LightwoodButton
which is not overridden by anything, and then refer to
that explicitly in the template.
Custom Widgets
Widgets can be subclassed by system integrators in variants and used by application developers by creating shared libraries linking to the widget library. Applications then link to said new library and once the new widgets are registered with the GObject type system they can be referred to in ClutterScript user interface files. If a system integrator wants a radically different widget, they can write something from scratch, ensuring to implement the appropriate interface. Subclassing existing widgets is for convenience but not technically necessary.
Widgets should be as modularised as possible, splitting functionality into virtual methods where a system integrator might want to override it. For example, if a system integrator wants the roller widget to have a different activation animation depending on the number of items in the model, they could create a roller widget subclass, and override the appropriate virtual methods (in this case activate) and update the animation as appropriate:
Models
Data that is to be displayed to the user in list widgets should be stored in an orthogonal model object. This object should have no dependency on anything visual (see MVC separation).
The actual implementation of the model should be of no importance to the widgets, and only basic model interface methods should be called by any widget. It is suggested to use the GListModel interface as said model interface as it provides a set of simple type-safe methods to enumerate, manipulate, and be notified of changes to the model.
As GListModel
is only an interface, an implementation of said interface
should be written, ensuring to implement all methods and signals, like
GListStore
.
Theming
Using the GtkStyleContext
object from GTK+ is wise for styling widgets
as it can aggregate styling information from many sources, including
CSS. GTK+’s CSS parsing code is advanced and well tested as GTK+ itself
switched its Adwaita default theme to pure CSS some time ago, replacing
theme engines that required C code to be written to customise appearance.
Said parser and aggregator support multiple layers of overrides. This means that CSS rules can be given priorities and rules are followed in a specific order (for example theme rules are set, and can be overridden by variant rules, and can be overridden by application rules, where necessary). This is ideal for Apertis where themes set defaults and variants need only make changes where necessary.
Theme Changes
Applications should listen to a documented GSettings key for
changes to the theme and icon theme. Changes to the theme should update
the style properties in the GtkStyleContext
and will trigger a widget
redraw and changes to the icon theme should update the icon paths and
trigger icon redraws.
Language Support
GNU gettext is a well-known system for managing translations of applications. It provides tools to scan source code looking for translatable strings and a library to resolve said strings against language files which are easily updated without touching the source code of said applications.
Language Changes
Applications should listen to a documented GSettings key for changes to the user-chosen language, then re-translate all strings and redraw.
Updating Languages
Language files for GNU gettext saved into the appropriate directory can be easily used immediately with no other changes to the application. Over the air (OTA) updates can contain updated language files which get saved to the correct location and would be loaded the next time the application is started.
Day & Night Mode
Inspired by GTK+’s dark mode, variant CSS should provide a dark
class for widgets to be used in night mode. If the dark
class is not set the user
interface should be in day mode. CSS transitions
should make the animation smooth.
A central GSettings key should be read to know when the system is in day or night mode. It will be modifiable for testing and in development.
Speed Lock
There should be a system-operated service that determines when the vehicle is moving and when it is stationary. From this point the Apertis widgets and applications should change when and where appropriate.
There should be a GSettings key which indicates whether the speed lock is active or not. This key should only be modifiable by said system-operated service and should be readable by the entire system.
List Columns
The number of columns visible should be reduced to remove superfluous information when the speed lock is active (see List columns). The nature of every list can be different and the detection of superfluous information is impossible automatically. There should be a way of either application authors specifying which columns should be hidden, or it should be left up to the application itself. If the latter is not an option (see enforcement comments in Speed lock), the entire list widget should be masked to hide its contents.
Keyboard
As mentioned in Keyboard, applications should deal with the possibility that the keyboard may not be available at any given time, if the speed lock is active. In the case that the keyboard request is denied, the application should change its user experience slightly to accommodate for this, such as the example with bookmarks given previously.
The change of user experience also means there must be other ways in which users can edit named items using default values after the speed lock has been disabled.
Insensitive Widgets
As highlighted in Insensitive widgets, it should be made obvious to the user when functionality is disabled, and why. There should be a uniform visual change to widgets when they have been made insensitive so users can immediately recognise what is happening.
A documented CSS class should be added to widgets that are made insensitive by the speed lock so that said widgets follow an identical change in display.
Notifications
Pop-up notifications or a status bar message should make it clear to the user that the speed lock is active and if appropriate, highlight the current functionality that has been disabled.
Masking Unknown Applications
Applications can technically implement custom widgets and not respect the rules of the speed lock. As a result, applications which haven’t been vetted by an approved authority should not be able to be run when the speed lock is active. When they are already running and the speed lock is activated, they should be masked and the user should not be able to interact with them.
This behaviour should be customisable and possibly only enabled in a region in which laws are very strict about speed lock restrictions.