Each head unit manufacturer supports a set of user interface templates. These templates determine the position and size of the text, images, and buttons on the screen. Once the app has connected successfully with an SDL enabled head unit, a list of supported templates is available on sdlManager.getSystemCapabilityManager().getDefaultMainWindowCapability().getTemplatesAvailable()
.
To change a template at any time, use ScreenManager.changeLayout()
. This guide requires SDL Java Suite version 5.0. If using an older version, use the SetDisplayLayout
RPC.
When changing the layout, you may get an error or failure if the update is "superseded." This isn't technically a failure, because changing the layout has not yet been attempted. The layout or batched operation was cancelled before it could be completed because another operation was requested. The layout change will then be inserted into the future operation and completed then.
TemplateConfiguration templateConfiguration = new TemplateConfiguration().setTemplate(PredefinedLayout.GRAPHIC_WITH_TEXT.toString()); sdlManager.getScreenManager().changeLayout(templateConfiguration, new CompletionListener() { @Override public void onComplete(boolean success) { if (success) { DebugTool.logInfo(TAG, "Layout set successfully"); } else { DebugTool.logInfo(TAG, "Layout not set successfully"); } } });
Template changes can also be batched with text and graphics updates:
sdlManager.getScreenManager().beginTransaction(); sdlManager.getScreenManager().setTextField1("Line of Text"); sdlManager.getScreenManager().changeLayout(templateConfiguration, new CompletionListener() { @Override public void onComplete(boolean success) { // This listener will be ignored, and will use the CompletionListener sent in commit. } }); sdlManager.getScreenManager().setPrimaryGraphic(sdlArtwork); sdlManager.getScreenManager().commit(new CompletionListener() { @Override public void onComplete(boolean success) { if (success) { DebugTool.logInfo(TAG, "The data and template have been set successfully"); } } });
When changing screen layouts and template data (for example, to show a weather hourly data screen vs. a daily weather screen), it is recommended to encapsulate these updates into a class or method. Doing so is a good way to keep SDL UI changes organized. A fully-formed example of this can be seen in the example weather app. Below is a generic example.
This example code creates an interface that can be implemented by various "screens" of your SDL app. This is a recommended design pattern so that you can separate your code to only involve the data models you need. This is just a simple example and your own needs may be different.
All screens will need to have access to the ScreenManager
object and a function to display the screen. Therefore, it is recommended to create a generic interface for all screens to follow. For the example below, the CustomSDLScreen
protocol requires an initializer with the parameters SDLManager
and a showScreen
method.
public class CustomSdlScreen { protected SdlManager sdlManager; public CustomSdlScreen(SdlManager sdlManager) { this.sdlManager = sdlManager; } public void showScreen() { // stub } }
The following example code shows a few implementations of the example screen changing protocol. A good practice for screen classes is to keep screen data in a view model. Doing so will add a layer of abstraction for exposing public properties and commands to the screen.
For the example below, the HomeScreen
class will inherit the CustomSDLScreen
interface and will have a property of type HomeDataViewModel
. The screen manager will change its text fields based on the view model's data. In addition, the home screen will also create a navigation button to open the ButtonSDLScreen
when pressed.
public class HomeSdlScreen extends CustomSdlScreen { private ButtonSdlScreen buttonScreen; // An example of your data model that will feed data to the SDL screen's UI private HomeDataViewModel homeDataViewModel; public HomeSdlScreen(SdlManager sdlManager) { super(sdlManager); buttonScreen = new ButtonSdlScreen(sdlManager); homeDataViewModel = new HomeDataViewModel(); } public void showScreen() { // Batch Updates sdlManager.getScreenManager().beginTransaction(); // Change template to Graphics With Text and Soft Buttons TemplateConfiguration templateConfiguration = new TemplateConfiguration().setTemplate(PredefinedLayout.GRAPHIC_WITH_TEXT.toString()); sdlManager.getScreenManager().changeLayout(templateConfiguration, new CompletionListener() { @Override public void onComplete(boolean success) {} }); // Assign text fields to view model data sdlManager.getScreenManager().setTextField1(homeDataViewModel.getText1()); sdlManager.getScreenManager().setTextField2(homeDataViewModel.getText2()); sdlManager.getScreenManager().setTextField3(homeDataViewModel.getText3()); sdlManager.getScreenManager().setTextField4(homeDataViewModel.getText4()); // Create and assign a button to navigate to the ButtonSdlScreen SoftButtonState textState = new SoftButtonState("ButtonSdlScreenState", "Button Screen", null); SoftButtonObject navigationButton = new SoftButtonObject("ButtonSdlScreen", Collections.singletonList(textState), textState.getName(), new SoftButtonObject.OnEventListener() { @Override public void onPress(SoftButtonObject softButtonObject, OnButtonPress onButtonPress) { buttonScreen.showScreen(); } @Override public void onEvent(SoftButtonObject softButtonObject, OnButtonEvent onButtonEvent) { } }); sdlManager.getScreenManager().setSoftButtonObjects(Collections.singletonList(navigationButton)); sdlManager.getScreenManager().commit(new CompletionListener() { @Override public void onComplete(boolean success) {} }); } }
The ButtonSDLScreen
follows the same patterns as the HomeSDLScreen
but has minor implementation differences. The screen's view model ButtonDataViewModel
contains properties unique to the ButtonSDLScreen
such as text fields and an array of soft button objects. It also changes the template configuration to tiles only.
public class ButtonSdlScreen extends CustomSdlScreen { private ButtonDataViewModel buttonDataViewModel; public ButtonSdlScreen(SdlManager sdlManager) { super(sdlManager); buttonDataViewModel = new ButtonDataViewModel(); } public void showScreen() { sdlManager.getScreenManager().beginTransaction(); TemplateConfiguration templateConfiguration = new TemplateConfiguration().setTemplate(PredefinedLayout.TILES_ONLY.toString()); sdlManager.getScreenManager().changeLayout(templateConfiguration, new CompletionListener() { @Override public void onComplete(boolean success) {} }); sdlManager.getScreenManager().setSoftButtonObjects(buttonDataViewModel.getButtonObjects()); sdlManager.getScreenManager().commit(new CompletionListener() { @Override public void onComplete(boolean success) {} }); } }
There are fifteen standard templates to choose from, however some head units may only support a subset of these templates. The following examples show how templates will appear on the Generic HMI and Ford's SYNC® 3 HMI.