summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBilal Alsharifi <599206+bilal-alsharifi@users.noreply.github.com>2019-09-12 10:59:26 -0400
committerGitHub <noreply@github.com>2019-09-12 10:59:26 -0400
commit982720336d06d1daf1a97c6cfd32af5627ffd99c (patch)
tree8f69960646780153f04fad2fba0ba01245cb4221
parent8150ae84e32784476094750f17b398b638c67d03 (diff)
parent70f343d0f237b2e4bb2164d1bc9d2171b2e45790 (diff)
downloadsdl_android-982720336d06d1daf1a97c6cfd32af5627ffd99c.tar.gz
Merge pull request #1156 from smartdevicelink/feature/cancel_interaction_RPC
Implement SDL-0184 CancelInteraction RPC
-rw-r--r--android/sdl_android/src/androidTest/assets/json/Alert.json1
-rw-r--r--android/sdl_android/src/androidTest/assets/json/CancelInteraction.json14
-rw-r--r--android/sdl_android/src/androidTest/assets/json/PerformInteraction.json1
-rw-r--r--android/sdl_android/src/androidTest/assets/json/ScrollableMessage.json1
-rw-r--r--android/sdl_android/src/androidTest/assets/json/Slider.json3
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetManagerTests.java62
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetTests.java16
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PresentChoiceSetOperationTests.java226
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PresentKeyboardOperationTests.java223
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/AlertTests.java6
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/CancelInteractionTests.java135
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/PerformInteractionTests.java10
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/ScrollableMessageTests.java12
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SliderTests.java12
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/CancelInteractionResponseTests.java108
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/ProxyBridge.java6
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java16
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/screen/BaseScreenManager.java14
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/screen/choiceset/AsynchronousOperation.java122
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/screen/choiceset/BaseChoiceSetManager.java116
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/screen/choiceset/CheckChoiceVROptionalOperation.java13
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSet.java11
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetCanceledListener.java42
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/screen/choiceset/DeleteChoicesOperation.java9
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PreloadChoicesOperation.java9
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PresentChoiceSetOperation.java102
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PresentKeyboardOperation.java94
-rw-r--r--base/src/main/java/com/smartdevicelink/protocol/enums/FunctionID.java1
-rw-r--r--base/src/main/java/com/smartdevicelink/proxy/interfaces/IProxyListenerBase.java9
-rw-r--r--base/src/main/java/com/smartdevicelink/proxy/rpc/Alert.java86
-rw-r--r--base/src/main/java/com/smartdevicelink/proxy/rpc/CancelInteraction.java126
-rw-r--r--base/src/main/java/com/smartdevicelink/proxy/rpc/CancelInteractionResponse.java73
-rw-r--r--base/src/main/java/com/smartdevicelink/proxy/rpc/PerformInteraction.java132
-rw-r--r--base/src/main/java/com/smartdevicelink/proxy/rpc/ScrollableMessage.java95
-rw-r--r--base/src/main/java/com/smartdevicelink/proxy/rpc/Slider.java99
35 files changed, 1781 insertions, 224 deletions
diff --git a/android/sdl_android/src/androidTest/assets/json/Alert.json b/android/sdl_android/src/androidTest/assets/json/Alert.json
index 7e8397a62..75ff2ca50 100644
--- a/android/sdl_android/src/androidTest/assets/json/Alert.json
+++ b/android/sdl_android/src/androidTest/assets/json/Alert.json
@@ -9,6 +9,7 @@
"alertText2":"Line 2",
"alertText3":"Line 3",
"progressIndicator":true,
+ "cancelID":45,
"alertIcon":{
"value":"alertIconImage1.png",
"imageType":"DYNAMIC"
diff --git a/android/sdl_android/src/androidTest/assets/json/CancelInteraction.json b/android/sdl_android/src/androidTest/assets/json/CancelInteraction.json
new file mode 100644
index 000000000..dc420ad8f
--- /dev/null
+++ b/android/sdl_android/src/androidTest/assets/json/CancelInteraction.json
@@ -0,0 +1,14 @@
+{
+ "request":{
+ "name":"CancelInteraction",
+ "correlationID":554,
+ "parameters":{
+ "cancelID":6052,
+ "functionID":12
+ }
+ },
+ "response":{
+ "name":"CancelInteractionResponse",
+ "correlationID":554
+ }
+} \ No newline at end of file
diff --git a/android/sdl_android/src/androidTest/assets/json/PerformInteraction.json b/android/sdl_android/src/androidTest/assets/json/PerformInteraction.json
index b8965ee61..583a72b1c 100644
--- a/android/sdl_android/src/androidTest/assets/json/PerformInteraction.json
+++ b/android/sdl_android/src/androidTest/assets/json/PerformInteraction.json
@@ -43,6 +43,7 @@
}
],
"timeout":0,
+ "cancelID":45,
"vrHelp":[
{
"position":7,
diff --git a/android/sdl_android/src/androidTest/assets/json/ScrollableMessage.json b/android/sdl_android/src/androidTest/assets/json/ScrollableMessage.json
index f86dc188c..3b14d1a43 100644
--- a/android/sdl_android/src/androidTest/assets/json/ScrollableMessage.json
+++ b/android/sdl_android/src/androidTest/assets/json/ScrollableMessage.json
@@ -5,6 +5,7 @@
"parameters":{
"scrollableMessageBody":"Sample body text",
"timeout":1000,
+ "cancelID":45,
"softButtons":[
{
"isHighlighted":true,
diff --git a/android/sdl_android/src/androidTest/assets/json/Slider.json b/android/sdl_android/src/androidTest/assets/json/Slider.json
index 38f033df4..5b69f4728 100644
--- a/android/sdl_android/src/androidTest/assets/json/Slider.json
+++ b/android/sdl_android/src/androidTest/assets/json/Slider.json
@@ -12,7 +12,8 @@
"Header Line 4"
],
"position":11,
- "timeout":30000
+ "timeout":30000,
+ "cancelID":45
}
},
"response":{
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 e52f7b273..b8af1a68c 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
@@ -52,8 +52,14 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
public class ChoiceSetManagerTests extends AndroidTestCase2 {
@@ -98,7 +104,7 @@ public class ChoiceSetManagerTests extends AndroidTestCase2 {
assertEquals(csm.nextChoiceId, 1);
assertTrue(csm.executor.isShutdown());
- assertTrue(csm.isVROptional);
+ assertFalse(csm.isVROptional);
assertEquals(csm.getState(), BaseSubManager.SHUTDOWN);
@@ -232,7 +238,61 @@ public class ChoiceSetManagerTests extends AndroidTestCase2 {
for (ChoiceCell cell : returnedChoices){
assertEquals(cell.getText(), "test2");
}
+ }
+
+ public void testPresentingKeyboardShouldReturnCancelIDIfKeyboardCanBeSent() {
+ ISdl internalInterface = mock(ISdl.class);
+ FileManager fileManager = mock(FileManager.class);
+
+ ChoiceSetManager newCSM = new ChoiceSetManager(internalInterface, fileManager);
+ ChoiceSetManager partialMockCSM = spy(newCSM);
+ when(partialMockCSM.getState()).thenReturn(BaseSubManager.READY);
+ Integer cancelId = partialMockCSM.presentKeyboard("initial text", mock(KeyboardProperties.class), mock(KeyboardListener.class));
+ assertNotNull(cancelId);
}
+ public void testPresentingKeyboardShouldNotReturnCancelIDIfKeyboardCannotBeSent() {
+ ISdl internalInterface = mock(ISdl.class);
+ FileManager fileManager = mock(FileManager.class);
+
+ ChoiceSetManager newCSM = new ChoiceSetManager(internalInterface, fileManager);
+ ChoiceSetManager partialMockCSM = spy(newCSM);
+ when(partialMockCSM.getState()).thenReturn(BaseSubManager.ERROR);
+
+ Integer cancelId = partialMockCSM.presentKeyboard("initial text", mock(KeyboardProperties.class), mock(KeyboardListener.class));
+ assertNull(cancelId);
+ }
+
+ public void testDismissingExecutingKeyboard(){
+ Integer testCancelID = 42;
+ PresentKeyboardOperation testKeyboardOp = mock(PresentKeyboardOperation.class);
+ doReturn(testCancelID).when(testKeyboardOp).getCancelID();
+ csm.currentlyPresentedKeyboardOperation = testKeyboardOp;
+ csm.dismissKeyboard(testCancelID);
+ verify(testKeyboardOp, times(1)).dismissKeyboard();
+ }
+
+ public void testDismissingQueuedKeyboard(){
+ Integer testCancelID = 42;
+
+ // Currently executing operation
+ PresentKeyboardOperation testKeyboardOp = mock(PresentKeyboardOperation.class);
+ doReturn(true).when(testKeyboardOp).isExecuting();
+ doReturn(96).when(testKeyboardOp).getCancelID();
+ csm.currentlyPresentedKeyboardOperation = testKeyboardOp;
+
+ // Queued operations
+ PresentKeyboardOperation testKeyboardOp2 = mock(PresentKeyboardOperation.class);
+ doReturn(true).when(testKeyboardOp2).isExecuting();
+ doReturn(testCancelID).when(testKeyboardOp2).getCancelID();
+ LinkedBlockingQueue<Runnable> testOperationQueue = new LinkedBlockingQueue<>();
+ testOperationQueue.add(testKeyboardOp2);
+ csm.operationQueue = testOperationQueue;
+
+ // Queued operation should be canceled
+ csm.dismissKeyboard(testCancelID);
+ verify(testKeyboardOp, times(0)).dismissKeyboard();
+ verify(testKeyboardOp2, times(1)).dismissKeyboard();
+ }
}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetTests.java
index 3d7a30a79..900336594 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetTests.java
@@ -46,6 +46,7 @@ public class ChoiceSetTests extends AndroidTestCase2 {
private ChoiceSetLayout layout;
private List<ChoiceCell> choices;
private Integer defaultTimeout;
+ private Boolean canceledHandlerCalled;
@Override
public void setUp() throws Exception{
@@ -55,6 +56,7 @@ public class ChoiceSetTests extends AndroidTestCase2 {
layout = ChoiceSetLayout.CHOICE_SET_LAYOUT_LIST;
defaultTimeout = 10;
choices = Arrays.asList(new ChoiceCell(Test.GENERAL_STRING), new ChoiceCell(Test.GENERAL_STRING));
+ canceledHandlerCalled = false;
}
@Override
@@ -98,4 +100,18 @@ public class ChoiceSetTests extends AndroidTestCase2 {
assertEquals(choiceSet2.getChoices(), choices);
assertEquals(choiceSet2.getChoiceSetSelectionListener(), listener);
}
+
+ public void testCancelingChoiceSet() {
+ ChoiceSet choiceSet = new ChoiceSet(Test.GENERAL_STRING, choices, listener);
+
+ choiceSet.canceledListener = new ChoiceSetCanceledListener() {
+ @Override
+ public void onChoiceSetCanceled() {
+ canceledHandlerCalled = true;
+ }
+ };
+
+ choiceSet.cancel();
+ assertTrue(canceledHandlerCalled);
+ }
}
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
index ea5204eae..d8cf5be9d 100644
--- 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
@@ -36,34 +36,60 @@
package com.smartdevicelink.managers.screen.choiceset;
import com.smartdevicelink.AndroidTestCase2;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCResponse;
import com.smartdevicelink.proxy.interfaces.ISdl;
+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.Test;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import java.util.Collections;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+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;
public class PresentChoiceSetOperationTests extends AndroidTestCase2 {
private PresentChoiceSetOperation presentChoiceSetOperation;
+ private ChoiceSet choiceSet;
+ private ISdl internalInterface;
+ private KeyboardListener keyboardListener;
+ private ChoiceSetSelectionListener choiceSetSelectionListener;
+
+ private ExecutorService executor;
@Override
public void setUp() throws Exception{
super.setUp();
- ISdl internalInterface = mock(ISdl.class);
- KeyboardListener keyboardListener = mock(KeyboardListener.class);
- ChoiceSetSelectionListener choiceSetSelectionListener = mock(ChoiceSetSelectionListener.class);
+ internalInterface = mock(ISdl.class);
+
+ keyboardListener = mock(KeyboardListener.class);
+ choiceSetSelectionListener = mock(ChoiceSetSelectionListener.class);
+
ChoiceCell cell1 = new ChoiceCell("Cell1");
cell1.setChoiceId(0);
- ChoiceSet choiceSet = new ChoiceSet("Test", Collections.singletonList(cell1), choiceSetSelectionListener);
- presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, getKeyBoardProperties(), keyboardListener, choiceSetSelectionListener);
+ choiceSet = new ChoiceSet("Test", Collections.singletonList(cell1), choiceSetSelectionListener);
+
+ executor = Executors.newCachedThreadPool();
}
@Override
@@ -71,35 +97,209 @@ public class PresentChoiceSetOperationTests extends AndroidTestCase2 {
super.tearDown();
}
- public void testGetLayoutMode(){
+ private KeyboardProperties getKeyBoardProperties(){
+ KeyboardProperties properties = new KeyboardProperties();
+ properties.setLanguage(Language.EN_US);
+ properties.setKeyboardLayout(KeyboardLayout.QWERTZ);
+ properties.setKeypressMode(KeypressMode.RESEND_CURRENT_ENTRY);
+ return properties;
+ }
+
+ 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, Test.GENERAL_INTEGER);
+
assertEquals(presentChoiceSetOperation.getLayoutMode(), LayoutMode.LIST_WITH_SEARCH);
presentChoiceSetOperation.keyboardListener = null;
assertEquals(presentChoiceSetOperation.getLayoutMode(), LayoutMode.LIST_ONLY);
}
public void testGetPerformInteraction(){
+ presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, getKeyBoardProperties(), keyboardListener, choiceSetSelectionListener, Test.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(), Test.GENERAL_INTEGER);
assertEquals(presentChoiceSetOperation.getLayoutMode(), LayoutMode.LIST_WITH_SEARCH);
}
public void testSetSelectedCellWithId(){
+ presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, getKeyBoardProperties(), keyboardListener, choiceSetSelectionListener, Test.GENERAL_INTEGER);
+
assertNull(presentChoiceSetOperation.selectedCellRow);
presentChoiceSetOperation.setSelectedCellWithId(0);
assertEquals(presentChoiceSetOperation.selectedCellRow, Integer.valueOf(0));
}
- private KeyboardProperties getKeyBoardProperties(){
- KeyboardProperties properties = new KeyboardProperties();
- properties.setLanguage(Language.EN_US);
- properties.setKeyboardLayout(KeyboardLayout.QWERTZ);
- properties.setKeypressMode(KeypressMode.RESEND_CURRENT_ENTRY);
- return properties;
+ public void testCancelingChoiceSetSuccessfullyIfThreadIsRunning(){
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
+ presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, null, null, choiceSetSelectionListener, Test.GENERAL_INTEGER);
+ executor.execute(presentChoiceSetOperation);
+
+ try {
+ executor.awaitTermination(1, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {}
+
+ assertTrue(presentChoiceSetOperation.isExecuting());
+ assertFalse(presentChoiceSetOperation.isFinished());
+ assertFalse(presentChoiceSetOperation.isCancelled());
+
+ 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(), Test.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));
+
+ assertTrue(presentChoiceSetOperation.isExecuting());
+ assertFalse(presentChoiceSetOperation.isFinished());
+ assertFalse(presentChoiceSetOperation.isCancelled());
}
-}
+ public void testCancelingChoiceSetUnsuccessfullyIfThreadIsRunning(){
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
+ presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, null, null, choiceSetSelectionListener, Test.GENERAL_INTEGER);
+ executor.execute(presentChoiceSetOperation);
+ try {
+ executor.awaitTermination(1, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {}
+
+ assertTrue(presentChoiceSetOperation.isExecuting());
+ assertFalse(presentChoiceSetOperation.isFinished());
+ assertFalse(presentChoiceSetOperation.isCancelled());
+
+ 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(), Test.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));
+
+ assertTrue(presentChoiceSetOperation.isExecuting());
+ assertFalse(presentChoiceSetOperation.isFinished());
+ assertFalse(presentChoiceSetOperation.isCancelled());
+ }
+
+ public void testCancelingChoiceSetIfThreadHasFinished(){
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
+ presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, null, null, choiceSetSelectionListener, Test.GENERAL_INTEGER);
+ presentChoiceSetOperation.finishOperation();
+
+ assertFalse(presentChoiceSetOperation.isExecuting());
+ assertTrue(presentChoiceSetOperation.isFinished());
+ assertFalse(presentChoiceSetOperation.isCancelled());
+
+ choiceSet.cancel();
+ verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
+
+ assertFalse(presentChoiceSetOperation.isExecuting());
+ assertTrue(presentChoiceSetOperation.isFinished());
+ assertFalse(presentChoiceSetOperation.isCancelled());
+ }
+
+ public void testCancelingChoiceSetIfThreadHasNotYetRun(){
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
+ presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, null, null, choiceSetSelectionListener, Test.GENERAL_INTEGER);
+
+ assertFalse(presentChoiceSetOperation.isExecuting());
+ assertFalse(presentChoiceSetOperation.isFinished());
+ assertFalse(presentChoiceSetOperation.isCancelled());
+
+ choiceSet.cancel();
+
+ // Once the operation has started
+ executor.execute(presentChoiceSetOperation);
+ try {
+ executor.awaitTermination(1, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {}
+
+ assertFalse(presentChoiceSetOperation.isExecuting());
+ assertTrue(presentChoiceSetOperation.isFinished());
+ assertFalse(presentChoiceSetOperation.isCancelled());
+
+ // 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));
+ }
+
+ 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, Test.GENERAL_INTEGER);
+ executor.execute(presentChoiceSetOperation);
+ try {
+ executor.awaitTermination(1, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {}
+
+ assertTrue(presentChoiceSetOperation.isExecuting());
+ assertFalse(presentChoiceSetOperation.isFinished());
+ assertFalse(presentChoiceSetOperation.isCancelled());
+
+ choiceSet.cancel();
+
+ verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
+ verify(internalInterface, times(1)).sendRPC(any(PerformInteraction.class));
+ }
+
+ 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, Test.GENERAL_INTEGER);
+
+ assertFalse(presentChoiceSetOperation.isExecuting());
+ assertFalse(presentChoiceSetOperation.isFinished());
+ assertFalse(presentChoiceSetOperation.isCancelled());
+
+ choiceSet.cancel();
+
+ verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
+
+ // Once the operation has started
+ executor.execute(presentChoiceSetOperation);
+ try {
+ executor.awaitTermination(1, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {}
+
+ assertFalse(presentChoiceSetOperation.isExecuting());
+ assertTrue(presentChoiceSetOperation.isFinished());
+ assertFalse(presentChoiceSetOperation.isCancelled());
+
+ // 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/choiceset/PresentKeyboardOperationTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PresentKeyboardOperationTests.java
index ccf498293..486a1c361 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PresentKeyboardOperationTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/PresentKeyboardOperationTests.java
@@ -36,27 +36,66 @@
package com.smartdevicelink.managers.screen.choiceset;
import com.smartdevicelink.AndroidTestCase2;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCResponse;
import com.smartdevicelink.proxy.interfaces.ISdl;
+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.SetGlobalProperties;
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.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+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;
public class PresentKeyboardOperationTests extends AndroidTestCase2 {
private PresentKeyboardOperation presentKeyboardOperation;
+ private KeyboardListener keyboardListener;
+ private ISdl internalInterface;
+
+ private ExecutorService executor;
@Override
public void setUp() throws Exception{
super.setUp();
- ISdl internalInterface = mock(ISdl.class);
- KeyboardListener keyboardListener = mock(KeyboardListener.class);
- presentKeyboardOperation = new PresentKeyboardOperation(internalInterface, getKeyBoardProperties(), "Test", null, keyboardListener);
+ internalInterface = mock(ISdl.class);
+ keyboardListener = mock(KeyboardListener.class);
+
+ Answer<Void> setGlobalPropertiesAnswer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ SetGlobalProperties setGlobalProperties = (SetGlobalProperties) args[0];
+
+ RPCResponse response = new RPCResponse(FunctionID.SET_GLOBAL_PROPERTIES.toString());
+ response.setSuccess(true);
+ setGlobalProperties.getOnRPCResponseListener().onResponse(0, response);
+
+ return null;
+ }
+ };
+ doAnswer(setGlobalPropertiesAnswer).when(internalInterface).sendRPC(any(SetGlobalProperties.class));
+
+ executor = Executors.newCachedThreadPool();
}
@Override
@@ -64,20 +103,186 @@ public class PresentKeyboardOperationTests extends AndroidTestCase2 {
super.tearDown();
}
+ private KeyboardProperties getKeyBoardProperties(){
+ KeyboardProperties properties = new KeyboardProperties();
+ properties.setLanguage(Language.EN_US);
+ properties.setKeyboardLayout(KeyboardLayout.QWERTZ);
+ properties.setKeypressMode(KeypressMode.RESEND_CURRENT_ENTRY);
+ return properties;
+ }
+
public void testGetPerformInteraction(){
+ presentKeyboardOperation = new PresentKeyboardOperation(internalInterface, getKeyBoardProperties(), "Test", null, keyboardListener, Test.GENERAL_INTEGER);
+
PerformInteraction pi = presentKeyboardOperation.getPerformInteraction();
assertEquals(pi.getInitialText(), "Test");
assertNull(pi.getHelpPrompt());
assertNull(pi.getTimeoutPrompt());
assertNull(pi.getVrHelp());
assertEquals(pi.getInteractionLayout(), LayoutMode.KEYBOARD);
+ assertEquals(pi.getCancelID(), Test.GENERAL_INTEGER);
}
- private KeyboardProperties getKeyBoardProperties(){
- KeyboardProperties properties = new KeyboardProperties();
- properties.setLanguage(Language.EN_US);
- properties.setKeyboardLayout(KeyboardLayout.QWERTZ);
- properties.setKeypressMode(KeypressMode.RESEND_CURRENT_ENTRY);
- return properties;
+ public void testCancelingKeyboardSuccessfullyIfThreadIsRunning(){
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
+ presentKeyboardOperation = new PresentKeyboardOperation(internalInterface, null, "Test", null, null, Test.GENERAL_INTEGER);
+ executor.execute(presentKeyboardOperation);
+ try {
+ executor.awaitTermination(1, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {}
+
+ assertTrue(presentKeyboardOperation.isExecuting());
+ assertFalse(presentKeyboardOperation.isFinished());
+ assertFalse(presentKeyboardOperation.isCancelled());
+
+ presentKeyboardOperation.dismissKeyboard();
+ Answer<Void> cancelInteractionAnswer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ CancelInteraction cancelInteraction = (CancelInteraction) args[0];
+
+ assertEquals(cancelInteraction.getCancelID(), Test.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));
+
+ assertTrue(presentKeyboardOperation.isExecuting());
+ assertFalse(presentKeyboardOperation.isFinished());
+ assertFalse(presentKeyboardOperation.isCancelled());
+ }
+
+ public void testCancelingKeyboardUnsuccessfullyIfThreadIsRunning(){
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
+ presentKeyboardOperation = new PresentKeyboardOperation(internalInterface, null, "Test", null, null, Test.GENERAL_INTEGER);
+ executor.execute(presentKeyboardOperation);
+ try {
+ executor.awaitTermination(1, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {}
+
+ presentKeyboardOperation.dismissKeyboard();
+ Answer<Void> cancelInteractionAnswer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ CancelInteraction cancelInteraction = (CancelInteraction) args[0];
+
+ assertEquals(cancelInteraction.getCancelID(), Test.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));
+
+ assertTrue(presentKeyboardOperation.isExecuting());
+ assertFalse(presentKeyboardOperation.isFinished());
+ assertFalse(presentKeyboardOperation.isCancelled());
+ }
+
+ public void testCancelingKeyboardIfThreadHasFinished(){
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
+ presentKeyboardOperation = new PresentKeyboardOperation(internalInterface, null, "Test", null, null, Test.GENERAL_INTEGER);
+ presentKeyboardOperation.finishOperation();
+
+ assertFalse(presentKeyboardOperation.isExecuting());
+ assertTrue(presentKeyboardOperation.isFinished());
+ assertFalse(presentKeyboardOperation.isCancelled());
+
+ presentKeyboardOperation.dismissKeyboard();
+ verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
+
+ assertFalse(presentKeyboardOperation.isExecuting());
+ assertTrue(presentKeyboardOperation.isFinished());
+ assertFalse(presentKeyboardOperation.isCancelled());
+ }
+
+ public void testCancelingKeyboardIfThreadHasNotYetRun(){
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0));
+ presentKeyboardOperation = new PresentKeyboardOperation(internalInterface, null, "Test", null, null, Test.GENERAL_INTEGER);
+
+ assertFalse(presentKeyboardOperation.isExecuting());
+ assertFalse(presentKeyboardOperation.isFinished());
+ assertFalse(presentKeyboardOperation.isCancelled());
+
+ presentKeyboardOperation.dismissKeyboard();
+
+ // Once the operation has started
+ executor.execute(presentKeyboardOperation);
+ try {
+ executor.awaitTermination(1, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {}
+
+ assertFalse(presentKeyboardOperation.isExecuting());
+ assertTrue(presentKeyboardOperation.isFinished());
+ assertFalse(presentKeyboardOperation.isCancelled());
+
+ // 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));
+ }
+
+ public void testCancelingChoiceSetIfHeadUnitDoesNotSupportFeature(){
+ // Cancel Interaction is only supported on RPC specs v.6.0.0+
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(5, 3));
+ presentKeyboardOperation = new PresentKeyboardOperation(internalInterface, null, "Test", null, null, Test.GENERAL_INTEGER);
+ executor.execute(presentKeyboardOperation);
+ try {
+ executor.awaitTermination(1, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {}
+
+ assertTrue(presentKeyboardOperation.isExecuting());
+ assertFalse(presentKeyboardOperation.isFinished());
+ assertFalse(presentKeyboardOperation.isCancelled());
+
+ presentKeyboardOperation.dismissKeyboard();
+
+ verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
+ verify(internalInterface, times(1)).sendRPC(any(PerformInteraction.class));
+ }
+
+ public void testCancelingChoiceSetIfHeadUnitDoesNotSupportFeatureButThreadIsNotRunning(){
+ // Cancel Interaction is only supported on RPC specs v.6.0.0+
+ when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(5, 3));
+ presentKeyboardOperation = new PresentKeyboardOperation(internalInterface, null, "Test", null, null, Test.GENERAL_INTEGER);
+
+ assertFalse(presentKeyboardOperation.isExecuting());
+ assertFalse(presentKeyboardOperation.isFinished());
+ assertFalse(presentKeyboardOperation.isCancelled());
+
+ presentKeyboardOperation.dismissKeyboard();
+
+ verify(internalInterface, never()).sendRPC(any(CancelInteraction.class));
+
+ // Once the operation has started
+ executor.execute(presentKeyboardOperation);
+ try {
+ executor.awaitTermination(1, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {}
+
+ assertFalse(presentKeyboardOperation.isExecuting());
+ assertTrue(presentKeyboardOperation.isFinished());
+ assertFalse(presentKeyboardOperation.isCancelled());
+
+ // 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/test/rpc/requests/AlertTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/AlertTests.java
index d4a7bd473..8bd229d4d 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/AlertTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/AlertTests.java
@@ -39,6 +39,7 @@ public class AlertTests extends BaseRpcTests{
msg.setProgressIndicator(Test.GENERAL_BOOLEAN);
msg.setTtsChunks(Test.GENERAL_TTSCHUNK_LIST);
msg.setSoftButtons(Test.GENERAL_SOFTBUTTON_LIST);
+ msg.setCancelID(Test.GENERAL_INTEGER);
msg.setAlertIcon(Test.GENERAL_IMAGE);
return msg;
@@ -67,6 +68,7 @@ public class AlertTests extends BaseRpcTests{
result.put(Alert.KEY_PROGRESS_INDICATOR, Test.GENERAL_BOOLEAN);
result.put(Alert.KEY_TTS_CHUNKS, Test.JSON_TTSCHUNKS);
result.put(Alert.KEY_SOFT_BUTTONS, Test.JSON_SOFTBUTTONS);
+ result.put(Alert.KEY_CANCEL_ID, Test.GENERAL_INTEGER);
result.put(Alert.KEY_ALERT_ICON, Test.JSON_IMAGE);
}catch(JSONException e){
fail(Test.JSON_FAIL);
@@ -88,6 +90,7 @@ public class AlertTests extends BaseRpcTests{
boolean testProgressIndicator = ( (Alert) msg ).getProgressIndicator();
List<TTSChunk> testTtsChunks = ( (Alert) msg ).getTtsChunks();
List<SoftButton> testSoftButtons = ( (Alert) msg ).getSoftButtons();
+ Integer testCancelID = ( (Alert) msg ).getCancelID();
Image alertIcon = ( (Alert) msg ).getAlertIcon();
// Valid Tests
@@ -99,6 +102,7 @@ public class AlertTests extends BaseRpcTests{
assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, testProgressIndicator);
assertTrue(Test.TRUE, Validator.validateSoftButtons(Test.GENERAL_SOFTBUTTON_LIST, testSoftButtons));
assertTrue(Test.TRUE, Validator.validateTtsChunks(Test.GENERAL_TTSCHUNK_LIST, testTtsChunks));
+ assertEquals(Test.MATCH, Test.GENERAL_INTEGER, testCancelID);
assertTrue(Test.TRUE, Validator.validateImage(Test.GENERAL_IMAGE, alertIcon));
// Invalid/Null Tests
@@ -114,6 +118,7 @@ public class AlertTests extends BaseRpcTests{
assertNull(Test.NULL, msg.getProgressIndicator());
assertNull(Test.NULL, msg.getTtsChunks());
assertNull(Test.NULL, msg.getSoftButtons());
+ assertNull(Test.NULL, msg.getCancelID());
assertNull(Test.NULL, msg.getAlertIcon());
}
@@ -141,6 +146,7 @@ public class AlertTests extends BaseRpcTests{
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, Alert.KEY_ALERT_TEXT_2), cmd.getAlertText2());
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, Alert.KEY_ALERT_TEXT_3), cmd.getAlertText3());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, Alert.KEY_PROGRESS_INDICATOR), cmd.getProgressIndicator());
+ assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(parameters, Alert.KEY_CANCEL_ID), cmd.getCancelID());
JSONArray ttsChunkArray = JsonUtils.readJsonArrayFromJsonObject(parameters, Alert.KEY_TTS_CHUNKS);
List<TTSChunk> ttsChunkList = new ArrayList<TTSChunk>();
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/CancelInteractionTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/CancelInteractionTests.java
new file mode 100644
index 000000000..8735bea9c
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/CancelInteractionTests.java
@@ -0,0 +1,135 @@
+/*
+ * 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 Nicole Yarroch on 7/17/19 10:06 AM
+ */
+
+package com.smartdevicelink.test.rpc.requests;
+
+import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCMessage;
+import com.smartdevicelink.proxy.rpc.CancelInteraction;
+import com.smartdevicelink.test.BaseRpcTests;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+import com.smartdevicelink.test.json.rpc.JsonFileReader;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Hashtable;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.proxy.rpc.CancelInteraction}
+ */
+public class CancelInteractionTests extends BaseRpcTests {
+
+ @Override
+ protected RPCMessage createMessage() {
+ CancelInteraction msg = new CancelInteraction();
+ msg.setInteractionFunctionID(Test.GENERAL_INTEGER);
+ msg.setCancelID(Test.GENERAL_INTEGER);
+ return msg;
+ }
+
+ @Override
+ protected String getMessageType(){
+ return RPCMessage.KEY_REQUEST;
+ }
+
+ @Override
+ protected String getCommandType(){
+ return FunctionID.CANCEL_INTERACTION.toString();
+ }
+
+ @Override
+ protected JSONObject getExpectedParameters(int sdlVersion) {
+ JSONObject result = new JSONObject();
+
+ try {
+ result.put(CancelInteraction.KEY_FUNCTION_ID, Test.GENERAL_INTEGER);
+ result.put(CancelInteraction.KEY_CANCEL_ID, Test.GENERAL_INTEGER);
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+
+ return result;
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues () {
+ // Test Values
+ Integer testFunctionID = ((CancelInteraction) msg).getInteractionFunctionID();
+ Integer testCancelID = ((CancelInteraction) msg).getCancelID();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_INTEGER, testFunctionID);
+ assertEquals(Test.MATCH, Test.GENERAL_INTEGER, testCancelID);
+
+ // Invalid/Null Tests
+ CancelInteraction msg = new CancelInteraction();
+ assertNotNull(Test.NOT_NULL, msg);
+ testNullBase(msg);
+
+ assertNull(Test.NULL, msg.getInteractionFunctionID());
+ assertNull(Test.NULL, msg.getCancelID());
+ }
+
+ /**
+ * Tests a valid JSON construction of this RPC message.
+ */
+ public void testJsonConstructor () {
+ JSONObject commandJson = JsonFileReader.readId(this.mContext, getCommandType(), getMessageType());
+ assertNotNull(Test.NOT_NULL, commandJson);
+
+ try {
+ Hashtable<String, Object> hash = JsonRPCMarshaller.deserializeJSONObject(commandJson);
+ CancelInteraction cmd = new CancelInteraction(hash);
+ JSONObject body = JsonUtils.readJsonObjectFromJsonObject(commandJson, getMessageType());
+ assertNotNull(Test.NOT_NULL, body);
+
+ // Test everything in the json body.
+ assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(body, RPCMessage.KEY_FUNCTION_NAME), cmd.getFunctionName());
+ assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(body, RPCMessage.KEY_CORRELATION_ID), cmd.getCorrelationID());
+ JSONObject parameters = JsonUtils.readJsonObjectFromJsonObject(body, RPCMessage.KEY_PARAMETERS);
+
+ assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(parameters, CancelInteraction.KEY_FUNCTION_ID), cmd.getInteractionFunctionID());
+ assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(parameters, CancelInteraction.KEY_CANCEL_ID), cmd.getCancelID());
+ }
+ catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/PerformInteractionTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/PerformInteractionTests.java
index e415d8382..cd3ea00b4 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/PerformInteractionTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/PerformInteractionTests.java
@@ -24,7 +24,7 @@ import java.util.List;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.PerformInteraction}
+ * {@link com.smartdevicelink.proxy.rpc.PerformInteraction}
*/
public class PerformInteractionTests extends BaseRpcTests {
@@ -41,6 +41,7 @@ public class PerformInteractionTests extends BaseRpcTests {
msg.setInitialText(Test.GENERAL_STRING);
msg.setInteractionMode(Test.GENERAL_INTERACTIONMODE);
msg.setTimeout(Test.GENERAL_INT);
+ msg.setCancelID(Test.GENERAL_INTEGER);
return msg;
}
@@ -68,7 +69,8 @@ public class PerformInteractionTests extends BaseRpcTests {
result.put(PerformInteraction.KEY_INTERACTION_LAYOUT, Test.GENERAL_LAYOUTMODE);
result.put(PerformInteraction.KEY_INITIAL_TEXT, Test.GENERAL_STRING);
result.put(PerformInteraction.KEY_INTERACTION_MODE, Test.GENERAL_INTERACTIONMODE);
- result.put(PerformInteraction.KEY_TIMEOUT, Test.GENERAL_INT);
+ result.put(PerformInteraction.KEY_TIMEOUT, Test.GENERAL_INT);
+ result.put(PerformInteraction.KEY_CANCEL_ID, Test.GENERAL_INTEGER);
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -90,6 +92,7 @@ public class PerformInteractionTests extends BaseRpcTests {
String testInitialText = ( (PerformInteraction) msg).getInitialText();
InteractionMode testMode = ( (PerformInteraction) msg).getInteractionMode();
Integer testTimeout = ( (PerformInteraction) msg).getTimeout();
+ Integer testCancelID = ( (PerformInteraction) msg ).getCancelID();
// Valid Tests
assertTrue(Test.TRUE, Validator.validateTtsChunks(Test.GENERAL_TTSCHUNK_LIST, testInitialPrompt));
@@ -101,6 +104,7 @@ public class PerformInteractionTests extends BaseRpcTests {
assertEquals(Test.MATCH, Test.GENERAL_STRING, testInitialText);
assertEquals(Test.MATCH, Test.GENERAL_INTERACTIONMODE, testMode);
assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, testTimeout);
+ assertEquals(Test.MATCH, Test.GENERAL_INTEGER, testCancelID);
// Invald/Null Tests
PerformInteraction msg = new PerformInteraction();
@@ -117,6 +121,7 @@ public class PerformInteractionTests extends BaseRpcTests {
assertNull(Test.NULL, msg.getInitialText());
assertNull(Test.NULL, msg.getInteractionMode());
assertNull(Test.NULL, msg.getTimeout());
+ assertNull(Test.NULL, msg.getCancelID());
}
/**
@@ -140,6 +145,7 @@ public class PerformInteractionTests extends BaseRpcTests {
JSONObject parameters = JsonUtils.readJsonObjectFromJsonObject(body, RPCMessage.KEY_PARAMETERS);
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, PerformInteraction.KEY_INITIAL_TEXT), cmd.getInitialText());
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, PerformInteraction.KEY_INTERACTION_MODE), cmd.getInteractionMode().toString());
+ assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(parameters, PerformInteraction.KEY_CANCEL_ID), cmd.getCancelID());
List<Integer> interactionIDList = JsonUtils.readIntegerListFromJsonObject(parameters, PerformInteraction.KEY_INTERACTION_CHOICE_SET_ID_LIST);
List<Integer> testIDList = cmd.getInteractionChoiceSetIDList();
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/ScrollableMessageTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/ScrollableMessageTests.java
index 2a4e14a6a..195cb7973 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/ScrollableMessageTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/ScrollableMessageTests.java
@@ -21,7 +21,7 @@ import java.util.List;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.ScrollableMessage}
+ * {@link com.smartdevicelink.proxy.rpc.ScrollableMessage}
*/
public class ScrollableMessageTests extends BaseRpcTests {
@@ -32,6 +32,7 @@ public class ScrollableMessageTests extends BaseRpcTests {
msg.setTimeout(Test.GENERAL_INT);
msg.setSoftButtons(Test.GENERAL_SOFTBUTTON_LIST);
msg.setScrollableMessageBody(Test.GENERAL_STRING);
+ msg.setCancelID(Test.GENERAL_INTEGER);
return msg;
}
@@ -53,7 +54,8 @@ public class ScrollableMessageTests extends BaseRpcTests {
try {
result.put(ScrollableMessage.KEY_SCROLLABLE_MESSAGE_BODY, Test.GENERAL_STRING);
result.put(ScrollableMessage.KEY_TIMEOUT, Test.GENERAL_INT);
- result.put(ScrollableMessage.KEY_SOFT_BUTTONS, Test.JSON_SOFTBUTTONS);
+ result.put(ScrollableMessage.KEY_SOFT_BUTTONS, Test.JSON_SOFTBUTTONS);
+ result.put(ScrollableMessage.KEY_CANCEL_ID, Test.GENERAL_INTEGER);
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -69,6 +71,7 @@ public class ScrollableMessageTests extends BaseRpcTests {
String testBody = ( (ScrollableMessage) msg ).getScrollableMessageBody();
Integer testTimeout = ( (ScrollableMessage) msg ).getTimeout();
List<SoftButton> testSoftButtons = ( (ScrollableMessage) msg ).getSoftButtons();
+ Integer testCancelID = ( (ScrollableMessage) msg ).getCancelID();
// Valid Tests
assertEquals(Test.MATCH, Test.GENERAL_STRING, testBody);
@@ -77,7 +80,8 @@ public class ScrollableMessageTests extends BaseRpcTests {
for (int i = 0; i < Test.GENERAL_SOFTBUTTON_LIST.size(); i++) {
assertEquals(Test.MATCH, Test.GENERAL_SOFTBUTTON_LIST.get(i), testSoftButtons.get(i));
}
-
+ assertEquals(Test.MATCH, Test.GENERAL_INTEGER, testCancelID);
+
// Invalid/Null Tests
ScrollableMessage msg = new ScrollableMessage();
assertNotNull(Test.NOT_NULL, msg);
@@ -87,6 +91,7 @@ public class ScrollableMessageTests extends BaseRpcTests {
assertNull(Test.NULL, msg.getScrollableMessageBody());
assertNull(Test.NULL, msg.getTimeout());
assertNull(Test.NULL, msg.getSoftButtons());
+ assertNull(Test.NULL, msg.getCancelID());
}
/**
@@ -110,6 +115,7 @@ public class ScrollableMessageTests extends BaseRpcTests {
JSONObject parameters = JsonUtils.readJsonObjectFromJsonObject(body, RPCMessage.KEY_PARAMETERS);
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, ScrollableMessage.KEY_SCROLLABLE_MESSAGE_BODY), cmd.getScrollableMessageBody());
assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(parameters, ScrollableMessage.KEY_TIMEOUT), cmd.getTimeout());
+ assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(parameters, ScrollableMessage.KEY_CANCEL_ID), cmd.getCancelID());
JSONArray softButtonArray = JsonUtils.readJsonArrayFromJsonObject(parameters, ScrollableMessage.KEY_SOFT_BUTTONS);
List<SoftButton> softButtonList = new ArrayList<SoftButton>();
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SliderTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SliderTests.java
index 12119b847..cce913632 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SliderTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SliderTests.java
@@ -18,7 +18,7 @@ import java.util.List;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.Slider}
+ * {@link com.smartdevicelink.proxy.rpc.Slider}
*/
public class SliderTests extends BaseRpcTests {
@@ -31,6 +31,7 @@ public class SliderTests extends BaseRpcTests {
msg.setTimeout(Test.GENERAL_INT);
msg.setSliderHeader(Test.GENERAL_STRING);
msg.setSliderFooter(Test.GENERAL_STRING_LIST);
+ msg.setCancelID(Test.GENERAL_INTEGER);
return msg;
}
@@ -54,7 +55,8 @@ public class SliderTests extends BaseRpcTests {
result.put(Slider.KEY_SLIDER_FOOTER, JsonUtils.createJsonArray(Test.GENERAL_STRING_LIST));
result.put(Slider.KEY_POSITION, Test.GENERAL_INT);
result.put(Slider.KEY_TIMEOUT, Test.GENERAL_INT);
- result.put(Slider.KEY_NUM_TICKS, Test.GENERAL_INT);
+ result.put(Slider.KEY_NUM_TICKS, Test.GENERAL_INT);
+ result.put(Slider.KEY_CANCEL_ID, Test.GENERAL_INTEGER);
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -72,13 +74,15 @@ public class SliderTests extends BaseRpcTests {
Integer testPosition = ( (Slider) msg ).getPosition();
String testSlider = ( (Slider) msg ).getSliderHeader();
List<String> testFooter = ( (Slider) msg ).getSliderFooter();
-
+ Integer testCancelID = ( (Slider) msg ).getCancelID();
+
// Valid Tests
assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, testNumTicks);
assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, testTimeout);
assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, testPosition);
assertEquals(Test.MATCH, Test.GENERAL_STRING, testSlider);
assertTrue(Test.TRUE, Validator.validateStringList(Test.GENERAL_STRING_LIST, testFooter));
+ assertEquals(Test.MATCH, Test.GENERAL_INTEGER, testCancelID);
// Invalid/Null Tests
Slider msg = new Slider();
@@ -90,6 +94,7 @@ public class SliderTests extends BaseRpcTests {
assertNull(Test.NULL, msg.getPosition());
assertNull(Test.NULL, msg.getTimeout());
assertNull(Test.NULL, msg.getNumTicks());
+ assertNull(Test.NULL, msg.getCancelID());
}
/**
@@ -121,6 +126,7 @@ public class SliderTests extends BaseRpcTests {
assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(parameters, Slider.KEY_POSITION), cmd.getPosition());
assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(parameters, Slider.KEY_TIMEOUT), cmd.getTimeout());
+ assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(parameters, Slider.KEY_CANCEL_ID), cmd.getCancelID());
}
catch (JSONException e) {
fail(Test.JSON_FAIL);
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/CancelInteractionResponseTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/CancelInteractionResponseTests.java
new file mode 100644
index 000000000..e983327f2
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/CancelInteractionResponseTests.java
@@ -0,0 +1,108 @@
+/*
+ * 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 Nicole Yarroch on 7/24/19 9:35 AM
+ */
+
+package com.smartdevicelink.test.rpc.responses;
+
+import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCMessage;
+import com.smartdevicelink.proxy.rpc.CancelInteractionResponse;
+import com.smartdevicelink.test.BaseRpcTests;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+import com.smartdevicelink.test.json.rpc.JsonFileReader;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Hashtable;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.proxy.rpc.CancelInteractionResponse}
+ */
+public class CancelInteractionResponseTests extends BaseRpcTests {
+
+ @Override
+ protected RPCMessage createMessage(){
+ return new CancelInteractionResponse();
+ }
+
+ @Override
+ protected String getMessageType(){
+ return RPCMessage.KEY_RESPONSE;
+ }
+
+ @Override
+ protected String getCommandType(){
+ return FunctionID.CANCEL_INTERACTION.toString();
+ }
+
+ @Override
+ protected JSONObject getExpectedParameters(int sdlVersion){
+ return new JSONObject();
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues () {
+ // Invalid/Null Tests
+ CancelInteractionResponse msg = new CancelInteractionResponse();
+ assertNotNull(Test.NOT_NULL, msg);
+ testNullBase(msg);
+ }
+
+ /**
+ * Tests a valid JSON construction of this RPC message.
+ */
+ public void testJsonConstructor () {
+ JSONObject commandJson = JsonFileReader.readId(this.mContext, getCommandType(), getMessageType());
+ assertNotNull(Test.NOT_NULL, commandJson);
+
+ try {
+ Hashtable<String, Object> hash = JsonRPCMarshaller.deserializeJSONObject(commandJson);
+ CancelInteractionResponse cmd = new CancelInteractionResponse(hash);
+
+ JSONObject body = JsonUtils.readJsonObjectFromJsonObject(commandJson, getMessageType());
+ assertNotNull(Test.NOT_NULL, body);
+
+ // Test everything in the json body.
+ assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(body, RPCMessage.KEY_FUNCTION_NAME), cmd.getFunctionName());
+ assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(body, RPCMessage.KEY_CORRELATION_ID), cmd.getCorrelationID());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/ProxyBridge.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/ProxyBridge.java
index 50200b247..23c37bea5 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/ProxyBridge.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/ProxyBridge.java
@@ -44,6 +44,7 @@ import com.smartdevicelink.proxy.rpc.AddSubMenuResponse;
import com.smartdevicelink.proxy.rpc.AlertManeuverResponse;
import com.smartdevicelink.proxy.rpc.AlertResponse;
import com.smartdevicelink.proxy.rpc.ButtonPressResponse;
+import com.smartdevicelink.proxy.rpc.CancelInteractionResponse;
import com.smartdevicelink.proxy.rpc.ChangeRegistrationResponse;
import com.smartdevicelink.proxy.rpc.CloseApplicationResponse;
import com.smartdevicelink.proxy.rpc.CreateInteractionChoiceSetResponse;
@@ -671,6 +672,11 @@ public class ProxyBridge implements IProxyListener{
}
@Override
+ public void onCancelInteractionResponse(CancelInteractionResponse response) {
+ onRPCReceived(response);
+ }
+
+ @Override
public void onShowAppMenuResponse(ShowAppMenuResponse response) {
onRPCReceived(response);
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java b/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java
index a3e798ade..c6e6d8b6d 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java
@@ -3750,6 +3750,22 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
_proxyListener.onCloseApplicationResponse(msg);
onRPCResponseReceived(msg);
}
+ } else if (functionName.equals(FunctionID.CANCEL_INTERACTION.toString())) {
+ final CancelInteractionResponse msg = new CancelInteractionResponse(hash);
+ msg.format(rpcSpecVersion, true);
+ if (_callbackToUIThread) {
+ // Run in UI thread
+ _mainUIHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ _proxyListener.onCancelInteractionResponse(msg);
+ onRPCResponseReceived(msg);
+ }
+ });
+ } else {
+ _proxyListener.onCancelInteractionResponse(msg);
+ onRPCResponseReceived(msg);
+ }
} else if (functionName.equals(FunctionID.UNPUBLISH_APP_SERVICE.toString())) {
final UnpublishAppServiceResponse msg = new UnpublishAppServiceResponse(hash);
msg.format(rpcSpecVersion, true);
diff --git a/base/src/main/java/com/smartdevicelink/managers/screen/BaseScreenManager.java b/base/src/main/java/com/smartdevicelink/managers/screen/BaseScreenManager.java
index 572182801..0a9404c4c 100644
--- a/base/src/main/java/com/smartdevicelink/managers/screen/BaseScreenManager.java
+++ b/base/src/main/java/com/smartdevicelink/managers/screen/BaseScreenManager.java
@@ -522,9 +522,10 @@ abstract class BaseScreenManager extends BaseSubManager {
* @param initialText - The initial text that is used as a placeholder text. It might not work on some head units.
* @param customKeyboardProperties - the custom keyboard configuration to be used when the keyboard is displayed
* @param keyboardListener - A keyboard listener to capture user input
+ * @return A unique cancelID that can be used to cancel this keyboard. If `null`, no keyboard was created.
*/
- public void presentKeyboard(@NonNull String initialText, @Nullable KeyboardProperties customKeyboardProperties, @NonNull KeyboardListener keyboardListener){
- this.choiceSetManager.presentKeyboard(initialText, customKeyboardProperties, keyboardListener);
+ public Integer presentKeyboard(@NonNull String initialText, @Nullable KeyboardProperties customKeyboardProperties, @NonNull KeyboardListener keyboardListener){
+ return this.choiceSetManager.presentKeyboard(initialText, customKeyboardProperties, keyboardListener);
}
/**
@@ -542,6 +543,14 @@ abstract class BaseScreenManager extends BaseSubManager {
return this.choiceSetManager.getPreloadedChoices();
}
+ /**
+ * Dismisses a currently presented keyboard with the associated ID. Canceling a keyboard only works when connected to SDL Core v.6.0+. When connected to older versions of SDL Core the keyboard will not be dismissed.
+ * @param cancelID The unique ID assigned to the keyboard
+ */
+ public void dismissKeyboard(@NonNull Integer cancelID) {
+ this.choiceSetManager.dismissKeyboard(cancelID);
+ }
+
// END CHOICE SETS
/**
@@ -581,5 +590,4 @@ abstract class BaseScreenManager extends BaseSubManager {
}
});
}
-
}
diff --git a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/AsynchronousOperation.java b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/AsynchronousOperation.java
new file mode 100644
index 000000000..c0a1dbb25
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/AsynchronousOperation.java
@@ -0,0 +1,122 @@
+/*
+ * 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 Nicole Yarroch on 7/25/19 8:43 AM
+ */
+
+package com.smartdevicelink.managers.screen.choiceset;
+
+import com.smartdevicelink.util.DebugTool;
+
+class AsynchronousOperation implements Runnable {
+ private static final String TAG = "AsynchronousOperation - ";
+ private Thread thread;
+ private final Object lock;
+ private boolean blocked;
+ private boolean executing;
+ private boolean finished;
+ private boolean cancelled;
+
+ AsynchronousOperation() {
+ lock = new Object();
+ blocked = false;
+ executing = false;
+ finished = false;
+ cancelled = false;
+ }
+
+ @Override
+ public void run() {
+ thread = Thread.currentThread();
+ DebugTool.logInfo(TAG + "Starting: " + toString());
+ if (isCancelled()) {
+ finished = true;
+ DebugTool.logInfo(TAG + "Operation was cancelled: " + toString());
+ return;
+ }
+
+ executing = true;
+ }
+
+ void finishOperation() {
+ unblock();
+ executing = false;
+ finished = true;
+ cancelled = false;
+ DebugTool.logInfo(TAG + "Finishing: " + toString());
+ }
+
+ boolean isExecuting() {
+ return executing;
+ }
+
+ boolean isFinished() {
+ return finished;
+ }
+
+ void cancel(){
+ cancelled = true;
+ }
+
+ boolean isCancelled() {
+ return cancelled;
+ }
+
+ void block(){
+ if (!blocked && !finished) {
+ blocked = true;
+ DebugTool.logInfo(TAG + "Blocking: " + toString());
+ try {
+ synchronized (lock) {
+ lock.wait();
+ }
+ } catch (InterruptedException e) {
+ DebugTool.logWarning(TAG + "InterruptedException: " + toString());
+ finishOperation();
+ }
+ }
+ }
+
+ void unblock(){
+ if (blocked) {
+ blocked = false;
+ DebugTool.logInfo(TAG + "Unblocking: " + toString());
+ synchronized (lock) {
+ lock.notify();
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + " (OpId: " + System.identityHashCode(this) + ", OpThread:" + (thread != null ? thread.getName() : "no operating thread") + ", currentThread:" + Thread.currentThread().getName() + ", blocked:" + blocked + ", executing:" + executing + ", finished:" + finished + ", cancelled:" + cancelled + ")";
+ }
+}
diff --git a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/BaseChoiceSetManager.java b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/BaseChoiceSetManager.java
index 2636ada50..e343cd131 100644
--- a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/BaseChoiceSetManager.java
+++ b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/BaseChoiceSetManager.java
@@ -86,16 +86,18 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
SystemContext currentSystemContext;
HashSet<ChoiceCell> preloadedChoices, pendingPreloadChoices;
ChoiceSet pendingPresentationSet;
- private List<ChoiceCell> waitingChoices;
- private CompletionListener waitingListener;
// We will pass operations into this to be completed
PausableThreadPoolExecutor executor;
LinkedBlockingQueue<Runnable> operationQueue;
Future pendingPresentOperation;
+ PresentKeyboardOperation currentlyPresentedKeyboardOperation;
+
int nextChoiceId;
+ int nextCancelId;
final int choiceCellIdMin = 1;
+ final int choiceCellCancelIdMin = 1;
boolean isVROptional;
BaseChoiceSetManager(@NonNull ISdl internalInterface, @NonNull FileManager fileManager) {
@@ -111,11 +113,14 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
preloadedChoices = new HashSet<>();
pendingPreloadChoices = new HashSet<>();
nextChoiceId = choiceCellIdMin;
+ nextCancelId = choiceCellCancelIdMin;
isVROptional = false;
keyboardConfiguration = defaultKeyboardConfiguration();
operationQueue = new LinkedBlockingQueue<>();
executor = new PausableThreadPoolExecutor(1, Runtime.getRuntime().availableProcessors(), 10, TimeUnit.SECONDS, operationQueue);
executor.pause(); // pause until HMI ready
+
+ currentlyPresentedKeyboardOperation = null;
}
@Override
@@ -138,10 +143,9 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
pendingPresentationSet = null;
pendingPresentOperation = null;
- waitingChoices = null;
- waitingListener = null;
- isVROptional = true;
+ isVROptional = false;
nextChoiceId = choiceCellIdMin;
+ nextCancelId = choiceCellCancelIdMin;
// remove listeners
internalInterface.removeOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, hmiListener);
@@ -162,7 +166,7 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
@Override
public void onError(String error) {
- // At this point, there were errors trying to send a test CICS
+ // At this point, there were errors trying to send a test PICS
// If we reach this state, we cannot use the manager
DebugTool.logError(error);
transitionToState(ERROR);
@@ -182,10 +186,7 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
*/
public void preloadChoices(@NonNull List<ChoiceCell> choices, @Nullable final CompletionListener listener){
- if (!isReady()){
- waitingChoices = new ArrayList<>(choices);
- waitingListener = listener;
- DebugTool.logInfo("Preload pending choice set manager being ready");
+ if (getState() == ERROR){
return;
}
@@ -215,15 +216,11 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
if (listener != null){
listener.onComplete(true);
}
- waitingChoices = null;
- waitingListener = null;
}else {
DebugTool.logError("There was an error pre loading choice cells");
- if (listener != null){
+ if (listener != null) {
listener.onComplete(false);
}
- waitingChoices = null;
- waitingListener = null;
}
}
});
@@ -240,7 +237,10 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
*/
public void deleteChoices(@NonNull List<ChoiceCell> choices){
- if (!isReady()){ return; }
+ if (getState() == ERROR) {
+ DebugTool.logWarning("Choice Manager In Error State");
+ return;
+ }
// Find cells to be deleted that are already uploaded or are pending upload
final HashSet<ChoiceCell> cellsToBeDeleted = choicesToBeDeletedWithArray(choices);
@@ -252,7 +252,7 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
}
if (pendingPresentOperation != null && !pendingPresentOperation.isCancelled() && !pendingPresentOperation.isDone() && (cellsToBeDeleted.retainAll(pendingPresentationChoices) || cellsToBeRemovedFromPending.retainAll(pendingPresentationChoices))){
- pendingPresentOperation.cancel(true);
+ pendingPresentOperation.cancel(false);
DebugTool.logWarning("Attempting to delete choice cells while there is a pending presentation operation. Pending presentation cancelled.");
pendingPresentOperation = null;
}
@@ -292,13 +292,16 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
*/
public void presentChoiceSet(@NonNull final ChoiceSet choiceSet, @Nullable final InteractionMode mode, @Nullable final KeyboardListener keyboardListener){
- if (!isReady()){ return; }
+ if (getState() == ERROR) {
+ DebugTool.logWarning("Choice Manager In Error State");
+ return;
+ }
// Perform additional checks against the ChoiceSet
if (!setUpChoiceSet(choiceSet)){ return; }
if (this.pendingPresentationSet != null && pendingPresentOperation != null){
- pendingPresentOperation.cancel(true);
+ pendingPresentOperation.cancel(false);
DebugTool.logWarning("Presenting a choice set while one is currently presented. Cancelling previous and continuing");
}
@@ -322,6 +325,7 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
}
findIdsOnChoiceSet(pendingPresentationSet);
+
// Pass back the information to the developer
ChoiceSetSelectionListener privateChoiceListener = new ChoiceSetSelectionListener() {
@Override
@@ -329,8 +333,6 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
if (pendingPresentationSet.getChoiceSetSelectionListener() != null){
pendingPresentationSet.getChoiceSetSelectionListener().onChoiceSelected(choiceCell, triggerSource,rowIndex);
}
- pendingPresentationSet = null;
- pendingPresentOperation = null;
}
@Override
@@ -338,8 +340,6 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
if (pendingPresentationSet.getChoiceSetSelectionListener() != null){
pendingPresentationSet.getChoiceSetSelectionListener().onError(error);
}
- pendingPresentationSet = null;
- pendingPresentOperation = null;
}
};
@@ -348,11 +348,11 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
if (keyboardListener == null){
// Non-searchable choice set
DebugTool.logInfo("Creating non-searchable choice set");
- presentOp = new PresentChoiceSetOperation(internalInterface, pendingPresentationSet, mode, null, null, privateChoiceListener);
+ presentOp = new PresentChoiceSetOperation(internalInterface, pendingPresentationSet, mode, null, null, privateChoiceListener, nextCancelId++);
} else {
// Searchable choice set
DebugTool.logInfo("Creating searchable choice set");
- presentOp = new PresentChoiceSetOperation(internalInterface, pendingPresentationSet, mode, keyboardConfiguration, keyboardListener, privateChoiceListener);
+ presentOp = new PresentChoiceSetOperation(internalInterface, pendingPresentationSet, mode, keyboardConfiguration, keyboardListener, privateChoiceListener, nextCancelId++);
}
pendingPresentOperation = executor.submit(presentOp);
@@ -363,18 +363,21 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
* @param initialText - The initial text that is used as a placeholder text. It might not work on some head units.
* @param customKeyboardConfig - the custom keyboard configuration to be used when the keyboard is displayed
* @param listener - A keyboard listener to capture user input
+ * @return - A unique id that can be used to cancel this keyboard. If `null`, no keyboard was created.
*/
- public void presentKeyboard(@NonNull String initialText, @Nullable KeyboardProperties customKeyboardConfig, @NonNull KeyboardListener listener){
-
+ public Integer presentKeyboard(@NonNull String initialText, @Nullable KeyboardProperties customKeyboardConfig, @NonNull KeyboardListener listener){
if (initialText == null || initialText.length() == 0){
DebugTool.logError("initialText cannot be an empty string.");
- return;
+ return null;
}
- if (!isReady()){ return; }
+ if (getState() == ERROR) {
+ DebugTool.logWarning("Choice Manager In Error State");
+ return null;
+ }
if (pendingPresentationSet != null && pendingPresentOperation != null){
- pendingPresentOperation.cancel(true);
+ pendingPresentOperation.cancel(false);
pendingPresentationSet = null;
DebugTool.logWarning("There is a current or pending choice set, cancelling and continuing.");
}
@@ -389,8 +392,42 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
// Present a keyboard with the choice set that we used to test VR's optional state
DebugTool.logInfo("Presenting Keyboard - Choice Set Manager");
- PresentKeyboardOperation keyboardOp = new PresentKeyboardOperation(internalInterface, keyboardConfiguration, initialText, customKeyboardConfig, listener);
+ Integer keyboardCancelID = nextCancelId++;
+ PresentKeyboardOperation keyboardOp = new PresentKeyboardOperation(internalInterface, keyboardConfiguration, initialText, customKeyboardConfig, listener, keyboardCancelID);
+ currentlyPresentedKeyboardOperation = keyboardOp;
pendingPresentOperation = executor.submit(keyboardOp);
+ return keyboardCancelID;
+ }
+
+ /**
+ * Cancels the keyboard-only interface if it is currently showing. If the keyboard has not yet been sent to Core, it will not be sent.
+ *
+ * This will only dismiss an already presented keyboard if connected to head units running SDL 6.0+.
+ *
+ * @param cancelID - The unique ID assigned to the keyboard, passed as the return value from `presentKeyboard`
+ */
+ public void dismissKeyboard(@NonNull Integer cancelID) {
+ if (getState() == ERROR) {
+ DebugTool.logWarning("Choice Manager In Error State");
+ return;
+ }
+
+ // First, attempt to cancel the currently executing keyboard operation (Once an operation has started it is removed from the operationQueue)
+ if (currentlyPresentedKeyboardOperation != null && currentlyPresentedKeyboardOperation.getCancelID().equals(cancelID)) {
+ currentlyPresentedKeyboardOperation.dismissKeyboard();
+ return;
+ }
+
+ // Next, attempt to cancel keyboard operations that have not yet started
+ for (Runnable operation : operationQueue){
+ if (!(operation instanceof PresentKeyboardOperation)){ continue; }
+
+ PresentKeyboardOperation pendingOp = (PresentKeyboardOperation) operation;
+ if (!(pendingOp.getCancelID().equals(cancelID))) { continue; }
+
+ pendingOp.dismissKeyboard();
+ break;
+ }
}
/**
@@ -503,10 +540,6 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
if (oldHMILevel == HMILevel.HMI_NONE && currentHMILevel != HMILevel.HMI_NONE){
executor.resume();
- if (waitingChoices != null && waitingChoices.size() > 0){
- DebugTool.logInfo("Pending Preload Choices now being sent");
- preloadChoices(waitingChoices, waitingListener);
- }
}
currentSystemContext = onHMIStatus.getSystemContext();
@@ -517,10 +550,6 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
if (currentSystemContext == SystemContext.SYSCTXT_MAIN && currentHMILevel != HMILevel.HMI_NONE){
executor.resume();
- if (waitingChoices != null && waitingChoices.size() > 0){
- DebugTool.logInfo("Pending Preload Choices now being sent");
- preloadChoices(waitingChoices, waitingListener);
- }
}
}
@@ -590,13 +619,4 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
defaultProperties.setKeypressMode(KeypressMode.RESEND_CURRENT_ENTRY);
return defaultProperties;
}
-
- @SuppressWarnings("BooleanMethodIsAlwaysInverted")
- private boolean isReady(){
- if (getState() != READY){
- DebugTool.logWarning("Choice Manager In Not-Ready State");
- return false;
- }
- return true;
- }
}
diff --git a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/CheckChoiceVROptionalOperation.java b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/CheckChoiceVROptionalOperation.java
index 4ac5cb659..1c427c16b 100644
--- a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/CheckChoiceVROptionalOperation.java
+++ b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/CheckChoiceVROptionalOperation.java
@@ -47,21 +47,24 @@ import com.smartdevicelink.util.DebugTool;
import java.lang.ref.WeakReference;
import java.util.Collections;
-class CheckChoiceVROptionalOperation implements Runnable {
+class CheckChoiceVROptionalOperation extends AsynchronousOperation {
private CheckChoiceVROptionalInterface checkChoiceVROptionalInterface;
private WeakReference<ISdl> internalInterface;
private boolean isVROptional;
CheckChoiceVROptionalOperation(ISdl internalInterface, CheckChoiceVROptionalInterface checkChoiceVROptionalInterface){
+ super();
this.internalInterface = new WeakReference<>(internalInterface);
this.checkChoiceVROptionalInterface = checkChoiceVROptionalInterface;
}
@Override
public void run() {
+ CheckChoiceVROptionalOperation.super.run();
DebugTool.logInfo("Choice Operation: Executing check vr optional operation");
sendTestChoiceNoVR();
+ block();
}
/**
@@ -117,6 +120,8 @@ class CheckChoiceVROptionalOperation implements Runnable {
if (checkChoiceVROptionalInterface != null){
checkChoiceVROptionalInterface.onError(response.getInfo());
}
+
+ CheckChoiceVROptionalOperation.super.finishOperation();
}
}
@@ -127,6 +132,8 @@ class CheckChoiceVROptionalOperation implements Runnable {
if (checkChoiceVROptionalInterface != null){
checkChoiceVROptionalInterface.onError(info);
}
+
+ CheckChoiceVROptionalOperation.super.finishOperation();
}
});
@@ -147,6 +154,8 @@ class CheckChoiceVROptionalOperation implements Runnable {
if (checkChoiceVROptionalInterface != null){
checkChoiceVROptionalInterface.onCheckChoiceVROperationComplete(isVROptional);
}
+
+ CheckChoiceVROptionalOperation.super.finishOperation();
}
@Override
@@ -155,6 +164,8 @@ class CheckChoiceVROptionalOperation implements Runnable {
if (checkChoiceVROptionalInterface != null){
checkChoiceVROptionalInterface.onError(info);
}
+
+ CheckChoiceVROptionalOperation.super.finishOperation();
}
});
if (internalInterface.get() != null){
diff --git a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSet.java b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSet.java
index 7a1c0b138..b846760c7 100644
--- a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSet.java
+++ b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSet.java
@@ -53,6 +53,7 @@ public class ChoiceSet {
private List<VrHelpItem> vrHelpList;
private ChoiceSetSelectionListener choiceSetSelectionListener;
private KeyboardProperties customKeyboardConfiguration;
+ ChoiceSetCanceledListener canceledListener;
// defaults
private Integer defaultTimeout = 10;
@@ -153,6 +154,16 @@ public class ChoiceSet {
}
/**
+ * Cancels the choice set. If the choice set has not yet been sent to Core, it will not be sent. If the choice set is already presented on Core, the choice set will be immediately dismissed. Canceling an already presented choice set will only work if connected to Core versions 6.0+. On older versions of Core, the choice set will not be dismissed.
+ */
+ public void cancel() {
+ if (canceledListener == null) {
+ return;
+ }
+ canceledListener.onChoiceSetCanceled();
+ }
+
+ /**
* Maps to PerformInteraction.initialText. The title of the choice set, and/or the initial text on a keyboard prompt.
* @return the title
*/
diff --git a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetCanceledListener.java b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetCanceledListener.java
new file mode 100644
index 000000000..89e850b1e
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetCanceledListener.java
@@ -0,0 +1,42 @@
+/*
+ * 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 Nicole Yarroch on 7/24/19 2:08 PM
+ */
+
+package com.smartdevicelink.managers.screen.choiceset;
+
+interface ChoiceSetCanceledListener {
+ /**
+ * Notifies the subscriber that the choice set should be cancelled.
+ */
+ void onChoiceSetCanceled();
+}
diff --git a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/DeleteChoicesOperation.java b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/DeleteChoicesOperation.java
index fdb01ae38..2fc6c314d 100644
--- a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/DeleteChoicesOperation.java
+++ b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/DeleteChoicesOperation.java
@@ -48,13 +48,14 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
-class DeleteChoicesOperation implements Runnable {
+class DeleteChoicesOperation extends AsynchronousOperation {
private WeakReference<ISdl> internalInterface;
private HashSet<ChoiceCell> cellsToDelete;
private CompletionListener completionListener;
DeleteChoicesOperation(ISdl internalInterface, HashSet<ChoiceCell> cellsToDelete, CompletionListener completionListener){
+ super();
this.internalInterface = new WeakReference<>(internalInterface);
this.cellsToDelete = cellsToDelete;
this.completionListener = completionListener;
@@ -62,8 +63,10 @@ class DeleteChoicesOperation implements Runnable {
@Override
public void run() {
+ DeleteChoicesOperation.super.run();
DebugTool.logInfo("Choice Operation: Executing delete choices operation");
sendDeletions();
+ block();
}
private void sendDeletions(){
@@ -84,6 +87,8 @@ class DeleteChoicesOperation implements Runnable {
completionListener.onComplete(true);
}
DebugTool.logInfo("Successfully deleted choices");
+
+ DeleteChoicesOperation.super.finishOperation();
}
@Override
@@ -92,6 +97,8 @@ class DeleteChoicesOperation implements Runnable {
completionListener.onComplete(false);
}
DebugTool.logError("Failed to delete choice: " + info + " | Corr ID: " + correlationId);
+
+ DeleteChoicesOperation.super.finishOperation();
}
@Override
diff --git a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PreloadChoicesOperation.java b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PreloadChoicesOperation.java
index f3d708998..99cd91a96 100644
--- a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PreloadChoicesOperation.java
+++ b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PreloadChoicesOperation.java
@@ -62,7 +62,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
-class PreloadChoicesOperation implements Runnable {
+class PreloadChoicesOperation extends AsynchronousOperation {
private WeakReference<ISdl> internalInterface;
private WeakReference<FileManager> fileManager;
@@ -74,6 +74,7 @@ class PreloadChoicesOperation implements Runnable {
PreloadChoicesOperation(ISdl internalInterface, FileManager fileManager, DisplayCapabilities displayCapabilities,
Boolean isVROptional, HashSet<ChoiceCell> cellsToPreload, CompletionListener listener){
+ super();
this.internalInterface = new WeakReference<>(internalInterface);
this.fileManager = new WeakReference<>(fileManager);
this.displayCapabilities = displayCapabilities;
@@ -84,6 +85,7 @@ class PreloadChoicesOperation implements Runnable {
@Override
public void run() {
+ PreloadChoicesOperation.super.run();
DebugTool.logInfo("Choice Operation: Executing preload choices operation");
preloadCellArtworks(new CompletionListener() {
@Override
@@ -91,6 +93,7 @@ class PreloadChoicesOperation implements Runnable {
preloadCells();
}
});
+ block();
}
void removeChoicesFromUpload(HashSet<ChoiceCell> choices){
@@ -161,11 +164,15 @@ class PreloadChoicesOperation implements Runnable {
isRunning = false;
DebugTool.logInfo("Finished pre loading choice cells");
completionListener.onComplete(true);
+
+ PreloadChoicesOperation.super.finishOperation();
}
@Override
public void onError(int correlationId, Result resultCode, String info) {
DebugTool.logError("There was an error uploading a choice cell: "+ info + " resultCode: " + resultCode);
+
+ PreloadChoicesOperation.super.finishOperation();
}
@Override
diff --git a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PresentChoiceSetOperation.java b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PresentChoiceSetOperation.java
index e170dd89e..af69c0926 100644
--- a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PresentChoiceSetOperation.java
+++ b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PresentChoiceSetOperation.java
@@ -40,10 +40,12 @@ import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCNotification;
import com.smartdevicelink.proxy.RPCResponse;
import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.rpc.CancelInteraction;
import com.smartdevicelink.proxy.rpc.KeyboardProperties;
import com.smartdevicelink.proxy.rpc.OnKeyboardInput;
import com.smartdevicelink.proxy.rpc.PerformInteraction;
import com.smartdevicelink.proxy.rpc.PerformInteractionResponse;
+import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
import com.smartdevicelink.proxy.rpc.SetGlobalProperties;
import com.smartdevicelink.proxy.rpc.enums.InteractionMode;
import com.smartdevicelink.proxy.rpc.enums.KeyboardEvent;
@@ -58,10 +60,11 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
-class PresentChoiceSetOperation implements Runnable {
+class PresentChoiceSetOperation extends AsynchronousOperation {
private WeakReference<ISdl> internalInterface;
private ChoiceSet choiceSet;
+ private Integer cancelID;
private InteractionMode presentationMode;
private KeyboardProperties originalKeyboardProperties, keyboardProperties;
private ChoiceCell selectedCell;
@@ -71,27 +74,44 @@ class PresentChoiceSetOperation implements Runnable {
private ChoiceSetSelectionListener choiceSetSelectionListener;
Integer selectedCellRow;
KeyboardListener keyboardListener;
+ SdlMsgVersion sdlMsgVersion;
PresentChoiceSetOperation(ISdl internalInterface, ChoiceSet choiceSet, InteractionMode mode,
- KeyboardProperties originalKeyboardProperties, KeyboardListener keyboardListener, ChoiceSetSelectionListener choiceSetSelectionListener){
+ KeyboardProperties originalKeyboardProperties, KeyboardListener keyboardListener, ChoiceSetSelectionListener choiceSetSelectionListener, Integer cancelID){
+ super();
this.internalInterface = new WeakReference<>(internalInterface);
this.keyboardListener = keyboardListener;
this.choiceSet = choiceSet;
+ this.choiceSet.canceledListener = new ChoiceSetCanceledListener() {
+ @Override
+ public void onChoiceSetCanceled() {
+ cancelInteraction();
+ }
+ };
this.presentationMode = mode;
+ this.cancelID = cancelID;
this.originalKeyboardProperties = originalKeyboardProperties;
this.keyboardProperties = originalKeyboardProperties;
this.selectedCellRow = null;
this.choiceSetSelectionListener = choiceSetSelectionListener;
+ this.sdlMsgVersion = internalInterface.getSdlMsgVersion();
}
@Override
public void run() {
+ PresentChoiceSetOperation.super.run();
DebugTool.logInfo("Choice Operation: Executing present choice set operation");
addListeners();
start();
+ block();
}
private void start(){
+ if (isCancelled()) {
+ finishOperation();
+ return;
+ }
+
// Check if we're using a keyboard (searchable) choice set and setup keyboard properties if we need to
if (keyboardListener != null && choiceSet.getCustomKeyboardConfiguration() != null){
keyboardProperties = choiceSet.getCustomKeyboardConfiguration();
@@ -101,6 +121,10 @@ class PresentChoiceSetOperation implements Runnable {
updateKeyboardProperties(new CompletionListener() {
@Override
public void onComplete(boolean success) {
+ if (isCancelled()) {
+ finishOperation();
+ return;
+ }
presentChoiceSet();
}
});
@@ -139,8 +163,10 @@ class PresentChoiceSetOperation implements Runnable {
@Override
public void onError(int correlationId, Result resultCode, String info) {
+ if (listener != null){
+ listener.onComplete(false);
+ }
DebugTool.logError("Error Setting keyboard properties in present keyboard operation - choice manager - " + info);
- super.onError(correlationId, resultCode, info);
}
});
if (internalInterface.get() != null){
@@ -174,6 +200,16 @@ class PresentChoiceSetOperation implements Runnable {
finishOperation();
}
+
+ @Override
+ public void onError(int correlationId, Result resultCode, String info) {
+ DebugTool.logError("Presenting Choice set failed: " + resultCode + ", " + info);
+
+ if (choiceSetSelectionListener != null){
+ choiceSetSelectionListener.onError(resultCode + ", " + info);
+ }
+ finishOperation();
+ }
});
if (internalInterface.get() != null){
internalInterface.get().sendRPC(pi);
@@ -182,8 +218,7 @@ class PresentChoiceSetOperation implements Runnable {
}
}
- private void finishOperation() {
-
+ void finishOperation() {
if (updatedKeyboardProperties) {
// We need to reset the keyboard properties
SetGlobalProperties setGlobalProperties = new SetGlobalProperties();
@@ -193,6 +228,13 @@ class PresentChoiceSetOperation implements Runnable {
public void onResponse(int correlationId, RPCResponse response) {
updatedKeyboardProperties = false;
DebugTool.logInfo("Successfully reset choice keyboard properties to original config");
+ PresentChoiceSetOperation.super.finishOperation();
+ }
+
+ @Override
+ public void onError(int correlationId, Result resultCode, String info) {
+ DebugTool.logError("Failed to reset choice keyboard properties to original config " + resultCode + ", " + info);
+ PresentChoiceSetOperation.super.finishOperation();
}
});
@@ -202,13 +244,56 @@ class PresentChoiceSetOperation implements Runnable {
} else {
DebugTool.logError("Internal Interface null when finishing choice keyboard reset");
}
+ } else {
+ PresentChoiceSetOperation.super.finishOperation();
+ }
+ }
+
+ /*
+ * Cancels the choice set. If the choice set has not yet been sent to Core, it will not be sent. If the choice set is already presented on Core, the choice set will be dismissed using the `CancelInteraction` RPC.
+ */
+ private void cancelInteraction() {
+ if (isFinished()) {
+ DebugTool.logInfo("This operation has already finished so it can not be canceled.");
+ return;
+ } else if (isCancelled()) {
+ DebugTool.logInfo("This operation has already been canceled. It will be finished at some point during the operation.");
+ return;
+ } else if (isExecuting()) {
+ if (sdlMsgVersion.getMajorVersion() < 6){
+ DebugTool.logWarning("Canceling a presented choice set is not supported on this head unit");
+ return;
+ }
+
+ DebugTool.logInfo("Canceling the presented choice set interaction.");
+
+ CancelInteraction cancelInteraction = new CancelInteraction(FunctionID.PERFORM_INTERACTION.getId(), cancelID);
+ cancelInteraction.setOnRPCResponseListener(new OnRPCResponseListener() {
+ @Override
+ public void onResponse(int correlationId, RPCResponse response) {
+ DebugTool.logInfo("Canceled the presented choice set " + ((response.getResultCode() == Result.SUCCESS) ? "successfully" : "unsuccessfully"));
+ }
+
+ @Override
+ public void onError(int correlationId, Result resultCode, String info){
+ DebugTool.logError("Error canceling the presented choice set " + resultCode + " " + info);
+ };
+ });
+
+ if (internalInterface.get() != null){
+ internalInterface.get().sendRPC(cancelInteraction);
+ } else {
+ DebugTool.logError("Internal interface null - could not send cancel interaction for choice set");
+ }
+ } else {
+ DebugTool.logInfo("Canceling a choice set that has not yet been sent to Core");
+ this.cancel();
}
}
// GETTERS
PerformInteraction getPerformInteraction() {
-
PerformInteraction pi = new PerformInteraction(choiceSet.getTitle(), presentationMode, getChoiceIds());
pi.setInitialPrompt(choiceSet.getInitialPrompt());
pi.setHelpPrompt(choiceSet.getHelpPrompt());
@@ -216,6 +301,7 @@ class PresentChoiceSetOperation implements Runnable {
pi.setVrHelp(choiceSet.getVrHelpList());
pi.setTimeout(choiceSet.getTimeout() * 1000);
pi.setInteractionLayout(getLayoutMode());
+ pi.setCancelID(cancelID);
return pi;
}
@@ -260,6 +346,10 @@ class PresentChoiceSetOperation implements Runnable {
keyboardRPCListener = new OnRPCNotificationListener() {
@Override
public void onNotified(RPCNotification notification) {
+ if (isCancelled()) {
+ finishOperation();
+ return;
+ }
if (keyboardListener == null){
DebugTool.logError("Received Keyboard Input But Listener is null");
diff --git a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PresentKeyboardOperation.java b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PresentKeyboardOperation.java
index 06d86edd5..5089d0c92 100644
--- a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PresentKeyboardOperation.java
+++ b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PresentKeyboardOperation.java
@@ -40,9 +40,11 @@ import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCNotification;
import com.smartdevicelink.proxy.RPCResponse;
import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.rpc.CancelInteraction;
import com.smartdevicelink.proxy.rpc.KeyboardProperties;
import com.smartdevicelink.proxy.rpc.OnKeyboardInput;
import com.smartdevicelink.proxy.rpc.PerformInteraction;
+import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
import com.smartdevicelink.proxy.rpc.SetGlobalProperties;
import com.smartdevicelink.proxy.rpc.enums.InteractionMode;
import com.smartdevicelink.proxy.rpc.enums.KeyboardEvent;
@@ -57,7 +59,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-class PresentKeyboardOperation implements Runnable {
+class PresentKeyboardOperation extends AsynchronousOperation {
private WeakReference<ISdl> internalInterface;
private KeyboardListener keyboardListener;
@@ -65,24 +67,38 @@ class PresentKeyboardOperation implements Runnable {
private boolean updatedKeyboardProperties;
private String initialText;
private OnRPCNotificationListener keyboardRPCListener;
+ private Integer cancelID;
+ SdlMsgVersion sdlMsgVersion;
- PresentKeyboardOperation(ISdl internalInterface, KeyboardProperties originalKeyboardProperties, String initialText, KeyboardProperties customConfig, KeyboardListener keyboardListener){
+ PresentKeyboardOperation(ISdl internalInterface, KeyboardProperties originalKeyboardProperties, String initialText, KeyboardProperties customConfig, KeyboardListener keyboardListener, Integer cancelID){
+ super();
this.internalInterface = new WeakReference<>(internalInterface);
this.keyboardListener = keyboardListener;
this.originalKeyboardProperties = originalKeyboardProperties;
this.keyboardProperties = originalKeyboardProperties;
this.customConfig = customConfig;
this.initialText = initialText;
+ this.cancelID = cancelID;
+ this.sdlMsgVersion = internalInterface.getSdlMsgVersion();
}
@Override
public void run() {
+ PresentKeyboardOperation.super.run();
+ DebugTool.logInfo("Keyboard Operation: Executing present keyboard operation");
addListeners();
start();
+ block();
}
private void start(){
DebugTool.logInfo("Choice Operation: Executing present keyboard operation");
+
+ if (isCancelled()) {
+ finishOperation();
+ return;
+ }
+
if (keyboardListener != null){
keyboardProperties = customConfig;
updatedKeyboardProperties = true;
@@ -91,6 +107,11 @@ class PresentKeyboardOperation implements Runnable {
updateKeyboardProperties(new CompletionListener() {
@Override
public void onComplete(boolean success) {
+ if (isCancelled()) {
+ finishOperation();
+ return;
+ }
+
presentKeyboard();
}
});
@@ -99,9 +120,7 @@ class PresentKeyboardOperation implements Runnable {
// SENDING REQUESTS
private void presentKeyboard(){
-
if (internalInterface.get() != null){
-
PerformInteraction pi = getPerformInteraction();
pi.setOnRPCResponseListener(new OnRPCResponseListener() {
@Override
@@ -121,11 +140,52 @@ class PresentKeyboardOperation implements Runnable {
}else{
DebugTool.logError("Internal Interface null in present keyboard operation - choice");
}
+ }
+ /**
+ * Cancels the keyboard-only interface if it is currently showing. If the keyboard has not yet been sent to Core, it will not be sent.
+ *
+ * This will only dismiss an already presented keyboard if connected to head units running SDL 6.0+.
+ */
+ void dismissKeyboard() {
+ if (isFinished()) {
+ DebugTool.logInfo("This operation has already finished so it can not be canceled.");
+ return;
+ } else if (isCancelled()) {
+ DebugTool.logInfo("This operation has already been canceled. It will be finished at some point during the operation.");
+ return;
+ } else if (isExecuting()) {
+ if (sdlMsgVersion.getMajorVersion() < 6){
+ DebugTool.logWarning("Canceling a keyboard is not supported on this head unit");
+ return;
+ }
+
+ DebugTool.logInfo("Canceling the presented keyboard.");
+
+ CancelInteraction cancelInteraction = new CancelInteraction(FunctionID.PERFORM_INTERACTION.getId(), cancelID);
+ cancelInteraction.setOnRPCResponseListener(new OnRPCResponseListener() {
+ @Override
+ public void onResponse(int correlationId, RPCResponse response) {
+ DebugTool.logInfo("Canceled the presented keyboard " + ((response.getResultCode() == Result.SUCCESS) ? "successfully" : "unsuccessfully"));
+ }
+
+ @Override
+ public void onError(int correlationId, Result resultCode, String info){
+ DebugTool.logError("Error canceling the presented keyboard " + resultCode + " " + info);
+ }
+ });
+ if (internalInterface.get() != null){
+ internalInterface.get().sendRPC(cancelInteraction);
+ } else {
+ DebugTool.logError("Internal interface null - could not send cancel interaction for keyboard.");
+ }
+ } else {
+ DebugTool.logInfo("Canceling a keyboard that has not yet been sent to Core.");
+ this.cancel();
+ }
}
private void updateKeyboardProperties(final CompletionListener listener){
-
if (keyboardProperties == null){
if (listener != null){
listener.onComplete(false);
@@ -157,6 +217,9 @@ class PresentKeyboardOperation implements Runnable {
@Override
public void onError(int correlationId, Result resultCode, String info) {
+ if (listener != null){
+ listener.onComplete(false);
+ }
DebugTool.logError("Error Setting keyboard properties in present keyboard operation - choice manager - " + info);
super.onError(correlationId, resultCode, info);
}
@@ -169,8 +232,7 @@ class PresentKeyboardOperation implements Runnable {
}
}
- private void finishOperation() {
-
+ void finishOperation() {
if (updatedKeyboardProperties) {
// We need to reset the keyboard properties
SetGlobalProperties setGlobalProperties = new SetGlobalProperties();
@@ -180,6 +242,13 @@ class PresentKeyboardOperation implements Runnable {
public void onResponse(int correlationId, RPCResponse response) {
updatedKeyboardProperties = false;
DebugTool.logInfo("Successfully reset choice keyboard properties to original config");
+ PresentKeyboardOperation.super.finishOperation();
+ }
+
+ @Override
+ public void onError(int correlationId, Result resultCode, String info) {
+ DebugTool.logError("Failed to reset choice keyboard properties to original config " + resultCode + ", " + info);
+ PresentKeyboardOperation.super.finishOperation();
}
});
@@ -189,6 +258,8 @@ class PresentKeyboardOperation implements Runnable {
} else {
DebugTool.logError("Internal Interface null when finishing choice keyboard reset");
}
+ } else {
+ PresentKeyboardOperation.super.finishOperation();
}
}
@@ -200,9 +271,14 @@ class PresentKeyboardOperation implements Runnable {
pi.setInteractionMode(InteractionMode.MANUAL_ONLY);
pi.setInteractionChoiceSetIDList(Collections.<Integer>emptyList());
pi.setInteractionLayout(LayoutMode.KEYBOARD);
+ pi.setCancelID(cancelID);
return pi;
}
+ public Integer getCancelID() {
+ return cancelID;
+ }
+
// LISTENERS
private void addListeners(){
@@ -210,6 +286,10 @@ class PresentKeyboardOperation implements Runnable {
keyboardRPCListener = new OnRPCNotificationListener() {
@Override
public void onNotified(RPCNotification notification) {
+ if (isCancelled()) {
+ finishOperation();
+ return;
+ }
if (keyboardListener == null){
DebugTool.logError("Received Keyboard Input But Listener is null");
diff --git a/base/src/main/java/com/smartdevicelink/protocol/enums/FunctionID.java b/base/src/main/java/com/smartdevicelink/protocol/enums/FunctionID.java
index a7c722ee2..964000dad 100644
--- a/base/src/main/java/com/smartdevicelink/protocol/enums/FunctionID.java
+++ b/base/src/main/java/com/smartdevicelink/protocol/enums/FunctionID.java
@@ -101,6 +101,7 @@ public enum FunctionID{
GET_FILE(54, "GetFile"),
PERFORM_APP_SERVICES_INTERACTION(55, "PerformAppServiceInteraction"),
UNPUBLISH_APP_SERVICE(56, "UnpublishAppService"),
+ CANCEL_INTERACTION(57, "CancelInteraction"),
CLOSE_APPLICATION(58, "CloseApplication"),
SHOW_APP_MENU(59, "ShowAppMenu"),
CREATE_WINDOW(60, "CreateWindow"),
diff --git a/base/src/main/java/com/smartdevicelink/proxy/interfaces/IProxyListenerBase.java b/base/src/main/java/com/smartdevicelink/proxy/interfaces/IProxyListenerBase.java
index dfa18ff52..988325bd9 100644
--- a/base/src/main/java/com/smartdevicelink/proxy/interfaces/IProxyListenerBase.java
+++ b/base/src/main/java/com/smartdevicelink/proxy/interfaces/IProxyListenerBase.java
@@ -38,6 +38,7 @@ import com.smartdevicelink.proxy.rpc.AddSubMenuResponse;
import com.smartdevicelink.proxy.rpc.AlertManeuverResponse;
import com.smartdevicelink.proxy.rpc.AlertResponse;
import com.smartdevicelink.proxy.rpc.ButtonPressResponse;
+import com.smartdevicelink.proxy.rpc.CancelInteractionResponse;
import com.smartdevicelink.proxy.rpc.ChangeRegistrationResponse;
import com.smartdevicelink.proxy.rpc.CloseApplicationResponse;
import com.smartdevicelink.proxy.rpc.CreateInteractionChoiceSetResponse;
@@ -437,6 +438,14 @@ public interface IProxyListenerBase {
*/
public void onCloseApplicationResponse(CloseApplicationResponse response);
+ /**
+ * onCancelInteractionResponse being called indicates that SDL has
+ * responded to a request to dismiss a modal view on the module.
+ *
+ * @param response - Contains information about the response sent from SDL.
+ */
+ public void onCancelInteractionResponse(CancelInteractionResponse response);
+
/**
* UnpublishAppServiceResponse being called indicates that SDL has
* responded to a request to close the application on the module.
diff --git a/base/src/main/java/com/smartdevicelink/proxy/rpc/Alert.java b/base/src/main/java/com/smartdevicelink/proxy/rpc/Alert.java
index 8802e8d95..a67484131 100644
--- a/base/src/main/java/com/smartdevicelink/proxy/rpc/Alert.java
+++ b/base/src/main/java/com/smartdevicelink/proxy/rpc/Alert.java
@@ -39,7 +39,9 @@ import java.util.List;
/**
* Provides information to the user using either TTS, the Display or both and
- * can include a system-generated alert tone
+ * can include a system-generated alert tone.
+ *
+ * If connecting to SDL Core v.6.0+, the alert can be canceled programmatically using the `cancelID`. Canceling will not dismiss the alert's speech - only the modal view will be dismissed. On older versions of SDL Core, the alert will persist until the user has interacted with the alert or the specified timeout has elapsed.
*
* <ul>
* <li>The displayed portion of the Alert, if any, will persist until the
@@ -68,7 +70,7 @@ import java.util.List;
* <th>Name</th>
* <th>Type</th>
* <th>Description</th>
- * <th> Req.</th>
+ * <th>Req.</th>
* <th>Notes</th>
* <th>Version Available</th>
* </tr>
@@ -76,23 +78,23 @@ import java.util.List;
* <td>alertText1</td>
* <td>String</td>
* <td>Text to be displayed in the first field of the display during the Alert. </td>
- * <td>N</td>
- * <td> Length is limited to what is indicated in RegisterAppInterface response. If omitted, top display line will be cleared. Text is always centered</td>
+ * <td>N</td>
+ * <td>Length is limited to what is indicated in RegisterAppInterface response. If omitted, top display line will be cleared. Text is always centered</td>
* <td>SmartDeviceLink 1.0</td>
* </tr>
* <tr>
* <td>alertText2</td>
* <td>String</td>
* <td>Text to be displayed in the second field of the display during the Alert. </td>
- * <td>N</td>
- * <td> Only permitted if HMI supports a second display line. Length is limited to what is indicated in RegisterAppInterface response. If omitted, second display line will be cleared. </td>
+ * <td>N</td>
+ * <td>Only permitted if HMI supports a second display line. Length is limited to what is indicated in RegisterAppInterface response. If omitted, second display line will be cleared. </td>
* <td>SmartDeviceLink 1.0</td>
* </tr>
* <tr>
* <td>alertText3</td>
* <td>String</td>
* <td>Text to be displayed in the third field of the display during the Alert.</td>
- * <td>N</td>
+ * <td>N</td>
* <td>Array must have a least one element. </td>
* <td>SmartDeviceLink 1.0</td>
* </tr>
@@ -100,23 +102,23 @@ import java.util.List;
* <td>ttsChunks</td>
* <td>TTSChunk[]</td>
* <td>Array of type TTSChunk which, taken together, specify what is to be spoken to the user.</td>
- * <td>N</td>
+ * <td>N</td>
* <td>Array must have a least one element. </td>
* <td>SmartDeviceLink 1.0</td>
* </tr>
* <tr>
* <td>duration</td>
* <td>Integer</td>
- * <td><p>The duration of the displayed portion of the alert, in milliseconds.</p> After this amount of time has passed, the display fields alertText1 and alertText2 will revert to what was displayed in those fields before the alert began.</td>
- * <td>N</td>
- * <td>Min Value: 3000 Max Value: 10000 <p>If omitted, the default is 5000 milliseconds</p></td>
+ * <td>The duration of the displayed portion of the alert, in milliseconds. After this amount of time has passed, the display fields alertText1 and alertText2 will revert to what was displayed in those fields before the alert began.</td>
+ * <td>N</td>
+ * <td>Min Value: 3000 Max Value: 10000. If omitted, the default is 5000 milliseconds</td>
* <td>SmartDeviceLink 1.0</td>
* </tr>
* <tr>
* <td>playTone</td>
* <td>Boolean</td>
* <td>Specifies whether the alert tone should be played before the TTS (if any) is spoken.</td>
- * <td>N</td>
+ * <td>N</td>
* <td>If omitted, default is true.</td>
* <td>SmartDeviceLink 1.0</td>
* </tr>
@@ -124,7 +126,7 @@ import java.util.List;
* <td>softButtons</td>
* <td>SoftButton[]</td>
* <td>Specifies the softbuttons, the apps wants to use in this alert.</td>
- * <td></td>
+ * <td>N</td>
* <td>If omitted on supported displays, the alert will not have any SoftButton.ArrayMin: 0; ArrayMax: 4</td>
* <td>SmartDeviceLink 1.0</td>
* </tr>
@@ -132,15 +134,23 @@ import java.util.List;
* <td>progressIndicator</td>
* <td>Boolean</td>
* <td>If supported on the given platform, the alert GUI will include some sort of animation indicating that loading of a feature is progressing. e.g. a spinning wheel or hourglass, etc.</td>
- * <td>N</td>
+ * <td>N</td>
* <td></td>
* <td>SmartDeviceLink 1.0</td>
* </tr>
* <tr>
+ * <td>cancelID</td>
+ * <td>Integer</td>
+ * <td>An ID for this specific alert to allow cancellation through the `CancelInteraction` RPC.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>SmartDeviceLink 6.0</td>
+ * </tr>
+ * <tr>
* <td>alertIcon</td>
* <td>Image</td>
* <td>Image struct determining whether the icon is static or dynamic. If omitted on supported displays, no (or the default if applicable) icon should be displayed.</td>
- * <td>N</td>
+ * <td>N</td>
* <td></td>
* <td>SmartDeviceLink 6.0.0</td>
* </tr>
@@ -162,6 +172,7 @@ public class Alert extends RPCRequest {
public static final String KEY_PROGRESS_INDICATOR = "progressIndicator";
public static final String KEY_TTS_CHUNKS = "ttsChunks";
public static final String KEY_SOFT_BUTTONS = "softButtons";
+ public static final String KEY_CANCEL_ID = "cancelID";
public static final String KEY_ALERT_ICON = "alertIcon";
/**
@@ -373,18 +384,55 @@ public class Alert extends RPCRequest {
* </ul>
* @since SmartDeviceLink 2.0
*/
-
public void setSoftButtons(List<SoftButton> softButtons) {
setParameters(KEY_SOFT_BUTTONS, softButtons);
}
- public Boolean getProgressIndicator() {
- return getBoolean(KEY_PROGRESS_INDICATOR);
+
+ /**
+ * Gets a Boolean value representing the progress indicator
+ *
+ * @return Boolean - If TRUE, the alert GUI will include some sort of animation indicating that loading of a feature is progressing. e.g. a spinning wheel or hourglass, etc.
+ *
+ * @since SmartDeviceLink 3.0
+ */
+ public Boolean getProgressIndicator() {
+ return getBoolean(KEY_PROGRESS_INDICATOR);
}
- public void setProgressIndicator(Boolean progressIndicator) {
+
+ /**
+ * Sets whether the progress indicator should be shown
+ *
+ * @param progressIndicator A Boolean value which specifies whether the alert GUI will include some sort of animation indicating that loading of a feature is progressing. e.g. a spinning wheel or hourglass, etc.
+ *
+ * @since SmartDeviceLink 3.0
+ */
+ public void setProgressIndicator(Boolean progressIndicator) {
setParameters(KEY_PROGRESS_INDICATOR, progressIndicator);
}
/**
+ * Gets an Integer value representing the cancel ID
+ *
+ * @return Integer - An Integer value representing the ID for this specific alert to allow cancellation through the `CancelInteraction` RPC.
+ *
+ * @since SmartDeviceLink 6.0
+ */
+ public Integer getCancelID() {
+ return getInteger(KEY_CANCEL_ID);
+ }
+
+ /**
+ * Sets the cancel ID
+ *
+ * @param cancelID An Integer ID for this specific alert to allow cancellation through the `CancelInteraction` RPC.
+ *
+ * @since SmartDeviceLink 6.0
+ */
+ public void setCancelID(Integer cancelID) {
+ setParameters(KEY_CANCEL_ID, cancelID);
+ };
+
+ /**
* <p>Sets the Image
* If provided, defines the image to be shown along with the alert</p>
* @param alertIcon
diff --git a/base/src/main/java/com/smartdevicelink/proxy/rpc/CancelInteraction.java b/base/src/main/java/com/smartdevicelink/proxy/rpc/CancelInteraction.java
new file mode 100644
index 000000000..3fb02422c
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/proxy/rpc/CancelInteraction.java
@@ -0,0 +1,126 @@
+/*
+ * 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 Nicole Yarroch on 7/17/19 8:40 AM
+ */
+
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCRequest;
+
+import java.util.Hashtable;
+
+/*
+ * Used to dismiss a modal view programmatically without needing to wait for the timeout to complete. Can be used to dismiss alerts, scrollable messages, sliders, and perform interactions (i.e. pop-up menus).
+ *
+ * @see Alert, ScrollableMessage, Slider, PerformInteraction
+ */
+public class CancelInteraction extends RPCRequest {
+ public static final String KEY_CANCEL_ID = "cancelID";
+ public static final String KEY_FUNCTION_ID = "functionID";
+
+ // Constructors
+
+ /**
+ * Constructs a new CancelInteraction object
+ */
+ public CancelInteraction() {
+ super(FunctionID.CANCEL_INTERACTION.toString());
+ }
+
+ /**
+ * Constructs a new CancelInteraction object indicated by the Hashtable parameter
+ *
+ * @param hash The Hashtable to use
+ */
+ public CancelInteraction(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Convenience init for dismissing an interaction type.
+ * @param functionID - The ID of the type of interaction to dismiss
+ */
+ public CancelInteraction(@NonNull Integer functionID) {
+ this();
+ setInteractionFunctionID(functionID);
+ }
+
+ /**
+ * Convenience init for dismissing a specific interaction.
+ * @param functionID - The ID of the type of interaction to dismiss
+ * @param cancelID - The ID of the specific interaction to dismiss
+ */
+ public CancelInteraction(@NonNull Integer functionID, Integer cancelID) {
+ this();
+ setInteractionFunctionID(functionID);
+ setCancelID(cancelID);
+ }
+
+ // Custom Getters / Setters
+
+ /**
+ * The ID of the type of interaction to dismiss.
+ * Only values 10 (PerformInteractionID), 12 (AlertID), 25 (ScrollableMessageID), and 26 (SliderID) are permitted.
+ * @return - the functionID
+ */
+ public Integer getInteractionFunctionID() {
+ return getInteger(KEY_FUNCTION_ID);
+ }
+
+ /**
+ * The ID of the type of interaction to dismiss.
+ * Only values 10 (PerformInteractionID), 12 (AlertID), 25 (ScrollableMessageID), and 26 (SliderID) are permitted.
+ * @param functionID - the functionID
+ */
+ public void setInteractionFunctionID(@NonNull Integer functionID) {
+ setParameters(KEY_FUNCTION_ID, functionID);
+ }
+
+ /**
+ * The ID of the specific interaction to dismiss. If not set, the most recent of the RPC type set in functionID will be dismissed.
+ * @return - the cancelID
+ */
+ public Integer getCancelID() {
+ return getInteger(KEY_CANCEL_ID);
+ }
+
+ /**
+ * The ID of the specific interaction to dismiss. If not set, the most recent of the RPC type set in functionID will be dismissed.
+ * @param cancelID - the cancelID
+ */
+ public void setCancelID(Integer cancelID) {
+ setParameters(KEY_CANCEL_ID, cancelID);
+ }
+} \ No newline at end of file
diff --git a/base/src/main/java/com/smartdevicelink/proxy/rpc/CancelInteractionResponse.java b/base/src/main/java/com/smartdevicelink/proxy/rpc/CancelInteractionResponse.java
new file mode 100644
index 000000000..defab83c9
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/proxy/rpc/CancelInteractionResponse.java
@@ -0,0 +1,73 @@
+/*
+ * 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 Nicole Yarroch on 7/24/19 9:29 AM
+ */
+
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCResponse;
+import com.smartdevicelink.proxy.rpc.enums.Result;
+
+import java.util.Hashtable;
+
+/**
+ * Response to the request to dismiss a modal view. If no applicable request can be dismissed, the `resultCode` will be `IGNORED`.
+ */
+public class CancelInteractionResponse extends RPCResponse {
+ /**
+ * Constructs a new CancelInteractionResponse object
+ */
+ public CancelInteractionResponse() { super(FunctionID.CANCEL_INTERACTION.toString()); }
+
+ /**
+ * Constructs a new CancelInteractionResponse object indicated by the Hashtable parameter
+ *
+ * @param hash The Hashtable to use
+ */
+ public CancelInteractionResponse(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Constructs a new CancelInteractionResponse object
+ * @param success whether the request is successfully processed
+ * @param resultCode whether the request is successfully processed
+ */
+ public CancelInteractionResponse(@NonNull Boolean success, @NonNull Result resultCode) {
+ this();
+ setSuccess(success);
+ setResultCode(resultCode);
+ }
+}
diff --git a/base/src/main/java/com/smartdevicelink/proxy/rpc/PerformInteraction.java b/base/src/main/java/com/smartdevicelink/proxy/rpc/PerformInteraction.java
index 12be13e9f..5e253e540 100644
--- a/base/src/main/java/com/smartdevicelink/proxy/rpc/PerformInteraction.java
+++ b/base/src/main/java/com/smartdevicelink/proxy/rpc/PerformInteraction.java
@@ -1,34 +1,34 @@
-/*
- * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, 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 SmartDeviceLink Consortium, 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.
- */
+/*
+ * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, 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 SmartDeviceLink Consortium, 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.proxy.rpc;
import android.support.annotation.NonNull;
@@ -47,7 +47,9 @@ import java.util.List;
* application may use a PerformInteraction to ask a user to say the name of a
* song to play. The user's response is only valid if it appears in the
* specified Choice Sets and is recognized by SDL
- * <p></p>
+ *
+ * If connecting to SDL Core v.6.0+, the perform interaction can be canceled programmatically using the `cancelID`. On older versions of SDL Core, the perform interaction will persist until the user has interacted with the perform interaction or the specified timeout has elapsed.
+ *
* <p>Function Group: Base</p>
*
* <p><b>HMILevel needs to be FULL</b></p>
@@ -134,6 +136,14 @@ import java.util.List;
* <td></td>
* <td>SmartDeviceLink 3.0</td>
* </tr>
+ * <tr>
+ * <td>cancelID</td>
+ * <td>Integer</td>
+ * <td>An ID for this specific perform interaction to allow cancellation through the `CancelInteraction` RPC.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>SmartDeviceLink 6.0</td>
+ * </tr>
* </table>
*
*
@@ -151,6 +161,8 @@ public class PerformInteraction extends RPCRequest {
public static final String KEY_TIMEOUT_PROMPT = "timeoutPrompt";
public static final String KEY_TIMEOUT = "timeout";
public static final String KEY_VR_HELP = "vrHelp";
+ public static final String KEY_CANCEL_ID = "cancelID";
+
/**
* Constructs a new PerformInteraction object
*/
@@ -168,10 +180,10 @@ public class PerformInteraction extends RPCRequest {
}
/**
* Constructs a new PerformInteraction object
- * @param initialText a String value that Displayed when the interaction begins
+ * @param initialText a String value that is displayed when the interaction begins
* @param interactionMode indicate how user selects interaction choice (VR_ONLY, MANUAL_ONLY or BOTH)
* @param interactionChoiceSetIDList a List<Integer> representing an Array of one or more Choice Set IDs. User can select any choice from any of the specified
- * Choice Sets <b>Notes: </b>Min Value: 0; Max Vlaue: 2000000000
+ * Choice Sets <b>Notes: </b>Min Value: 0; Max Value: 2000000000
*/
public PerformInteraction(@NonNull String initialText, @NonNull InteractionMode interactionMode, @NonNull List<Integer> interactionChoiceSetIDList) {
this();
@@ -361,8 +373,7 @@ public class PerformInteraction extends RPCRequest {
}
/**
- * Gets a Voice recognition Help, which is a suggested VR Help Items to
- * display on-screen during Perform Interaction
+ * Gets a Voice Recognition Help list, which is a list of suggested VR Help Items to display on-screen during a Perform Interaction
*
* @return List<VrHelpItem> -a List value representing a suggested VR
* Help Items to display on-screen during Perform Interaction
@@ -374,7 +385,8 @@ public class PerformInteraction extends RPCRequest {
}
/**
- *
+ * Sets a Voice Recognition Help list, which is a list of suggested VR Help Items to display on-screen during a Perform Interaction
+ *
* @param vrHelp
* a List representing a suggested VR Help Items to display
* on-screen during Perform Interaction
@@ -387,12 +399,48 @@ public class PerformInteraction extends RPCRequest {
public void setVrHelp(List<VrHelpItem> vrHelp) {
setParameters(KEY_VR_HELP, vrHelp);
}
-
- public LayoutMode getInteractionLayout() {
+
+ /**
+ * Gets the layout mode of how the choices are presented. For touchscreen interactions only.
+ *
+ * @return LayoutMode - The interaction layout mode
+ *
+ * @since SmartDeviceLink 3.0
+ */
+ public LayoutMode getInteractionLayout() {
return (LayoutMode) getObject(LayoutMode.class, KEY_INTERACTION_LAYOUT);
}
-
- public void setInteractionLayout( LayoutMode interactionLayout ) {
+
+ /**
+ * Sets the mode of how the choices are presented. For touchscreen interactions only.
+ *
+ * @param interactionLayout A LayoutMode representing the interaction layout mode
+ *
+ * @since SmartDeviceLink 3.0
+ */
+ public void setInteractionLayout(LayoutMode interactionLayout ) {
setParameters(KEY_INTERACTION_LAYOUT, interactionLayout);
- }
+ }
+
+ /**
+ * Gets an Integer value representing the cancel ID
+ *
+ * @return Integer - An Integer value representing the ID for this specific perform interaction to allow cancellation through the `CancelInteraction` RPC.
+ *
+ * @since SmartDeviceLink 6.0
+ */
+ public Integer getCancelID() {
+ return getInteger(KEY_CANCEL_ID);
+ }
+
+ /**
+ * Sets the cancel ID
+ *
+ * @param cancelID An Integer ID for this specific perform interaction to allow cancellation through the `CancelInteraction` RPC.
+ *
+ * @since SmartDeviceLink 6.0
+ */
+ public void setCancelID(Integer cancelID) {
+ setParameters(KEY_CANCEL_ID, cancelID);
+ }
}
diff --git a/base/src/main/java/com/smartdevicelink/proxy/rpc/ScrollableMessage.java b/base/src/main/java/com/smartdevicelink/proxy/rpc/ScrollableMessage.java
index b4e212fcc..a3bb9a567 100644
--- a/base/src/main/java/com/smartdevicelink/proxy/rpc/ScrollableMessage.java
+++ b/base/src/main/java/com/smartdevicelink/proxy/rpc/ScrollableMessage.java
@@ -1,34 +1,34 @@
-/*
- * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, 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 SmartDeviceLink Consortium, 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.
- */
+/*
+ * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, 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 SmartDeviceLink Consortium, 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.proxy.rpc;
import android.support.annotation.NonNull;
@@ -42,6 +42,8 @@ import java.util.List;
/**
* Creates a full screen overlay containing a large block of formatted text that
* can be scrolled with up to 8 SoftButtons defined
+ *
+ * If connecting to SDL Core v.6.0+, the scrollable message can be canceled programmatically using the `cancelID`. On older versions of SDL Core, the scrollable message will persist until the user has interacted with the scrollable message or the specified timeout has elapsed.
*
* <p>Function Group: ScrollableMessage</p>
*
@@ -81,6 +83,14 @@ import java.util.List;
* <td>minsize=0; maxsize=8</td>
* <td>SmartDevice Link 1.0 </td>
* </tr>
+ * <tr>
+ * <td>cancelID</td>
+ * <td>Integer</td>
+ * <td>An ID for this specific ScrollableMessage to allow cancellation through the `CancelInteraction` RPC.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>SmartDeviceLink 6.0</td>
+ * </tr>
* </table>
* <p> <b>Response</b></p>
*<b>Non-default Result Codes:</b>
@@ -102,6 +112,7 @@ public class ScrollableMessage extends RPCRequest {
public static final String KEY_SCROLLABLE_MESSAGE_BODY = "scrollableMessageBody";
public static final String KEY_TIMEOUT = "timeout";
public static final String KEY_SOFT_BUTTONS = "softButtons";
+ public static final String KEY_CANCEL_ID = "cancelID";
/**
* Constructs a new ScrollableMessage object
@@ -197,4 +208,26 @@ public class ScrollableMessage extends RPCRequest {
public List<SoftButton> getSoftButtons() {
return (List<SoftButton>) getObject(SoftButton.class, KEY_SOFT_BUTTONS);
}
+
+ /**
+ * Gets an Integer value representing the cancel ID
+ *
+ * @return Integer - An Integer value representing the ID for this specific scrollable message to allow cancellation through the `CancelInteraction` RPC.
+ *
+ * @since SmartDeviceLink 6.0
+ */
+ public Integer getCancelID() {
+ return getInteger(KEY_CANCEL_ID);
+ }
+
+ /**
+ * Sets the cancel ID
+ *
+ * @param cancelID An Integer ID for this specific scrollable message to allow cancellation through the `CancelInteraction` RPC.
+ *
+ * @since SmartDeviceLink 6.0
+ */
+ public void setCancelID(Integer cancelID) {
+ setParameters(KEY_CANCEL_ID, cancelID);
+ }
}
diff --git a/base/src/main/java/com/smartdevicelink/proxy/rpc/Slider.java b/base/src/main/java/com/smartdevicelink/proxy/rpc/Slider.java
index 530352c6d..466879845 100644
--- a/base/src/main/java/com/smartdevicelink/proxy/rpc/Slider.java
+++ b/base/src/main/java/com/smartdevicelink/proxy/rpc/Slider.java
@@ -1,34 +1,34 @@
-/*
- * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, 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 SmartDeviceLink Consortium, 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.
- */
+/*
+ * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, 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 SmartDeviceLink Consortium, 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.proxy.rpc;
import android.support.annotation.NonNull;
@@ -40,8 +40,9 @@ import java.util.Hashtable;
import java.util.List;
/**
- * <p>Creates a full screen or pop-up overlay (depending on platform) with a single
- * user controlled slider.</p>
+ * Creates a full screen or pop-up overlay (depending on platform) with a single user controlled slider.
+ *
+ * If connecting to SDL Core v.6.0+, the slider can be canceled programmatically using the `cancelID`. On older versions of SDL Core, the slider will persist until the user has interacted with the slider or the specified timeout has elapsed.
*
* <p>Function Group: Base</p>
*
@@ -99,6 +100,14 @@ import java.util.List;
* <td>Minvalue=0; Maxvalue=65535; Defvalue= 10000</td>
* <td>SmartDeviceLink 2.0</td>
* </tr>
+ * <tr>
+ * <td>cancelID</td>
+ * <td>Integer</td>
+ * <td>An ID for this specific slider to allow cancellation through the `CancelInteraction` RPC.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>SmartDeviceLink 6.0</td>
+ * </tr>
* </table>
*<p><b>Response </b></p>
*
@@ -124,6 +133,8 @@ public class Slider extends RPCRequest {
public static final String KEY_SLIDER_FOOTER = "sliderFooter";
public static final String KEY_POSITION = "position";
public static final String KEY_TIMEOUT = "timeout";
+ public static final String KEY_CANCEL_ID = "cancelID";
+
/**
* Constructs a new Slider object
*/
@@ -263,4 +274,26 @@ public class Slider extends RPCRequest {
public Integer getTimeout() {
return getInteger(KEY_TIMEOUT);
}
+
+ /**
+ * Gets an Integer value representing the cancel ID
+ *
+ * @return Integer - An Integer value representing the ID for this specific slider to allow cancellation through the `CancelInteraction` RPC.
+ *
+ * @since SmartDeviceLink 6.0
+ */
+ public Integer getCancelID() {
+ return getInteger(KEY_CANCEL_ID);
+ }
+
+ /**
+ * Sets the cancel ID
+ *
+ * @param cancelID An Integer ID for this specific slider to allow cancellation through the `CancelInteraction` RPC.
+ *
+ * @since SmartDeviceLink 6.0
+ */
+ public void setCancelID(Integer cancelID) {
+ setParameters(KEY_CANCEL_ID, cancelID);
+ }
}