
com.smartdevicelink.managers.screen.BaseScreenManager Maven / Gradle / Ivy
/*
* Copyright (c) 2019 Livio, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following
* disclaimer in the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of the Livio Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package com.smartdevicelink.managers.screen;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import com.smartdevicelink.managers.AlertCompletionListener;
import com.smartdevicelink.managers.BaseSubManager;
import com.smartdevicelink.managers.CompletionListener;
import com.smartdevicelink.managers.ISdl;
import com.smartdevicelink.managers.file.FileManager;
import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
import com.smartdevicelink.managers.screen.choiceset.ChoiceCell;
import com.smartdevicelink.managers.screen.choiceset.ChoiceSet;
import com.smartdevicelink.managers.screen.choiceset.ChoiceSetManager;
import com.smartdevicelink.managers.screen.choiceset.KeyboardListener;
import com.smartdevicelink.managers.screen.menu.DynamicMenuUpdatesMode;
import com.smartdevicelink.managers.screen.menu.MenuCell;
import com.smartdevicelink.managers.screen.menu.MenuConfiguration;
import com.smartdevicelink.managers.screen.menu.MenuManager;
import com.smartdevicelink.managers.screen.menu.VoiceCommand;
import com.smartdevicelink.managers.screen.menu.VoiceCommandManager;
import com.smartdevicelink.proxy.rpc.KeyboardProperties;
import com.smartdevicelink.proxy.rpc.TemplateConfiguration;
import com.smartdevicelink.proxy.rpc.enums.ButtonName;
import com.smartdevicelink.proxy.rpc.enums.InteractionMode;
import com.smartdevicelink.proxy.rpc.enums.MetadataType;
import com.smartdevicelink.proxy.rpc.enums.TextAlignment;
import com.smartdevicelink.util.DebugTool;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.List;
/**
* ScreenManager
*
* Note: This class must be accessed through the SdlManager. Do not instantiate it by itself.
*/
abstract class BaseScreenManager extends BaseSubManager {
private static final String TAG = "ScreenManager";
private final WeakReference fileManager;
private SoftButtonManager softButtonManager;
private TextAndGraphicManager textAndGraphicManager;
private VoiceCommandManager voiceCommandManager;
private MenuManager menuManager;
private ChoiceSetManager choiceSetManager;
private SubscribeButtonManager subscribeButtonManager;
private AlertManager alertManager;
static final int SOFT_BUTTON_ID_NOT_SET_VALUE = -1;
static final int SOFT_BUTTON_ID_MIN_VALUE = 0;
static final int SOFT_BUTTON_ID_MAX_VALUE = 10000;
static HashSet softButtonIDBySoftButtonManager;
static HashSet softButtonIDByAlertManager;
// Sub manager listener
private final CompletionListener subManagerListener = new CompletionListener() {
@Override
public synchronized void onComplete(boolean success) {
if (softButtonManager != null && textAndGraphicManager != null && voiceCommandManager != null && menuManager != null && choiceSetManager != null && subscribeButtonManager != null) {
if (softButtonManager.getState() == BaseSubManager.READY && textAndGraphicManager.getState() == BaseSubManager.READY && voiceCommandManager.getState() == BaseSubManager.READY && menuManager.getState() == BaseSubManager.READY
&& subscribeButtonManager.getState() == BaseSubManager.READY && alertManager.getState() == BaseSubManager.READY) {
DebugTool.logInfo(TAG, "Starting screen manager, all sub managers are in ready state");
transitionToState(READY);
} else if (softButtonManager.getState() == BaseSubManager.ERROR && textAndGraphicManager.getState() == BaseSubManager.ERROR && voiceCommandManager.getState() == BaseSubManager.ERROR && menuManager.getState() == BaseSubManager.ERROR
&& choiceSetManager.getState() == BaseSubManager.ERROR && subscribeButtonManager.getState() == BaseSubManager.ERROR && alertManager.getState() == BaseSubManager.ERROR) {
DebugTool.logError(TAG, "ERROR starting screen manager, all sub managers are in error state");
transitionToState(ERROR);
} else if (textAndGraphicManager.getState() == BaseSubManager.SETTING_UP || softButtonManager.getState() == BaseSubManager.SETTING_UP || voiceCommandManager.getState() == BaseSubManager.SETTING_UP || menuManager.getState() == BaseSubManager.SETTING_UP
|| choiceSetManager.getState() == BaseSubManager.SETTING_UP || subscribeButtonManager.getState() == BaseSubManager.SETTING_UP || alertManager.getState() == BaseSubManager.SETTING_UP) {
DebugTool.logInfo(TAG, "SETTING UP screen manager, at least one sub manager is still setting up");
transitionToState(SETTING_UP);
} else {
DebugTool.logWarning(TAG, "LIMITED starting screen manager, at least one sub manager is in error state and the others are ready");
transitionToState(LIMITED);
}
} else {
// We should never be here, but somehow one of the sub-sub managers is null
DebugTool.logError(TAG, "ERROR one of the screen sub managers is null");
transitionToState(ERROR);
}
}
};
BaseScreenManager(@NonNull ISdl internalInterface, @NonNull FileManager fileManager) {
super(internalInterface);
this.fileManager = new WeakReference<>(fileManager);
softButtonIDBySoftButtonManager = new HashSet<>();
softButtonIDByAlertManager = new HashSet<>();
initialize();
}
@Override
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void start(CompletionListener listener) {
super.start(listener);
this.softButtonManager.start(subManagerListener);
this.textAndGraphicManager.start(subManagerListener);
this.voiceCommandManager.start(subManagerListener);
this.menuManager.start(subManagerListener);
this.choiceSetManager.start(subManagerListener);
this.subscribeButtonManager.start(subManagerListener);
this.alertManager.start(subManagerListener);
}
private void initialize() {
if (fileManager.get() != null) {
this.softButtonManager = new SoftButtonManager(internalInterface, fileManager.get());
this.textAndGraphicManager = new TextAndGraphicManager(internalInterface, fileManager.get(), softButtonManager);
this.menuManager = new MenuManager(internalInterface, fileManager.get());
this.choiceSetManager = new ChoiceSetManager(internalInterface, fileManager.get());
this.alertManager = new AlertManager(internalInterface, fileManager.get());
}
this.subscribeButtonManager = new SubscribeButtonManager(internalInterface);
this.voiceCommandManager = new VoiceCommandManager(internalInterface);
}
/**
* Called when manager is being torn down
*/
@Override
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void dispose() {
softButtonManager.dispose();
textAndGraphicManager.dispose();
voiceCommandManager.dispose();
menuManager.dispose();
choiceSetManager.dispose();
subscribeButtonManager.dispose();
alertManager.dispose();
softButtonIDByAlertManager = null;
softButtonIDBySoftButtonManager = null;
super.dispose();
}
/**
* The top text field within a template layout. Pass an empty string "" to clear the text field.
*
* If the system does not support a full 4 fields, this will automatically be concatenated and properly send the field available.
*
* If 3 lines are available: [field1, field2, field3 - field 4]
*
* If 2 lines are available: [field1 - field2, field3 - field4]
*
* If 1 line is available: [field1 - field2 - field3 - field4]
*
* @param textField1 String value represents the textField1
*/
public void setTextField1(String textField1) {
this.softButtonManager.setCurrentMainField1(textField1);
this.textAndGraphicManager.setTextField1(textField1);
}
/**
* Get the current textField1 value
*
* @return a String value represents the current textField1 value
*/
public String getTextField1() {
return this.textAndGraphicManager.getTextField1();
}
/**
* Sets the second text field within a template layout. Pass an empty string "" to clear the text field.
*
* If the system does not support a full 4 fields, this will automatically be concatenated and properly send the field available.
*
* If 3 lines are available: [field1, field2, field3 - field 4]
*
* If 2 lines are available: [field1 - field2, field3 - field4]
*
* If 1 line is available: [field1 - field2 - field3 - field4]
*
* @param textField2 String value represents the textField1
*/
public void setTextField2(String textField2) {
this.textAndGraphicManager.setTextField2(textField2);
}
/**
* Get the current textField2 value
*
* @return a String value represents the current textField2 value
*/
public String getTextField2() {
return this.textAndGraphicManager.getTextField2();
}
/**
* Sets the third text field within a template layout. Pass an empty string "" to clear the text field.
*
* If the system does not support a full 4 fields, this will automatically be concatenated and properly send the field available.
*
* If 3 lines are available: [field1, field2, field3 - field 4]
*
* If 2 lines are available: [field1 - field2, field3 - field4]
*
* If 1 line is available: [field1 - field2 - field3 - field4]
*
* @param textField3 String value represents the textField1
*/
public void setTextField3(String textField3) {
this.textAndGraphicManager.setTextField3(textField3);
}
/**
* Get the current textField3 value
*
* @return a String value represents the current textField3 value
*/
public String getTextField3() {
return this.textAndGraphicManager.getTextField3();
}
/**
* Sets the fourth text field within a template layout. Pass an empty string "" to clear the text field.
*
* If the system does not support a full 4 fields, this will automatically be concatenated and properly send the field available.
*
* If 3 lines are available: [field1, field2, field3 - field 4]
*
* If 2 lines are available: [field1 - field2, field3 - field4]
*
* If 1 line is available: [field1 - field2 - field3 - field4]
*
* @param textField4 String value represents the textField1
*/
public void setTextField4(String textField4) {
this.textAndGraphicManager.setTextField4(textField4);
}
/**
* Get the current textField4 value
*
* @return a String value represents the current textField4 value
*/
public String getTextField4() {
return this.textAndGraphicManager.getTextField4();
}
/**
* Set the mediaTrackTextField on the head unit screen
*
* @param mediaTrackTextField String value represents the mediaTrackTextField
*/
public void setMediaTrackTextField(String mediaTrackTextField) {
this.textAndGraphicManager.setMediaTrackTextField(mediaTrackTextField);
}
/**
* Get the current mediaTrackTextField value
*
* @return a String value represents the current mediaTrackTextField
*/
public String getMediaTrackTextField() {
return this.textAndGraphicManager.getMediaTrackTextField();
}
/**
* Set the primaryGraphic on the head unit screen
*
* @param primaryGraphic an SdlArtwork object represents the primaryGraphic
*/
public void setPrimaryGraphic(SdlArtwork primaryGraphic) {
if (primaryGraphic == null) {
primaryGraphic = textAndGraphicManager.getBlankArtwork();
}
this.textAndGraphicManager.setPrimaryGraphic(primaryGraphic);
}
/**
* Get the current primaryGraphic value
*
* @return an SdlArtwork object represents the current primaryGraphic
*/
public SdlArtwork getPrimaryGraphic() {
if (this.textAndGraphicManager.getPrimaryGraphic() == null || textAndGraphicManager.getPrimaryGraphic().getName() == null || this.textAndGraphicManager.getPrimaryGraphic().getName().equals(textAndGraphicManager.getBlankArtwork().getName())) {
return null;
}
return this.textAndGraphicManager.getPrimaryGraphic();
}
/**
* Set the secondaryGraphic on the head unit screen
*
* @param secondaryGraphic an SdlArtwork object represents the secondaryGraphic
*/
public void setSecondaryGraphic(SdlArtwork secondaryGraphic) {
if (secondaryGraphic == null) {
secondaryGraphic = textAndGraphicManager.getBlankArtwork();
}
this.textAndGraphicManager.setSecondaryGraphic(secondaryGraphic);
}
/**
* Get the current secondaryGraphic value
*
* @return an SdlArtwork object represents the current secondaryGraphic
*/
public SdlArtwork getSecondaryGraphic() {
if (this.textAndGraphicManager.getSecondaryGraphic() == null || textAndGraphicManager.getSecondaryGraphic().getName() == null || this.textAndGraphicManager.getSecondaryGraphic().getName().equals(textAndGraphicManager.getBlankArtwork().getName())) {
return null;
}
return this.textAndGraphicManager.getSecondaryGraphic();
}
/**
* Set the alignment for the text fields
*
* @param textAlignment TextAlignment value represents the alignment for the text fields
*/
public void setTextAlignment(TextAlignment textAlignment) {
this.textAndGraphicManager.setTextAlignment(textAlignment);
}
/**
* Get the alignment for the text fields
*
* @return a TextAlignment value represents the alignment for the text fields
*/
public TextAlignment getTextAlignment() {
return this.textAndGraphicManager.getTextAlignment();
}
/**
* Set the metadata type for the textField1
*
* @param textField1Type a MetadataType value represents the metadata for textField1
*/
public void setTextField1Type(MetadataType textField1Type) {
this.textAndGraphicManager.setTextField1Type(textField1Type);
}
/**
* Get the metadata type for textField1
*
* @return a MetadataType value represents the metadata for textField1
*/
public MetadataType getTextField1Type() {
return this.textAndGraphicManager.getTextField1Type();
}
/**
* Set the metadata type for the textField2
*
* @param textField2Type a MetadataType value represents the metadata for textField2
*/
public void setTextField2Type(MetadataType textField2Type) {
this.textAndGraphicManager.setTextField2Type(textField2Type);
}
/**
* Get the metadata type for textField2
*
* @return a MetadataType value represents the metadata for textField2
*/
public MetadataType getTextField2Type() {
return this.textAndGraphicManager.getTextField2Type();
}
/**
* Set the metadata type for the textField3
*
* @param textField3Type a MetadataType value represents the metadata for textField3
*/
public void setTextField3Type(MetadataType textField3Type) {
this.textAndGraphicManager.setTextField3Type(textField3Type);
}
/**
* Get the metadata type for textField3
*
* @return a MetadataType value represents the metadata for textField3
*/
public MetadataType getTextField3Type() {
return this.textAndGraphicManager.getTextField3Type();
}
/**
* Set the metadata type for the textField4
*
* @param textField4Type a MetadataType value represents the metadata for textField4
*/
public void setTextField4Type(MetadataType textField4Type) {
this.textAndGraphicManager.setTextField4Type(textField4Type);
}
/**
* Get the metadata type for textField4
*
* @return a MetadataType value represents the metadata for textField4
*/
public MetadataType getTextField4Type() {
return this.textAndGraphicManager.getTextField4Type();
}
/**
* Sets the title of the new template that will be displayed.
* Sending an empty String "" will clear the field
*
* @param title the title of the new template that will be displayed. MaxLength: 100.
*/
public void setTitle(String title) {
this.textAndGraphicManager.setTitle(title);
}
/**
* Gets the title of the new template that will be displayed
*
* @return title - String value that represents the title of the new template that will be displayed
*/
public String getTitle() {
return this.textAndGraphicManager.getTitle();
}
/**
* Change the current layout to a new layout and optionally update the layout's night and day color schemes. The values set for the text, graphics,
* buttons and template title persist between layout changes. To update the text, graphics, buttons and template title at the same time as the template,
* batch all the updates between beginTransaction and commit. If the layout update fails while batching, then the updated text, graphics, buttons or template title will also not be updated.
*
* If you are connected on a < v6.0 connection and batching the update, the layout will be updated, then the text and graphics will be updated.
* If you are connected on a >= v6.0 connection, the layout will be updated at the same time that the text and graphics are updated.
*
* If this update is batched between beginTransaction and commit, the completionListener here will not be called. Use the completionListener with commit(completionListener)
*
* NOTE: If this update returns an false, it may have been superseded by another update.
* This means that it was cancelled while in-progress because another update was requested, whether batched or not.
*
* @param templateConfiguration The new configuration of the template, including the layout and color scheme.
* @param listener A listener that will be called when the layout change finished.
*/
public void changeLayout(@NonNull TemplateConfiguration templateConfiguration, CompletionListener listener) {
textAndGraphicManager.changeLayout(templateConfiguration, listener);
}
/**
* Set softButtonObjects list and upload the images to the head unit
*
* @param softButtonObjects the list of the SoftButtonObject values that should be displayed on the head unit
*/
public void setSoftButtonObjects(@NonNull List softButtonObjects) {
softButtonManager.setSoftButtonObjects(softButtonObjects);
}
/**
* Get the soft button objects list
*
* @return a List
*/
public List getSoftButtonObjects() {
return softButtonManager.getSoftButtonObjects();
}
/**
* Get the SoftButtonObject that has the provided name
*
* @param name a String value that represents the name
* @return a SoftButtonObject
*/
public SoftButtonObject getSoftButtonObjectByName(@NonNull String name) {
return softButtonManager.getSoftButtonObjectByName(name);
}
/**
* Get the SoftButtonObject that has the provided buttonId
*
* @param buttonId a int value that represents the id of the button
* @return a SoftButtonObject
*/
public SoftButtonObject getSoftButtonObjectById(int buttonId) {
return softButtonManager.getSoftButtonObjectById(buttonId);
}
/**
* Get the currently set voice commands
*
* @return a List of Voice Command objects
*/
public List getVoiceCommands() {
return voiceCommandManager.getVoiceCommands();
}
/**
* Set voice commands
*
* @param voiceCommands the voice commands to be sent to the head unit
*/
public void setVoiceCommands(@NonNull List voiceCommands) {
this.voiceCommandManager.setVoiceCommands(voiceCommands);
}
// MENUS
/**
* The list of currently set menu cells
*
* @return a List of the currently set menu cells
*/
public List getMenu() {
return this.menuManager.getMenuCells();
}
/**
* Creates and sends all associated Menu RPCs
* Note: the manager will store a deep copy the menuCells internally to be able to handle future updates correctly
*
* @param menuCells - the menu cells that are to be sent to the head unit, including their sub-cells.
*/
public void setMenu(@NonNull List menuCells) {
this.menuManager.setMenuCells(menuCells);
}
/**
* Sets the behavior of how menus are updated. For explanations of the differences, see {@link DynamicMenuUpdatesMode}
*
* @param value - the update mode
*/
public void setDynamicMenuUpdatesMode(@NonNull DynamicMenuUpdatesMode value) {
this.menuManager.setDynamicUpdatesMode(value);
}
/**
* @return The currently set DynamicMenuUpdatesMode. It defaults to ON_WITH_COMPAT_MODE if not set.
*/
public DynamicMenuUpdatesMode getDynamicMenuUpdatesMode() {
return this.menuManager.getDynamicMenuUpdatesMode();
}
/**
* Requires SDL RPC Version 6.0.0 or greater
* Opens the Main Menu.
*
* @return boolean success / failure - whether the request was able to be sent
*/
public boolean openMenu() {
return this.menuManager.openMenu();
}
/**
* Requires SDL RPC Version 6.0.0 or greater
* Opens a subMenu. The cell you pass in must be constructed with {@link MenuCell(String,SdlArtwork,List)}
*
* @param cell - A SubMenu cell whose sub menu you wish to open
* @return boolean success / failure - whether the request was able to be sent
*/
public boolean openSubMenu(@NonNull MenuCell cell) {
return this.menuManager.openSubMenu(cell);
}
/**
* The main menu layout. See available menu layouts on WindowCapability.menuLayoutsAvailable.
*
* @param menuConfiguration - The default menuConfiguration
*/
public void setMenuConfiguration(@NonNull MenuConfiguration menuConfiguration) {
this.menuManager.setMenuConfiguration(menuConfiguration);
}
/**
* The main menu layout. See available menu layouts on WindowCapability.menuLayoutsAvailable.
*
* @return the currently set MenuConfiguration
*/
public MenuConfiguration getMenuConfiguration() {
return this.menuManager.getMenuConfiguration();
}
// CHOICE SETS
/**
* Deletes choices that were sent previously
*
* @param choices - A list of ChoiceCell objects
*/
public void deleteChoices(@NonNull List choices) {
this.choiceSetManager.deleteChoices(choices);
}
/**
* Preload choices to improve performance while presenting a choice set at a later time
*
* @param choices - a list of ChoiceCell objects that will be part of a choice set later
* @param listener - a completion listener to inform when the operation is complete
*/
public void preloadChoices(@NonNull List choices, CompletionListener listener) {
this.choiceSetManager.preloadChoices(choices, listener);
}
/**
* Presents a searchable choice set
*
* @param choiceSet - The choice set to be presented. This can include Choice Cells that were preloaded or not
* @param mode - The intended interaction mode
* @param keyboardListener - A keyboard listener to capture user input
*/
public void presentSearchableChoiceSet(@NonNull ChoiceSet choiceSet, @Nullable InteractionMode mode, @NonNull KeyboardListener keyboardListener) {
this.choiceSetManager.presentChoiceSet(choiceSet, mode, keyboardListener);
}
/**
* Presents a choice set
*
* @param choiceSet - The choice set to be presented. This can include Choice Cells that were preloaded or not
* @param mode - The intended interaction mode
*/
public void presentChoiceSet(@NonNull ChoiceSet choiceSet, @Nullable InteractionMode mode) {
this.choiceSetManager.presentChoiceSet(choiceSet, mode, null);
}
/**
* Presents a keyboard on the Head unit to capture user input
*
* @param initialText - The initial text that is used as a placeholder text. It might not work on some head units.
* @param customKeyboardProperties - the custom keyboard configuration to be used when the keyboard is displayed
* @param keyboardListener - A keyboard listener to capture user input
* @return A unique cancelID that can be used to cancel this keyboard. If `null`, no keyboard was created.
*/
public Integer presentKeyboard(@NonNull String initialText, @Nullable KeyboardProperties customKeyboardProperties, @NonNull KeyboardListener keyboardListener) {
return this.choiceSetManager.presentKeyboard(initialText, customKeyboardProperties, keyboardListener);
}
/**
* Set a custom keyboard configuration for this session. If set to null, it will reset to default keyboard configuration.
*
* @param keyboardConfiguration - the custom keyboard configuration to be used when the keyboard is displayed
*/
public void setKeyboardConfiguration(@Nullable KeyboardProperties keyboardConfiguration) {
this.choiceSetManager.setKeyboardConfiguration(keyboardConfiguration);
}
/**
* @return A set of choice cells that have been preloaded to the head unit
*/
public HashSet getPreloadedChoices() {
return this.choiceSetManager.getPreloadedChoices();
}
/**
* Dismisses a currently presented keyboard with the associated ID. Canceling a keyboard only works when connected to SDL Core v.6.0+. When connected to older versions of SDL Core the keyboard will not be dismissed.
*
* @param cancelID The unique ID assigned to the keyboard
*/
public void dismissKeyboard(@NonNull Integer cancelID) {
this.choiceSetManager.dismissKeyboard(cancelID);
}
// END CHOICE SETS
/**
* Begin a multiple updates transaction. The updates will be applied when commit() is called
* Note: if we don't use beginTransaction & commit, every update will be sent individually.
*/
public void beginTransaction() {
softButtonManager.setBatchUpdates(true);
textAndGraphicManager.setBatchUpdates(true);
}
/**
* Pairs with beginTransaction() to batch text, graphic, and layout changes into a single update with a callback when the update is complete.
* Update text fields with new text set into the text field properties, updates the primary and secondary images with new image(s) if new one(s) been set,
* and updates the template if one was changed using changeLayout(TemplateConfiguration, CompletionListener).
* NOTE: The CompletionListener in changeLayout(TemplateConfiguration, CompletionListener) will not be called if the update is batched into this update
* NOTE: If this CompletionListener returns false, it may have been superseded by another update. This means that it was cancelled while in-progress because another update was requested, whether batched or not.
*
* @param listener a CompletionListener that has a callback that will be called when the updates are finished
*/
public void commit(final CompletionListener listener) {
softButtonManager.setBatchUpdates(false);
textAndGraphicManager.setBatchUpdates(false);
textAndGraphicManager.update(new CompletionListener() {
@Override
public void onComplete(boolean success) {
if (listener != null) {
listener.onComplete(success);
}
}
});
}
public void addButtonListener(@NonNull ButtonName buttonName, @NonNull OnButtonListener listener) {
subscribeButtonManager.addButtonListener(buttonName, listener);
}
public void removeButtonListener(@NonNull ButtonName buttonName, @NonNull OnButtonListener listener) {
subscribeButtonManager.removeButtonListener(buttonName, listener);
}
public void presentAlert(AlertView alert, AlertCompletionListener listener) {
alertManager.presentAlert(alert, listener);
}
@Retention(RetentionPolicy.SOURCE)
@IntDef({ManagerLocation.SOFTBUTTON_MANAGER, ManagerLocation.ALERT_MANAGER})
@interface ManagerLocation {
int SOFTBUTTON_MANAGER = 0;
int ALERT_MANAGER = 1;
}
/**
* Used across managers to check and assign SoftButton ID's to prevent conflicts.
*
* @param softButtonObjects - list of SoftButtonObjects
* @param location - location from which the button came from, so if new buttons get set on screen, we can clear the old ID's out
* @return True if ButtonID's are good, False if not.
*/
static boolean checkAndAssignButtonIds(List softButtonObjects, @ManagerLocation int location) {
HashSet buttonIdsSetHashSet = new HashSet<>();
// Depending on location form which the softButtons came from, we will clear out the id list so they can be reset
if (location == ManagerLocation.ALERT_MANAGER) {
softButtonIDByAlertManager.clear();
buttonIdsSetHashSet = (HashSet) softButtonIDBySoftButtonManager.clone();
} else if (location == ManagerLocation.SOFTBUTTON_MANAGER) {
softButtonIDBySoftButtonManager.clear();
buttonIdsSetHashSet = (HashSet) softButtonIDByAlertManager.clone();
}
// Check if multiple soft button objects have the same id
int currentSoftButtonId, numberOfButtonIdsSet = buttonIdsSetHashSet.size(), maxButtonIdsSetByDev = SOFT_BUTTON_ID_MIN_VALUE;
for (SoftButtonObject softButtonObject : softButtonObjects) {
currentSoftButtonId = softButtonObject.getButtonId();
if (currentSoftButtonId != SOFT_BUTTON_ID_NOT_SET_VALUE) {
if (softButtonIDByAlertManager.contains(currentSoftButtonId) || softButtonIDBySoftButtonManager.contains(currentSoftButtonId)) {
return false;
}
numberOfButtonIdsSet++;
if (currentSoftButtonId > maxButtonIdsSetByDev) {
maxButtonIdsSetByDev = currentSoftButtonId;
}
buttonIdsSetHashSet.add(softButtonObject.getButtonId());
}
}
if (numberOfButtonIdsSet != buttonIdsSetHashSet.size()) {
return false;
}
// Set ids for soft button objects
int generatedSoftButtonId = maxButtonIdsSetByDev;
for (SoftButtonObject softButtonObject : softButtonObjects) {
// If the dev did not set the buttonId, the manager should set an id on the dev's behalf
currentSoftButtonId = softButtonObject.getButtonId();
if (currentSoftButtonId == SOFT_BUTTON_ID_NOT_SET_VALUE) {
do {
if (generatedSoftButtonId >= SOFT_BUTTON_ID_MAX_VALUE) {
generatedSoftButtonId = SOFT_BUTTON_ID_MIN_VALUE;
}
generatedSoftButtonId++;
} while (buttonIdsSetHashSet.contains(generatedSoftButtonId));
softButtonObject.setButtonId(generatedSoftButtonId);
buttonIdsSetHashSet.add(generatedSoftButtonId);
if (location == ManagerLocation.ALERT_MANAGER) {
softButtonIDByAlertManager.add(generatedSoftButtonId);
} else if (location == ManagerLocation.SOFTBUTTON_MANAGER) {
softButtonIDBySoftButtonManager.add(generatedSoftButtonId);
}
}
}
return true;
}
}