summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBilal Alsharifi <bilal.alsharifi@gmail.com>2019-02-27 13:07:13 -0500
committerBilal Alsharifi <bilal.alsharifi@gmail.com>2019-02-27 13:07:13 -0500
commit9530856d8b280d21c43b4e867e5fb19523a64807 (patch)
treefc3d6f505149f75cc066f5a938b5307b101895cd
parent54969ba09498a42d0f1865535fcbda720a43255b (diff)
parent3a8dc4545c2a186fd80804097049e0c2284faac8 (diff)
downloadsdl_android-feature/app_services_base.tar.gz
Merge branch 'develop' into feature/app_services_basefeature/app_services_base
# Conflicts: # sdl_android/src/androidTest/java/com/smartdevicelink/test/Test.java
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/managers/SdlManagerTests.java4
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java22
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/SoftButtonManagerTests.java5
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/Test.java3
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java2
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SystemCapabilityManagerTests.java3
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/StartTimeTest.java11
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SdlDisconnectedReasonTests.java2
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetMediaClockTimerTests.java65
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/GetAppServiceDataResponseTests.java3
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession.java4
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession2.java4
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java37
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/file/FileManager.java5
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java25
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java17
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java11
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonState.java4
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java27
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java7
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java55
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetMediaClockTimer.java109
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/StartTime.java13
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SdlDisconnectedReason.java4
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexUsbTransport.java43
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java183
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/TransportBroker.java13
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java4
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java20
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/UsbTransferProvider.java50
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java13
-rw-r--r--sdl_android/src/main/res/values/sdl.xml2
32 files changed, 667 insertions, 103 deletions
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/SdlManagerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/SdlManagerTests.java
index b226f2998..b1a1df0ed 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/SdlManagerTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/SdlManagerTests.java
@@ -117,6 +117,8 @@ public class SdlManagerTests extends AndroidTestCase2 {
builder.setVrSynonyms(Test.GENERAL_VECTOR_STRING);
builder.setTtsName(Test.GENERAL_VECTOR_TTS_CHUNKS);
builder.setLockScreenConfig(lockScreenConfig);
+ builder.setMinimumProtocolVersion(Test.GENERAL_VERSION);
+ builder.setMinimumRPClVersion(Test.GENERAL_VERSION);
manager = builder.build();
// mock SdlProxyBase and set it manually
@@ -160,6 +162,8 @@ public class SdlManagerTests extends AndroidTestCase2 {
assertEquals(Test.GENERAL_VECTOR_STRING, sdlManager.getVrSynonyms());
assertEquals(Test.GENERAL_VECTOR_TTS_CHUNKS, sdlManager.getTtsChunks());
assertEquals(Test.GENERAL_LOCKSCREENCONFIG, sdlManager.getLockScreenConfig());
+ assertEquals(Test.GENERAL_VERSION, sdlManager.getMinimumProtocolVersion());
+ assertEquals(Test.GENERAL_VERSION, sdlManager.getMinimumRPCVersion());
}
public void testStartingManager(){
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java
index 05838d727..b4e27f205 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java
@@ -16,6 +16,7 @@ import com.smartdevicelink.proxy.rpc.PutFile;
import com.smartdevicelink.proxy.rpc.PutFileResponse;
import com.smartdevicelink.proxy.rpc.enums.FileType;
import com.smartdevicelink.proxy.rpc.enums.Result;
+import com.smartdevicelink.proxy.rpc.enums.StaticIconName;
import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
import com.smartdevicelink.test.Test;
@@ -219,6 +220,27 @@ public class FileManagerTests extends AndroidTestCase2 {
});
}
+ public void testFileUploadForStaticIcon(){
+ ISdl internalInterface = mock(ISdl.class);
+
+ doAnswer(onListFilesSuccess).when(internalInterface).sendRPCRequest(any(ListFiles.class));
+
+ final FileManager fileManager = new FileManager(internalInterface, mTestContext);
+ fileManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertTrue(success);
+ SdlArtwork artwork = new SdlArtwork(StaticIconName.ALBUM);
+ fileManager.uploadFile(artwork, new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertTrue(success);
+ }
+ });
+ }
+ });
+ }
+
public void testInvalidSdlFileInput(){
ISdl internalInterface = mock(ISdl.class);
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/SoftButtonManagerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/SoftButtonManagerTests.java
index 3198bc116..144057c36 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/SoftButtonManagerTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/SoftButtonManagerTests.java
@@ -16,6 +16,7 @@ import com.smartdevicelink.proxy.rpc.enums.FileType;
import com.smartdevicelink.proxy.rpc.enums.HMILevel;
import com.smartdevicelink.proxy.rpc.enums.ImageType;
import com.smartdevicelink.proxy.rpc.enums.SoftButtonType;
+import com.smartdevicelink.proxy.rpc.enums.StaticIconName;
import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
import com.smartdevicelink.test.Validator;
@@ -108,7 +109,7 @@ public class SoftButtonManagerTests extends AndroidTestCase2 {
// Create soft button objects
softButtonState1 = new SoftButtonState("object1-state1", "o1s1", new SdlArtwork("image1", FileType.GRAPHIC_PNG, 1, true));
- softButtonState2 = new SoftButtonState("object1-state2", "o1s2", new SdlArtwork("image2", FileType.GRAPHIC_PNG, 2, true));
+ softButtonState2 = new SoftButtonState("object1-state2", "o1s2", new SdlArtwork(StaticIconName.ALBUM));
softButtonObject1 = new SoftButtonObject("object1", Arrays.asList(softButtonState1, softButtonState2), softButtonState1.getName(), null);
softButtonState3 = new SoftButtonState("object2-state1", "o2s1", null);
softButtonState4 = new SoftButtonState("object2-state2", "o2s2", new SdlArtwork("image3", FileType.GRAPHIC_PNG, 3, true));
@@ -184,6 +185,8 @@ public class SoftButtonManagerTests extends AndroidTestCase2 {
// Test SoftButtonState.getArtwork()
SdlArtwork artworkExpectedValue = new SdlArtwork("image1", FileType.GRAPHIC_PNG, 1, true);
assertTrue("Returned SdlArtwork doesn't match the expected value", Validator.validateSdlFile(artworkExpectedValue, softButtonState1.getArtwork()));
+ SdlArtwork artworkExpectedValue2 = new SdlArtwork(StaticIconName.ALBUM);
+ assertTrue("Returned SdlArtwork doesn't match the expected value", Validator.validateSdlFile(artworkExpectedValue2, softButtonState2.getArtwork()));
// Test SoftButtonState.getSoftButton()
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/Test.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/Test.java
index 3ed906237..d3446e8e2 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/Test.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/Test.java
@@ -179,6 +179,7 @@ import com.smartdevicelink.proxy.rpc.enums.VideoStreamingState;
import com.smartdevicelink.proxy.rpc.enums.VrCapabilities;
import com.smartdevicelink.proxy.rpc.enums.WarningLightStatus;
import com.smartdevicelink.proxy.rpc.enums.WayPointType;
+import com.smartdevicelink.util.Version;
import org.json.JSONArray;
import org.json.JSONException;
@@ -345,7 +346,7 @@ public class Test {
public static final NavigationJunction GENERAL_NAVIGATION_JUNCTION = NavigationJunction.BIFURCATION;
public static final Direction GENERAL_DIRECTION = Direction.RIGHT;
public static final NavigationInstruction GENERAL_NAVIGATION_INSTRUCTION = new NavigationInstruction();
-
+ public static final Version GENERAL_VERSION = new Version("4.0.0");
public static final ModuleType GENERAL_MODULETYPE = ModuleType.CLIMATE;
public static final Temperature GENERAL_TEMPERATURE = new Temperature();
public static final TemperatureUnit GENERAL_TEMPERATUREUNIT = TemperatureUnit.CELSIUS;
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java
index 939b25acc..595793049 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java
@@ -296,7 +296,7 @@ public class Validator{
return false;
}
- if(!( sdlFile1.getType().equals(sdlFile2.getType()) )){
+ if((sdlFile1.getType()!= null && sdlFile2.getType() != null) && !( sdlFile1.getType().equals(sdlFile2.getType()) )){
log("validateSdlFile",
"sdlFile1 type \"" + sdlFile1.getType() + "\" didn't match sdlFile2 type \"" + sdlFile2.getType() + "\".");
return false;
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SystemCapabilityManagerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SystemCapabilityManagerTests.java
index 91bd19d34..91fbf6dde 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SystemCapabilityManagerTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SystemCapabilityManagerTests.java
@@ -173,6 +173,9 @@ public class SystemCapabilityManagerTests extends AndroidTestCase2 {
public void sendRPCRequest(RPCRequest message) {}
@Override
+ public void sendRPC(RPCRequest message) {}
+
+ @Override
public void sendRequests(List<? extends RPCRequest> rpcs, OnMultipleRequestListener listener) {
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/StartTimeTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/StartTimeTest.java
index f84ca3ec3..7d1c7361b 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/StartTimeTest.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/StartTimeTest.java
@@ -13,7 +13,7 @@ import com.smartdevicelink.test.Test;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.StartTime}
+ * {@link com.smartdevicelink.proxy.rpc.StartTime}
*/
public class StartTimeTest extends TestCase {
@@ -41,11 +41,16 @@ public class StartTimeTest extends TestCase {
assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, hours);
assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, minutes);
assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, seconds);
-
+
+ // TimeInterval constructor test
+ StartTime startTime = new StartTime(7000);
+ assertEquals(Test.MATCH, (Integer) 1, startTime.getHours());
+ assertEquals(Test.MATCH, (Integer) 56, startTime.getMinutes());
+ assertEquals(Test.MATCH, (Integer) 40, startTime.getSeconds());
+
// Invalid/Null Tests
StartTime msg = new StartTime();
assertNotNull(Test.NOT_NULL, msg);
-
assertNull(Test.NULL, msg.getHours());
assertNull(Test.NULL, msg.getMinutes());
assertNull(Test.NULL, msg.getSeconds());
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SdlDisconnectedReasonTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SdlDisconnectedReasonTests.java
index 1b32c9544..c0c06c251 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SdlDisconnectedReasonTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SdlDisconnectedReasonTests.java
@@ -147,6 +147,8 @@ public class SdlDisconnectedReasonTests extends TestCase {
enumTestList.add(SdlDisconnectedReason.LEGACY_BLUETOOTH_MODE_ENABLED);
enumTestList.add(SdlDisconnectedReason.RPC_SESSION_ENDED);
enumTestList.add(SdlDisconnectedReason.PRIMARY_TRANSPORT_CYCLE_REQUEST);
+ enumTestList.add(SdlDisconnectedReason.MINIMUM_PROTOCOL_VERSION_HIGHER_THAN_SUPPORTED);
+ enumTestList.add(SdlDisconnectedReason.MINIMUM_RPC_VERSION_HIGHER_THAN_SUPPORTED);
assertTrue("Enum value list does not match enum class list",
enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetMediaClockTimerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetMediaClockTimerTests.java
index a90bd31b9..8083c65ed 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetMediaClockTimerTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetMediaClockTimerTests.java
@@ -88,6 +88,71 @@ public class SetMediaClockTimerTests extends BaseRpcTests {
assertNull(Test.NULL, msg.getUpdateMode());
assertNull(Test.NULL, msg.getAudioStreamingIndicator());
}
+
+ /**
+ * Test static initializers
+ */
+ public void testInitializers(){
+ Integer timeInterval1 = 5000;
+ StartTime startTime1 = new StartTime(timeInterval1);
+ Integer timeInterval2 = 7000;
+ StartTime startTime2 = new StartTime(timeInterval2);
+ SetMediaClockTimer msg;
+
+ msg = SetMediaClockTimer.countUpFromStartTimeInterval(timeInterval1, timeInterval2, Test.GENERAL_AUDIO_STREAMING_INDICATOR);
+ assertEquals(Test.MATCH, msg.getUpdateMode(), UpdateMode.COUNTUP);
+ assertTrue(Test.TRUE, Validator.validateStartTime(startTime1, msg.getStartTime()));
+ assertTrue(Test.TRUE, Validator.validateStartTime(startTime2, msg.getEndTime()));
+ assertEquals(Test.MATCH, Test.GENERAL_AUDIO_STREAMING_INDICATOR, msg.getAudioStreamingIndicator());
+
+ msg = SetMediaClockTimer.countUpFromStartTime(startTime1, startTime2, Test.GENERAL_AUDIO_STREAMING_INDICATOR);
+ assertEquals(Test.MATCH, msg.getUpdateMode(), UpdateMode.COUNTUP);
+ assertTrue(Test.TRUE, Validator.validateStartTime(startTime1, msg.getStartTime()));
+ assertTrue(Test.TRUE, Validator.validateStartTime(startTime2, msg.getEndTime()));
+ assertEquals(Test.MATCH, Test.GENERAL_AUDIO_STREAMING_INDICATOR, msg.getAudioStreamingIndicator());
+
+ msg = SetMediaClockTimer.countDownFromStartTimeInterval(timeInterval1, timeInterval2, Test.GENERAL_AUDIO_STREAMING_INDICATOR);
+ assertEquals(Test.MATCH, msg.getUpdateMode(), UpdateMode.COUNTDOWN);
+ assertTrue(Test.TRUE, Validator.validateStartTime(startTime1, msg.getStartTime()));
+ assertTrue(Test.TRUE, Validator.validateStartTime(startTime2, msg.getEndTime()));
+ assertEquals(Test.MATCH, Test.GENERAL_AUDIO_STREAMING_INDICATOR, msg.getAudioStreamingIndicator());
+
+ msg = SetMediaClockTimer.countDownFromStartTime(startTime1, startTime2, Test.GENERAL_AUDIO_STREAMING_INDICATOR);
+ assertEquals(Test.MATCH, msg.getUpdateMode(), UpdateMode.COUNTDOWN);
+ assertTrue(Test.TRUE, Validator.validateStartTime(startTime1, msg.getStartTime()));
+ assertTrue(Test.TRUE, Validator.validateStartTime(startTime2, msg.getEndTime()));
+ assertEquals(Test.MATCH, Test.GENERAL_AUDIO_STREAMING_INDICATOR, msg.getAudioStreamingIndicator());
+
+ msg = SetMediaClockTimer.pauseWithPlayPauseIndicator(Test.GENERAL_AUDIO_STREAMING_INDICATOR);
+ assertEquals(Test.MATCH, msg.getUpdateMode(), UpdateMode.PAUSE);
+ assertNull(Test.NULL, msg.getStartTime());
+ assertNull(Test.NULL, msg.getEndTime());
+ assertEquals(Test.MATCH, Test.GENERAL_AUDIO_STREAMING_INDICATOR, msg.getAudioStreamingIndicator());
+
+ msg = SetMediaClockTimer.updatePauseWithNewStartTimeInterval(timeInterval1, timeInterval2, Test.GENERAL_AUDIO_STREAMING_INDICATOR);
+ assertEquals(Test.MATCH, msg.getUpdateMode(), UpdateMode.PAUSE);
+ assertTrue(Test.TRUE, Validator.validateStartTime(startTime1, msg.getStartTime()));
+ assertTrue(Test.TRUE, Validator.validateStartTime(startTime2, msg.getEndTime()));
+ assertEquals(Test.MATCH, Test.GENERAL_AUDIO_STREAMING_INDICATOR, msg.getAudioStreamingIndicator());
+
+ msg = SetMediaClockTimer.updatePauseWithNewStartTime(startTime1, startTime2, Test.GENERAL_AUDIO_STREAMING_INDICATOR);
+ assertEquals(Test.MATCH, msg.getUpdateMode(), UpdateMode.PAUSE);
+ assertTrue(Test.TRUE, Validator.validateStartTime(startTime1, msg.getStartTime()));
+ assertTrue(Test.TRUE, Validator.validateStartTime(startTime2, msg.getEndTime()));
+ assertEquals(Test.MATCH, Test.GENERAL_AUDIO_STREAMING_INDICATOR, msg.getAudioStreamingIndicator());
+
+ msg = SetMediaClockTimer.resumeWithPlayPauseIndicator(Test.GENERAL_AUDIO_STREAMING_INDICATOR);
+ assertEquals(Test.MATCH, msg.getUpdateMode(), UpdateMode.RESUME);
+ assertNull(Test.NULL, msg.getStartTime());
+ assertNull(Test.NULL, msg.getEndTime());
+ assertEquals(Test.MATCH, Test.GENERAL_AUDIO_STREAMING_INDICATOR, msg.getAudioStreamingIndicator());
+
+ msg = SetMediaClockTimer.clearWithPlayPauseIndicator(Test.GENERAL_AUDIO_STREAMING_INDICATOR);
+ assertEquals(Test.MATCH, msg.getUpdateMode(), UpdateMode.CLEAR);
+ assertNull(Test.NULL, msg.getStartTime());
+ assertNull(Test.NULL, msg.getEndTime());
+ assertEquals(Test.MATCH, Test.GENERAL_AUDIO_STREAMING_INDICATOR, msg.getAudioStreamingIndicator());
+ }
/**
* Tests a valid JSON construction of this RPC message.
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/GetAppServiceDataResponseTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/GetAppServiceDataResponseTests.java
index 85a0883de..08a8f6536 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/GetAppServiceDataResponseTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/GetAppServiceDataResponseTests.java
@@ -5,6 +5,7 @@ import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCMessage;
import com.smartdevicelink.proxy.rpc.AppServiceData;
import com.smartdevicelink.proxy.rpc.GetAppServiceDataResponse;
+import com.smartdevicelink.proxy.rpc.enums.Result;
import com.smartdevicelink.test.BaseRpcTests;
import com.smartdevicelink.test.JsonUtils;
import com.smartdevicelink.test.Test;
@@ -56,7 +57,7 @@ public class GetAppServiceDataResponseTests extends BaseRpcTests {
assertEquals(Test.GENERAL_APPSERVICE_DATA, serviceData);
// test constructor
- msg = new GetAppServiceDataResponse(Test.GENERAL_APPSERVICE_DATA);
+ msg = new GetAppServiceDataResponse(true, Result.SUCCESS, Test.GENERAL_APPSERVICE_DATA);
serviceData = msg.getServiceData();
assertEquals(Test.GENERAL_APPSERVICE_DATA, serviceData);
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession.java b/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession.java
index c3e66fb06..f509f412c 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession.java
@@ -161,6 +161,10 @@ public class SdlSession implements ISdlConnectionListener, IHeartbeatMonitorList
}
}
+ public void resetSession(){
+
+ }
+
public void startStream(InputStream is, SessionType sType, byte rpcSessionID) throws IOException {
if (sType.equals(SessionType.NAV))
{
diff --git a/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession2.java b/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession2.java
index 497e3da95..501fc31c8 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession2.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession2.java
@@ -106,6 +106,10 @@ public class SdlSession2 extends SdlSession implements ISdlProtocol{
}
}
+ @Override
+ public void resetSession (){
+ sdlProtocol.resetSession();
+ }
@SuppressWarnings("ConstantConditions")
@Override
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java b/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java
index 3b42fdb08..c650f8687 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java
@@ -87,6 +87,8 @@ public class SdlManager{
private List<Class<? extends SdlSecurityBase>> sdlSecList;
private LockScreenConfig lockScreenConfig;
private final Object STATE_LOCK = new Object();
+ private Version minimumProtocolVersion;
+ private Version minimumRPCVersion;
// Managers
@@ -397,6 +399,10 @@ public class SdlManager{
protected String getShortAppName() { return shortAppName; }
+ protected Version getMinimumProtocolVersion() { return minimumProtocolVersion; }
+
+ protected Version getMinimumRPCVersion() { return minimumRPCVersion; }
+
protected Language getHmiLanguage() { return hmiLanguage; }
protected TemplateColorScheme getDayColorScheme() { return dayColorScheme; }
@@ -564,6 +570,8 @@ public class SdlManager{
proxy = new SdlProxyBase(proxyBridge, context, appName, shortAppName, isMediaApp, hmiLanguage,
hmiLanguage, hmiTypes, appId, transport, vrSynonyms, ttsChunks, dayColorScheme,
nightColorScheme) {};
+ proxy.setMinimumProtocolVersion(minimumProtocolVersion);
+ proxy.setMinimumRPCVersion(minimumRPCVersion);
if (sdlSecList != null && !sdlSecList.isEmpty()) {
proxy.setSdlSecurityClassList(sdlSecList);
}
@@ -812,6 +820,27 @@ public class SdlManager{
}
/**
+ * Sets the minimum protocol version that will be permitted to connect.
+ * If the protocol version of the head unit connected is below this version,
+ * the app will disconnect with an EndService protocol message and will not register.
+ * @param minimumProtocolVersion
+ */
+ public Builder setMinimumProtocolVersion(final Version minimumProtocolVersion) {
+ sdlManager.minimumProtocolVersion = minimumProtocolVersion;
+ return this;
+ }
+
+ /**
+ * The minimum RPC version that will be permitted to connect.
+ * If the RPC version of the head unit connected is below this version, an UnregisterAppInterface will be sent.
+ * @param minimumRPCVersion
+ */
+ public Builder setMinimumRPClVersion(final Version minimumRPCVersion) {
+ sdlManager.minimumRPCVersion = minimumRPCVersion;
+ return this;
+ }
+
+ /**
* Sets the Language of the App
* @param hmiLanguage
*/
@@ -958,6 +987,14 @@ public class SdlManager{
sdlManager.hmiLanguage = Language.EN_US;
}
+ if (sdlManager.minimumProtocolVersion == null){
+ sdlManager.minimumProtocolVersion = new Version("1.0.0");
+ }
+
+ if (sdlManager.minimumRPCVersion == null){
+ sdlManager.minimumRPCVersion = new Version("1.0.0");
+ }
+
sdlManager.transitionToState(BaseSubManager.SETTING_UP);
return sdlManager;
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/file/FileManager.java b/sdl_android/src/main/java/com/smartdevicelink/managers/file/FileManager.java
index 559b74514..61d049832 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/managers/file/FileManager.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/file/FileManager.java
@@ -272,6 +272,11 @@ public class FileManager extends BaseSubManager {
* @param listener called when core responds to the attempt to upload the file
*/
public void uploadFile(@NonNull final SdlFile file, final CompletionListener listener){
+ if (file.isStaticIcon()){
+ Log.w(TAG, "Static icons don't need to be uploaded");
+ listener.onComplete(true);
+ return;
+ }
PutFile putFile = createPutFile(file);
putFile.setOnRPCResponseListener(new OnRPCResponseListener() {
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java b/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java
index f0ce5f685..664376d7b 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java
@@ -3,13 +3,17 @@ package com.smartdevicelink.managers.file.filetypes;
import android.net.Uri;
import android.support.annotation.NonNull;
+import com.smartdevicelink.proxy.rpc.Image;
import com.smartdevicelink.proxy.rpc.enums.FileType;
+import com.smartdevicelink.proxy.rpc.enums.ImageType;
+import com.smartdevicelink.proxy.rpc.enums.StaticIconName;
/**
* A class that extends SdlFile, representing artwork (JPEG, PNG, or BMP) to be uploaded to core
*/
public class SdlArtwork extends SdlFile {
private boolean isTemplate;
+ private Image imageRPC;
public SdlArtwork(){}
@@ -25,6 +29,10 @@ public class SdlArtwork extends SdlFile {
super(fileName, fileType, data, persistentFile);
}
+ public SdlArtwork(@NonNull StaticIconName staticIconName) {
+ super(staticIconName);
+ }
+
/**
* Set whether this SdlArtwork is a template image whose coloring should be decided by the HMI
* @param isTemplate boolean that tells whether this SdlArtwork is a template image
@@ -50,4 +58,21 @@ public class SdlArtwork extends SdlFile {
throw new IllegalArgumentException("Only JPEG, PNG, and BMP image types are supported.");
}
}
+
+ /**
+ * Get the Image RPC representing this artwork. Generally for use internally, you should instead pass an artwork to a Screen Manager method.
+ * @return The Image RPC representing this artwork.
+ */
+ public Image getImageRPC() {
+ if (imageRPC == null) {
+ if (isStaticIcon()) {
+ imageRPC = new Image(getName(), ImageType.STATIC);
+ imageRPC.setIsTemplate(true);
+ } else {
+ imageRPC = new Image(getName(), ImageType.DYNAMIC);
+ imageRPC.setIsTemplate(isTemplate);
+ }
+ }
+ return imageRPC;
+ }
} \ No newline at end of file
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java b/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java
index ce4cf8285..71eaa22fd 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java
@@ -4,6 +4,7 @@ import android.net.Uri;
import android.support.annotation.NonNull;
import com.smartdevicelink.proxy.rpc.enums.FileType;
+import com.smartdevicelink.proxy.rpc.enums.StaticIconName;
/**
* A class representing data to be uploaded to core
@@ -15,6 +16,8 @@ public class SdlFile{
private byte[] fileData;
private FileType fileType;
private boolean persistentFile;
+ private boolean isStaticIcon;
+
public SdlFile(){}
@@ -39,6 +42,13 @@ public class SdlFile{
this.persistentFile = persistentFile;
}
+ public SdlFile(@NonNull StaticIconName staticIconName){
+ this.fileName = staticIconName.toString();
+ this.fileData = staticIconName.toString().getBytes();
+ this.persistentFile = false;
+ this.isStaticIcon = true;
+ }
+
public void setName(@NonNull String fileName){
this.fileName = fileName;
}
@@ -80,4 +90,11 @@ public class SdlFile{
public boolean isPersistent(){
return this.persistentFile;
}
+
+ public void setStaticIcon(boolean staticIcon) {
+ isStaticIcon = staticIcon;
+ }
+ public boolean isStaticIcon() {
+ return isStaticIcon;
+ }
} \ No newline at end of file
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java
index f995231eb..d6bd49e67 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java
@@ -287,7 +287,7 @@ class SoftButtonManager extends BaseSubManager {
}
if (initialState != null && softButtonObject.getStates() != null) {
for (SoftButtonState softButtonState : softButtonObject.getStates()) {
- if (softButtonState != null && softButtonState.getName() != null && softButtonState.getArtwork() != null && !fileManager.get().hasUploadedFile(softButtonState.getArtwork())) {
+ if (softButtonState != null && softButtonState.getName() != null && sdlArtworkNeedsUpload(softButtonState.getArtwork())) {
if (softButtonState.getName().equals(initialState.getName())) {
initialStatesToBeUploaded.add(softButtonObject.getCurrentState().getArtwork());
} else{
@@ -527,7 +527,7 @@ class SoftButtonManager extends BaseSubManager {
if (fileManager.get() != null) {
for (SoftButtonObject softButtonObject : softButtonObjects) {
SoftButtonState currentState = softButtonObject.getCurrentState();
- if (currentState != null && currentState.getArtwork() != null && !fileManager.get().hasUploadedFile(currentState.getArtwork())) {
+ if (currentState != null && sdlArtworkNeedsUpload(currentState.getArtwork())) {
return false;
}
}
@@ -535,6 +535,13 @@ class SoftButtonManager extends BaseSubManager {
return true;
}
+ private boolean sdlArtworkNeedsUpload(SdlArtwork artwork){
+ if (fileManager.get() != null) {
+ return artwork != null && !fileManager.get().hasUploadedFile(artwork) && !artwork.isStaticIcon();
+ }
+ return false;
+ }
+
/**
* Returns text soft buttons representing the initial states of the button objects, or null if _any_ of the buttons' current states are image only buttons.
* @return The text soft buttons
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonState.java b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonState.java
index d8bf7952b..d6c81ada9 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonState.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonState.java
@@ -54,9 +54,7 @@ public class SoftButtonState {
// Set the SoftButton's image
if (artwork != null) {
- Image image = new Image(artwork.getName(), ImageType.DYNAMIC);
- image.setIsTemplate(artwork.isTemplateImage());
- softButton.setImage(image);
+ softButton.setImage(artwork.getImageRPC());
}
// Set the SoftButton's text
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java
index 397ac33c8..1f2b8b4d1 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java
@@ -218,7 +218,7 @@ class TextAndGraphicManager extends BaseSubManager {
inProgressUpdate = extractTextFromShow(fullShow);
sendShow();
- }else if (isArtworkUploadedOrDoesntExist(primaryGraphic) && ( secondaryGraphic == blankArtwork || isArtworkUploadedOrDoesntExist(secondaryGraphic))){
+ }else if (!sdlArtworkNeedsUpload(primaryGraphic) && (secondaryGraphic == blankArtwork || !sdlArtworkNeedsUpload(secondaryGraphic))){
//Images already uploaded, sending full update
// The files to be updated are already uploaded, send the full show immediately
@@ -298,15 +298,20 @@ class TextAndGraphicManager extends BaseSubManager {
List<SdlArtwork> artworksToUpload = new ArrayList<>();
// add primary image
- if (shouldUpdatePrimaryImage()){
+ if (shouldUpdatePrimaryImage() && !primaryGraphic.isStaticIcon()){
artworksToUpload.add(primaryGraphic);
}
// add secondary image
- if (shouldUpdateSecondaryImage()){
+ if (shouldUpdateSecondaryImage() && !secondaryGraphic.isStaticIcon()){
artworksToUpload.add(secondaryGraphic);
}
+ if (artworksToUpload.size() == 0 && (primaryGraphic.isStaticIcon() || secondaryGraphic.isStaticIcon())){
+ DebugTool.logInfo("Upload attempted on static icons, sending them without upload instead");
+ listener.onComplete(true);
+ }
+
// use file manager to upload art
if (fileManager.get() != null) {
fileManager.get().uploadArtworks(artworksToUpload, new MultipleFileCompletionListener() {
@@ -326,15 +331,11 @@ class TextAndGraphicManager extends BaseSubManager {
private Show assembleShowImages(Show show){
if (shouldUpdatePrimaryImage()){
- Image primaryImage = new Image(primaryGraphic.getName(), ImageType.DYNAMIC);
- primaryImage.setIsTemplate(primaryGraphic.isTemplateImage());
- show.setGraphic(primaryImage);
+ show.setGraphic(primaryGraphic.getImageRPC());
}
if (shouldUpdateSecondaryImage()){
- Image secondaryImage = new Image(secondaryGraphic.getName(), ImageType.DYNAMIC);
- secondaryImage.setIsTemplate(secondaryGraphic.isTemplateImage());
- show.setSecondaryGraphic(secondaryImage);
+ show.setSecondaryGraphic(secondaryGraphic.getImageRPC());
}
return show;
@@ -683,12 +684,10 @@ class TextAndGraphicManager extends BaseSubManager {
return blankArtwork;
}
- private boolean isArtworkUploadedOrDoesntExist(SdlArtwork artwork){
-
- if (fileManager.get() != null){
- return artwork != null && fileManager.get().hasUploadedFile(artwork);
+ private boolean sdlArtworkNeedsUpload(SdlArtwork artwork){
+ if (fileManager.get() != null) {
+ return artwork != null && !fileManager.get().hasUploadedFile(artwork) && !artwork.isStaticIcon();
}
-
return false;
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java b/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java
index f03a12d1f..7c0f7750a 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java
@@ -170,6 +170,10 @@ public class SdlProtocol {
return mtu;
}
+ public void resetSession (){
+ transportManager.resetSession();
+ }
+
public boolean isConnected(){
return transportManager != null && transportManager.isConnected(null,null);
}
@@ -1142,7 +1146,7 @@ public class SdlProtocol {
activeTransports.remove(SessionType.PCM);
}
- if(disconnectedTransport.equals(getTransportForSession(SessionType.RPC))){
+ if(disconnectedTransport.equals(getTransportForSession(SessionType.RPC)) || disconnectedTransport.equals(connectedPrimaryTransport)){
//transportTypes.remove(type);
boolean primaryTransportAvailable = false;
if(requestedPrimaryTransports != null && requestedPrimaryTransports.size() > 1){
@@ -1156,6 +1160,7 @@ public class SdlProtocol {
}
}
}
+ connectedPrimaryTransport = null;
transportManager.close(iSdlProtocol.getSessionId());
transportManager = null;
requestedSession = false;
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java
index d30bb4ae0..96b55ada8 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java
@@ -259,6 +259,9 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
protected VideoStreamingManager manager; //Will move to SdlSession once the class becomes public
+ private Version minimumProtocolVersion;
+ private Version minimumRPCVersion;
+
// Interface broker
private SdlInterfaceBroker _interfaceBroker = null;
@@ -541,6 +544,19 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}else{
setProtocolVersion(new com.smartdevicelink.util.Version(version,0,0));
}
+
+
+ if (minimumProtocolVersion != null && minimumProtocolVersion.isNewerThan(getProtocolVersion()) == 1){
+ Log.w(TAG, String.format("Disconnecting from head unit, the configured minimum protocol version %s is greater than the supported protocol version %s", minimumProtocolVersion, getProtocolVersion()));
+ endService(sessionType);
+ try {
+ cleanProxy(SdlDisconnectedReason.MINIMUM_PROTOCOL_VERSION_HIGHER_THAN_SUPPORTED);
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+ return;
+ }
+
if (sessionType.eq(SessionType.RPC)) {
@@ -1638,6 +1654,10 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
@SuppressWarnings("UnusedParameters")
private void cleanProxy(SdlDisconnectedReason disconnectedReason) throws SdlException {
+ if (disconnectedReason == SdlDisconnectedReason.MINIMUM_PROTOCOL_VERSION_HIGHER_THAN_SUPPORTED || disconnectedReason == SdlDisconnectedReason.MINIMUM_RPC_VERSION_HIGHER_THAN_SUPPORTED){
+ notifyProxyClosed(disconnectedReason.toString(), null, disconnectedReason);
+ sdlSession.resetSession();
+ }
try {
// ALM Specific Cleanup
@@ -2356,6 +2376,22 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}else{
rpcSpecVersion = MAX_SUPPORTED_RPC_VERSION;
}
+
+ if (minimumRPCVersion != null && minimumRPCVersion.isNewerThan(rpcSpecVersion) == 1){
+ Log.w(TAG, String.format("Disconnecting from head unit, the configured minimum RPC version %s is greater than the supported RPC version %s", minimumRPCVersion, rpcSpecVersion));
+ try {
+ unregisterAppInterfacePrivate(UNREGISTER_APP_INTERFACE_CORRELATION_ID);
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+ try {
+ cleanProxy(SdlDisconnectedReason.MINIMUM_RPC_VERSION_HIGHER_THAN_SUPPORTED);
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+ return;
+ }
+
_vehicleType = msg.getVehicleType();
_systemSoftwareVersion = msg.getSystemSoftwareVersion();
_proxyVersionInfo = msg.getProxyVersionInfo();
@@ -7500,6 +7536,25 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
}
+ /**
+ * Sets the minimum protocol version that will be permitted to connect.
+ * If the protocol version of the head unit connected is below this version,
+ * the app will disconnect with an EndService protocol message and will not register.
+ * @param minimumProtocolVersion
+ */
+ public void setMinimumProtocolVersion(Version minimumProtocolVersion){
+ this.minimumProtocolVersion = minimumProtocolVersion;
+ }
+
+ /**
+ * The minimum RPC version that will be permitted to connect.
+ * If the RPC version of the head unit connected is below this version, an UnregisterAppInterface will be sent.
+ * @param minimumRPCVersion
+ */
+ public void setMinimumRPCVersion(Version minimumRPCVersion){
+ this.minimumRPCVersion = minimumRPCVersion;
+ }
+
@SuppressWarnings("unused")
public boolean isServiceTypeProtected(SessionType sType) {
return sdlSession != null && sdlSession.isServiceProtected(sType);
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetMediaClockTimer.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetMediaClockTimer.java
index 8dd53449d..9063430a5 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetMediaClockTimer.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetMediaClockTimer.java
@@ -1,6 +1,7 @@
package com.smartdevicelink.proxy.rpc;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCRequest;
@@ -116,6 +117,114 @@ public class SetMediaClockTimer extends RPCRequest {
this();
setUpdateMode(updateMode);
}
+ private SetMediaClockTimer(@NonNull UpdateMode updateMode, @Nullable StartTime startTime, @Nullable StartTime endTime, @Nullable AudioStreamingIndicator audioStreamingIndicator){
+ this();
+ this.setUpdateMode(updateMode);
+ if (startTime != null) {
+ this.setStartTime(startTime);
+ }
+ if (endTime != null) {
+ this.setEndTime(endTime);
+ }
+ if (audioStreamingIndicator != null) {
+ this.setAudioStreamingIndicator(audioStreamingIndicator);
+ }
+ }
+ /**
+ * Create a media clock timer that counts up, e.g from 0:00 to 4:18.
+ *
+ * @param startTimeInterval The start time interval, e.g. (0) 0:00
+ * @param endTimeInterval The end time interval, e.g. (258) 4:18
+ * @param audioStreamingIndicator playPauseIndicator An optional audio indicator to change the play/pause button
+ * @return An object of SetMediaClockTimer
+ */
+ public static SetMediaClockTimer countUpFromStartTimeInterval(@NonNull Integer startTimeInterval, @NonNull Integer endTimeInterval, @Nullable AudioStreamingIndicator audioStreamingIndicator) {
+ return new SetMediaClockTimer(UpdateMode.COUNTUP, new StartTime(startTimeInterval), new StartTime(endTimeInterval), audioStreamingIndicator);
+ }
+ /**
+ * Create a media clock timer that counts up, e.g from 0:00 to 4:18.
+ *
+ * @param startTime The start time interval, e.g. 0:00
+ * @param endTime The end time interval, e.g. 4:18
+ * @param audioStreamingIndicator An optional audio indicator to change the play/pause button
+ * @return An object of SetMediaClockTimer
+ */
+ public static SetMediaClockTimer countUpFromStartTime(@NonNull StartTime startTime, @NonNull StartTime endTime, @Nullable AudioStreamingIndicator audioStreamingIndicator) {
+ return new SetMediaClockTimer(UpdateMode.COUNTUP, startTime, endTime, audioStreamingIndicator);
+ }
+ /**
+ * Create a media clock timer that counts down, e.g. from 4:18 to 0:00
+ * This will fail if endTime is greater than startTime
+ *
+ * @param startTimeInterval The start time interval, e.g. (258) 4:18
+ * @param endTimeInterval The end time interval, e.g. (0) 0:00
+ * @param audioStreamingIndicator An optional audio indicator to change the play/pause button
+ * @return An object of SetMediaClockTimer
+ */
+ public static SetMediaClockTimer countDownFromStartTimeInterval(@NonNull Integer startTimeInterval, @NonNull Integer endTimeInterval, @Nullable AudioStreamingIndicator audioStreamingIndicator) {
+ return new SetMediaClockTimer(UpdateMode.COUNTDOWN, new StartTime(startTimeInterval), new StartTime(endTimeInterval), audioStreamingIndicator);
+ }
+ /**
+ * Create a media clock timer that counts down, e.g. from 4:18 to 0:00
+ * This will fail if endTime is greater than startTime
+ *
+ * @param startTime The start time interval, e.g. 4:18
+ * @param endTime The end time interval, e.g. 0:00
+ * @param audioStreamingIndicator An optional audio indicator to change the play/pause button
+ * @return An object of SetMediaClockTimer
+ */
+ public static SetMediaClockTimer countDownFromStartTime(@NonNull StartTime startTime, @NonNull StartTime endTime, @Nullable AudioStreamingIndicator audioStreamingIndicator) {
+ return new SetMediaClockTimer(UpdateMode.COUNTDOWN, startTime, endTime, audioStreamingIndicator);
+ }
+ /**
+ * Pause an existing (counting up / down) media clock timer
+ *
+ * @param audioStreamingIndicator An optional audio indicator to change the play/pause button
+ * @return An object of SetMediaClockTimer
+ */
+ public static SetMediaClockTimer pauseWithPlayPauseIndicator(@Nullable AudioStreamingIndicator audioStreamingIndicator) {
+ return new SetMediaClockTimer(UpdateMode.PAUSE, null, null, audioStreamingIndicator);
+ }
+ /**
+ * Update a pause time (or pause and update the time) on a media clock timer
+ *
+ * @param startTimeInterval The new start time interval
+ * @param endTimeInterval The new end time interval
+ * @param audioStreamingIndicator An optional audio indicator to change the play/pause button
+ * @return An object of SetMediaClockTimer
+ */
+ public static SetMediaClockTimer updatePauseWithNewStartTimeInterval(@NonNull Integer startTimeInterval, @NonNull Integer endTimeInterval, @Nullable AudioStreamingIndicator audioStreamingIndicator) {
+ return new SetMediaClockTimer(UpdateMode.PAUSE, new StartTime(startTimeInterval), new StartTime(endTimeInterval), audioStreamingIndicator);
+ }
+ /**
+ * Update a pause time (or pause and update the time) on a media clock timer
+ *
+ * @param startTime The new start time
+ * @param endTime The new end time
+ * @param audioStreamingIndicator An optional audio indicator to change the play/pause button
+ * @return An object of SetMediaClockTimer
+ */
+ public static SetMediaClockTimer updatePauseWithNewStartTime(@NonNull StartTime startTime, @NonNull StartTime endTime, @Nullable AudioStreamingIndicator audioStreamingIndicator) {
+ return new SetMediaClockTimer(UpdateMode.PAUSE, startTime, endTime, audioStreamingIndicator);
+ }
+ /**
+ * Resume a paused media clock timer. It resumes at the same time at which it was paused.
+ *
+ * @param audioStreamingIndicator An optional audio indicator to change the play/pause button
+ * @return An object of SetMediaClockTimer
+ */
+ public static SetMediaClockTimer resumeWithPlayPauseIndicator(@Nullable AudioStreamingIndicator audioStreamingIndicator) {
+ return new SetMediaClockTimer(UpdateMode.RESUME, null, null, audioStreamingIndicator);
+ }
+ /**
+ * Remove a media clock timer from the screen
+ *
+ * @param audioStreamingIndicator An optional audio indicator to change the play/pause button
+ * @return An object of SetMediaClockTimer
+ */
+ public static SetMediaClockTimer clearWithPlayPauseIndicator(@Nullable AudioStreamingIndicator audioStreamingIndicator) {
+ return new SetMediaClockTimer(UpdateMode.CLEAR, null, null, audioStreamingIndicator);
+ }
/**
* Gets the Start Time which media clock timer is set
*
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/StartTime.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/StartTime.java
index e047a716b..97efa8c05 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/StartTime.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/StartTime.java
@@ -58,6 +58,19 @@ public class StartTime extends RPCStruct {
/**
* Constructs a newly allocated StartTime object
+ * @param timeInterval time interval in seconds
+ */
+ public StartTime(@NonNull Integer timeInterval){
+ this();
+ int hours = timeInterval / 3600;
+ int minutes = (timeInterval % 3600) / 60;
+ int seconds = timeInterval % 60;
+ setHours(hours);
+ setMinutes(minutes);
+ setSeconds(seconds);
+ }
+ /**
+ * Constructs a newly allocated StartTime object
* @param hours The hour
* @param minutes The minute
* @param seconds The second
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SdlDisconnectedReason.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SdlDisconnectedReason.java
index 60ecf5450..6c83fc1d9 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SdlDisconnectedReason.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SdlDisconnectedReason.java
@@ -26,7 +26,9 @@ public enum SdlDisconnectedReason {
*/
LEGACY_BLUETOOTH_MODE_ENABLED,
RPC_SESSION_ENDED,
- PRIMARY_TRANSPORT_CYCLE_REQUEST
+ PRIMARY_TRANSPORT_CYCLE_REQUEST,
+ MINIMUM_PROTOCOL_VERSION_HIGHER_THAN_SUPPORTED,
+ MINIMUM_RPC_VERSION_HIGHER_THAN_SUPPORTED,
;
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexUsbTransport.java b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexUsbTransport.java
index e807f7ac7..7ebcec1c2 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexUsbTransport.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexUsbTransport.java
@@ -62,7 +62,8 @@ public class MultiplexUsbTransport extends MultiplexBaseTransport{
private final Bundle deviceInfo;
private ReaderThread readerThread;
private WriterThread writerThread;
- private final ParcelFileDescriptor parcelFileDescriptor;
+ private ParcelFileDescriptor parcelFileDescriptor;
+ private Boolean connectionSuccessful = null;
MultiplexUsbTransport(ParcelFileDescriptor parcelFileDescriptor, Handler handler, Bundle bundle){
super(handler, TransportType.USB);
@@ -99,9 +100,18 @@ public class MultiplexUsbTransport extends MultiplexBaseTransport{
public synchronized void start(){
setState(STATE_CONNECTING);
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
+ if(fileDescriptor == null || !fileDescriptor.valid()){
+ Log.e(TAG, "USB FD was null or not valid,");
+ setState(STATE_NONE);
+ return;
+ }
readerThread = new ReaderThread(fileDescriptor);
+ readerThread.setDaemon(true);
writerThread = new WriterThread(fileDescriptor);
+ writerThread.setDaemon(true);
+ readerThread.start();
+ writerThread.start();
// Send the name of the connected device back to the UI Activity
Message msg = handler.obtainMessage(SdlRouterService.MESSAGE_DEVICE_NAME);
@@ -112,29 +122,33 @@ public class MultiplexUsbTransport extends MultiplexBaseTransport{
handler.sendMessage(msg);
setState(STATE_CONNECTED);
- readerThread.start();
- writerThread.start();
}
protected synchronized void stop(int stateToTransitionTo) {
//Log.d(TAG, "Attempting to close the Usb transports");
if (writerThread != null) {
writerThread.cancel();
+ writerThread.interrupt();
writerThread = null;
}
if (readerThread != null) {
readerThread.cancel();
+ readerThread.interrupt();
readerThread = null;
}
- if(parcelFileDescriptor != null){
+ if( (connectionSuccessful== null || connectionSuccessful == true ) //else, the connection was bad. Not closing the PFD helps recover
+ && parcelFileDescriptor != null){
try {
parcelFileDescriptor.close();
} catch (IOException e) {
e.printStackTrace();
}
}
+ parcelFileDescriptor = null;
+
+ System.gc();
setState(stateToTransitionTo);
}
@@ -182,8 +196,12 @@ public class MultiplexUsbTransport extends MultiplexBaseTransport{
bundle.putString(LOG, "Device connection was lost");
msg.setData(bundle);
handler.sendMessage(msg);
- stop();
-
+ handler.postDelayed(new Runnable() { //sends this stop back to the main thread to exit the reader thread
+ @Override
+ public void run() {
+ stop();
+ }
+ }, 250);
}
private class ReaderThread extends Thread{
@@ -199,7 +217,7 @@ public class MultiplexUsbTransport extends MultiplexBaseTransport{
@Override
public void run() { //FIXME probably check to see what the BT does
super.run();
- final int READ_BUFFER_SIZE = 4096;
+ final int READ_BUFFER_SIZE = 16384;
byte[] buffer = new byte[READ_BUFFER_SIZE];
int bytesRead;
boolean stateProgress;
@@ -221,6 +239,9 @@ public class MultiplexUsbTransport extends MultiplexBaseTransport{
Log.w(TAG,"Read some data, but thread is interrupted");
return;
}
+ if(connectionSuccessful != null && connectionSuccessful == false){
+ connectionSuccessful = true;
+ }
byte input;
for(int i=0;i<bytesRead; i++){
input=buffer[i];
@@ -284,12 +305,11 @@ public class MultiplexUsbTransport extends MultiplexBaseTransport{
public WriterThread(FileDescriptor fileDescriptor) {
//Log.d(TAG, "Creating a Connected - Write Thread");
OutputStream tmpOut = null;
- setName("SDL Router BT Write Thread");
+ setName("SDL USB Write Thread");
// Get the Usb output streams
mmOutStream = new FileOutputStream(fileDescriptor);
-
-
}
+
/**
* Write to the connected OutStream.
* @param buffer The bytes to write
@@ -302,6 +322,9 @@ public class MultiplexUsbTransport extends MultiplexBaseTransport{
}
//This would be a good spot to log out all bytes received
mmOutStream.write(buffer, offset, count);
+ if(connectionSuccessful == null){
+ connectionSuccessful = false;
+ }
//Log.w(TAG, "Wrote out to device: bytes = "+ count);
} catch (IOException|NullPointerException e) { // STRICTLY to catch mmOutStream NPE
// Exception during write
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java b/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
index f6a6a8736..e0f71a121 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
@@ -47,6 +47,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -80,6 +81,7 @@ import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
+import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
import android.os.DeadObjectException;
@@ -92,6 +94,7 @@ import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.RemoteException;
+import android.support.annotation.NonNull;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -136,7 +139,7 @@ public class SdlRouterService extends Service{
/**
* <b> NOTE: DO NOT MODIFY THIS UNLESS YOU KNOW WHAT YOU'RE DOING.</b>
*/
- protected static final int ROUTER_SERVICE_VERSION_NUMBER = 8;
+ protected static final int ROUTER_SERVICE_VERSION_NUMBER = 9;
private static final String ROUTER_SERVICE_PROCESS = "com.smartdevicelink.router";
@@ -207,7 +210,7 @@ public class SdlRouterService extends Service{
private boolean startSequenceComplete = false;
private ExecutorService packetExecutor = null;
- HashMap<TransportType, PacketWriteTaskMaster> packetWriteTaskMasterMap = null;
+ ConcurrentHashMap<TransportType, PacketWriteTaskMaster> packetWriteTaskMasterMap = null;
/**
@@ -819,12 +822,14 @@ public class SdlRouterService extends Service{
@SuppressWarnings("Convert2Diamond")
static class UsbTransferHandler extends Handler {
final WeakReference<SdlRouterService> provider;
+ Runnable usbCableDisconnectRunnable;
+ BroadcastReceiver usbCableDisconnectBroadcastReceiver;
public UsbTransferHandler(SdlRouterService provider){
this.provider = new WeakReference<SdlRouterService>(provider);
}
- @Override
+ @Override
public void handleMessage(Message msg) {
if(this.provider.get() == null){
return;
@@ -832,14 +837,51 @@ public class SdlRouterService extends Service{
SdlRouterService service = this.provider.get();
switch(msg.what){
case TransportConstants.USB_CONNECTED_WITH_DEVICE:
+ service.enterForeground("Opening USB connection",FOREGROUND_TIMEOUT,false);
+ service.resetForegroundTimeOut(FOREGROUND_TIMEOUT);
int flags = msg.arg1;
- ParcelFileDescriptor parcelFileDescriptor = (ParcelFileDescriptor)msg.obj;
- if(parcelFileDescriptor != null){
- //New USB constructor with PFD
- service.usbTransport = new MultiplexUsbTransport(parcelFileDescriptor,service.usbHandler,msg.getData());
- service.usbTransport.start();
+ ParcelFileDescriptor parcelFileDescriptor = (ParcelFileDescriptor)msg.obj;
+
+ if(parcelFileDescriptor != null) {
+ //New USB constructor with PFD
+ service.usbTransport = new MultiplexUsbTransport(parcelFileDescriptor, service.usbHandler, msg.getData());
+
+
+ usbCableDisconnectRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if(provider.get() != null && AndroidTools.isUSBCableConnected(provider.get().getApplicationContext())) {
+ provider.get().usbTransport.start();
+ }
+ }
+ };
+ postDelayed(usbCableDisconnectRunnable, 4000);
+
+
+ // Register a BroadcastReceiver to stop USB transport if USB cable got disconnected
+ if (provider.get() != null) {
+ usbCableDisconnectBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+ if (provider.get()!= null && plugged != BatteryManager.BATTERY_PLUGGED_AC && plugged != BatteryManager.BATTERY_PLUGGED_USB) {
+ try {
+ provider.get().getApplicationContext().unregisterReceiver(usbCableDisconnectBroadcastReceiver);
+ } catch (Exception e){ }
+ removeCallbacks(usbCableDisconnectRunnable);
+ if (provider.get().usbTransport != null) {
+ provider.get().usbTransport.stop();
+ }
+ }
+ }
+ };
+ provider.get().getApplicationContext().registerReceiver(usbCableDisconnectBroadcastReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
+
+
+ }
+
if(msg.replyTo!=null){
Message message = Message.obtain();
message.what = TransportConstants.ROUTER_USB_ACC_RECEIVED;
@@ -849,12 +891,7 @@ public class SdlRouterService extends Service{
e.printStackTrace();
}
}
- if(service.isPrimaryTransportConnected() && ((TransportConstants.ROUTER_STATUS_FLAG_TRIGGER_PING & flags) == TransportConstants.ROUTER_STATUS_FLAG_TRIGGER_PING)){
- if(service.pingIntent == null){
- service.initPingIntent();
- }
- AndroidTools.sendExplicitBroadcast(service.getApplicationContext(),service.pingIntent, null);
- }
+
break;
case TransportConstants.ALT_TRANSPORT_CONNECTED:
break;
@@ -1319,7 +1356,14 @@ public class SdlRouterService extends Service{
foregroundTimeoutRunnable = new Runnable() {
@Override
public void run() {
- exitForeground();
+ if(!getConnectedTransports().isEmpty()){
+ // Updates notification to one of still connected transport
+ enterForeground(createConnectedNotificationText(),0,true);
+ return;
+ }else{
+ exitForeground();//Leave our foreground state as we don't have a connection
+
+ }
}
};
} else {
@@ -1392,7 +1436,8 @@ public class SdlRouterService extends Service{
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
builder.setContentIntent(pendingIntent);
- if(chronometerLength > 0) {
+ if(chronometerLength > 0 && android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ //The countdown method is only available in SDKs >= 24
builder.setWhen(chronometerLength + System.currentTimeMillis());
builder.setUsesChronometer(true);
builder.setChronometerCountDown(true);
@@ -1607,7 +1652,7 @@ public class SdlRouterService extends Service{
enterForeground(createConnectedNotificationText(),0,true);
if(packetWriteTaskMasterMap == null){
- packetWriteTaskMasterMap = new HashMap<>();
+ packetWriteTaskMasterMap = new ConcurrentHashMap<>();
}
TransportType type = record.getType();
@@ -1615,6 +1660,7 @@ public class SdlRouterService extends Service{
if(packetWriteTaskMaster!=null){
packetWriteTaskMaster.close();
+ packetWriteTaskMaster.alert();
}
packetWriteTaskMaster = new PacketWriteTaskMaster();
packetWriteTaskMaster.setTransportType(type);
@@ -1670,6 +1716,9 @@ public class SdlRouterService extends Service{
public void onTransportDisconnected(TransportRecord record){
cachedModuleVersion = -1; //Reset our cached version
+ //Stop any current pings being sent before the proper state can be determined.
+ stopClientPings();
+
if(registeredApps != null && !registeredApps.isEmpty()){
Message message = Message.obtain();
message.what = TransportConstants.HARDWARE_CONNECTION_EVENT;
@@ -1686,7 +1735,61 @@ public class SdlRouterService extends Service{
message.setData(bundle);
notifyClients(message);
+
+ synchronized (REGISTERED_APPS_LOCK) {
+ Collection<RegisteredApp> apps = registeredApps.values();
+ for (RegisteredApp app : apps) {
+ app.unregisterTransport(-1,record.getType());
+
+ }
+ }
}
+ //Remove and close the packet task master assigned to this transport
+ if(packetWriteTaskMasterMap != null
+ && record != null
+ && packetWriteTaskMasterMap.containsKey(record.getType())){
+ PacketWriteTaskMaster master = packetWriteTaskMasterMap.remove(record.getType());
+ if(master != null){
+ master.close();
+ master.alert();
+ }
+ }
+ //Ensure the associated transport is dealt with
+ switch (record.getType()){
+ case BLUETOOTH:
+ synchronized(SESSION_LOCK){
+ if(bluetoothSessionMap!= null){
+ bluetoothSessionMap.clear();
+ }
+ }
+ if(!connectAsClient ){
+ if(!legacyModeEnabled && !closing){
+ initBluetoothSerialService();
+ }
+ }
+ break;
+ case USB:
+ if(usbTransport != null){
+ usbTransport = null;
+ }
+ synchronized(SESSION_LOCK){
+ if(usbSessionMap!= null){
+ usbSessionMap.clear();
+ }
+ }
+ break;
+ case TCP:
+ if(tcpTransport != null){
+ tcpTransport = null;
+ }
+ synchronized(SESSION_LOCK){
+ if(tcpSessionMap!=null){
+ tcpSessionMap.clear();
+ }
+ }
+ break;
+ }
+
if(!getConnectedTransports().isEmpty()){
// Updates notification to one of still connected transport
enterForeground(createConnectedNotificationText(),0,true);
@@ -1701,32 +1804,12 @@ public class SdlRouterService extends Service{
if(altTransportService!=null){ //If we still have an alt transport open, then we don't need to tell the clients to close
return;
}
- switch (record.getType()){
- case BLUETOOTH:
- if(!connectAsClient ){
- if(!legacyModeEnabled && !closing){
- initBluetoothSerialService();
- }
- }
- break;
- case USB:
- break;
- case TCP:
- break;
- }
- Log.e(TAG, "Notifying client service of hardware disconnect.");
- stopClientPings();
+ Log.e(TAG, "Notifying client service of hardware disconnect.");
- PacketWriteTaskMaster packetWriteTaskMaster = packetWriteTaskMasterMap.remove(record.getType());
- if(packetWriteTaskMaster!=null){
- packetWriteTaskMaster.close();
- }
-
//We've notified our clients, less clean up the mess now.
synchronized(SESSION_LOCK){
- this.bluetoothSessionMap.clear();
this.sessionHashIdMap.clear();
}
synchronized(REGISTERED_APPS_LOCK){
@@ -2855,7 +2938,7 @@ public class SdlRouterService extends Service{
int priorityForBuffingMessage;
DeathRecipient deathNote = null;
//Packet queue vars
- final HashMap<TransportType, PacketWriteTaskBlockingQueue> queues;
+ final ConcurrentHashMap<TransportType, PacketWriteTaskBlockingQueue> queues;
Handler queueWaitHandler;
Runnable queueWaitRunnable = null;
boolean queuePaused = false;
@@ -2873,7 +2956,7 @@ public class SdlRouterService extends Service{
this.appId = appId;
this.messenger = messenger;
this.sessionIds = new Vector<Long>();
- this.queues = new HashMap<>();
+ this.queues = new ConcurrentHashMap<>();
queueWaitHandler = new Handler();
registeredTransports = new SparseArray<ArrayList<TransportType>>();
awaitingSession = new Vector<>();
@@ -2891,7 +2974,7 @@ public class SdlRouterService extends Service{
this.appId = appId;
this.messenger = messenger;
this.sessionIds = new Vector<Long>();
- this.queues = new HashMap<>();
+ this.queues = new ConcurrentHashMap<>();
queueWaitHandler = new Handler();
registeredTransports = new SparseArray<ArrayList<TransportType>>();
awaitingSession = new Vector<>();
@@ -3049,14 +3132,25 @@ public class SdlRouterService extends Service{
}
}
- protected boolean unregisterTransport(int sessionId, TransportType transportType){
+ protected boolean unregisterTransport(int sessionId, @NonNull TransportType transportType){
+ if(queues != null && queues.containsValue(transportType)){
+ PacketWriteTaskBlockingQueue queue = queues.remove(transportType);
+ queue.clear();
+ }
synchronized (TRANSPORT_LOCK){
- if(this.registeredTransports.indexOfKey(sessionId) >= 0){
+ if(sessionId == -1){
+ int size = this.registeredTransports.size();
+ for(int i = 0; i <size; i++){
+ this.registeredTransports.valueAt(i).remove(transportType);
+ }
+ return true;
+ }else if(this.registeredTransports.indexOfKey(sessionId) >= 0){
return this.registeredTransports.get(sessionId).remove(transportType);
}else{
return false;
}
}
+
}
protected void unregisterAllTransports(int sessionId){
@@ -3066,7 +3160,7 @@ public class SdlRouterService extends Service{
}else if(sessionId == -1){
int size = this.registeredTransports.size();
for(int i = 0; i <size; i++){
- this.registeredTransports.get(i).clear();
+ this.registeredTransports.valueAt(i).clear();
}
}
}
@@ -3347,6 +3441,7 @@ public class SdlRouterService extends Service{
public PacketWriteTaskMaster(){
this.setName("PacketWriteTaskMaster");
+ this.setDaemon(true);
}
protected void setTransportType(TransportType transportType){
this.transportType = transportType;
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/TransportBroker.java b/sdl_android/src/main/java/com/smartdevicelink/transport/TransportBroker.java
index 21e9fedef..7bdd10857 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/TransportBroker.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/TransportBroker.java
@@ -118,6 +118,7 @@ public class TransportBroker {
Log.d(TAG, "Unbound from service " + className.getClassName());
routerServiceMessenger = null;
registeredWithRouterService = false;
+ unBindFromRouterService();
isBound = false;
onHardwareDisconnected(null, null);
}
@@ -446,6 +447,7 @@ public class TransportBroker {
routerServiceMessenger = null;
queuedOnTransportConnect = null;
unBindFromRouterService();
+ isBound = false;
}
}
@@ -464,12 +466,13 @@ public class TransportBroker {
}
}
- private void unBindFromRouterService() {
+ private synchronized void unBindFromRouterService() {
try {
- if (getContext() != null && routerConnection != null) {
+ if (isBound && getContext() != null && routerConnection != null) {
getContext().unbindService(routerConnection);
+ isBound = false;
} else {
- Log.w(TAG, "Unable to unbind from router service, context was null");
+ Log.w(TAG, "Unable to unbind from router service. bound? " + isBound + " context? " + (getContext()!=null) + " router connection?" + (routerConnection != null));
}
} catch (IllegalArgumentException e) {
@@ -652,6 +655,10 @@ public class TransportBroker {
@SuppressLint("InlinedApi")
private boolean sendBindingIntent() {
+ if(this.isBound){
+ Log.e(TAG, "Already bound");
+ return false;
+ }
if (this.routerPackage != null && this.routerClassName != null) {
Log.d(TAG, "Sending bind request to " + this.routerPackage + " - " + this.routerClassName);
Intent bindingIntent = new Intent();
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java b/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java
index eb0e28190..5892390cd 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java
@@ -116,6 +116,10 @@ public class TransportManager {
}
}
+ public void resetSession(){
+ transport.resetSession();
+ }
+
/**
* Check to see if a transport is connected.
* @param transportType the transport to have its connection status returned. If `null` is
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java b/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java
index 4b878c2aa..878715147 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java
@@ -98,7 +98,6 @@ public class USBAccessoryAttachmentActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- checkUsbAccessoryIntent("Create");
}
@Override
@@ -107,7 +106,16 @@ public class USBAccessoryAttachmentActivity extends Activity {
checkUsbAccessoryIntent("Resume");
}
- private void checkUsbAccessoryIntent(String sourceAction) {
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ this.setIntent(intent);
+ }
+
+ private synchronized void checkUsbAccessoryIntent(String sourceAction) {
+ if(usbAccessory != null){
+ return;
+ }
final Intent intent = getIntent();
String action = intent.getAction();
Log.d(TAG, sourceAction + " with action: " + action);
@@ -118,8 +126,16 @@ public class USBAccessoryAttachmentActivity extends Activity {
wakeUpRouterService(getApplicationContext());
+ }else{
+ finish();
}
+ }
+ @Override
+ protected void onDestroy() {
+ usbAccessory = null;
+ permissionGranted = null;
+ super.onDestroy();
}
@SuppressWarnings("deprecation")
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/UsbTransferProvider.java b/sdl_android/src/main/java/com/smartdevicelink/transport/UsbTransferProvider.java
index 9657a2c27..1479fa9e1 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/UsbTransferProvider.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/UsbTransferProvider.java
@@ -40,6 +40,7 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -51,6 +52,8 @@ import android.os.RemoteException;
import android.util.Log;
import com.smartdevicelink.util.AndroidTools;
+
+import java.io.IOException;
import java.lang.ref.WeakReference;
@TargetApi(12)
@@ -103,12 +106,13 @@ public class UsbTransferProvider {
if(context == null || service == null || usbAccessory == null){
throw new IllegalStateException("Supplied params are not correct. Context == null? "+ (context==null) + " ComponentName == null? " + (service == null) + " Usb Accessory == null? " + usbAccessory);
}
- this.context = context;
- this.routerService = service;
- this.callback = callback;
- this.clientMessenger = new Messenger(new ClientHandler(this));
- usbPfd = getFileDescriptor(usbAccessory);
- if(usbPfd != null){
+ usbPfd = getFileDescriptor(usbAccessory, context);
+ if(usbPfd != null && usbPfd.getFileDescriptor() != null && usbPfd.getFileDescriptor().valid()){
+ this.context = context;
+ this.routerService = service;
+ this.callback = callback;
+ this.clientMessenger = new Messenger(new ClientHandler(this));
+
usbInfoBundle = new Bundle();
usbInfoBundle.putString(MultiplexUsbTransport.MANUFACTURER, usbAccessory.getManufacturer());
usbInfoBundle.putString(MultiplexUsbTransport.MODEL, usbAccessory.getModel());
@@ -117,20 +121,28 @@ public class UsbTransferProvider {
usbInfoBundle.putString(MultiplexUsbTransport.SERIAL, usbAccessory.getSerial());
usbInfoBundle.putString(MultiplexUsbTransport.DESCRIPTION, usbAccessory.getDescription());
checkIsConnected();
+ }else{
+ Log.e(TAG, "Unable to open accessory");
+ clientMessenger = null;
+ if(callback != null){
+ callback.onUsbTransferUpdate(false);
+ }
}
}
@SuppressLint("NewApi")
- private ParcelFileDescriptor getFileDescriptor(UsbAccessory accessory) {
- try {
- UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
+ private ParcelFileDescriptor getFileDescriptor(UsbAccessory accessory, Context context) {
+ if (AndroidTools.isUSBCableConnected(context)) {
+ try {
+ UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
- if (manager != null) {
- return manager.openAccessory(accessory);
+ if (manager != null) {
+ return manager.openAccessory(accessory);
+ }
+ } catch (Exception e) {
}
- }catch (Exception e){}
-
+ }
return null;
}
@@ -181,11 +193,19 @@ public class UsbTransferProvider {
}
private void finish(){
- if(callback != null){
- callback.onUsbTransferUpdate(true);
+ try {
+ usbPfd.close();
+ } catch (IOException e) {
+ e.printStackTrace();
}
+ usbPfd = null;
unBindFromService();
routerServiceMessenger =null;
+ context = null;
+ System.gc();
+ if(callback != null){
+ callback.onUsbTransferUpdate(true);
+ }
}
static class ClientHandler extends Handler {
diff --git a/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java b/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
index 62f379031..4237845b7 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
@@ -35,11 +35,13 @@ package com.smartdevicelink.util;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.os.BatteryManager;
import com.smartdevicelink.transport.TransportConstants;
@@ -160,4 +162,15 @@ public class AndroidTools {
}
}
+ /**
+ * Checks if the usb cable is physically connected or not
+ * Note: the intent here is a sticky intent so registerReceiver is actually a synchronous call and doesn't register a receiver on each call
+ * @param context a context instance
+ * @return boolean value that represents whether the usb cable is physically connected or not
+ */
+ public static boolean isUSBCableConnected(Context context) {
+ Intent intent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+ int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+ return plugged == BatteryManager.BATTERY_PLUGGED_AC || plugged == BatteryManager.BATTERY_PLUGGED_USB;
+ }
}
diff --git a/sdl_android/src/main/res/values/sdl.xml b/sdl_android/src/main/res/values/sdl.xml
index ca8b15851..8ee8f70cb 100644
--- a/sdl_android/src/main/res/values/sdl.xml
+++ b/sdl_android/src/main/res/values/sdl.xml
@@ -2,7 +2,7 @@
<resources>
<string name="sdl_router_service_version_name" translatable="false">sdl_router_version</string>
- <integer name="sdl_router_service_version_value">8</integer>
+ <integer name="sdl_router_service_version_value">9</integer>
<string name="sdl_router_service_is_custom_name" translatable="false">sdl_custom_router</string>
</resources>