diff options
author | Julian Kast <Julian.kast@livio.io> | 2021-06-04 14:30:38 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-04 14:30:38 -0400 |
commit | 6522cd560f23e57ae2cd3baf618f73dc2ac51595 (patch) | |
tree | acfc6fdf08f1aba69da8e170d5a5d628f3bc69fd | |
parent | 9e73aee1ed7218c12a7e57a212022fb6921491c4 (diff) | |
download | sdl_android-6522cd560f23e57ae2cd3baf618f73dc2ac51595.tar.gz |
Fix Choice Cells and Menu Cells do not take which properties are available into account for uniqueness (#1684)
* BaseChoiceSetManager, Strip away unsupported textFields from choices
* Add image checking to ChoiceSetManager uniqueness check
* MenuManager strip parameters away from uniqueness check if hmi does not support fields
* added logic to check subcells properly
* Add missing !
* Fix copy paste error with naming
* Clone choiceCell when comparing for visual uniqueness
* Clone menuCell when comparing for visual uniqueness
* update comment
* Add check for submenu
* Refactor check for uniqueness
* Add WindowCapability to menuManagerTest
* Change menuCellsAreUnique to package private and add unit test
* Update unit test
* add menuManager test
* Clean up BaseChoiceSetManager logic
* Add more unit test
* Modify menu manger unit test
* Formatting and cleanup of unitTest
* Added logic for : On RPC v7.1+ connections, we will no longer display duplicate menu cells if some property of the cell is different but that property isn't actually displayed on the head unit.
* Remove testing logic that was not meant to be uploaded.
* Fix not checking available ChoiceCell properties
* Add null checks and remove added unitTest,
* Fix subCell logic for MenuCells
* Add unit test to menuManager
* Remove testing code and add unit test for the choiceSetManager
* Update comments/alignment
* remove unused import
Co-authored-by: Julian Kast <julian@livio.com>
4 files changed, 340 insertions, 21 deletions
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetManagerTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetManagerTests.java index 16ea857f5..81f912361 100644 --- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetManagerTests.java +++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetManagerTests.java @@ -40,18 +40,23 @@ import com.livio.taskmaster.Taskmaster; import com.smartdevicelink.managers.BaseSubManager; import com.smartdevicelink.managers.ISdl; import com.smartdevicelink.managers.file.FileManager; +import com.smartdevicelink.proxy.rpc.ImageField; import com.smartdevicelink.proxy.rpc.KeyboardCapabilities; import com.smartdevicelink.proxy.rpc.KeyboardLayoutCapability; import com.smartdevicelink.proxy.rpc.KeyboardProperties; import com.smartdevicelink.proxy.rpc.SdlMsgVersion; +import com.smartdevicelink.proxy.rpc.TextField; 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.KeyboardInputMask; import com.smartdevicelink.proxy.rpc.enums.KeyboardLayout; import com.smartdevicelink.proxy.rpc.enums.KeypressMode; import com.smartdevicelink.proxy.rpc.enums.Language; import com.smartdevicelink.proxy.rpc.enums.SystemContext; +import com.smartdevicelink.proxy.rpc.enums.TextFieldName; import com.smartdevicelink.proxy.rpc.enums.TriggerSource; +import com.smartdevicelink.test.TestValues; import org.junit.After; import org.junit.Before; @@ -231,7 +236,8 @@ public class ChoiceSetManagerTests { ChoiceCell cell4 = new ChoiceCell("McDonalds", "4 mile away", null, null, null, null); ChoiceCell cell5 = new ChoiceCell("Starbucks", "5 mile away", null, null, null, null); ChoiceCell cell6 = new ChoiceCell("Meijer", "6 mile away", null, null, null, null); - LinkedHashSet<ChoiceCell> cellList = new LinkedHashSet<>(); + List<ChoiceCell> cellList = new ArrayList<>(); + cellList.add(cell1); cellList.add(cell2); cellList.add(cell3); @@ -468,4 +474,51 @@ public class ChoiceSetManagerTests { verify(testKeyboardOp, times(0)).dismissKeyboard(); verify(testKeyboardOp2, times(1)).dismissKeyboard(); } + + @Test + public void testUniquenessForAvailableFields() { + WindowCapability windowCapability = new WindowCapability(); + TextField secondaryText = new TextField(); + secondaryText.setName(TextFieldName.secondaryText); + TextField tertiaryText = new TextField(); + tertiaryText.setName(TextFieldName.tertiaryText); + + List<TextField> textFields = new ArrayList<>(); + textFields.add(secondaryText); + textFields.add(tertiaryText); + windowCapability.setTextFields(textFields); + + ImageField choiceImage = new ImageField(); + choiceImage.setName(ImageFieldName.choiceImage); + ImageField choiceSecondaryImage = new ImageField(); + choiceSecondaryImage.setName(ImageFieldName.choiceSecondaryImage); + List<ImageField> imageFieldList = new ArrayList<>(); + imageFieldList.add(choiceImage); + imageFieldList.add(choiceSecondaryImage); + windowCapability.setImageFields(imageFieldList); + + csm.defaultMainWindowCapability = windowCapability; + + ChoiceCell cell1 = new ChoiceCell("Item 1", "null", "tertiaryText", null, TestValues.GENERAL_ARTWORK, TestValues.GENERAL_ARTWORK); + ChoiceCell cell2 = new ChoiceCell("Item 1", "null2", "tertiaryText2", null, null, null); + List<ChoiceCell> choiceCellList = new ArrayList<>(); + choiceCellList.add(cell1); + choiceCellList.add(cell2); + + List<ChoiceCell> removedProperties = csm.removeUnusedProperties(choiceCellList); + assertNotNull(removedProperties.get(0).getSecondaryText()); + + textFields.remove(secondaryText); + textFields.remove(tertiaryText); + imageFieldList.remove(choiceImage); + imageFieldList.remove(choiceSecondaryImage); + + removedProperties = csm.removeUnusedProperties(choiceCellList); + csm.addUniqueNamesBasedOnStrippedCells(removedProperties, choiceCellList); + assertEquals(choiceCellList.get(1).getUniqueText(), "Item 1 (2)"); + + + } + + } diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuManagerTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuManagerTests.java index 2419023f6..e71d8295c 100644 --- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuManagerTests.java +++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuManagerTests.java @@ -43,17 +43,22 @@ import com.smartdevicelink.managers.file.filetypes.SdlArtwork; import com.smartdevicelink.protocol.enums.FunctionID; import com.smartdevicelink.proxy.RPCRequest; import com.smartdevicelink.proxy.RPCResponse; +import com.smartdevicelink.proxy.rpc.ImageField; import com.smartdevicelink.proxy.rpc.OnCommand; import com.smartdevicelink.proxy.rpc.OnHMIStatus; import com.smartdevicelink.proxy.rpc.SdlMsgVersion; import com.smartdevicelink.proxy.rpc.SetGlobalProperties; +import com.smartdevicelink.proxy.rpc.TextField; import com.smartdevicelink.proxy.rpc.WindowCapability; import com.smartdevicelink.proxy.rpc.enums.FileType; import com.smartdevicelink.proxy.rpc.enums.HMILevel; +import com.smartdevicelink.proxy.rpc.enums.ImageFieldName; import com.smartdevicelink.proxy.rpc.enums.MenuLayout; 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.test.TestValues; import org.junit.After; import org.junit.Before; @@ -63,6 +68,7 @@ import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -598,6 +604,111 @@ public class MenuManagerTests { assertEquals(menuManager.menuCells.get(3).getSubCells().get(3).getUniqueTitle(), "A"); } + @Test + public void testUniquenessForAvailableFields() { + WindowCapability windowCapability = new WindowCapability(); + TextField menuSubMenuSecondaryText = new TextField(); + menuSubMenuSecondaryText.setName(TextFieldName.menuSubMenuSecondaryText); + TextField menuSubMenuTertiaryText = new TextField(); + menuSubMenuTertiaryText.setName(TextFieldName.menuSubMenuTertiaryText); + TextField menuCommandSecondaryText = new TextField(); + menuCommandSecondaryText.setName(TextFieldName.menuCommandSecondaryText); + TextField menuCommandTertiaryText = new TextField(); + menuCommandTertiaryText.setName(TextFieldName.menuCommandTertiaryText); + List<TextField> textFields = new ArrayList<>(); + textFields.add(menuSubMenuSecondaryText); + textFields.add(menuSubMenuTertiaryText); + textFields.add(menuCommandSecondaryText); + textFields.add(menuCommandTertiaryText); + windowCapability.setTextFields(textFields); + + ImageField cmdIcon = new ImageField(); + cmdIcon.setName(ImageFieldName.cmdIcon); + ImageField menuSubMenuSecondaryImage = new ImageField(); + menuSubMenuSecondaryImage.setName(ImageFieldName.menuSubMenuSecondaryImage); + ImageField menuCommandSecondaryImage = new ImageField(); + menuCommandSecondaryImage.setName(ImageFieldName.menuCommandSecondaryImage); + List<ImageField> imageFieldList = new ArrayList<>(); + imageFieldList.add(cmdIcon); + imageFieldList.add(menuSubMenuSecondaryImage); + imageFieldList.add(menuCommandSecondaryImage); + windowCapability.setImageFields(imageFieldList); + menuManager.defaultMainWindowCapability = windowCapability; + + assertNull(menuManager.removeUnusedProperties(null)); + + MenuCell cell1 = new MenuCell("Text1", "SecondaryText", "TText", TestValues.GENERAL_ARTWORK, TestValues.GENERAL_ARTWORK, null, new MenuSelectionListener() { + @Override + public void onTriggered(TriggerSource trigger) { + + } + }); + + MenuCell cell2 = new MenuCell("Text1", "SecondaryText2", "TText2", null, null, null, new MenuSelectionListener() { + @Override + public void onTriggered(TriggerSource trigger) { + + } + }); + + MenuCell subCell1 = new MenuCell("SubCell1", "Secondary Text", "TText", TestValues.GENERAL_ARTWORK, TestValues.GENERAL_ARTWORK, null, new MenuSelectionListener() { + @Override + public void onTriggered(TriggerSource trigger) { + } + }); + + MenuCell subCell2 = new MenuCell("SubCell1", "Secondary Text2", "TText2", null, null, null, new MenuSelectionListener() { + @Override + public void onTriggered(TriggerSource trigger) { + } + }); + + List<MenuCell> subCellList = new ArrayList<>(); + subCellList.add(subCell1); + subCellList.add(subCell2); + + + MenuCell cell3 = new MenuCell("Test Cell 3 (sub menu)", "SecondaryText", "TText", MenuLayout.LIST, TestValues.GENERAL_ARTWORK, TestValues.GENERAL_ARTWORK, subCellList); + MenuCell cell4 = new MenuCell("Test Cell 3 (sub menu)", null, null, MenuLayout.LIST, null, null, subCellList); + + List<MenuCell> menuCellList = new ArrayList<>(); + menuCellList.add(cell1); + menuCellList.add(cell2); + menuCellList.add(cell3); + menuCellList.add(cell4); + + List<MenuCell> removedProperties = menuManager.removeUnusedProperties(menuCellList); + assertNotNull(removedProperties.get(0).getSecondaryText()); + menuManager.addUniqueNamesBasedOnStrippedCells(removedProperties, menuCellList); + assertEquals(menuCellList.get(1).getUniqueTitle(), "Text1"); + + // Remove menuCommandSecondaryText as a supported TextField + textFields.remove(menuCommandSecondaryText); + textFields.remove(menuCommandTertiaryText); + imageFieldList.remove(cmdIcon); + imageFieldList.remove(menuCommandSecondaryImage); + imageFieldList.remove(menuSubMenuSecondaryImage); + textFields.remove(menuSubMenuSecondaryText); + textFields.remove(menuSubMenuTertiaryText); + textFields.remove(menuSubMenuSecondaryImage); + + // Test removeUnusedProperties + removedProperties = menuManager.removeUnusedProperties(menuCellList); + assertNull(removedProperties.get(0).getSecondaryText()); + assertNull(removedProperties.get(0).getTertiaryText()); + + menuManager.addUniqueNamesBasedOnStrippedCells(removedProperties, menuCellList); + assertEquals(menuCellList.get(1).getUniqueTitle(), "Text1 (2)"); + + // SubCell test + assertEquals(menuCellList.get(3).getUniqueTitle(), "Test Cell 3 (sub menu) (2)"); + assertEquals(menuCellList.get(2).getSubCells().get(1).getUniqueTitle(), "SubCell1 (2)"); + + + } + + + // HELPERS // Emulate what happens when Core sends OnHMIStatus notification @@ -849,4 +960,5 @@ public class MenuManagerTests { return Arrays.asList(A, B, C, D); } + } 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 746d49865..893909718 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,6 +42,7 @@ 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; @@ -54,6 +55,7 @@ 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; @@ -61,11 +63,13 @@ 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; @@ -540,7 +544,7 @@ abstract class BaseChoiceSetManager extends BaseSubManager { * 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(LinkedHashSet<ChoiceCell> choices) { + void addUniqueNamesToCells(List<ChoiceCell> choices) { HashMap<String, Integer> dictCounter = new HashMap<>(); for (ChoiceCell cell : choices) { @@ -556,16 +560,80 @@ abstract class BaseChoiceSetManager extends BaseSubManager { } } + 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; + } + + List<ChoiceCell> clone = new ArrayList<>(); + for (ChoiceCell choiceCell : originalList) { + clone.add(choiceCell.clone()); + } + return clone; + } + private LinkedHashSet<ChoiceCell> getChoicesToBeUploadedWithArray(List<ChoiceCell> choices) { - LinkedHashSet<ChoiceCell> choiceSet = new LinkedHashSet<>(choices); - // If we're running on a connection < RPC 7.1, we need to de-duplicate cells because presenting them will fail if we have the same cell primary text. + // 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))) { - addUniqueNamesToCells(choiceSet); + // 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); } - choiceSet.removeAll(preloadedChoices); - return choiceSet; + 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) { @@ -672,6 +740,14 @@ 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(); @@ -695,9 +771,8 @@ abstract class BaseChoiceSetManager extends BaseSubManager { int choiceCellWithVoiceCommandCount = 0; for (ChoiceCell cell : choices) { - uniqueChoiceCells.add(cell); - + // Not using cloned cell here because we set the clone's VoiceCommands to null for visual check only if (cell.getVoiceCommands() != null) { uniqueVoiceCommands.addAll(cell.getVoiceCommands()); choiceCellWithVoiceCommandCount += 1; diff --git a/base/src/main/java/com/smartdevicelink/managers/screen/menu/BaseMenuManager.java b/base/src/main/java/com/smartdevicelink/managers/screen/menu/BaseMenuManager.java index 3c409059a..149d3fa2b 100644 --- a/base/src/main/java/com/smartdevicelink/managers/screen/menu/BaseMenuManager.java +++ b/base/src/main/java/com/smartdevicelink/managers/screen/menu/BaseMenuManager.java @@ -176,11 +176,9 @@ abstract class BaseMenuManager extends BaseSubManager { // Create a deep copy of the list so future changes by developers don't affect the algorithm logic List<MenuCell> clonedCells = cloneMenuCellsList(cells); - // If we're running on a connection < RPC 7.1, we need to de-duplicate cells because presenting them will fail if we have the same cell primary text. - if (clonedCells != null && internalInterface.getSdlMsgVersion() != null - && (internalInterface.getSdlMsgVersion().getMajorVersion() < 7 - || (internalInterface.getSdlMsgVersion().getMajorVersion() == 7 && internalInterface.getSdlMsgVersion().getMinorVersion() == 0))) { - addUniqueNamesToCells(clonedCells); + // Check for cell lists with completely duplicate information, or any duplicate voiceCommands and return if it fails (logs are in the called method). + if (clonedCells != null && !menuCellsAreUnique(clonedCells, new ArrayList<String>())) { + return; } if (currentHMILevel == null || currentHMILevel.equals(HMILevel.HMI_NONE) || currentSystemContext.equals(SystemContext.SYSCTXT_MENU)) { @@ -194,6 +192,23 @@ abstract class BaseMenuManager extends BaseSubManager { } waitingOnHMIUpdate = false; + // If we're running on a connection < RPC 7.1, we need to de-duplicate cells because presenting them will fail if we have the same cell primary text. + if (clonedCells != null && internalInterface.getSdlMsgVersion() != null + && (internalInterface.getSdlMsgVersion().getMajorVersion() < 7 + || (internalInterface.getSdlMsgVersion().getMajorVersion() == 7 && internalInterface.getSdlMsgVersion().getMinorVersion() == 0))) { + addUniqueNamesToCellsWithDuplicatePrimaryText(clonedCells); + } else { + // On > RPC 7.1, at this point all cells are unique when considering all properties, + // but we also need to check if any cells will _appear_ as duplicates when displayed on the screen. + // To check that, we'll remove properties from the set cells based on the system capabilities + // (we probably don't need to consider them changing between now and when they're actually sent to the HU unless the menu layout changes) + // and check for uniqueness again. Then we'll add unique identifiers to primary text if there are duplicates. + // Then we transfer the primary text identifiers back to the main cells and add those to an operation to be sent. + List<MenuCell> strippedCellsClone = removeUnusedProperties(clonedCells); + addUniqueNamesBasedOnStrippedCells(strippedCellsClone, clonedCells); + + } + // Update our Lists // set old list if (menuCells != null) { @@ -205,11 +220,6 @@ abstract class BaseMenuManager extends BaseSubManager { menuCells.addAll(clonedCells); } - // Check for cell lists with completely duplicate information, or any duplicate voiceCommands and return if it fails (logs are in the called method). - if (!menuCellsAreUnique(menuCells, new ArrayList<String>())) { - return; - } - // Upload the Artworks List<SdlArtwork> artworksToBeUploaded = findAllArtworksToBeUploadedFromCells(menuCells); if (artworksToBeUploaded.size() > 0 && fileManager.get() != null) { @@ -1441,7 +1451,7 @@ abstract class BaseMenuManager extends BaseSubManager { return clone; } - private void addUniqueNamesToCells(List<MenuCell> cells) { + private void addUniqueNamesToCellsWithDuplicatePrimaryText(List<MenuCell> cells) { HashMap<String, Integer> dictCounter = new HashMap<>(); for (MenuCell cell : cells) { @@ -1456,11 +1466,80 @@ abstract class BaseMenuManager extends BaseSubManager { } if (cell.getSubCells() != null && cell.getSubCells().size() > 0) { - addUniqueNamesToCells(cell.getSubCells()); + addUniqueNamesToCellsWithDuplicatePrimaryText(cell.getSubCells()); } } } + void addUniqueNamesBasedOnStrippedCells(List<MenuCell> strippedCells, List<MenuCell> 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<MenuCell, Integer> dictCounter = new HashMap<>(); + for (int i = 0; i < strippedCells.size(); i++) { + MenuCell cell = strippedCells.get(i); + Integer counter = dictCounter.get(cell); + if (counter != null) { + counter = counter + 1; + dictCounter.put(cell, counter); + } else { + dictCounter.put(cell, 1); + } + counter = dictCounter.get(cell); + if (counter > 1) { + unstrippedCells.get(i).setUniqueTitle(unstrippedCells.get(i).getTitle() + " (" + counter + ")"); + } + + if (cell.getSubCells() != null && cell.getSubCells().size() > 0) { + addUniqueNamesBasedOnStrippedCells(cell.getSubCells(), unstrippedCells.get(i).getSubCells()); + } + + } + + + } + + List<MenuCell> removeUnusedProperties(List<MenuCell> menuCells) { + if (menuCells == null) { + return null; + } + List<MenuCell> removePropertiesClone = cloneMenuCellsList(menuCells); + for (MenuCell cell : removePropertiesClone) { + // Strip away fields that cannot be used to determine uniqueness visually including fields not supported by the HMI + cell.setVoiceCommands(null); + + // Don't check ImageFieldName.subMenuIcon because it was added in 7.0 when the feature was added in 5.0. + // Just assume that if cmdIcon is not available, the submenu icon is not either. + if (!hasImageFieldOfName(ImageFieldName.cmdIcon)) { + cell.setIcon(null); + } + // Check for subMenu fields supported + if (cell.getSubCells() != null) { + if (!hasTextFieldOfName(TextFieldName.menuSubMenuSecondaryText)) { + cell.setSecondaryText(null); + } + if (!hasTextFieldOfName(TextFieldName.menuSubMenuTertiaryText)) { + cell.setTertiaryText(null); + } + if (!hasImageFieldOfName(ImageFieldName.menuSubMenuSecondaryImage)) { + cell.setSecondaryArtwork(null); + } + cell.setSubCells(removeUnusedProperties(cell.getSubCells())); + } else { + if (!hasTextFieldOfName(TextFieldName.menuCommandSecondaryText)) { + cell.setSecondaryText(null); + } + if (!hasTextFieldOfName(TextFieldName.menuCommandTertiaryText)) { + cell.setTertiaryText(null); + } + if (!hasImageFieldOfName(ImageFieldName.menuCommandSecondaryImage)) { + cell.setSecondaryArtwork(null); + } + } + } + return removePropertiesClone; + } /** * Check for cell lists with completely duplicate information, or any duplicate voiceCommands |