diff options
Diffstat (limited to 'base/src/main/java/com/smartdevicelink/managers/screen/choiceset/BaseChoiceSetManager.java')
-rw-r--r-- | base/src/main/java/com/smartdevicelink/managers/screen/choiceset/BaseChoiceSetManager.java | 309 |
1 files changed, 65 insertions, 244 deletions
diff --git a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/BaseChoiceSetManager.java b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/BaseChoiceSetManager.java index 893909718..0aae71751 100644 --- a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/BaseChoiceSetManager.java +++ b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/BaseChoiceSetManager.java @@ -42,7 +42,6 @@ import com.livio.taskmaster.Task; import com.smartdevicelink.managers.BaseSubManager; import com.smartdevicelink.managers.CompletionListener; import com.smartdevicelink.managers.ISdl; -import com.smartdevicelink.managers.ManagerUtility; import com.smartdevicelink.managers.file.FileManager; import com.smartdevicelink.managers.lifecycle.OnSystemCapabilityListener; import com.smartdevicelink.managers.lifecycle.SystemCapabilityManager; @@ -55,7 +54,6 @@ import com.smartdevicelink.proxy.rpc.KeyboardProperties; import com.smartdevicelink.proxy.rpc.OnHMIStatus; import com.smartdevicelink.proxy.rpc.WindowCapability; import com.smartdevicelink.proxy.rpc.enums.HMILevel; -import com.smartdevicelink.proxy.rpc.enums.ImageFieldName; import com.smartdevicelink.proxy.rpc.enums.InteractionMode; import com.smartdevicelink.proxy.rpc.enums.KeyboardLayout; import com.smartdevicelink.proxy.rpc.enums.KeypressMode; @@ -63,14 +61,12 @@ import com.smartdevicelink.proxy.rpc.enums.Language; import com.smartdevicelink.proxy.rpc.enums.PredefinedWindows; import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType; import com.smartdevicelink.proxy.rpc.enums.SystemContext; -import com.smartdevicelink.proxy.rpc.enums.TextFieldName; import com.smartdevicelink.proxy.rpc.enums.TriggerSource; import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener; import com.smartdevicelink.util.DebugTool; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; @@ -94,18 +90,14 @@ abstract class BaseChoiceSetManager extends BaseSubManager { WindowCapability defaultMainWindowCapability; String displayName; SystemContext currentSystemContext; - HashSet<ChoiceCell> preloadedChoices, pendingPreloadChoices; - ChoiceSet pendingPresentationSet; + HashSet<ChoiceCell> preloadedChoices; // We will pass operations into this to be completed final Queue transactionQueue; - Task pendingPresentOperation; PresentKeyboardOperation currentlyPresentedKeyboardOperation; - int nextChoiceId; int nextCancelId; - final int choiceCellIdMin = 1; private final int choiceCellCancelIdMin = 101; private final int choiceCellCancelIdMax = 200; boolean isVROptional; @@ -126,8 +118,6 @@ abstract class BaseChoiceSetManager extends BaseSubManager { // setting/instantiating class vars this.fileManager = new WeakReference<>(fileManager); preloadedChoices = new HashSet<>(); - pendingPreloadChoices = new HashSet<>(); - nextChoiceId = choiceCellIdMin; nextCancelId = choiceCellCancelIdMin; isVROptional = false; @@ -151,10 +141,8 @@ abstract class BaseChoiceSetManager extends BaseSubManager { currentSystemContext = null; defaultMainWindowCapability = null; - pendingPresentationSet = null; - pendingPresentOperation = null; + preloadedChoices = null; isVROptional = false; - nextChoiceId = choiceCellIdMin; nextCancelId = choiceCellCancelIdMin; // remove listeners @@ -191,6 +179,10 @@ abstract class BaseChoiceSetManager extends BaseSubManager { transactionQueue.add(checkChoiceVR, false); } + interface ChoicesOperationCompletionListener { + void onComplete(boolean success, HashSet<ChoiceCell> loadedChoiceCells); + } + /** * Preload choices to improve performance while presenting a choice set at a later time * @@ -203,12 +195,7 @@ abstract class BaseChoiceSetManager extends BaseSubManager { return; } - LinkedHashSet<ChoiceCell> mutableChoicesToUpload = getChoicesToBeUploadedWithArray(choices); - - mutableChoicesToUpload.removeAll(preloadedChoices); - mutableChoicesToUpload.removeAll(pendingPreloadChoices); - - final LinkedHashSet<ChoiceCell> choicesToUpload = (LinkedHashSet<ChoiceCell>) mutableChoicesToUpload.clone(); + final LinkedHashSet<ChoiceCell> choicesToUpload = new LinkedHashSet<>(choices); if (choicesToUpload.size() == 0) { if (listener != null) { @@ -217,26 +204,17 @@ abstract class BaseChoiceSetManager extends BaseSubManager { return; } - updateIdsOnChoices(choicesToUpload); - - // Add the preload cells to the pending preload choices - pendingPreloadChoices.addAll(choicesToUpload); - if (fileManager.get() != null) { - PreloadChoicesOperation preloadChoicesOperation = new PreloadChoicesOperation(internalInterface, fileManager.get(), displayName, defaultMainWindowCapability, isVROptional, choicesToUpload, new CompletionListener() { + PreloadPresentChoicesOperation preloadChoicesOperation = new PreloadPresentChoicesOperation(internalInterface, fileManager.get(), displayName, defaultMainWindowCapability, isVROptional, choicesToUpload, this.preloadedChoices, new ChoicesOperationCompletionListener() { @Override - public void onComplete(boolean success) { - if (success) { - preloadedChoices.addAll(choicesToUpload); - pendingPreloadChoices.removeAll(choicesToUpload); - if (listener != null) { - listener.onComplete(true); - } - } else { - DebugTool.logError(TAG, "There was an error pre loading choice cells"); - if (listener != null) { - listener.onComplete(false); + public void onComplete(boolean success, HashSet<ChoiceCell> loadedCells) { + preloadedChoices = loadedCells; + updatePendingTasksWithCurrentPreloads(); + if (listener != null) { + if (!success) { + DebugTool.logError(TAG, "There was an error pre loading choice cells"); } + listener.onComplete(success); } } }); @@ -259,45 +237,15 @@ abstract class BaseChoiceSetManager extends BaseSubManager { return; } - // Find cells to be deleted that are already uploaded or are pending upload - final HashSet<ChoiceCell> cellsToBeDeleted = choicesToBeDeletedWithArray(choices); - HashSet<ChoiceCell> cellsToBeRemovedFromPending = choicesToBeRemovedFromPendingWithArray(choices); - // If choices are deleted that are already uploaded or pending and are used by a pending presentation, cancel it and send an error - HashSet<ChoiceCell> pendingPresentationChoices = new HashSet<>(); - if (pendingPresentationSet != null && pendingPresentationSet.getChoices() != null) { - pendingPresentationChoices.addAll(pendingPresentationSet.getChoices()); - } - - if (pendingPresentOperation != null && pendingPresentOperation.getState() != Task.CANCELED && pendingPresentOperation.getState() != Task.FINISHED && (cellsToBeDeleted.retainAll(pendingPresentationChoices) || cellsToBeRemovedFromPending.retainAll(pendingPresentationChoices))) { - pendingPresentOperation.cancelTask(); - DebugTool.logWarning(TAG, "Attempting to delete choice cells while there is a pending presentation operation. Pending presentation cancelled."); - pendingPresentOperation = null; - } - - // Remove cells from pending and delete choices - pendingPresentationChoices.removeAll(cellsToBeRemovedFromPending); - for (Task operation : transactionQueue.getTasksAsList()) { - if (!(operation instanceof PreloadChoicesOperation)) { - continue; - } - ((PreloadChoicesOperation) operation).removeChoicesFromUpload(cellsToBeRemovedFromPending); - } - - // Find Choices to delete - if (cellsToBeDeleted.size() == 0) { - DebugTool.logInfo(TAG, "Cells to be deleted size == 0"); - return; - } - findIdsOnChoices(cellsToBeDeleted); - - DeleteChoicesOperation deleteChoicesOperation = new DeleteChoicesOperation(internalInterface, cellsToBeDeleted, new CompletionListener() { + DeleteChoicesOperation deleteChoicesOperation = new DeleteChoicesOperation(internalInterface, new HashSet<>(choices), preloadedChoices, new ChoicesOperationCompletionListener() { @Override - public void onComplete(boolean success) { + public void onComplete(boolean success, HashSet<ChoiceCell> updatedLoadedChoiceCells) { if (!success) { DebugTool.logError(TAG, "Failed to delete choices"); return; } - preloadedChoices.removeAll(cellsToBeDeleted); + preloadedChoices = updatedLoadedChoiceCells; + updatePendingTasksWithCurrentPreloads(); } }); transactionQueue.add(deleteChoicesOperation, false); @@ -322,63 +270,56 @@ abstract class BaseChoiceSetManager extends BaseSubManager { return; } - if (this.pendingPresentationSet != null && pendingPresentOperation != null) { - pendingPresentOperation.cancelTask(); - DebugTool.logWarning(TAG, "Presenting a choice set while one is currently presented. Cancelling previous and continuing"); - } - - this.pendingPresentationSet = choiceSet; - preloadChoices(this.pendingPresentationSet.getChoices(), new CompletionListener() { - @Override - public void onComplete(boolean success) { - if (!success) { - choiceSet.getChoiceSetSelectionListener().onError("There was an error pre-loading choice set choices"); - } else { - sendPresentOperation(keyboardListener, mode); - } - } - }); + sendPresentOperation(choiceSet, keyboardListener, mode); } - private void sendPresentOperation(KeyboardListener keyboardListener, InteractionMode mode) { + private void sendPresentOperation(final ChoiceSet choiceSet, KeyboardListener keyboardListener, InteractionMode mode) { if (mode == null) { mode = InteractionMode.MANUAL_ONLY; } - findIdsOnChoiceSet(pendingPresentationSet); - // Pass back the information to the developer - ChoiceSetSelectionListener privateChoiceListener = new ChoiceSetSelectionListener() { + ChoiceSetSelectionListener listener = new ChoiceSetSelectionListener() { @Override public void onChoiceSelected(ChoiceCell choiceCell, TriggerSource triggerSource, int rowIndex) { - if (pendingPresentationSet != null && pendingPresentationSet.getChoiceSetSelectionListener() != null) { - pendingPresentationSet.getChoiceSetSelectionListener().onChoiceSelected(choiceCell, triggerSource, rowIndex); + if (choiceSet != null && choiceSet.getChoiceSetSelectionListener() != null) { + choiceSet.getChoiceSetSelectionListener().onChoiceSelected(choiceCell, triggerSource, rowIndex); } } @Override public void onError(String error) { - if (pendingPresentationSet != null && pendingPresentationSet.getChoiceSetSelectionListener() != null) { - pendingPresentationSet.getChoiceSetSelectionListener().onError(error); + if (choiceSet != null && choiceSet.getChoiceSetSelectionListener() != null) { + if (error != null) { + choiceSet.getChoiceSetSelectionListener().onError(error); + } else if (getState() == SHUTDOWN) { + choiceSet.getChoiceSetSelectionListener().onError("Incorrect State"); + } else { + DebugTool.logError(TAG, "Present finished but an unhandled state occurred and callback failed"); + choiceSet.getChoiceSetSelectionListener().onError("callback failed"); + } } } }; - PresentChoiceSetOperation presentOp; + PreloadPresentChoicesOperation presentOp; - if (keyboardListener == null) { - // Non-searchable choice set - DebugTool.logInfo(TAG, "Creating non-searchable choice set"); - presentOp = new PresentChoiceSetOperation(internalInterface, pendingPresentationSet, mode, null, null, privateChoiceListener, getNextCancelId()); + if (fileManager.get() != null) { + if (keyboardListener == null) { + // Non-searchable choice set + DebugTool.logInfo(TAG, "Creating non-searchable choice set"); + presentOp = new PreloadPresentChoicesOperation(internalInterface, fileManager.get(), choiceSet, mode, null, null, getNextCancelId(), displayName, defaultMainWindowCapability, isVROptional, this.preloadedChoices, null, listener); + } else { + // Searchable choice set + DebugTool.logInfo(TAG, "Creating searchable choice set"); + presentOp = new PreloadPresentChoicesOperation(internalInterface, this.fileManager.get(), choiceSet, mode, keyboardConfiguration, keyboardListener, getNextCancelId(), displayName, defaultMainWindowCapability, isVROptional, this.preloadedChoices, null, listener); + } + + transactionQueue.add(presentOp, false); } else { - // Searchable choice set - DebugTool.logInfo(TAG, "Creating searchable choice set"); - presentOp = new PresentChoiceSetOperation(internalInterface, pendingPresentationSet, mode, keyboardConfiguration, keyboardListener, privateChoiceListener, getNextCancelId()); + DebugTool.logError(TAG, "File Manager was null in preload choice operation"); } - - transactionQueue.add(presentOp, false); - pendingPresentOperation = presentOp; } /** @@ -400,12 +341,6 @@ abstract class BaseChoiceSetManager extends BaseSubManager { return null; } - if (pendingPresentationSet != null && pendingPresentOperation != null) { - pendingPresentOperation.cancelTask(); - pendingPresentationSet = null; - DebugTool.logWarning(TAG, "There is a current or pending choice set, cancelling and continuing."); - } - customKeyboardConfig = createValidKeyboardConfigurationBasedOnKeyboardCapabilitiesFromConfiguration(customKeyboardConfig); if (customKeyboardConfig == null) { if (this.keyboardConfiguration != null) { @@ -421,7 +356,6 @@ abstract class BaseChoiceSetManager extends BaseSubManager { PresentKeyboardOperation keyboardOp = new PresentKeyboardOperation(internalInterface, keyboardConfiguration, initialText, customKeyboardConfig, listener, keyboardCancelID); currentlyPresentedKeyboardOperation = keyboardOp; transactionQueue.add(keyboardOp, false); - pendingPresentOperation = keyboardOp; return keyboardCancelID; } @@ -527,63 +461,6 @@ abstract class BaseChoiceSetManager extends BaseSubManager { // CHOICE SET MANAGEMENT HELPERS - HashSet<ChoiceCell> choicesToBeDeletedWithArray(List<ChoiceCell> choices) { - HashSet<ChoiceCell> choicesSet = new HashSet<>(choices); - choicesSet.retainAll(this.preloadedChoices); - return choicesSet; - } - - HashSet<ChoiceCell> choicesToBeRemovedFromPendingWithArray(List<ChoiceCell> choices) { - HashSet<ChoiceCell> choicesSet = new HashSet<>(choices); - choicesSet.retainAll(this.pendingPreloadChoices); - return choicesSet; - } - - /** - * Checks if 2 or more cells have the same text/title. In case this condition is true, this function will handle the presented issue by adding "(count)". - * E.g. Choices param contains 2 cells with text/title "Address" will be handled by updating the uniqueText/uniqueTitle of the second cell to "Address (2)". - * @param choices The list of choiceCells to be uploaded. - */ - void addUniqueNamesToCells(List<ChoiceCell> choices) { - HashMap<String, Integer> dictCounter = new HashMap<>(); - - for (ChoiceCell cell : choices) { - String cellName = cell.getText(); - Integer counter = dictCounter.get(cellName); - - if (counter != null) { - dictCounter.put(cellName, ++counter); - cell.setUniqueText(cell.getText() + " (" + counter + ")"); - } else { - dictCounter.put(cellName, 1); - } - } - } - - void addUniqueNamesBasedOnStrippedCells(List<ChoiceCell> strippedCells, List<ChoiceCell> unstrippedCells) { - if (strippedCells == null || unstrippedCells == null || strippedCells.size() != unstrippedCells.size()) { - return; - } - // Tracks how many of each cell primary text there are so that we can append numbers to make each unique as necessary - HashMap<ChoiceCell, Integer> dictCounter = new HashMap<>(); - for (int i = 0; i < strippedCells.size(); i++) { - ChoiceCell cell = strippedCells.get(i); - Integer counter = dictCounter.get(cell); - if (counter != null) { - counter++; - dictCounter.put(cell, counter); - } else { - dictCounter.put(cell, 1); - } - - counter = dictCounter.get(cell); - - if (counter > 1) { - unstrippedCells.get(i).setUniqueText(unstrippedCells.get(i).getText() + " (" + counter + ")"); - } - } - } - private List<ChoiceCell> cloneChoiceCellList(List<ChoiceCell> originalList) { if (originalList == null) { return null; @@ -596,71 +473,6 @@ abstract class BaseChoiceSetManager extends BaseSubManager { return clone; } - private LinkedHashSet<ChoiceCell> getChoicesToBeUploadedWithArray(List<ChoiceCell> choices) { - // Clone choices - List<ChoiceCell> choicesClone = cloneChoiceCellList(choices); - if (choices != null && internalInterface.getSdlMsgVersion() != null - && (internalInterface.getSdlMsgVersion().getMajorVersion() < 7 - || (internalInterface.getSdlMsgVersion().getMajorVersion() == 7 && internalInterface.getSdlMsgVersion().getMinorVersion() == 0))) { - // If we're on < RPC 7.1, all primary texts need to be unique, so we don't need to check removed properties and duplicate cells - addUniqueNamesToCells(choicesClone); - } else { - List<ChoiceCell> strippedCellsClone = removeUnusedProperties(choicesClone); - addUniqueNamesBasedOnStrippedCells(strippedCellsClone, choicesClone); - } - LinkedHashSet<ChoiceCell> choiceCloneLinkedHash = new LinkedHashSet<>(choicesClone); - choiceCloneLinkedHash.removeAll(preloadedChoices); - return choiceCloneLinkedHash; - } - - List<ChoiceCell> removeUnusedProperties(List<ChoiceCell> choiceCells) { - List<ChoiceCell> strippedCellsClone = cloneChoiceCellList(choiceCells); - //Clone Cells - for (ChoiceCell cell : strippedCellsClone) { - // Strip away fields that cannot be used to determine uniqueness visually including fields not supported by the HMI - cell.setVoiceCommands(null); - - if (!hasImageFieldOfName(ImageFieldName.choiceImage)) { - cell.setArtwork(null); - } - if (!hasTextFieldOfName(TextFieldName.secondaryText)) { - cell.setSecondaryText(null); - } - if (!hasTextFieldOfName(TextFieldName.tertiaryText)) { - cell.setTertiaryText(null); - } - if (!hasImageFieldOfName(ImageFieldName.choiceSecondaryImage)) { - cell.setSecondaryArtwork(null); - } - } - return strippedCellsClone; - } - - void updateIdsOnChoices(LinkedHashSet<ChoiceCell> choices) { - for (ChoiceCell cell : choices) { - cell.setChoiceId(this.nextChoiceId); - this.nextChoiceId++; - } - } - - private void findIdsOnChoiceSet(ChoiceSet choiceSet) { - findIdsOnChoices(new HashSet<>(choiceSet.getChoices())); - } - - private void findIdsOnChoices(HashSet<ChoiceCell> choices) { - for (ChoiceCell cell : choices) { - ChoiceCell uploadCell = null; - if (pendingPreloadChoices.contains(cell)) { - uploadCell = findIfPresent(cell, pendingPreloadChoices); - } else if (preloadedChoices.contains(cell)) { - uploadCell = findIfPresent(cell, preloadedChoices); - } - if (uploadCell != null) { - cell.setChoiceId(uploadCell.getChoiceId()); - } - } - } - ChoiceCell findIfPresent(ChoiceCell cell, HashSet<ChoiceCell> set) { if (set.contains(cell)) { for (ChoiceCell setCell : set) { @@ -671,6 +483,22 @@ abstract class BaseChoiceSetManager extends BaseSubManager { return null; } + private void updatePendingTasksWithCurrentPreloads() { + for (Task task : this.transactionQueue.getTasksAsList()) { + if (task.getState() == Task.IN_PROGRESS || task.getState() == Task.CANCELED) { + continue; + } + + if (task instanceof PreloadPresentChoicesOperation) { + PreloadPresentChoicesOperation preloadOp = (PreloadPresentChoicesOperation) task; + preloadOp.setLoadedCells(this.preloadedChoices); + } else if (task instanceof DeleteChoicesOperation) { + DeleteChoicesOperation deleteOp = (DeleteChoicesOperation) task; + deleteOp.setLoadedCells(this.preloadedChoices); + } + } + } + // LISTENERS private void addListeners() { @@ -740,14 +568,6 @@ abstract class BaseChoiceSetManager extends BaseSubManager { // ADDITIONAL HELPERS - private boolean hasImageFieldOfName(ImageFieldName imageFieldName) { - return defaultMainWindowCapability == null || ManagerUtility.WindowCapabilityUtility.hasImageFieldOfName(defaultMainWindowCapability, imageFieldName); - } - - private boolean hasTextFieldOfName(TextFieldName textFieldName) { - return defaultMainWindowCapability == null || ManagerUtility.WindowCapabilityUtility.hasTextFieldOfName(defaultMainWindowCapability, textFieldName); - } - boolean setUpChoiceSet(ChoiceSet choiceSet) { List<ChoiceCell> choices = choiceSet.getChoices(); @@ -765,8 +585,9 @@ abstract class BaseChoiceSetManager extends BaseSubManager { } } - HashSet<ChoiceCell> uniqueChoiceCells = new HashSet<>(); HashSet<String> uniqueVoiceCommands = new HashSet<>(); + HashSet<ChoiceCell> uniqueChoiceCells = new HashSet<>(); + int allVoiceCommandsCount = 0; int choiceCellWithVoiceCommandCount = 0; |