diff options
author | Bilal Alsharifi <599206+bilal-alsharifi@users.noreply.github.com> | 2019-09-12 08:27:08 -0400 |
---|---|---|
committer | NicoleYarroch <nicole@livio.io> | 2019-09-12 08:27:08 -0400 |
commit | 70f343d0f237b2e4bb2164d1bc9d2171b2e45790 (patch) | |
tree | 0ed9cbf5e32bc8df02598041fedbb02b1af30d29 | |
parent | b7039e3c32488c67ad46e13bbf48137357f3e125 (diff) | |
download | sdl_android-70f343d0f237b2e4bb2164d1bc9d2171b2e45790.tar.gz |
Make ChoiceSetManager operations blocking (#1155)feature/cancel_interaction_RPC
* Add blocking operations support
* Update AsynchronousOperation.ToString()
* Handle some missing onError logic in operations
* Update cancel() and isCancelled() to use the current thread
* Avoid interrupting thread when canceling operations
* Clean up BaseChoiceSetManager
* fix NPE from pendingSet
* fix failing tests in ChoiceSetManagerTests
* Comment out cancel interaction tests temporarily
* Avoid using thread interruptions in AsynchronousOperation
* Update AsynchronousOperation.toString()
* Fixed print statement crashing if no operating thread
* Fixed present choice set cancel operation tests
* Fixed spacing issues
* Added additional assert + fixed doc grammar
* Fixed cancel keyboard operation tests
* Modified termination duration in test cases
10 files changed, 348 insertions, 140 deletions
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetManagerTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetManagerTests.java index 7c7874c30..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 @@ -104,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); @@ -246,7 +246,7 @@ public class ChoiceSetManagerTests extends AndroidTestCase2 { ChoiceSetManager newCSM = new ChoiceSetManager(internalInterface, fileManager); ChoiceSetManager partialMockCSM = spy(newCSM); - when(partialMockCSM.isReady()).thenReturn(true); + when(partialMockCSM.getState()).thenReturn(BaseSubManager.READY); Integer cancelId = partialMockCSM.presentKeyboard("initial text", mock(KeyboardProperties.class), mock(KeyboardListener.class)); assertNotNull(cancelId); @@ -258,7 +258,7 @@ public class ChoiceSetManagerTests extends AndroidTestCase2 { ChoiceSetManager newCSM = new ChoiceSetManager(internalInterface, fileManager); ChoiceSetManager partialMockCSM = spy(newCSM); - when(partialMockCSM.isReady()).thenReturn(false); + when(partialMockCSM.getState()).thenReturn(BaseSubManager.ERROR); Integer cancelId = partialMockCSM.presentKeyboard("initial text", mock(KeyboardProperties.class), mock(KeyboardListener.class)); assertNull(cancelId); 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 7bc2816e3..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 @@ -54,32 +54,42 @@ 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(); internalInterface = mock(ISdl.class); - KeyboardListener keyboardListener = mock(KeyboardListener.class); - ChoiceSetSelectionListener choiceSetSelectionListener = mock(ChoiceSetSelectionListener.class); + + keyboardListener = mock(KeyboardListener.class); + choiceSetSelectionListener = mock(ChoiceSetSelectionListener.class); ChoiceCell cell1 = new ChoiceCell("Cell1"); cell1.setChoiceId(0); choiceSet = new ChoiceSet("Test", Collections.singletonList(cell1), choiceSetSelectionListener); - presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, getKeyBoardProperties(), keyboardListener, choiceSetSelectionListener, Test.GENERAL_INTEGER); - presentChoiceSetOperation.sdlMsgVersion = new SdlMsgVersion(6, 0); + + executor = Executors.newCachedThreadPool(); } @Override @@ -87,14 +97,26 @@ 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()); @@ -106,22 +128,27 @@ public class PresentChoiceSetOperationTests extends AndroidTestCase2 { } 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(){ - presentChoiceSetOperation.run(); + 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) { @@ -140,15 +167,27 @@ public class PresentChoiceSetOperationTests extends AndroidTestCase2 { }; doAnswer(cancelInteractionAnswer).when(internalInterface).sendRPC(any(CancelInteraction.class)); - choiceSet.cancel(); + verify(internalInterface, times(1)).sendRPC(any(CancelInteraction.class)); + verify(internalInterface, times(1)).sendRPC(any(PerformInteraction.class)); - assertTrue(presentChoiceSetOperation.isExecuting()); + assertTrue(presentChoiceSetOperation.isExecuting()); assertFalse(presentChoiceSetOperation.isFinished()); + assertFalse(presentChoiceSetOperation.isCancelled()); } public void testCancelingChoiceSetUnsuccessfullyIfThreadIsRunning(){ - presentChoiceSetOperation.run(); + 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) { @@ -167,66 +206,100 @@ public class PresentChoiceSetOperationTests extends AndroidTestCase2 { }; doAnswer(cancelInteractionAnswer).when(internalInterface).sendRPC(any(CancelInteraction.class)); - choiceSet.cancel(); + 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(){ - presentChoiceSetOperation.run(); + when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0)); + presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, null, null, choiceSetSelectionListener, Test.GENERAL_INTEGER); presentChoiceSetOperation.finishOperation(); - choiceSet.cancel(); + 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(){ - choiceSet.cancel(); + when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0)); + presentChoiceSetOperation = new PresentChoiceSetOperation(internalInterface, choiceSet, InteractionMode.MANUAL_ONLY, null, null, choiceSetSelectionListener, Test.GENERAL_INTEGER); - verify(internalInterface, never()).sendRPC(any(CancelInteraction.class)); + assertFalse(presentChoiceSetOperation.isExecuting()); + assertFalse(presentChoiceSetOperation.isFinished()); + assertFalse(presentChoiceSetOperation.isCancelled()); - // Once the thread has started - presentChoiceSetOperation.run(); + choiceSet.cancel(); - // Make sure neither a `CancelInteraction` or `PerformInteraction` RPC is sent - verify(internalInterface, never()).sendRPC(any(CancelInteraction.class)); - verify(internalInterface, never()).sendRPC(any(PerformInteraction.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)); } public void testCancelingChoiceSetIfHeadUnitDoesNotSupportFeature(){ - // Only supported with RPC spec versions 6.0.0+ - presentChoiceSetOperation.sdlMsgVersion = new SdlMsgVersion(5, 3); - presentChoiceSetOperation.run(); + // 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(){ - // Only supported with RPC spec versions 6.0.0+ - presentChoiceSetOperation.sdlMsgVersion = new SdlMsgVersion(5, 3); + // 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 thread has started - presentChoiceSetOperation.run(); - - // Make sure neither a `CancelInteraction` or `PerformInteraction` RPC is sent - verify(internalInterface, never()).sendRPC(any(CancelInteraction.class)); - verify(internalInterface, never()).sendRPC(any(PerformInteraction.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 072fa3f43..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 @@ -53,25 +53,32 @@ 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(); internalInterface = mock(ISdl.class); - KeyboardListener keyboardListener = mock(KeyboardListener.class); - - presentKeyboardOperation = new PresentKeyboardOperation(internalInterface, getKeyBoardProperties(), "Test", null, keyboardListener, Test.GENERAL_INTEGER); + keyboardListener = mock(KeyboardListener.class); Answer<Void> setGlobalPropertiesAnswer = new Answer<Void>() { @Override @@ -88,7 +95,7 @@ public class PresentKeyboardOperationTests extends AndroidTestCase2 { }; doAnswer(setGlobalPropertiesAnswer).when(internalInterface).sendRPC(any(SetGlobalProperties.class)); - presentKeyboardOperation.sdlMsgVersion = new SdlMsgVersion(6,0); + executor = Executors.newCachedThreadPool(); } @Override @@ -96,7 +103,17 @@ 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()); @@ -106,17 +123,19 @@ public class PresentKeyboardOperationTests extends AndroidTestCase2 { 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(){ - presentKeyboardOperation.run(); + 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) { @@ -135,16 +154,24 @@ public class PresentKeyboardOperationTests extends AndroidTestCase2 { }; doAnswer(cancelInteractionAnswer).when(internalInterface).sendRPC(any(CancelInteraction.class)); - presentKeyboardOperation.dismissKeyboard(); + 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(){ - presentKeyboardOperation.run(); - - Answer<Void> cancelInteractionAnswer = new Answer<Void>() { + 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(); @@ -162,64 +189,100 @@ public class PresentKeyboardOperationTests extends AndroidTestCase2 { }; doAnswer(cancelInteractionAnswer).when(internalInterface).sendRPC(any(CancelInteraction.class)); - presentKeyboardOperation.dismissKeyboard(); + verify(internalInterface, times(1)).sendRPC(any(CancelInteraction.class)); + verify(internalInterface, times(1)).sendRPC(any(PerformInteraction.class)); - assertTrue(presentKeyboardOperation.isExecuting()); - assertFalse(presentKeyboardOperation.isFinished()); + assertTrue(presentKeyboardOperation.isExecuting()); + assertFalse(presentKeyboardOperation.isFinished()); + assertFalse(presentKeyboardOperation.isCancelled()); } public void testCancelingKeyboardIfThreadHasFinished(){ - presentKeyboardOperation.run(); + when(internalInterface.getSdlMsgVersion()).thenReturn(new SdlMsgVersion(6, 0)); + presentKeyboardOperation = new PresentKeyboardOperation(internalInterface, null, "Test", null, null, Test.GENERAL_INTEGER); presentKeyboardOperation.finishOperation(); - presentKeyboardOperation.dismissKeyboard(); + 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(); - // Make sure neither a `CancelInteraction` or `PerformInteraction` RPC is sent - verify(internalInterface, never()).sendRPC(any(CancelInteraction.class)); - verify(internalInterface, never()).sendRPC(any(PerformInteraction.class)); + // Once the operation has started + executor.execute(presentKeyboardOperation); + try { + executor.awaitTermination(1, TimeUnit.SECONDS); + } catch (InterruptedException e) {} assertFalse(presentKeyboardOperation.isExecuting()); - assertFalse(presentKeyboardOperation.isFinished()); + 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(){ - // Only supported with RPC spec versions 6.0.0+ - presentKeyboardOperation.sdlMsgVersion = new SdlMsgVersion(5, 3); - presentKeyboardOperation.run(); + // 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(){ - // Only supported with RPC spec versions 6.0.0+ - presentKeyboardOperation.sdlMsgVersion = new SdlMsgVersion(5, 3); + // 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 thread has started - presentKeyboardOperation.run(); - - // Make sure neither a `CancelInteraction` or `PerformInteraction` RPC is sent - verify(internalInterface, never()).sendRPC(any(CancelInteraction.class)); - verify(internalInterface, never()).sendRPC(any(PerformInteraction.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/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/AsynchronousOperation.java b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/AsynchronousOperation.java index 4ba98b384..c0a1dbb25 100644 --- a/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/AsynchronousOperation.java +++ b/base/src/main/java/com/smartdevicelink/managers/screen/choiceset/AsynchronousOperation.java @@ -37,20 +37,29 @@ package com.smartdevicelink.managers.screen.choiceset; import com.smartdevicelink.util.DebugTool; class AsynchronousOperation implements Runnable { - private Boolean executing; - private Boolean finished; + 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() { - DebugTool.logInfo("Starting operation: " + toString()); + thread = Thread.currentThread(); + DebugTool.logInfo(TAG + "Starting: " + toString()); if (isCancelled()) { finished = true; - DebugTool.logInfo("Operation was cancelled: " + toString()); + DebugTool.logInfo(TAG + "Operation was cancelled: " + toString()); return; } @@ -58,30 +67,56 @@ class AsynchronousOperation implements Runnable { } void finishOperation() { + unblock(); executing = false; finished = true; - DebugTool.logInfo("Finishing operation: " + toString()); + cancelled = false; + DebugTool.logInfo(TAG + "Finishing: " + toString()); } - public Boolean isAsynchronous() { - return true; - } - - public Boolean isExecuting() { + boolean isExecuting() { return executing; } - public Boolean isFinished() { + boolean isFinished() { return finished; } - public Boolean isCancelled() { - return Thread.currentThread().isInterrupted(); + 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 "Executing: " + executing + ", finished: " + finished + "."; + 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 c936548ba..9dc1ff1d6 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 @@ -85,8 +85,6 @@ 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; @@ -144,9 +142,7 @@ abstract class BaseChoiceSetManager extends BaseSubManager { pendingPresentationSet = null; pendingPresentOperation = null; - waitingChoices = null; - waitingListener = null; - isVROptional = true; + isVROptional = false; nextChoiceId = choiceCellIdMin; nextCancelId = choiceCellCancelIdMin; @@ -189,10 +185,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; } @@ -222,15 +215,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; } } }); @@ -247,7 +236,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); @@ -259,7 +251,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; } @@ -299,13 +291,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"); } @@ -337,8 +332,6 @@ abstract class BaseChoiceSetManager extends BaseSubManager { if (pendingPresentationSet.getChoiceSetSelectionListener() != null){ pendingPresentationSet.getChoiceSetSelectionListener().onChoiceSelected(choiceCell, triggerSource,rowIndex); } - pendingPresentationSet = null; - pendingPresentOperation = null; } @Override @@ -346,8 +339,6 @@ abstract class BaseChoiceSetManager extends BaseSubManager { if (pendingPresentationSet.getChoiceSetSelectionListener() != null){ pendingPresentationSet.getChoiceSetSelectionListener().onError(error); } - pendingPresentationSet = null; - pendingPresentOperation = null; } }; @@ -379,10 +370,13 @@ abstract class BaseChoiceSetManager extends BaseSubManager { return null; } - if (!isReady()){ return null; } + 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."); } @@ -412,6 +406,11 @@ abstract class BaseChoiceSetManager extends BaseSubManager { * @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(); @@ -537,10 +536,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 = hmiStatus.getSystemContext(); @@ -551,10 +546,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); - } } } @@ -624,13 +615,4 @@ abstract class BaseChoiceSetManager extends BaseSubManager { defaultProperties.setKeypressMode(KeypressMode.RESEND_CURRENT_ENTRY); return defaultProperties; } - - @SuppressWarnings("BooleanMethodIsAlwaysInverted") - 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/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 40672a2df..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 @@ -103,6 +103,7 @@ class PresentChoiceSetOperation extends AsynchronousOperation { DebugTool.logInfo("Choice Operation: Executing present choice set operation"); addListeners(); start(); + block(); } private void start(){ @@ -162,8 +163,10 @@ class PresentChoiceSetOperation extends AsynchronousOperation { @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){ @@ -197,6 +200,16 @@ class PresentChoiceSetOperation extends AsynchronousOperation { 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); @@ -217,6 +230,12 @@ class PresentChoiceSetOperation extends AsynchronousOperation { 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(); + } }); if (internalInterface.get() != null) { @@ -268,7 +287,7 @@ class PresentChoiceSetOperation extends AsynchronousOperation { } } else { DebugTool.logInfo("Canceling a choice set that has not yet been sent to Core"); - Thread.currentThread().interrupt(); + this.cancel(); } } 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 188016129..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 @@ -71,6 +71,7 @@ class PresentKeyboardOperation extends AsynchronousOperation { SdlMsgVersion sdlMsgVersion; 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; @@ -87,6 +88,7 @@ class PresentKeyboardOperation extends AsynchronousOperation { DebugTool.logInfo("Keyboard Operation: Executing present keyboard operation"); addListeners(); start(); + block(); } private void start(){ @@ -179,7 +181,7 @@ class PresentKeyboardOperation extends AsynchronousOperation { } } else { DebugTool.logInfo("Canceling a keyboard that has not yet been sent to Core."); - Thread.currentThread().interrupt(); + this.cancel(); } } @@ -215,6 +217,9 @@ class PresentKeyboardOperation extends AsynchronousOperation { @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); } @@ -239,6 +244,12 @@ class PresentKeyboardOperation extends AsynchronousOperation { 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(); + } }); if (internalInterface.get() != null) { |