summaryrefslogtreecommitdiff
path: root/android/sdl_android
diff options
context:
space:
mode:
Diffstat (limited to 'android/sdl_android')
-rw-r--r--android/sdl_android/build.gradle4
-rw-r--r--android/sdl_android/gradle.properties2
-rw-r--r--android/sdl_android/libs/TaskMaster-0.5.jarbin17590 -> 0 bytes
-rw-r--r--android/sdl_android/libs/Taskmaster-0.6.jarbin0 -> 17636 bytes
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java36
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/filetypes/SdlArtworkTests.java3
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/lifecycle/SystemCapabilityManagerTests.java31
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/ScreenManagerTests.java10
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/TextAndGraphicManagerTests.java1
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceCellTests.java27
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetManagerTests.java178
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/DeleteChoicesOperationTests.java2
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PreloadChoicesOperationTests.java193
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PreloadPresentChoicesOperationTests.java443
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PresentChoiceSetOperationTests.java295
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/DynamicMenuUpdateRunScoreTests.java (renamed from android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/RunScoreTests.java)16
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuCellTests.java41
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuConfigurationUpdateOperationTests.java225
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuManagerTests.java710
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuReplaceOperationTests.java287
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuReplaceUtilitiesTests.java343
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuShowOperationTests.java144
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/SubCellCommandListTests.java63
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/video/HapticInterfaceManagerTest.java59
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/TestValues.java102
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java73
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/SecurityQueryPayloadTests.java126
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryErrorCodeTests.java189
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryIDTests.java91
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryTypeTests.java97
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/VehicleTypeTest.java14
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java119
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java37
-rw-r--r--android/sdl_android/src/androidTest/res/xml/supported_vehicle_type.xml12
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java2
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java13
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java21
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java27
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java3
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/protocol/heartbeat/HeartbeatMonitor.java2
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java5
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java47
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java109
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java8
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java2
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/transport/utl/SdlDeviceListener.java103
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java169
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java2
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java193
-rw-r--r--android/sdl_android/src/main/res/values/sdl.xml3
50 files changed, 3295 insertions, 1387 deletions
diff --git a/android/sdl_android/build.gradle b/android/sdl_android/build.gradle
index 73665a4b7..489da844e 100644
--- a/android/sdl_android/build.gradle
+++ b/android/sdl_android/build.gradle
@@ -5,7 +5,7 @@ android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 30
- versionCode 20
+ versionCode 21
versionName new File(projectDir.path, ('/../../VERSION')).text.trim()
buildConfigField "String", "VERSION_NAME", '\"' + versionName + '\"'
resValue "string", "SDL_LIB_VERSION", '\"' + versionName + '\"'
@@ -42,7 +42,7 @@ android {
dependencies {
api fileTree(dir: 'libs', include: ['*.jar'])
- //api 'com.livio.taskmaster:taskmaster:0.4.0'
+ //api 'com.livio.taskmaster:taskmaster:0.6.0'
api 'com.smartdevicelink:bson_java_port:1.2.5'
api 'androidx.lifecycle:lifecycle-extensions:2.2.0'
api 'androidx.annotation:annotation:1.1.0'
diff --git a/android/sdl_android/gradle.properties b/android/sdl_android/gradle.properties
index 3136c040b..d93b695d2 100644
--- a/android/sdl_android/gradle.properties
+++ b/android/sdl_android/gradle.properties
@@ -1,6 +1,6 @@
GROUP=com.smartdevicelink
POM_ARTIFACT_ID=sdl_android
-VERSION_NAME=5.2.0
+VERSION_NAME=5.3.0
POM_NAME=sdl_android
POM_PACKAGING=aar
diff --git a/android/sdl_android/libs/TaskMaster-0.5.jar b/android/sdl_android/libs/TaskMaster-0.5.jar
deleted file mode 100644
index a7881051b..000000000
--- a/android/sdl_android/libs/TaskMaster-0.5.jar
+++ /dev/null
Binary files differ
diff --git a/android/sdl_android/libs/Taskmaster-0.6.jar b/android/sdl_android/libs/Taskmaster-0.6.jar
new file mode 100644
index 000000000..8f249d0f7
--- /dev/null
+++ b/android/sdl_android/libs/Taskmaster-0.6.jar
Binary files differ
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java
index 90bedd434..b3d489eaa 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java
@@ -851,6 +851,42 @@ public class FileManagerTests {
}
/**
+ * Tests to make sure files are not being uploaded to head unit multiple times in a row
+ */
+ @Test
+ public void testFileNotOnHmi() {
+ final ISdl internalInterface = createISdlMock();
+
+ doAnswer(onListFilesSuccess).when(internalInterface).sendRPC(any(ListFiles.class));
+ doAnswer(onPutFileSuccess).when(internalInterface).sendRPC(any(PutFile.class));
+
+ final SdlArtwork validFile2 = new SdlArtwork(TestValues.GENERAL_STRING + "2", FileType.GRAPHIC_JPEG, TestValues.GENERAL_STRING.getBytes(), false);
+
+ final List<SdlArtwork> list = Arrays.asList(validFile2, validFile2);
+
+ FileManagerConfig fileManagerConfig = new FileManagerConfig();
+
+ final FileManager fileManager = new FileManager(internalInterface, mTestContext, fileManagerConfig);
+ fileManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ fileManager.uploadArtworks(list, new MultipleFileCompletionListener() {
+ @Override
+ public void onComplete(final Map<String, String> errors) {
+ assertOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ verify(internalInterface, times(1)).sendRPC(any(PutFile.class));
+ }
+ });
+ }
+ });
+ }
+ });
+ }
+
+
+ /**
* Test custom overridden SdlFile equals method
*/
@Test
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/filetypes/SdlArtworkTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/filetypes/SdlArtworkTests.java
index f4fb5e3d2..49a10ab3d 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/filetypes/SdlArtworkTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/filetypes/SdlArtworkTests.java
@@ -37,6 +37,9 @@ public class SdlArtworkTests {
}
public static boolean equalTest(SdlArtwork original, SdlArtwork clone) {
+ if (original == null && clone == null) {
+ return true;
+ }
assertNotNull(original);
assertNotNull(clone);
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/lifecycle/SystemCapabilityManagerTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/lifecycle/SystemCapabilityManagerTests.java
index 65f9c7bb4..03854d3ee 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/lifecycle/SystemCapabilityManagerTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/lifecycle/SystemCapabilityManagerTests.java
@@ -32,6 +32,7 @@ import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
import com.smartdevicelink.proxy.rpc.SetDisplayLayoutResponse;
import com.smartdevicelink.proxy.rpc.SoftButtonCapabilities;
import com.smartdevicelink.proxy.rpc.SystemCapability;
+import com.smartdevicelink.proxy.rpc.TextField;
import com.smartdevicelink.proxy.rpc.VideoStreamingCapability;
import com.smartdevicelink.proxy.rpc.WindowCapability;
import com.smartdevicelink.proxy.rpc.WindowTypeCapabilities;
@@ -52,6 +53,7 @@ import com.smartdevicelink.proxy.rpc.enums.ServiceUpdateReason;
import com.smartdevicelink.proxy.rpc.enums.SpeechCapabilities;
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.WindowType;
import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
import com.smartdevicelink.proxy.rpc.listeners.OnRPCListener;
@@ -689,6 +691,35 @@ public class SystemCapabilityManagerTests {
verify(internalInterface, times(0)).sendRPC(any(GetSystemCapability.class));
}
+ /**
+ * Test to verify that we can get null for templatesAvailable without hitting an NPE and
+ * test media field conversion for NON_MEDIA to NON-MEDIA for Sync bug.
+ */
+ @Test
+ public void testMediaFieldConversion() {
+ SystemCapabilityManager systemCapabilityManager = new SystemCapabilityManager(new InternalSDLInterface());
+
+ RegisterAppInterfaceResponse raiResponse = new RegisterAppInterfaceResponse();
+ DisplayCapabilities displayCapabilities = new DisplayCapabilities();
+ displayCapabilities.setGraphicSupported(false);
+ TextField textField = new TextField();
+ textField.setName(TextFieldName.mainField1);
+ displayCapabilities.setTextFields(Collections.singletonList(textField));
+ raiResponse.setDisplayCapabilities(displayCapabilities);
+ raiResponse.setSuccess(true);
+ systemCapabilityManager.parseRAIResponse(raiResponse);
+
+ WindowCapability windowCapability = systemCapabilityManager.getDefaultMainWindowCapability();
+ assertNull(windowCapability.getTemplatesAvailable());
+
+ List<String> templates = new ArrayList<>();
+ templates.add("NON_MEDIA");
+ displayCapabilities.setTemplatesAvailable(templates);
+ systemCapabilityManager.parseRAIResponse(raiResponse);
+ windowCapability = systemCapabilityManager.getDefaultMainWindowCapability();
+ assertTrue(windowCapability.getTemplatesAvailable().contains("NON-MEDIA"));
+ }
+
@Test
public void testListConversion() {
SystemCapabilityManager systemCapabilityManager = createSampleManager();
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/ScreenManagerTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/ScreenManagerTests.java
index 6ccf93aeb..b5cecf26c 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/ScreenManagerTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/ScreenManagerTests.java
@@ -68,14 +68,15 @@ public class ScreenManagerTests {
assertNull(screenManager.getTextField2Type());
assertNull(screenManager.getTextField3Type());
assertNull(screenManager.getTextField4Type());
- assertNull(screenManager.getMenu());
+ assertTrue(screenManager.getMenu().isEmpty());
assertNull(screenManager.getVoiceCommands());
assertTrue(screenManager.getSoftButtonObjects().isEmpty());
assertNull(screenManager.getSoftButtonObjectByName("test"));
assertNull(screenManager.getSoftButtonObjectById(1));
assertEquals(screenManager.getDynamicMenuUpdatesMode(), DynamicMenuUpdatesMode.ON_WITH_COMPAT_MODE);
assertEquals(screenManager.getState(), BaseSubManager.READY);
- assertNull(screenManager.getMenuConfiguration());
+ assertNull(screenManager.getMenuConfiguration().getMenuLayout());
+ assertNull(screenManager.getMenuConfiguration().getSubMenuLayout());
}
@Test
@@ -147,10 +148,9 @@ public class ScreenManagerTests {
screenManager.setMenu(TestValues.GENERAL_MENUCELL_LIST);
screenManager.setMenuConfiguration(TestValues.GENERAL_MENU_CONFIGURATION);
- assertEquals(screenManager.getMenu(), TestValues.GENERAL_MENUCELL_LIST);
assertEquals(screenManager.getDynamicMenuUpdatesMode(), DynamicMenuUpdatesMode.FORCE_ON);
- // Should not set because of improper RAI response and improper HMI states
- assertNull(screenManager.getMenuConfiguration());
+ assertEquals(screenManager.getMenu(), TestValues.GENERAL_MENUCELL_LIST);
+ assertEquals(screenManager.getMenuConfiguration(), TestValues.GENERAL_MENU_CONFIGURATION);
}
@Test
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/TextAndGraphicManagerTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/TextAndGraphicManagerTests.java
index 9b948f808..3999e7d2c 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/TextAndGraphicManagerTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/TextAndGraphicManagerTests.java
@@ -275,6 +275,7 @@ public class TextAndGraphicManagerTests {
@Test
public void testOperationManagement() {
+ textAndGraphicManager.transactionQueue.pause();
textAndGraphicManager.isDirty = true;
textAndGraphicManager.updateOperation = null;
textAndGraphicManager.update(null);
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceCellTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceCellTests.java
index 0dde875ea..a761b1f88 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceCellTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceCellTests.java
@@ -61,7 +61,7 @@ public class ChoiceCellTests {
choiceCell.setVoiceCommands(TestValues.GENERAL_STRING_LIST);
choiceCell.setArtwork(artwork);
choiceCell.setSecondaryArtwork(artwork);
- choiceCell.setUniqueText(TestValues.GENERAL_STRING);
+ choiceCell.setUniqueTextId(TestValues.GENERAL_INT);
// use getters and assert equality
assertEquals(choiceCell.getText(), TestValues.GENERAL_STRING);
@@ -71,7 +71,7 @@ public class ChoiceCellTests {
assertEquals(choiceCell.getArtwork(), artwork);
assertEquals(choiceCell.getSecondaryArtwork(), artwork);
assertEquals(choiceCell.getChoiceId(), MAX_ID);
- assertEquals(choiceCell.getUniqueText(), TestValues.GENERAL_STRING);
+ assertEquals(choiceCell.getUniqueTextId(), TestValues.GENERAL_INTEGER);
}
@Test
@@ -121,14 +121,27 @@ public class ChoiceCellTests {
choiceCell3.setSecondaryText(TestValues.GENERAL_STRING);
choiceCell3.setTertiaryText(TestValues.GENERAL_STRING);
- //UniqueText should not be taken into consideration when checking equality
- choiceCell.setUniqueText(TestValues.GENERAL_STRING);
- choiceCell2.setUniqueText(TestValues.GENERAL_STRING);
- choiceCell3.setUniqueText(TestValues.GENERAL_STRING);
-
// Make sure our overridden method works, even though these are different objects in memory
assertTrue(choiceCell.equals(choiceCell2));
assertFalse(choiceCell.equals(choiceCell3));
}
+
+ @Test
+ public void testGetUniqueCellText() {
+ ChoiceCell choiceCell = new ChoiceCell("Test");
+ ChoiceCell choiceCell2 = new ChoiceCell("Test");
+ choiceCell2.setUniqueTextId(2);
+ ChoiceCell choiceCell3 = new ChoiceCell("Test");
+ choiceCell3.setUniqueTextId(3);
+
+ assertEquals((int) choiceCell.getUniqueTextId(), 1);
+ assertEquals(choiceCell.getUniqueText(), "Test");
+
+ assertEquals((int) choiceCell2.getUniqueTextId(), 2);
+ assertEquals(choiceCell2.getUniqueText(), "Test (2)");
+
+ assertEquals((int) choiceCell3.getUniqueTextId(), 3);
+ assertEquals(choiceCell3.getUniqueText(), "Test (3)");
+ }
}
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 81f912361..f26a7a5c5 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
@@ -38,25 +38,21 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.livio.taskmaster.Taskmaster;
import com.smartdevicelink.managers.BaseSubManager;
+import com.smartdevicelink.managers.CompletionListener;
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;
@@ -68,13 +64,10 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertNotNull;
-import static junit.framework.TestCase.assertNotSame;
import static junit.framework.TestCase.assertNull;
import static junit.framework.TestCase.assertTrue;
import static org.mockito.Mockito.doReturn;
@@ -103,16 +96,12 @@ public class ChoiceSetManagerTests {
assertEquals(csm.getState(), BaseSubManager.SETTING_UP);
assertEquals(csm.currentSystemContext, SystemContext.SYSCTXT_MAIN);
assertEquals(csm.currentHMILevel, HMILevel.HMI_NONE);
- assertEquals(csm.choiceCellIdMin, 1);
- assertEquals(csm.nextChoiceId, 1);
assertFalse(csm.isVROptional);
assertNotNull(csm.fileManager);
assertNotNull(csm.preloadedChoices);
- assertNotNull(csm.pendingPreloadChoices);
assertNotNull(csm.transactionQueue);
assertNotNull(csm.hmiListener);
assertNotNull(csm.onDisplayCapabilityListener);
- assertNull(csm.pendingPresentOperation);
}
@After
@@ -123,11 +112,8 @@ public class ChoiceSetManagerTests {
assertNull(csm.currentHMILevel);
assertNull(csm.currentSystemContext);
assertNull(csm.defaultMainWindowCapability);
- assertNull(csm.pendingPresentationSet);
- assertNull(csm.pendingPresentOperation);
assertEquals(csm.transactionQueue.getTasksAsList().size(), 0);
- assertEquals(csm.nextChoiceId, 1);
assertFalse(csm.isVROptional);
@@ -160,12 +146,6 @@ public class ChoiceSetManagerTests {
ChoiceSet choiceSet1 = new ChoiceSet("test", Collections.<ChoiceCell>emptyList(), choiceSetSelectionListener);
assertFalse(csm.setUpChoiceSet(choiceSet1));
- // Identical cells will not be allowed
- ChoiceCell cell1 = new ChoiceCell("test");
- ChoiceCell cell2 = new ChoiceCell("test");
- ChoiceSet choiceSet2 = new ChoiceSet("test", Arrays.asList(cell1, cell2), choiceSetSelectionListener);
- assertFalse(csm.setUpChoiceSet(choiceSet2));
-
// cells that have duplicate text will be allowed if there is another property to make them unique because a unique name will be assigned and used
ChoiceCell cell3 = new ChoiceCell("test");
cell3.setSecondaryText("text 1");
@@ -208,103 +188,56 @@ public class ChoiceSetManagerTests {
}
@Test
- public void testUpdateIdsOnChoices() {
-
+ public void preloadChoicesAddsToQueue() {
ChoiceCell cell1 = new ChoiceCell("test");
ChoiceCell cell2 = new ChoiceCell("test2");
ChoiceCell cell3 = new ChoiceCell("test3");
- LinkedHashSet<ChoiceCell> cellSet = new LinkedHashSet<>();
+ ArrayList<ChoiceCell> cellSet = new ArrayList<>();
cellSet.add(cell1);
cellSet.add(cell2);
cellSet.add(cell3);
- // Cells are initially set to MAX_ID
- assertEquals(cell1.getChoiceId(), 2000000000);
- assertEquals(cell2.getChoiceId(), 2000000000);
- assertEquals(cell3.getChoiceId(), 2000000000);
- csm.updateIdsOnChoices(cellSet);
- // We are looking for unique IDs
- assertNotSame(cell1.getChoiceId(), 2000000000);
- assertNotSame(cell2.getChoiceId(), 2000000000);
- assertNotSame(cell3.getChoiceId(), 2000000000);
- }
+ csm.preloadChoices(cellSet, new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
- @Test
- public void testAddUniqueNamesToCells() {
- ChoiceCell cell1 = new ChoiceCell("McDonalds", "1 mile away", null, null, null, null);
- ChoiceCell cell2 = new ChoiceCell("McDonalds", "2 mile away", null, null, null, null);
- ChoiceCell cell3 = new ChoiceCell("Starbucks", "3 mile away", null, null, null, null);
- 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);
- List<ChoiceCell> cellList = new ArrayList<>();
-
- cellList.add(cell1);
- cellList.add(cell2);
- cellList.add(cell3);
- cellList.add(cell4);
- cellList.add(cell5);
- cellList.add(cell6);
-
- csm.addUniqueNamesToCells(cellList);
-
- assertEquals(cell1.getUniqueText(), "McDonalds");
- assertEquals(cell2.getUniqueText(), "McDonalds (2)");
- assertEquals(cell3.getUniqueText(), "Starbucks");
- assertEquals(cell4.getUniqueText(), "McDonalds (3)");
- assertEquals(cell5.getUniqueText(), "Starbucks (2)");
- assertEquals(cell6.getUniqueText(), "Meijer");
+ }
+ });
+ assertEquals(csm.transactionQueue.getTasksAsList().size(), 1);
}
@Test
- public void testChoicesToBeRemovedFromPendingWithArray() {
-
- ChoiceCell cell1 = new ChoiceCell("test");
- ChoiceCell cell2 = new ChoiceCell("test2");
- ChoiceCell cell3 = new ChoiceCell("test3");
-
- HashSet<ChoiceCell> pendingPreloadSet = new HashSet<>();
- pendingPreloadSet.add(cell1);
- pendingPreloadSet.add(cell2);
- pendingPreloadSet.add(cell3);
-
- csm.pendingPreloadChoices.clear();
- csm.pendingPreloadChoices = pendingPreloadSet;
-
- List<ChoiceCell> choices = new ArrayList<>();
- choices.add(cell2);
-
- HashSet<ChoiceCell> returnedChoices = csm.choicesToBeRemovedFromPendingWithArray(choices);
+ public void preloadChoicesQueueEmptyWhenNoChoiceCells() {
+ ArrayList<ChoiceCell> cellSet = new ArrayList<>();
+ csm.preloadChoices(cellSet, new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
- assertEquals(returnedChoices.size(), 1);
- for (ChoiceCell cell : returnedChoices) {
- assertEquals(cell.getText(), "test2");
- }
+ }
+ });
+ assertEquals(csm.transactionQueue.getTasksAsList().size(), 0);
}
@Test
- public void testChoicesToBeUploadedWithArray() {
-
+ public void testPreloadChoicesQueueEmptyIfFileManagerNull() {
ChoiceCell cell1 = new ChoiceCell("test");
ChoiceCell cell2 = new ChoiceCell("test2");
ChoiceCell cell3 = new ChoiceCell("test3");
+ ArrayList<ChoiceCell> cellSet = new ArrayList<>();
+ cellSet.add(cell1);
+ cellSet.add(cell2);
+ cellSet.add(cell3);
- HashSet<ChoiceCell> pendingDeleteSet = new HashSet<>();
- pendingDeleteSet.add(cell1);
- pendingDeleteSet.add(cell2);
- pendingDeleteSet.add(cell3);
-
- csm.preloadedChoices.clear();
- csm.preloadedChoices = pendingDeleteSet;
-
- List<ChoiceCell> choices = new ArrayList<>();
- choices.add(cell2);
-
- HashSet<ChoiceCell> returnedChoices = csm.choicesToBeDeletedWithArray(choices);
+ ISdl internalInterface = mock(ISdl.class);
+ when(internalInterface.getTaskmaster()).thenReturn(taskmaster);
+ FileManager fileManager = null;
+ ChoiceSetManager newCSM = new ChoiceSetManager(internalInterface, fileManager);
+ newCSM.preloadChoices(cellSet, new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
- assertEquals(returnedChoices.size(), 1);
- for (ChoiceCell cell : returnedChoices) {
- assertEquals(cell.getText(), "test2");
- }
+ }
+ });
+ assertEquals(csm.transactionQueue.getTasksAsList().size(), 0);
}
@Test
@@ -474,51 +407,4 @@ 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/choiceset/DeleteChoicesOperationTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/DeleteChoicesOperationTests.java
index 2b472eda8..fdb141b07 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/DeleteChoicesOperationTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/DeleteChoicesOperationTests.java
@@ -66,7 +66,7 @@ public class DeleteChoicesOperationTests {
cellsToDelete.add(cell2);
ISdl internalInterface = mock(ISdl.class);
- deleteChoicesOperation = new DeleteChoicesOperation(internalInterface, cellsToDelete, null);
+ deleteChoicesOperation = new DeleteChoicesOperation(internalInterface, cellsToDelete, null, null);
}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PreloadChoicesOperationTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PreloadChoicesOperationTests.java
deleted file mode 100644
index 9e879a73a..000000000
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PreloadChoicesOperationTests.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * 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.
- *
- * Created by brettywhite on 6/12/19 1:52 PM
- *
- */
-
-package com.smartdevicelink.managers.screen.choiceset;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.smartdevicelink.managers.ISdl;
-import com.smartdevicelink.managers.file.FileManager;
-import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
-import com.smartdevicelink.managers.file.filetypes.SdlFile;
-import com.smartdevicelink.proxy.rpc.ImageField;
-import com.smartdevicelink.proxy.rpc.TextField;
-import com.smartdevicelink.proxy.rpc.WindowCapability;
-import com.smartdevicelink.proxy.rpc.enums.CharacterSet;
-import com.smartdevicelink.proxy.rpc.enums.FileType;
-import com.smartdevicelink.proxy.rpc.enums.ImageFieldName;
-import com.smartdevicelink.proxy.rpc.enums.ImageType;
-import com.smartdevicelink.proxy.rpc.enums.TextFieldName;
-import com.smartdevicelink.test.TestValues;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertFalse;
-import static junit.framework.TestCase.assertNotNull;
-import static junit.framework.TestCase.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-@RunWith(AndroidJUnit4.class)
-public class PreloadChoicesOperationTests {
-
- private PreloadChoicesOperation preloadChoicesOperation;
- private PreloadChoicesOperation preloadChoicesOperationNullCapability;
- private PreloadChoicesOperation preloadChoicesOperationEmptyCapability;
-
-
- @Before
- public void setUp() throws Exception {
-
- ChoiceCell cell1 = new ChoiceCell("cell 1");
- ChoiceCell cell2 = new ChoiceCell("cell 2", null, TestValues.GENERAL_ARTWORK);
- LinkedHashSet<ChoiceCell> cellsToPreload = new LinkedHashSet<>();
- cellsToPreload.add(cell1);
- cellsToPreload.add(cell2);
-
- ImageField imageField = new ImageField(ImageFieldName.choiceImage, Arrays.asList(FileType.GRAPHIC_PNG, FileType.GRAPHIC_JPEG));
- ImageField imageField2 = new ImageField();
- imageField2.setName(ImageFieldName.choiceSecondaryImage);
- TextField textField = new TextField(TextFieldName.menuName, CharacterSet.CID1SET, 2, 2);
-
- TextField textField2 = new TextField();
- TextField textField3 = new TextField();
-
- textField2.setName(TextFieldName.secondaryText);
- textField3.setName(TextFieldName.tertiaryText);
-
-
- WindowCapability windowCapability = new WindowCapability();
- windowCapability.setImageFields(Arrays.asList(imageField, imageField2));
- windowCapability.setImageTypeSupported(Arrays.asList(ImageType.STATIC, ImageType.DYNAMIC));
- windowCapability.setTextFields(Arrays.asList(textField, textField2, textField3));
-
- ISdl internalInterface = mock(ISdl.class);
- FileManager fileManager = mock(FileManager.class);
-
- // We still want the mock fileManager to use the real implementation for fileNeedsUpload()
- when(fileManager.fileNeedsUpload(any(SdlFile.class))).thenCallRealMethod();
-
- preloadChoicesOperation = new PreloadChoicesOperation(internalInterface, fileManager, null, windowCapability, true, cellsToPreload, null);
- }
-
- /**
- * Sets up PreloadChoicesOperation with WindowCapability being null
- */
- public void setUpNullWindowCapability() {
-
- ChoiceCell cell1 = new ChoiceCell("cell 1");
- ChoiceCell cell2 = new ChoiceCell("cell 2", null, TestValues.GENERAL_ARTWORK);
- LinkedHashSet<ChoiceCell> cellsToPreload = new LinkedHashSet<>();
- cellsToPreload.add(cell1);
- cellsToPreload.add(cell2);
-
- ISdl internalInterface = mock(ISdl.class);
- FileManager fileManager = mock(FileManager.class);
- preloadChoicesOperationNullCapability = new PreloadChoicesOperation(internalInterface, fileManager, null, null, true, cellsToPreload, null);
- }
-
- /**
- * Sets up PreloadChoicesOperation with an Capability not being set
- * certain imageFields and TextFields
- */
- public void setUpEmptyWindowCapability() {
-
- ChoiceCell cell1 = new ChoiceCell("cell 1");
- ChoiceCell cell2 = new ChoiceCell("cell 2", null, TestValues.GENERAL_ARTWORK);
- LinkedHashSet<ChoiceCell> cellsToPreload = new LinkedHashSet<>();
- cellsToPreload.add(cell1);
- cellsToPreload.add(cell2);
-
- ImageField imageField = new ImageField();
- imageField.setName(ImageFieldName.alertIcon);
-
- TextField textField = new TextField();
- textField.setName(TextFieldName.mainField1);
-
- WindowCapability windowCapability = new WindowCapability();
- windowCapability.setImageFields(Collections.singletonList(imageField));
- windowCapability.setTextFields(Collections.singletonList(textField));
-
- ISdl internalInterface = mock(ISdl.class);
- FileManager fileManager = mock(FileManager.class);
- preloadChoicesOperationEmptyCapability = new PreloadChoicesOperation(internalInterface, fileManager, null, windowCapability, true, cellsToPreload, null);
- }
-
- @Test
- public void testArtworksToUpload() {
- List<SdlArtwork> artworksToUpload = preloadChoicesOperation.artworksToUpload();
- assertNotNull(artworksToUpload);
- assertEquals(artworksToUpload.size(), 1);
- }
-
- /**
- * Testing shouldSend method's with varying WindowCapability set.
- */
- @Test
- public void testShouldSendText() {
-
- setUpNullWindowCapability();
- assertTrue(preloadChoicesOperationNullCapability.shouldSendChoicePrimaryImage());
- assertTrue(preloadChoicesOperationNullCapability.shouldSendChoiceSecondaryImage());
- assertTrue(preloadChoicesOperationNullCapability.shouldSendChoiceSecondaryText());
- assertTrue(preloadChoicesOperationNullCapability.shouldSendChoiceTertiaryText());
- assertTrue(preloadChoicesOperationNullCapability.shouldSendChoiceText());
-
-
- assertTrue(preloadChoicesOperation.shouldSendChoicePrimaryImage());
- assertTrue(preloadChoicesOperation.shouldSendChoiceSecondaryImage());
- assertTrue(preloadChoicesOperation.shouldSendChoiceSecondaryText());
- assertTrue(preloadChoicesOperation.shouldSendChoiceTertiaryText());
- assertTrue(preloadChoicesOperation.shouldSendChoiceText());
-
- setUpEmptyWindowCapability();
- assertFalse(preloadChoicesOperationEmptyCapability.shouldSendChoicePrimaryImage());
- assertFalse(preloadChoicesOperationEmptyCapability.shouldSendChoiceSecondaryImage());
- assertFalse(preloadChoicesOperationEmptyCapability.shouldSendChoiceSecondaryText());
- assertFalse(preloadChoicesOperationEmptyCapability.shouldSendChoiceTertiaryText());
- assertFalse(preloadChoicesOperationEmptyCapability.shouldSendChoiceText());
- }
-
-}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PreloadPresentChoicesOperationTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PreloadPresentChoicesOperationTests.java
new file mode 100644
index 000000000..0f3725f53
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PreloadPresentChoicesOperationTests.java
@@ -0,0 +1,443 @@
+package com.smartdevicelink.managers.screen.choiceset;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.livio.taskmaster.Queue;
+import com.livio.taskmaster.Task;
+import com.livio.taskmaster.Taskmaster;
+import com.smartdevicelink.managers.ISdl;
+import com.smartdevicelink.managers.file.FileManager;
+import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
+import com.smartdevicelink.managers.file.filetypes.SdlFile;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCResponse;
+import com.smartdevicelink.proxy.rpc.CancelInteraction;
+import com.smartdevicelink.proxy.rpc.ImageField;
+import com.smartdevicelink.proxy.rpc.KeyboardProperties;
+import com.smartdevicelink.proxy.rpc.PerformInteraction;
+import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
+import com.smartdevicelink.proxy.rpc.TextField;
+import com.smartdevicelink.proxy.rpc.WindowCapability;
+import com.smartdevicelink.proxy.rpc.enums.CharacterSet;
+import com.smartdevicelink.proxy.rpc.enums.FileType;
+import com.smartdevicelink.proxy.rpc.enums.ImageFieldName;
+import com.smartdevicelink.proxy.rpc.enums.ImageType;
+import com.smartdevicelink.proxy.rpc.enums.InteractionMode;
+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.LayoutMode;
+import com.smartdevicelink.proxy.rpc.enums.TextFieldName;
+import com.smartdevicelink.test.TestValues;
+import com.smartdevicelink.util.Version;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertNull;
+import static junit.framework.TestCase.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(AndroidJUnit4.class)
+public class PreloadPresentChoicesOperationTests {
+
+ private PreloadPresentChoicesOperation preloadChoicesOperation;
+ private PreloadPresentChoicesOperation preloadChoicesOperationNullCapability;
+ private PreloadPresentChoicesOperation preloadChoicesOperationEmptyCapability;
+
+ private PreloadPresentChoicesOperation presentChoicesOperation;
+ private ChoiceSet choiceSet;
+ private ISdl internalInterface;
+ private FileManager fileManager;
+ private KeyboardListener keyboardListener;
+ private ChoiceSetSelectionListener choiceSetSelectionListener;
+
+ private Taskmaster taskmaster;
+ private Queue queue;
+
+ @Before
+ public void setUp() throws Exception {
+ ChoiceCell cell1 = new ChoiceCell("cell 1");
+ ChoiceCell cell2 = new ChoiceCell("cell 2", null, TestValues.GENERAL_ARTWORK);
+ LinkedHashSet<ChoiceCell> cellsToPreload = new LinkedHashSet<>();
+ cellsToPreload.add(cell1);
+ cellsToPreload.add(cell2);
+
+ ImageField imageField = new ImageField(ImageFieldName.choiceImage, Arrays.asList(FileType.GRAPHIC_PNG, FileType.GRAPHIC_JPEG));
+ ImageField imageField2 = new ImageField();
+ imageField2.setName(ImageFieldName.choiceSecondaryImage);
+ TextField textField = new TextField(TextFieldName.menuName, CharacterSet.CID1SET, 2, 2);
+
+ TextField textField2 = new TextField();
+ TextField textField3 = new TextField();
+
+ textField2.setName(TextFieldName.secondaryText);
+ textField3.setName(TextFieldName.tertiaryText);
+
+
+ WindowCapability windowCapability = new WindowCapability();
+ windowCapability.setImageFields(Arrays.asList(imageField, imageField2));
+ windowCapability.setImageTypeSupported(Arrays.asList(ImageType.STATIC, ImageType.DYNAMIC));
+ windowCapability.setTextFields(Arrays.asList(textField, textField2, textField3));
+
+ internalInterface = mock(ISdl.class);
+ fileManager = mock(FileManager.class);
+
+ // We still want the mock fileManager to use the real implementation for fileNeedsUpload()
+ when(fileManager.fileNeedsUpload(any(SdlFile.class))).thenCallRealMethod();
+
+ preloadChoicesOperation = new PreloadPresentChoicesOperation(internalInterface, fileManager, null, windowCapability, true, cellsToPreload, null, null);
+
+ keyboardListener = mock(KeyboardListener.class);
+ choiceSetSelectionListener = mock(ChoiceSetSelectionListener.class);
+
+ ChoiceCell cell = new ChoiceCell("Cell1");
+ cell.setChoiceId(0);
+ choiceSet = new ChoiceSet("Test", Collections.singletonList(cell), choiceSetSelectionListener);
+
+ taskmaster = new Taskmaster.Builder().build();
+ queue = taskmaster.createQueue("test", 100, false);
+ taskmaster.start();
+ }
+
+ private KeyboardProperties getKeyBoardProperties() {
+ KeyboardProperties properties = new KeyboardProperties();
+ properties.setLanguage(Language.EN_US);
+ properties.setKeyboardLayout(KeyboardLayout.QWERTZ);
+ properties.setKeypressMode(KeypressMode.RESEND_CURRENT_ENTRY);
+ return properties;
+ }
+
+ /**
+ * Sets up PreloadChoicesOperation with WindowCapability being null
+ */
+ public void setUpNullWindowCapability() {
+
+ ChoiceCell cell1 = new ChoiceCell("cell 1");
+ ChoiceCell cell2 = new ChoiceCell("cell 2", null, TestValues.GENERAL_ARTWORK);
+ LinkedHashSet<ChoiceCell> cellsToPreload = new LinkedHashSet<>();
+ cellsToPreload.add(cell1);
+ cellsToPreload.add(cell2);
+
+ ISdl internalInterface = mock(ISdl.class);
+ preloadChoicesOperationNullCapability = new PreloadPresentChoicesOperation(internalInterface, fileManager, null, null, true, cellsToPreload, null, null);
+ }
+
+ /**
+ * Sets up PreloadChoicesOperation with an Capability not being set
+ * certain imageFields and TextFields
+ */
+ public void setUpEmptyWindowCapability() {
+
+ ChoiceCell cell1 = new ChoiceCell("cell 1");
+ ChoiceCell cell2 = new ChoiceCell("cell 2", null, TestValues.GENERAL_ARTWORK);
+ LinkedHashSet<ChoiceCell> cellsToPreload = new LinkedHashSet<>();
+ cellsToPreload.add(cell1);
+ cellsToPreload.add(cell2);
+
+ ImageField imageField = new ImageField();
+ imageField.setName(ImageFieldName.alertIcon);
+
+ TextField textField = new TextField();
+ textField.setName(TextFieldName.mainField1);
+
+ WindowCapability windowCapability = new WindowCapability();
+ windowCapability.setImageFields(Collections.singletonList(imageField));
+ windowCapability.setTextFields(Collections.singletonList(textField));
+
+ ISdl internalInterface = mock(ISdl.class);
+ preloadChoicesOperationEmptyCapability = new PreloadPresentChoicesOperation(internalInterface, fileManager, null, windowCapability, true, cellsToPreload, null, null);
+ }
+
+ @Test
+ public void testArtworksToUpload() {
+ HashSet<SdlArtwork> artworksToUpload = preloadChoicesOperation.artworksToUpload();
+ assertNotNull(artworksToUpload);
+ assertEquals(artworksToUpload.size(), 1);
+ }
+
+ /**
+ * Testing shouldSend method's with varying WindowCapability set.
+ */
+ @Test
+ public void testShouldSendText() {
+
+ setUpNullWindowCapability();
+ assertTrue(preloadChoicesOperationNullCapability.shouldSendChoicePrimaryImage());
+ assertTrue(preloadChoicesOperationNullCapability.shouldSendChoiceSecondaryImage());
+ assertTrue(preloadChoicesOperationNullCapability.shouldSendChoiceSecondaryText());
+ assertTrue(preloadChoicesOperationNullCapability.shouldSendChoiceTertiaryText());
+ assertTrue(preloadChoicesOperationNullCapability.shouldSendChoiceText());
+
+
+ assertTrue(preloadChoicesOperation.shouldSendChoicePrimaryImage());
+ assertTrue(preloadChoicesOperation.shouldSendChoiceSecondaryImage());
+ assertTrue(preloadChoicesOperation.shouldSendChoiceSecondaryText());
+ assertTrue(preloadChoicesOperation.shouldSendChoiceTertiaryText());
+ assertTrue(preloadChoicesOperation.shouldSendChoiceText());
+
+ setUpEmptyWindowCapability();
+ assertFalse(preloadChoicesOperationEmptyCapability.shouldSendChoicePrimaryImage());
+ assertFalse(preloadChoicesOperationEmptyCapability.shouldSendChoiceSecondaryImage());
+ assertFalse(preloadChoicesOperationEmptyCapability.shouldSendChoiceSecondaryText());
+ assertFalse(preloadChoicesOperationEmptyCapability.shouldSendChoiceTertiaryText());
+ assertFalse(preloadChoicesOperationEmptyCapability.shouldSendChoiceText());
+ }
+
+
+ @Test
+ public void testGetLayoutMode() {
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(7, 1));
+ // First we will check knowing our keyboard listener is NOT NULL
+ WindowCapability windowCapability = new WindowCapability();
+ HashSet<ChoiceCell> loadedCells = new HashSet<>();
+ presentChoicesOperation = new PreloadPresentChoicesOperation(internalInterface, fileManager, choiceSet, InteractionMode.MANUAL_ONLY, getKeyBoardProperties(), keyboardListener, TestValues.GENERAL_INTEGER, null, windowCapability, true, loadedCells, null, null);
+
+ assertEquals(presentChoicesOperation.getLayoutMode(), LayoutMode.LIST_WITH_SEARCH);
+ presentChoicesOperation.keyboardListener = null;
+ assertEquals(presentChoicesOperation.getLayoutMode(), LayoutMode.LIST_ONLY);
+ }
+
+ @Test
+ public void testGetPerformInteraction() {
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(7, 1));
+ WindowCapability windowCapability = new WindowCapability();
+ HashSet<ChoiceCell> loadedCells = new HashSet<>();
+ presentChoicesOperation = new PreloadPresentChoicesOperation(internalInterface, fileManager, choiceSet, InteractionMode.MANUAL_ONLY, getKeyBoardProperties(), keyboardListener, TestValues.GENERAL_INTEGER, null, windowCapability, true, loadedCells, null, null);
+
+ PerformInteraction pi = presentChoicesOperation.getPerformInteraction();
+ assertEquals(pi.getInitialText(), "Test");
+ assertNull(pi.getHelpPrompt());
+ assertNull(pi.getTimeoutPrompt());
+ assertNull(pi.getVrHelp());
+ assertEquals(pi.getTimeout(), Integer.valueOf(10000));
+ assertEquals(pi.getCancelID(), TestValues.GENERAL_INTEGER);
+ assertEquals(presentChoicesOperation.getLayoutMode(), LayoutMode.LIST_WITH_SEARCH);
+ }
+
+ @Test
+ public void testSetSelectedCellWithId() {
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(7, 1));
+ WindowCapability windowCapability = new WindowCapability();
+ HashSet<ChoiceCell> loadedCells = new HashSet<>();
+ presentChoicesOperation = new PreloadPresentChoicesOperation(internalInterface, fileManager, choiceSet, InteractionMode.MANUAL_ONLY, getKeyBoardProperties(), keyboardListener, TestValues.GENERAL_INTEGER, null, windowCapability, true, loadedCells, null, null);
+
+ assertNull(presentChoicesOperation.selectedCellRow);
+ presentChoicesOperation.setSelectedCellWithId(0);
+ assertEquals(presentChoicesOperation.selectedCellRow, Integer.valueOf(0));
+ }
+
+ private void sleep() {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void testCancelingChoiceSetSuccessfullyIfThreadIsRunning() {
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
+ WindowCapability windowCapability = new WindowCapability();
+ HashSet<ChoiceCell> loadedCells = new HashSet<>();
+ BaseChoiceSetManager.ChoicesOperationCompletionListener listener = new BaseChoiceSetManager.ChoicesOperationCompletionListener() {
+ @Override
+ public void onComplete(boolean success, HashSet<ChoiceCell> loadedChoiceCells) {
+ choiceSet.cancel();
+ sleep();
+
+ verify(internalInterface, times(1)).sendRPC(any(CancelInteraction.class));
+ verify(internalInterface, times(1)).sendRPC(any(PerformInteraction.class));
+
+ assertEquals(Task.IN_PROGRESS, presentChoicesOperation.getState());
+ }
+ };
+ presentChoicesOperation = new PreloadPresentChoicesOperation(internalInterface, fileManager, choiceSet, InteractionMode.MANUAL_ONLY, null, null, TestValues.GENERAL_INTEGER, null, windowCapability, true, loadedCells, listener, null);
+ presentChoicesOperation.setLoadedCells(new HashSet<ChoiceCell>());
+ queue.add(presentChoicesOperation, false);
+
+ sleep();
+
+ assertEquals(Task.IN_PROGRESS, presentChoicesOperation.getState());
+
+ Answer<Void> cancelInteractionAnswer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ CancelInteraction cancelInteraction = (CancelInteraction) args[0];
+
+ assertEquals(cancelInteraction.getCancelID(), TestValues.GENERAL_INTEGER);
+ assertEquals(cancelInteraction.getInteractionFunctionID().intValue(), FunctionID.PERFORM_INTERACTION.getId());
+
+ RPCResponse response = new RPCResponse(FunctionID.CANCEL_INTERACTION.toString());
+ response.setSuccess(true);
+ cancelInteraction.getOnRPCResponseListener().onResponse(0, response);
+
+ return null;
+ }
+ };
+ doAnswer(cancelInteractionAnswer).when(internalInterface).sendRPC(any(CancelInteraction.class));
+ }
+
+ @Test
+ public void testCancelingChoiceSetUnsuccessfullyIfThreadIsRunning() {
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
+ WindowCapability windowCapability = new WindowCapability();
+ HashSet<ChoiceCell> loadedCells = new HashSet<>();
+ BaseChoiceSetManager.ChoicesOperationCompletionListener listener = new BaseChoiceSetManager.ChoicesOperationCompletionListener() {
+ @Override
+ public void onComplete(boolean success, HashSet<ChoiceCell> loadedChoiceCells) {
+ choiceSet.cancel();
+ sleep();
+
+ verify(internalInterface, times(1)).sendRPC(any(CancelInteraction.class));
+ verify(internalInterface, times(1)).sendRPC(any(PerformInteraction.class));
+
+ assertEquals(Task.IN_PROGRESS, presentChoicesOperation.getState());
+ }
+ };
+ presentChoicesOperation = new PreloadPresentChoicesOperation(internalInterface, fileManager, choiceSet, InteractionMode.MANUAL_ONLY, null, null, TestValues.GENERAL_INTEGER, null, windowCapability, true, loadedCells, listener, null);
+ presentChoicesOperation.setLoadedCells(new HashSet<ChoiceCell>());
+ queue.add(presentChoicesOperation, false);
+ sleep();
+
+ assertEquals(Task.IN_PROGRESS, presentChoicesOperation.getState());
+
+ Answer<Void> cancelInteractionAnswer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ CancelInteraction cancelInteraction = (CancelInteraction) args[0];
+
+ assertEquals(cancelInteraction.getCancelID(), TestValues.GENERAL_INTEGER);
+ assertEquals(cancelInteraction.getInteractionFunctionID().intValue(), FunctionID.PERFORM_INTERACTION.getId());
+
+ RPCResponse response = new RPCResponse(FunctionID.CANCEL_INTERACTION.toString());
+ response.setSuccess(false);
+ cancelInteraction.getOnRPCResponseListener().onResponse(0, response);
+
+ return null;
+ }
+ };
+ doAnswer(cancelInteractionAnswer).when(internalInterface).sendRPC(any(CancelInteraction.class));
+ }
+
+ @Test
+ public void testCancelingChoiceSetIfThreadHasFinished() {
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
+ WindowCapability windowCapability = new WindowCapability();
+ HashSet<ChoiceCell> loadedCells = new HashSet<>();
+ presentChoicesOperation = new PreloadPresentChoicesOperation(internalInterface, fileManager, choiceSet, InteractionMode.MANUAL_ONLY, null, null, TestValues.GENERAL_INTEGER,null, windowCapability, true, loadedCells, null, null);
+ presentChoicesOperation.finishOperation(false);
+
+ assertEquals(Task.FINISHED, presentChoicesOperation.getState());
+
+ choiceSet.cancel();
+ verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
+
+ assertEquals(Task.FINISHED, presentChoicesOperation.getState());
+ }
+
+ @Test
+ public void testCancelingChoiceSetIfThreadHasCanceled() {
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
+ WindowCapability windowCapability = new WindowCapability();
+ HashSet<ChoiceCell> loadedCells = new HashSet<>();
+ presentChoicesOperation = new PreloadPresentChoicesOperation(internalInterface, fileManager, choiceSet, InteractionMode.MANUAL_ONLY, null, null, TestValues.GENERAL_INTEGER,null, windowCapability, true, loadedCells, null, null);
+ presentChoicesOperation.cancelTask();
+
+ assertEquals(Task.CANCELED, presentChoicesOperation.getState());
+
+ choiceSet.cancel();
+ verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
+
+ assertEquals(Task.CANCELED, presentChoicesOperation.getState());
+ }
+
+ @Test
+ public void testCancelingChoiceSetIfThreadHasNotYetRun() {
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
+ WindowCapability windowCapability = new WindowCapability();
+ HashSet<ChoiceCell> loadedCells = new HashSet<>();
+ presentChoicesOperation = new PreloadPresentChoicesOperation(internalInterface, fileManager, choiceSet, InteractionMode.MANUAL_ONLY, null, null, TestValues.GENERAL_INTEGER, null, windowCapability, true, loadedCells, null, null);
+
+ assertEquals(Task.BLOCKED, presentChoicesOperation.getState());
+
+ choiceSet.cancel();
+
+ // Once the operation has started
+ queue.add(presentChoicesOperation, false);
+ sleep();
+
+ assertEquals(Task.CANCELED, presentChoicesOperation.getState());
+
+ // Make sure neither a `CancelInteraction` or `PerformInteraction` RPC is ever sent
+ verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
+ verify(internalInterface, never()).sendRPC(any(PerformInteraction.class));
+ }
+
+ @Test
+ public void testCancelingChoiceSetIfHeadUnitDoesNotSupportFeature() {
+ // Cancel Interaction is only supported on RPC specs v.6.0.0+
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(5, 3));
+ WindowCapability windowCapability = new WindowCapability();
+ HashSet<ChoiceCell> loadedCells = new HashSet<>();
+ BaseChoiceSetManager.ChoicesOperationCompletionListener listener = new BaseChoiceSetManager.ChoicesOperationCompletionListener() {
+ @Override
+ public void onComplete(boolean success, HashSet<ChoiceCell> loadedChoiceCells) {
+ choiceSet.cancel();
+ sleep();
+
+ assertEquals(Task.IN_PROGRESS, presentChoicesOperation.getState());
+
+ verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
+ verify(internalInterface, times(1)).sendRPC(any(PerformInteraction.class));
+ }
+ };
+ presentChoicesOperation = new PreloadPresentChoicesOperation(internalInterface, fileManager, choiceSet, InteractionMode.MANUAL_ONLY, null, null, TestValues.GENERAL_INTEGER, null, windowCapability, true, loadedCells, listener, null);
+ presentChoicesOperation.setLoadedCells(new HashSet<ChoiceCell>());
+ queue.add(presentChoicesOperation, false);
+ }
+
+ @Test
+ public void testCancelingChoiceSetIfHeadUnitDoesNotSupportFeatureButThreadIsNotRunning() {
+ // Cancel Interaction is only supported on RPC specs v.6.0.0+
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(5, 3));
+ WindowCapability windowCapability = new WindowCapability();
+ HashSet<ChoiceCell> loadedCells = new HashSet<>();
+ presentChoicesOperation = new PreloadPresentChoicesOperation(internalInterface, fileManager, choiceSet, InteractionMode.MANUAL_ONLY, null, null, TestValues.GENERAL_INTEGER, null, windowCapability, true, loadedCells, null, null);
+
+ assertEquals(Task.BLOCKED, presentChoicesOperation.getState());
+
+ choiceSet.cancel();
+
+ verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
+
+ // Once the operation has started
+ queue.add(presentChoicesOperation, false);
+ sleep();
+
+ assertEquals(Task.CANCELED, presentChoicesOperation.getState());
+
+ // Make sure neither a `CancelInteraction` or `PerformInteraction` RPC is ever sent
+ verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
+ verify(internalInterface, never()).sendRPC(any(PerformInteraction.class));
+ }
+}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PresentChoiceSetOperationTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PresentChoiceSetOperationTests.java
deleted file mode 100644
index 3d22f352b..000000000
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PresentChoiceSetOperationTests.java
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * 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.
- *
- * Created by brettywhite on 6/12/19 1:52 PM
- *
- */
-
-package com.smartdevicelink.managers.screen.choiceset;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.livio.taskmaster.Queue;
-import com.livio.taskmaster.Task;
-import com.livio.taskmaster.Taskmaster;
-import com.smartdevicelink.managers.ISdl;
-import com.smartdevicelink.protocol.enums.FunctionID;
-import com.smartdevicelink.proxy.RPCResponse;
-import com.smartdevicelink.proxy.rpc.CancelInteraction;
-import com.smartdevicelink.proxy.rpc.KeyboardProperties;
-import com.smartdevicelink.proxy.rpc.PerformInteraction;
-import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
-import com.smartdevicelink.proxy.rpc.enums.InteractionMode;
-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.LayoutMode;
-import com.smartdevicelink.test.TestValues;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.util.Collections;
-
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@RunWith(AndroidJUnit4.class)
-public class PresentChoiceSetOperationTests {
-
- private PresentChoiceSetOperation presentChoiceSetOperation;
- private ChoiceSet choiceSet;
- private ISdl internalInterface;
- private KeyboardListener keyboardListener;
- private ChoiceSetSelectionListener choiceSetSelectionListener;
-
- private Taskmaster taskmaster;
- private Queue queue;
-
- @Before
- public void setUp() throws Exception {
-
- internalInterface = mock(ISdl.class);
-
- keyboardListener = mock(KeyboardListener.class);
- choiceSetSelectionListener = mock(ChoiceSetSelectionListener.class);
-
- ChoiceCell cell1 = new ChoiceCell("Cell1");
- cell1.setChoiceId(0);
- choiceSet = new ChoiceSet("Test", Collections.singletonList(cell1), choiceSetSelectionListener);
-
- taskmaster = new Taskmaster.Builder().build();
- queue = taskmaster.createQueue("test", 100, false);
- taskmaster.start();
- }
-
-
- private KeyboardProperties getKeyBoardProperties() {
- KeyboardProperties properties = new KeyboardProperties();
- properties.setLanguage(Language.EN_US);
- properties.setKeyboardLayout(KeyboardLayout.QWERTZ);
- properties.setKeypressMode(KeypressMode.RESEND_CURRENT_ENTRY);
- return properties;
- }
-
- @Test
- public void testGetLayoutMode() {
- // First we will check knowing our keyboard listener is NOT NULL
- presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, getKeyBoardProperties(), keyboardListener, choiceSetSelectionListener, TestValues.GENERAL_INTEGER);
-
- assertEquals(presentChoiceSetOperation.getLayoutMode(), LayoutMode.LIST_WITH_SEARCH);
- presentChoiceSetOperation.keyboardListener = null;
- assertEquals(presentChoiceSetOperation.getLayoutMode(), LayoutMode.LIST_ONLY);
- }
-
- @Test
- public void testGetPerformInteraction() {
- presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, getKeyBoardProperties(), keyboardListener, choiceSetSelectionListener, TestValues.GENERAL_INTEGER);
-
- PerformInteraction pi = presentChoiceSetOperation.getPerformInteraction();
- assertEquals(pi.getInitialText(), "Test");
- assertNull(pi.getHelpPrompt());
- assertNull(pi.getTimeoutPrompt());
- assertNull(pi.getVrHelp());
- assertEquals(pi.getTimeout(), Integer.valueOf(10000));
- assertEquals(pi.getCancelID(), TestValues.GENERAL_INTEGER);
- assertEquals(presentChoiceSetOperation.getLayoutMode(), LayoutMode.LIST_WITH_SEARCH);
- }
-
- @Test
- public void testSetSelectedCellWithId() {
- presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, getKeyBoardProperties(), keyboardListener, choiceSetSelectionListener, TestValues.GENERAL_INTEGER);
-
- assertNull(presentChoiceSetOperation.selectedCellRow);
- presentChoiceSetOperation.setSelectedCellWithId(0);
- assertEquals(presentChoiceSetOperation.selectedCellRow, Integer.valueOf(0));
- }
-
- private void sleep() {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- @Test
- public void testCancelingChoiceSetSuccessfullyIfThreadIsRunning() {
- when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
- presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, null, null, choiceSetSelectionListener, TestValues.GENERAL_INTEGER);
- queue.add(presentChoiceSetOperation, false);
-
- sleep();
-
- assertEquals(Task.IN_PROGRESS, presentChoiceSetOperation.getState());
-
- choiceSet.cancel();
- Answer<Void> cancelInteractionAnswer = new Answer<Void>() {
- @Override
- public Void answer(InvocationOnMock invocation) {
- Object[] args = invocation.getArguments();
- CancelInteraction cancelInteraction = (CancelInteraction) args[0];
-
- assertEquals(cancelInteraction.getCancelID(), TestValues.GENERAL_INTEGER);
- assertEquals(cancelInteraction.getInteractionFunctionID().intValue(), FunctionID.PERFORM_INTERACTION.getId());
-
- RPCResponse response = new RPCResponse(FunctionID.CANCEL_INTERACTION.toString());
- response.setSuccess(true);
- cancelInteraction.getOnRPCResponseListener().onResponse(0, response);
-
- return null;
- }
- };
- doAnswer(cancelInteractionAnswer).when(internalInterface).sendRPC(any(CancelInteraction.class));
-
- verify(internalInterface, times(1)).sendRPC(any(CancelInteraction.class));
- verify(internalInterface, times(1)).sendRPC(any(PerformInteraction.class));
-
- assertEquals(Task.IN_PROGRESS, presentChoiceSetOperation.getState());
- }
-
- @Test
- public void testCancelingChoiceSetUnsuccessfullyIfThreadIsRunning() {
- when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
- presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, null, null, choiceSetSelectionListener, TestValues.GENERAL_INTEGER);
- queue.add(presentChoiceSetOperation, false);
- sleep();
-
- assertEquals(Task.IN_PROGRESS, presentChoiceSetOperation.getState());
-
- choiceSet.cancel();
- Answer<Void> cancelInteractionAnswer = new Answer<Void>() {
- @Override
- public Void answer(InvocationOnMock invocation) {
- Object[] args = invocation.getArguments();
- CancelInteraction cancelInteraction = (CancelInteraction) args[0];
-
- assertEquals(cancelInteraction.getCancelID(), TestValues.GENERAL_INTEGER);
- assertEquals(cancelInteraction.getInteractionFunctionID().intValue(), FunctionID.PERFORM_INTERACTION.getId());
-
- RPCResponse response = new RPCResponse(FunctionID.CANCEL_INTERACTION.toString());
- response.setSuccess(false);
- cancelInteraction.getOnRPCResponseListener().onResponse(0, response);
-
- return null;
- }
- };
- doAnswer(cancelInteractionAnswer).when(internalInterface).sendRPC(any(CancelInteraction.class));
-
- verify(internalInterface, times(1)).sendRPC(any(CancelInteraction.class));
- verify(internalInterface, times(1)).sendRPC(any(PerformInteraction.class));
-
- assertEquals(Task.IN_PROGRESS, presentChoiceSetOperation.getState());
- }
-
- @Test
- public void testCancelingChoiceSetIfThreadHasFinished() {
- when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
- presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, null, null, choiceSetSelectionListener, TestValues.GENERAL_INTEGER);
- presentChoiceSetOperation.finishOperation();
-
- assertEquals(Task.FINISHED, presentChoiceSetOperation.getState());
-
- choiceSet.cancel();
- verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
-
- assertEquals(Task.FINISHED, presentChoiceSetOperation.getState());
- }
-
- @Test
- public void testCancelingChoiceSetIfThreadHasNotYetRun() {
- when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
- presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, null, null, choiceSetSelectionListener, TestValues.GENERAL_INTEGER);
-
- assertEquals(Task.BLOCKED, presentChoiceSetOperation.getState());
-
- choiceSet.cancel();
-
- // Once the operation has started
- queue.add(presentChoiceSetOperation, false);
- sleep();
-
- assertEquals(Task.CANCELED, presentChoiceSetOperation.getState());
-
- // Make sure neither a `CancelInteraction` or `PerformInteraction` RPC is ever sent
- verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
- verify(internalInterface, never()).sendRPC(any(PerformInteraction.class));
- }
-
- @Test
- public void testCancelingChoiceSetIfHeadUnitDoesNotSupportFeature() {
- // Cancel Interaction is only supported on RPC specs v.6.0.0+
- when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(5, 3));
- presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, null, null, choiceSetSelectionListener, TestValues.GENERAL_INTEGER);
- queue.add(presentChoiceSetOperation, false);
- sleep();
-
- assertEquals(Task.IN_PROGRESS, presentChoiceSetOperation.getState());
-
- choiceSet.cancel();
-
- verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
- verify(internalInterface, times(1)).sendRPC(any(PerformInteraction.class));
- }
-
- @Test
- public void testCancelingChoiceSetIfHeadUnitDoesNotSupportFeatureButThreadIsNotRunning() {
- // Cancel Interaction is only supported on RPC specs v.6.0.0+
- when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(5, 3));
- presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, null, null, choiceSetSelectionListener, TestValues.GENERAL_INTEGER);
-
- assertEquals(Task.BLOCKED, presentChoiceSetOperation.getState());
-
- choiceSet.cancel();
-
- verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
-
- // Once the operation has started
- queue.add(presentChoiceSetOperation, false);
- sleep();
-
- assertEquals(Task.CANCELED, presentChoiceSetOperation.getState());
-
- // Make sure neither a `CancelInteraction` or `PerformInteraction` RPC is ever sent
- verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
- verify(internalInterface, never()).sendRPC(any(PerformInteraction.class));
- }
-} \ No newline at end of file
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/RunScoreTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/DynamicMenuUpdateRunScoreTests.java
index e92656846..69350965a 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/RunScoreTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/DynamicMenuUpdateRunScoreTests.java
@@ -39,21 +39,29 @@ import com.smartdevicelink.test.TestValues;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.smartdevicelink.managers.screen.menu.DynamicMenuUpdateAlgorithm.MenuCellState.ADD;
+import static com.smartdevicelink.managers.screen.menu.DynamicMenuUpdateAlgorithm.MenuCellState.DELETE;
+import static com.smartdevicelink.managers.screen.menu.DynamicMenuUpdateAlgorithm.MenuCellState.KEEP;
import static junit.framework.TestCase.assertEquals;
@RunWith(AndroidJUnit4.class)
-public class RunScoreTests {
+public class DynamicMenuUpdateRunScoreTests {
@Test
public void testSettersAndGetters() {
// set everything - we only use the constructor to set variables in the Menu Manager
- RunScore runScore = new RunScore(TestValues.GENERAL_INT, TestValues.GENERAL_INTEGER_LIST, TestValues.GENERAL_INTEGER_LIST);
+ List<DynamicMenuUpdateAlgorithm.MenuCellState> oldStatus = Arrays.asList(KEEP, DELETE);
+ List<DynamicMenuUpdateAlgorithm.MenuCellState> updatedStatus = Arrays.asList(KEEP, ADD);
+ DynamicMenuUpdateRunScore runScore = new DynamicMenuUpdateRunScore(oldStatus, updatedStatus, TestValues.GENERAL_INT);
// use getters and assert equality
assertEquals(runScore.getScore(), TestValues.GENERAL_INT);
- assertEquals(runScore.getCurrentMenu(), TestValues.GENERAL_INTEGER_LIST);
- assertEquals(runScore.getOldMenu(), TestValues.GENERAL_INTEGER_LIST);
+ assertEquals(runScore.getOldStatus(), oldStatus);
+ assertEquals(runScore.getUpdatedStatus(), updatedStatus);
}
}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuCellTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuCellTests.java
index b0e703e33..8088538e1 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuCellTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuCellTests.java
@@ -43,13 +43,13 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertNotSame;
-import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertNotEquals;
@RunWith(AndroidJUnit4.class)
public class MenuCellTests {
@@ -63,7 +63,6 @@ public class MenuCellTests {
@Test
public void testSettersAndGetters() {
-
// set everything
MenuCell menuCell = new MenuCell(TestValues.GENERAL_STRING, null, null, menuSelectionListener);
menuCell.setIcon(TestValues.GENERAL_ARTWORK);
@@ -91,7 +90,6 @@ public class MenuCellTests {
@Test
public void testConstructors() {
-
// first constructor was tested in previous method, use the last two here
MenuCell menuCell3 = new MenuCell(TestValues.GENERAL_STRING, TestValues.GENERAL_ARTWORK, TestValues.GENERAL_STRING_LIST, menuSelectionListener);
@@ -99,20 +97,16 @@ public class MenuCellTests {
assertEquals(menuCell3.getIcon(), TestValues.GENERAL_ARTWORK);
assertEquals(menuCell3.getVoiceCommands(), TestValues.GENERAL_STRING_LIST);
assertEquals(menuCell3.getMenuSelectionListener(), menuSelectionListener);
- assertEquals(menuCell3.getUniqueTitle(), TestValues.GENERAL_STRING);
MenuCell menuCell4 = new MenuCell(TestValues.GENERAL_STRING, null, null, menuSelectionListener);
assertEquals(menuCell4.getTitle(), TestValues.GENERAL_STRING);
assertEquals(menuCell4.getMenuSelectionListener(), menuSelectionListener);
- assertEquals(menuCell4.getUniqueTitle(), TestValues.GENERAL_STRING);
MenuCell menuCell5 = new MenuCell(TestValues.GENERAL_STRING, TestValues.GENERAL_MENU_LAYOUT, TestValues.GENERAL_ARTWORK, TestValues.GENERAL_MENUCELL_LIST);
assertEquals(menuCell5.getTitle(), TestValues.GENERAL_STRING);
assertEquals(menuCell5.getIcon(), TestValues.GENERAL_ARTWORK);
assertEquals(menuCell5.getSubMenuLayout(), TestValues.GENERAL_MENU_LAYOUT);
assertEquals(menuCell5.getSubCells(), TestValues.GENERAL_MENUCELL_LIST);
- assertEquals(menuCell5.getUniqueTitle(), TestValues.GENERAL_STRING);
-
MenuCell menuCell6 = new MenuCell(TestValues.GENERAL_STRING, TestValues.GENERAL_STRING, TestValues.GENERAL_STRING, TestValues.GENERAL_ARTWORK, TestValues.GENERAL_ARTWORK, TestValues.GENERAL_STRING_LIST, menuSelectionListener);
assertEquals(menuCell6.getTitle(), TestValues.GENERAL_STRING);
@@ -139,36 +133,34 @@ public class MenuCellTests {
@Test
public void testEquality() {
+ MenuCell menuCell1 = new MenuCell(TestValues.GENERAL_STRING, TestValues.GENERAL_ARTWORK, TestValues.GENERAL_STRING_LIST, menuSelectionListener);
+ MenuCell menuCell1_1 = new MenuCell(TestValues.GENERAL_STRING, TestValues.GENERAL_ARTWORK, TestValues.GENERAL_STRING_LIST, menuSelectionListener);
+ menuCell1.setSubCells(Collections.singletonList(menuCell1_1));
- //We should use assertTrue (or assertFalse) because we want to use the overridden equals() method
-
- MenuCell menuCell = new MenuCell(TestValues.GENERAL_STRING, TestValues.GENERAL_ARTWORK, TestValues.GENERAL_STRING_LIST, menuSelectionListener);
- menuCell.setSecondaryText(TestValues.GENERAL_STRING);
- menuCell.setTertiaryText(TestValues.GENERAL_STRING);
- menuCell.setSecondaryArtwork(TestValues.GENERAL_ARTWORK);
MenuCell menuCell2 = new MenuCell(TestValues.GENERAL_STRING, TestValues.GENERAL_ARTWORK, TestValues.GENERAL_STRING_LIST, menuSelectionListener);
- menuCell2.setSecondaryText(TestValues.GENERAL_STRING);
- menuCell2.setTertiaryText(TestValues.GENERAL_STRING);
- menuCell2.setSecondaryArtwork(TestValues.GENERAL_ARTWORK);
+ MenuCell menuCell2_1 = new MenuCell(TestValues.GENERAL_STRING, TestValues.GENERAL_ARTWORK, TestValues.GENERAL_STRING_LIST, menuSelectionListener);
+ menuCell2.setSubCells(Collections.singletonList(menuCell2_1));
// these are the same object, should be equal.
- assertTrue(menuCell.equals(menuCell));
+ assertEquals(menuCell1, menuCell1);
// Make sure these are marked as equals, even though they are different objects
- assertTrue(menuCell.equals(menuCell2));
+ assertEquals(menuCell1, menuCell2);
MenuCell menuCell3 = new MenuCell(TestValues.GENERAL_STRING, null, TestValues.GENERAL_STRING_LIST, menuSelectionListener);
// these should be different
- assertFalse(menuCell.equals(menuCell3));
+ assertNotEquals(menuCell1, menuCell3);
+
+ menuCell1_1.setTitle("new title");
+
+ // Make sure sub cells are not compared
+ assertEquals(menuCell1, menuCell2);
}
@Test
public void testClone() {
MenuCell original = new MenuCell(TestValues.GENERAL_STRING, TestValues.GENERAL_ARTWORK, TestValues.GENERAL_STRING_LIST, menuSelectionListener);
- original.setSecondaryText(TestValues.GENERAL_STRING);
- original.setTertiaryText(TestValues.GENERAL_STRING);
- original.setSecondaryArtwork(TestValues.GENERAL_ARTWORK);
MenuCell clone = original.clone();
assertNotNull(clone);
@@ -208,8 +200,5 @@ public class MenuCellTests {
assertNotSame(originalSubCells.get(i), cloneSubCells.get(i));
}
-
-
}
-
}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuConfigurationUpdateOperationTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuConfigurationUpdateOperationTests.java
new file mode 100644
index 000000000..c52cf6186
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuConfigurationUpdateOperationTests.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2021 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.menu;
+
+import android.os.Handler;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.livio.taskmaster.Queue;
+import com.livio.taskmaster.Taskmaster;
+import com.smartdevicelink.managers.CompletionListener;
+import com.smartdevicelink.managers.ISdl;
+import com.smartdevicelink.proxy.RPCRequest;
+import com.smartdevicelink.proxy.RPCResponse;
+import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
+import com.smartdevicelink.proxy.rpc.SetGlobalProperties;
+import com.smartdevicelink.proxy.rpc.WindowCapability;
+import com.smartdevicelink.proxy.rpc.enums.MenuLayout;
+import com.smartdevicelink.util.Version;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(AndroidJUnit4.class)
+public class MenuConfigurationUpdateOperationTests {
+
+ private Handler mainHandler;
+ private Taskmaster taskmaster;
+ private Queue transactionQueue;
+
+ @Before
+ public void setUp() throws Exception {
+ mainHandler = new Handler(getInstrumentation().getTargetContext().getMainLooper());
+ taskmaster = new Taskmaster.Builder().build();
+ taskmaster.start();
+ transactionQueue = taskmaster.createQueue("MenuManager", new Random().nextInt(), false);
+ }
+
+ @Test
+ public void testSuccess() {
+ final ISdl internalInterface = mock(ISdl.class);
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(new Version(7, 0, 0)));
+ doAnswer(createSetGlobalPropertiesAnswer(true)).when(internalInterface).sendRPC(any(SetGlobalProperties.class));
+ WindowCapability windowCapability = createWindowCapability(true, true);
+ MenuConfiguration menuConfiguration = new MenuConfiguration(MenuLayout.LIST, MenuLayout.LIST);
+ MenuConfigurationUpdateOperation operation = new MenuConfigurationUpdateOperation(internalInterface, windowCapability, menuConfiguration, new CompletionListener() {
+ @Override
+ public void onComplete(final boolean success) {
+ assertOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(success);
+ verify(internalInterface, Mockito.times(1)).sendRPC(any(SetGlobalProperties.class));
+ }
+ });
+ }
+ });
+ transactionQueue.add(operation, false);
+ }
+
+ @Test
+ public void testFailsRPCVersionOld() {
+ final ISdl internalInterface = mock(ISdl.class);
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(new Version(5, 0, 0)));
+ doAnswer(createSetGlobalPropertiesAnswer(true)).when(internalInterface).sendRPC(any(SetGlobalProperties.class));
+ WindowCapability windowCapability = createWindowCapability(true, true);
+ MenuConfiguration menuConfiguration = new MenuConfiguration(MenuLayout.LIST, MenuLayout.LIST);
+ MenuConfigurationUpdateOperation operation = new MenuConfigurationUpdateOperation(internalInterface, windowCapability, menuConfiguration, new CompletionListener() {
+ @Override
+ public void onComplete(final boolean success) {
+ assertOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ assertFalse(success);
+ verify(internalInterface, Mockito.times(0)).sendRPC(any(SetGlobalProperties.class));
+ }
+ });
+ }
+ });
+ transactionQueue.add(operation, false);
+ }
+
+ @Test
+ public void testFailsMenuLayoutNotSet() {
+ final ISdl internalInterface = mock(ISdl.class);
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(new Version(7, 0, 0)));
+ doAnswer(createSetGlobalPropertiesAnswer(true)).when(internalInterface).sendRPC(any(SetGlobalProperties.class));
+ WindowCapability windowCapability = createWindowCapability(true, true);
+ MenuConfiguration menuConfiguration = new MenuConfiguration(null, MenuLayout.LIST);
+ MenuConfigurationUpdateOperation operation = new MenuConfigurationUpdateOperation(internalInterface, windowCapability, menuConfiguration, new CompletionListener() {
+ @Override
+ public void onComplete(final boolean success) {
+ assertOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ assertFalse(success);
+ verify(internalInterface, Mockito.times(0)).sendRPC(any(SetGlobalProperties.class));
+ }
+ });
+ }
+ });
+ transactionQueue.add(operation, false);
+ }
+
+ @Test
+ public void testFailsMenuLayoutsAvailableEmpty() {
+ final ISdl internalInterface = mock(ISdl.class);
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(new Version(7, 0, 0)));
+ doAnswer(createSetGlobalPropertiesAnswer(true)).when(internalInterface).sendRPC(any(SetGlobalProperties.class));
+ WindowCapability windowCapability = createWindowCapability(true, true);
+ MenuConfiguration menuConfiguration = new MenuConfiguration(null, null);
+ MenuConfigurationUpdateOperation operation = new MenuConfigurationUpdateOperation(internalInterface, windowCapability, menuConfiguration, new CompletionListener() {
+ @Override
+ public void onComplete(final boolean success) {
+ assertOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ assertFalse(success);
+ verify(internalInterface, Mockito.times(0)).sendRPC(any(SetGlobalProperties.class));
+ }
+ });
+ }
+ });
+ transactionQueue.add(operation, false);
+ }
+
+ @Test
+ public void testFailsRPCNotSent() {
+ final ISdl internalInterface = mock(ISdl.class);
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(new Version(7, 0, 0)));
+ doAnswer(createSetGlobalPropertiesAnswer(false)).when(internalInterface).sendRPC(any(SetGlobalProperties.class));
+ WindowCapability windowCapability = createWindowCapability(true, true);
+ MenuConfiguration menuConfiguration = new MenuConfiguration(MenuLayout.LIST, MenuLayout.LIST);
+ MenuConfigurationUpdateOperation operation = new MenuConfigurationUpdateOperation(internalInterface, windowCapability, menuConfiguration, new CompletionListener() {
+ @Override
+ public void onComplete(final boolean success) {
+ assertOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ assertFalse(success);
+ verify(internalInterface, Mockito.times(1)).sendRPC(any(SetGlobalProperties.class));
+ }
+ });
+ }
+ });
+ transactionQueue.add(operation, false);
+ }
+
+ private Answer<Void> createSetGlobalPropertiesAnswer(final boolean success){
+ return new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ RPCRequest request = (RPCRequest) args[0];
+ RPCResponse response = new RPCResponse(request.getFunctionID().toString());
+ response.setSuccess(success);
+ request.getOnRPCResponseListener().onResponse(request.getCorrelationID(), response);
+ return null;
+ }
+ };
+ }
+
+ private WindowCapability createWindowCapability (boolean supportsList, boolean supportsTile) {
+ WindowCapability windowCapability = new WindowCapability();
+ windowCapability.setMenuLayoutsAvailable(new ArrayList<MenuLayout>());
+ if (supportsList) {
+ windowCapability.getMenuLayoutsAvailable().add(MenuLayout.LIST);
+ }
+ if (supportsTile) {
+ windowCapability.getMenuLayoutsAvailable().add(MenuLayout.TILES);
+ }
+ return windowCapability;
+ }
+
+ // Asserts on Taskmaster threads will fail silently so we need to do the assertions on main thread if the code is triggered from Taskmaster
+ private void assertOnMainThread(Runnable runnable) {
+ mainHandler.post(runnable);
+ }
+}
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 e71d8295c..6f8bff69d 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
@@ -34,6 +34,7 @@ package com.smartdevicelink.managers.screen.menu;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.livio.taskmaster.Taskmaster;
import com.smartdevicelink.R;
import com.smartdevicelink.managers.BaseSubManager;
import com.smartdevicelink.managers.CompletionListener;
@@ -41,26 +42,23 @@ import com.smartdevicelink.managers.ISdl;
import com.smartdevicelink.managers.file.FileManager;
import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCMessage;
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.OnMultipleRequestListener;
import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
-import com.smartdevicelink.test.TestValues;
+import com.smartdevicelink.util.Version;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,6 +71,10 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import static com.smartdevicelink.managers.screen.menu.DynamicMenuUpdateAlgorithm.MenuCellState;
+import static com.smartdevicelink.managers.screen.menu.DynamicMenuUpdateAlgorithm.MenuCellState.ADD;
+import static com.smartdevicelink.managers.screen.menu.DynamicMenuUpdateAlgorithm.MenuCellState.DELETE;
+import static com.smartdevicelink.managers.screen.menu.DynamicMenuUpdateAlgorithm.MenuCellState.KEEP;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertNotNull;
@@ -81,10 +83,10 @@ import static junit.framework.TestCase.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
/**
* the Algorithm specific tests are defined based on: https://github.com/smartdevicelink/sdl_evolution/blob/master/proposals/0210-mobile-dynamic-menu-cell-updating.md
@@ -96,7 +98,11 @@ public class MenuManagerTests {
private MenuManager menuManager;
private List<MenuCell> cells;
private MenuCell mainCell1, mainCell4;
- final ISdl internalInterface = mock(ISdl.class);
+ private final MenuSelectionListener menuSelectionListenerA = mock(MenuSelectionListener.class);
+ private final MenuSelectionListener menuSelectionListenerB = mock(MenuSelectionListener.class);
+ private final MenuSelectionListener menuSelectionListenerC = mock(MenuSelectionListener.class);
+ private final MenuSelectionListener menuSelectionListenerD = mock(MenuSelectionListener.class);
+ private final MenuSelectionListener menuSelectionListenerE = mock(MenuSelectionListener.class);
// SETUP / HELPERS
@@ -105,8 +111,12 @@ public class MenuManagerTests {
cells = createTestCells();
+ final ISdl internalInterface = mock(ISdl.class);
FileManager fileManager = mock(FileManager.class);
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(new Version(6, 0, 0)));
+
+
// When internalInterface.addOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, OnRPCNotificationListener) is called
// inside MenuManager's constructor, then keep a reference to the OnRPCNotificationListener so we can trigger it later
// to emulate what Core does when it sends OnHMIStatus notification
@@ -130,7 +140,29 @@ public class MenuManagerTests {
};
doAnswer(onCommandAnswer).when(internalInterface).addOnRPCNotificationListener(eq(FunctionID.ON_COMMAND), any(OnRPCNotificationListener.class));
- Answer<Void> answer = new Answer<Void>() {
+ // When internalInterface.sendRPCs() is called, call listener.onFinished() to fake the response
+ final Answer<Void> answer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ List<RPCMessage> rpcs = (List<RPCMessage>) args[0];
+ OnMultipleRequestListener listener = (OnMultipleRequestListener) args[1];
+
+ for (RPCMessage rpcMessage : rpcs) {
+ RPCRequest request = (RPCRequest) rpcMessage;
+ RPCResponse response = new RPCResponse(request.getFunctionID().toString());
+ response.setCorrelationID(request.getCorrelationID());
+ response.setSuccess(true);
+ listener.onResponse(request.getCorrelationID(), response);
+ }
+
+ listener.onFinished();
+ return null;
+ }
+ };
+ doAnswer(answer).when(internalInterface).sendRPCs(any(List.class), any(OnMultipleRequestListener.class));
+
+ Answer<Void> setGlobalPropertiesAnswer = new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
@@ -141,110 +173,107 @@ public class MenuManagerTests {
return null;
}
};
- doAnswer(answer).when(internalInterface).sendRPC(any(SetGlobalProperties.class));
-
- SdlMsgVersion version = new SdlMsgVersion();
- version.setMajorVersion(7);
- version.setMinorVersion(0);
- doReturn(version).when(internalInterface).getSdlMsgVersion();
+ doAnswer(setGlobalPropertiesAnswer).when(internalInterface).sendRPC(any(SetGlobalProperties.class));
+ // Create MenuManager
+ Taskmaster taskmaster = new Taskmaster.Builder().build();
+ taskmaster.start();
+ when(internalInterface.getTaskmaster()).thenReturn(taskmaster);
menuManager = new MenuManager(internalInterface, fileManager);
// Check some stuff during setup
- assertEquals(menuManager.currentHMILevel, HMILevel.HMI_NONE);
- assertEquals(menuManager.getState(), BaseSubManager.SETTING_UP);
- assertEquals(menuManager.currentSystemContext, SystemContext.SYSCTXT_MAIN);
- assertEquals(menuManager.dynamicMenuUpdatesMode, DynamicMenuUpdatesMode.ON_WITH_COMPAT_MODE);
- assertEquals(menuManager.lastMenuId, 1);
- assertNull(menuManager.menuCells);
- assertNull(menuManager.waitingUpdateMenuCells);
- assertNull(menuManager.oldMenuCells);
- assertNull(menuManager.inProgressUpdate);
- assertNull(menuManager.keepsNew);
- assertNull(menuManager.keepsOld);
- assertNull(menuManager.menuConfiguration);
+ assertEquals(HMILevel.HMI_NONE, menuManager.currentHMILevel);
+ assertEquals(BaseSubManager.SETTING_UP, menuManager.getState());
+ assertEquals(SystemContext.SYSCTXT_MAIN, menuManager.currentSystemContext);
+ assertEquals(DynamicMenuUpdatesMode.ON_WITH_COMPAT_MODE, menuManager.dynamicMenuUpdatesMode);
+ assertTrue(menuManager.menuCells.isEmpty());
+ assertTrue(menuManager.currentMenuCells.isEmpty());
+ assertNull(menuManager.menuConfiguration.getMenuLayout());
+ assertNull(menuManager.menuConfiguration.getSubMenuLayout());
assertNotNull(menuManager.hmiListener);
assertNotNull(menuManager.commandListener);
assertNotNull(menuManager.onDisplaysCapabilityListener);
-
- }
-
- @After
- public void tearDown() throws Exception {
-
- menuManager.dispose();
-
- assertEquals(menuManager.currentSystemContext, SystemContext.SYSCTXT_MAIN);
- assertEquals(menuManager.dynamicMenuUpdatesMode, DynamicMenuUpdatesMode.ON_WITH_COMPAT_MODE);
- assertEquals(menuManager.lastMenuId, 1);
- assertNull(menuManager.menuCells);
- assertNull(menuManager.oldMenuCells);
- assertNull(menuManager.currentHMILevel);
- assertNull(menuManager.defaultMainWindowCapability);
- assertNull(menuManager.inProgressUpdate);
- assertNull(menuManager.waitingUpdateMenuCells);
- assertNull(menuManager.keepsNew);
- assertNull(menuManager.keepsOld);
- assertNull(menuManager.menuConfiguration);
-
- // after everything, make sure we are in the correct state
- assertEquals(menuManager.getState(), BaseSubManager.SHUTDOWN);
-
}
@Test
public void testStartMenuManager() {
-
menuManager.start(new CompletionListener() {
@Override
public void onComplete(boolean success) {
assertTrue(success);
// Make sure the state has changed, as the Screen Manager is dependant on it
- assertEquals(menuManager.getState(), BaseSubManager.READY);
+ assertEquals(BaseSubManager.READY, menuManager.getState());
}
});
}
@Test
public void testHMINotReady() {
-
- menuManager.currentHMILevel = HMILevel.HMI_NONE;
menuManager.setMenuCells(cells);
+ assertEquals(HMILevel.HMI_NONE, menuManager.currentHMILevel);
+ assertTrue(menuManager.currentMenuCells.isEmpty());
- // updating voice commands before HMI is ready
- assertTrue(menuManager.waitingOnHMIUpdate);
- // these are the 2 commands we have waiting
- assertEquals(menuManager.waitingUpdateMenuCells.size(), 4);
- assertEquals(menuManager.currentHMILevel, HMILevel.HMI_NONE);
// The Menu Manager should send new menu once HMI full occurs
sendFakeCoreOnHMIFullNotifications();
+
// Listener should be triggered - which sets new HMI level and should proceed to send our pending update
- assertEquals(menuManager.currentHMILevel, HMILevel.HMI_FULL);
- // This being false means it received the hmi notification and sent the pending commands
- assertFalse(menuManager.waitingOnHMIUpdate);
+ assertEquals(HMILevel.HMI_FULL, menuManager.currentHMILevel);
+
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
+
+ assertEquals(cells, menuManager.currentMenuCells);
}
@Test
- public void testUpdatingOldWay() {
+ public void testSettingNullMenu() {
+ menuManager.setMenuCells(null);
+ assertEquals(HMILevel.HMI_NONE, menuManager.currentHMILevel);
+ assertTrue(menuManager.currentMenuCells.isEmpty());
+
+ // The Menu Manager should send new menu once HMI full occurs
+ sendFakeCoreOnHMIFullNotifications();
+ // Listener should be triggered - which sets new HMI level and should proceed to send our pending update
+ assertEquals(HMILevel.HMI_FULL, menuManager.currentHMILevel);
+
+ assertTrue(menuManager.currentMenuCells.isEmpty());
+ }
+
+ @Test
+ public void testSettingNonUniqueCells() {
+ MenuSelectionListener listener = null;
+ MenuCell cell1 = new MenuCell("cell", null, null, listener);
+ MenuCell cell2 = new MenuCell("cell", null, null, listener);
+
+ menuManager.setMenuCells(Arrays.asList(cell1, cell2));
+ assertEquals(HMILevel.HMI_NONE, menuManager.currentHMILevel);
+ assertTrue(menuManager.currentMenuCells.isEmpty());
+
+ // The Menu Manager should send new menu once HMI full occurs
+ sendFakeCoreOnHMIFullNotifications();
+
+ // Listener should be triggered - which sets new HMI level and should proceed to send our pending update
+ assertEquals(HMILevel.HMI_FULL, menuManager.currentHMILevel);
+
+ assertTrue(menuManager.transactionQueue.getTasksAsList().isEmpty());
+ }
+
+ @Test
+ public void testUpdatingOldWay() {
// Force Menu Manager to use the old way of deleting / sending all
menuManager.setDynamicUpdatesMode(DynamicMenuUpdatesMode.FORCE_OFF);
assertEquals(menuManager.dynamicMenuUpdatesMode, DynamicMenuUpdatesMode.FORCE_OFF);
// when we only send one command to update, we should only be returned one add command
List<MenuCell> newArray = Arrays.asList(mainCell1, mainCell4);
- assertEquals(menuManager.allCommandsForCells(newArray, false).size(), 4); // 1 root cells, 1 sub menu root cell, 2 sub menu cells
+ assertEquals(MenuReplaceUtilities.allCommandsForCells(newArray, menuManager.fileManager.get(), menuManager.windowCapability, MenuLayout.LIST).size(), 4); // 1 root cells, 1 sub menu root cell, 2 sub menu cells
menuManager.currentHMILevel = HMILevel.HMI_FULL;
menuManager.setMenuCells(newArray);
- // Algorithm should NOT have run
- assertNull(menuManager.keepsNew);
- assertNull(menuManager.keepsOld);
-
- // Unlike voice commands, the Menu Manager dynamically assigns Cell ID's. Because of this, we need to get the updated
- // cell list after setting it and then test the listeners, as they use the newly assigned cell ID's.
- List<MenuCell> updatedCells = menuManager.getMenuCells();
- for (MenuCell cell : updatedCells) {
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
+ for (MenuCell cell : menuManager.currentMenuCells) {
// grab 2 of our newly updated cells - 1 root and 1 sub cell, and make sure they can get triggered
if (cell.getTitle().equalsIgnoreCase("Test Cell 1")) {
// Fake onCommand - we want to make sure that we can pass back onCommand events to our root Menu Cell
@@ -272,39 +301,46 @@ public class MenuManagerTests {
@Test
public void testAlgorithmTest1() {
-
// Force Menu Manager to use the new way
menuManager.setDynamicUpdatesMode(DynamicMenuUpdatesMode.FORCE_ON);
assertEquals(menuManager.dynamicMenuUpdatesMode, DynamicMenuUpdatesMode.FORCE_ON);
// start fresh
- menuManager.oldMenuCells = null;
- menuManager.menuCells = null;
- menuManager.inProgressUpdate = null;
- menuManager.waitingUpdateMenuCells = null;
- menuManager.waitingOnHMIUpdate = false;
+ menuManager.currentMenuCells = new ArrayList<>();
+ menuManager.menuCells = new ArrayList<>();
+
+ sendFakeCoreOnHMIFullNotifications();
- menuManager.currentHMILevel = HMILevel.HMI_FULL;
// send new cells. They should set the old way
List<MenuCell> oldMenu = createDynamicMenu1();
List<MenuCell> newMenu = createDynamicMenu1New();
menuManager.setMenuCells(oldMenu);
- assertEquals(menuManager.menuCells.size(), 4);
+
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
+
+ assertEquals(menuManager.currentMenuCells.size(), 4);
+
+ menuManager.setMenuCells(newMenu);
+
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
// this happens in the menu manager but lets make sure its behaving
- RunScore runScore = menuManager.runMenuCompareAlgorithm(oldMenu, newMenu);
+ DynamicMenuUpdateRunScore runScore = DynamicMenuUpdateAlgorithm.dynamicRunScoreOldMenuCells(oldMenu, newMenu);
- List<Integer> oldMenuScore = Arrays.asList(0, 0, 0, 0);
- List<Integer> newMenuScore = Arrays.asList(0, 0, 0, 0, 1);
+ List<MenuCellState> oldMenuStatus = Arrays.asList(KEEP, KEEP, KEEP, KEEP);
+ List<MenuCellState> newMenuStatus = Arrays.asList(KEEP, KEEP, KEEP, KEEP, ADD);
- assertEquals(runScore.getScore(), 1);
- assertEquals(runScore.getOldMenu(), oldMenuScore);
- assertEquals(runScore.getCurrentMenu(), newMenuScore);
+ assertEquals(1, runScore.getScore());
+ assertEquals(runScore.getOldStatus(), oldMenuStatus);
+ assertEquals(runScore.getUpdatedStatus(), newMenuStatus);
- menuManager.setMenuCells(newMenu);
- assertEquals(menuManager.menuCells.size(), 5);
- assertEquals(menuManager.keepsNew.size(), 4);
- assertEquals(menuManager.keepsOld.size(), 4);
+ assertEquals(5, menuManager.currentMenuCells.size());
+ List<MenuCell> oldKeeps = filterMenuCellsWithStatusList(menuManager.currentMenuCells, runScore.getOldStatus(), KEEP);
+ List<MenuCell> newKeeps = filterMenuCellsWithStatusList(menuManager.currentMenuCells, runScore.getUpdatedStatus(), KEEP);
+ assertEquals(4, oldKeeps.size());
+ assertEquals(4, newKeeps.size());
}
@Test
@@ -315,33 +351,41 @@ public class MenuManagerTests {
assertEquals(menuManager.dynamicMenuUpdatesMode, DynamicMenuUpdatesMode.FORCE_ON);
// start fresh
- menuManager.oldMenuCells = null;
- menuManager.menuCells = null;
- menuManager.inProgressUpdate = null;
- menuManager.waitingUpdateMenuCells = null;
- menuManager.waitingOnHMIUpdate = false;
+ menuManager.currentMenuCells = new ArrayList<>();
+ menuManager.menuCells = new ArrayList<>();
+
+ sendFakeCoreOnHMIFullNotifications();
- menuManager.currentHMILevel = HMILevel.HMI_FULL;
// send new cells. They should set the old way
List<MenuCell> oldMenu = createDynamicMenu2();
List<MenuCell> newMenu = createDynamicMenu2New();
menuManager.setMenuCells(oldMenu);
- assertEquals(menuManager.menuCells.size(), 4);
+
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
+
+ assertEquals(4, menuManager.currentMenuCells.size());
+
+ menuManager.setMenuCells(newMenu);
+
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
// this happens in the menu manager but lets make sure its behaving
- RunScore runScore = menuManager.runMenuCompareAlgorithm(oldMenu, newMenu);
+ DynamicMenuUpdateRunScore runScore = DynamicMenuUpdateAlgorithm.dynamicRunScoreOldMenuCells(oldMenu, newMenu);
- List<Integer> oldMenuScore = Arrays.asList(0, 0, 0, 2);
- List<Integer> newMenuScore = Arrays.asList(0, 0, 0);
+ List<MenuCellState> oldMenuScore = Arrays.asList(KEEP, KEEP, KEEP, DELETE);
+ List<MenuCellState> newMenuScore = Arrays.asList(KEEP, KEEP, KEEP);
assertEquals(runScore.getScore(), 0);
- assertEquals(runScore.getOldMenu(), oldMenuScore);
- assertEquals(runScore.getCurrentMenu(), newMenuScore);
+ assertEquals(runScore.getOldStatus(), oldMenuScore);
+ assertEquals(runScore.getUpdatedStatus(), newMenuScore);
- menuManager.setMenuCells(newMenu);
- assertEquals(menuManager.menuCells.size(), 3);
- assertEquals(menuManager.keepsNew.size(), 3);
- assertEquals(menuManager.keepsOld.size(), 3);
+ assertEquals(3, menuManager.currentMenuCells.size());
+ List<MenuCell> oldKeeps = filterMenuCellsWithStatusList(menuManager.currentMenuCells, runScore.getOldStatus(), KEEP);
+ List<MenuCell> newKeeps = filterMenuCellsWithStatusList(menuManager.currentMenuCells, runScore.getUpdatedStatus(), KEEP);
+ assertEquals(3, oldKeeps.size());
+ assertEquals(3, newKeeps.size());
}
@Test
@@ -352,33 +396,41 @@ public class MenuManagerTests {
assertEquals(menuManager.dynamicMenuUpdatesMode, DynamicMenuUpdatesMode.FORCE_ON);
// start fresh
- menuManager.oldMenuCells = null;
- menuManager.menuCells = null;
- menuManager.inProgressUpdate = null;
- menuManager.waitingUpdateMenuCells = null;
- menuManager.waitingOnHMIUpdate = false;
+ menuManager.currentMenuCells = new ArrayList<>();
+ menuManager.menuCells = new ArrayList<>();
+
+ sendFakeCoreOnHMIFullNotifications();
- menuManager.currentHMILevel = HMILevel.HMI_FULL;
// send new cells. They should set the old way
List<MenuCell> oldMenu = createDynamicMenu3();
List<MenuCell> newMenu = createDynamicMenu3New();
menuManager.setMenuCells(oldMenu);
- assertEquals(menuManager.menuCells.size(), 3);
+
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
+
+ assertEquals(menuManager.currentMenuCells.size(), 3);
+
+ menuManager.setMenuCells(newMenu);
+
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
// this happens in the menu manager but lets make sure its behaving
- RunScore runScore = menuManager.runMenuCompareAlgorithm(oldMenu, newMenu);
+ DynamicMenuUpdateRunScore runScore = DynamicMenuUpdateAlgorithm.dynamicRunScoreOldMenuCells(oldMenu, newMenu);
- List<Integer> oldMenuScore = Arrays.asList(2, 2, 2);
- List<Integer> newMenuScore = Arrays.asList(1, 1, 1);
+ List<MenuCellState> oldMenuStatus = Arrays.asList(DELETE, DELETE, DELETE);
+ List<MenuCellState> newMenuStatus = Arrays.asList(ADD, ADD, ADD);
assertEquals(runScore.getScore(), 3);
- assertEquals(runScore.getOldMenu(), oldMenuScore);
- assertEquals(runScore.getCurrentMenu(), newMenuScore);
+ assertEquals(runScore.getOldStatus(), oldMenuStatus);
+ assertEquals(runScore.getUpdatedStatus(), newMenuStatus);
- menuManager.setMenuCells(newMenu);
- assertEquals(menuManager.menuCells.size(), 3);
- assertEquals(menuManager.keepsNew.size(), 0);
- assertEquals(menuManager.keepsOld.size(), 0);
+ assertEquals(menuManager.currentMenuCells.size(), 3);
+ List<MenuCell> oldKeeps = filterMenuCellsWithStatusList(menuManager.currentMenuCells, runScore.getOldStatus(), KEEP);
+ List<MenuCell> newKeeps = filterMenuCellsWithStatusList(menuManager.currentMenuCells, runScore.getUpdatedStatus(), KEEP);
+ assertEquals(0, newKeeps.size());
+ assertEquals(0, oldKeeps.size());
}
@Test
@@ -389,33 +441,41 @@ public class MenuManagerTests {
assertEquals(menuManager.dynamicMenuUpdatesMode, DynamicMenuUpdatesMode.FORCE_ON);
// start fresh
- menuManager.oldMenuCells = null;
- menuManager.menuCells = null;
- menuManager.inProgressUpdate = null;
- menuManager.waitingUpdateMenuCells = null;
- menuManager.waitingOnHMIUpdate = false;
+ menuManager.currentMenuCells = new ArrayList<>();
+ menuManager.menuCells = new ArrayList<>();
+
+ sendFakeCoreOnHMIFullNotifications();
- menuManager.currentHMILevel = HMILevel.HMI_FULL;
// send new cells. They should set the old way
List<MenuCell> oldMenu = createDynamicMenu4();
List<MenuCell> newMenu = createDynamicMenu4New();
menuManager.setMenuCells(oldMenu);
- assertEquals(menuManager.menuCells.size(), 4);
+
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
+
+ assertEquals(menuManager.currentMenuCells.size(), 4);
+
+ menuManager.setMenuCells(newMenu);
+
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
// this happens in the menu manager but lets make sure its behaving
- RunScore runScore = menuManager.runMenuCompareAlgorithm(oldMenu, newMenu);
+ DynamicMenuUpdateRunScore runScore = DynamicMenuUpdateAlgorithm.dynamicRunScoreOldMenuCells(oldMenu, newMenu);
- List<Integer> oldMenuScore = Arrays.asList(0, 2, 0, 2);
- List<Integer> newMenuScore = Arrays.asList(1, 0, 1, 0);
+ List<MenuCellState> oldMenuStatus = Arrays.asList(KEEP, DELETE, KEEP, DELETE);
+ List<MenuCellState> newMenuStatus = Arrays.asList(ADD, KEEP, ADD, KEEP);
assertEquals(runScore.getScore(), 2);
- assertEquals(runScore.getOldMenu(), oldMenuScore);
- assertEquals(runScore.getCurrentMenu(), newMenuScore);
+ assertEquals(runScore.getOldStatus(), oldMenuStatus);
+ assertEquals(runScore.getUpdatedStatus(), newMenuStatus);
- menuManager.setMenuCells(newMenu);
- assertEquals(menuManager.menuCells.size(), 4);
- assertEquals(menuManager.keepsNew.size(), 2);
- assertEquals(menuManager.keepsOld.size(), 2);
+ assertEquals(menuManager.currentMenuCells.size(), 4);
+ List<MenuCell> oldKeeps = filterMenuCellsWithStatusList(menuManager.currentMenuCells, runScore.getOldStatus(), KEEP);
+ List<MenuCell> newKeeps = filterMenuCellsWithStatusList(menuManager.currentMenuCells, runScore.getUpdatedStatus(), KEEP);
+ assertEquals(2, newKeeps.size());
+ assertEquals(2, oldKeeps.size());
}
@Test
@@ -426,77 +486,68 @@ public class MenuManagerTests {
assertEquals(menuManager.dynamicMenuUpdatesMode, DynamicMenuUpdatesMode.FORCE_ON);
// start fresh
- menuManager.oldMenuCells = null;
- menuManager.menuCells = null;
- menuManager.inProgressUpdate = null;
- menuManager.waitingUpdateMenuCells = null;
- menuManager.waitingOnHMIUpdate = false;
+ menuManager.currentMenuCells = new ArrayList<>();
+ menuManager.menuCells = new ArrayList<>();
+
+ sendFakeCoreOnHMIFullNotifications();
- menuManager.currentHMILevel = HMILevel.HMI_FULL;
// send new cells. They should set the old way
List<MenuCell> oldMenu = createDynamicMenu5();
List<MenuCell> newMenu = createDynamicMenu5New();
menuManager.setMenuCells(oldMenu);
- assertEquals(menuManager.menuCells.size(), 4);
- // this happens in the menu manager but lets make sure its behaving
- RunScore runScore = menuManager.runMenuCompareAlgorithm(oldMenu, newMenu);
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
- List<Integer> oldMenuScore = Arrays.asList(2, 0, 0, 0);
- List<Integer> newMenuScore = Arrays.asList(0, 0, 0, 1);
-
- assertEquals(runScore.getScore(), 1);
- assertEquals(runScore.getOldMenu(), oldMenuScore);
- assertEquals(runScore.getCurrentMenu(), newMenuScore);
+ assertEquals(menuManager.currentMenuCells.size(), 4);
menuManager.setMenuCells(newMenu);
- assertEquals(menuManager.menuCells.size(), 4);
- assertEquals(menuManager.keepsNew.size(), 3);
- assertEquals(menuManager.keepsOld.size(), 3);
- }
- @Test
- public void testSettingNullMenu() {
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
- // Make sure we can send an empty menu with no issues
- // start fresh
- menuManager.oldMenuCells = null;
- menuManager.menuCells = null;
- menuManager.inProgressUpdate = null;
- menuManager.waitingUpdateMenuCells = null;
- menuManager.waitingOnHMIUpdate = false;
+ // this happens in the menu manager but lets make sure its behaving
+ DynamicMenuUpdateRunScore runScore = DynamicMenuUpdateAlgorithm.dynamicRunScoreOldMenuCells(oldMenu, newMenu);
- menuManager.currentHMILevel = HMILevel.HMI_FULL;
- // send new cells. They should set the old way
- List<MenuCell> oldMenu = createDynamicMenu1();
- List<MenuCell> newMenu = null;
- menuManager.setMenuCells(oldMenu);
- assertEquals(menuManager.menuCells.size(), 4);
+ List<MenuCellState> oldMenuStatus = Arrays.asList(DELETE, KEEP, KEEP, KEEP);
+ List<MenuCellState> newMenuStatus = Arrays.asList(KEEP, KEEP, KEEP, ADD);
- menuManager.setMenuCells(newMenu);
- assertEquals(menuManager.menuCells.size(), 0);
+ assertEquals(runScore.getScore(), 1);
+ assertEquals(runScore.getOldStatus(), oldMenuStatus);
+ assertEquals(runScore.getUpdatedStatus(), newMenuStatus);
+
+ assertEquals(menuManager.currentMenuCells.size(), 4);
+ List<MenuCell> oldKeeps = filterMenuCellsWithStatusList(menuManager.currentMenuCells, runScore.getOldStatus(), KEEP);
+ List<MenuCell> newKeeps = filterMenuCellsWithStatusList(menuManager.currentMenuCells, runScore.getUpdatedStatus(), KEEP);
+ assertEquals(3, newKeeps.size());
+ assertEquals(3, oldKeeps.size());
}
@Test
public void testClearingMenu() {
-
// Make sure we can send an empty menu with no issues
// start fresh
- menuManager.oldMenuCells = null;
- menuManager.menuCells = null;
- menuManager.inProgressUpdate = null;
- menuManager.waitingUpdateMenuCells = null;
- menuManager.waitingOnHMIUpdate = false;
+ menuManager.currentMenuCells = new ArrayList<>();
+ menuManager.menuCells = new ArrayList<>();
+
+ sendFakeCoreOnHMIFullNotifications();
- menuManager.currentHMILevel = HMILevel.HMI_FULL;
// send new cells. They should set the old way
List<MenuCell> oldMenu = createDynamicMenu1();
List<MenuCell> newMenu = Collections.emptyList();
menuManager.setMenuCells(oldMenu);
- assertEquals(menuManager.menuCells.size(), 4);
+
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
+
+ assertEquals(4, menuManager.currentMenuCells.size());
menuManager.setMenuCells(newMenu);
- assertEquals(menuManager.menuCells.size(), 0);
+
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
+
+ assertEquals(0 , menuManager.currentMenuCells.size());
}
@Test
@@ -512,7 +563,7 @@ public class MenuManagerTests {
// call open Menu
MenuManager mockMenuManager = mock(MenuManager.class);
MenuCell cell = mock(MenuCell.class);
- mockMenuManager.oldMenuCells = null;
+ mockMenuManager.currentMenuCells = null;
assertFalse(mockMenuManager.openSubMenu(cell));
}
@@ -520,201 +571,40 @@ public class MenuManagerTests {
public void testOpeningSubMenu() {
// call open Menu
List<MenuCell> testCells = createTestCells();
- menuManager.oldMenuCells = testCells;
- menuManager.sdlMsgVersion = new SdlMsgVersion(6, 0);
- // has to get success response to be true
- assertTrue(menuManager.openSubMenu(testCells.get(3)));
- }
-
- @Test
- public void testSetMenuConfiguration() {
- menuManager.currentHMILevel = HMILevel.HMI_FULL;
- menuManager.currentSystemContext = SystemContext.SYSCTXT_MAIN;
- menuManager.sdlMsgVersion = new SdlMsgVersion(6, 0);
- menuManager.defaultMainWindowCapability = new WindowCapability();
-
- List<MenuLayout> menuLayouts = Arrays.asList(MenuLayout.LIST, MenuLayout.TILES);
- menuManager.defaultMainWindowCapability.setMenuLayoutsAvailable(menuLayouts);
-
- MenuConfiguration menuConfigurationTest = new MenuConfiguration(MenuLayout.LIST, MenuLayout.LIST);
- menuManager.setMenuConfiguration(menuConfigurationTest);
- assertEquals(menuManager.menuConfiguration, menuConfigurationTest);
+ menuManager.setMenuCells(testCells);
- }
-
- @Test
- public void testSettingUniqueMenuNames() {
- //Testing using SDLMsgVersion 7.0, at this version uniqueTitles will be set
-
- // Make sure we can send an empty menu with no issues
- // start fresh
- menuManager.oldMenuCells = null;
- menuManager.menuCells = null;
- menuManager.inProgressUpdate = null;
- menuManager.waitingUpdateMenuCells = null;
- menuManager.waitingOnHMIUpdate = false;
-
- menuManager.currentHMILevel = HMILevel.HMI_FULL;
- // send new cells. They should set the old way
- List<MenuCell> oldMenu = createDynamicMenu6_forUniqueNamesTest();
- menuManager.setMenuCells(oldMenu);
- assertEquals(menuManager.menuCells.size(), 4);
- assertEquals(menuManager.menuCells.get(0).getUniqueTitle(), "A");
- assertEquals(menuManager.menuCells.get(1).getUniqueTitle(), "A (2)");
- assertEquals(menuManager.menuCells.get(2).getUniqueTitle(), "A (3)");
- assertEquals(menuManager.menuCells.get(3).getUniqueTitle(), "A (4)");
-
- assertEquals((menuManager.menuCells.get(3).getSubCells().size()), 4);
- assertEquals(menuManager.menuCells.get(3).getSubCells().get(0).getUniqueTitle(), "A");
- assertEquals(menuManager.menuCells.get(3).getSubCells().get(1).getUniqueTitle(), "A (2)");
- assertEquals(menuManager.menuCells.get(3).getSubCells().get(2).getUniqueTitle(), "A (3)");
- assertEquals(menuManager.menuCells.get(3).getSubCells().get(3).getUniqueTitle(), "A (4)");
- }
-
- @Test
- public void testAllowingNonUniqueTitles() {
- //Testing using SDLMsgVersion 7.1, at this version uniqueTitles will be set
- SdlMsgVersion version = new SdlMsgVersion();
- version.setMajorVersion(7);
- version.setMinorVersion(1);
- doReturn(version).when(internalInterface).getSdlMsgVersion();
+ sendFakeCoreOnHMIFullNotifications();
- // Make sure we can send an empty menu with no issues
- // start fresh
- menuManager.oldMenuCells = null;
- menuManager.menuCells = null;
- menuManager.inProgressUpdate = null;
- menuManager.waitingUpdateMenuCells = null;
- menuManager.waitingOnHMIUpdate = false;
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
- menuManager.currentHMILevel = HMILevel.HMI_FULL;
- // send new cells. They should set the old way
- List<MenuCell> oldMenu = createDynamicMenu6_forUniqueNamesTest();
- menuManager.setMenuCells(oldMenu);
- assertEquals(menuManager.menuCells.size(), 4);
- assertEquals(menuManager.menuCells.get(0).getUniqueTitle(), "A");
- assertEquals(menuManager.menuCells.get(1).getUniqueTitle(), "A");
- assertEquals(menuManager.menuCells.get(2).getUniqueTitle(), "A");
- assertEquals(menuManager.menuCells.get(3).getUniqueTitle(), "A");
-
- assertEquals((menuManager.menuCells.get(3).getSubCells().size()), 4);
- assertEquals(menuManager.menuCells.get(3).getSubCells().get(0).getUniqueTitle(), "A");
- assertEquals(menuManager.menuCells.get(3).getSubCells().get(1).getUniqueTitle(), "A");
- assertEquals(menuManager.menuCells.get(3).getSubCells().get(2).getUniqueTitle(), "A");
- assertEquals(menuManager.menuCells.get(3).getSubCells().get(3).getUniqueTitle(), "A");
+ // Has to get success response to be true
+ MenuCell submenu = testCells.get(3);
+ assertTrue(menuManager.openSubMenu(submenu));
}
@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)");
+ public void testSetMenuConfiguration() {
+ sendFakeCoreOnHMIFullNotifications();
+ menuManager.windowCapability = new WindowCapability();
+ menuManager.windowCapability.setMenuLayoutsAvailable(Arrays.asList(MenuLayout.LIST, MenuLayout.TILES));
- // SubCell test
- assertEquals(menuCellList.get(3).getUniqueTitle(), "Test Cell 3 (sub menu) (2)");
- assertEquals(menuCellList.get(2).getSubCells().get(1).getUniqueTitle(), "SubCell1 (2)");
+ MenuConfiguration menuConfigurationTest = new MenuConfiguration(MenuLayout.LIST, MenuLayout.LIST);
+ menuManager.setMenuConfiguration(menuConfigurationTest);
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
+ assertEquals(menuManager.menuConfiguration, menuConfigurationTest);
}
-
-
// HELPERS
// Emulate what happens when Core sends OnHMIStatus notification
private void sendFakeCoreOnHMIFullNotifications() {
OnHMIStatus onHMIStatusFakeNotification = new OnHMIStatus();
onHMIStatusFakeNotification.setHmiLevel(HMILevel.HMI_FULL);
+ onHMIStatusFakeNotification.setSystemContext(SystemContext.SYSCTXT_MAIN);
onHMIStatusListener.onNotified(onHMIStatusFakeNotification);
}
@@ -750,12 +640,6 @@ public class MenuManagerTests {
}
private List<MenuCell> createDynamicMenu1() {
-
- MenuSelectionListener menuSelectionListenerA = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerB = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerC = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerD = mock(MenuSelectionListener.class);
-
MenuCell A = new MenuCell("A", null, null, menuSelectionListenerA);
MenuCell B = new MenuCell("B", null, null, menuSelectionListenerB);
@@ -769,13 +653,6 @@ public class MenuManagerTests {
}
private List<MenuCell> createDynamicMenu1New() {
-
- MenuSelectionListener menuSelectionListenerA = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerB = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerC = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerD = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerE = mock(MenuSelectionListener.class);
-
MenuCell A = new MenuCell("A", null, null, menuSelectionListenerA);
MenuCell B = new MenuCell("B", null, null, menuSelectionListenerB);
@@ -791,12 +668,6 @@ public class MenuManagerTests {
}
private List<MenuCell> createDynamicMenu2() {
-
- MenuSelectionListener menuSelectionListenerA = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerB = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerC = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerD = mock(MenuSelectionListener.class);
-
MenuCell A = new MenuCell("A", null, null, menuSelectionListenerA);
MenuCell B = new MenuCell("B", null, null, menuSelectionListenerB);
@@ -810,11 +681,6 @@ public class MenuManagerTests {
}
private List<MenuCell> createDynamicMenu2New() {
-
- MenuSelectionListener menuSelectionListenerA = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerB = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerC = mock(MenuSelectionListener.class);
-
MenuCell A = new MenuCell("A", null, null, menuSelectionListenerA);
MenuCell B = new MenuCell("B", null, null, menuSelectionListenerB);
@@ -826,11 +692,6 @@ public class MenuManagerTests {
}
private List<MenuCell> createDynamicMenu3() {
-
- MenuSelectionListener menuSelectionListenerA = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerB = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerC = mock(MenuSelectionListener.class);
-
MenuCell A = new MenuCell("A", null, null, menuSelectionListenerA);
MenuCell B = new MenuCell("B", null, null, menuSelectionListenerB);
@@ -858,12 +719,6 @@ public class MenuManagerTests {
}
private List<MenuCell> createDynamicMenu4() {
-
- MenuSelectionListener menuSelectionListenerA = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerB = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerC = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerD = mock(MenuSelectionListener.class);
-
MenuCell A = new MenuCell("A", null, null, menuSelectionListenerA);
MenuCell B = new MenuCell("B", null, null, menuSelectionListenerB);
@@ -877,12 +732,6 @@ public class MenuManagerTests {
}
private List<MenuCell> createDynamicMenu4New() {
-
- MenuSelectionListener menuSelectionListenerA = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerB = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerC = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerD = mock(MenuSelectionListener.class);
-
MenuCell A = new MenuCell("A", null, null, menuSelectionListenerA);
MenuCell B = new MenuCell("B", null, null, menuSelectionListenerB);
@@ -896,12 +745,6 @@ public class MenuManagerTests {
}
private List<MenuCell> createDynamicMenu5() {
-
- MenuSelectionListener menuSelectionListenerA = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerB = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerC = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerD = mock(MenuSelectionListener.class);
-
MenuCell A = new MenuCell("A", null, null, menuSelectionListenerA);
MenuCell B = new MenuCell("B", null, null, menuSelectionListenerB);
@@ -915,12 +758,6 @@ public class MenuManagerTests {
}
private List<MenuCell> createDynamicMenu5New() {
-
- MenuSelectionListener menuSelectionListenerA = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerB = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerC = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerD = mock(MenuSelectionListener.class);
-
MenuCell A = new MenuCell("A", null, null, menuSelectionListenerA);
MenuCell B = new MenuCell("B", null, null, menuSelectionListenerB);
@@ -933,32 +770,21 @@ public class MenuManagerTests {
}
- private List<MenuCell> createDynamicMenu6_forUniqueNamesTest() {
- MenuSelectionListener menuSelectionListenerA = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerB = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerC = mock(MenuSelectionListener.class);
- MenuSelectionListener menuSelectionListenerD = mock(MenuSelectionListener.class);
-
- SdlArtwork icon1 = new SdlArtwork("livio", FileType.GRAPHIC_PNG, R.drawable.sdl_lockscreen_icon, false);
- SdlArtwork icon2 = new SdlArtwork("livio2", FileType.GRAPHIC_PNG, R.drawable.ic_sdl, false);
- SdlArtwork icon3 = new SdlArtwork("livio3", FileType.GRAPHIC_PNG, R.drawable.sdl_tray_icon, false);
- SdlArtwork icon4 = new SdlArtwork("livio4", FileType.GRAPHIC_PNG, R.drawable.spp_error, false);
-
- MenuCell A = new MenuCell("A", icon1, null, menuSelectionListenerA);
-
- MenuCell B = new MenuCell("A", icon2, null, menuSelectionListenerB);
-
- MenuCell C = new MenuCell("A", icon3, null, menuSelectionListenerC);
-
- MenuCell subA = new MenuCell("A", icon1, null, menuSelectionListenerA);
- MenuCell subB = new MenuCell("A", icon2, null, menuSelectionListenerB);
- MenuCell subC = new MenuCell("A", icon3, null, menuSelectionListenerC);
- MenuCell subD = new MenuCell("A", icon4, null, menuSelectionListenerD);
-
- MenuCell D = new MenuCell("A", MenuLayout.LIST, icon4, Arrays.asList(subA, subB, subC, subD));
-
- return Arrays.asList(A, B, C, D);
+ private List<MenuCell> filterMenuCellsWithStatusList(List<MenuCell> menuCells, List<DynamicMenuUpdateAlgorithm.MenuCellState> statusList, DynamicMenuUpdateAlgorithm.MenuCellState menuCellState) {
+ List<MenuCell> filteredCells = new ArrayList<>();
+ for (int index = 0; index < statusList.size(); index++) {
+ if (statusList.get(index).equals(menuCellState)) {
+ filteredCells.add(menuCells.get(index));
+ }
+ }
+ return filteredCells;
}
-
+ private void sleep() {
+ try {
+ Thread.sleep(250);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuReplaceOperationTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuReplaceOperationTests.java
new file mode 100644
index 000000000..284f1efd5
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuReplaceOperationTests.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2021 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.menu;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.smartdevicelink.managers.screen.menu.MenuReplaceUtilities.cloneMenuCellsList;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.livio.taskmaster.Queue;
+import com.livio.taskmaster.Taskmaster;
+import com.smartdevicelink.managers.ISdl;
+import com.smartdevicelink.managers.file.FileManager;
+import com.smartdevicelink.managers.file.MultipleFileCompletionListener;
+import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
+import com.smartdevicelink.proxy.RPCMessage;
+import com.smartdevicelink.proxy.RPCRequest;
+import com.smartdevicelink.proxy.RPCResponse;
+import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
+import com.smartdevicelink.proxy.rpc.TextField;
+import com.smartdevicelink.proxy.rpc.WindowCapability;
+import com.smartdevicelink.proxy.rpc.enums.MenuLayout;
+import com.smartdevicelink.proxy.rpc.enums.TriggerSource;
+import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
+import com.smartdevicelink.test.TestValues;
+import com.smartdevicelink.util.Version;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+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.List;
+import java.util.Random;
+
+@RunWith(AndroidJUnit4.class)
+public class MenuReplaceOperationTests {
+ private Handler mainHandler;
+ private Taskmaster taskmaster;
+ private Queue transactionQueue;
+
+ @Before
+ public void setUp() throws Exception {
+ mainHandler = new Handler(getInstrumentation().getTargetContext().getMainLooper());
+ taskmaster = new Taskmaster.Builder().build();
+ taskmaster.start();
+ transactionQueue = taskmaster.createQueue("MenuManager", new Random().nextInt(), false);
+ }
+
+ @Test
+ public void testSuccess() {
+ final ISdl internalInterface = createISdlMock();
+ FileManager fileManager = createFileManagerMock();
+ WindowCapability windowCapability = createWindowCapability(true, true, new ArrayList<TextField>());
+ MenuConfiguration menuConfiguration = new MenuConfiguration(MenuLayout.LIST, MenuLayout.LIST);
+
+ MenuCell menuCell1_1 = new MenuCell("cell 1_1", TestValues.GENERAL_ARTWORK, null, null);
+ MenuCell menuCell1 = new MenuCell("cell 1", null, TestValues.GENERAL_ARTWORK, Arrays.asList(menuCell1_1));
+ MenuCell menuCell2 = new MenuCell("cell 2", TestValues.GENERAL_ARTWORK, null, null);
+
+ final List<MenuCell> currentMenu = new ArrayList<>();
+ final List<MenuCell> updatedMenu = cloneMenuCellsList(Arrays.asList(menuCell1, menuCell2));
+ MenuReplaceOperation operation = new MenuReplaceOperation(internalInterface, fileManager, windowCapability, menuConfiguration, currentMenu, updatedMenu, true, new MenuManagerCompletionListener() {
+ @Override
+ public void onComplete(final boolean success, final List<MenuCell> currentMenuCells) {
+ assertOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(success);
+ assertEquals(currentMenuCells, updatedMenu);
+ verify(internalInterface, Mockito.times(2)).sendRPCs(any(List.class), any(OnMultipleRequestListener.class));
+ }
+ });
+ }
+ });
+ transactionQueue.add(operation, false);
+ }
+
+ @Test
+ public void testSwitchingCellsOrder() {
+ // This unit test is for this bug https://github.com/smartdevicelink/sdl_java_suite/issues/1723
+ final ISdl internalInterface = createISdlMock();
+ final FileManager fileManager = createFileManagerMock();
+ final WindowCapability windowCapability = createWindowCapability(true, true, new ArrayList<TextField>());
+ final MenuConfiguration menuConfiguration = new MenuConfiguration(MenuLayout.LIST, MenuLayout.LIST);
+
+ MenuSelectionListener listener = null;
+ final MenuCell menuCell1 = new MenuCell("A", "SecondaryText", null, null, null, null, listener);
+ final MenuCell menuCell2 = new MenuCell("A", null, null, null, null, null, listener);
+ final MenuCell menuCell3 = new MenuCell("C", null, null, null, null, null, listener);
+
+ MenuReplaceOperation operation = new MenuReplaceOperation(internalInterface, fileManager, windowCapability, menuConfiguration, new ArrayList<MenuCell>(), cloneMenuCellsList(Arrays.asList(menuCell1, menuCell2, menuCell3)), true, new MenuManagerCompletionListener() {
+ @Override
+ public void onComplete(final boolean success, final List<MenuCell> currentMenuCells1) {
+ assertOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(success);
+ assertEquals(3, currentMenuCells1.size());
+ assertEquals("A", currentMenuCells1.get(0).getUniqueTitle());
+ assertEquals("A (2)", currentMenuCells1.get(1).getUniqueTitle());
+ assertEquals("C", currentMenuCells1.get(2).getUniqueTitle());
+
+ verify(internalInterface, Mockito.times(1)).sendRPCs(any(List.class), any(OnMultipleRequestListener.class));
+
+ MenuReplaceOperation operation = new MenuReplaceOperation(internalInterface, fileManager, windowCapability, menuConfiguration, currentMenuCells1, cloneMenuCellsList(Arrays.asList(menuCell2, menuCell1)), true, new MenuManagerCompletionListener() {
+ @Override
+ public void onComplete(final boolean success, final List<MenuCell> currentMenuCells2) {
+ assertOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(success);
+ assertEquals(2, currentMenuCells2.size());
+ assertEquals("A", currentMenuCells2.get(0).getUniqueTitle());
+ assertEquals("A (2)", currentMenuCells2.get(1).getUniqueTitle());
+ verify(internalInterface, Mockito.times(2)).sendRPCs(any(List.class), any(OnMultipleRequestListener.class));
+ }
+ });
+ }
+ });
+ transactionQueue.add(operation, false);
+ }
+ });
+ }
+ });
+ transactionQueue.add(operation, false);
+ }
+
+ @Test
+ public void testResendingSameCellWithDifferentListener() {
+ final ISdl internalInterface = createISdlMock();
+ final FileManager fileManager = createFileManagerMock();
+ final WindowCapability windowCapability = createWindowCapability(true, true, new ArrayList<TextField>());
+ final MenuConfiguration menuConfiguration = new MenuConfiguration(MenuLayout.LIST, MenuLayout.LIST);
+
+ final MenuSelectionListener listener1 = new MenuSelectionListener() {
+ @Override
+ public void onTriggered(TriggerSource trigger) {}
+ };
+ final MenuSelectionListener listener2 = new MenuSelectionListener() {
+ @Override
+ public void onTriggered(TriggerSource trigger) {}
+ };
+ final MenuCell menuCell1 = new MenuCell("A", null, null, null, null, null, listener1);
+ final MenuCell menuCell2 = new MenuCell("A", null, null, null, null, null, listener2);
+
+ MenuReplaceOperation operation = new MenuReplaceOperation(internalInterface, fileManager, windowCapability, menuConfiguration, new ArrayList<MenuCell>(), cloneMenuCellsList(Arrays.asList(menuCell1)), true, new MenuManagerCompletionListener() {
+ @Override
+ public void onComplete(final boolean success, final List<MenuCell> currentMenuCells1) {
+ assertOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(success);
+ assertEquals(1, currentMenuCells1.size());
+ assertEquals(listener1, currentMenuCells1.get(0).getMenuSelectionListener());
+ verify(internalInterface, Mockito.times(1)).sendRPCs(any(List.class), any(OnMultipleRequestListener.class));
+
+ MenuReplaceOperation operation = new MenuReplaceOperation(internalInterface, fileManager, windowCapability, menuConfiguration, currentMenuCells1, cloneMenuCellsList(Arrays.asList(menuCell2)), true, new MenuManagerCompletionListener() {
+ @Override
+ public void onComplete(final boolean success, final List<MenuCell> currentMenuCells2) {
+ assertOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(success);
+ assertEquals(1, currentMenuCells2.size());
+ assertEquals(listener2, currentMenuCells2.get(0).getMenuSelectionListener());
+ verify(internalInterface, Mockito.times(1)).sendRPCs(any(List.class), any(OnMultipleRequestListener.class));
+ }
+ });
+ }
+ });
+ transactionQueue.add(operation, false);
+ }
+ });
+ }
+ });
+ transactionQueue.add(operation, false);
+ }
+
+ private ISdl createISdlMock() {
+ final ISdl internalInterface = mock(ISdl.class);
+
+ // When internalInterface.sendRPCs() is called, call listener.onFinished() to fake the response
+ final Answer<Void> answer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ List<RPCMessage> rpcs = (List<RPCMessage>) args[0];
+ OnMultipleRequestListener listener = (OnMultipleRequestListener) args[1];
+
+ for (RPCMessage rpcMessage : rpcs) {
+ RPCRequest request = (RPCRequest) rpcMessage;
+ RPCResponse response = new RPCResponse(request.getFunctionID().toString());
+ response.setCorrelationID(request.getCorrelationID());
+ response.setSuccess(true);
+ listener.onResponse(request.getCorrelationID(), response);
+ }
+
+ listener.onFinished();
+ return null;
+ }
+ };
+ doAnswer(answer).when(internalInterface).sendRPCs(any(List.class), any(OnMultipleRequestListener.class));
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(new Version(7, 1, 0)));
+
+ return internalInterface;
+ }
+
+ private FileManager createFileManagerMock() {
+ FileManager fileManager = mock(FileManager.class);
+
+ when(fileManager.hasUploadedFile(any(SdlArtwork.class))).thenReturn(true);
+
+ Answer<Void> onFileManagerUploadAnswer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ MultipleFileCompletionListener multipleFileCompletionListener = (MultipleFileCompletionListener) args[1];
+ multipleFileCompletionListener.onComplete(null);
+ return null;
+ }
+ };
+ doAnswer(onFileManagerUploadAnswer).when(fileManager).uploadArtworks(any(List.class), any(MultipleFileCompletionListener.class));
+ return fileManager;
+ }
+
+ private WindowCapability createWindowCapability(boolean supportsList, boolean supportsTile, ArrayList<TextField> supportedTextFields) {
+ WindowCapability windowCapability = new WindowCapability();
+ windowCapability.setTextFields(supportedTextFields);
+ windowCapability.setMenuLayoutsAvailable(new ArrayList<MenuLayout>());
+ if (supportsList) {
+ windowCapability.getMenuLayoutsAvailable().add(MenuLayout.LIST);
+ }
+ if (supportsTile) {
+ windowCapability.getMenuLayoutsAvailable().add(MenuLayout.TILES);
+ }
+ return windowCapability;
+ }
+
+ // Asserts on Taskmaster threads will fail silently so we need to do the assertions on main thread if the code is triggered from Taskmaster
+ private void assertOnMainThread(Runnable runnable) {
+ mainHandler.post(runnable);
+ }
+}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuReplaceUtilitiesTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuReplaceUtilitiesTests.java
new file mode 100644
index 000000000..61587dbdc
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuReplaceUtilitiesTests.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2021 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.menu;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.smartdevicelink.managers.file.FileManager;
+import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
+import com.smartdevicelink.proxy.rpc.ImageField;
+import com.smartdevicelink.proxy.rpc.WindowCapability;
+import com.smartdevicelink.proxy.rpc.enums.ImageFieldName;
+import com.smartdevicelink.proxy.rpc.enums.MenuLayout;
+import com.smartdevicelink.test.TestValues;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.smartdevicelink.managers.screen.menu.BaseMenuManager.parentIdNotFound;
+import static com.smartdevicelink.managers.screen.menu.MenuReplaceUtilities.addIdsToMenuCells;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Created by Bilal Alsharifi on 2/4/21.
+ */
+@RunWith(AndroidJUnit4.class)
+public class MenuReplaceUtilitiesTests {
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @Test
+ public void testRemoveMenuCellFromList() {
+ MenuCell menuCellToDelete;
+ boolean cellRemoved;
+ List<MenuCell> actualMenuCellList = createMenuCellList();
+ List<MenuCell> expectedMenuCellList = createMenuCellList();
+
+ // Delete cell c4
+ menuCellToDelete = actualMenuCellList.get(3);
+ cellRemoved = MenuReplaceUtilities.removeCellFromList(actualMenuCellList, menuCellToDelete.getCellId());
+ assertTrue(cellRemoved);
+ expectedMenuCellList.remove(3);
+ assertEquals(expectedMenuCellList, actualMenuCellList);
+ assertEquals(3, actualMenuCellList.size());
+
+ // Delete cell c4 again - removal should fail and list should not change
+ cellRemoved = MenuReplaceUtilities.removeCellFromList(actualMenuCellList, menuCellToDelete.getCellId());
+ assertFalse(cellRemoved);
+ assertEquals(expectedMenuCellList, actualMenuCellList);
+ assertEquals(3, actualMenuCellList.size());
+
+ // Delete cell c3
+ menuCellToDelete = actualMenuCellList.get(2);
+ cellRemoved = MenuReplaceUtilities.removeCellFromList(actualMenuCellList, menuCellToDelete.getCellId());
+ assertTrue(cellRemoved);
+ expectedMenuCellList.remove(2);
+ assertEquals(expectedMenuCellList, actualMenuCellList);
+ assertEquals(2, actualMenuCellList.size());
+
+ // Delete cell c2-2-2
+ menuCellToDelete = actualMenuCellList.get(1).getSubCells().get(1).getSubCells().get(1);
+ cellRemoved = MenuReplaceUtilities.removeCellFromList(actualMenuCellList, menuCellToDelete.getCellId());
+ assertTrue(cellRemoved);
+ expectedMenuCellList.get(1).getSubCells().get(1).getSubCells().remove(1);
+ assertEquals(expectedMenuCellList, actualMenuCellList);
+ assertEquals(2, actualMenuCellList.size());
+ assertEquals(1, actualMenuCellList.get(1).getSubCells().get(1).getSubCells().size());
+
+ // Delete cell c2-2-1
+ menuCellToDelete = actualMenuCellList.get(1).getSubCells().get(1).getSubCells().get(0);
+ cellRemoved = MenuReplaceUtilities.removeCellFromList(actualMenuCellList, menuCellToDelete.getCellId());
+ assertTrue(cellRemoved);
+ expectedMenuCellList.get(1).getSubCells().get(1).getSubCells().remove(0);
+ assertEquals(expectedMenuCellList, actualMenuCellList);
+ assertEquals(2, actualMenuCellList.size());
+ assertEquals(0, actualMenuCellList.get(1).getSubCells().get(1).getSubCells().size());
+
+ // Delete cell c2-2
+ menuCellToDelete = actualMenuCellList.get(1).getSubCells().get(1);
+ cellRemoved = MenuReplaceUtilities.removeCellFromList(actualMenuCellList, menuCellToDelete.getCellId());
+ assertTrue(cellRemoved);
+ expectedMenuCellList.get(1).getSubCells().remove(1);
+ assertEquals(expectedMenuCellList, actualMenuCellList);
+ assertEquals(2, actualMenuCellList.size());
+ assertEquals(1, actualMenuCellList.get(1).getSubCells().size());
+
+ // Delete cell c2-1
+ menuCellToDelete = actualMenuCellList.get(1).getSubCells().get(0);
+ cellRemoved = MenuReplaceUtilities.removeCellFromList(actualMenuCellList, menuCellToDelete.getCellId());
+ assertTrue(cellRemoved);
+ expectedMenuCellList.get(1).getSubCells().remove(0);
+ assertEquals(expectedMenuCellList, actualMenuCellList);
+ assertEquals(2, actualMenuCellList.size());
+ assertEquals(0, actualMenuCellList.get(1).getSubCells().size());
+
+ // Delete cell c2
+ menuCellToDelete = actualMenuCellList.get(1);
+ cellRemoved = MenuReplaceUtilities.removeCellFromList(actualMenuCellList, menuCellToDelete.getCellId());
+ assertTrue(cellRemoved);
+ expectedMenuCellList.remove(1);
+ assertEquals(expectedMenuCellList, actualMenuCellList);
+ assertEquals(1, actualMenuCellList.size());
+
+ // Delete cell c1
+ menuCellToDelete = actualMenuCellList.get(0);
+ cellRemoved = MenuReplaceUtilities.removeCellFromList(actualMenuCellList, menuCellToDelete.getCellId());
+ assertTrue(cellRemoved);
+ expectedMenuCellList.remove(0);
+ assertEquals(expectedMenuCellList, actualMenuCellList);
+ assertEquals(0, actualMenuCellList.size());
+ }
+
+ @Test
+ public void testAddMenuRequestWithCommandId() {
+ MenuCell menuCellToAdd;
+ boolean cellAdded;
+ List<MenuCell> actualMenuCellList = createMenuCellList();
+ List<MenuCell> expectedMenuCellList = createMenuCellList();
+ List<MenuCell> newMenuList = createNewMenuList();
+
+ // Add cell c5
+ menuCellToAdd = newMenuList.get(0);
+ cellAdded = MenuReplaceUtilities.addCellWithCellId(menuCellToAdd.getCellId(), 4, newMenuList, actualMenuCellList);
+ assertTrue(cellAdded);
+ expectedMenuCellList.add(4, cloneMenuCellAndRemoveSubCells(menuCellToAdd));
+ assertEquals(expectedMenuCellList, actualMenuCellList);
+ assertEquals(5, actualMenuCellList.size());
+ assertEquals(0, actualMenuCellList.get(4).getSubCells().size());
+
+ // Add cell c5-1
+ menuCellToAdd = newMenuList.get(0).getSubCells().get(0);
+ cellAdded = MenuReplaceUtilities.addCellWithCellId(menuCellToAdd.getCellId(), 0, newMenuList, actualMenuCellList);
+ assertTrue(cellAdded);
+ expectedMenuCellList.get(4).getSubCells().add(0, cloneMenuCellAndRemoveSubCells(menuCellToAdd));
+ assertEquals(expectedMenuCellList, actualMenuCellList);
+ assertEquals(5, actualMenuCellList.size());
+ assertEquals(1, actualMenuCellList.get(4).getSubCells().size());
+
+ // Add cell c5-1-1
+ menuCellToAdd = newMenuList.get(0).getSubCells().get(0).getSubCells().get(0);
+ cellAdded = MenuReplaceUtilities.addCellWithCellId(menuCellToAdd.getCellId(), 0, newMenuList, actualMenuCellList);
+ assertTrue(cellAdded);
+ expectedMenuCellList.get(4).getSubCells().get(0).getSubCells().add(0, cloneMenuCellAndRemoveSubCells(menuCellToAdd));
+ assertEquals(expectedMenuCellList, actualMenuCellList);
+ assertEquals(5, actualMenuCellList.size());
+ assertEquals(1, actualMenuCellList.get(4).getSubCells().size());
+ assertEquals(1, actualMenuCellList.get(4).getSubCells().get(0).getSubCells().size());
+
+ // Add cell c5-2
+ menuCellToAdd = newMenuList.get(0).getSubCells().get(1);
+ cellAdded = MenuReplaceUtilities.addCellWithCellId(menuCellToAdd.getCellId(), 1, newMenuList, actualMenuCellList);
+ assertTrue(cellAdded);
+ expectedMenuCellList.get(4).getSubCells().add(1, cloneMenuCellAndRemoveSubCells(menuCellToAdd));
+ assertEquals(expectedMenuCellList, actualMenuCellList);
+ assertEquals(5, actualMenuCellList.size());
+ assertEquals(2, actualMenuCellList.get(4).getSubCells().size());
+ assertEquals(1, actualMenuCellList.get(4).getSubCells().get(0).getSubCells().size());
+ assertEquals(0, actualMenuCellList.get(4).getSubCells().get(1).getSubCells().size());
+
+ // Add cell c5-2-1
+ menuCellToAdd = newMenuList.get(0).getSubCells().get(1).getSubCells().get(0);
+ cellAdded = MenuReplaceUtilities.addCellWithCellId(menuCellToAdd.getCellId(), 0, newMenuList, actualMenuCellList);
+ assertTrue(cellAdded);
+ expectedMenuCellList.get(4).getSubCells().get(1).getSubCells().add(0, cloneMenuCellAndRemoveSubCells(menuCellToAdd));
+ assertEquals(expectedMenuCellList, actualMenuCellList);
+ assertEquals(5, actualMenuCellList.size());
+ assertEquals(2, actualMenuCellList.get(4).getSubCells().size());
+ assertEquals(1, actualMenuCellList.get(4).getSubCells().get(0).getSubCells().size());
+ assertEquals(1, actualMenuCellList.get(4).getSubCells().get(1).getSubCells().size());
+ }
+
+ @Test
+ public void testShouldCellIncludeImage() {
+ MenuCell menuCell;
+ WindowCapability windowCapability;
+ FileManager fileManager;
+ List<String> voiceCommands = null;
+
+ // Case 1
+ menuCell = new MenuCell(TestValues.GENERAL_STRING, TestValues.GENERAL_ARTWORK, voiceCommands, null);
+ windowCapability = createWindowCapability(true, true);
+ fileManager = createMockFileManager(true);
+ assertTrue(MenuReplaceUtilities.shouldCellIncludePrimaryImageFromCell(menuCell, fileManager, windowCapability));
+
+ // Case 2 - Image are not supported
+ menuCell = new MenuCell(TestValues.GENERAL_STRING, TestValues.GENERAL_ARTWORK, voiceCommands, null);
+ windowCapability = createWindowCapability(false, false);
+ fileManager = createMockFileManager(true);
+ assertFalse(MenuReplaceUtilities.shouldCellIncludePrimaryImageFromCell(menuCell, fileManager, windowCapability));
+
+ // Case 3 - Artwork is null
+ menuCell = new MenuCell(TestValues.GENERAL_STRING, null, voiceCommands, null);
+ windowCapability = createWindowCapability(true, true);
+ fileManager = createMockFileManager(true);
+ assertFalse(MenuReplaceUtilities.shouldCellIncludePrimaryImageFromCell(menuCell, fileManager, windowCapability));
+
+ // Case 4 - Artwork has not been uploaded
+ menuCell = new MenuCell(TestValues.GENERAL_STRING, TestValues.GENERAL_ARTWORK, voiceCommands, null);
+ windowCapability = createWindowCapability(true, true);
+ fileManager = createMockFileManager(false);
+ assertFalse(MenuReplaceUtilities.shouldCellIncludePrimaryImageFromCell(menuCell, fileManager, windowCapability));
+
+ // Case 5 - Artwork is static icon
+ menuCell = new MenuCell(TestValues.GENERAL_STRING, TestValues.GENERAL_ARTWORK_STATIC, voiceCommands, null);
+ windowCapability = createWindowCapability(true, true);
+ fileManager = createMockFileManager(false);
+ assertTrue(MenuReplaceUtilities.shouldCellIncludePrimaryImageFromCell(menuCell, fileManager, windowCapability));
+ }
+
+ private WindowCapability createWindowCapability (boolean supportsCmdIcon, boolean supportsSubMenuIcon) {
+ WindowCapability windowCapability = new WindowCapability();
+ windowCapability.setImageFields(new ArrayList<ImageField>());
+ if (supportsCmdIcon) {
+ windowCapability.getImageFields().add(new ImageField(ImageFieldName.cmdIcon, null));
+ }
+ if (supportsSubMenuIcon) {
+ windowCapability.getImageFields().add(new ImageField(ImageFieldName.subMenuIcon, null));
+ }
+ return windowCapability;
+ }
+
+ private FileManager createMockFileManager (boolean hasUploadedFile) {
+ FileManager fileManager = mock(FileManager.class);
+ when(fileManager.hasUploadedFile(any(SdlArtwork.class))).thenReturn(hasUploadedFile);
+ return fileManager;
+ }
+
+ private MenuCell cloneMenuCellAndRemoveSubCells(MenuCell menuCell) {
+ MenuCell clonedCell = menuCell.clone();
+ if (clonedCell.getSubCells() != null) {
+ clonedCell.getSubCells().clear();
+ }
+ return clonedCell;
+ }
+
+ private List<MenuCell> createMenuCellList() {
+ /*
+
+ c1 c2 c3 c4
+ / \ / \
+ / \ / \
+ c2-1 c2-2 c4-1 c4-2
+ / \
+ / \
+ c2-2-1 c2-2-2
+
+ */
+
+ SdlArtwork sdlArtwork = null;
+ List<String> voiceCommands = null;
+ MenuSelectionListener listener = null;
+ MenuLayout subMenuLayout = null;
+
+ MenuCell menuCell1 = new MenuCell("c1", sdlArtwork, voiceCommands, listener);
+
+ MenuCell menuCell2_1 = new MenuCell("c2_1", sdlArtwork, voiceCommands, listener);
+ MenuCell menuCell2_2_1 = new MenuCell("c2_2_1", sdlArtwork, voiceCommands, listener);
+ MenuCell menuCell2_2_2 = new MenuCell("c2_2_2", sdlArtwork, voiceCommands, listener);
+ MenuCell menuCell2_2 = new MenuCell("c2_2", subMenuLayout, sdlArtwork, new ArrayList<>(Arrays.asList(menuCell2_2_1, menuCell2_2_2)));
+ MenuCell menuCell2 = new MenuCell("c2", subMenuLayout, sdlArtwork, new ArrayList<>(Arrays.asList(menuCell2_1, menuCell2_2)));
+
+ MenuCell menuCell3 = new MenuCell("c3", sdlArtwork, voiceCommands, listener);
+
+ MenuCell menuCell4_1 = new MenuCell("c4_1", sdlArtwork, voiceCommands, listener);
+ MenuCell menuCell4_2 = new MenuCell("c4_2", sdlArtwork, voiceCommands, listener);
+ MenuCell menuCell4 = new MenuCell("c4", subMenuLayout, sdlArtwork, new ArrayList<>(Arrays.asList(menuCell4_1, menuCell4_2)));
+
+ List<MenuCell> menuCellList = new ArrayList<>(Arrays.asList(menuCell1, menuCell2, menuCell3, menuCell4));
+ addIdsToMenuCells(menuCellList, parentIdNotFound);
+
+ return menuCellList ;
+ }
+
+ private List<MenuCell> createNewMenuList() {
+ /*
+
+ c5
+ / \
+ / \
+ c5-1 c5-2
+ / /
+ / /
+ c5-1-1 c5-2-1
+
+ */
+
+ SdlArtwork sdlArtwork = null;
+ List<String> voiceCommands = null;
+ MenuSelectionListener listener = null;
+ MenuLayout subMenuLayout = null;
+
+ MenuCell menuCell5_1_1 = new MenuCell("c5_1_1", sdlArtwork, voiceCommands, listener);
+ MenuCell menuCell5_1 = new MenuCell("c5_1", subMenuLayout, sdlArtwork, new ArrayList<>(Arrays.asList(menuCell5_1_1)));
+ MenuCell menuCell5_2_1 = new MenuCell("c5_2_1", sdlArtwork, voiceCommands, listener);
+ MenuCell menuCell5_2 = new MenuCell("c5_2", subMenuLayout, sdlArtwork, new ArrayList<>(Arrays.asList(menuCell5_2_1)));
+ MenuCell menuCell5 = new MenuCell("c5", subMenuLayout, sdlArtwork, new ArrayList<>(Arrays.asList(menuCell5_1, menuCell5_2)));
+
+ List<MenuCell> newMenuList = new ArrayList<>(Arrays.asList(menuCell5));
+ addIdsToMenuCells(newMenuList, parentIdNotFound);
+
+ return newMenuList ;
+ }
+}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuShowOperationTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuShowOperationTests.java
new file mode 100644
index 000000000..ee90cee49
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/MenuShowOperationTests.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2021 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.menu;
+
+import android.os.Handler;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.livio.taskmaster.Queue;
+import com.livio.taskmaster.Taskmaster;
+import com.smartdevicelink.managers.ISdl;
+import com.smartdevicelink.proxy.RPCRequest;
+import com.smartdevicelink.proxy.RPCResponse;
+import com.smartdevicelink.proxy.rpc.ShowAppMenu;
+import com.smartdevicelink.proxy.rpc.enums.MenuLayout;
+import com.smartdevicelink.test.TestValues;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.Random;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+@RunWith(AndroidJUnit4.class)
+public class MenuShowOperationTests {
+ private Handler mainHandler;
+ private Taskmaster taskmaster;
+ private Queue transactionQueue;
+
+ @Before
+ public void setUp() throws Exception {
+ mainHandler = new Handler(getInstrumentation().getTargetContext().getMainLooper());
+ taskmaster = new Taskmaster.Builder().build();
+ taskmaster.start();
+ transactionQueue = taskmaster.createQueue("MenuManager", new Random().nextInt(), false);
+ }
+
+ @Test
+ public void testOpenMainMenu() {
+ final ISdl internalInterface = mock(ISdl.class);
+ MenuCell menuCell = null;
+ Integer menuIdToAssert = menuCell != null ? menuCell.getCellId() : null;
+ Answer<Void> showAppMenuAnswer = createShowAppMenuAnswer(true, menuIdToAssert);
+ doAnswer(showAppMenuAnswer).when(internalInterface).sendRPC(any(ShowAppMenu.class));
+ MenuShowOperation operation = new MenuShowOperation(internalInterface, menuCell);
+ transactionQueue.add(operation, false);
+
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
+
+ verify(internalInterface, Mockito.times(1)).sendRPC(any(ShowAppMenu.class));
+ }
+
+ @Test
+ public void testOpenSubMenu() {
+ final ISdl internalInterface = mock(ISdl.class);
+ MenuCell menuCell = new MenuCell(TestValues.GENERAL_STRING, MenuLayout.TILES, null, null);
+ menuCell.setCellId(TestValues.GENERAL_INT);
+ Integer menuIdToAssert = menuCell != null ? menuCell.getCellId() : null;
+ Answer<Void> showAppMenuAnswer = createShowAppMenuAnswer(true, menuIdToAssert);
+ doAnswer(showAppMenuAnswer).when(internalInterface).sendRPC(any(ShowAppMenu.class));
+ MenuShowOperation operation = new MenuShowOperation(internalInterface, menuCell);
+ transactionQueue.add(operation, false);
+
+ // Sleep to give time to Taskmaster to run the operations
+ sleep();
+
+ verify(internalInterface, Mockito.times(1)).sendRPC(any(ShowAppMenu.class));
+ }
+
+ private Answer<Void> createShowAppMenuAnswer(final boolean success, final Integer menuIdToAssert){
+ return new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ final RPCRequest request = (RPCRequest) args[0];
+ assertOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ ShowAppMenu showAppMenu = (ShowAppMenu) request;
+ assertEquals(showAppMenu.getMenuID(), menuIdToAssert);
+ }
+ });
+ RPCResponse response = new RPCResponse(request.getFunctionID().toString());
+ response.setSuccess(success);
+ request.getOnRPCResponseListener().onResponse(request.getCorrelationID(), response);
+ return null;
+ }
+ };
+ }
+
+ private void sleep() {
+ try {
+ Thread.sleep(250);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // Asserts on Taskmaster threads will fail silently so we need to do the assertions on main thread if the code is triggered from Taskmaster
+ private void assertOnMainThread(Runnable runnable) {
+ mainHandler.post(runnable);
+ }
+}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/SubCellCommandListTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/SubCellCommandListTests.java
deleted file mode 100644
index 03afc5348..000000000
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/menu/SubCellCommandListTests.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.menu;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.smartdevicelink.test.TestValues;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static junit.framework.TestCase.assertEquals;
-
-@RunWith(AndroidJUnit4.class)
-public class SubCellCommandListTests {
-
- @Test
- public void testSettersAndGetters() {
-
- RunScore runScore = new RunScore(TestValues.GENERAL_INT, TestValues.GENERAL_INTEGER_LIST, TestValues.GENERAL_INTEGER_LIST);
-
- // set everything
- SubCellCommandList subCellCommandList = new SubCellCommandList(TestValues.GENERAL_STRING, TestValues.GENERAL_INTEGER, runScore, TestValues.GENERAL_MENUCELL_LIST, TestValues.GENERAL_MENUCELL_LIST);
-
- // use getters and assert equality
- assertEquals(subCellCommandList.getMenuTitle(), TestValues.GENERAL_STRING);
- assertEquals(subCellCommandList.getParentId(), TestValues.GENERAL_INTEGER);
- assertEquals(runScore, runScore);
- assertEquals(subCellCommandList.getNewList(), TestValues.GENERAL_MENUCELL_LIST);
- assertEquals(subCellCommandList.getOldList(), TestValues.GENERAL_MENUCELL_LIST);
-
- }
-}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/video/HapticInterfaceManagerTest.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/video/HapticInterfaceManagerTest.java
index dc74cb12a..bd75e2440 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/video/HapticInterfaceManagerTest.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/video/HapticInterfaceManagerTest.java
@@ -21,6 +21,7 @@
**************************************************************************************************/
package com.smartdevicelink.managers.video;
+import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
@@ -45,9 +46,7 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
-import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnitRunner;
-import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.List;
@@ -56,7 +55,6 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -222,36 +220,53 @@ public class HapticInterfaceManagerTest extends TestCase {
}
private View createViews() {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
- View view = mock(View.class);
+ final View view = new View(context) {
+ private int count = 0;
- ViewGroup parent1 = mock(ViewGroup.class);
- ViewGroup parent2 = mock(ViewGroup.class);
+ @Override
+ public boolean isClickable() {
+ int curCount = count++;
+ return (curCount >= 1) && (curCount <= 4);
+ }
+ };
- when(parent1.getChildCount()).thenReturn(5);
+ final ViewGroup parent1 = new ViewGroup(context) {
+ @Override
+ protected void onLayout(boolean b, int i, int i1, int i2, int i3) {}
- when(parent1.getChildAt(0)).thenReturn(view);
- when(parent1.getChildAt(1)).thenReturn(view);
- when(parent1.getChildAt(2)).thenReturn(view);
- when(parent1.getChildAt(3)).thenReturn(parent2);
- when(parent1.getChildAt(4)).thenReturn(view);
+ @Override
+ public View getChildAt(int index) {
+ return view;
+ }
- when(parent2.getChildCount()).thenReturn(2);
- when(parent2.getChildAt(0)).thenReturn(view);
- when(parent2.getChildAt(1)).thenReturn(view);
+ @Override
+ public int getChildCount() {
+ return 2;
+ }
+ };
+ final ViewGroup parent2 = new ViewGroup(context) {
+ @Override
+ protected void onLayout(boolean b, int i, int i1, int i2, int i3) {}
- doAnswer(new Answer<Boolean>() {
- private int count = 0;
+ @Override
+ public View getChildAt(int index) {
+ if (index == 3) {
+ return parent1;
+ } else {
+ return view;
+ }
+ }
@Override
- public Boolean answer(InvocationOnMock invocation) throws Throwable {
- int curCount = count++;
- return (curCount >= 1) && (curCount <= 4);
+ public int getChildCount() {
+ return 5;
}
- }).when(view).isClickable();
+ };
- return parent1;
+ return parent2;
}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/TestValues.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/TestValues.java
index 713770984..da3bb5846 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/TestValues.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/TestValues.java
@@ -18,106 +18,7 @@ import com.smartdevicelink.protocol.SdlProtocol;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.rpc.AppCapability;
import com.smartdevicelink.proxy.rpc.*;
-import com.smartdevicelink.proxy.rpc.enums.AmbientLightStatus;
-import com.smartdevicelink.proxy.rpc.enums.AppCapabilityType;
-import com.smartdevicelink.proxy.rpc.enums.AppHMIType;
-import com.smartdevicelink.proxy.rpc.enums.AppInterfaceUnregisteredReason;
-import com.smartdevicelink.proxy.rpc.enums.AppServiceType;
-import com.smartdevicelink.proxy.rpc.enums.AudioStreamingIndicator;
-import com.smartdevicelink.proxy.rpc.enums.AudioStreamingState;
-import com.smartdevicelink.proxy.rpc.enums.AudioType;
-import com.smartdevicelink.proxy.rpc.enums.BitsPerSample;
-import com.smartdevicelink.proxy.rpc.enums.ButtonEventMode;
-import com.smartdevicelink.proxy.rpc.enums.ButtonName;
-import com.smartdevicelink.proxy.rpc.enums.ButtonPressMode;
-import com.smartdevicelink.proxy.rpc.enums.CapacityUnit;
-import com.smartdevicelink.proxy.rpc.enums.CarModeStatus;
-import com.smartdevicelink.proxy.rpc.enums.CharacterSet;
-import com.smartdevicelink.proxy.rpc.enums.CompassDirection;
-import com.smartdevicelink.proxy.rpc.enums.ComponentVolumeStatus;
-import com.smartdevicelink.proxy.rpc.enums.DefrostZone;
-import com.smartdevicelink.proxy.rpc.enums.DeviceLevelStatus;
-import com.smartdevicelink.proxy.rpc.enums.Dimension;
-import com.smartdevicelink.proxy.rpc.enums.Direction;
-import com.smartdevicelink.proxy.rpc.enums.DisplayMode;
-import com.smartdevicelink.proxy.rpc.enums.DisplayType;
-import com.smartdevicelink.proxy.rpc.enums.DistanceUnit;
-import com.smartdevicelink.proxy.rpc.enums.DoorStatusType;
-import com.smartdevicelink.proxy.rpc.enums.DriverDistractionState;
-import com.smartdevicelink.proxy.rpc.enums.ECallConfirmationStatus;
-import com.smartdevicelink.proxy.rpc.enums.EmergencyEventType;
-import com.smartdevicelink.proxy.rpc.enums.FileType;
-import com.smartdevicelink.proxy.rpc.enums.FuelCutoffStatus;
-import com.smartdevicelink.proxy.rpc.enums.FuelType;
-import com.smartdevicelink.proxy.rpc.enums.GlobalProperty;
-import com.smartdevicelink.proxy.rpc.enums.HMILevel;
-import com.smartdevicelink.proxy.rpc.enums.HmiZoneCapabilities;
-import com.smartdevicelink.proxy.rpc.enums.HybridAppPreference;
-import com.smartdevicelink.proxy.rpc.enums.IgnitionStableStatus;
-import com.smartdevicelink.proxy.rpc.enums.IgnitionStatus;
-import com.smartdevicelink.proxy.rpc.enums.ImageFieldName;
-import com.smartdevicelink.proxy.rpc.enums.ImageType;
-import com.smartdevicelink.proxy.rpc.enums.InteractionMode;
-import com.smartdevicelink.proxy.rpc.enums.KeyboardEvent;
-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.LayoutMode;
-import com.smartdevicelink.proxy.rpc.enums.LightName;
-import com.smartdevicelink.proxy.rpc.enums.LightStatus;
-import com.smartdevicelink.proxy.rpc.enums.LockScreenStatus;
-import com.smartdevicelink.proxy.rpc.enums.MassageCushion;
-import com.smartdevicelink.proxy.rpc.enums.MassageMode;
-import com.smartdevicelink.proxy.rpc.enums.MassageZone;
-import com.smartdevicelink.proxy.rpc.enums.MediaClockFormat;
-import com.smartdevicelink.proxy.rpc.enums.MediaType;
-import com.smartdevicelink.proxy.rpc.enums.MenuLayout;
-import com.smartdevicelink.proxy.rpc.enums.MetadataType;
-import com.smartdevicelink.proxy.rpc.enums.ModuleType;
-import com.smartdevicelink.proxy.rpc.enums.NavigationAction;
-import com.smartdevicelink.proxy.rpc.enums.NavigationJunction;
-import com.smartdevicelink.proxy.rpc.enums.PRNDL;
-import com.smartdevicelink.proxy.rpc.enums.PowerModeQualificationStatus;
-import com.smartdevicelink.proxy.rpc.enums.PowerModeStatus;
-import com.smartdevicelink.proxy.rpc.enums.PrerecordedSpeech;
-import com.smartdevicelink.proxy.rpc.enums.PrimaryAudioSource;
-import com.smartdevicelink.proxy.rpc.enums.RadioBand;
-import com.smartdevicelink.proxy.rpc.enums.RadioState;
-import com.smartdevicelink.proxy.rpc.enums.RequestType;
-import com.smartdevicelink.proxy.rpc.enums.Result;
-import com.smartdevicelink.proxy.rpc.enums.SamplingRate;
-import com.smartdevicelink.proxy.rpc.enums.SeatMemoryActionType;
-import com.smartdevicelink.proxy.rpc.enums.SeekIndicatorType;
-import com.smartdevicelink.proxy.rpc.enums.ServiceUpdateReason;
-import com.smartdevicelink.proxy.rpc.enums.SoftButtonType;
-import com.smartdevicelink.proxy.rpc.enums.SpeechCapabilities;
-import com.smartdevicelink.proxy.rpc.enums.SupportedSeat;
-import com.smartdevicelink.proxy.rpc.enums.SystemAction;
-import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
-import com.smartdevicelink.proxy.rpc.enums.SystemContext;
-import com.smartdevicelink.proxy.rpc.enums.TBTState;
-import com.smartdevicelink.proxy.rpc.enums.TPMS;
-import com.smartdevicelink.proxy.rpc.enums.TemperatureUnit;
-import com.smartdevicelink.proxy.rpc.enums.TextAlignment;
-import com.smartdevicelink.proxy.rpc.enums.TextFieldName;
-import com.smartdevicelink.proxy.rpc.enums.TouchType;
-import com.smartdevicelink.proxy.rpc.enums.TransmissionType;
-import com.smartdevicelink.proxy.rpc.enums.TriggerSource;
-import com.smartdevicelink.proxy.rpc.enums.UpdateMode;
-import com.smartdevicelink.proxy.rpc.enums.VehicleDataEventStatus;
-import com.smartdevicelink.proxy.rpc.enums.VehicleDataNotificationStatus;
-import com.smartdevicelink.proxy.rpc.enums.VehicleDataResultCode;
-import com.smartdevicelink.proxy.rpc.enums.VehicleDataStatus;
-import com.smartdevicelink.proxy.rpc.enums.VehicleDataType;
-import com.smartdevicelink.proxy.rpc.enums.VentilationMode;
-import com.smartdevicelink.proxy.rpc.enums.VideoStreamingCodec;
-import com.smartdevicelink.proxy.rpc.enums.VideoStreamingProtocol;
-import com.smartdevicelink.proxy.rpc.enums.VideoStreamingState;
-import com.smartdevicelink.proxy.rpc.enums.VrCapabilities;
-import com.smartdevicelink.proxy.rpc.enums.WarningLightStatus;
-import com.smartdevicelink.proxy.rpc.enums.WayPointType;
-import com.smartdevicelink.proxy.rpc.enums.WindowType;
+import com.smartdevicelink.proxy.rpc.enums.*;
import com.smartdevicelink.util.Version;
import org.json.JSONArray;
@@ -365,6 +266,7 @@ public class TestValues {
public static final DisplayCapability GENERAL_DISPLAY_CAPABILITY = new DisplayCapability();
public static final SdlArtwork GENERAL_ARTWORK = new SdlArtwork("sdl", FileType.GRAPHIC_PNG, R.drawable.ic_sdl, false);
+ public static final SdlArtwork GENERAL_ARTWORK_STATIC = new SdlArtwork(StaticIconName.BACK);
public static final MenuLayout GENERAL_MENU_LAYOUT = MenuLayout.LIST;
public static final MenuConfiguration GENERAL_MENU_CONFIGURATION = new MenuConfiguration(GENERAL_MENU_LAYOUT, GENERAL_MENU_LAYOUT);
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java
index e8d89c818..094b29794 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java
@@ -3,6 +3,9 @@ package com.smartdevicelink.test;
import com.smartdevicelink.managers.file.filetypes.SdlFile;
import com.smartdevicelink.protocol.enums.FrameDataControlFrameType;
import com.smartdevicelink.protocol.enums.FrameType;
+import com.smartdevicelink.protocol.enums.SecurityQueryErrorCode;
+import com.smartdevicelink.protocol.enums.SecurityQueryID;
+import com.smartdevicelink.protocol.enums.SecurityQueryType;
import com.smartdevicelink.protocol.enums.SessionType;
import com.smartdevicelink.proxy.rpc.*;
import com.smartdevicelink.proxy.rpc.enums.AppServiceType;
@@ -10,7 +13,6 @@ import com.smartdevicelink.proxy.rpc.enums.DefrostZone;
import com.smartdevicelink.proxy.rpc.enums.FileType;
import com.smartdevicelink.proxy.rpc.enums.HMILevel;
import com.smartdevicelink.proxy.rpc.enums.HmiZoneCapabilities;
-import com.smartdevicelink.proxy.rpc.enums.KeyboardLayout;
import com.smartdevicelink.proxy.rpc.enums.PRNDL;
import com.smartdevicelink.proxy.rpc.enums.PrerecordedSpeech;
import com.smartdevicelink.proxy.rpc.enums.SpeechCapabilities;
@@ -126,6 +128,75 @@ public class Validator {
return true;
}
+ public static boolean validateQueryTypeArray(SecurityQueryType[] array1, SecurityQueryType[] array2) {
+
+ if (array1 == null) {
+ return (array2 == null);
+ }
+
+ if (array2 == null) {
+ return (array1 == null);
+ }
+
+ if (array1.length != array2.length) {
+ return false;
+ }
+
+ for (int i = 0; i < array1.length; i++) {
+ if (array1[i] != array2[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean validateQueryIDArray(SecurityQueryID[] array1, SecurityQueryID[] array2) {
+
+ if (array1 == null) {
+ return (array2 == null);
+ }
+
+ if (array2 == null) {
+ return (array1 == null);
+ }
+
+ if (array1.length != array2.length) {
+ return false;
+ }
+
+ for (int i = 0; i < array1.length; i++) {
+ if (array1[i] != array2[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean validateQueryErrorCodeArray(SecurityQueryErrorCode[] array1, SecurityQueryErrorCode[] array2) {
+
+ if (array1 == null) {
+ return (array2 == null);
+ }
+
+ if (array2 == null) {
+ return (array1 == null);
+ }
+
+ if (array1.length != array2.length) {
+ return false;
+ }
+
+ for (int i = 0; i < array1.length; i++) {
+ if (array1[i] != array2[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
public static boolean validateFrameDataControlFrameTypeArray(FrameDataControlFrameType[] array1, FrameDataControlFrameType[] array2) {
if (array1 == null) {
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/SecurityQueryPayloadTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/SecurityQueryPayloadTests.java
new file mode 100644
index 000000000..8c0c36041
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/SecurityQueryPayloadTests.java
@@ -0,0 +1,126 @@
+package com.smartdevicelink.test.protocol;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.smartdevicelink.protocol.SecurityQueryPayload;
+import com.smartdevicelink.protocol.enums.SecurityQueryID;
+import com.smartdevicelink.protocol.enums.SecurityQueryType;
+import com.smartdevicelink.util.BitConverter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+@RunWith(AndroidJUnit4.class)
+public class SecurityQueryPayloadTests {
+
+ public static SecurityQueryPayload createDummyBqh() {
+ SecurityQueryPayload bqh = new SecurityQueryPayload();
+ bqh.setCorrelationID(123);
+ bqh.setQueryID(SecurityQueryID.SEND_HANDSHAKE_DATA);
+ bqh.setQueryType(SecurityQueryType.REQUEST);
+ bqh.setBulkData(null);
+ bqh.setJsonSize(0);
+ return bqh;
+ }
+
+ public SecurityQueryPayload safeParse(byte[] array) {
+ try {
+ return SecurityQueryPayload.parseBinaryQueryHeader(array);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ @Test
+ public void testCorrectParsing() {
+ byte[] array = new byte[12];
+ array[0] = 0;
+ array[1] = 0;
+ array[2] = 0;
+ array[3] = 2;
+ array[4] = 0;
+ array[5] = 0;
+ array[6] = 0;
+ array[7] = 3;
+ array[8] = 0;
+ array[9] = 0;
+ array[10] = 0;
+ array[11] = 0;
+
+ SecurityQueryPayload parsedBqh = SecurityQueryPayload.parseBinaryQueryHeader(array);
+ assertEquals(parsedBqh.getQueryType(), SecurityQueryType.REQUEST);
+ assertEquals(parsedBqh.getQueryID(), SecurityQueryID.SEND_INTERNAL_ERROR);
+ assertEquals(parsedBqh.getCorrelationID(), 3);
+ assertEquals(parsedBqh.getJsonSize(), 0);
+ }
+
+ @Test
+ public void testCorrectHeaderAssembly() {
+ SecurityQueryPayload dummyBqh = new SecurityQueryPayload();
+ dummyBqh.setQueryType(SecurityQueryType.REQUEST);
+ dummyBqh.setQueryID(SecurityQueryID.SEND_HANDSHAKE_DATA);
+ dummyBqh.setCorrelationID(3);
+ dummyBqh.setJsonSize(0);
+
+ byte[] assembledHeader = dummyBqh.assembleHeaderBytes();
+ assertEquals(dummyBqh.getQueryType(), SecurityQueryType.valueOf(assembledHeader[0]));
+ byte[] queryIDFromHeader = new byte[3];
+ System.arraycopy(assembledHeader, 1, queryIDFromHeader, 0, 3);
+ assertEquals(dummyBqh.getQueryID(), SecurityQueryID.valueOf(queryIDFromHeader));
+ assertEquals(dummyBqh.getCorrelationID(), BitConverter.intFromByteArray(assembledHeader, 4));
+ assertEquals(dummyBqh.getJsonSize(), BitConverter.intFromByteArray(assembledHeader, 8));
+ }
+
+ @Test
+ public void testAssemblyAndParse() {
+ SecurityQueryPayload bqh = createDummyBqh();
+
+ byte[] bqhBytes = bqh.assembleHeaderBytes();
+ assertNotNull(bqhBytes);
+
+ SecurityQueryPayload parsedBqh = SecurityQueryPayload.parseBinaryQueryHeader(bqhBytes);
+ assertNotNull(parsedBqh);
+
+ assertEquals(bqh.getCorrelationID(), parsedBqh.getCorrelationID());
+ assertEquals(bqh.getQueryID(), parsedBqh.getQueryID());
+ assertEquals(bqh.getQueryType(), parsedBqh.getQueryType());
+ assertEquals(bqh.getBulkData(), parsedBqh.getBulkData());
+ assertEquals(bqh.getJsonData(), parsedBqh.getJsonData());
+ assertEquals(bqh.getJsonSize(), parsedBqh.getJsonSize());
+ }
+
+ @Test
+ public void testCorruptHeader() {
+ SecurityQueryPayload bqh = createDummyBqh();
+
+ byte[] bqhBytes = bqh.assembleHeaderBytes();
+
+ assertNotNull(safeParse(bqhBytes));
+
+ int size = bqhBytes.length;
+ for (int i = 0; i < size; i++) {
+ bqhBytes[i] = (byte) 0x99;
+ }
+
+ assertNull(safeParse(bqhBytes));
+ SecurityQueryPayload head = SecurityQueryPayload.parseBinaryQueryHeader(bqhBytes);
+ assertNull(head);
+ }
+
+ @Test
+ public void testJsonSetException() {
+ try {
+ SecurityQueryPayload bqh = createDummyBqh();
+ bqh.setJsonData(null);
+ fail("Setting JSON data to null should have thrown an exception");
+ } catch (Exception e) {
+ //Pass
+ }
+ }
+}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryErrorCodeTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryErrorCodeTests.java
new file mode 100644
index 000000000..0b6cd3f61
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryErrorCodeTests.java
@@ -0,0 +1,189 @@
+package com.smartdevicelink.test.protocol.enums;
+
+import com.smartdevicelink.protocol.enums.SecurityQueryErrorCode;
+import com.smartdevicelink.test.Validator;
+
+import junit.framework.TestCase;
+
+import java.util.Vector;
+
+public class SecurityQueryErrorCodeTests extends TestCase {
+
+ private Vector<SecurityQueryErrorCode> list = SecurityQueryErrorCode.getList();
+
+ public void testValidEnums() {
+ final byte ERROR_SUCCESS_BYTE = (byte) 0x00;
+ final String ERROR_SUCCESS_STRING = "ERROR_SUCCESS";
+
+ final byte ERROR_INVALID_QUERY_SIZE_BYTE = (byte) 0x01;
+ final String ERROR_INVALID_QUERY_SIZE_STRING = "ERROR_INVALID_QUERY_SIZE";
+
+ final byte ERROR_INVALID_QUERY_ID_BYTE = (byte) 0x02;
+ final String ERROR_INVALID_QUERY_ID_STRING = "ERROR_INVALID_QUERY_ID";
+
+ final byte ERROR_NOT_SUPPORTED_BYTE = (byte) 0x03;
+ final String ERROR_NOT_SUPPORTED_STRING = "ERROR_NOT_SUPPORTED";
+
+ final byte ERROR_SERVICE_ALREADY_PROTECTED_BYTE = (byte) 0x04;
+ final String ERROR_SERVICE_ALREADY_PROTECTED_STRING = "ERROR_SERVICE_ALREADY_PROTECTED";
+
+ final byte ERROR_SERVICE_NOT_PROTECTED_BYTE = (byte) 0x05;
+ final String ERROR_SERVICE_NOT_PROTECTED_STRING = "ERROR_SERVICE_NOT_PROTECTED";
+
+ final byte ERROR_DECRYPTION_FAILED_BYTE = (byte) 0x06;
+ final String ERROR_DECRYPTION_FAILED_STRING = "ERROR_DECRYPTION_FAILED";
+
+ final byte ERROR_ENCRYPTION_FAILED_BYTE = (byte) 0x07;
+ final String ERROR_ENCRYPTION_FAILED_STRING = "ERROR_ENCRYPTION_FAILED";
+
+ final byte ERROR_SSL_INVALID_DATA_BYTE = (byte) 0x08;
+ final String ERROR_SSL_INVALID_DATA_STRING = "ERROR_SSL_INVALID_DATA";
+
+ final byte ERROR_HANDSHAKE_FAILED_BYTE = (byte) 0x09;
+ final String ERROR_HANDSHAKE_FAILED_STRING = "ERROR_HANDSHAKE_FAILED";
+
+ final byte INVALID_CERT_BYTE = (byte) 0x0A;
+ final String INVALID_CERT_STRING = "INVALID_CERT";
+
+ final byte EXPIRED_CERT_BYTE = (byte) 0x0B;
+ final String EXPIRED_CERT_STRING = "EXPIRED_CERT";
+
+ final byte ERROR_INTERNAL_BYTE = (byte) 0xFF;
+ final String ERROR_INTERNAL_STRING = "ERROR_INTERNAL";
+
+ final byte ERROR_UNKNOWN_INTERNAL_ERROR_BYTE = (byte) 0xFE;
+ final String ERROR_UNKNOWN_INTERNAL_ERROR_STRING = "ERROR_UNKNOWN_INTERNAL_ERROR";
+
+ try {
+ assertNotNull("QueryErrorCode list returned null", list);
+
+ SecurityQueryErrorCode enumSuccess = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SUCCESS_BYTE);
+ SecurityQueryErrorCode enumInvalidQuerySize = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_INVALID_QUERY_SIZE_BYTE);
+ SecurityQueryErrorCode enumInvalidQueryID = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_INVALID_QUERY_ID_BYTE);
+ SecurityQueryErrorCode enumNotSupported = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_NOT_SUPPORTED_BYTE);
+ SecurityQueryErrorCode enumServiceAlreadyProtected = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SERVICE_ALREADY_PROTECTED_BYTE);
+ SecurityQueryErrorCode enumServiceNotProtected = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SERVICE_NOT_PROTECTED_BYTE);
+ SecurityQueryErrorCode enumDecryptionFailed = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_DECRYPTION_FAILED_BYTE);
+ SecurityQueryErrorCode enumEncryptionFailed = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_ENCRYPTION_FAILED_BYTE);
+ SecurityQueryErrorCode enumSSLInvalidData = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SSL_INVALID_DATA_BYTE);
+ SecurityQueryErrorCode enumHandshakeFailed = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_HANDSHAKE_FAILED_BYTE);
+ SecurityQueryErrorCode enumInvalidCert = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, INVALID_CERT_BYTE);
+ SecurityQueryErrorCode enumExpiredCert = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, EXPIRED_CERT_BYTE);
+ SecurityQueryErrorCode enumInternal = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_INTERNAL_BYTE);
+ SecurityQueryErrorCode enumUnknownInternalError = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_UNKNOWN_INTERNAL_ERROR_BYTE);
+
+ assertNotNull("Success byte match returned null", enumSuccess);
+ assertNotNull("Invalid Query Size byte match returned null", enumInvalidQuerySize);
+ assertNotNull("Invalid Query ID byte match returned null", enumInvalidQueryID);
+ assertNotNull("Not Supported byte match returned null", enumNotSupported);
+ assertNotNull("Service Already Protected byte match returned null", enumServiceAlreadyProtected);
+ assertNotNull("Service Not Protected byte match returned null", enumServiceNotProtected);
+ assertNotNull("Decryption Failed byte match returned null", enumDecryptionFailed);
+ assertNotNull("Encryption Failed byte match returned null", enumEncryptionFailed);
+ assertNotNull("SSL Invalid Data byte match returned null", enumSSLInvalidData);
+ assertNotNull("Handshake Failed byte match returned null", enumHandshakeFailed);
+ assertNotNull("Invalid Cert byte match returned null", enumInvalidCert);
+ assertNotNull("Expired Cert byte match returned null", enumExpiredCert);
+ assertNotNull("Internal byte match returned null", enumInternal);
+ assertNotNull("Unknown Internal byte match returned null", enumUnknownInternalError);
+
+ enumSuccess = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SUCCESS_STRING);
+ enumInvalidQuerySize = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_INVALID_QUERY_SIZE_STRING);
+ enumInvalidQueryID = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_INVALID_QUERY_ID_STRING);
+ enumNotSupported = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_NOT_SUPPORTED_STRING);
+ enumServiceAlreadyProtected = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SERVICE_ALREADY_PROTECTED_STRING);
+ enumServiceNotProtected = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SERVICE_NOT_PROTECTED_STRING);
+ enumDecryptionFailed = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_DECRYPTION_FAILED_STRING);
+ enumEncryptionFailed = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_ENCRYPTION_FAILED_STRING);
+ enumSSLInvalidData = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SSL_INVALID_DATA_STRING);
+ enumHandshakeFailed = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_HANDSHAKE_FAILED_STRING);
+ enumInvalidCert = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, INVALID_CERT_STRING);
+ enumExpiredCert = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, EXPIRED_CERT_STRING);
+ enumInternal = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_INTERNAL_STRING);
+ enumUnknownInternalError = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_UNKNOWN_INTERNAL_ERROR_STRING);
+
+ assertNotNull("Success string match returned null", enumSuccess);
+ assertNotNull("Invalid Query Size string match returned null", enumInvalidQuerySize);
+ assertNotNull("Invalid Query ID string match returned null", enumInvalidQueryID);
+ assertNotNull("Not Supported string match returned null", enumNotSupported);
+ assertNotNull("Service Already Protected string match returned null", enumServiceAlreadyProtected);
+ assertNotNull("Service Not Protected string match returned null", enumServiceNotProtected);
+ assertNotNull("Decryption Failed string match returned null", enumDecryptionFailed);
+ assertNotNull("Encryption Failed string match returned null", enumEncryptionFailed);
+ assertNotNull("SSL Invalid Data string match returned null", enumSSLInvalidData);
+ assertNotNull("Handshake Failed string match returned null", enumHandshakeFailed);
+ assertNotNull("Invalid Cert string match returned null", enumInvalidCert);
+ assertNotNull("Expired Cert string match returned null", enumExpiredCert);
+ assertNotNull("Internal string match returned null", enumInternal);
+ assertNotNull("Unknown Internal string match returned null", enumUnknownInternalError);
+ } catch (NullPointerException exception) {
+ fail("Null enum list throws NullPointerException.");
+ }
+ }
+
+ public void testInvalidEnum() {
+ final byte INVALID_BYTE = (byte) 0xAB;
+ final String INVALID_STRING = "Invalid";
+
+ try {
+ SecurityQueryErrorCode enumInvalid = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, INVALID_BYTE);
+ assertNull("Invalid byte match didn't return null", enumInvalid);
+
+ enumInvalid = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, INVALID_STRING);
+ assertNull("Invalid byte match didn't return null", enumInvalid);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ public void testNullEnum() {
+ try {
+ SecurityQueryErrorCode enumNull = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, null);
+ assertNull("Null lookup returns a value", enumNull);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ public void testListEnum() {
+ Vector<SecurityQueryErrorCode> enumTestList = new Vector<>();
+ enumTestList.add(SecurityQueryErrorCode.ERROR_SUCCESS);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_INVALID_QUERY_SIZE);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_INVALID_QUERY_ID);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_NOT_SUPPORTED);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_SERVICE_ALREADY_PROTECTED);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_SERVICE_NOT_PROTECTED);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_DECRYPTION_FAILED);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_ENCRYPTION_FAILED);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_SSL_INVALID_DATA);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_HANDSHAKE_FAILED);
+ enumTestList.add(SecurityQueryErrorCode.INVALID_CERT);
+ enumTestList.add(SecurityQueryErrorCode.EXPIRED_CERT);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_INTERNAL);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_UNKNOWN_INTERNAL_ERROR);
+
+ assertTrue("List does not match enum test list.",
+ list.containsAll(enumTestList) &&
+ enumTestList.containsAll(list));
+
+ SecurityQueryErrorCode[] enumValueArray = SecurityQueryErrorCode.values();
+ SecurityQueryErrorCode[] enumTestArray = {
+ SecurityQueryErrorCode.ERROR_SUCCESS,
+ SecurityQueryErrorCode.ERROR_INVALID_QUERY_SIZE,
+ SecurityQueryErrorCode.ERROR_INVALID_QUERY_ID,
+ SecurityQueryErrorCode.ERROR_NOT_SUPPORTED,
+ SecurityQueryErrorCode.ERROR_SERVICE_ALREADY_PROTECTED,
+ SecurityQueryErrorCode.ERROR_SERVICE_NOT_PROTECTED,
+ SecurityQueryErrorCode.ERROR_DECRYPTION_FAILED,
+ SecurityQueryErrorCode.ERROR_ENCRYPTION_FAILED,
+ SecurityQueryErrorCode.ERROR_SSL_INVALID_DATA,
+ SecurityQueryErrorCode.ERROR_HANDSHAKE_FAILED,
+ SecurityQueryErrorCode.INVALID_CERT,
+ SecurityQueryErrorCode.EXPIRED_CERT,
+ SecurityQueryErrorCode.ERROR_INTERNAL,
+ SecurityQueryErrorCode.ERROR_UNKNOWN_INTERNAL_ERROR
+ };
+ assertTrue("Array does not match enum values array.",
+ Validator.validateQueryErrorCodeArray(enumValueArray, enumTestArray));
+ }
+}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryIDTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryIDTests.java
new file mode 100644
index 000000000..4f73f8139
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryIDTests.java
@@ -0,0 +1,91 @@
+package com.smartdevicelink.test.protocol.enums;
+
+import com.smartdevicelink.protocol.enums.SecurityQueryID;
+import com.smartdevicelink.test.Validator;
+
+import junit.framework.TestCase;
+
+import java.util.Vector;
+
+public class SecurityQueryIDTests extends TestCase {
+
+ private Vector<SecurityQueryID> list = SecurityQueryID.getList();
+
+ public void testValidEnums() {
+ final byte[] SEND_HANDSHAKE_DATA_BYTES = {(byte) 0x00, (byte) 0x00, (byte) 0x01};
+ final String SEND_HANDSHAKE_DATA_STRING = "SEND_HANDSHAKE_DATA";
+
+ final byte[] SEND_INTERNAL_ERROR_BYTES = {(byte) 0x00, (byte) 0x00, (byte) 0x02};
+ final String SEND_INTERNAL_ERROR_STRING = "SEND_INTERNAL_ERROR";
+
+ final byte[] INVALID_QUERY_ID_BYTES = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
+ final String INVALID_QUERY_ID_STRING = "INVALID_QUERY_ID";
+
+ try {
+ assertNotNull("QueryID list returned null", list);
+
+ SecurityQueryID enumHandshakeData = (SecurityQueryID) SecurityQueryID.get(list, SEND_HANDSHAKE_DATA_BYTES);
+ SecurityQueryID enumInternalError = (SecurityQueryID) SecurityQueryID.get(list, SEND_INTERNAL_ERROR_BYTES);
+ SecurityQueryID enumInvalidSecurityQueryId = (SecurityQueryID) SecurityQueryID.get(list, INVALID_QUERY_ID_BYTES);
+
+ assertNotNull("Send Handshake Data byte match returned null", enumHandshakeData);
+ assertNotNull("Send Internal Error byte match returned null", enumInternalError);
+ assertNotNull("Send Invalid QueryID byte match returned null", enumInvalidSecurityQueryId);
+
+ enumHandshakeData = (SecurityQueryID) SecurityQueryID.get(list, SEND_HANDSHAKE_DATA_STRING);
+ enumInternalError = (SecurityQueryID) SecurityQueryID.get(list, SEND_INTERNAL_ERROR_STRING);
+ enumInvalidSecurityQueryId = (SecurityQueryID) SecurityQueryID.get(list, INVALID_QUERY_ID_STRING);
+
+ assertNotNull("Send Handshake Data string match returned null", enumHandshakeData);
+ assertNotNull("Send Internal Error string match returned null", enumInternalError);
+ assertNotNull("Send Invalid QueryID string match returned null", enumInvalidSecurityQueryId);
+ } catch(NullPointerException exception) {
+ fail("Null enum list throws NullPointerException.");
+ }
+ }
+
+ public void testInvalidEnum() {
+
+ final byte[] INVALID_BYTE_ARRAY = {(byte) 0xAB, (byte) 0xAB, (byte) 0xAB};
+ final String INVALID_STRING = "Invalid";
+
+ try {
+ SecurityQueryID enumInvalid = (SecurityQueryID) SecurityQueryID.get(list, INVALID_BYTE_ARRAY);
+ assertNull("Invalid byte[] match didn't return null", enumInvalid);
+
+ enumInvalid = (SecurityQueryID) SecurityQueryID.get(list, INVALID_STRING);
+ assertNull("Invalid string match didn't return null", enumInvalid);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ public void testNullEnum() {
+ try {
+ SecurityQueryID enumNull = (SecurityQueryID) SecurityQueryID.get(list, (String) null);
+ assertNull("Null lookup returns a null string value", enumNull);
+
+ enumNull = (SecurityQueryID) SecurityQueryID.get(list, (byte[]) null);
+ assertNull("Null lookup returns a null byte[] value", enumNull);
+ }catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ public void testListEnum() {
+ Vector<SecurityQueryID> enumTestList = new Vector<>();
+ enumTestList.add(SecurityQueryID.SEND_HANDSHAKE_DATA);
+ enumTestList.add(SecurityQueryID.SEND_INTERNAL_ERROR);
+ enumTestList.add(SecurityQueryID.INVALID_QUERY_ID);
+
+ assertTrue("List does not match enum test list.",
+ list.containsAll(enumTestList) &&
+ enumTestList.containsAll(list));
+
+ SecurityQueryID[] enumValueArray = SecurityQueryID.values();
+ SecurityQueryID[] enumTestArray = {SecurityQueryID.SEND_HANDSHAKE_DATA, SecurityQueryID.SEND_INTERNAL_ERROR, SecurityQueryID.INVALID_QUERY_ID};
+ assertTrue("Array does not match enum values array.",
+ Validator.validateQueryIDArray(enumValueArray, enumTestArray));
+ }
+
+}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryTypeTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryTypeTests.java
new file mode 100644
index 000000000..6835da946
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryTypeTests.java
@@ -0,0 +1,97 @@
+package com.smartdevicelink.test.protocol.enums;
+
+import com.smartdevicelink.protocol.enums.SecurityQueryType;
+import com.smartdevicelink.test.Validator;
+
+import junit.framework.TestCase;
+
+import java.util.Vector;
+
+public class SecurityQueryTypeTests extends TestCase {
+
+ private Vector<SecurityQueryType> list = SecurityQueryType.getList();
+
+ public void testValidEnums() {
+ final byte REQUEST_BYTE = (byte) 0x00;
+ final String REQUEST_STRING = "REQUEST";
+
+ final byte RESPONSE_BYTE = (byte) 0x10;
+ final String RESPONSE_STRING = "RESPONSE";
+
+ final byte NOTIFICATION_BYTE = (byte) 0x20;
+ final String NOTIFICATION_STRING = "NOTIFICATION";
+
+ final byte INVALID_QUERY_TYPE_BYTE = (byte) 0xFF;
+ final String INVALID_QUERY_TYPE_STRING = "INVALID_QUERY_TYPE";
+
+ try {
+ assertNotNull("QueryType list returned null", list);
+
+ SecurityQueryType enumRequest = (SecurityQueryType) SecurityQueryType.get(list, REQUEST_BYTE);
+ SecurityQueryType enumResponse = (SecurityQueryType) SecurityQueryType.get(list, RESPONSE_BYTE);
+ SecurityQueryType enumNotification = (SecurityQueryType) SecurityQueryType.get(list, NOTIFICATION_BYTE);
+ SecurityQueryType enumInvalidSecurityQueryType = (SecurityQueryType) SecurityQueryType.get(list, INVALID_QUERY_TYPE_BYTE);
+
+ assertNotNull("Request byte match returned null", enumRequest);
+ assertNotNull("Response byte match returned null", enumResponse);
+ assertNotNull("Notification byte match returned null", enumNotification);
+ assertNotNull("Invalid Query Type byte match returned null", enumInvalidSecurityQueryType);
+
+ enumRequest = (SecurityQueryType) SecurityQueryType.get(list, REQUEST_STRING);
+ enumResponse = (SecurityQueryType) SecurityQueryType.get(list, RESPONSE_STRING);
+ enumNotification = (SecurityQueryType) SecurityQueryType.get(list, NOTIFICATION_STRING);
+ enumInvalidSecurityQueryType = (SecurityQueryType) SecurityQueryType.get(list, INVALID_QUERY_TYPE_STRING);
+
+ assertNotNull("Request string match returned null", enumRequest);
+ assertNotNull("Response string match returned null", enumResponse);
+ assertNotNull("Notification string match returned null", enumNotification);
+ assertNotNull("Invalid Query string byte match returned null", enumInvalidSecurityQueryType);
+
+
+ }catch (NullPointerException exception) {
+ fail("Null enum list throws NullPointerException.");
+ }
+ }
+
+ public void testInvalidEnum() {
+
+ final byte INVALID_BYTE = (byte) 0xAB;
+ final String INVALID_STRING = "Invalid";
+
+ try {
+ SecurityQueryType enumInvalid = (SecurityQueryType) SecurityQueryType.get(list, INVALID_BYTE);
+ assertNull("Invalid byte match didn't return null", enumInvalid);
+
+ enumInvalid = (SecurityQueryType) SecurityQueryType.get(list, INVALID_STRING);
+ assertNull("Invalid string match didn't return null", enumInvalid);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ public void testNullEnum() {
+ try {
+ SecurityQueryType enumNull = (SecurityQueryType) SecurityQueryType.get(list, null);
+ assertNull("Null lookup returns a value", enumNull);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ public void testListEnum() {
+ Vector<SecurityQueryType> enumTestList = new Vector<>();
+ enumTestList.add(SecurityQueryType.REQUEST);
+ enumTestList.add(SecurityQueryType.RESPONSE);
+ enumTestList.add(SecurityQueryType.NOTIFICATION);
+ enumTestList.add(SecurityQueryType.INVALID_QUERY_TYPE);
+
+ assertTrue("List does not match enum test list.",
+ list.containsAll(enumTestList) &&
+ enumTestList.containsAll(list));
+
+ SecurityQueryType[] enumValueArray = SecurityQueryType.values();
+ SecurityQueryType[] enumTestArray = {SecurityQueryType.REQUEST, SecurityQueryType.RESPONSE, SecurityQueryType.NOTIFICATION, SecurityQueryType.INVALID_QUERY_TYPE};
+ assertTrue("Array does not match enum values array.",
+ Validator.validateQueryTypeArray(enumValueArray, enumTestArray));
+ }
+}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/VehicleTypeTest.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/VehicleTypeTest.java
index a77de7473..9bb432e51 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/VehicleTypeTest.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/VehicleTypeTest.java
@@ -8,7 +8,10 @@ import junit.framework.TestCase;
import org.json.JSONException;
import org.json.JSONObject;
+import org.junit.Assert;
+import java.util.HashMap;
+import java.util.Hashtable;
import java.util.Iterator;
public class VehicleTypeTest extends TestCase {
@@ -72,4 +75,15 @@ public class VehicleTypeTest extends TestCase {
fail(TestValues.JSON_FAIL);
}
}
+
+ public void testHashMapConstructor() {
+ Hashtable<String, Object> store = msg.getStore();
+ HashMap<String, Object> hashMap = new HashMap(store);
+ VehicleType type = new VehicleType(hashMap);
+
+ Assert.assertEquals(type.getMake(), msg.getMake());
+ Assert.assertEquals(type.getModel(), msg.getModel());
+ Assert.assertEquals(type.getModelYear(), msg.getModelYear());
+ Assert.assertEquals(type.getTrim(), msg.getTrim());
+ }
} \ No newline at end of file
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java
index 7909d4997..1dfa0700b 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java
@@ -42,6 +42,8 @@ import android.os.Bundle;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.smartdevicelink.R;
+import com.smartdevicelink.proxy.rpc.VehicleType;
+import com.smartdevicelink.test.TestValues;
import com.smartdevicelink.util.SdlAppInfo;
import org.junit.Before;
@@ -49,10 +51,12 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertNotNull;
@@ -85,7 +89,7 @@ public class SdlAppInfoTests {
@Test
public void testConstructorWithDefaultData() {
- SdlAppInfo info = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo);
+ SdlAppInfo info = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo, context);
assertNotNull(info);
@@ -105,10 +109,10 @@ public class SdlAppInfoTests {
*/
@Test
public void testCompareVersion() {
- SdlAppInfo defaultInfo = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo);
+ SdlAppInfo defaultInfo = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo, context);
int newVersion = context.getResources().getInteger(R.integer.sdl_router_service_version_value) + 1;
- SdlAppInfo testInfo = new SdlAppInfo(createResolveInfo(newVersion, "com.smartdevicelink.test2", "com.smartdevicelink.test2.SdlRouterService", false), defaultPackageInfo);
+ SdlAppInfo testInfo = new SdlAppInfo(createResolveInfo(newVersion, "com.smartdevicelink.test2", "com.smartdevicelink.test2.SdlRouterService", false), defaultPackageInfo, context);
List<SdlAppInfo> infos = new ArrayList<>();
infos.add(defaultInfo);
@@ -126,10 +130,10 @@ public class SdlAppInfoTests {
*/
@Test
public void testCompareVersionAndCustom() {
- SdlAppInfo defaultInfo = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo);
+ SdlAppInfo defaultInfo = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo, context);
int newVersion = context.getResources().getInteger(R.integer.sdl_router_service_version_value) + 1;
- SdlAppInfo testInfo = new SdlAppInfo(createResolveInfo(newVersion, "com.smartdevicelink.test2", "com.smartdevicelink.test2.SdlRouterService", true), defaultPackageInfo);
+ SdlAppInfo testInfo = new SdlAppInfo(createResolveInfo(newVersion, "com.smartdevicelink.test2", "com.smartdevicelink.test2.SdlRouterService", true), defaultPackageInfo, context);
List<SdlAppInfo> infos = new ArrayList<>();
infos.add(defaultInfo);
@@ -147,12 +151,12 @@ public class SdlAppInfoTests {
*/
@Test
public void testCompareUpdatedTime() {
- SdlAppInfo defaultInfo = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo);
+ SdlAppInfo defaultInfo = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo, context);
PackageInfo packageInfo = new PackageInfo();
packageInfo.firstInstallTime = defaultPackageInfo.firstInstallTime;
packageInfo.lastUpdateTime = defaultPackageInfo.lastUpdateTime + 500;
- SdlAppInfo testInfo = new SdlAppInfo(defaultResolveInfo, packageInfo);
+ SdlAppInfo testInfo = new SdlAppInfo(defaultResolveInfo, packageInfo, context);
List<SdlAppInfo> infos = new ArrayList<>();
infos.add(defaultInfo);
@@ -179,5 +183,106 @@ public class SdlAppInfoTests {
return info;
}
+ @Test
+ public void testDeserializeVehicleInfo() {
+ VehicleType type = new VehicleType();
+ type.setMake("SDL");
+ type.setModel("Car");
+ type.setModelYear("2019");
+ type.setTrim("GT");
+ List<VehicleType> deserializedList = SdlAppInfo.deserializeSupportedVehicles(getInstrumentation().getContext().getResources().getXml(com.smartdevicelink.test.R.xml.supported_vehicle_type));
+ assertTrue(deserializedList.contains(type));
+ assertEquals(1, deserializedList.size());
+ }
+
+ @Test
+ public void testVehicleTypeSupported() {
+ // tests check with all params
+ VehicleType type1 = new VehicleType();
+ type1.setMake(TestValues.GENERAL_STRING);
+ type1.setModel(TestValues.GENERAL_STRING);
+ type1.setMake(TestValues.GENERAL_STRING);
+ type1.setTrim(TestValues.GENERAL_STRING);
+
+ VehicleType type2 = new VehicleType();
+ type2.setMake(TestValues.GENERAL_STRING);
+ type2.setModel(TestValues.GENERAL_STRING);
+ type2.setModelYear(TestValues.GENERAL_INTEGER.toString());
+ type2.setTrim(TestValues.GENERAL_STRING);
+
+ List<VehicleType> supportedVehicleList = Arrays.asList(type1, type2);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(supportedVehicleList, type2));
+
+ // tests check with not all params in connectedVehicle
+ VehicleType connectedVehicle = new VehicleType();
+
+ // make only param
+ connectedVehicle.setMake(TestValues.GENERAL_STRING);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(supportedVehicleList, connectedVehicle));
+
+ // make and model params
+ connectedVehicle.setModel(TestValues.GENERAL_STRING);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(supportedVehicleList, connectedVehicle));
+
+ // make, model and year params
+ connectedVehicle.setModelYear(TestValues.GENERAL_STRING);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(supportedVehicleList, connectedVehicle));
+
+ // make, model and trim params
+ connectedVehicle.setModelYear(null);
+ connectedVehicle.setTrim(TestValues.GENERAL_STRING);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(supportedVehicleList, connectedVehicle));
+
+ // tests check with not all params in supportedVehicle
+ VehicleType supportedVehicle = new VehicleType();
+ supportedVehicle.setMake(TestValues.GENERAL_STRING);
+
+ // make param only
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(Collections.singletonList(supportedVehicle), connectedVehicle));
+
+ // make and model params
+ supportedVehicle.setModel(TestValues.GENERAL_STRING);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(Collections.singletonList(supportedVehicle), connectedVehicle));
+
+ // make, model and trim params
+ supportedVehicle.setTrim(TestValues.GENERAL_STRING);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(Collections.singletonList(supportedVehicle), connectedVehicle));
+
+ // make, model and trim params
+ supportedVehicle.setTrim(TestValues.GENERAL_STRING);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(Collections.singletonList(supportedVehicle), connectedVehicle));
+
+ // make, model and trim params
+ connectedVehicle.setTrim(null);
+ connectedVehicle.setModelYear(TestValues.GENERAL_INTEGER.toString());
+ supportedVehicle.setModelYear(TestValues.GENERAL_INTEGER.toString());
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(Collections.singletonList(supportedVehicle), connectedVehicle));
+ }
+
+ @Test
+ public void testVehicleTypeNotSupported() {
+ VehicleType type1 = new VehicleType();
+
+ type1.setModel(TestValues.GENERAL_STRING);
+ type1.setMake(TestValues.GENERAL_INTEGER.toString());
+ type1.setTrim(TestValues.GENERAL_STRING);
+ type1.setModelYear(TestValues.GENERAL_STRING);
+
+ VehicleType type2 = new VehicleType();
+
+ type2.setModel(TestValues.GENERAL_STRING);
+ type2.setMake(TestValues.GENERAL_INTEGER.toString());
+ type2.setTrim(TestValues.GENERAL_STRING);
+ type2.setModelYear(TestValues.GENERAL_STRING);
+
+ VehicleType type3 = new VehicleType();
+
+ type3.setModel(TestValues.GENERAL_STRING);
+ type3.setMake(TestValues.GENERAL_STRING);
+ type3.setTrim(TestValues.GENERAL_STRING);
+ type3.setModelYear(TestValues.GENERAL_INTEGER.toString());
+
+ assertFalse(SdlAppInfo.checkIfVehicleSupported(Arrays.asList(type1, type2), type3));
+ }
}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java
index 1ad01a1c3..c4104b585 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java
@@ -1,17 +1,26 @@
package com.smartdevicelink.test.utl;
import android.content.ComponentName;
+import android.content.Context;
+import android.content.SharedPreferences;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.smartdevicelink.proxy.rpc.VehicleType;
import com.smartdevicelink.util.AndroidTools;
import junit.framework.Assert;
+import org.json.JSONException;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
@RunWith(AndroidJUnit4.class)
public class AndroidToolsTests {
@@ -39,4 +48,32 @@ public class AndroidToolsTests {
}
+ @Test
+ public void testVehicleTypeSave() throws JSONException {
+ Context mMockContext = mock(Context.class);
+ VehicleType mMockVehicleType = new VehicleType();
+ String mAddress = "1234";
+
+ mMockVehicleType.setMake("Ford");
+ mMockVehicleType.setTrim("GT");
+ mMockVehicleType.setModel("Mustang");
+ mMockVehicleType.setModelYear("2019");
+
+ SharedPreferences.Editor editor = mock(SharedPreferences.Editor.class);
+ when(editor.commit()).thenReturn(true);
+
+ SharedPreferences sharedPrefs = Mockito.mock(SharedPreferences.class);
+ when(mMockContext.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
+ when(sharedPrefs.edit()).thenReturn(editor);
+ when(sharedPrefs.getString(mAddress, null)).thenReturn(mMockVehicleType.serializeJSON().toString());
+
+ AndroidTools.saveVehicleType(mMockContext, mMockVehicleType, mAddress);
+ VehicleType type = new VehicleType(AndroidTools.getVehicleTypeFromPrefs(mMockContext, mAddress));
+
+ org.junit.Assert.assertEquals(type.getMake(), mMockVehicleType.getMake());
+ org.junit.Assert.assertEquals(type.getModel(), mMockVehicleType.getModel());
+ org.junit.Assert.assertEquals(type.getModelYear(), mMockVehicleType.getModelYear());
+ org.junit.Assert.assertEquals(type.getTrim(), mMockVehicleType.getTrim());
+ }
+
}
diff --git a/android/sdl_android/src/androidTest/res/xml/supported_vehicle_type.xml b/android/sdl_android/src/androidTest/res/xml/supported_vehicle_type.xml
new file mode 100644
index 000000000..36e2fd169
--- /dev/null
+++ b/android/sdl_android/src/androidTest/res/xml/supported_vehicle_type.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resource>
+ <vehicle-type
+ make="SDL"
+ model="Car"
+ modelYear="2019"
+ trim="GT" />
+
+ <vehicle-type
+ make="SDL2"
+ modelYear="2019" />
+</resource> \ No newline at end of file
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java b/android/sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java
index 7c8df5b98..3eba6af30 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java
@@ -337,7 +337,7 @@ public class VirtualDisplayEncoder {
Looper.prepare();
// create a Handler for this thread
- mHandler = new Handler() {
+ mHandler = new Handler(Looper.myLooper()) {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_TICK: {
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java
index c8887d4e1..b46745917 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java
@@ -40,7 +40,6 @@ import com.smartdevicelink.proxy.rpc.Image;
import com.smartdevicelink.proxy.rpc.enums.FileType;
import com.smartdevicelink.proxy.rpc.enums.ImageType;
import com.smartdevicelink.proxy.rpc.enums.StaticIconName;
-import com.smartdevicelink.util.DebugTool;
/**
* A class that extends SdlFile, representing artwork (JPEG, PNG, or BMP) to be uploaded to core
@@ -159,16 +158,10 @@ public class SdlArtwork extends SdlFile implements Cloneable {
*/
@Override
public SdlArtwork clone() {
- try {
- SdlArtwork artwork = (SdlArtwork) super.clone();
- if (artwork != null) {
- artwork.imageRPC = artwork.createImageRPC();
- }
+ SdlArtwork artwork = (SdlArtwork) super.clone();
+ if (artwork != null) {
+ artwork.imageRPC = artwork.createImageRPC();
return artwork;
- } catch (CloneNotSupportedException e) {
- if (DebugTool.isDebugEnabled()) {
- throw new RuntimeException("Clone not supported by super class");
- }
}
return null;
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java
index 13c7d3119..a0c0d9369 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java
@@ -38,6 +38,7 @@ import androidx.annotation.NonNull;
import com.smartdevicelink.proxy.rpc.enums.FileType;
import com.smartdevicelink.proxy.rpc.enums.StaticIconName;
+import com.smartdevicelink.util.DebugTool;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -46,7 +47,7 @@ import java.util.Arrays;
/**
* A class representing data to be uploaded to core
*/
-public class SdlFile {
+public class SdlFile implements Cloneable {
private String fileName;
private int id = -1;
private Uri uri;
@@ -368,4 +369,22 @@ public class SdlFile {
// return comparison
return hashCode() == o.hashCode();
}
+
+ /**
+ * Creates a deep copy of the object
+ *
+ * @return deep copy of the object, null if an exception occurred
+ */
+ @Override
+ public SdlFile clone() {
+ try {
+ SdlFile fileClone = (SdlFile) super.clone();
+ return fileClone;
+ } catch (CloneNotSupportedException e) {
+ if (DebugTool.isDebugEnabled()) {
+ throw new RuntimeException("Clone not supported by super class");
+ }
+ }
+ return null;
+ }
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java
index 1b54b0e1f..6d4fddb3d 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java
@@ -40,6 +40,7 @@ import com.smartdevicelink.exception.SdlException;
import com.smartdevicelink.exception.SdlExceptionCause;
import com.smartdevicelink.protocol.ISdlServiceListener;
import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.proxy.rpc.VehicleType;
import com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason;
import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
import com.smartdevicelink.security.SdlSecurityBase;
@@ -49,9 +50,12 @@ import com.smartdevicelink.transport.BaseTransportConfig;
import com.smartdevicelink.transport.MultiplexTransportConfig;
import com.smartdevicelink.transport.TCPTransportConfig;
import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
+import com.smartdevicelink.util.AndroidTools;
import com.smartdevicelink.util.DebugTool;
import java.lang.ref.WeakReference;
+import java.util.List;
/**
* The lifecycle manager creates a central point for all SDL session logic to converge. It should only be used by
@@ -98,6 +102,29 @@ public class LifecycleManager extends BaseLifecycleManager {
}
}
+ @Override
+ void saveVehicleType(String address, VehicleType type) {
+ AndroidTools.saveVehicleType(contextWeakReference.get(), type, address);
+ }
+
+ @Override
+ void saveVehicleType(List<TransportRecord> activeTransports, VehicleType type) {
+ if (activeTransports == null || activeTransports.isEmpty() || type == null) {
+ DebugTool.logWarning(TAG, "Unable to save vehicle type");
+ return;
+ }
+
+ for (TransportRecord record: activeTransports) {
+ if (record.getType() == TransportType.BLUETOOTH) {
+ String address = record.getAddress();
+ if (address != null && !address.isEmpty()) {
+ saveVehicleType(address, type);
+ }
+ break;
+ }
+ }
+ }
+
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setContext(Context context) {
this.contextWeakReference = new WeakReference<>(context);
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java
index 6f0e68aba..97e8c8bca 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java
@@ -38,6 +38,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.os.Handler;
+import android.os.Looper;
import androidx.annotation.RestrictTo;
@@ -227,7 +228,7 @@ public class LockScreenManager extends BaseSubManager {
mLockScreenShouldBeAutoDismissed = false;
}
if (!receivedFirstDDNotification) {
- new Handler().postDelayed(new Runnable() {
+ new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
launchLockScreenActivity();
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/protocol/heartbeat/HeartbeatMonitor.java b/android/sdl_android/src/main/java/com/smartdevicelink/protocol/heartbeat/HeartbeatMonitor.java
index c60cdaadf..831e59da4 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/protocol/heartbeat/HeartbeatMonitor.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/protocol/heartbeat/HeartbeatMonitor.java
@@ -155,7 +155,7 @@ public class HeartbeatMonitor implements IHeartbeatMonitor {
Looper.prepare();
mHeartbeatThreadLooper = Looper.myLooper();
- mHeartbeatThreadHandler = new Handler();
+ mHeartbeatThreadHandler = new Handler(mHeartbeatThreadLooper);
mIsAckReceived = true;
isHeartbeatReceived = true;
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java
index fba01a561..31cea21c8 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java
@@ -348,7 +348,10 @@ public class MultiplexBluetoothTransport extends MultiplexBaseTransport {
}
private void timerDelayRemoveDialog(final BluetoothSocket sock) {
- timeOutHandler = new Handler();
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ timeOutHandler = new Handler(Looper.myLooper());
socketRunnable = new Runnable() {
public void run() {
//Log.e(TAG, "BLUETOOTH SOCKET CONNECT TIMEOUT - ATTEMPT TO CLOSE SOCKET");
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java
index c86cb6d94..588b905cc 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java
@@ -49,6 +49,7 @@ import android.util.AndroidRuntimeException;
import androidx.annotation.CallSuper;
+import com.smartdevicelink.proxy.rpc.VehicleType;
import com.smartdevicelink.transport.RouterServiceValidator.TrustedListCallback;
import com.smartdevicelink.transport.enums.TransportType;
import com.smartdevicelink.transport.utl.SdlDeviceListener;
@@ -58,6 +59,8 @@ import com.smartdevicelink.util.IntegrationValidator;
import com.smartdevicelink.util.SdlAppInfo;
import com.smartdevicelink.util.ServiceFinder;
+import java.util.HashMap;
+import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Vector;
@@ -145,6 +148,15 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
DebugTool.logError(TAG, "You cannot use the default SdlRouterService class, it must be extended in your project. THIS WILL THROW AN EXCEPTION IN FUTURE RELEASES!!");
}
+ HashMap<String, Object> vehicleInfoStore = (HashMap<String, Object>) intent.getSerializableExtra(TransportConstants.VEHICLE_INFO_EXTRA);
+
+ VehicleType vehicleType;
+ if (vehicleInfoStore == null || vehicleInfoStore.isEmpty()) {
+ vehicleType = null;
+ } else {
+ vehicleType = new VehicleType(vehicleInfoStore);
+ }
+
//This will only be true if we are being told to reopen our SDL service because SDL is enabled
if (action.equalsIgnoreCase(TransportConstants.START_ROUTER_SERVICE_ACTION)) {
if (intent.hasExtra(TransportConstants.START_ROUTER_SERVICE_SDL_ENABLED_EXTRA)) {
@@ -178,7 +190,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
} else if (intent.getBooleanExtra(TransportConstants.PING_ROUTER_SERVICE_EXTRA, false)) {
//We were told to wake up our router services
boolean altServiceWake = intent.getBooleanExtra(TransportConstants.BIND_REQUEST_TYPE_ALT_TRANSPORT, false);
- didStart = wakeUpRouterService(context, false, altServiceWake, device);
+ didStart = wakeUpRouterService(context, false, altServiceWake, device, vehicleType);
}
}
@@ -189,7 +201,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
if (!didStart) {
DebugTool.logInfo(TAG, "attempting to wake up router service");
- didStart = wakeUpRouterService(context, true, false, device);
+ didStart = wakeUpRouterService(context, true, false, device, vehicleType);
}
//So even though we started our own version, on some older phones we find that two services are started up so we want to make sure we send our version that we are working with
@@ -211,8 +223,10 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
* @param componentName the router service that should be started
* @param altTransportWake if the alt transport flag should be set. Only used in debug
* @param device the connected bluetooth device
+ * @param confirmedDevice if the device is confirmed
+ * @param vehicleType vehicle params retrieved from connected device
*/
- private static void startRouterService(Context context, ComponentName componentName, boolean altTransportWake, BluetoothDevice device, boolean confirmedDevice) {
+ private static void startRouterService(Context context, ComponentName componentName, boolean altTransportWake, BluetoothDevice device, boolean confirmedDevice, VehicleType vehicleType) {
if (componentName == null) {
return;
}
@@ -232,6 +246,17 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
serviceIntent.putExtra(TransportConstants.CONFIRMED_SDL_DEVICE, confirmedDevice);
}
+ if (vehicleType == null) {
+ final String address = device != null ? device.getAddress() : null;
+ Hashtable<String, Object> store = AndroidTools.getVehicleTypeFromPrefs(context, address);
+ if (store != null) {
+ vehicleType = new VehicleType(store);
+ }
+ }
+ if (vehicleType != null) {
+ serviceIntent.putExtra(TransportConstants.VEHICLE_INFO_EXTRA, vehicleType.getStore());
+ }
+
try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
context.startService(serviceIntent);
@@ -254,7 +279,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
}
}
- private boolean wakeUpRouterService(final Context context, final boolean ping, final boolean altTransportWake, final BluetoothDevice device) {
+ private boolean wakeUpRouterService(final Context context, final boolean ping, final boolean altTransportWake, final BluetoothDevice device, final VehicleType vehicleType) {
new ServiceFinder(context, context.getPackageName(), new ServiceFinder.ServiceFinderCallback() {
@Override
public void onComplete(Vector<ComponentName> routerServices) {
@@ -263,7 +288,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
if (runningBluetoothServicePackage.isEmpty()) {
//If there isn't a service running we should try to start one
//We will try to sort the SDL enabled apps and find the one that's been installed the longest
- final List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator());
+ final List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator(), vehicleType);
synchronized (DEVICE_LISTENER_LOCK) {
final boolean sdlDeviceListenerEnabled = SdlDeviceListener.isFeatureSupported(sdlAppInfoList);
if (sdlDeviceListenerEnabled) {
@@ -294,7 +319,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
}
if (sdlAppInfoList != null && !sdlAppInfoList.isEmpty()) {
- startRouterService(context, sdlAppInfoList.get(0).getRouterServiceComponentName(), altTransportWake, device, false);
+ startRouterService(context, sdlAppInfoList.get(0).getRouterServiceComponentName(), altTransportWake, device, false, vehicleType);
} else {
DebugTool.logInfo(TAG, "No SDL Router Services found");
DebugTool.logInfo(TAG, "WARNING: This application has not specified its SdlRouterService correctly in the manifest. THIS WILL THROW AN EXCEPTION IN FUTURE RELEASES!!");
@@ -564,10 +589,16 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
synchronized (DEVICE_LISTENER_LOCK) {
sdlDeviceListener = null;
if (context != null) {
- final List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator());
+ VehicleType vehicleType = null;
+ final String address = bluetoothDevice != null ? bluetoothDevice.getAddress() : null;
+ Hashtable<String, Object> store = AndroidTools.getVehicleTypeFromPrefs(context, address);
+ if (store != null) {
+ vehicleType = new VehicleType(store);
+ }
+ final List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator(), vehicleType);
if (sdlAppInfoList != null && !sdlAppInfoList.isEmpty()) {
ComponentName routerService = sdlAppInfoList.get(0).getRouterServiceComponentName();
- startRouterService(context, routerService, false, bluetoothDevice, true);
+ startRouterService(context, routerService, false, bluetoothDevice, true, vehicleType);
}
}
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
index af63c9219..9d24ddfec 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
@@ -89,6 +89,7 @@ import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.protocol.enums.MessageType;
import com.smartdevicelink.protocol.enums.SessionType;
import com.smartdevicelink.proxy.rpc.UnregisterAppInterface;
+import com.smartdevicelink.proxy.rpc.VehicleType;
import com.smartdevicelink.transport.enums.TransportType;
import com.smartdevicelink.transport.utl.ByteAraryMessageAssembler;
import com.smartdevicelink.transport.utl.ByteArrayMessageSpliter;
@@ -141,7 +142,7 @@ public class SdlRouterService extends Service {
/**
* <b> NOTE: DO NOT MODIFY THIS UNLESS YOU KNOW WHAT YOU'RE DOING.</b>
*/
- protected static final int ROUTER_SERVICE_VERSION_NUMBER = 14;
+ protected static final int ROUTER_SERVICE_VERSION_NUMBER = 15;
private static final String ROUTER_SERVICE_PROCESS = "com.smartdevicelink.router";
@@ -201,6 +202,7 @@ public class SdlRouterService extends Service {
private boolean wrongProcess = false;
private boolean initPassed = false;
private boolean hasCalledStartForeground = false;
+ boolean firstStart = true;
public static HashMap<String, RegisteredApp> registeredApps;
private SparseArray<String> bluetoothSessionMap, usbSessionMap, tcpSessionMap;
@@ -212,6 +214,7 @@ public class SdlRouterService extends Service {
private static Messenger altTransportService = null;
private boolean startSequenceComplete = false;
+ private VehicleType receivedVehicleType;
private ExecutorService packetExecutor = null;
ConcurrentHashMap<TransportType, PacketWriteTaskMaster> packetWriteTaskMasterMap = null;
@@ -1096,6 +1099,28 @@ public class SdlRouterService extends Service {
DebugTool.logError(TAG, "Service isn't exported. Shutting down");
return false;
}
+
+ ComponentName name = new ComponentName(this, this.getClass());
+ SdlAppInfo currentAppInfo = null;
+
+ List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(getApplicationContext(), new SdlAppInfo.BestRouterComparator(), null);
+ for (SdlAppInfo appInfo : sdlAppInfoList) {
+ if (appInfo.getRouterServiceComponentName().equals(name)) {
+ currentAppInfo = appInfo;
+ break;
+ }
+ }
+
+ if (currentAppInfo == null) {
+ DebugTool.logError(TAG, "AppInfo for current package is not available. Shutting down");
+ return false;
+ }
+
+ if (!SdlAppInfo.checkIfVehicleSupported(currentAppInfo.getSupportedVehicles(), receivedVehicleType)) {
+ DebugTool.logError(TAG, "Received vehicle data is not supported. Shutting down");
+ return false;
+ }
+
return true;
}
@@ -1118,37 +1143,13 @@ public class SdlRouterService extends Service {
hasCalledStartForeground = true;
resetForegroundTimeOut(FOREGROUND_TIMEOUT / 1000);
}
-
-
- if (!initCheck()) { // Run checks on process and permissions
- deployNextRouterService();
- closeSelf();
- return;
- }
- initPassed = true;
-
-
- synchronized (REGISTERED_APPS_LOCK) {
- registeredApps = new HashMap<String, RegisteredApp>();
- }
- closing = false;
-
- synchronized (SESSION_LOCK) {
- this.bluetoothSessionMap = new SparseArray<String>();
- this.sessionHashIdMap = new SparseIntArray();
- this.cleanedSessionMap = new SparseIntArray();
- }
-
- packetExecutor = Executors.newSingleThreadExecutor();
-
- startUpSequence();
}
/**
* The method will attempt to start up the next router service in line based on the sorting criteria of best router service.
*/
protected void deployNextRouterService() {
- List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(getApplicationContext(), new SdlAppInfo.BestRouterComparator());
+ List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(getApplicationContext(), new SdlAppInfo.BestRouterComparator(), null);
if (sdlAppInfoList != null && !sdlAppInfoList.isEmpty()) {
ComponentName name = new ComponentName(this, this.getClass());
SdlAppInfo info;
@@ -1250,6 +1251,37 @@ public class SdlRouterService extends Service {
@SuppressLint({"NewApi", "MissingPermission"})
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent != null && intent.hasExtra(TransportConstants.VEHICLE_INFO_EXTRA)) {
+ receivedVehicleType = new VehicleType(
+ (HashMap<String, Object>) intent.getSerializableExtra(TransportConstants.VEHICLE_INFO_EXTRA)
+ );
+ }
+ // Only trusting the first intent received to start the RouterService and run initial checks to avoid a case where an app could send incorrect data after the spp connection has started.
+ if (firstStart) {
+ firstStart = false;
+ if (!initCheck()) { // Run checks on process and permissions
+ deployNextRouterService();
+ closeSelf();
+ return START_REDELIVER_INTENT;
+ }
+ initPassed = true;
+
+
+ synchronized (REGISTERED_APPS_LOCK) {
+ registeredApps = new HashMap<String, RegisteredApp>();
+ }
+ closing = false;
+
+ synchronized (SESSION_LOCK) {
+ this.bluetoothSessionMap = new SparseArray<String>();
+ this.sessionHashIdMap = new SparseIntArray();
+ this.cleanedSessionMap = new SparseIntArray();
+ }
+
+ packetExecutor = Executors.newSingleThreadExecutor();
+
+ startUpSequence();
+ }
if (intent != null) {
if (intent.getBooleanExtra(FOREGROUND_EXTRA, false)) {
hasCalledStartForeground = false;
@@ -1410,7 +1442,10 @@ public class SdlRouterService extends Service {
public void resetForegroundTimeOut(long delay) {
synchronized (FOREGROUND_NOTIFICATION_LOCK) {
if (foregroundTimeoutHandler == null) {
- foregroundTimeoutHandler = new Handler();
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ foregroundTimeoutHandler = new Handler(Looper.myLooper());
}
if (foregroundTimeoutRunnable == null) {
foregroundTimeoutRunnable = new Runnable() {
@@ -1756,6 +1791,9 @@ public class SdlRouterService extends Service {
startService.putExtra(TransportConstants.FORCE_TRANSPORT_CONNECTED, true);
startService.putExtra(TransportConstants.START_ROUTER_SERVICE_SDL_ENABLED_APP_PACKAGE, getBaseContext().getPackageName());
startService.putExtra(TransportConstants.START_ROUTER_SERVICE_SDL_ENABLED_CMP_NAME, new ComponentName(this, this.getClass()));
+ if (receivedVehicleType != null) {
+ startService.putExtra(TransportConstants.VEHICLE_INFO_EXTRA, receivedVehicleType.getStore());
+ }
if (record != null && record.getType() != null) {
startService.putExtra(TransportConstants.START_ROUTER_SERVICE_TRANSPORT_CONNECTED, record.getType().toString());
@@ -2416,7 +2454,7 @@ public class SdlRouterService extends Service {
/**
* Set the connection establishment status of the particular device
*
- * @param address address of the device in quesiton
+ * @param address address of the device in question
* @param hasSDLConnected true if a connection has been established, false if not
*/
protected void setSDLConnectedStatus(String address, boolean hasSDLConnected) {
@@ -2501,7 +2539,10 @@ public class SdlRouterService extends Service {
* This method is used to check for the newest version of this class to make sure the latest and greatest is up and running.
*/
private void startAltTransportTimer() {
- altTransportTimerHandler = new Handler();
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ altTransportTimerHandler = new Handler(Looper.myLooper());
altTransportTimerRunnable = new Runnable() {
public void run() {
altTransportTimerHandler = null;
@@ -2833,6 +2874,9 @@ public class SdlRouterService extends Service {
pingIntent.putExtra(TransportConstants.START_ROUTER_SERVICE_SDL_ENABLED_APP_PACKAGE, getBaseContext().getPackageName());
pingIntent.putExtra(TransportConstants.START_ROUTER_SERVICE_SDL_ENABLED_CMP_NAME, new ComponentName(SdlRouterService.this, SdlRouterService.this.getClass()));
pingIntent.putExtra(TransportConstants.START_ROUTER_SERVICE_SDL_ENABLED_PING, true);
+ if (receivedVehicleType != null) {
+ pingIntent.putExtra(TransportConstants.VEHICLE_INFO_EXTRA, receivedVehicleType.getStore());
+ }
}
private void startClientPings() {
@@ -3057,7 +3101,10 @@ public class SdlRouterService extends Service {
this.messenger = messenger;
this.sessionIds = new Vector<Long>();
this.queues = new ConcurrentHashMap<>();
- queueWaitHandler = new Handler();
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ queueWaitHandler = new Handler(Looper.myLooper());
registeredTransports = new SparseArray<ArrayList<TransportType>>();
awaitingSession = new Vector<>();
setDeathNote(); //messaging Version
@@ -3272,7 +3319,7 @@ public class SdlRouterService extends Service {
try {
List<TransportType> transportTypes = (List<TransportType>) obj;
if (transportTypes != null) {
- if (transportTypes.get(0) != null) {
+ if (transportTypes.size() > 0 && transportTypes.get(0) != null) {
return transportTypes.get(0);
}
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java
index a1392aace..6c3050301 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java
@@ -402,10 +402,10 @@ public class TransportManager extends TransportManagerBase {
return; //Already in legacy mode
}
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
if (transportListener.onLegacyModeEnabled(info)) {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
legacyBluetoothHandler = new LegacyBluetoothHandler(this);
legacyBluetoothTransport = new MultiplexBluetoothTransport(legacyBluetoothHandler);
if (contextWeakReference.get() != null) {
@@ -415,7 +415,7 @@ public class TransportManager extends TransportManagerBase {
contextWeakReference.get().registerReceiver(legacyDisconnectReceiver, intentFilter);
}
} else {
- new Handler().postDelayed(new Runnable() {
+ new Handler(Looper.myLooper()).postDelayed(new Runnable() {
@Override
public void run() {
transportListener.onError(info + " - Legacy mode unacceptable; shutting down.");
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java
index 604e3b435..8e54de9a1 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java
@@ -143,7 +143,7 @@ public class USBAccessoryAttachmentActivity extends Activity {
//If there isn't a service running we should try to start one
//We will try to sort the SDL enabled apps and find the one that's been installed the longest
Intent serviceIntent;
- List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator());
+ List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator(), null);
if (sdlAppInfoList != null && !sdlAppInfoList.isEmpty()) {
SdlAppInfo optimalRouterService = sdlAppInfoList.get(0);
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/utl/SdlDeviceListener.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/utl/SdlDeviceListener.java
index 23cdd9857..41ada091d 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/utl/SdlDeviceListener.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/utl/SdlDeviceListener.java
@@ -42,13 +42,22 @@ import android.os.Message;
import androidx.annotation.NonNull;
+import com.smartdevicelink.protocol.SdlPacket;
+import com.smartdevicelink.protocol.SdlPacketFactory;
+import com.smartdevicelink.protocol.enums.ControlFrameTags;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.proxy.rpc.VehicleType;
import com.smartdevicelink.transport.MultiplexBaseTransport;
import com.smartdevicelink.transport.MultiplexBluetoothTransport;
import com.smartdevicelink.transport.SdlRouterService;
+import com.smartdevicelink.util.AndroidTools;
+import com.smartdevicelink.util.BitConverter;
import com.smartdevicelink.util.DebugTool;
import com.smartdevicelink.util.SdlAppInfo;
+import com.smartdevicelink.util.Version;
import java.lang.ref.WeakReference;
+import java.util.Hashtable;
import java.util.List;
@@ -59,6 +68,9 @@ public class SdlDeviceListener {
private static final String SDL_DEVICE_STATUS_SHARED_PREFS = "sdl.device.status";
private static final Object LOCK = new Object(), RUNNING_LOCK = new Object();
+ // If increasing MAX PROTOCOL VERSION major version, make sure to alter it in SdlProtocolBase
+ private static final Version MAX_PROTOCOL_VERSION = new Version(5, 4, 0);
+
private final WeakReference<Context> contextWeakReference;
private final Callback callback;
private BluetoothDevice connectedDevice;
@@ -152,16 +164,10 @@ public class SdlDeviceListener {
case SdlRouterService.MESSAGE_STATE_CHANGE:
switch (msg.arg1) {
case MultiplexBaseTransport.STATE_CONNECTED:
- if(sdlListener.connectedDevice == null) {
+ if (sdlListener.connectedDevice == null) {
sdlListener.connectedDevice = sdlListener.bluetoothTransport.getConnectedDevice();
}
- sdlListener.setSDLConnectedStatus(sdlListener.contextWeakReference.get(), sdlListener.connectedDevice.getAddress(), true);
- boolean keepConnectionOpen = sdlListener.callback.onTransportConnected(sdlListener.contextWeakReference.get(), sdlListener.connectedDevice);
- if (!keepConnectionOpen) {
- sdlListener.bluetoothTransport.stop();
- sdlListener.bluetoothTransport = null;
- sdlListener.timeoutHandler.removeCallbacks(sdlListener.timeoutRunner);
- }
+ sendStartService();
break;
case MultiplexBaseTransport.STATE_NONE:
// We've just lost the connection
@@ -174,9 +180,90 @@ public class SdlDeviceListener {
break;
case com.smartdevicelink.transport.SdlRouterService.MESSAGE_READ:
+ onPacketRead((SdlPacket) msg.obj);
break;
}
}
+
+ /**
+ * This method will start the RPC service so that we can retrieve vehicle info
+ */
+ public void sendStartService() {
+ SdlDeviceListener sdlListener = this.provider.get();
+ SdlPacket serviceProbe = SdlPacketFactory.createStartSession(SessionType.RPC, 0x00, (byte)0x01, (byte)0x00, false);
+ serviceProbe.putTag(ControlFrameTags.RPC.StartService.PROTOCOL_VERSION, MAX_PROTOCOL_VERSION.toString());
+ byte[] constructed = serviceProbe.constructPacket();
+ if (sdlListener.bluetoothTransport != null && sdlListener.bluetoothTransport.getState() == MultiplexBluetoothTransport.STATE_CONNECTED) {
+ sdlListener.bluetoothTransport.write(constructed, 0, constructed.length);
+ } else {
+ sdlListener.callback.onTransportError(sdlListener.connectedDevice);
+ }
+ }
+
+ /**
+ * This method will pull vehicle data out of a StartServiceACK and then end the RPC session
+ *
+ * @param packet - info received from connected module
+ */
+ public void onPacketRead(SdlPacket packet) {
+ SdlDeviceListener sdlListener = this.provider.get();
+ VehicleType vehicleType = null;
+ if (packet.getFrameInfo() == SdlPacket.FRAME_INFO_START_SERVICE_ACK) {
+ int hashID;
+ if (packet.getVersion() >= 5) {
+ vehicleType = getVehicleType(packet);
+ hashID = (Integer) packet.getTag(ControlFrameTags.RPC.StartServiceACK.HASH_ID);
+ } else {
+ hashID = BitConverter.intFromByteArray(packet.getPayload(), 0);
+ }
+ byte[] stopService = SdlPacketFactory.createEndSession(SessionType.RPC, (byte)packet.getSessionId(), 0, (byte)packet.getVersion(), hashID).constructPacket();
+ if (sdlListener.bluetoothTransport != null && sdlListener.bluetoothTransport.getState() == MultiplexBluetoothTransport.STATE_CONNECTED) {
+ sdlListener.bluetoothTransport.write(stopService, 0, stopService.length);
+ }
+ notifyConnection(vehicleType);
+ }
+ }
+
+ /**
+ * Retrieves vehicle type from the StartServiceACK
+ *
+ * @param packet - info received from connected module
+ * @return vehicle type of connected module
+ */
+ private VehicleType getVehicleType(SdlPacket packet) {
+ String make = (String) packet.getTag(ControlFrameTags.RPC.StartServiceACK.MAKE);
+ String model = (String) packet.getTag(ControlFrameTags.RPC.StartServiceACK.MODEL);
+ String modelYear = (String) packet.getTag(ControlFrameTags.RPC.StartServiceACK.MODEL_YEAR);
+ String vehicleTrim = (String) packet.getTag(ControlFrameTags.RPC.StartServiceACK.TRIM);
+ if (make != null) {
+ // checking if tags have come from core
+ VehicleType type = new VehicleType();
+ type.setMake(make);
+ type.setModel(model);
+ type.setModelYear(modelYear);
+ type.setTrim(vehicleTrim);
+ return type;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Notify connection about vehicle type.
+ *
+ * @param vehicleType the information about the type of vehicle
+ */
+ public void notifyConnection(VehicleType vehicleType) {
+ SdlDeviceListener sdlListener = this.provider.get();
+ sdlListener.setSDLConnectedStatus(sdlListener.contextWeakReference.get(), sdlListener.connectedDevice.getAddress(), true);
+ AndroidTools.saveVehicleType(sdlListener.contextWeakReference.get(), vehicleType, sdlListener.connectedDevice.getAddress());
+ boolean keepConnectionOpen = sdlListener.callback.onTransportConnected(sdlListener.contextWeakReference.get(), sdlListener.connectedDevice);
+ if (!keepConnectionOpen) {
+ sdlListener.bluetoothTransport.stop();
+ sdlListener.bluetoothTransport = null;
+ sdlListener.timeoutHandler.removeCallbacks(sdlListener.timeoutRunner);
+ }
+ }
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java b/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
index 9109dc3ad..1f4ba2de0 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
@@ -36,18 +36,28 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.BatteryManager;
+import android.os.Bundle;
+import androidx.annotation.Nullable;
+import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.proxy.rpc.VehicleType;
import com.smartdevicelink.transport.TransportConstants;
+import org.json.JSONException;
+import org.json.JSONObject;
+
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.URL;
@@ -56,9 +66,16 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.Hashtable;
import java.util.List;
+
public class AndroidTools {
+
+ private static final String TAG = "AndroidTools";
+ private static final String SDL_DEVICE_VEHICLES_PREFS = "sdl.device.vehicles";
+ private static final Object VEHICLE_PREF_LOCK = new Object();
+
/**
* Check to see if a component is exported
*
@@ -97,7 +114,6 @@ public class AndroidTools {
return sdlMultiList;
}
-
/**
* Finds all SDL apps via their SdlRouterService manifest entry. It will return the metadata associated with that router service.
*
@@ -105,6 +121,7 @@ public class AndroidTools {
* @param comparator the Comparator to sort the resulting list. If null is supplied, they will be returned as they are from the system
* @return the sorted list of SdlAppInfo objects that represent SDL apps
*/
+ @Deprecated
public static List<SdlAppInfo> querySdlAppInfo(Context context, Comparator<SdlAppInfo> comparator) {
List<SdlAppInfo> sdlAppInfoList = new ArrayList<>();
Intent intent = new Intent(TransportConstants.ROUTER_SERVICE_ACTION);
@@ -118,7 +135,7 @@ public class AndroidTools {
PackageInfo packageInfo;
try {
packageInfo = packageManager.getPackageInfo(info.serviceInfo.packageName, 0);
- sdlAppInfoList.add(new SdlAppInfo(info, packageInfo));
+ sdlAppInfoList.add(new SdlAppInfo(info, packageInfo, context));
} catch (NameNotFoundException e) {
//Package was not found, likely a sign the resolve info can't be trusted.
}
@@ -134,6 +151,54 @@ public class AndroidTools {
return sdlAppInfoList;
}
+ /**
+ * Finds all SDL apps via their SdlRouterService manifest entry. It will return the metadata associated with that router service.
+ *
+ * @param context a context instance to obtain the package manager
+ * @param comparator the Comparator to sort the resulting list. If null is supplied, they will be returned as they are from the system
+ * @return the sorted list of SdlAppInfo objects that represent SDL apps
+ */
+ public static List<SdlAppInfo> querySdlAppInfo(Context context, Comparator<SdlAppInfo> comparator, VehicleType type) {
+ List<SdlAppInfo> sdlAppInfoList = new ArrayList<>();
+ Intent intent = new Intent(TransportConstants.ROUTER_SERVICE_ACTION);
+ List<ResolveInfo> resolveInfoList = context.getPackageManager().queryIntentServices(intent, PackageManager.GET_META_DATA);
+
+ if (resolveInfoList != null && resolveInfoList.size() > 0) {
+ PackageManager packageManager = context.getPackageManager();
+ if (packageManager != null) {
+
+ for (ResolveInfo info : resolveInfoList) {
+ PackageInfo packageInfo;
+ try {
+ packageInfo = packageManager.getPackageInfo(info.serviceInfo.packageName, 0);
+ SdlAppInfo appInformation = new SdlAppInfo(info, packageInfo, context);
+ sdlAppInfoList.add(appInformation);
+
+ } catch (NameNotFoundException e) {
+ //Package was not found, likely a sign the resolve info can't be trusted.
+ }
+
+ }
+ }
+
+ List<SdlAppInfo> sdlAppInfoListVehicleType = new ArrayList<>();
+
+ for (SdlAppInfo appInformation : sdlAppInfoList) {
+ if (appInformation.routerServiceVersion < 15) {
+ sdlAppInfoListVehicleType.add(appInformation);
+ } else if (SdlAppInfo.checkIfVehicleSupported(appInformation.supportedVehicles, type)) {
+ sdlAppInfoListVehicleType.add(appInformation);
+ }
+ }
+ sdlAppInfoList = sdlAppInfoListVehicleType;
+
+ if (comparator != null) {
+ Collections.sort(sdlAppInfoList, comparator);
+ }
+ }
+ return sdlAppInfoList;
+ }
+
/**
* Sends the provided intent to the specified destinations making it an explicit intent, rather
@@ -204,4 +269,104 @@ public class AndroidTools {
}
return false;
}
+
+ /**
+ * Saves the mac address along with vehicle details into user's shared prefs.
+ *
+ * @param context a context instance to obtain the shared preferences.
+ * @param vehicleType a RPCStruct that describes the type of vehicle the mobile phone is connected with.
+ * @param address a string containing the Bluetooth Mac address of the connected vehicle.
+ */
+ public static void saveVehicleType(Context context, VehicleType vehicleType, String address) {
+ synchronized (VEHICLE_PREF_LOCK) {
+ if (vehicleType == null || address == null || context == null) {
+ DebugTool.logWarning(TAG, String.format("Unable to save vehicle type. Context is %1$s, Address is %2$s and VehicleType is %3$s", context, address, vehicleType));
+ return;
+ }
+ try {
+ SharedPreferences preferences = context.getSharedPreferences(SDL_DEVICE_VEHICLES_PREFS, Context.MODE_PRIVATE);
+
+ String jsonString = vehicleType.serializeJSON().toString();
+ SharedPreferences.Editor editor = preferences.edit();
+ editor.putString(address, jsonString);
+ editor.commit();
+ } catch (JSONException e) {
+ DebugTool.logError(TAG, "Unable to serialize vehicle type to JSON.", e);
+ }
+ }
+ }
+
+ /**
+ * Retrieves the vehicle details by the mac address of the connected vehicle.
+ *
+ * @param context a context instance to obtain the shared preferences.
+ * @param address a string containing the Bluetooth Mac address of the connected vehicle.
+ * @return The Hashtable to be used to construct VehicleTyp
+ */
+ public static @Nullable Hashtable<String, Object> getVehicleTypeFromPrefs(Context context, String address) {
+ synchronized (VEHICLE_PREF_LOCK) {
+ if (context == null || address == null) {
+ DebugTool.logWarning(TAG, String.format("Unable to get vehicle type from prefs. Context is %1$s and Address is %2$s", context, address));
+ return null;
+ }
+ try {
+ SharedPreferences preferences = context.getSharedPreferences(SDL_DEVICE_VEHICLES_PREFS, Context.MODE_PRIVATE);
+ String storedVehicleTypeSerialized = preferences.getString(address, null);
+
+ if (storedVehicleTypeSerialized == null) {
+ return null;
+ } else {
+ JSONObject object = new JSONObject(storedVehicleTypeSerialized);
+ return JsonRPCMarshaller.deserializeJSONObject(object);
+ }
+ } catch (JSONException e) {
+ DebugTool.logError(TAG, "Unable to deserialize stored vehicle type.", e);
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Retrieves the list of vehicle types that are set in the manifest.
+ *
+ * @param context a context to access Android system services through.
+ * @param component a component name of a LocalRouterService.
+ * @param manifestFieldId a string resources id that indicates an unique name for the vehicle data in the manifest.
+ * @return The list of vehicle types, or null if an error occurred or field was not found.
+ */
+ public static @Nullable List<VehicleType> getVehicleTypesFromManifest(Context context, ComponentName component, int manifestFieldId) {
+ if (context == null || component == null) {
+ DebugTool.logWarning(TAG, String.format("Unable to get vehicle type from manifest. Context is %1$s and Component is %2$s", context, component));
+ return null;
+ }
+ try {
+ PackageManager pm = context.getPackageManager();
+ Resources resources = context.getResources();
+ if (pm == null || resources == null) {
+ DebugTool.logWarning(TAG, String.format("Unable to get vehicle type from manifest. PackageManager is %1$s and Resources is %2$s", pm, resources));
+ return null;
+ }
+
+ Bundle metaData = pm.getServiceInfo(component, PackageManager.GET_META_DATA).metaData;
+ if (metaData == null) {
+ DebugTool.logError(TAG, "metaData isn't available.");
+ return null;
+ }
+
+ int xmlFieldId = metaData.getInt(resources.getString(manifestFieldId));
+ if (xmlFieldId == 0) {
+ DebugTool.logError(TAG, "Field with id " + manifestFieldId + " was not found in manifest");
+ return null;
+ }
+
+ XmlResourceParser parser = resources.getXml(xmlFieldId);
+ return SdlAppInfo.deserializeSupportedVehicles(parser);
+ } catch (PackageManager.NameNotFoundException e) {
+ DebugTool.logError(TAG, "Failed to get OEM vehicle data filter: " + e.getMessage()+ " - assume vehicle data is supported");
+ return null;
+ } catch (Resources.NotFoundException ex) {
+ DebugTool.logError(TAG, "Failed to find resource: " + ex.getMessage()+ " - assume vehicle data is supported");
+ return null;
+ }
+ }
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java b/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java
index ba15ff4aa..8e904a45f 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java
@@ -198,7 +198,7 @@ public class IntegrationValidator {
boolean serviceFilterHasAction = false;
String className = localRouterClass.getName();
- List<SdlAppInfo> services = AndroidTools.querySdlAppInfo(context, null);
+ List<SdlAppInfo> services = AndroidTools.querySdlAppInfo(context, null, null);
for (SdlAppInfo sdlAppInfo : services) {
if (sdlAppInfo != null && sdlAppInfo.getRouterServiceComponentName() != null
&& className.equals((sdlAppInfo.getRouterServiceComponentName().getClassName()))) {
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java b/android/sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java
index d49e63575..7d5ade055 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java
@@ -33,11 +33,23 @@
package com.smartdevicelink.util;
import android.content.ComponentName;
+import android.content.Context;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
import android.os.Bundle;
+import com.smartdevicelink.proxy.rpc.VehicleType;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
import java.util.Comparator;
+import java.util.List;
/**
* Created by Joey Grover on 2/2/18.
@@ -49,15 +61,17 @@ public class SdlAppInfo {
//FIXME we shouldn't be duplicating constants, but this currently keeps us from needing a context instance.
private static final String SDL_ROUTER_VERSION_METADATA = "sdl_router_version";
private static final String SDL_CUSTOM_ROUTER_METADATA = "sdl_custom_router";
+ private static final String SDL_OEM_VEHICLE_TYPE_METADATA = "sdl_oem_vehicle_type";
String packageName;
ComponentName routerServiceComponentName;
int routerServiceVersion = 4; //We use this as a default and assume if the number doesn't exist in meta data it is because the app hasn't updated.
boolean isCustomRouterService = false;
+ List<VehicleType> supportedVehicles = new ArrayList<>();
long lastUpdateTime;
-
+ @Deprecated
public SdlAppInfo(ResolveInfo resolveInfo, PackageInfo packageInfo) {
if (resolveInfo.serviceInfo != null) {
@@ -89,6 +103,75 @@ public class SdlAppInfo {
}
}
+ public SdlAppInfo(ResolveInfo resolveInfo, PackageInfo packageInfo, Context context) {
+ if (resolveInfo.serviceInfo != null) {
+
+ this.packageName = resolveInfo.serviceInfo.packageName;
+ this.routerServiceComponentName = new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
+
+ Bundle metadata = resolveInfo.serviceInfo.metaData;
+ if (metadata != null) {
+
+ if (metadata.containsKey(SDL_ROUTER_VERSION_METADATA)) {
+ this.routerServiceVersion = metadata.getInt(SDL_ROUTER_VERSION_METADATA);
+ }
+
+ if (metadata.containsKey(SDL_CUSTOM_ROUTER_METADATA)) {
+ this.isCustomRouterService = metadata.getBoolean(SDL_CUSTOM_ROUTER_METADATA);
+ }
+
+ if (metadata.containsKey(SDL_OEM_VEHICLE_TYPE_METADATA)) {
+ if (context == null) {
+ DebugTool.logWarning(TAG, "Unable to deserialize supported vehicles: supplied Context is null");
+ return;
+ }
+
+ String contextPackageName = context.getPackageName();
+ if (contextPackageName == null || packageName == null) {
+ DebugTool.logWarning(TAG, String.format("Unable to deserialize supported vehicles. ContextPackageName: %1$s and PackageName: %2$s", contextPackageName, packageName));
+ return;
+ }
+
+ Resources resources = null;
+ if (!contextPackageName.equals(packageName)) {
+ try {
+ Context appContext = context.createPackageContext(packageName, 0);
+ if (appContext == null){
+ DebugTool.logError(TAG, "Failed to create context with the given package name");
+ return;
+ }
+ resources = appContext.getResources();
+ } catch (PackageManager.NameNotFoundException e) {
+ DebugTool.logError(TAG, "Failed to create context with the given package name: " + e.getMessage());
+ }
+ } else {
+ resources = context.getResources();
+ }
+
+ if (resources != null) {
+ try {
+ XmlResourceParser parser = resources.getXml(metadata.getInt(SDL_OEM_VEHICLE_TYPE_METADATA));
+ this.supportedVehicles = deserializeSupportedVehicles(parser);
+ } catch (Resources.NotFoundException ex) {
+ DebugTool.logError(TAG, "Failed to find resource: " + ex.getMessage());
+ }
+ }
+ }
+ } else {
+ DebugTool.logWarning(TAG, packageName + " has not supplied metadata with their router service!");
+ }
+ }
+
+ if (packageInfo != null) {
+ this.lastUpdateTime = packageInfo.lastUpdateTime;
+ if (this.lastUpdateTime <= 0) {
+ this.lastUpdateTime = packageInfo.firstInstallTime;
+ }
+ } else {
+ this.lastUpdateTime = 0;
+ }
+ }
+
public int getRouterServiceVersion() {
return routerServiceVersion;
}
@@ -122,12 +205,120 @@ public class SdlAppInfo {
builder.append("\nLast updated: ");
builder.append(this.lastUpdateTime);
+ builder.append("\nVehicle make list: ");
+ builder.append(this.supportedVehicles);
+
builder.append("\n-------- Sdl App Info End------");
return builder.toString();
}
/**
+ * Retrieves the list of vehicle types that are set in the xml file.
+ *
+ * @param parser The xml parsing interface for the vehicle types xml file.
+ * @return The list of vehicle types.
+ */
+ public static List<VehicleType> deserializeSupportedVehicles(XmlResourceParser parser) {
+ List<VehicleType> vehicleMakesList = new ArrayList<>();
+ if (parser == null) {
+ return vehicleMakesList;
+ }
+ try {
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG) {
+ String tagName = parser.getName();
+ if (tagName != null && tagName.equalsIgnoreCase("vehicle-type")) {
+ VehicleType vehicleMake = new VehicleType();
+ String make = parser.getAttributeValue(null, "make");
+ if (make != null) {
+ vehicleMake.setMake(make);
+ String model = parser.getAttributeValue(null, "model");
+ String modelYear = parser.getAttributeValue(null, "modelYear");
+ String trim = parser.getAttributeValue(null, "trim");
+
+ if (model == null && modelYear == null && trim == null) {
+ vehicleMakesList.add(vehicleMake);
+ } else if (model != null){
+ vehicleMake.setModel(model);
+ if (modelYear != null) {
+ vehicleMake.setModelYear(modelYear);
+ }
+ if (trim != null) {
+ vehicleMake.setTrim(trim);
+ }
+ vehicleMakesList.add(vehicleMake);
+ }
+ }
+ }
+ }
+ eventType = parser.next();
+ }
+ } catch (XmlPullParserException e) {
+ DebugTool.logError(TAG, "Failed to parse xml file", e);
+ } catch (IOException e) {
+ DebugTool.logError(TAG, "Failed to find next element in the xml file", e);
+ }
+ return vehicleMakesList;
+ }
+
+ /**
+ * Check to see if a vehicle type is supported.
+ *
+ * @param supportedVehicleList the list of supported vehicle types.
+ * @param connectedVehicle the vehicle type to check.
+ * @return true if vehicle type is supported.
+ */
+ public static boolean checkIfVehicleSupported(List<VehicleType> supportedVehicleList, VehicleType connectedVehicle) {
+ if (supportedVehicleList == null || supportedVehicleList.isEmpty() || connectedVehicle == null || connectedVehicle.getStore() == null|| connectedVehicle.getStore().isEmpty()) {
+ return true;
+ }
+ if (supportedVehicleList.contains(connectedVehicle)) {
+ return true;
+ }
+ for (VehicleType supportedVehicle: supportedVehicleList) {
+ boolean areVehicleMakesEqual = CompareUtils.areStringsEqual(supportedVehicle.getMake(), connectedVehicle.getMake(), true, false);
+ if (areVehicleMakesEqual) {
+ String supportedVehicleModel = supportedVehicle.getModel();
+ String connectedVehicleModel = connectedVehicle.getModel();
+ if (supportedVehicleModel != null && connectedVehicleModel != null) {
+ if (connectedVehicleModel.equalsIgnoreCase(supportedVehicleModel)) {
+ boolean ret = true;
+ String supportedVehicleModelYear = supportedVehicle.getModelYear();
+ String connectedVehicleModelYear = connectedVehicle.getModelYear();
+ if (supportedVehicleModelYear != null && connectedVehicleModelYear != null) {
+ ret = connectedVehicleModelYear.equalsIgnoreCase(supportedVehicleModelYear);
+ }
+ String supportedVehicleTrim = supportedVehicle.getTrim();
+ String connectedVehicleTrim = connectedVehicle.getTrim();
+ if (supportedVehicleTrim != null && connectedVehicleTrim != null) {
+ ret &= connectedVehicleTrim.equalsIgnoreCase(supportedVehicleTrim);
+ }
+ if (ret) {
+ // We found matches and return or continue iteration otherwise
+ return true;
+ }
+ }
+ } else {
+ // Return true if only make is defined and it matches
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Gets app's supported vehicle types.
+ *
+ * @return List<VehicleType> a list of supported vehicle types.
+ */
+ public List<VehicleType> getSupportedVehicles() {
+ return supportedVehicles;
+ }
+
+ /**
* This comparator will sort a list to find the best router service to start out of the known SDL enabled apps
*/
public static class BestRouterComparator implements Comparator<SdlAppInfo> {
diff --git a/android/sdl_android/src/main/res/values/sdl.xml b/android/sdl_android/src/main/res/values/sdl.xml
index 1d5f0897a..7bb919f0b 100644
--- a/android/sdl_android/src/main/res/values/sdl.xml
+++ b/android/sdl_android/src/main/res/values/sdl.xml
@@ -2,7 +2,8 @@
<resources>
<string name="sdl_router_service_version_name" translatable="false">sdl_router_version</string>
- <integer name="sdl_router_service_version_value">14</integer>
+ <integer name="sdl_router_service_version_value">15</integer>
<string name="sdl_router_service_is_custom_name" translatable="false">sdl_custom_router</string>
+ <string name="sdl_oem_vehicle_type_filter_name" translatable="false">sdl_oem_vehicle_type</string>
</resources>