summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Kast <Julian.kast@livio.io>2021-06-04 14:30:38 -0400
committerGitHub <noreply@github.com>2021-06-04 14:30:38 -0400
commit6522cd560f23e57ae2cd3baf618f73dc2ac51595 (patch)
treeacfc6fdf08f1aba69da8e170d5a5d628f3bc69fd
parent9e73aee1ed7218c12a7e57a212022fb6921491c4 (diff)
downloadsdl_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>
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetManagerTests.java55
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuManagerTests.java112
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/screen/choiceset/BaseChoiceSetManager.java91
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/screen/menu/BaseMenuManager.java103
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