summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBilal Alsharifi <bilal.alsharifi@gmail.com>2021-09-14 15:01:38 -0400
committerBilal Alsharifi <bilal.alsharifi@gmail.com>2021-09-14 15:01:38 -0400
commitd0a76254a19ab5c1a145164dfc3695b04b3be62f (patch)
treef860db7339ce001e91f1d467654d86d45322e5c0
parent7b02f590d60f957e315c13cd9b4ffd8796b7cd34 (diff)
parent732801d16f2e90cd852c818b57876a985bc031cf (diff)
downloadsdl_android-d0a76254a19ab5c1a145164dfc3695b04b3be62f.tar.gz
Merge branch 'develop' into feature/issue_1605_menu_manager_refactor
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/video/HapticInterfaceManagerTest.java59
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/VehicleTypeTest.java14
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java119
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java37
-rw-r--r--android/sdl_android/src/androidTest/res/xml/supported_vehicle_type.xml12
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java2
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java27
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java3
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/protocol/heartbeat/HeartbeatMonitor.java2
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java5
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java47
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java105
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java8
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java2
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/transport/utl/SdlDeviceListener.java103
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java169
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java2
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java193
-rw-r--r--android/sdl_android/src/main/res/values/sdl.xml3
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseLifecycleManager.java11
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/screen/choiceset/BaseChoiceSetManager.java15
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/screen/choiceset/PreloadChoicesOperation.java24
-rw-r--r--base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java12
-rw-r--r--base/src/main/java/com/smartdevicelink/proxy/rpc/TireStatus.java320
-rw-r--r--base/src/main/java/com/smartdevicelink/proxy/rpc/VehicleType.java13
-rw-r--r--base/src/main/java/com/smartdevicelink/session/BaseSdlSession.java17
-rw-r--r--base/src/main/java/com/smartdevicelink/transport/TransportConstants.java1
27 files changed, 1153 insertions, 172 deletions
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/video/HapticInterfaceManagerTest.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/video/HapticInterfaceManagerTest.java
index dc74cb12a..bd75e2440 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/video/HapticInterfaceManagerTest.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/video/HapticInterfaceManagerTest.java
@@ -21,6 +21,7 @@
**************************************************************************************************/
package com.smartdevicelink.managers.video;
+import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
@@ -45,9 +46,7 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
-import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnitRunner;
-import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.List;
@@ -56,7 +55,6 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -222,36 +220,53 @@ public class HapticInterfaceManagerTest extends TestCase {
}
private View createViews() {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
- View view = mock(View.class);
+ final View view = new View(context) {
+ private int count = 0;
- ViewGroup parent1 = mock(ViewGroup.class);
- ViewGroup parent2 = mock(ViewGroup.class);
+ @Override
+ public boolean isClickable() {
+ int curCount = count++;
+ return (curCount >= 1) && (curCount <= 4);
+ }
+ };
- when(parent1.getChildCount()).thenReturn(5);
+ final ViewGroup parent1 = new ViewGroup(context) {
+ @Override
+ protected void onLayout(boolean b, int i, int i1, int i2, int i3) {}
- when(parent1.getChildAt(0)).thenReturn(view);
- when(parent1.getChildAt(1)).thenReturn(view);
- when(parent1.getChildAt(2)).thenReturn(view);
- when(parent1.getChildAt(3)).thenReturn(parent2);
- when(parent1.getChildAt(4)).thenReturn(view);
+ @Override
+ public View getChildAt(int index) {
+ return view;
+ }
- when(parent2.getChildCount()).thenReturn(2);
- when(parent2.getChildAt(0)).thenReturn(view);
- when(parent2.getChildAt(1)).thenReturn(view);
+ @Override
+ public int getChildCount() {
+ return 2;
+ }
+ };
+ final ViewGroup parent2 = new ViewGroup(context) {
+ @Override
+ protected void onLayout(boolean b, int i, int i1, int i2, int i3) {}
- doAnswer(new Answer<Boolean>() {
- private int count = 0;
+ @Override
+ public View getChildAt(int index) {
+ if (index == 3) {
+ return parent1;
+ } else {
+ return view;
+ }
+ }
@Override
- public Boolean answer(InvocationOnMock invocation) throws Throwable {
- int curCount = count++;
- return (curCount >= 1) && (curCount <= 4);
+ public int getChildCount() {
+ return 5;
}
- }).when(view).isClickable();
+ };
- return parent1;
+ return parent2;
}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/VehicleTypeTest.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/VehicleTypeTest.java
index a77de7473..9bb432e51 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/VehicleTypeTest.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/VehicleTypeTest.java
@@ -8,7 +8,10 @@ import junit.framework.TestCase;
import org.json.JSONException;
import org.json.JSONObject;
+import org.junit.Assert;
+import java.util.HashMap;
+import java.util.Hashtable;
import java.util.Iterator;
public class VehicleTypeTest extends TestCase {
@@ -72,4 +75,15 @@ public class VehicleTypeTest extends TestCase {
fail(TestValues.JSON_FAIL);
}
}
+
+ public void testHashMapConstructor() {
+ Hashtable<String, Object> store = msg.getStore();
+ HashMap<String, Object> hashMap = new HashMap(store);
+ VehicleType type = new VehicleType(hashMap);
+
+ Assert.assertEquals(type.getMake(), msg.getMake());
+ Assert.assertEquals(type.getModel(), msg.getModel());
+ Assert.assertEquals(type.getModelYear(), msg.getModelYear());
+ Assert.assertEquals(type.getTrim(), msg.getTrim());
+ }
} \ No newline at end of file
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java
index 7909d4997..1dfa0700b 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java
@@ -42,6 +42,8 @@ import android.os.Bundle;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.smartdevicelink.R;
+import com.smartdevicelink.proxy.rpc.VehicleType;
+import com.smartdevicelink.test.TestValues;
import com.smartdevicelink.util.SdlAppInfo;
import org.junit.Before;
@@ -49,10 +51,12 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertNotNull;
@@ -85,7 +89,7 @@ public class SdlAppInfoTests {
@Test
public void testConstructorWithDefaultData() {
- SdlAppInfo info = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo);
+ SdlAppInfo info = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo, context);
assertNotNull(info);
@@ -105,10 +109,10 @@ public class SdlAppInfoTests {
*/
@Test
public void testCompareVersion() {
- SdlAppInfo defaultInfo = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo);
+ SdlAppInfo defaultInfo = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo, context);
int newVersion = context.getResources().getInteger(R.integer.sdl_router_service_version_value) + 1;
- SdlAppInfo testInfo = new SdlAppInfo(createResolveInfo(newVersion, "com.smartdevicelink.test2", "com.smartdevicelink.test2.SdlRouterService", false), defaultPackageInfo);
+ SdlAppInfo testInfo = new SdlAppInfo(createResolveInfo(newVersion, "com.smartdevicelink.test2", "com.smartdevicelink.test2.SdlRouterService", false), defaultPackageInfo, context);
List<SdlAppInfo> infos = new ArrayList<>();
infos.add(defaultInfo);
@@ -126,10 +130,10 @@ public class SdlAppInfoTests {
*/
@Test
public void testCompareVersionAndCustom() {
- SdlAppInfo defaultInfo = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo);
+ SdlAppInfo defaultInfo = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo, context);
int newVersion = context.getResources().getInteger(R.integer.sdl_router_service_version_value) + 1;
- SdlAppInfo testInfo = new SdlAppInfo(createResolveInfo(newVersion, "com.smartdevicelink.test2", "com.smartdevicelink.test2.SdlRouterService", true), defaultPackageInfo);
+ SdlAppInfo testInfo = new SdlAppInfo(createResolveInfo(newVersion, "com.smartdevicelink.test2", "com.smartdevicelink.test2.SdlRouterService", true), defaultPackageInfo, context);
List<SdlAppInfo> infos = new ArrayList<>();
infos.add(defaultInfo);
@@ -147,12 +151,12 @@ public class SdlAppInfoTests {
*/
@Test
public void testCompareUpdatedTime() {
- SdlAppInfo defaultInfo = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo);
+ SdlAppInfo defaultInfo = new SdlAppInfo(defaultResolveInfo, defaultPackageInfo, context);
PackageInfo packageInfo = new PackageInfo();
packageInfo.firstInstallTime = defaultPackageInfo.firstInstallTime;
packageInfo.lastUpdateTime = defaultPackageInfo.lastUpdateTime + 500;
- SdlAppInfo testInfo = new SdlAppInfo(defaultResolveInfo, packageInfo);
+ SdlAppInfo testInfo = new SdlAppInfo(defaultResolveInfo, packageInfo, context);
List<SdlAppInfo> infos = new ArrayList<>();
infos.add(defaultInfo);
@@ -179,5 +183,106 @@ public class SdlAppInfoTests {
return info;
}
+ @Test
+ public void testDeserializeVehicleInfo() {
+ VehicleType type = new VehicleType();
+ type.setMake("SDL");
+ type.setModel("Car");
+ type.setModelYear("2019");
+ type.setTrim("GT");
+ List<VehicleType> deserializedList = SdlAppInfo.deserializeSupportedVehicles(getInstrumentation().getContext().getResources().getXml(com.smartdevicelink.test.R.xml.supported_vehicle_type));
+ assertTrue(deserializedList.contains(type));
+ assertEquals(1, deserializedList.size());
+ }
+
+ @Test
+ public void testVehicleTypeSupported() {
+ // tests check with all params
+ VehicleType type1 = new VehicleType();
+ type1.setMake(TestValues.GENERAL_STRING);
+ type1.setModel(TestValues.GENERAL_STRING);
+ type1.setMake(TestValues.GENERAL_STRING);
+ type1.setTrim(TestValues.GENERAL_STRING);
+
+ VehicleType type2 = new VehicleType();
+ type2.setMake(TestValues.GENERAL_STRING);
+ type2.setModel(TestValues.GENERAL_STRING);
+ type2.setModelYear(TestValues.GENERAL_INTEGER.toString());
+ type2.setTrim(TestValues.GENERAL_STRING);
+
+ List<VehicleType> supportedVehicleList = Arrays.asList(type1, type2);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(supportedVehicleList, type2));
+
+ // tests check with not all params in connectedVehicle
+ VehicleType connectedVehicle = new VehicleType();
+
+ // make only param
+ connectedVehicle.setMake(TestValues.GENERAL_STRING);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(supportedVehicleList, connectedVehicle));
+
+ // make and model params
+ connectedVehicle.setModel(TestValues.GENERAL_STRING);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(supportedVehicleList, connectedVehicle));
+
+ // make, model and year params
+ connectedVehicle.setModelYear(TestValues.GENERAL_STRING);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(supportedVehicleList, connectedVehicle));
+
+ // make, model and trim params
+ connectedVehicle.setModelYear(null);
+ connectedVehicle.setTrim(TestValues.GENERAL_STRING);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(supportedVehicleList, connectedVehicle));
+
+ // tests check with not all params in supportedVehicle
+ VehicleType supportedVehicle = new VehicleType();
+ supportedVehicle.setMake(TestValues.GENERAL_STRING);
+
+ // make param only
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(Collections.singletonList(supportedVehicle), connectedVehicle));
+
+ // make and model params
+ supportedVehicle.setModel(TestValues.GENERAL_STRING);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(Collections.singletonList(supportedVehicle), connectedVehicle));
+
+ // make, model and trim params
+ supportedVehicle.setTrim(TestValues.GENERAL_STRING);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(Collections.singletonList(supportedVehicle), connectedVehicle));
+
+ // make, model and trim params
+ supportedVehicle.setTrim(TestValues.GENERAL_STRING);
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(Collections.singletonList(supportedVehicle), connectedVehicle));
+
+ // make, model and trim params
+ connectedVehicle.setTrim(null);
+ connectedVehicle.setModelYear(TestValues.GENERAL_INTEGER.toString());
+ supportedVehicle.setModelYear(TestValues.GENERAL_INTEGER.toString());
+ assertTrue(SdlAppInfo.checkIfVehicleSupported(Collections.singletonList(supportedVehicle), connectedVehicle));
+ }
+
+ @Test
+ public void testVehicleTypeNotSupported() {
+ VehicleType type1 = new VehicleType();
+
+ type1.setModel(TestValues.GENERAL_STRING);
+ type1.setMake(TestValues.GENERAL_INTEGER.toString());
+ type1.setTrim(TestValues.GENERAL_STRING);
+ type1.setModelYear(TestValues.GENERAL_STRING);
+
+ VehicleType type2 = new VehicleType();
+
+ type2.setModel(TestValues.GENERAL_STRING);
+ type2.setMake(TestValues.GENERAL_INTEGER.toString());
+ type2.setTrim(TestValues.GENERAL_STRING);
+ type2.setModelYear(TestValues.GENERAL_STRING);
+
+ VehicleType type3 = new VehicleType();
+
+ type3.setModel(TestValues.GENERAL_STRING);
+ type3.setMake(TestValues.GENERAL_STRING);
+ type3.setTrim(TestValues.GENERAL_STRING);
+ type3.setModelYear(TestValues.GENERAL_INTEGER.toString());
+
+ assertFalse(SdlAppInfo.checkIfVehicleSupported(Arrays.asList(type1, type2), type3));
+ }
}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java
index 1ad01a1c3..c4104b585 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java
@@ -1,17 +1,26 @@
package com.smartdevicelink.test.utl;
import android.content.ComponentName;
+import android.content.Context;
+import android.content.SharedPreferences;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.smartdevicelink.proxy.rpc.VehicleType;
import com.smartdevicelink.util.AndroidTools;
import junit.framework.Assert;
+import org.json.JSONException;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
@RunWith(AndroidJUnit4.class)
public class AndroidToolsTests {
@@ -39,4 +48,32 @@ public class AndroidToolsTests {
}
+ @Test
+ public void testVehicleTypeSave() throws JSONException {
+ Context mMockContext = mock(Context.class);
+ VehicleType mMockVehicleType = new VehicleType();
+ String mAddress = "1234";
+
+ mMockVehicleType.setMake("Ford");
+ mMockVehicleType.setTrim("GT");
+ mMockVehicleType.setModel("Mustang");
+ mMockVehicleType.setModelYear("2019");
+
+ SharedPreferences.Editor editor = mock(SharedPreferences.Editor.class);
+ when(editor.commit()).thenReturn(true);
+
+ SharedPreferences sharedPrefs = Mockito.mock(SharedPreferences.class);
+ when(mMockContext.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
+ when(sharedPrefs.edit()).thenReturn(editor);
+ when(sharedPrefs.getString(mAddress, null)).thenReturn(mMockVehicleType.serializeJSON().toString());
+
+ AndroidTools.saveVehicleType(mMockContext, mMockVehicleType, mAddress);
+ VehicleType type = new VehicleType(AndroidTools.getVehicleTypeFromPrefs(mMockContext, mAddress));
+
+ org.junit.Assert.assertEquals(type.getMake(), mMockVehicleType.getMake());
+ org.junit.Assert.assertEquals(type.getModel(), mMockVehicleType.getModel());
+ org.junit.Assert.assertEquals(type.getModelYear(), mMockVehicleType.getModelYear());
+ org.junit.Assert.assertEquals(type.getTrim(), mMockVehicleType.getTrim());
+ }
+
}
diff --git a/android/sdl_android/src/androidTest/res/xml/supported_vehicle_type.xml b/android/sdl_android/src/androidTest/res/xml/supported_vehicle_type.xml
new file mode 100644
index 000000000..36e2fd169
--- /dev/null
+++ b/android/sdl_android/src/androidTest/res/xml/supported_vehicle_type.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resource>
+ <vehicle-type
+ make="SDL"
+ model="Car"
+ modelYear="2019"
+ trim="GT" />
+
+ <vehicle-type
+ make="SDL2"
+ modelYear="2019" />
+</resource> \ No newline at end of file
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java b/android/sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java
index 7c8df5b98..3eba6af30 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java
@@ -337,7 +337,7 @@ public class VirtualDisplayEncoder {
Looper.prepare();
// create a Handler for this thread
- mHandler = new Handler() {
+ mHandler = new Handler(Looper.myLooper()) {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_TICK: {
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java
index 1b54b0e1f..6d4fddb3d 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java
@@ -40,6 +40,7 @@ import com.smartdevicelink.exception.SdlException;
import com.smartdevicelink.exception.SdlExceptionCause;
import com.smartdevicelink.protocol.ISdlServiceListener;
import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.proxy.rpc.VehicleType;
import com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason;
import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
import com.smartdevicelink.security.SdlSecurityBase;
@@ -49,9 +50,12 @@ import com.smartdevicelink.transport.BaseTransportConfig;
import com.smartdevicelink.transport.MultiplexTransportConfig;
import com.smartdevicelink.transport.TCPTransportConfig;
import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
+import com.smartdevicelink.util.AndroidTools;
import com.smartdevicelink.util.DebugTool;
import java.lang.ref.WeakReference;
+import java.util.List;
/**
* The lifecycle manager creates a central point for all SDL session logic to converge. It should only be used by
@@ -98,6 +102,29 @@ public class LifecycleManager extends BaseLifecycleManager {
}
}
+ @Override
+ void saveVehicleType(String address, VehicleType type) {
+ AndroidTools.saveVehicleType(contextWeakReference.get(), type, address);
+ }
+
+ @Override
+ void saveVehicleType(List<TransportRecord> activeTransports, VehicleType type) {
+ if (activeTransports == null || activeTransports.isEmpty() || type == null) {
+ DebugTool.logWarning(TAG, "Unable to save vehicle type");
+ return;
+ }
+
+ for (TransportRecord record: activeTransports) {
+ if (record.getType() == TransportType.BLUETOOTH) {
+ String address = record.getAddress();
+ if (address != null && !address.isEmpty()) {
+ saveVehicleType(address, type);
+ }
+ break;
+ }
+ }
+ }
+
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setContext(Context context) {
this.contextWeakReference = new WeakReference<>(context);
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java
index 6f0e68aba..97e8c8bca 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java
@@ -38,6 +38,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.os.Handler;
+import android.os.Looper;
import androidx.annotation.RestrictTo;
@@ -227,7 +228,7 @@ public class LockScreenManager extends BaseSubManager {
mLockScreenShouldBeAutoDismissed = false;
}
if (!receivedFirstDDNotification) {
- new Handler().postDelayed(new Runnable() {
+ new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
launchLockScreenActivity();
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/protocol/heartbeat/HeartbeatMonitor.java b/android/sdl_android/src/main/java/com/smartdevicelink/protocol/heartbeat/HeartbeatMonitor.java
index c60cdaadf..831e59da4 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/protocol/heartbeat/HeartbeatMonitor.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/protocol/heartbeat/HeartbeatMonitor.java
@@ -155,7 +155,7 @@ public class HeartbeatMonitor implements IHeartbeatMonitor {
Looper.prepare();
mHeartbeatThreadLooper = Looper.myLooper();
- mHeartbeatThreadHandler = new Handler();
+ mHeartbeatThreadHandler = new Handler(mHeartbeatThreadLooper);
mIsAckReceived = true;
isHeartbeatReceived = true;
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java
index fba01a561..31cea21c8 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java
@@ -348,7 +348,10 @@ public class MultiplexBluetoothTransport extends MultiplexBaseTransport {
}
private void timerDelayRemoveDialog(final BluetoothSocket sock) {
- timeOutHandler = new Handler();
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ timeOutHandler = new Handler(Looper.myLooper());
socketRunnable = new Runnable() {
public void run() {
//Log.e(TAG, "BLUETOOTH SOCKET CONNECT TIMEOUT - ATTEMPT TO CLOSE SOCKET");
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java
index c86cb6d94..588b905cc 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java
@@ -49,6 +49,7 @@ import android.util.AndroidRuntimeException;
import androidx.annotation.CallSuper;
+import com.smartdevicelink.proxy.rpc.VehicleType;
import com.smartdevicelink.transport.RouterServiceValidator.TrustedListCallback;
import com.smartdevicelink.transport.enums.TransportType;
import com.smartdevicelink.transport.utl.SdlDeviceListener;
@@ -58,6 +59,8 @@ import com.smartdevicelink.util.IntegrationValidator;
import com.smartdevicelink.util.SdlAppInfo;
import com.smartdevicelink.util.ServiceFinder;
+import java.util.HashMap;
+import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Vector;
@@ -145,6 +148,15 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
DebugTool.logError(TAG, "You cannot use the default SdlRouterService class, it must be extended in your project. THIS WILL THROW AN EXCEPTION IN FUTURE RELEASES!!");
}
+ HashMap<String, Object> vehicleInfoStore = (HashMap<String, Object>) intent.getSerializableExtra(TransportConstants.VEHICLE_INFO_EXTRA);
+
+ VehicleType vehicleType;
+ if (vehicleInfoStore == null || vehicleInfoStore.isEmpty()) {
+ vehicleType = null;
+ } else {
+ vehicleType = new VehicleType(vehicleInfoStore);
+ }
+
//This will only be true if we are being told to reopen our SDL service because SDL is enabled
if (action.equalsIgnoreCase(TransportConstants.START_ROUTER_SERVICE_ACTION)) {
if (intent.hasExtra(TransportConstants.START_ROUTER_SERVICE_SDL_ENABLED_EXTRA)) {
@@ -178,7 +190,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
} else if (intent.getBooleanExtra(TransportConstants.PING_ROUTER_SERVICE_EXTRA, false)) {
//We were told to wake up our router services
boolean altServiceWake = intent.getBooleanExtra(TransportConstants.BIND_REQUEST_TYPE_ALT_TRANSPORT, false);
- didStart = wakeUpRouterService(context, false, altServiceWake, device);
+ didStart = wakeUpRouterService(context, false, altServiceWake, device, vehicleType);
}
}
@@ -189,7 +201,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
if (!didStart) {
DebugTool.logInfo(TAG, "attempting to wake up router service");
- didStart = wakeUpRouterService(context, true, false, device);
+ didStart = wakeUpRouterService(context, true, false, device, vehicleType);
}
//So even though we started our own version, on some older phones we find that two services are started up so we want to make sure we send our version that we are working with
@@ -211,8 +223,10 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
* @param componentName the router service that should be started
* @param altTransportWake if the alt transport flag should be set. Only used in debug
* @param device the connected bluetooth device
+ * @param confirmedDevice if the device is confirmed
+ * @param vehicleType vehicle params retrieved from connected device
*/
- private static void startRouterService(Context context, ComponentName componentName, boolean altTransportWake, BluetoothDevice device, boolean confirmedDevice) {
+ private static void startRouterService(Context context, ComponentName componentName, boolean altTransportWake, BluetoothDevice device, boolean confirmedDevice, VehicleType vehicleType) {
if (componentName == null) {
return;
}
@@ -232,6 +246,17 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
serviceIntent.putExtra(TransportConstants.CONFIRMED_SDL_DEVICE, confirmedDevice);
}
+ if (vehicleType == null) {
+ final String address = device != null ? device.getAddress() : null;
+ Hashtable<String, Object> store = AndroidTools.getVehicleTypeFromPrefs(context, address);
+ if (store != null) {
+ vehicleType = new VehicleType(store);
+ }
+ }
+ if (vehicleType != null) {
+ serviceIntent.putExtra(TransportConstants.VEHICLE_INFO_EXTRA, vehicleType.getStore());
+ }
+
try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
context.startService(serviceIntent);
@@ -254,7 +279,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
}
}
- private boolean wakeUpRouterService(final Context context, final boolean ping, final boolean altTransportWake, final BluetoothDevice device) {
+ private boolean wakeUpRouterService(final Context context, final boolean ping, final boolean altTransportWake, final BluetoothDevice device, final VehicleType vehicleType) {
new ServiceFinder(context, context.getPackageName(), new ServiceFinder.ServiceFinderCallback() {
@Override
public void onComplete(Vector<ComponentName> routerServices) {
@@ -263,7 +288,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
if (runningBluetoothServicePackage.isEmpty()) {
//If there isn't a service running we should try to start one
//We will try to sort the SDL enabled apps and find the one that's been installed the longest
- final List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator());
+ final List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator(), vehicleType);
synchronized (DEVICE_LISTENER_LOCK) {
final boolean sdlDeviceListenerEnabled = SdlDeviceListener.isFeatureSupported(sdlAppInfoList);
if (sdlDeviceListenerEnabled) {
@@ -294,7 +319,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
}
if (sdlAppInfoList != null && !sdlAppInfoList.isEmpty()) {
- startRouterService(context, sdlAppInfoList.get(0).getRouterServiceComponentName(), altTransportWake, device, false);
+ startRouterService(context, sdlAppInfoList.get(0).getRouterServiceComponentName(), altTransportWake, device, false, vehicleType);
} else {
DebugTool.logInfo(TAG, "No SDL Router Services found");
DebugTool.logInfo(TAG, "WARNING: This application has not specified its SdlRouterService correctly in the manifest. THIS WILL THROW AN EXCEPTION IN FUTURE RELEASES!!");
@@ -564,10 +589,16 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver {
synchronized (DEVICE_LISTENER_LOCK) {
sdlDeviceListener = null;
if (context != null) {
- final List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator());
+ VehicleType vehicleType = null;
+ final String address = bluetoothDevice != null ? bluetoothDevice.getAddress() : null;
+ Hashtable<String, Object> store = AndroidTools.getVehicleTypeFromPrefs(context, address);
+ if (store != null) {
+ vehicleType = new VehicleType(store);
+ }
+ final List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator(), vehicleType);
if (sdlAppInfoList != null && !sdlAppInfoList.isEmpty()) {
ComponentName routerService = sdlAppInfoList.get(0).getRouterServiceComponentName();
- startRouterService(context, routerService, false, bluetoothDevice, true);
+ startRouterService(context, routerService, false, bluetoothDevice, true, vehicleType);
}
}
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
index af63c9219..7f6eb2b40 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
@@ -89,6 +89,7 @@ import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.protocol.enums.MessageType;
import com.smartdevicelink.protocol.enums.SessionType;
import com.smartdevicelink.proxy.rpc.UnregisterAppInterface;
+import com.smartdevicelink.proxy.rpc.VehicleType;
import com.smartdevicelink.transport.enums.TransportType;
import com.smartdevicelink.transport.utl.ByteAraryMessageAssembler;
import com.smartdevicelink.transport.utl.ByteArrayMessageSpliter;
@@ -141,7 +142,7 @@ public class SdlRouterService extends Service {
/**
* <b> NOTE: DO NOT MODIFY THIS UNLESS YOU KNOW WHAT YOU'RE DOING.</b>
*/
- protected static final int ROUTER_SERVICE_VERSION_NUMBER = 14;
+ protected static final int ROUTER_SERVICE_VERSION_NUMBER = 15;
private static final String ROUTER_SERVICE_PROCESS = "com.smartdevicelink.router";
@@ -201,6 +202,7 @@ public class SdlRouterService extends Service {
private boolean wrongProcess = false;
private boolean initPassed = false;
private boolean hasCalledStartForeground = false;
+ boolean firstStart = true;
public static HashMap<String, RegisteredApp> registeredApps;
private SparseArray<String> bluetoothSessionMap, usbSessionMap, tcpSessionMap;
@@ -212,6 +214,7 @@ public class SdlRouterService extends Service {
private static Messenger altTransportService = null;
private boolean startSequenceComplete = false;
+ private VehicleType receivedVehicleType;
private ExecutorService packetExecutor = null;
ConcurrentHashMap<TransportType, PacketWriteTaskMaster> packetWriteTaskMasterMap = null;
@@ -1096,6 +1099,28 @@ public class SdlRouterService extends Service {
DebugTool.logError(TAG, "Service isn't exported. Shutting down");
return false;
}
+
+ ComponentName name = new ComponentName(this, this.getClass());
+ SdlAppInfo currentAppInfo = null;
+
+ List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(getApplicationContext(), new SdlAppInfo.BestRouterComparator(), null);
+ for (SdlAppInfo appInfo : sdlAppInfoList) {
+ if (appInfo.getRouterServiceComponentName().equals(name)) {
+ currentAppInfo = appInfo;
+ break;
+ }
+ }
+
+ if (currentAppInfo == null) {
+ DebugTool.logError(TAG, "AppInfo for current package is not available. Shutting down");
+ return false;
+ }
+
+ if (!SdlAppInfo.checkIfVehicleSupported(currentAppInfo.getSupportedVehicles(), receivedVehicleType)) {
+ DebugTool.logError(TAG, "Received vehicle data is not supported. Shutting down");
+ return false;
+ }
+
return true;
}
@@ -1118,37 +1143,13 @@ public class SdlRouterService extends Service {
hasCalledStartForeground = true;
resetForegroundTimeOut(FOREGROUND_TIMEOUT / 1000);
}
-
-
- if (!initCheck()) { // Run checks on process and permissions
- deployNextRouterService();
- closeSelf();
- return;
- }
- initPassed = true;
-
-
- synchronized (REGISTERED_APPS_LOCK) {
- registeredApps = new HashMap<String, RegisteredApp>();
- }
- closing = false;
-
- synchronized (SESSION_LOCK) {
- this.bluetoothSessionMap = new SparseArray<String>();
- this.sessionHashIdMap = new SparseIntArray();
- this.cleanedSessionMap = new SparseIntArray();
- }
-
- packetExecutor = Executors.newSingleThreadExecutor();
-
- startUpSequence();
}
/**
* The method will attempt to start up the next router service in line based on the sorting criteria of best router service.
*/
protected void deployNextRouterService() {
- List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(getApplicationContext(), new SdlAppInfo.BestRouterComparator());
+ List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(getApplicationContext(), new SdlAppInfo.BestRouterComparator(), null);
if (sdlAppInfoList != null && !sdlAppInfoList.isEmpty()) {
ComponentName name = new ComponentName(this, this.getClass());
SdlAppInfo info;
@@ -1250,6 +1251,37 @@ public class SdlRouterService extends Service {
@SuppressLint({"NewApi", "MissingPermission"})
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent != null && intent.hasExtra(TransportConstants.VEHICLE_INFO_EXTRA)) {
+ receivedVehicleType = new VehicleType(
+ (HashMap<String, Object>) intent.getSerializableExtra(TransportConstants.VEHICLE_INFO_EXTRA)
+ );
+ }
+ // Only trusting the first intent received to start the RouterService and run initial checks to avoid a case where an app could send incorrect data after the spp connection has started.
+ if (firstStart) {
+ firstStart = false;
+ if (!initCheck()) { // Run checks on process and permissions
+ deployNextRouterService();
+ closeSelf();
+ return START_REDELIVER_INTENT;
+ }
+ initPassed = true;
+
+
+ synchronized (REGISTERED_APPS_LOCK) {
+ registeredApps = new HashMap<String, RegisteredApp>();
+ }
+ closing = false;
+
+ synchronized (SESSION_LOCK) {
+ this.bluetoothSessionMap = new SparseArray<String>();
+ this.sessionHashIdMap = new SparseIntArray();
+ this.cleanedSessionMap = new SparseIntArray();
+ }
+
+ packetExecutor = Executors.newSingleThreadExecutor();
+
+ startUpSequence();
+ }
if (intent != null) {
if (intent.getBooleanExtra(FOREGROUND_EXTRA, false)) {
hasCalledStartForeground = false;
@@ -1410,7 +1442,10 @@ public class SdlRouterService extends Service {
public void resetForegroundTimeOut(long delay) {
synchronized (FOREGROUND_NOTIFICATION_LOCK) {
if (foregroundTimeoutHandler == null) {
- foregroundTimeoutHandler = new Handler();
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ foregroundTimeoutHandler = new Handler(Looper.myLooper());
}
if (foregroundTimeoutRunnable == null) {
foregroundTimeoutRunnable = new Runnable() {
@@ -1756,6 +1791,9 @@ public class SdlRouterService extends Service {
startService.putExtra(TransportConstants.FORCE_TRANSPORT_CONNECTED, true);
startService.putExtra(TransportConstants.START_ROUTER_SERVICE_SDL_ENABLED_APP_PACKAGE, getBaseContext().getPackageName());
startService.putExtra(TransportConstants.START_ROUTER_SERVICE_SDL_ENABLED_CMP_NAME, new ComponentName(this, this.getClass()));
+ if (receivedVehicleType != null) {
+ startService.putExtra(TransportConstants.VEHICLE_INFO_EXTRA, receivedVehicleType.getStore());
+ }
if (record != null && record.getType() != null) {
startService.putExtra(TransportConstants.START_ROUTER_SERVICE_TRANSPORT_CONNECTED, record.getType().toString());
@@ -2501,7 +2539,10 @@ public class SdlRouterService extends Service {
* This method is used to check for the newest version of this class to make sure the latest and greatest is up and running.
*/
private void startAltTransportTimer() {
- altTransportTimerHandler = new Handler();
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ altTransportTimerHandler = new Handler(Looper.myLooper());
altTransportTimerRunnable = new Runnable() {
public void run() {
altTransportTimerHandler = null;
@@ -2833,6 +2874,9 @@ public class SdlRouterService extends Service {
pingIntent.putExtra(TransportConstants.START_ROUTER_SERVICE_SDL_ENABLED_APP_PACKAGE, getBaseContext().getPackageName());
pingIntent.putExtra(TransportConstants.START_ROUTER_SERVICE_SDL_ENABLED_CMP_NAME, new ComponentName(SdlRouterService.this, SdlRouterService.this.getClass()));
pingIntent.putExtra(TransportConstants.START_ROUTER_SERVICE_SDL_ENABLED_PING, true);
+ if (receivedVehicleType != null) {
+ pingIntent.putExtra(TransportConstants.VEHICLE_INFO_EXTRA, receivedVehicleType.getStore());
+ }
}
private void startClientPings() {
@@ -3057,7 +3101,10 @@ public class SdlRouterService extends Service {
this.messenger = messenger;
this.sessionIds = new Vector<Long>();
this.queues = new ConcurrentHashMap<>();
- queueWaitHandler = new Handler();
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ queueWaitHandler = new Handler(Looper.myLooper());
registeredTransports = new SparseArray<ArrayList<TransportType>>();
awaitingSession = new Vector<>();
setDeathNote(); //messaging Version
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java
index a1392aace..6c3050301 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java
@@ -402,10 +402,10 @@ public class TransportManager extends TransportManagerBase {
return; //Already in legacy mode
}
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
if (transportListener.onLegacyModeEnabled(info)) {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
legacyBluetoothHandler = new LegacyBluetoothHandler(this);
legacyBluetoothTransport = new MultiplexBluetoothTransport(legacyBluetoothHandler);
if (contextWeakReference.get() != null) {
@@ -415,7 +415,7 @@ public class TransportManager extends TransportManagerBase {
contextWeakReference.get().registerReceiver(legacyDisconnectReceiver, intentFilter);
}
} else {
- new Handler().postDelayed(new Runnable() {
+ new Handler(Looper.myLooper()).postDelayed(new Runnable() {
@Override
public void run() {
transportListener.onError(info + " - Legacy mode unacceptable; shutting down.");
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java
index 604e3b435..8e54de9a1 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java
@@ -143,7 +143,7 @@ public class USBAccessoryAttachmentActivity extends Activity {
//If there isn't a service running we should try to start one
//We will try to sort the SDL enabled apps and find the one that's been installed the longest
Intent serviceIntent;
- List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator());
+ List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator(), null);
if (sdlAppInfoList != null && !sdlAppInfoList.isEmpty()) {
SdlAppInfo optimalRouterService = sdlAppInfoList.get(0);
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/utl/SdlDeviceListener.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/utl/SdlDeviceListener.java
index 23cdd9857..41ada091d 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/utl/SdlDeviceListener.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/utl/SdlDeviceListener.java
@@ -42,13 +42,22 @@ import android.os.Message;
import androidx.annotation.NonNull;
+import com.smartdevicelink.protocol.SdlPacket;
+import com.smartdevicelink.protocol.SdlPacketFactory;
+import com.smartdevicelink.protocol.enums.ControlFrameTags;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.proxy.rpc.VehicleType;
import com.smartdevicelink.transport.MultiplexBaseTransport;
import com.smartdevicelink.transport.MultiplexBluetoothTransport;
import com.smartdevicelink.transport.SdlRouterService;
+import com.smartdevicelink.util.AndroidTools;
+import com.smartdevicelink.util.BitConverter;
import com.smartdevicelink.util.DebugTool;
import com.smartdevicelink.util.SdlAppInfo;
+import com.smartdevicelink.util.Version;
import java.lang.ref.WeakReference;
+import java.util.Hashtable;
import java.util.List;
@@ -59,6 +68,9 @@ public class SdlDeviceListener {
private static final String SDL_DEVICE_STATUS_SHARED_PREFS = "sdl.device.status";
private static final Object LOCK = new Object(), RUNNING_LOCK = new Object();
+ // If increasing MAX PROTOCOL VERSION major version, make sure to alter it in SdlProtocolBase
+ private static final Version MAX_PROTOCOL_VERSION = new Version(5, 4, 0);
+
private final WeakReference<Context> contextWeakReference;
private final Callback callback;
private BluetoothDevice connectedDevice;
@@ -152,16 +164,10 @@ public class SdlDeviceListener {
case SdlRouterService.MESSAGE_STATE_CHANGE:
switch (msg.arg1) {
case MultiplexBaseTransport.STATE_CONNECTED:
- if(sdlListener.connectedDevice == null) {
+ if (sdlListener.connectedDevice == null) {
sdlListener.connectedDevice = sdlListener.bluetoothTransport.getConnectedDevice();
}
- sdlListener.setSDLConnectedStatus(sdlListener.contextWeakReference.get(), sdlListener.connectedDevice.getAddress(), true);
- boolean keepConnectionOpen = sdlListener.callback.onTransportConnected(sdlListener.contextWeakReference.get(), sdlListener.connectedDevice);
- if (!keepConnectionOpen) {
- sdlListener.bluetoothTransport.stop();
- sdlListener.bluetoothTransport = null;
- sdlListener.timeoutHandler.removeCallbacks(sdlListener.timeoutRunner);
- }
+ sendStartService();
break;
case MultiplexBaseTransport.STATE_NONE:
// We've just lost the connection
@@ -174,9 +180,90 @@ public class SdlDeviceListener {
break;
case com.smartdevicelink.transport.SdlRouterService.MESSAGE_READ:
+ onPacketRead((SdlPacket) msg.obj);
break;
}
}
+
+ /**
+ * This method will start the RPC service so that we can retrieve vehicle info
+ */
+ public void sendStartService() {
+ SdlDeviceListener sdlListener = this.provider.get();
+ SdlPacket serviceProbe = SdlPacketFactory.createStartSession(SessionType.RPC, 0x00, (byte)0x01, (byte)0x00, false);
+ serviceProbe.putTag(ControlFrameTags.RPC.StartService.PROTOCOL_VERSION, MAX_PROTOCOL_VERSION.toString());
+ byte[] constructed = serviceProbe.constructPacket();
+ if (sdlListener.bluetoothTransport != null && sdlListener.bluetoothTransport.getState() == MultiplexBluetoothTransport.STATE_CONNECTED) {
+ sdlListener.bluetoothTransport.write(constructed, 0, constructed.length);
+ } else {
+ sdlListener.callback.onTransportError(sdlListener.connectedDevice);
+ }
+ }
+
+ /**
+ * This method will pull vehicle data out of a StartServiceACK and then end the RPC session
+ *
+ * @param packet - info received from connected module
+ */
+ public void onPacketRead(SdlPacket packet) {
+ SdlDeviceListener sdlListener = this.provider.get();
+ VehicleType vehicleType = null;
+ if (packet.getFrameInfo() == SdlPacket.FRAME_INFO_START_SERVICE_ACK) {
+ int hashID;
+ if (packet.getVersion() >= 5) {
+ vehicleType = getVehicleType(packet);
+ hashID = (Integer) packet.getTag(ControlFrameTags.RPC.StartServiceACK.HASH_ID);
+ } else {
+ hashID = BitConverter.intFromByteArray(packet.getPayload(), 0);
+ }
+ byte[] stopService = SdlPacketFactory.createEndSession(SessionType.RPC, (byte)packet.getSessionId(), 0, (byte)packet.getVersion(), hashID).constructPacket();
+ if (sdlListener.bluetoothTransport != null && sdlListener.bluetoothTransport.getState() == MultiplexBluetoothTransport.STATE_CONNECTED) {
+ sdlListener.bluetoothTransport.write(stopService, 0, stopService.length);
+ }
+ notifyConnection(vehicleType);
+ }
+ }
+
+ /**
+ * Retrieves vehicle type from the StartServiceACK
+ *
+ * @param packet - info received from connected module
+ * @return vehicle type of connected module
+ */
+ private VehicleType getVehicleType(SdlPacket packet) {
+ String make = (String) packet.getTag(ControlFrameTags.RPC.StartServiceACK.MAKE);
+ String model = (String) packet.getTag(ControlFrameTags.RPC.StartServiceACK.MODEL);
+ String modelYear = (String) packet.getTag(ControlFrameTags.RPC.StartServiceACK.MODEL_YEAR);
+ String vehicleTrim = (String) packet.getTag(ControlFrameTags.RPC.StartServiceACK.TRIM);
+ if (make != null) {
+ // checking if tags have come from core
+ VehicleType type = new VehicleType();
+ type.setMake(make);
+ type.setModel(model);
+ type.setModelYear(modelYear);
+ type.setTrim(vehicleTrim);
+ return type;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Notify connection about vehicle type.
+ *
+ * @param vehicleType the information about the type of vehicle
+ */
+ public void notifyConnection(VehicleType vehicleType) {
+ SdlDeviceListener sdlListener = this.provider.get();
+ sdlListener.setSDLConnectedStatus(sdlListener.contextWeakReference.get(), sdlListener.connectedDevice.getAddress(), true);
+ AndroidTools.saveVehicleType(sdlListener.contextWeakReference.get(), vehicleType, sdlListener.connectedDevice.getAddress());
+ boolean keepConnectionOpen = sdlListener.callback.onTransportConnected(sdlListener.contextWeakReference.get(), sdlListener.connectedDevice);
+ if (!keepConnectionOpen) {
+ sdlListener.bluetoothTransport.stop();
+ sdlListener.bluetoothTransport = null;
+ sdlListener.timeoutHandler.removeCallbacks(sdlListener.timeoutRunner);
+ }
+ }
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java b/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
index 9109dc3ad..1f4ba2de0 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
@@ -36,18 +36,28 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.BatteryManager;
+import android.os.Bundle;
+import androidx.annotation.Nullable;
+import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.proxy.rpc.VehicleType;
import com.smartdevicelink.transport.TransportConstants;
+import org.json.JSONException;
+import org.json.JSONObject;
+
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.URL;
@@ -56,9 +66,16 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.Hashtable;
import java.util.List;
+
public class AndroidTools {
+
+ private static final String TAG = "AndroidTools";
+ private static final String SDL_DEVICE_VEHICLES_PREFS = "sdl.device.vehicles";
+ private static final Object VEHICLE_PREF_LOCK = new Object();
+
/**
* Check to see if a component is exported
*
@@ -97,7 +114,6 @@ public class AndroidTools {
return sdlMultiList;
}
-
/**
* Finds all SDL apps via their SdlRouterService manifest entry. It will return the metadata associated with that router service.
*
@@ -105,6 +121,7 @@ public class AndroidTools {
* @param comparator the Comparator to sort the resulting list. If null is supplied, they will be returned as they are from the system
* @return the sorted list of SdlAppInfo objects that represent SDL apps
*/
+ @Deprecated
public static List<SdlAppInfo> querySdlAppInfo(Context context, Comparator<SdlAppInfo> comparator) {
List<SdlAppInfo> sdlAppInfoList = new ArrayList<>();
Intent intent = new Intent(TransportConstants.ROUTER_SERVICE_ACTION);
@@ -118,7 +135,7 @@ public class AndroidTools {
PackageInfo packageInfo;
try {
packageInfo = packageManager.getPackageInfo(info.serviceInfo.packageName, 0);
- sdlAppInfoList.add(new SdlAppInfo(info, packageInfo));
+ sdlAppInfoList.add(new SdlAppInfo(info, packageInfo, context));
} catch (NameNotFoundException e) {
//Package was not found, likely a sign the resolve info can't be trusted.
}
@@ -134,6 +151,54 @@ public class AndroidTools {
return sdlAppInfoList;
}
+ /**
+ * Finds all SDL apps via their SdlRouterService manifest entry. It will return the metadata associated with that router service.
+ *
+ * @param context a context instance to obtain the package manager
+ * @param comparator the Comparator to sort the resulting list. If null is supplied, they will be returned as they are from the system
+ * @return the sorted list of SdlAppInfo objects that represent SDL apps
+ */
+ public static List<SdlAppInfo> querySdlAppInfo(Context context, Comparator<SdlAppInfo> comparator, VehicleType type) {
+ List<SdlAppInfo> sdlAppInfoList = new ArrayList<>();
+ Intent intent = new Intent(TransportConstants.ROUTER_SERVICE_ACTION);
+ List<ResolveInfo> resolveInfoList = context.getPackageManager().queryIntentServices(intent, PackageManager.GET_META_DATA);
+
+ if (resolveInfoList != null && resolveInfoList.size() > 0) {
+ PackageManager packageManager = context.getPackageManager();
+ if (packageManager != null) {
+
+ for (ResolveInfo info : resolveInfoList) {
+ PackageInfo packageInfo;
+ try {
+ packageInfo = packageManager.getPackageInfo(info.serviceInfo.packageName, 0);
+ SdlAppInfo appInformation = new SdlAppInfo(info, packageInfo, context);
+ sdlAppInfoList.add(appInformation);
+
+ } catch (NameNotFoundException e) {
+ //Package was not found, likely a sign the resolve info can't be trusted.
+ }
+
+ }
+ }
+
+ List<SdlAppInfo> sdlAppInfoListVehicleType = new ArrayList<>();
+
+ for (SdlAppInfo appInformation : sdlAppInfoList) {
+ if (appInformation.routerServiceVersion < 15) {
+ sdlAppInfoListVehicleType.add(appInformation);
+ } else if (SdlAppInfo.checkIfVehicleSupported(appInformation.supportedVehicles, type)) {
+ sdlAppInfoListVehicleType.add(appInformation);
+ }
+ }
+ sdlAppInfoList = sdlAppInfoListVehicleType;
+
+ if (comparator != null) {
+ Collections.sort(sdlAppInfoList, comparator);
+ }
+ }
+ return sdlAppInfoList;
+ }
+
/**
* Sends the provided intent to the specified destinations making it an explicit intent, rather
@@ -204,4 +269,104 @@ public class AndroidTools {
}
return false;
}
+
+ /**
+ * Saves the mac address along with vehicle details into user's shared prefs.
+ *
+ * @param context a context instance to obtain the shared preferences.
+ * @param vehicleType a RPCStruct that describes the type of vehicle the mobile phone is connected with.
+ * @param address a string containing the Bluetooth Mac address of the connected vehicle.
+ */
+ public static void saveVehicleType(Context context, VehicleType vehicleType, String address) {
+ synchronized (VEHICLE_PREF_LOCK) {
+ if (vehicleType == null || address == null || context == null) {
+ DebugTool.logWarning(TAG, String.format("Unable to save vehicle type. Context is %1$s, Address is %2$s and VehicleType is %3$s", context, address, vehicleType));
+ return;
+ }
+ try {
+ SharedPreferences preferences = context.getSharedPreferences(SDL_DEVICE_VEHICLES_PREFS, Context.MODE_PRIVATE);
+
+ String jsonString = vehicleType.serializeJSON().toString();
+ SharedPreferences.Editor editor = preferences.edit();
+ editor.putString(address, jsonString);
+ editor.commit();
+ } catch (JSONException e) {
+ DebugTool.logError(TAG, "Unable to serialize vehicle type to JSON.", e);
+ }
+ }
+ }
+
+ /**
+ * Retrieves the vehicle details by the mac address of the connected vehicle.
+ *
+ * @param context a context instance to obtain the shared preferences.
+ * @param address a string containing the Bluetooth Mac address of the connected vehicle.
+ * @return The Hashtable to be used to construct VehicleTyp
+ */
+ public static @Nullable Hashtable<String, Object> getVehicleTypeFromPrefs(Context context, String address) {
+ synchronized (VEHICLE_PREF_LOCK) {
+ if (context == null || address == null) {
+ DebugTool.logWarning(TAG, String.format("Unable to get vehicle type from prefs. Context is %1$s and Address is %2$s", context, address));
+ return null;
+ }
+ try {
+ SharedPreferences preferences = context.getSharedPreferences(SDL_DEVICE_VEHICLES_PREFS, Context.MODE_PRIVATE);
+ String storedVehicleTypeSerialized = preferences.getString(address, null);
+
+ if (storedVehicleTypeSerialized == null) {
+ return null;
+ } else {
+ JSONObject object = new JSONObject(storedVehicleTypeSerialized);
+ return JsonRPCMarshaller.deserializeJSONObject(object);
+ }
+ } catch (JSONException e) {
+ DebugTool.logError(TAG, "Unable to deserialize stored vehicle type.", e);
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Retrieves the list of vehicle types that are set in the manifest.
+ *
+ * @param context a context to access Android system services through.
+ * @param component a component name of a LocalRouterService.
+ * @param manifestFieldId a string resources id that indicates an unique name for the vehicle data in the manifest.
+ * @return The list of vehicle types, or null if an error occurred or field was not found.
+ */
+ public static @Nullable List<VehicleType> getVehicleTypesFromManifest(Context context, ComponentName component, int manifestFieldId) {
+ if (context == null || component == null) {
+ DebugTool.logWarning(TAG, String.format("Unable to get vehicle type from manifest. Context is %1$s and Component is %2$s", context, component));
+ return null;
+ }
+ try {
+ PackageManager pm = context.getPackageManager();
+ Resources resources = context.getResources();
+ if (pm == null || resources == null) {
+ DebugTool.logWarning(TAG, String.format("Unable to get vehicle type from manifest. PackageManager is %1$s and Resources is %2$s", pm, resources));
+ return null;
+ }
+
+ Bundle metaData = pm.getServiceInfo(component, PackageManager.GET_META_DATA).metaData;
+ if (metaData == null) {
+ DebugTool.logError(TAG, "metaData isn't available.");
+ return null;
+ }
+
+ int xmlFieldId = metaData.getInt(resources.getString(manifestFieldId));
+ if (xmlFieldId == 0) {
+ DebugTool.logError(TAG, "Field with id " + manifestFieldId + " was not found in manifest");
+ return null;
+ }
+
+ XmlResourceParser parser = resources.getXml(xmlFieldId);
+ return SdlAppInfo.deserializeSupportedVehicles(parser);
+ } catch (PackageManager.NameNotFoundException e) {
+ DebugTool.logError(TAG, "Failed to get OEM vehicle data filter: " + e.getMessage()+ " - assume vehicle data is supported");
+ return null;
+ } catch (Resources.NotFoundException ex) {
+ DebugTool.logError(TAG, "Failed to find resource: " + ex.getMessage()+ " - assume vehicle data is supported");
+ return null;
+ }
+ }
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java b/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java
index ba15ff4aa..8e904a45f 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java
@@ -198,7 +198,7 @@ public class IntegrationValidator {
boolean serviceFilterHasAction = false;
String className = localRouterClass.getName();
- List<SdlAppInfo> services = AndroidTools.querySdlAppInfo(context, null);
+ List<SdlAppInfo> services = AndroidTools.querySdlAppInfo(context, null, null);
for (SdlAppInfo sdlAppInfo : services) {
if (sdlAppInfo != null && sdlAppInfo.getRouterServiceComponentName() != null
&& className.equals((sdlAppInfo.getRouterServiceComponentName().getClassName()))) {
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java b/android/sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java
index d49e63575..7d5ade055 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java
@@ -33,11 +33,23 @@
package com.smartdevicelink.util;
import android.content.ComponentName;
+import android.content.Context;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
import android.os.Bundle;
+import com.smartdevicelink.proxy.rpc.VehicleType;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
import java.util.Comparator;
+import java.util.List;
/**
* Created by Joey Grover on 2/2/18.
@@ -49,15 +61,17 @@ public class SdlAppInfo {
//FIXME we shouldn't be duplicating constants, but this currently keeps us from needing a context instance.
private static final String SDL_ROUTER_VERSION_METADATA = "sdl_router_version";
private static final String SDL_CUSTOM_ROUTER_METADATA = "sdl_custom_router";
+ private static final String SDL_OEM_VEHICLE_TYPE_METADATA = "sdl_oem_vehicle_type";
String packageName;
ComponentName routerServiceComponentName;
int routerServiceVersion = 4; //We use this as a default and assume if the number doesn't exist in meta data it is because the app hasn't updated.
boolean isCustomRouterService = false;
+ List<VehicleType> supportedVehicles = new ArrayList<>();
long lastUpdateTime;
-
+ @Deprecated
public SdlAppInfo(ResolveInfo resolveInfo, PackageInfo packageInfo) {
if (resolveInfo.serviceInfo != null) {
@@ -89,6 +103,75 @@ public class SdlAppInfo {
}
}
+ public SdlAppInfo(ResolveInfo resolveInfo, PackageInfo packageInfo, Context context) {
+ if (resolveInfo.serviceInfo != null) {
+
+ this.packageName = resolveInfo.serviceInfo.packageName;
+ this.routerServiceComponentName = new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
+
+ Bundle metadata = resolveInfo.serviceInfo.metaData;
+ if (metadata != null) {
+
+ if (metadata.containsKey(SDL_ROUTER_VERSION_METADATA)) {
+ this.routerServiceVersion = metadata.getInt(SDL_ROUTER_VERSION_METADATA);
+ }
+
+ if (metadata.containsKey(SDL_CUSTOM_ROUTER_METADATA)) {
+ this.isCustomRouterService = metadata.getBoolean(SDL_CUSTOM_ROUTER_METADATA);
+ }
+
+ if (metadata.containsKey(SDL_OEM_VEHICLE_TYPE_METADATA)) {
+ if (context == null) {
+ DebugTool.logWarning(TAG, "Unable to deserialize supported vehicles: supplied Context is null");
+ return;
+ }
+
+ String contextPackageName = context.getPackageName();
+ if (contextPackageName == null || packageName == null) {
+ DebugTool.logWarning(TAG, String.format("Unable to deserialize supported vehicles. ContextPackageName: %1$s and PackageName: %2$s", contextPackageName, packageName));
+ return;
+ }
+
+ Resources resources = null;
+ if (!contextPackageName.equals(packageName)) {
+ try {
+ Context appContext = context.createPackageContext(packageName, 0);
+ if (appContext == null){
+ DebugTool.logError(TAG, "Failed to create context with the given package name");
+ return;
+ }
+ resources = appContext.getResources();
+ } catch (PackageManager.NameNotFoundException e) {
+ DebugTool.logError(TAG, "Failed to create context with the given package name: " + e.getMessage());
+ }
+ } else {
+ resources = context.getResources();
+ }
+
+ if (resources != null) {
+ try {
+ XmlResourceParser parser = resources.getXml(metadata.getInt(SDL_OEM_VEHICLE_TYPE_METADATA));
+ this.supportedVehicles = deserializeSupportedVehicles(parser);
+ } catch (Resources.NotFoundException ex) {
+ DebugTool.logError(TAG, "Failed to find resource: " + ex.getMessage());
+ }
+ }
+ }
+ } else {
+ DebugTool.logWarning(TAG, packageName + " has not supplied metadata with their router service!");
+ }
+ }
+
+ if (packageInfo != null) {
+ this.lastUpdateTime = packageInfo.lastUpdateTime;
+ if (this.lastUpdateTime <= 0) {
+ this.lastUpdateTime = packageInfo.firstInstallTime;
+ }
+ } else {
+ this.lastUpdateTime = 0;
+ }
+ }
+
public int getRouterServiceVersion() {
return routerServiceVersion;
}
@@ -122,12 +205,120 @@ public class SdlAppInfo {
builder.append("\nLast updated: ");
builder.append(this.lastUpdateTime);
+ builder.append("\nVehicle make list: ");
+ builder.append(this.supportedVehicles);
+
builder.append("\n-------- Sdl App Info End------");
return builder.toString();
}
/**
+ * Retrieves the list of vehicle types that are set in the xml file.
+ *
+ * @param parser The xml parsing interface for the vehicle types xml file.
+ * @return The list of vehicle types.
+ */
+ public static List<VehicleType> deserializeSupportedVehicles(XmlResourceParser parser) {
+ List<VehicleType> vehicleMakesList = new ArrayList<>();
+ if (parser == null) {
+ return vehicleMakesList;
+ }
+ try {
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG) {
+ String tagName = parser.getName();
+ if (tagName != null && tagName.equalsIgnoreCase("vehicle-type")) {
+ VehicleType vehicleMake = new VehicleType();
+ String make = parser.getAttributeValue(null, "make");
+ if (make != null) {
+ vehicleMake.setMake(make);
+ String model = parser.getAttributeValue(null, "model");
+ String modelYear = parser.getAttributeValue(null, "modelYear");
+ String trim = parser.getAttributeValue(null, "trim");
+
+ if (model == null && modelYear == null && trim == null) {
+ vehicleMakesList.add(vehicleMake);
+ } else if (model != null){
+ vehicleMake.setModel(model);
+ if (modelYear != null) {
+ vehicleMake.setModelYear(modelYear);
+ }
+ if (trim != null) {
+ vehicleMake.setTrim(trim);
+ }
+ vehicleMakesList.add(vehicleMake);
+ }
+ }
+ }
+ }
+ eventType = parser.next();
+ }
+ } catch (XmlPullParserException e) {
+ DebugTool.logError(TAG, "Failed to parse xml file", e);
+ } catch (IOException e) {
+ DebugTool.logError(TAG, "Failed to find next element in the xml file", e);
+ }
+ return vehicleMakesList;
+ }
+
+ /**
+ * Check to see if a vehicle type is supported.
+ *
+ * @param supportedVehicleList the list of supported vehicle types.
+ * @param connectedVehicle the vehicle type to check.
+ * @return true if vehicle type is supported.
+ */
+ public static boolean checkIfVehicleSupported(List<VehicleType> supportedVehicleList, VehicleType connectedVehicle) {
+ if (supportedVehicleList == null || supportedVehicleList.isEmpty() || connectedVehicle == null || connectedVehicle.getStore() == null|| connectedVehicle.getStore().isEmpty()) {
+ return true;
+ }
+ if (supportedVehicleList.contains(connectedVehicle)) {
+ return true;
+ }
+ for (VehicleType supportedVehicle: supportedVehicleList) {
+ boolean areVehicleMakesEqual = CompareUtils.areStringsEqual(supportedVehicle.getMake(), connectedVehicle.getMake(), true, false);
+ if (areVehicleMakesEqual) {
+ String supportedVehicleModel = supportedVehicle.getModel();
+ String connectedVehicleModel = connectedVehicle.getModel();
+ if (supportedVehicleModel != null && connectedVehicleModel != null) {
+ if (connectedVehicleModel.equalsIgnoreCase(supportedVehicleModel)) {
+ boolean ret = true;
+ String supportedVehicleModelYear = supportedVehicle.getModelYear();
+ String connectedVehicleModelYear = connectedVehicle.getModelYear();
+ if (supportedVehicleModelYear != null && connectedVehicleModelYear != null) {
+ ret = connectedVehicleModelYear.equalsIgnoreCase(supportedVehicleModelYear);
+ }
+ String supportedVehicleTrim = supportedVehicle.getTrim();
+ String connectedVehicleTrim = connectedVehicle.getTrim();
+ if (supportedVehicleTrim != null && connectedVehicleTrim != null) {
+ ret &= connectedVehicleTrim.equalsIgnoreCase(supportedVehicleTrim);
+ }
+ if (ret) {
+ // We found matches and return or continue iteration otherwise
+ return true;
+ }
+ }
+ } else {
+ // Return true if only make is defined and it matches
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Gets app's supported vehicle types.
+ *
+ * @return List<VehicleType> a list of supported vehicle types.
+ */
+ public List<VehicleType> getSupportedVehicles() {
+ return supportedVehicles;
+ }
+
+ /**
* This comparator will sort a list to find the best router service to start out of the known SDL enabled apps
*/
public static class BestRouterComparator implements Comparator<SdlAppInfo> {
diff --git a/android/sdl_android/src/main/res/values/sdl.xml b/android/sdl_android/src/main/res/values/sdl.xml
index 1d5f0897a..7bb919f0b 100644
--- a/android/sdl_android/src/main/res/values/sdl.xml
+++ b/android/sdl_android/src/main/res/values/sdl.xml
@@ -2,7 +2,8 @@
<resources>
<string name="sdl_router_service_version_name" translatable="false">sdl_router_version</string>
- <integer name="sdl_router_service_version_value">14</integer>
+ <integer name="sdl_router_service_version_value">15</integer>
<string name="sdl_router_service_is_custom_name" translatable="false">sdl_custom_router</string>
+ <string name="sdl_oem_vehicle_type_filter_name" translatable="false">sdl_oem_vehicle_type</string>
</resources>
diff --git a/base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseLifecycleManager.java b/base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseLifecycleManager.java
index 9cf72f7cd..6602e7085 100644
--- a/base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseLifecycleManager.java
+++ b/base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseLifecycleManager.java
@@ -90,6 +90,7 @@ import com.smartdevicelink.session.ISdlSessionListener;
import com.smartdevicelink.session.SdlSession;
import com.smartdevicelink.streaming.video.VideoStreamingParameters;
import com.smartdevicelink.transport.BaseTransportConfig;
+import com.smartdevicelink.transport.utl.TransportRecord;
import com.smartdevicelink.util.CorrelationIdGenerator;
import com.smartdevicelink.util.DebugTool;
import com.smartdevicelink.util.FileUtls;
@@ -104,7 +105,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
abstract class BaseLifecycleManager {
static final String TAG = "Lifecycle Manager";
- public static final Version MAX_SUPPORTED_RPC_VERSION = new Version(7, 1, 0);
+ public static final Version MAX_SUPPORTED_RPC_VERSION = new Version(8, 0, 0);
// Protected Correlation IDs
private final int REGISTER_APP_INTERFACE_CORRELATION_ID = 65529,
@@ -398,6 +399,7 @@ abstract class BaseLifecycleManager {
VehicleType vehicleType = raiResponse.getVehicleType();
String systemSoftwareVersion = raiResponse.getSystemSoftwareVersion();
if (vehicleType != null || systemSoftwareVersion != null) {
+ saveVehicleType(session.getActiveTransports(), vehicleType);
SystemInfo systemInfo = new SystemInfo(vehicleType, systemSoftwareVersion, null);
boolean validSystemInfo = lifecycleListener.onSystemInfoReceived(systemInfo);
if (!validSystemInfo) {
@@ -946,6 +948,7 @@ abstract class BaseLifecycleManager {
if (systemInfo != null && lifecycleListener != null) {
didCheckSystemInfo = true;
+ saveVehicleType(session.getActiveTransports(), systemInfo.getVehicleType());
boolean validSystemInfo = lifecycleListener.onSystemInfoReceived(systemInfo);
if (!validSystemInfo) {
DebugTool.logWarning(TAG, "Disconnecting from head unit, the system info was not accepted.");
@@ -1325,6 +1328,12 @@ abstract class BaseLifecycleManager {
abstract void cycle(SdlDisconnectedReason disconnectedReason);
+ void saveVehicleType(String address, VehicleType type){
+ }
+
+ void saveVehicleType(List<TransportRecord> activeTransports, VehicleType type) {
+ }
+
void onTransportDisconnected(String info, boolean availablePrimary, BaseTransportConfig transportConfig) {
}
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 893909718..4a60fa2a4 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
@@ -223,9 +223,9 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
pendingPreloadChoices.addAll(choicesToUpload);
if (fileManager.get() != null) {
- PreloadChoicesOperation preloadChoicesOperation = new PreloadChoicesOperation(internalInterface, fileManager.get(), displayName, defaultMainWindowCapability, isVROptional, choicesToUpload, new CompletionListener() {
+ PreloadChoicesOperation preloadChoicesOperation = new PreloadChoicesOperation(internalInterface, fileManager.get(), displayName, defaultMainWindowCapability, isVROptional, choicesToUpload, new BaseChoiceSetManager.ChoiceSetCompletionListener() {
@Override
- public void onComplete(boolean success) {
+ public void onComplete(boolean success, HashSet<ChoiceCell> failedChoiceCells) {
if (success) {
preloadedChoices.addAll(choicesToUpload);
pendingPreloadChoices.removeAll(choicesToUpload);
@@ -234,6 +234,9 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
}
} else {
DebugTool.logError(TAG, "There was an error pre loading choice cells");
+ choicesToUpload.removeAll(failedChoiceCells);
+ preloadedChoices.addAll(choicesToUpload);
+ pendingPreloadChoices.removeAll(choicesToUpload);
if (listener != null) {
listener.onComplete(false);
}
@@ -671,6 +674,14 @@ abstract class BaseChoiceSetManager extends BaseSubManager {
return null;
}
+ /**
+ * Interface that sends a list of ChoiceCells that failed to preload, to allow BaseChoioceSetManager
+ * to stop keeping track of them for their onButtonEventListener
+ */
+ interface ChoiceSetCompletionListener {
+ void onComplete(boolean success, HashSet<ChoiceCell> failedChoiceCells);
+ }
+
// LISTENERS
private void addListeners() {
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 8f47a2880..d98ae3517 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
@@ -70,13 +70,13 @@ class PreloadChoicesOperation extends Task {
private final WindowCapability defaultMainWindowCapability;
private final String displayName;
private final HashSet<ChoiceCell> cellsToUpload;
- private final CompletionListener completionListener;
+ private final BaseChoiceSetManager.ChoiceSetCompletionListener completionListener;
private boolean isRunning;
private final boolean isVROptional;
private boolean choiceError = false;
PreloadChoicesOperation(ISdl internalInterface, FileManager fileManager, String displayName, WindowCapability defaultMainWindowCapability,
- Boolean isVROptional, LinkedHashSet<ChoiceCell> cellsToPreload, CompletionListener listener) {
+ Boolean isVROptional, LinkedHashSet<ChoiceCell> cellsToPreload, BaseChoiceSetManager.ChoiceSetCompletionListener listener) {
super("PreloadChoicesOperation");
this.internalInterface = new WeakReference<>(internalInterface);
this.fileManager = new WeakReference<>(fileManager);
@@ -141,7 +141,7 @@ class PreloadChoicesOperation extends Task {
private void preloadCells() {
isRunning = true;
- List<CreateInteractionChoiceSet> choiceRPCs = new ArrayList<>(cellsToUpload.size());
+ final List<CreateInteractionChoiceSet> choiceRPCs = new ArrayList<>(cellsToUpload.size());
for (ChoiceCell cell : cellsToUpload) {
CreateInteractionChoiceSet csCell = choiceFromCell(cell);
if (csCell != null) {
@@ -151,13 +151,15 @@ class PreloadChoicesOperation extends Task {
if (choiceRPCs.size() == 0) {
DebugTool.logError(TAG, " All Choice cells to send are null, so the choice set will not be shown");
- completionListener.onComplete(true);
+ completionListener.onComplete(true, null);
isRunning = false;
return;
}
if (internalInterface.get() != null) {
internalInterface.get().sendRPCs(choiceRPCs, new OnMultipleRequestListener() {
+ final HashSet<ChoiceCell> failedChoiceCells = new HashSet<>();
+
@Override
public void onUpdate(int remainingRequests) {
@@ -167,7 +169,7 @@ class PreloadChoicesOperation extends Task {
public void onFinished() {
isRunning = false;
DebugTool.logInfo(TAG, "Finished pre loading choice cells");
- completionListener.onComplete(!choiceError);
+ completionListener.onComplete(!choiceError, !choiceError ? null : failedChoiceCells);
choiceError = false;
PreloadChoicesOperation.super.onFinished();
}
@@ -177,13 +179,23 @@ class PreloadChoicesOperation extends Task {
if (!response.getSuccess()) {
DebugTool.logError(TAG, "There was an error uploading a choice cell: " + response.getInfo() + " resultCode: " + response.getResultCode());
choiceError = true;
+ for (CreateInteractionChoiceSet choiceSet : choiceRPCs) {
+ if (choiceSet.getCorrelationID() == correlationId) {
+ int choiceId = choiceSet.getChoiceSet().get(0).getChoiceID();
+ for (ChoiceCell cell : cellsToUpload) {
+ if (cell.getChoiceId() == choiceId) {
+ failedChoiceCells.add(cell);
+ }
+ }
+ }
+ }
}
}
});
} else {
DebugTool.logError(TAG, "Internal Interface null in preload choice operation");
isRunning = false;
- completionListener.onComplete(false);
+ completionListener.onComplete(false, cellsToUpload);
}
}
diff --git a/base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java b/base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java
index 5cac1302c..14222a548 100644
--- a/base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java
+++ b/base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java
@@ -1566,5 +1566,17 @@ public class SdlProtocolBase {
} // end-method
} // end-class
+ /**
+ * This method will return copy of active transports
+ *
+ * @return a list of active transports
+ * */
+ public List<TransportRecord> getActiveTransports() {
+ List<TransportRecord> records = new ArrayList<>();
+ for (TransportRecord record : activeTransports.values()) {
+ records.add(new TransportRecord(record.getType(), record.getAddress()));
+ }
+ return records;
+ }
}
diff --git a/base/src/main/java/com/smartdevicelink/proxy/rpc/TireStatus.java b/base/src/main/java/com/smartdevicelink/proxy/rpc/TireStatus.java
index 5db768cb5..68c47cf50 100644
--- a/base/src/main/java/com/smartdevicelink/proxy/rpc/TireStatus.java
+++ b/base/src/main/java/com/smartdevicelink/proxy/rpc/TireStatus.java
@@ -34,82 +34,131 @@ package com.smartdevicelink.proxy.rpc;
import androidx.annotation.NonNull;
import com.smartdevicelink.proxy.RPCStruct;
+import com.smartdevicelink.proxy.rpc.enums.ComponentVolumeStatus;
import com.smartdevicelink.proxy.rpc.enums.WarningLightStatus;
+import com.smartdevicelink.util.DebugTool;
import java.util.Hashtable;
/**
- * <p>The status and pressure of the tires.</p>
- * <p><b> Parameter List:</b></p>
+ * The status and pressure of the tires.
+ *
+ * <p><b>Parameter List</b></p>
*
* <table border="1" rules="all">
- * <tr>
- * <th>Param Name</th>
- * <th>Type</th>
- * <th>Description</th>
- * <th>Version</th>
- * </tr>
- * <tr>
- * <td>PressureTellTale</td>
- * <td>WarningLightStatus</td>
- * <td>Status of the Tire Pressure TellTale</td>
- * <td>SmartDeviceLink 2.0</td>
- * </tr>
- * <tr>
- * <td>LeftFront</td>
- * <td>SingleTireStatus</td>
- * <td>The status of the left front tire.</td>
- * <td>SmartDeviceLink 2.0</td>
- * </tr>
- * <tr>
- * <td>RightFront</td>
- * <td>SingleTireStatus</td>
- * <td>The status of the right front tire.</td>
- * <td>SmartDeviceLink 2.0</td>
- * </tr>
- * <tr>
- * <td>LeftRear</td>
- * <td>SingleTireStatus</td>
- * <td>The status of the left rear tire.</td>
- * <td>SmartDeviceLink 2.0</td>
- * </tr>
- * <tr>
- * <td>RightRear</td>
- * <td>SingleTireStatus</td>
- * <td>The status of the right rear tire</td>
- * <td>SmartDeviceLink 2.0</td>
- * </tr>
- * <tr>
- * <td>InnerLeftRear</td>
- * <td>SingleTireStatus</td>
- * <td>The status of the inner left rear tire.</td>
- * <td>SmartDeviceLink 2.0</td>
- * </tr>
- * <tr>
- * <td>InnerRightRear</td>
- * <td>SingleTireStatus</td>
- * <td>The status of the inner right rear tire.</td>
- * <td>SmartDeviceLink 2.0</td>
- * </tr>
- * </table>
- * <p>
- * @since SmartDeviceLink 2.0
+ * <tr>
+ * <th>Param Name</th>
+ * <th>Type</th>
+ * <th>Description</th>
+ * <th>Required</th>
+ * <th>Notes</th>
+ * <th>Version Available</th>
+ * </tr>
+ * <tr>
+ * <td>pressureTelltale</td>
+ * <td>WarningLightStatus</td>
+ * <td>Status of the Tire Pressure Telltale. See WarningLightStatus.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>
+ * @since SmartDeviceLink 2.0.0
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>leftFront</td>
+ * <td>SingleTireStatus</td>
+ * <td>The status of the left front tire.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>
+ * @since SmartDeviceLink 2.0.0
+ * </td>
+ *
+ * </tr>
+ * <tr>
+ * <td>rightFront</td>
+ * <td>SingleTireStatus</td>
+ * <td>The status of the right front tire.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>
+ * @since SmartDeviceLink 2.0.0
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>leftRear</td>
+ * <td>SingleTireStatus</td>
+ * <td>The status of the left rear tire.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>
+ * @since SmartDeviceLink 2.0.0
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>rightRear</td>
+ * <td>SingleTireStatus</td>
+ * <td>The status of the right rear tire.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>
+ * @since SmartDeviceLink 2.0.0
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>innerLeftRear</td>
+ * <td>SingleTireStatus</td>
+ * <td>The status of the inner left rear.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>
+ * @since SmartDeviceLink 2.0.0
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>innerRightRear</td>
+ * <td>SingleTireStatus</td>
+ * <td>The status of the inner right rear.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>
+ * @since SmartDeviceLink 2.0.0
+ * </td>
+ * </tr>
+ * </table>
*
- * @see WarningLightStatus
- * @see SingleTireStatus
- * @see GetVehicleData
- * @see OnVehicleData
+ * @since SmartDeviceLink 2.0.0
*/
-
public class TireStatus extends RPCStruct {
+ private static final String TAG = "TireStatus";
+ /**
+ * @since SmartDeviceLink 2.0.0
+ */
public static final String KEY_PRESSURE_TELL_TALE = "pressureTelltale";
+ /**
+ * @since SmartDeviceLink 2.0.0
+ */
public static final String KEY_LEFT_FRONT = "leftFront";
+ /**
+ * @since SmartDeviceLink 2.0.0
+ */
public static final String KEY_RIGHT_FRONT = "rightFront";
+ /**
+ * @since SmartDeviceLink 2.0.0
+ */
public static final String KEY_LEFT_REAR = "leftRear";
+ /**
+ * @since SmartDeviceLink 2.0.0
+ */
public static final String KEY_INNER_LEFT_REAR = "innerLeftRear";
+ /**
+ * @since SmartDeviceLink 2.0.0
+ */
public static final String KEY_INNER_RIGHT_REAR = "innerRightRear";
+ /**
+ * @since SmartDeviceLink 2.0.0
+ */
public static final String KEY_RIGHT_REAR = "rightRear";
-
public TireStatus() {
}
@@ -125,7 +174,7 @@ public class TireStatus extends RPCStruct {
/**
* Constructs a new TireStatus object
*
- * @param pressureTellTale Status of the Tire Pressure TellTale
+ * @param pressureTelltale Status of the Tire Pressure TellTale
* @param leftFront The status of the left front tire.
* @param rightFront The status of the right front tire.
* @param leftRear The status of the left rear tire.
@@ -133,9 +182,9 @@ public class TireStatus extends RPCStruct {
* @param innerLeftRear The status of the inner left rear tire.
* @param innerRightRear The status of the inner right rear tire.
*/
- public TireStatus(@NonNull WarningLightStatus pressureTellTale, @NonNull SingleTireStatus leftFront, @NonNull SingleTireStatus rightFront, @NonNull SingleTireStatus leftRear, @NonNull SingleTireStatus rightRear, @NonNull SingleTireStatus innerLeftRear, @NonNull SingleTireStatus innerRightRear) {
+ public TireStatus(WarningLightStatus pressureTelltale, SingleTireStatus leftFront, SingleTireStatus rightFront, SingleTireStatus leftRear, SingleTireStatus rightRear, SingleTireStatus innerLeftRear, SingleTireStatus innerRightRear) {
this();
- setPressureTelltale(pressureTellTale);
+ setPressureTelltale(pressureTelltale);
setLeftFront(leftFront);
setRightFront(rightFront);
setLeftRear(leftRear);
@@ -176,60 +225,181 @@ public class TireStatus extends RPCStruct {
* @return the status of the tire pressure Telltale.
*/
public WarningLightStatus getPressureTelltale() {
- return (WarningLightStatus) getObject(WarningLightStatus.class, KEY_PRESSURE_TELL_TALE);
+ WarningLightStatus warningLightStatus = (WarningLightStatus) getObject(WarningLightStatus.class, KEY_PRESSURE_TELL_TALE);
+ if (warningLightStatus == null) {
+ WarningLightStatus newWarningLightStatus = WarningLightStatus.NOT_USED;
+ setValue(KEY_PRESSURE_TELL_TALE, newWarningLightStatus);
+ warningLightStatus = newWarningLightStatus;
+ DebugTool.logWarning(TAG, "TireStatus.pressureTelltale was null and will be set to .notUsed. In the future, this will change to be nullable.");
+ }
+ return warningLightStatus;
}
- public TireStatus setLeftFront(@NonNull SingleTireStatus leftFront) {
+ /**
+ * Sets the leftFront.
+ *
+ * @param leftFront The status of the left front tire.
+ * @since SmartDeviceLink 2.0.0
+ */
+ public TireStatus setLeftFront(SingleTireStatus leftFront) {
setValue(KEY_LEFT_FRONT, leftFront);
return this;
}
+ /**
+ * Gets the leftFront.
+ *
+ * @return SingleTireStatus The status of the left front tire.
+ * @since SmartDeviceLink 2.0.0
+ */
public SingleTireStatus getLeftFront() {
- return (SingleTireStatus) getObject(SingleTireStatus.class, KEY_LEFT_FRONT);
+ SingleTireStatus tireStatus = (SingleTireStatus) getObject(SingleTireStatus.class, KEY_LEFT_FRONT);
+ if (tireStatus == null) {
+ SingleTireStatus newTireStatus = new SingleTireStatus().setStatus(ComponentVolumeStatus.UNKNOWN);
+ setValue(KEY_LEFT_FRONT, newTireStatus);
+ tireStatus = newTireStatus;
+ DebugTool.logWarning(TAG, "TireStatus.leftFront was null and will be set to .unknown. In the future, this will change to be nullable.");
+ }
+ return tireStatus;
}
- public TireStatus setRightFront(@NonNull SingleTireStatus rightFront) {
+ /**
+ * Sets the rightFront.
+ *
+ * @param rightFront The status of the right front tire.
+ * @since SmartDeviceLink 2.0.0
+ */
+ public TireStatus setRightFront(SingleTireStatus rightFront) {
setValue(KEY_RIGHT_FRONT, rightFront);
return this;
}
+ /**
+ * Gets the rightFront.
+ *
+ * @return SingleTireStatus The status of the right front tire.
+ * @since SmartDeviceLink 2.0.0
+ */
public SingleTireStatus getRightFront() {
- return (SingleTireStatus) getObject(SingleTireStatus.class, KEY_RIGHT_FRONT);
+ SingleTireStatus tireStatus = (SingleTireStatus) getObject(SingleTireStatus.class, KEY_RIGHT_FRONT);
+ if (tireStatus == null) {
+ SingleTireStatus newTireStatus = new SingleTireStatus().setStatus(ComponentVolumeStatus.UNKNOWN);
+ setValue(KEY_RIGHT_FRONT, newTireStatus);
+ tireStatus = newTireStatus;
+ DebugTool.logWarning(TAG, "TireStatus.rightFront was null and will be set to .unknown. In the future, this will change to be nullable.");
+ }
+ return tireStatus;
}
- public TireStatus setLeftRear(@NonNull SingleTireStatus leftRear) {
+ /**
+ * Sets the leftRear.
+ *
+ * @param leftRear The status of the left rear tire.
+ * @since SmartDeviceLink 2.0.0
+ */
+ public TireStatus setLeftRear(SingleTireStatus leftRear) {
setValue(KEY_LEFT_REAR, leftRear);
return this;
}
+ /**
+ * Gets the leftRear.
+ *
+ * @return SingleTireStatus The status of the left rear tire.
+ * @since SmartDeviceLink 2.0.0
+ */
public SingleTireStatus getLeftRear() {
- return (SingleTireStatus) getObject(SingleTireStatus.class, KEY_LEFT_REAR);
+ SingleTireStatus tireStatus = (SingleTireStatus) getObject(SingleTireStatus.class, KEY_LEFT_REAR);
+ if (tireStatus == null) {
+ SingleTireStatus newTireStatus = new SingleTireStatus().setStatus(ComponentVolumeStatus.UNKNOWN);
+ setValue(KEY_LEFT_REAR, newTireStatus);
+ tireStatus = newTireStatus;
+ DebugTool.logWarning(TAG, "TireStatus.leftRear was null and will be set to .unknown. In the future, this will change to be nullable.");
+ }
+ return tireStatus;
}
- public TireStatus setRightRear(@NonNull SingleTireStatus rightRear) {
+ /**
+ * Sets the rightRear.
+ *
+ * @param rightRear The status of the right rear tire.
+ * @since SmartDeviceLink 2.0.0
+ */
+ public TireStatus setRightRear(SingleTireStatus rightRear) {
setValue(KEY_RIGHT_REAR, rightRear);
return this;
}
+ /**
+ * Gets the rightRear.
+ *
+ * @return SingleTireStatus The status of the right rear tire.
+ * @since SmartDeviceLink 2.0.0
+ */
public SingleTireStatus getRightRear() {
- return (SingleTireStatus) getObject(SingleTireStatus.class, KEY_RIGHT_REAR);
+ SingleTireStatus tireStatus = (SingleTireStatus) getObject(SingleTireStatus.class, KEY_RIGHT_REAR);
+ if (tireStatus == null) {
+ SingleTireStatus newTireStatus = new SingleTireStatus().setStatus(ComponentVolumeStatus.UNKNOWN);
+ setValue(KEY_RIGHT_REAR, newTireStatus);
+ tireStatus = newTireStatus;
+ DebugTool.logWarning(TAG, "TireStatus.rightRear was null and will be set to .unknown. In the future, this will change to be nullable.");
+ }
+ return tireStatus;
}
- public TireStatus setInnerLeftRear(@NonNull SingleTireStatus innerLeftRear) {
+ /**
+ * Sets the innerLeftRear.
+ *
+ * @param innerLeftRear The status of the inner left rear.
+ * @since SmartDeviceLink 2.0.0
+ */
+ public TireStatus setInnerLeftRear(SingleTireStatus innerLeftRear) {
setValue(KEY_INNER_LEFT_REAR, innerLeftRear);
return this;
}
+ /**
+ * Gets the innerLeftRear.
+ *
+ * @return SingleTireStatus The status of the inner left rear.
+ * @since SmartDeviceLink 2.0.0
+ */
public SingleTireStatus getInnerLeftRear() {
- return (SingleTireStatus) getObject(SingleTireStatus.class, KEY_INNER_LEFT_REAR);
+ SingleTireStatus tireStatus = (SingleTireStatus) getObject(SingleTireStatus.class, KEY_INNER_LEFT_REAR);
+ if (tireStatus == null) {
+ SingleTireStatus newTireStatus = new SingleTireStatus().setStatus(ComponentVolumeStatus.UNKNOWN);
+ setValue(KEY_INNER_LEFT_REAR, newTireStatus);
+ tireStatus = newTireStatus;
+ DebugTool.logWarning(TAG, "TireStatus.innerLeftRear was null and will be set to .unknown. In the future, this will change to be nullable.");
+ }
+ return tireStatus;
}
- public TireStatus setInnerRightRear(@NonNull SingleTireStatus innerRightRear) {
+ /**
+ * Sets the innerRightRear.
+ *
+ * @param innerRightRear The status of the inner right rear.
+ * @since SmartDeviceLink 2.0.0
+ */
+ public TireStatus setInnerRightRear(SingleTireStatus innerRightRear) {
setValue(KEY_INNER_RIGHT_REAR, innerRightRear);
return this;
}
+ /**
+ * Gets the innerRightRear.
+ *
+ * @return SingleTireStatus The status of the inner right rear.
+ * @since SmartDeviceLink 2.0.0
+ */
public SingleTireStatus getInnerRightRear() {
- return (SingleTireStatus) getObject(SingleTireStatus.class, KEY_INNER_RIGHT_REAR);
+ SingleTireStatus tireStatus = (SingleTireStatus) getObject(SingleTireStatus.class, KEY_INNER_RIGHT_REAR);
+ if (tireStatus == null) {
+ SingleTireStatus newTireStatus = new SingleTireStatus().setStatus(ComponentVolumeStatus.UNKNOWN);
+ setValue(KEY_INNER_RIGHT_REAR, newTireStatus);
+ tireStatus = newTireStatus;
+ DebugTool.logWarning(TAG, "TireStatus.innerRightRear was null and will be set to .unknown. In the future, this will change to be nullable.");
+ }
+ return tireStatus;
}
}
diff --git a/base/src/main/java/com/smartdevicelink/proxy/rpc/VehicleType.java b/base/src/main/java/com/smartdevicelink/proxy/rpc/VehicleType.java
index a05216661..8841126c3 100644
--- a/base/src/main/java/com/smartdevicelink/proxy/rpc/VehicleType.java
+++ b/base/src/main/java/com/smartdevicelink/proxy/rpc/VehicleType.java
@@ -33,6 +33,7 @@ package com.smartdevicelink.proxy.rpc;
import com.smartdevicelink.proxy.RPCStruct;
+import java.util.HashMap;
import java.util.Hashtable;
/**
@@ -111,6 +112,18 @@ public class VehicleType extends RPCStruct {
}
/**
+ * <p>
+ * Constructs a new VehicleType object indicated by the Hashtable
+ * parameter
+ * </p>
+ *
+ * @param hash The Hashtable to use
+ */
+ public VehicleType(HashMap<String, Object> hash) {
+ super(new Hashtable<>(hash));
+ }
+
+ /**
* get the make of the vehicle
*
* @return the make of the vehicle
diff --git a/base/src/main/java/com/smartdevicelink/session/BaseSdlSession.java b/base/src/main/java/com/smartdevicelink/session/BaseSdlSession.java
index 8b35541b4..73c6bf0b3 100644
--- a/base/src/main/java/com/smartdevicelink/session/BaseSdlSession.java
+++ b/base/src/main/java/com/smartdevicelink/session/BaseSdlSession.java
@@ -32,6 +32,7 @@
package com.smartdevicelink.session;
+import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import com.smartdevicelink.exception.SdlException;
@@ -52,10 +53,12 @@ import com.smartdevicelink.security.SdlSecurityBase;
import com.smartdevicelink.streaming.video.VideoStreamingParameters;
import com.smartdevicelink.transport.BaseTransportConfig;
import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
import com.smartdevicelink.util.DebugTool;
import com.smartdevicelink.util.SystemInfo;
import com.smartdevicelink.util.Version;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
@@ -415,4 +418,18 @@ public abstract class BaseSdlSession implements ISdlProtocol, ISecurityInitializ
public boolean isTransportForServiceAvailable(SessionType sessionType) {
return sdlProtocol != null && sdlProtocol.isTransportForServiceAvailable(sessionType);
}
+
+ /**
+ * Retrieves list of the active transports
+ *
+ * @return a list of active transports
+ * */
+ @Nullable
+ public List<TransportRecord> getActiveTransports() {
+ if (this.sdlProtocol != null) {
+ return this.sdlProtocol.getActiveTransports();
+ } else {
+ return null;
+ }
+ }
}
diff --git a/base/src/main/java/com/smartdevicelink/transport/TransportConstants.java b/base/src/main/java/com/smartdevicelink/transport/TransportConstants.java
index d2a45fcb9..79a055bc9 100644
--- a/base/src/main/java/com/smartdevicelink/transport/TransportConstants.java
+++ b/base/src/main/java/com/smartdevicelink/transport/TransportConstants.java
@@ -44,6 +44,7 @@ public class TransportConstants {
public static final String ROUTER_SERVICE_ACTION = "com.smartdevicelink.router.service";
public static final String FOREGROUND_EXTRA = "foreground";
public static final String CONFIRMED_SDL_DEVICE = "confirmed_sdl_device";
+ public static final String VEHICLE_INFO_EXTRA = "vehicle_info";
public static final String BIND_LOCATION_PACKAGE_NAME_EXTRA = "BIND_LOCATION_PACKAGE_NAME_EXTRA";
public static final String BIND_LOCATION_CLASS_NAME_EXTRA = "BIND_LOCATION_CLASS_NAME_EXTRA";