summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRHenigan <heniganr1@gmail.com>2020-06-12 16:45:23 -0400
committerRHenigan <heniganr1@gmail.com>2020-06-12 16:45:23 -0400
commit7a709dc35681f5cc5f5679cc83aa69f71158ebb3 (patch)
treea91c37433c748b72d83031991e0c3b4b7d5d0903
parent8b943aeaab90ea0af7767bfad8562a5f729af065 (diff)
parent6b52e38eb9cb29e4c28e98191c312d2c1fd82607 (diff)
downloadsdl_android-bugfix/issue_1369.tar.gz
Merge branch 'develop' into bugfix/issue_1369bugfix/issue_1369
-rw-r--r--.github/workflows/android.yml2
-rwxr-xr-xandroid/hello_sdl_android/build.gradle2
-rwxr-xr-xandroid/hello_sdl_android/src/main/AndroidManifest.xml7
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/SdlManagerTests.java59
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java1465
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/EncryptionLifecycleManager.java48
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java394
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/BaseSdlManager.java735
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseEncryptionLifecycleManager.java3
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseLifecycleManager.java1508
-rw-r--r--base/src/main/java/com/smartdevicelink/managers/lifecycle/PoliciesFetcher.java2
-rw-r--r--base/src/main/java/com/smartdevicelink/util/NativeLogTool.java2
l---------baseAndroid/src/main/java/com/smartdevicelink/managers/lifecycle1
l---------baseAndroid/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleConfigurationUpdate.java1
l---------baseAndroid/src/main/java/com/smartdevicelink/managers/lifecycle/RpcConverter.java1
-rw-r--r--hello_sdl_java/src/main/java/com/smartdevicelink/java/Main.java6
-rw-r--r--javaSE/src/main/java/com/smartdevicelink/managers/SdlManager.java926
-rw-r--r--javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java1461
18 files changed, 3132 insertions, 3491 deletions
diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
index 056e51be8..c2ec6bf32 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/android.yml
@@ -25,7 +25,7 @@ jobs:
script: ./android/gradlew -p ./android :sdl_android:connectedCheck
- name: Hello Sdl Android Tests
- run: ./android/gradlew -p ./android :hello_sdl_android:build
+ run: ./android/gradlew -p ./android/hello_sdl_android test
- name: Sdl JavaSE Tests
run: ./javaSE/gradlew -p ./javaSE test
diff --git a/android/hello_sdl_android/build.gradle b/android/hello_sdl_android/build.gradle
index ac8b92278..da649cbbb 100755
--- a/android/hello_sdl_android/build.gradle
+++ b/android/hello_sdl_android/build.gradle
@@ -1,7 +1,7 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 28
+ compileSdkVersion 29
defaultConfig {
applicationId "com.sdl.hellosdlandroid"
minSdkVersion 14
diff --git a/android/hello_sdl_android/src/main/AndroidManifest.xml b/android/hello_sdl_android/src/main/AndroidManifest.xml
index 72a191542..214a04355 100755
--- a/android/hello_sdl_android/src/main/AndroidManifest.xml
+++ b/android/hello_sdl_android/src/main/AndroidManifest.xml
@@ -39,12 +39,15 @@
android:resource="@xml/accessory_filter" />
</activity>
- <service android:name="com.sdl.hellosdlandroid.SdlService" >
+ <service
+ android:name="com.sdl.hellosdlandroid.SdlService"
+ android:foregroundServiceType="connectedDevice">
</service>
<service
android:name=".SdlRouterService"
android:exported="true"
- android:process="com.smartdevicelink.router">
+ android:process="com.smartdevicelink.router"
+ android:foregroundServiceType="connectedDevice">
<intent-filter>
<action android:name="com.smartdevicelink.router.service"/>
</intent-filter>
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/SdlManagerTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/SdlManagerTests.java
index 589af4c52..84865f21e 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/SdlManagerTests.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/SdlManagerTests.java
@@ -3,14 +3,13 @@ package com.smartdevicelink.managers;
import android.content.Context;
import com.smartdevicelink.AndroidTestCase2;
-import com.smartdevicelink.exception.SdlException;
import com.smartdevicelink.managers.lifecycle.LifecycleConfigurationUpdate;
import com.smartdevicelink.managers.lockscreen.LockScreenConfig;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCMessage;
import com.smartdevicelink.proxy.RPCRequest;
import com.smartdevicelink.proxy.RPCResponse;
-import com.smartdevicelink.proxy.SdlProxyBase;
+import com.smartdevicelink.proxy.interfaces.ISdl;
import com.smartdevicelink.proxy.rpc.GetAppServiceDataResponse;
import com.smartdevicelink.proxy.rpc.GetVehicleData;
import com.smartdevicelink.proxy.rpc.OnAppServiceData;
@@ -49,7 +48,7 @@ public class SdlManagerTests extends AndroidTestCase2 {
private TemplateColorScheme templateColorScheme;
private int listenerCalledCounter;
private SdlManager sdlManager;
- private SdlProxyBase sdlProxyBase;
+ private ISdl internalInterface;
// transport related
@SuppressWarnings("FieldCanBeLocal")
@@ -136,9 +135,9 @@ public class SdlManagerTests extends AndroidTestCase2 {
builder.setContext(mTestContext);
manager = builder.build();
- // mock SdlProxyBase and set it manually
- sdlProxyBase = mock(SdlProxyBase.class);
- manager.setProxy(sdlProxyBase);
+ // mock internalInterface and set it manually
+ internalInterface = mock(ISdl.class);
+ manager._internalInterface = internalInterface;
return manager;
}
@@ -184,8 +183,11 @@ public class SdlManagerTests extends AndroidTestCase2 {
public void testStartingManager(){
listenerCalledCounter = 0;
-
- sdlManager.start();
+
+ try {
+ sdlManager.start();
+ } catch (Exception e) {
+ }
// Create and force all sub managers to be ready manually. Because SdlManager will not start until all sub managers are ready.
// Note: SdlManager.initialize() will not be called automatically by proxy as in real life because we have mock proxy not a real one
@@ -198,7 +200,7 @@ public class SdlManagerTests extends AndroidTestCase2 {
sdlManager.getLockScreenManager().transitionToState(BaseSubManager.READY);
// Make sure the listener is called exactly once
- assertEquals("Listener was not called or called more/less frequently than expected", listenerCalledCounter, 1);
+ assertEquals("Listener was not called or called more/less frequently than expected", 1, listenerCalledCounter);
}
public void testManagerStates() {
@@ -314,7 +316,7 @@ public class SdlManagerTests extends AndroidTestCase2 {
public void testSendRPC(){
listenerCalledCounter = 0;
- // When sdlProxyBase.sendRPCRequest() is called, create a fake success response
+ // When internalInterface.sendRPC() is called, create a fake success response
Answer<Void> answer = new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) {
@@ -326,11 +328,7 @@ public class SdlManagerTests extends AndroidTestCase2 {
return null;
}
};
- try {
- doAnswer(answer).when(sdlProxyBase).sendRPC(any(RPCMessage.class));
- } catch (SdlException e) {
- e.printStackTrace();
- }
+ doAnswer(answer).when(internalInterface).sendRPC(any(RPCMessage.class));
// Test send RPC request
@@ -347,7 +345,7 @@ public class SdlManagerTests extends AndroidTestCase2 {
sdlManager.sendRPC(request);
// Make sure the listener is called exactly once
- assertEquals("Listener was not called or called more/less frequently than expected", listenerCalledCounter, 1);
+ assertEquals("Listener was not called or called more/less frequently than expected", 1, listenerCalledCounter);
}
public void testSendRPCs(){
@@ -358,10 +356,10 @@ public class SdlManagerTests extends AndroidTestCase2 {
testSendMultipleRPCs(true);
}
- private void testSendMultipleRPCs(boolean sequentialSend){
+ private void testSendMultipleRPCs(boolean sequentialSend) {
listenerCalledCounter = 0;
- // When sdlProxyBase.sendRPCRequests() is called, call listener.onFinished() to fake the response
+ // When internalInterface.sendRPCs() is called, call listener.onFinished() to fake the response
final Answer<Void> answer = new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) {
@@ -371,15 +369,12 @@ public class SdlManagerTests extends AndroidTestCase2 {
return null;
}
};
- try {
- if (sequentialSend){
- doAnswer(answer).when(sdlProxyBase).sendSequentialRequests(any(List.class), any(OnMultipleRequestListener.class));
- } else {
- doAnswer(answer).when(sdlProxyBase).sendRequests(any(List.class), any(OnMultipleRequestListener.class));
- }
- } catch (SdlException e) {
- e.printStackTrace();
+ if (sequentialSend) {
+ doAnswer(answer).when(internalInterface).sendSequentialRPCs(any(List.class), any(OnMultipleRequestListener.class));
+
+ } else {
+ doAnswer(answer).when(internalInterface).sendRPCs(any(List.class), any(OnMultipleRequestListener.class));
}
@@ -387,7 +382,8 @@ public class SdlManagerTests extends AndroidTestCase2 {
List<RPCMessage> rpcsList = Arrays.asList(new GetVehicleData(), new Show(), new OnAppServiceData(), new GetAppServiceDataResponse());
OnMultipleRequestListener onMultipleRequestListener = new OnMultipleRequestListener() {
@Override
- public void onUpdate(int remainingRequests) { }
+ public void onUpdate(int remainingRequests) {
+ }
@Override
public void onFinished() {
@@ -395,10 +391,12 @@ public class SdlManagerTests extends AndroidTestCase2 {
}
@Override
- public void onError(int correlationId, Result resultCode, String info) {}
+ public void onError(int correlationId, Result resultCode, String info) {
+ }
@Override
- public void onResponse(int correlationId, RPCResponse response) {}
+ public void onResponse(int correlationId, RPCResponse response) {
+ }
};
if (sequentialSend) {
sdlManager.sendSequentialRPCs(rpcsList, onMultipleRequestListener);
@@ -408,7 +406,6 @@ public class SdlManagerTests extends AndroidTestCase2 {
// Make sure the listener is called exactly once
- assertEquals("Listener was not called or called more/less frequently than expected", listenerCalledCounter, 1);
+ assertEquals("Listener was not called or called more/less frequently than expected", 1, listenerCalledCounter);
}
-
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java
index bc8bd7194..2a34dc62e 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java
@@ -41,1225 +41,352 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
-import com.smartdevicelink.exception.SdlException;
import com.smartdevicelink.managers.audio.AudioStreamManager;
import com.smartdevicelink.managers.file.FileManager;
-import com.smartdevicelink.managers.file.FileManagerConfig;
-import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
-import com.smartdevicelink.managers.lifecycle.LifecycleConfigurationUpdate;
import com.smartdevicelink.managers.lockscreen.LockScreenConfig;
import com.smartdevicelink.managers.lockscreen.LockScreenManager;
import com.smartdevicelink.managers.permission.PermissionManager;
import com.smartdevicelink.managers.screen.ScreenManager;
import com.smartdevicelink.managers.video.VideoStreamManager;
-import com.smartdevicelink.protocol.enums.FunctionID;
-import com.smartdevicelink.protocol.enums.SessionType;
-import com.smartdevicelink.proxy.RPCMessage;
-import com.smartdevicelink.proxy.RPCRequest;
-import com.smartdevicelink.proxy.RPCResponse;
-import com.smartdevicelink.proxy.SdlProxyBase;
-import com.smartdevicelink.proxy.SystemCapabilityManager;
-import com.smartdevicelink.proxy.callbacks.OnServiceEnded;
-import com.smartdevicelink.proxy.callbacks.OnServiceNACKed;
-import com.smartdevicelink.proxy.interfaces.IAudioStreamListener;
-import com.smartdevicelink.proxy.interfaces.ISdl;
-import com.smartdevicelink.proxy.interfaces.ISdlServiceListener;
-import com.smartdevicelink.proxy.interfaces.IVideoStreamListener;
-import com.smartdevicelink.proxy.interfaces.OnSystemCapabilityListener;
-import com.smartdevicelink.proxy.rpc.ChangeRegistration;
-import com.smartdevicelink.proxy.rpc.OnHMIStatus;
-import com.smartdevicelink.proxy.rpc.RegisterAppInterfaceResponse;
-import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
-import com.smartdevicelink.proxy.rpc.SetAppIcon;
-import com.smartdevicelink.proxy.rpc.TTSChunk;
-import com.smartdevicelink.proxy.rpc.TemplateColorScheme;
import com.smartdevicelink.proxy.rpc.enums.AppHMIType;
-import com.smartdevicelink.proxy.rpc.enums.Language;
-import com.smartdevicelink.proxy.rpc.enums.Result;
import com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason;
-import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
-import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
-import com.smartdevicelink.proxy.rpc.listeners.OnRPCListener;
-import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
-import com.smartdevicelink.proxy.rpc.listeners.OnRPCRequestListener;
-import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener;
-import com.smartdevicelink.security.SdlSecurityBase;
-import com.smartdevicelink.streaming.audio.AudioStreamingCodec;
-import com.smartdevicelink.streaming.audio.AudioStreamingParams;
-import com.smartdevicelink.streaming.video.VideoStreamingParameters;
import com.smartdevicelink.transport.BaseTransportConfig;
import com.smartdevicelink.transport.MultiplexTransportConfig;
import com.smartdevicelink.transport.enums.TransportType;
import com.smartdevicelink.transport.utl.TransportRecord;
import com.smartdevicelink.util.DebugTool;
-import com.smartdevicelink.util.Version;
-import org.json.JSONException;
-
-import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
-import java.util.Vector;
/**
* <strong>SDLManager</strong> <br>
- *
+ * <p>
* This is the main point of contact between an application and SDL <br>
- *
+ * <p>
* It is broken down to these areas: <br>
- *
+ * <p>
* 1. SDLManagerBuilder <br>
* 2. ISdl Interface along with its overridden methods - This can be passed into attached managers <br>
* 3. Sending Requests <br>
* 4. Helper methods
*/
-public class SdlManager extends BaseSdlManager{
- private static final String TAG = "SdlManager";
- private SdlProxyBase proxy;
- private SdlArtwork appIcon;
- private Context context;
- private SdlManagerListener managerListener;
- private List<Class<? extends SdlSecurityBase>> sdlSecList;
- private LockScreenConfig lockScreenConfig;
- private FileManagerConfig fileManagerConfig;
- private ServiceEncryptionListener serviceEncryptionListener;
-
- // Managers
- private PermissionManager permissionManager;
- private FileManager fileManager;
- private LockScreenManager lockScreenManager;
- private ScreenManager screenManager;
- private VideoStreamManager videoStreamManager;
- private AudioStreamManager audioStreamManager;
-
-
- // Initialize proxyBridge with anonymous lifecycleListener
- private final ProxyBridge proxyBridge = new ProxyBridge(new ProxyBridge.LifecycleListener() {
- @Override
- public void onProxyConnected() {
- DebugTool.logInfo("Proxy is connected. Now initializing.");
- changeRegistrationRetry = 0;
- checkLifecycleConfiguration();
- initialize();
- }
-
- @Override
- public void onProxyClosed(String info, Exception e, SdlDisconnectedReason reason){
- if (!reason.equals(SdlDisconnectedReason.LANGUAGE_CHANGE)){
- dispose();
- }
- }
-
- @Override
- public void onServiceEnded(OnServiceEnded serviceEnded){
-
- }
-
- @Override
- public void onServiceNACKed(OnServiceNACKed serviceNACKed){
-
- }
-
- @Override
- public void onError(String info, Exception e){
-
- }
- });
-
- // Sub manager listener
- private final CompletionListener subManagerListener = new CompletionListener() {
- @Override
- public synchronized void onComplete(boolean success) {
- if(!success){
- Log.e(TAG, "Sub manager failed to initialize");
- }
- checkState();
- }
- };
-
- @Override
- void checkState() {
- if (permissionManager != null && fileManager != null && screenManager != null && (!lockScreenConfig.isEnabled() || lockScreenManager != null)) {
- if (permissionManager.getState() == BaseSubManager.READY && fileManager.getState() == BaseSubManager.READY && screenManager.getState() == BaseSubManager.READY && (!lockScreenConfig.isEnabled() || lockScreenManager.getState() == BaseSubManager.READY)) {
- DebugTool.logInfo("Starting sdl manager, all sub managers are in ready state");
- transitionToState(BaseSubManager.READY);
- handleQueuedNotifications();
- notifyDevListener(null);
- onReady();
- } else if (permissionManager.getState() == BaseSubManager.ERROR && fileManager.getState() == BaseSubManager.ERROR && screenManager.getState() == BaseSubManager.ERROR && (!lockScreenConfig.isEnabled() || lockScreenManager.getState() == BaseSubManager.ERROR)) {
- String info = "ERROR starting sdl manager, all sub managers are in error state";
- Log.e(TAG, info);
- transitionToState(BaseSubManager.ERROR);
- notifyDevListener(info);
- } else if (permissionManager.getState() == BaseSubManager.SETTING_UP || fileManager.getState() == BaseSubManager.SETTING_UP || screenManager.getState() == BaseSubManager.SETTING_UP || (lockScreenConfig.isEnabled() && lockScreenManager != null && lockScreenManager.getState() == BaseSubManager.SETTING_UP)) {
- DebugTool.logInfo("SETTING UP sdl manager, some sub managers are still setting up");
- transitionToState(BaseSubManager.SETTING_UP);
- // No need to notify developer here!
- } else {
- Log.w(TAG, "LIMITED starting sdl manager, some sub managers are in error or limited state and the others finished setting up");
- transitionToState(BaseSubManager.LIMITED);
- handleQueuedNotifications();
- notifyDevListener(null);
- onReady();
- }
- } else {
- // We should never be here, but somehow one of the sub-sub managers is null
- String info = "ERROR one of the sdl sub managers is null";
- Log.e(TAG, info);
- transitionToState(BaseSubManager.ERROR);
- notifyDevListener(info);
- }
- }
-
- private void notifyDevListener(String info) {
- if (managerListener != null) {
- if (getState() == BaseSubManager.ERROR){
- managerListener.onError(info, null);
- } else {
- managerListener.onStart();
- }
- }
- }
-
- private void onReady(){
- // Set the app icon
- if (SdlManager.this.appIcon != null && SdlManager.this.appIcon.getName() != null) {
- if (fileManager != null && fileManager.getState() == BaseSubManager.READY && !fileManager.hasUploadedFile(SdlManager.this.appIcon)) {
- fileManager.uploadArtwork(SdlManager.this.appIcon, new CompletionListener() {
- @Override
- public void onComplete(boolean success) {
- if (success) {
- SetAppIcon msg = new SetAppIcon(SdlManager.this.appIcon.getName());
- _internalInterface.sendRPCRequest(msg);
- }
- }
- });
- } else {
- SetAppIcon msg = new SetAppIcon(SdlManager.this.appIcon.getName());
- _internalInterface.sendRPCRequest(msg);
- }
- }
- }
+public class SdlManager extends BaseSdlManager {
+ private Context context;
+ private LockScreenConfig lockScreenConfig;
- @Override
- protected void checkLifecycleConfiguration(){
- final Language actualLanguage = this.getRegisterAppInterfaceResponse().getLanguage();
- final Language actualHMILanguage = this.getRegisterAppInterfaceResponse().getHmiDisplayLanguage();
+ // Managers
+ private LockScreenManager lockScreenManager;
+ private VideoStreamManager videoStreamManager;
+ private AudioStreamManager audioStreamManager;
- if ((actualLanguage != null && !actualLanguage.equals(language)) || (actualHMILanguage != null && !actualHMILanguage.equals(hmiLanguage))) {
-
- LifecycleConfigurationUpdate lcuNew = managerListener.managerShouldUpdateLifecycle(actualLanguage, actualHMILanguage);
- LifecycleConfigurationUpdate lcuOld = managerListener.managerShouldUpdateLifecycle(actualLanguage);
- final LifecycleConfigurationUpdate lcu;
- ChangeRegistration changeRegistration;
- if (lcuNew == null) {
- lcu = lcuOld;
- changeRegistration = new ChangeRegistration(actualLanguage, actualLanguage);
- } else {
- lcu = lcuNew;
- changeRegistration = new ChangeRegistration(actualLanguage, actualHMILanguage);
- }
-
- if (lcu != null) {
- changeRegistration.setAppName(lcu.getAppName());
- changeRegistration.setNgnMediaScreenAppName(lcu.getShortAppName());
- changeRegistration.setTtsName(lcu.getTtsName());
- changeRegistration.setVrSynonyms(lcu.getVoiceRecognitionCommandNames());
- changeRegistration.setOnRPCResponseListener(new OnRPCResponseListener() {
- @Override
- public void onResponse(int correlationId, RPCResponse response) {
- if (response.getSuccess()){
- // go through and change sdlManager properties that were changed via the LCU update
- hmiLanguage = actualHMILanguage;
- language = actualLanguage;
-
- if (lcu.getAppName() != null) {
- appName = lcu.getAppName();
- }
-
- if (lcu.getShortAppName() != null) {
- shortAppName = lcu.getShortAppName();
- }
-
- if (lcu.getTtsName() != null) {
- ttsChunks = lcu.getTtsName();
- }
-
- if (lcu.getVoiceRecognitionCommandNames() != null) {
- vrSynonyms = lcu.getVoiceRecognitionCommandNames();
- }
- }
- try {
- DebugTool.logInfo(response.serializeJSON().toString());
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void onError(int correlationId, Result resultCode, String info) {
- DebugTool.logError("Change Registration onError: " + resultCode + " | Info: " + info);
- changeRegistrationRetry++;
- if (changeRegistrationRetry < MAX_RETRY) {
- final Handler handler = new Handler(Looper.getMainLooper());
- handler.postDelayed(new Runnable() {
- @Override
- public void run() {
- checkLifecycleConfiguration();
- DebugTool.logInfo("Retry Change Registration Count: " + changeRegistrationRetry);
- }
- }, 3000);
- }
- }
- });
- this.sendRPC(changeRegistration);
- }
- }
- }
-
- @Override
- protected void initialize(){
- // Instantiate sub managers
- this.permissionManager = new PermissionManager(_internalInterface);
- this.fileManager = new FileManager(_internalInterface, context, fileManagerConfig);
- if (lockScreenConfig.isEnabled()) {
- this.lockScreenManager = new LockScreenManager(lockScreenConfig, context, _internalInterface);
- }
- this.screenManager = new ScreenManager(_internalInterface, this.fileManager);
- if(getAppTypes().contains(AppHMIType.NAVIGATION) || getAppTypes().contains(AppHMIType.PROJECTION)){
- this.videoStreamManager = new VideoStreamManager(_internalInterface);
- } else {
- this.videoStreamManager = null;
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
- && (getAppTypes().contains(AppHMIType.NAVIGATION) || getAppTypes().contains(AppHMIType.PROJECTION)) ) {
- this.audioStreamManager = new AudioStreamManager(_internalInterface, context);
- } else {
- this.audioStreamManager = null;
- }
-
- // Start sub managers
- this.permissionManager.start(subManagerListener);
- this.fileManager.start(subManagerListener);
- if (lockScreenConfig.isEnabled()){
- this.lockScreenManager.start(subManagerListener);
- }
- this.screenManager.start(subManagerListener);
- }
-
- /** Dispose SdlManager and clean its resources
- * <strong>Note: new instance of SdlManager should be created on every connection. SdlManager cannot be reused after getting disposed.</strong>
- */
- @SuppressLint("NewApi")
- @Override
- public void dispose() {
- if (this.permissionManager != null) {
- this.permissionManager.dispose();
- }
-
- if (this.fileManager != null) {
- this.fileManager.dispose();
- }
+ /**
+ * Starts up a SdlManager, and calls provided callback called once all BaseSubManagers are done setting up
+ */
+ @Override
+ public void start() {
+ if (lifecycleManager == null) {
+ if (transport != null && transport.getTransportType() == TransportType.MULTIPLEX) {
+ //Do the thing
+ MultiplexTransportConfig multiplexTransportConfig = (MultiplexTransportConfig) (transport);
+ final MultiplexTransportConfig.TransportListener devListener = multiplexTransportConfig.getTransportListener();
+ multiplexTransportConfig.setTransportListener(new MultiplexTransportConfig.TransportListener() {
+ @Override
+ public void onTransportEvent(List<TransportRecord> connectedTransports, boolean audioStreamTransportAvail, boolean videoStreamTransportAvail) {
+
+ //Pass to submanagers that need it
+ if (videoStreamManager != null) {
+ videoStreamManager.handleTransportUpdated(connectedTransports, audioStreamTransportAvail, videoStreamTransportAvail);
+ }
+
+ if (audioStreamManager != null) {
+ audioStreamManager.handleTransportUpdated(connectedTransports, audioStreamTransportAvail, videoStreamTransportAvail);
+ }
+ //If the developer supplied a listener to start, it is time to call that
+ if (devListener != null) {
+ devListener.onTransportEvent(connectedTransports, audioStreamTransportAvail, videoStreamTransportAvail);
+ }
+ }
+ });
+
+ //If the requires audio support has not been set, it should be set to true if the
+ //app is a media app, and false otherwise
+ if (multiplexTransportConfig.requiresAudioSupport() == null) {
+ multiplexTransportConfig.setRequiresAudioSupport(isMediaApp);
+ }
+ }
+
+ super.start();
+
+ lifecycleManager.setContext(context);
+ lifecycleManager.start();
+ }
+ }
+
+ @Override
+ protected void initialize() {
+ // Instantiate sub managers
+ this.permissionManager = new PermissionManager(_internalInterface);
+ this.fileManager = new FileManager(_internalInterface, context, fileManagerConfig);
+ if (lockScreenConfig.isEnabled()) {
+ this.lockScreenManager = new LockScreenManager(lockScreenConfig, context, _internalInterface);
+ }
+ this.screenManager = new ScreenManager(_internalInterface, this.fileManager);
+ if (getAppTypes().contains(AppHMIType.NAVIGATION) || getAppTypes().contains(AppHMIType.PROJECTION)) {
+ this.videoStreamManager = new VideoStreamManager(_internalInterface);
+ } else {
+ this.videoStreamManager = null;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
+ && (getAppTypes().contains(AppHMIType.NAVIGATION) || getAppTypes().contains(AppHMIType.PROJECTION))) {
+ this.audioStreamManager = new AudioStreamManager(_internalInterface, context);
+ } else {
+ this.audioStreamManager = null;
+ }
+
+ // Start sub managers
+ this.permissionManager.start(subManagerListener);
+ this.fileManager.start(subManagerListener);
+ if (lockScreenConfig.isEnabled()) {
+ this.lockScreenManager.start(subManagerListener);
+ }
+ this.screenManager.start(subManagerListener);
+ }
+
+ @Override
+ void checkState() {
+ if (permissionManager != null && fileManager != null && screenManager != null && (!lockScreenConfig.isEnabled() || lockScreenManager != null)) {
+ if (permissionManager.getState() == BaseSubManager.READY && fileManager.getState() == BaseSubManager.READY && screenManager.getState() == BaseSubManager.READY && (!lockScreenConfig.isEnabled() || lockScreenManager.getState() == BaseSubManager.READY)) {
+ DebugTool.logInfo("Starting sdl manager, all sub managers are in ready state");
+ transitionToState(BaseSubManager.READY);
+ handleQueuedNotifications();
+ notifyDevListener(null);
+ onReady();
+ } else if (permissionManager.getState() == BaseSubManager.ERROR && fileManager.getState() == BaseSubManager.ERROR && screenManager.getState() == BaseSubManager.ERROR && (!lockScreenConfig.isEnabled() || lockScreenManager.getState() == BaseSubManager.ERROR)) {
+ String info = "ERROR starting sdl manager, all sub managers are in error state";
+ Log.e(TAG, info);
+ transitionToState(BaseSubManager.ERROR);
+ notifyDevListener(info);
+ } else if (permissionManager.getState() == BaseSubManager.SETTING_UP || fileManager.getState() == BaseSubManager.SETTING_UP || screenManager.getState() == BaseSubManager.SETTING_UP || (lockScreenConfig.isEnabled() && lockScreenManager != null && lockScreenManager.getState() == BaseSubManager.SETTING_UP)) {
+ DebugTool.logInfo("SETTING UP sdl manager, some sub managers are still setting up");
+ transitionToState(BaseSubManager.SETTING_UP);
+ // No need to notify developer here!
+ } else {
+ Log.w(TAG, "LIMITED starting sdl manager, some sub managers are in error or limited state and the others finished setting up");
+ transitionToState(BaseSubManager.LIMITED);
+ handleQueuedNotifications();
+ notifyDevListener(null);
+ onReady();
+ }
+ } else {
+ // We should never be here, but somehow one of the sub-sub managers is null
+ String info = "ERROR one of the sdl sub managers is null";
+ Log.e(TAG, info);
+ transitionToState(BaseSubManager.ERROR);
+ notifyDevListener(info);
+ }
+ }
+
+ private void notifyDevListener(String info) {
+ if (managerListener != null) {
+ if (getState() == BaseSubManager.ERROR) {
+ managerListener.onError(info, null);
+ } else {
+ managerListener.onStart();
+ }
+ }
+ }
+
+ @Override
+ void retryChangeRegistration() {
+ changeRegistrationRetry++;
+ if (changeRegistrationRetry < MAX_RETRY) {
+ final Handler handler = new Handler(Looper.getMainLooper());
+ handler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ checkLifecycleConfiguration();
+ DebugTool.logInfo("Retry Change Registration Count: " + changeRegistrationRetry);
+ }
+ }, 3000);
+ }
+ }
+
+ @Override
+ void onProxyClosed(SdlDisconnectedReason reason) {
+ Log.i(TAG, "Proxy is closed.");
+ if (managerListener != null) {
+ managerListener.onDestroy();
+ }
+
+ if (reason == null || !reason.equals(SdlDisconnectedReason.LANGUAGE_CHANGE)) {
+ dispose();
+ }
+ }
- if (this.lockScreenManager != null) {
- this.lockScreenManager.dispose();
- }
+ /**
+ * Dispose SdlManager and clean its resources
+ * <strong>Note: new instance of SdlManager should be created on every connection. SdlManager cannot be reused after getting disposed.</strong>
+ */
+ @SuppressLint("NewApi")
+ @Override
+ public void dispose() {
+ if (this.permissionManager != null) {
+ this.permissionManager.dispose();
+ }
- if (this.screenManager != null) {
- this.screenManager.dispose();
- }
+ if (this.fileManager != null) {
+ this.fileManager.dispose();
+ }
- if(this.videoStreamManager != null) {
- this.videoStreamManager.dispose();
- }
+ if (this.lockScreenManager != null) {
+ this.lockScreenManager.dispose();
+ }
- // SuppressLint("NewApi") is used because audioStreamManager is only available on android >= jelly bean
- if (this.audioStreamManager != null) {
- this.audioStreamManager.dispose();
- }
+ if (this.screenManager != null) {
+ this.screenManager.dispose();
+ }
- if (this.proxy != null && !proxy.isDisposed()) {
- try {
- this.proxy.dispose();
- } catch (SdlException e) {
- DebugTool.logError("Issue disposing proxy in SdlManager", e);
- }
- }
+ if (this.videoStreamManager != null) {
+ this.videoStreamManager.dispose();
+ }
- if(managerListener != null){
- managerListener.onDestroy();
- managerListener = null;
- }
+ // SuppressLint("NewApi") is used because audioStreamManager is only available on android >= jelly bean
+ if (this.audioStreamManager != null) {
+ this.audioStreamManager.dispose();
+ }
- transitionToState(BaseSubManager.SHUTDOWN);
- }
+ if (this.lifecycleManager != null) {
+ this.lifecycleManager.stop();
+ }
- // MANAGER GETTERS
+ if (managerListener != null) {
+ managerListener.onDestroy();
+ managerListener = null;
+ }
- /**
- * Gets the PermissionManager. <br>
- * <strong>Note: PermissionManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
- * @return a PermissionManager object
- */
- public PermissionManager getPermissionManager() {
- if (permissionManager.getState() != BaseSubManager.READY && permissionManager.getState() != BaseSubManager.LIMITED){
- Log.e(TAG,"PermissionManager should not be accessed because it is not in READY/LIMITED state");
- }
- checkSdlManagerState();
- return permissionManager;
- }
+ transitionToState(BaseSubManager.SHUTDOWN);
+ }
- /**
- * Gets the FileManager. <br>
- * <strong>Note: FileManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
- * @return a FileManager object
- */
- public FileManager getFileManager() {
- if (fileManager.getState() != BaseSubManager.READY && fileManager.getState() != BaseSubManager.LIMITED){
- Log.e(TAG, "FileManager should not be accessed because it is not in READY/LIMITED state");
- }
- checkSdlManagerState();
- return fileManager;
- }
+ // MANAGER GETTERS
/**
* Gets the VideoStreamManager. <br>
- * The VideoStreamManager returned will only be not null if the registered app type is
- * either NAVIGATION or PROJECTION. Once the VideoStreamManager is retrieved, its start()
- * method will need to be called before use.
+ * The VideoStreamManager returned will only be not null if the registered app type is
+ * either NAVIGATION or PROJECTION. Once the VideoStreamManager is retrieved, its start()
+ * method will need to be called before use.
* <br><br><strong>Note: VideoStreamManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
+ *
* @return a VideoStreamManager object attached to this SdlManager instance
*/
- public @Nullable
+ public @Nullable
VideoStreamManager getVideoStreamManager() {
- checkSdlManagerState();
- return videoStreamManager;
- }
+ checkSdlManagerState();
+ return videoStreamManager;
+ }
/**
* Gets the AudioStreamManager. <br>
- * The AudioStreamManager returned will only be not null if the registered app type is
- * either NAVIGATION or PROJECTION. Once the AudioStreamManager is retrieved, its start()
- * method will need to be called before use.
+ * The AudioStreamManager returned will only be not null if the registered app type is
+ * either NAVIGATION or PROJECTION. Once the AudioStreamManager is retrieved, its start()
+ * method will need to be called before use.
* <br><strong>Note: AudioStreamManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
+ *
* @return a AudioStreamManager object
*/
- public @Nullable AudioStreamManager getAudioStreamManager() {
- checkSdlManagerState();
- return audioStreamManager;
- }
-
- /**
- * Gets the ScreenManager. <br>
- * <strong>Note: ScreenManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
- * @return a ScreenManager object
- */
- public ScreenManager getScreenManager() {
- if (screenManager.getState() != BaseSubManager.READY && screenManager.getState() != BaseSubManager.LIMITED){
- Log.e(TAG, "ScreenManager should not be accessed because it is not in READY/LIMITED state");
- }
- checkSdlManagerState();
- return screenManager;
- }
-
- /**
- * Gets the LockScreenManager. <br>
- * <strong>Note: LockScreenManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
- * @return a LockScreenManager object
- */
- public LockScreenManager getLockScreenManager() {
- if (lockScreenManager.getState() != BaseSubManager.READY && lockScreenManager.getState() != BaseSubManager.LIMITED){
- Log.e(TAG, "LockScreenManager should not be accessed because it is not in READY/LIMITED state");
- }
- checkSdlManagerState();
- return lockScreenManager;
- }
-
- /**
- * Gets the SystemCapabilityManager. <br>
- * <strong>Note: SystemCapabilityManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
- * @return a SystemCapabilityManager object
- */
- public SystemCapabilityManager getSystemCapabilityManager(){
- return proxy.getSystemCapabilityManager();
- }
-
- /**
- * Method to retrieve the RegisterAppInterface Response message that was sent back from the
- * module. It contains various attributes about the connected module and can be used to adapt
- * to different module types and their supported features.
- *
- * @return RegisterAppInterfaceResponse received from the module or null if the app has not yet
- * registered with the module.
- */
- @Override
- public RegisterAppInterfaceResponse getRegisterAppInterfaceResponse(){
- if(proxy != null){
- return proxy.getRegisterAppInterfaceResponse();
- }
- return null;
- }
-
- /**
- * Get the current OnHMIStatus
- * @return OnHMIStatus object represents the current OnHMIStatus
- */
- @Override
- public OnHMIStatus getCurrentHMIStatus(){
- if(this.proxy !=null ){
- return proxy.getCurrentHMIStatus();
- }
- return null;
- }
-
- /**
- * Retrieves the auth token, if any, that was attached to the StartServiceACK for the RPC
- * service from the module. For example, this should be used to login to a user account.
- * @return the string representation of the auth token
- */
- @Override
- public String getAuthToken(){
- return this.proxy.getAuthToken();
- }
-
- // PROTECTED GETTERS
-
- protected LockScreenConfig getLockScreenConfig() { return lockScreenConfig; }
-
- protected FileManagerConfig getFileManagerConfig() { return fileManagerConfig; }
-
- // SENDING REQUESTS
-
- /**
- * Send RPC Message
- * @param message RPCMessage
- */
- @Override
- public void sendRPC(RPCMessage message) {
- try{
- proxy.sendRPC(message);
- }catch (SdlException exception){
- handleSdlException(exception);
- }
- }
-
- /**
- * Takes a list of RPCMessages and sends it to SDL in a synchronous fashion. Responses are captured through callback on OnMultipleRequestListener.
- * For sending requests asynchronously, use sendRequests <br>
- *
- * <strong>NOTE: This will override any listeners on individual RPCs</strong><br>
- *
- * <strong>ADDITIONAL NOTE: This only takes the type of RPCRequest for now, notifications and responses will be thrown out</strong>
- *
- * @param rpcs is the list of RPCMessages being sent
- * @param listener listener for updates and completions
- */
- @Override
- public void sendSequentialRPCs(final List<? extends RPCMessage> rpcs, final OnMultipleRequestListener listener){
-
- List<RPCRequest> rpcRequestList = new ArrayList<>();
- for (int i = 0; i < rpcs.size(); i++) {
- if (rpcs.get(i) instanceof RPCRequest){
- rpcRequestList.add((RPCRequest)rpcs.get(i));
- }
- }
-
- if (rpcRequestList.size() > 0) {
- try{
- proxy.sendSequentialRequests(rpcRequestList, listener);
- }catch (SdlException exception){
- handleSdlException(exception);
- }
- }
- }
-
- /**
- * Takes a list of RPCMessages and sends it to SDL. Responses are captured through callback on OnMultipleRequestListener.
- * For sending requests synchronously, use sendSequentialRPCs <br>
- *
- * <strong>NOTE: This will override any listeners on individual RPCs</strong> <br>
- *
- * <strong>ADDITIONAL NOTE: This only takes the type of RPCRequest for now, notifications and responses will be thrown out</strong>
- *
- * @param rpcs is the list of RPCMessages being sent
- * @param listener listener for updates and completions
- */
- @Override
- public void sendRPCs(List<? extends RPCMessage> rpcs, final OnMultipleRequestListener listener) {
-
- List<RPCRequest> rpcRequestList = new ArrayList<>();
- for (int i = 0; i < rpcs.size(); i++) {
- if (rpcs.get(i) instanceof RPCRequest){
- rpcRequestList.add((RPCRequest)rpcs.get(i));
- }
- }
-
- if (rpcRequestList.size() > 0) {
- try{
- proxy.sendRequests(rpcRequestList, listener);
- }catch (SdlException exception){
- handleSdlException(exception);
- }
- }
- }
-
- private void handleSdlException(SdlException exception){
- if(exception != null){
- DebugTool.logError("Caught SdlException: " + exception.getSdlExceptionCause());
- // In the future this should handle logic to dispose the manager if it is an unrecoverable error
- }else{
- DebugTool.logError("Caught SdlException" );
- }
- }
-
- /**
- * Add an OnRPCNotificationListener
- * @param listener listener that will be called when a notification is received
- */
- @Override
- public void addOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener){
- proxy.addOnRPCNotificationListener(notificationId,listener);
- }
-
- /**
- * Remove an OnRPCNotificationListener
- * @param listener listener that was previously added
- */
- @Override
- public void removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener){
- proxy.removeOnRPCNotificationListener(notificationId, listener);
- }
-
- /**
- * Add an OnRPCRequestListener
- * @param listener listener that will be called when a request is received
- */
- @Override
- public void addOnRPCRequestListener(FunctionID requestId, OnRPCRequestListener listener){
- proxy.addOnRPCRequestListener(requestId,listener);
- }
-
- /**
- * Remove an OnRPCRequestListener
- * @param listener listener that was previously added
- */
- @Override
- public void removeOnRPCRequestListener(FunctionID requestId, OnRPCRequestListener listener){
- proxy.removeOnRPCRequestListener(requestId, listener);
- }
-
- // LIFECYCLE / OTHER
-
- // STARTUP
-
- /**
- * Starts up a SdlManager, and calls provided callback called once all BaseSubManagers are done setting up
- */
- @SuppressWarnings("unchecked")
- @Override
- public void start(){
- if (proxy == null) {
- try {
- if(transport!= null && transport.getTransportType() == TransportType.MULTIPLEX){
- //Do the thing
- MultiplexTransportConfig multiplexTransportConfig = (MultiplexTransportConfig)(transport);
- final MultiplexTransportConfig.TransportListener devListener = multiplexTransportConfig.getTransportListener();
- multiplexTransportConfig.setTransportListener(new MultiplexTransportConfig.TransportListener() {
- @Override
- public void onTransportEvent(List<TransportRecord> connectedTransports, boolean audioStreamTransportAvail, boolean videoStreamTransportAvail) {
-
- //Pass to submanagers that need it
- if(videoStreamManager != null){
- videoStreamManager.handleTransportUpdated(connectedTransports, audioStreamTransportAvail, videoStreamTransportAvail);
- }
-
- if(audioStreamManager != null){
- audioStreamManager.handleTransportUpdated(connectedTransports, audioStreamTransportAvail, videoStreamTransportAvail);
- }
- //If the developer supplied a listener to start, it is time to call that
- if(devListener != null){
- devListener.onTransportEvent(connectedTransports,audioStreamTransportAvail,videoStreamTransportAvail);
- }
- }
- });
-
- //If the requires audio support has not been set, it should be set to true if the
- //app is a media app, and false otherwise
- if(multiplexTransportConfig.requiresAudioSupport() == null){
- multiplexTransportConfig.setRequiresAudioSupport(isMediaApp);
- }
- }
-
- proxy = new SdlProxyBase(proxyBridge, context, appName, shortAppName, isMediaApp, hmiLanguage,
- hmiLanguage, hmiTypes, appId, transport, vrSynonyms, ttsChunks, dayColorScheme,
- nightColorScheme) {};
- proxy.setMinimumProtocolVersion(minimumProtocolVersion);
- proxy.setMinimumRPCVersion(minimumRPCVersion);
- if (sdlSecList != null && !sdlSecList.isEmpty()) {
- proxy.setSdlSecurity(sdlSecList, serviceEncryptionListener);
- }
- //Setup the notification queue
- initNotificationQueue();
-
- } catch (SdlException e) {
- transitionToState(BaseSubManager.ERROR);
- if (managerListener != null) {
- managerListener.onError("Unable to start manager", e);
- }
- }
- }
- }
-
- protected void setProxy(SdlProxyBase proxy){
- this.proxy = proxy;
- }
-
- // INTERNAL INTERFACE
- private ISdl _internalInterface = new ISdl() {
- @Override
- public void start() {
- try{
- proxy.initializeProxy();
- }catch (SdlException e){
- e.printStackTrace();
- }
- }
-
- @Override
- public void stop() {
- try{
- proxy.dispose();
- }catch (SdlException e){
- e.printStackTrace();
- }
- }
-
- @Override
- public boolean isConnected() {
- return proxy.getIsConnected();
- }
-
- @Override
- public void addServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener) {
- proxy.addServiceListener(serviceType,sdlServiceListener);
- }
-
- @Override
- public void removeServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener) {
- proxy.removeServiceListener(serviceType,sdlServiceListener);
- }
-
- @Override
- public void startVideoService(VideoStreamingParameters parameters, boolean encrypted) {
- if(proxy.getIsConnected()){
- proxy.startVideoService(encrypted,parameters);
- }
- }
+ public @Nullable
+ AudioStreamManager getAudioStreamManager() {
+ checkSdlManagerState();
+ return audioStreamManager;
+ }
- @Override
- public IVideoStreamListener startVideoStream(boolean isEncrypted, VideoStreamingParameters parameters){
- if(proxy.getIsConnected()){
- return proxy.startVideoStream(isEncrypted, parameters);
- }else{
- DebugTool.logError("Unable to start video stream, proxy not connected");
- return null;
- }
- }
-
- @Override
- public void stopVideoService() {
- if(proxy.getIsConnected()){
- proxy.endVideoStream();
- }
- }
-
- @Override
- public void startAudioService(boolean isEncrypted, AudioStreamingCodec codec,
- AudioStreamingParams params) {
- if(proxy.getIsConnected()){
- proxy.startAudioStream(isEncrypted, codec, params);
- }
- }
-
- @Override
- public void startAudioService(boolean encrypted) {
- if(isConnected()){
- proxy.startService(SessionType.PCM, encrypted);
- }
- }
-
- @Override
- public IAudioStreamListener startAudioStream(boolean isEncrypted, AudioStreamingCodec codec,
- AudioStreamingParams params) {
- return proxy.startAudioStream(isEncrypted, codec, params);
- }
-
- @Override
- public void stopAudioService() {
- if(proxy.getIsConnected()){
- proxy.endAudioStream();
- }
- }
-
- @Override
- public void sendRPCRequest(RPCRequest message){
- try {
- proxy.sendRPC(message);
- } catch (SdlException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void sendRPC(RPCMessage message) {
- try {
- proxy.sendRPC(message);
- } catch (SdlException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void sendRequests(List<? extends RPCRequest> rpcs, OnMultipleRequestListener listener) {
- try {
- proxy.sendRequests(rpcs, listener);
- } catch (SdlException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void sendRPCs(List<? extends RPCMessage> rpcs, OnMultipleRequestListener listener) {
- try {
- proxy.sendRequests(rpcs, listener);
- } catch (SdlException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void sendSequentialRPCs(List<? extends RPCMessage> rpcs, OnMultipleRequestListener listener) {
- try {
- proxy.sendSequentialRequests(rpcs,listener);
- } catch (SdlException e) {
- DebugTool.logError("Issue sending sequential RPCs ", e);
- }
- }
-
- @Override
- public void addOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {
- proxy.addOnRPCNotificationListener(notificationId,listener);
- }
-
- @Override
- public boolean removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {
- return proxy.removeOnRPCNotificationListener(notificationId,listener);
- }
-
- @Override
- public void addOnRPCRequestListener(FunctionID functionID, OnRPCRequestListener listener) {
- proxy.addOnRPCRequestListener(functionID, listener);
- }
-
- @Override
- public boolean removeOnRPCRequestListener(FunctionID functionID, OnRPCRequestListener listener) {
- return proxy.removeOnRPCRequestListener(functionID, listener);
- }
-
- @Override
- public void addOnRPCListener(final FunctionID responseId, final OnRPCListener listener) {
- proxyBridge.addRpcListener(responseId, listener);
- }
-
- @Override
- public boolean removeOnRPCListener(final FunctionID responseId, final OnRPCListener listener) {
- return proxyBridge.removeOnRPCListener(responseId, listener);
- }
-
- @Override
- public Object getCapability(SystemCapabilityType systemCapabilityType){
- return proxy.getCapability(systemCapabilityType);
- }
-
- @Override
- public void getCapability(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener scListener) {
- proxy.getCapability(systemCapabilityType, scListener);
- }
-
- @Override
- public RegisterAppInterfaceResponse getRegisterAppInterfaceResponse() {
- return proxy.getRegisterAppInterfaceResponse();
- }
-
- @Override
- public Object getCapability(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener scListener, boolean forceUpdate) {
- if (proxy != null && proxy.getSystemCapabilityManager() != null) {
- return proxy.getSystemCapabilityManager().getCapability(systemCapabilityType, scListener, forceUpdate);
- }
- return null;
- }
-
- @Override
- public boolean isCapabilitySupported(SystemCapabilityType systemCapabilityType){
- return proxy.isCapabilitySupported(systemCapabilityType);
- }
-
- @Override
- public void addOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) {
- proxy.addOnSystemCapabilityListener(systemCapabilityType, listener);
- }
-
- @Override
- public boolean removeOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) {
- return proxy.removeOnSystemCapabilityListener(systemCapabilityType, listener);
- }
-
- @Override
- public boolean isTransportForServiceAvailable(SessionType serviceType) {
- if(SessionType.NAV.equals(serviceType)){
- return proxy.isVideoStreamTransportAvailable();
- }else if(SessionType.PCM.equals(serviceType)){
- return proxy.isAudioStreamTransportAvailable();
- }
- return false;
- }
-
- @Override
- public SdlMsgVersion getSdlMsgVersion(){
- try {
- return proxy.getSdlMsgVersion();
- } catch (SdlException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- @Override
- public @NonNull Version getProtocolVersion() {
- if(proxy.getProtocolVersion() != null){
- return proxy.getProtocolVersion();
- }else{
- return new Version(1,0,0);
- }
- }
-
- @Override
- public void startRPCEncryption() {
- if (proxy != null) {
- proxy.startProtectedRPCService();
- }
- }
-
- };
-
-
- // BUILDER
- public static class Builder {
- SdlManager sdlManager;
-
- /**
- * Builder for the SdlManager. Parameters in the constructor are required.
- * @param context the current context
- * @param appId the app's ID
- * @param appName the app's name
- * @param listener a SdlManagerListener object
- */
- public Builder(@NonNull Context context, @NonNull final String appId, @NonNull final String appName, @NonNull final SdlManagerListener listener){
- sdlManager = new SdlManager();
- setContext(context);
- setAppId(appId);
- setAppName(appName);
- setManagerListener(listener);
- }
- /**
- * Builder for the SdlManager. Parameters in the constructor are required.
- * @param context the current context
- * @param appId the app's ID
- * @param appName the app's name
- * @param listener a SdlManagerListener object
- */
- public Builder(@NonNull Context context, @NonNull final String appId, @NonNull final String appName, @NonNull BaseTransportConfig transport, @NonNull final SdlManagerListener listener){
- sdlManager = new SdlManager();
- setContext(context);
- setAppId(appId);
- setAppName(appName);
- setTransportType(transport);
- setManagerListener(listener);
- }
-
- /**
- * Sets the App ID
- * @param appId
- */
- public Builder setAppId(@NonNull final String appId){
- sdlManager.appId = appId;
- return this;
- }
-
- /**
- * Sets the Application Name
- * @param appName
- */
- public Builder setAppName(@NonNull final String appName){
- sdlManager.appName = appName;
- return this;
- }
-
- /**
- * Sets the Short Application Name
- * @param shortAppName
- */
- public Builder setShortAppName(final String shortAppName) {
- sdlManager.shortAppName = shortAppName;
- return this;
- }
-
- /**
- * Sets the minimum protocol version that will be permitted to connect.
- * If the protocol version of the head unit connected is below this version,
- * the app will disconnect with an EndService protocol message and will not register.
- * @param minimumProtocolVersion the minimum Protocol spec version that should be accepted
- */
- public Builder setMinimumProtocolVersion(final Version minimumProtocolVersion) {
- sdlManager.minimumProtocolVersion = minimumProtocolVersion;
- return this;
- }
-
- /**
- * The minimum RPC version that will be permitted to connect.
- * If the RPC version of the head unit connected is below this version, an UnregisterAppInterface will be sent.
- * @param minimumRPCVersion the minimum RPC spec version that should be accepted
- */
- public Builder setMinimumRPCVersion(final Version minimumRPCVersion) {
- sdlManager.minimumRPCVersion = minimumRPCVersion;
- return this;
- }
-
- /**
- * Sets the Language of the App
- * @param hmiLanguage the desired language to be used on the display/HMI of the connected module
- */
- public Builder setLanguage(final Language hmiLanguage) {
- sdlManager.hmiLanguage = hmiLanguage;
- sdlManager.language = hmiLanguage;
- return this;
- }
-
- /**
- * Sets the TemplateColorScheme for daytime
- * @param dayColorScheme color scheme that will be used (if supported) when the display is
- * in a "Day Mode" or similar. Should comprise of colors that contrast
- * well during the day under sunlight.
- */
- public Builder setDayColorScheme(final TemplateColorScheme dayColorScheme){
- sdlManager.dayColorScheme = dayColorScheme;
- return this;
- }
-
- /**
- * Sets the TemplateColorScheme for nighttime
- * @param nightColorScheme color scheme that will be used (if supported) when the display is
- * in a "Night Mode" or similar. Should comprise of colors that
- * contrast well during the night and are not brighter than average.
- */
- public Builder setNightColorScheme(final TemplateColorScheme nightColorScheme){
- sdlManager.nightColorScheme = nightColorScheme;
- return this;
- }
-
- /**
- * Sets the FileManagerConfig for the session.<br>
- * <strong>Note: If not set, the default configuration value of 1 will be set for
- * artworkRetryCount and fileRetryCount in FileManagerConfig</strong>
- * @param fileManagerConfig - configuration options
- */
- public Builder setFileManagerConfig (final FileManagerConfig fileManagerConfig){
- sdlManager.fileManagerConfig = fileManagerConfig;
- return this;
- }
-
- /**
- * Sets the LockScreenConfig for the session. <br>
- * <strong>Note: If not set, the default configuration will be used.</strong>
- * @param lockScreenConfig - configuration options
- */
- public Builder setLockScreenConfig (final LockScreenConfig lockScreenConfig){
- sdlManager.lockScreenConfig = lockScreenConfig;
- return this;
- }
-
- /**
- * Sets the icon for the app on head unit / In-Vehicle-Infotainment system <br>
- * @param sdlArtwork the icon that will be used to represent this application on the
- * connected module
- */
- public Builder setAppIcon(final SdlArtwork sdlArtwork){
- sdlManager.appIcon = sdlArtwork;
- return this;
- }
-
- /**
- * Sets the vector of AppHMIType <br>
- * <strong>Note: This should be an ordered list from most -> least relevant</strong>
- * @param hmiTypes HMI types that represent this application. For example, if the app is a
- * music player, the MEDIA HMIType should be included.
- */
- public Builder setAppTypes(final Vector<AppHMIType> hmiTypes){
-
- sdlManager.hmiTypes = hmiTypes;
-
- if (hmiTypes != null) {
- sdlManager.isMediaApp = hmiTypes.contains(AppHMIType.MEDIA);
- }
-
- return this;
- }
-
- /**
- * Sets the voice recognition synonyms that can be used to identify this application.
- * @param vrSynonyms a vector of Strings that can be associated with this app. For example the app's name should
- * be included as well as any phonetic spellings of the app name that might help the on-board
- * VR system associated a users spoken word with the supplied synonyms.
- */
- public Builder setVrSynonyms(final Vector<String> vrSynonyms) {
- sdlManager.vrSynonyms = vrSynonyms;
- return this;
- }
-
- /**
- * Sets the Text-To-Speech Name of the application. These TTSChunks might be used by the module as an audio
- * representation of the app's name.
- * @param ttsChunks the TTS chunks that can represent this app's name
- */
- public Builder setTtsName(final Vector<TTSChunk> ttsChunks) {
- sdlManager.ttsChunks = ttsChunks;
- return this;
- }
-
- /**
- * This Object type may change with the transport refactor
- * Sets the BaseTransportConfig
- * @param transport the type of transport that should be used for this SdlManager instance.
- */
- public Builder setTransportType(@NonNull BaseTransportConfig transport){
- sdlManager.transport = transport;
- return this;
- }
-
- /**
- * Sets the Context
- * @param context
- */
- public Builder setContext(Context context){
- sdlManager.context = context;
- return this;
- }
-
- /**
- * Sets the Security library
- * @param secList The list of security class(es)
- */
- @Deprecated
- public Builder setSdlSecurity(List<Class<? extends SdlSecurityBase>> secList) {
- sdlManager.sdlSecList = secList;
- return this;
- }
-
- /**
- * Sets the security libraries and a callback to notify caller when there is update to encryption service
- * @param secList The list of security class(es)
- * @param listener The callback object
- */
- public Builder setSdlSecurity(@NonNull List<Class<? extends SdlSecurityBase>> secList, ServiceEncryptionListener listener) {
- sdlManager.sdlSecList = secList;
- sdlManager.serviceEncryptionListener = listener;
- return this;
- }
-
- /**
- * Set the SdlManager Listener
- * @param listener the listener
- */
- public Builder setManagerListener(@NonNull final SdlManagerListener listener){
- sdlManager.managerListener = listener;
- return this;
- }
-
- /**
- * Set RPCNotification listeners. SdlManager will preload these listeners before any RPCs are sent/received.
- * @param listeners a map of listeners that will be called when a notification is received.
- * Key represents the FunctionID of the notification and value represents the listener
- */
- public Builder setRPCNotificationListeners(Map<FunctionID, OnRPCNotificationListener> listeners){
- sdlManager.onRPCNotificationListeners = listeners;
- return this;
- }
-
- /**
- * Build SdlManager ang get it ready to be started
- * <strong>Note: new instance of SdlManager should be created on every connection. SdlManager cannot be reused after getting disposed.</strong>
- * @return SdlManager instance that is ready to be started
- */
- public SdlManager build() {
-
- if (sdlManager.appName == null) {
- throw new IllegalArgumentException("You must specify an app name by calling setAppName");
- }
-
- if (sdlManager.appId == null) {
- throw new IllegalArgumentException("You must specify an app ID by calling setAppId");
- }
-
- if (sdlManager.managerListener == null) {
- throw new IllegalArgumentException("You must set a SdlManagerListener object");
- }
-
- if (sdlManager.transport == null) {
- throw new IllegalArgumentException("You must set a transport type object");
- }
-
- if (sdlManager.hmiTypes == null) {
- Vector<AppHMIType> hmiTypesDefault = new Vector<>();
- hmiTypesDefault.add(AppHMIType.DEFAULT);
- sdlManager.hmiTypes = hmiTypesDefault;
- sdlManager.isMediaApp = false;
- }
-
- if (sdlManager.lockScreenConfig == null){
- // if lock screen params are not set, use default
- sdlManager.lockScreenConfig = new LockScreenConfig();
- }
-
- if(sdlManager.fileManagerConfig == null){
- //if FileManagerConfig is not set use default
- sdlManager.fileManagerConfig = new FileManagerConfig();
- }
-
- if (sdlManager.hmiLanguage == null){
- sdlManager.hmiLanguage = Language.EN_US;
- sdlManager.language = Language.EN_US;
- }
-
- if (sdlManager.minimumProtocolVersion == null){
- sdlManager.minimumProtocolVersion = new Version("1.0.0");
- }
-
- if (sdlManager.minimumRPCVersion == null){
- sdlManager.minimumRPCVersion = new Version("1.0.0");
- }
-
- sdlManager.transitionToState(BaseSubManager.SETTING_UP);
-
- return sdlManager;
- }
- }
-
- /**
- * Start a secured RPC service
- */
- public void startRPCEncryption() {
- if (proxy != null) {
- proxy.startProtectedRPCService();
- }
- }
+ /**
+ * Gets the LockScreenManager. <br>
+ * <strong>Note: LockScreenManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
+ *
+ * @return a LockScreenManager object
+ */
+ public LockScreenManager getLockScreenManager() {
+ if (lockScreenManager.getState() != BaseSubManager.READY && lockScreenManager.getState() != BaseSubManager.LIMITED) {
+ Log.e(TAG, "LockScreenManager should not be accessed because it is not in READY/LIMITED state");
+ }
+ checkSdlManagerState();
+ return lockScreenManager;
+ }
+
+ // PROTECTED GETTERS
+ protected LockScreenConfig getLockScreenConfig() {
+ return lockScreenConfig;
+ }
+
+ // BUILDER
+ public static class Builder extends BaseSdlManager.Builder {
+ /**
+ * Builder for the SdlManager. Parameters in the constructor are required.
+ *
+ * @param context the current context
+ * @param appId the app's ID
+ * @param appName the app's name
+ * @param listener a SdlManagerListener object
+ */
+ public Builder(@NonNull Context context, @NonNull final String appId, @NonNull final String appName, @NonNull final SdlManagerListener listener) {
+ super(appId, appName, listener);
+ setContext(context);
+ }
+
+ /**
+ * Builder for the SdlManager. Parameters in the constructor are required.
+ *
+ * @param context the current context
+ * @param appId the app's ID
+ * @param appName the app's name
+ * @param listener a SdlManagerListener object
+ */
+ public Builder(@NonNull Context context, @NonNull final String appId, @NonNull final String appName, @NonNull BaseTransportConfig transport, @NonNull final SdlManagerListener listener) {
+ super(appId, appName, listener);
+ setContext(context);
+ setTransportType(transport);
+ }
+
+ /**
+ * Sets the LockScreenConfig for the session. <br>
+ * <strong>Note: If not set, the default configuration will be used.</strong>
+ *
+ * @param lockScreenConfig - configuration options
+ */
+ public Builder setLockScreenConfig(final LockScreenConfig lockScreenConfig) {
+ sdlManager.lockScreenConfig = lockScreenConfig;
+ return this;
+ }
+
+ /**
+ * Sets the Context
+ *
+ * @param context the current context
+ */
+ public Builder setContext(Context context) {
+ sdlManager.context = context;
+ return this;
+ }
+
+ /**
+ * Build SdlManager ang get it ready to be started
+ * <strong>Note: new instance of SdlManager should be created on every connection. SdlManager cannot be reused after getting disposed.</strong>
+ *
+ * @return SdlManager instance that is ready to be started
+ */
+ public SdlManager build() {
+ if (sdlManager.transport == null) {
+ throw new IllegalArgumentException("You must set a transport type object");
+ }
+
+ if (sdlManager.lockScreenConfig == null) {
+ // if lock screen params are not set, use default
+ sdlManager.lockScreenConfig = new LockScreenConfig();
+ }
+
+ super.build();
+
+ return sdlManager;
+ }
+ }
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/EncryptionLifecycleManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/EncryptionLifecycleManager.java
new file mode 100644
index 000000000..99723b456
--- /dev/null
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/EncryptionLifecycleManager.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.managers.lifecycle;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.managers.ServiceEncryptionListener;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+
+class EncryptionLifecycleManager extends BaseEncryptionLifecycleManager {
+
+ EncryptionLifecycleManager(@NonNull ISdl internalInterface, ServiceEncryptionListener listener) {
+ super(internalInterface, listener);
+ internalInterface.addServiceListener(SessionType.NAV, securedServiceListener);
+ internalInterface.addServiceListener(SessionType.PCM, securedServiceListener);
+ }
+}
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
new file mode 100644
index 000000000..777e29f1b
--- /dev/null
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.managers.lifecycle;
+
+import android.app.Service;
+import android.content.Context;
+import android.support.annotation.RestrictTo;
+import android.util.Log;
+
+import com.smartdevicelink.SdlConnection.SdlSession;
+import com.smartdevicelink.SdlConnection.SdlSession2;
+import com.smartdevicelink.exception.SdlException;
+import com.smartdevicelink.exception.SdlExceptionCause;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.proxy.interfaces.ISdlServiceListener;
+import com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason;
+import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
+import com.smartdevicelink.security.SdlSecurityBase;
+import com.smartdevicelink.streaming.video.VideoStreamingParameters;
+import com.smartdevicelink.transport.BaseTransportConfig;
+import com.smartdevicelink.transport.MultiplexTransportConfig;
+import com.smartdevicelink.transport.TCPTransportConfig;
+import com.smartdevicelink.transport.USBTransportConfig;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.util.DebugTool;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.ScheduledExecutorService;
+
+/**
+ * The lifecycle manager creates a central point for all SDL session logic to converge. It should only be used by
+ * the library itself. Usage outside the library is not permitted and will not be protected for in the future.
+ *
+ * @author Bilal Alsharifi.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class LifecycleManager extends BaseLifecycleManager {
+ private static final int RESPONSE_WAIT_TIME = 2000;
+ private ISdlServiceListener navServiceListener;
+ private boolean navServiceStartResponseReceived = false;
+ private boolean navServiceStartResponse = false;
+ private boolean navServiceEndResponseReceived = false;
+ private boolean navServiceEndResponse = false;
+ private boolean pcmServiceEndResponseReceived = false;
+ private boolean pcmServiceEndResponse = false;
+ private Context context;
+
+ public LifecycleManager(AppConfig appConfig, BaseTransportConfig config, LifecycleListener listener) {
+ super(appConfig, config, listener);
+ }
+
+ @Override
+ void initializeProxy() {
+ super.initializeProxy();
+
+ //Handle legacy USB connections
+ if (_transportConfig != null && TransportType.USB.equals(_transportConfig.getTransportType())) {
+ //A USB transport config was provided
+ USBTransportConfig usbTransportConfig = (USBTransportConfig) _transportConfig;
+ if (usbTransportConfig.getUsbAccessory() == null) {
+ DebugTool.logInfo("Legacy USB transport config was used, but received null for accessory. Attempting to connect with router service");
+ //The accessory was null which means it came from a router service
+ MultiplexTransportConfig multiplexTransportConfig = new MultiplexTransportConfig(usbTransportConfig.getUSBContext(), appConfig.getAppID());
+ multiplexTransportConfig.setRequiresHighBandwidth(true);
+ multiplexTransportConfig.setSecurityLevel(MultiplexTransportConfig.FLAG_MULTI_SECURITY_OFF);
+ multiplexTransportConfig.setPrimaryTransports(Collections.singletonList(TransportType.USB));
+ multiplexTransportConfig.setSecondaryTransports(new ArrayList<TransportType>());
+ _transportConfig = multiplexTransportConfig;
+ }
+ }
+
+ if (_transportConfig != null && _transportConfig.getTransportType().equals(TransportType.MULTIPLEX)) {
+ this.session = new SdlSession2(sdlConnectionListener, (MultiplexTransportConfig) _transportConfig);
+ } else if (_transportConfig != null && _transportConfig.getTransportType().equals(TransportType.TCP)) {
+ this.session = new SdlSession2(sdlConnectionListener, (TCPTransportConfig) _transportConfig);
+ } else {
+ this.session = SdlSession.createSession((byte) getProtocolVersion().getMajor(), sdlConnectionListener, _transportConfig);
+ }
+ }
+
+ private void cycleProxy(SdlDisconnectedReason disconnectedReason) {
+ cleanProxy();
+ initializeProxy();
+ if (!SdlDisconnectedReason.LEGACY_BLUETOOTH_MODE_ENABLED.equals(disconnectedReason) && !SdlDisconnectedReason.PRIMARY_TRANSPORT_CYCLE_REQUEST.equals(disconnectedReason)) {
+ //We don't want to alert higher if we are just cycling for legacy bluetooth
+ onClose("Sdl Proxy Cycled", new SdlException("Sdl Proxy Cycled", SdlExceptionCause.SDL_PROXY_CYCLED));
+ }
+ try {
+ session.startSession();
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ public void setContext(Context context) {
+ this.context = context;
+ }
+
+ @Override
+ void setSdlSecurityStaticVars() {
+ super.setSdlSecurityStaticVars();
+
+ Service service = null;
+ if (context != null && context instanceof Service) {
+ service = (Service) context;
+ }
+ SdlSecurityBase.setAppService(service);
+ SdlSecurityBase.setContext(context);
+ }
+
+ @Override
+ void onProtocolSessionStarted(SessionType sessionType) {
+ super.onProtocolSessionStarted(sessionType);
+ if (sessionType.eq(SessionType.NAV)) {
+ navServiceStartResponseReceived = true;
+ navServiceStartResponse = true;
+ }
+ }
+
+ @Override
+ void onTransportDisconnected(String info, boolean availablePrimary, BaseTransportConfig transportConfig) {
+ super.onTransportDisconnected(info, availablePrimary, transportConfig);
+ if (availablePrimary) {
+ _transportConfig = transportConfig;
+ Log.d(TAG, "notifying RPC session ended, but potential primary transport available");
+ cycleProxy(SdlDisconnectedReason.PRIMARY_TRANSPORT_CYCLE_REQUEST);
+ } else {
+ onClose(info, null);
+ }
+ }
+
+ @Override
+ void onProtocolSessionStartedNACKed(SessionType sessionType) {
+ super.onProtocolSessionStartedNACKed(sessionType);
+ if (sessionType.eq(SessionType.NAV)) {
+ navServiceStartResponseReceived = true;
+ navServiceStartResponse = false;
+ }
+ }
+
+ @Override
+ void onProtocolSessionEnded(SessionType sessionType) {
+ super.onProtocolSessionEnded(sessionType);
+ if (sessionType.eq(SessionType.NAV)) {
+ navServiceEndResponseReceived = true;
+ navServiceEndResponse = true;
+ } else if (sessionType.eq(SessionType.PCM)) {
+ pcmServiceEndResponseReceived = true;
+ pcmServiceEndResponse = true;
+ }
+ }
+
+ @Override
+ void onProtocolSessionEndedNACKed(SessionType sessionType) {
+ super.onProtocolSessionEndedNACKed(sessionType);
+ if (sessionType.eq(SessionType.NAV)) {
+ navServiceEndResponseReceived = true;
+ navServiceEndResponse = false;
+ } else if (sessionType.eq(SessionType.PCM)) {
+ pcmServiceEndResponseReceived = true;
+ pcmServiceEndResponse = false;
+ }
+ }
+
+ /**
+ * This method will try to start the video service with the requested parameters.
+ * When it returns it will attempt to store the accepted parameters if available.
+ *
+ * @param isEncrypted if the service should be encrypted
+ * @param parameters the desired video streaming parameters
+ */
+ @Override
+ void startVideoService(boolean isEncrypted, VideoStreamingParameters parameters) {
+ if (session == null) {
+ DebugTool.logWarning("SdlSession is not created yet.");
+ return;
+ }
+ if (!session.getIsConnected()) {
+ DebugTool.logWarning("Connection is not available.");
+ return;
+ }
+
+ session.setDesiredVideoParams(parameters);
+ tryStartVideoStream(isEncrypted, parameters);
+ }
+
+ /**
+ * Try to open a video service by using the video streaming parameters supplied.
+ * Only information from codecs, width and height are used during video format negotiation.
+ *
+ * @param isEncrypted Specify true if packets on this service have to be encrypted
+ * @param parameters VideoStreamingParameters that are desired. Does not guarantee this is what will be accepted.
+ * @return If the service is opened successfully, an instance of VideoStreamingParams is
+ * returned which contains accepted video format. If the service is opened with legacy
+ * mode (i.e. without any negotiation) then an instance of VideoStreamingParams is
+ * returned. If the service was not opened then null is returned.
+ */
+ private VideoStreamingParameters tryStartVideoStream(boolean isEncrypted, VideoStreamingParameters parameters) {
+ if (session == null) {
+ DebugTool.logWarning("SdlSession is not created yet.");
+ return null;
+ }
+ if (getProtocolVersion() != null && getProtocolVersion().getMajor() >= 5 && !systemCapabilityManager.isCapabilitySupported(SystemCapabilityType.VIDEO_STREAMING)) {
+ DebugTool.logWarning("Module doesn't support video streaming.");
+ return null;
+ }
+ if (parameters == null) {
+ DebugTool.logWarning("Video parameters were not supplied.");
+ return null;
+ }
+
+ if (!navServiceStartResponseReceived || !navServiceStartResponse //If we haven't started the service before
+ || (navServiceStartResponse && isEncrypted && !session.isServiceProtected(SessionType.NAV))) { //Or the service has been started but we'd like to start an encrypted one
+ session.setDesiredVideoParams(parameters);
+
+ navServiceStartResponseReceived = false;
+ navServiceStartResponse = false;
+
+ session.startService(SessionType.NAV, session.getSessionId(), isEncrypted);
+ addNavListener();
+ FutureTask<Void> fTask = new FutureTask<>(new CallableMethod(RESPONSE_WAIT_TIME));
+ ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
+ scheduler.execute(fTask);
+
+ //noinspection StatementWithEmptyBody
+ while (!navServiceStartResponseReceived && !fTask.isDone()) ;
+ scheduler.shutdown();
+ }
+
+ if (navServiceStartResponse) {
+ if (getProtocolVersion() != null && getProtocolVersion().getMajor() < 5) { //Versions 1-4 do not support streaming parameter negotiations
+ session.setAcceptedVideoParams(parameters);
+ }
+ return session.getAcceptedVideoParams();
+ }
+
+ return null;
+ }
+
+ private void addNavListener() {
+ // videos may be started and stopped. Only add this once
+ if (navServiceListener == null) {
+
+ navServiceListener = new ISdlServiceListener() {
+ @Override
+ public void onServiceStarted(SdlSession session, SessionType type, boolean isEncrypted) {
+ }
+
+ @Override
+ public void onServiceEnded(SdlSession session, SessionType type) {
+ // reset nav flags so nav can start upon the next transport connection
+ navServiceStartResponseReceived = false;
+ navServiceStartResponse = false;
+ }
+
+ @Override
+ public void onServiceError(SdlSession session, SessionType type, String reason) {
+ // if there is an error reset the flags so that there is a chance to restart streaming
+ navServiceStartResponseReceived = false;
+ navServiceStartResponse = false;
+ }
+ };
+ session.addServiceListener(SessionType.NAV, navServiceListener);
+ }
+ }
+
+ /**
+ * Closes the opened video service (serviceType 11)
+ *
+ * @return true if the video service is closed successfully, return false otherwise
+ */
+ @Override
+ boolean endVideoStream() {
+ if (session == null) {
+ DebugTool.logWarning("SdlSession is not created yet.");
+ return false;
+ }
+ if (!session.getIsConnected()) {
+ DebugTool.logWarning("Connection is not available.");
+ return false;
+ }
+
+ navServiceEndResponseReceived = false;
+ navServiceEndResponse = false;
+ session.stopVideoStream();
+
+ FutureTask<Void> fTask = new FutureTask<>(new CallableMethod(RESPONSE_WAIT_TIME));
+ ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
+ scheduler.execute(fTask);
+
+ //noinspection StatementWithEmptyBody
+ while (!navServiceEndResponseReceived && !fTask.isDone()) ;
+ scheduler.shutdown();
+
+ return navServiceEndResponse;
+ }
+
+ @Override
+ void startAudioService(boolean isEncrypted) {
+ if (session == null) {
+ DebugTool.logWarning("SdlSession is not created yet.");
+ return;
+ }
+ if (!session.getIsConnected()) {
+ DebugTool.logWarning("Connection is not available.");
+ return;
+ }
+ session.startService(SessionType.PCM, session.getSessionId(), isEncrypted);
+ }
+
+ /**
+ * Closes the opened audio service (serviceType 10)
+ *
+ * @return true if the audio service is closed successfully, return false otherwise
+ */
+ @Override
+ boolean endAudioStream() {
+ if (session == null) {
+ DebugTool.logWarning("SdlSession is not created yet.");
+ return false;
+ }
+ if (!session.getIsConnected()) {
+ DebugTool.logWarning("Connection is not available.");
+ return false;
+ }
+
+ pcmServiceEndResponseReceived = false;
+ pcmServiceEndResponse = false;
+ session.stopAudioStream();
+
+ FutureTask<Void> fTask = new FutureTask<>(new CallableMethod(RESPONSE_WAIT_TIME));
+ ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
+ scheduler.execute(fTask);
+
+ //noinspection StatementWithEmptyBody
+ while (!pcmServiceEndResponseReceived && !fTask.isDone()) ;
+ scheduler.shutdown();
+
+ return pcmServiceEndResponse;
+ }
+
+ private class CallableMethod implements Callable<Void> {
+ private final long waitTime;
+
+ public CallableMethod(int timeInMillis) {
+ this.waitTime = timeInMillis;
+ }
+
+ @Override
+ public Void call() {
+ try {
+ Thread.sleep(waitTime);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+ }
+}
diff --git a/base/src/main/java/com/smartdevicelink/managers/BaseSdlManager.java b/base/src/main/java/com/smartdevicelink/managers/BaseSdlManager.java
index df1c18d42..c52f27b2d 100644
--- a/base/src/main/java/com/smartdevicelink/managers/BaseSdlManager.java
+++ b/base/src/main/java/com/smartdevicelink/managers/BaseSdlManager.java
@@ -31,24 +31,46 @@
*/
package com.smartdevicelink.managers;
+import android.support.annotation.NonNull;
import android.util.Log;
+import com.smartdevicelink.managers.file.FileManager;
+import com.smartdevicelink.managers.file.FileManagerConfig;
+import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
+import com.smartdevicelink.managers.lifecycle.LifecycleConfigurationUpdate;
+import com.smartdevicelink.managers.lifecycle.LifecycleManager;
+import com.smartdevicelink.managers.permission.PermissionManager;
+import com.smartdevicelink.managers.screen.ScreenManager;
import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.protocol.enums.SessionType;
import com.smartdevicelink.proxy.RPCMessage;
import com.smartdevicelink.proxy.RPCNotification;
+import com.smartdevicelink.proxy.RPCRequest;
+import com.smartdevicelink.proxy.RPCResponse;
+import com.smartdevicelink.proxy.SystemCapabilityManager;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.rpc.ChangeRegistration;
import com.smartdevicelink.proxy.rpc.OnHMIStatus;
import com.smartdevicelink.proxy.rpc.RegisterAppInterfaceResponse;
+import com.smartdevicelink.proxy.rpc.SetAppIcon;
import com.smartdevicelink.proxy.rpc.TTSChunk;
import com.smartdevicelink.proxy.rpc.TemplateColorScheme;
import com.smartdevicelink.proxy.rpc.enums.AppHMIType;
import com.smartdevicelink.proxy.rpc.enums.Language;
+import com.smartdevicelink.proxy.rpc.enums.Result;
+import com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason;
import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
import com.smartdevicelink.proxy.rpc.listeners.OnRPCRequestListener;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener;
+import com.smartdevicelink.security.SdlSecurityBase;
import com.smartdevicelink.transport.BaseTransportConfig;
import com.smartdevicelink.util.DebugTool;
import com.smartdevicelink.util.Version;
+import org.json.JSONException;
+
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
@@ -58,13 +80,9 @@ import java.util.concurrent.ConcurrentLinkedQueue;
abstract class BaseSdlManager {
- private static final String TAG = "BaseSubManager";
-
+ static final String TAG = "BaseSubManager";
final Object STATE_LOCK = new Object();
int state = -1;
-
- static final int MAX_RETRY = 3;
- int changeRegistrationRetry = 0;
String appId, appName, shortAppName;
boolean isMediaApp;
Language hmiLanguage;
@@ -76,41 +94,153 @@ abstract class BaseSdlManager {
TemplateColorScheme dayColorScheme, nightColorScheme;
Version minimumProtocolVersion;
Version minimumRPCVersion;
-
Queue<RPCNotification> queuedNotifications = null;
OnRPCNotificationListener queuedNotificationListener = null;
Map<FunctionID, OnRPCNotificationListener> onRPCNotificationListeners;
+ SdlArtwork appIcon;
+ SdlManagerListener managerListener;
+ List<Class<? extends SdlSecurityBase>> sdlSecList;
+ ServiceEncryptionListener serviceEncryptionListener;
+ FileManagerConfig fileManagerConfig;
+ int changeRegistrationRetry = 0;
+ static final int MAX_RETRY = 3;
- // PROTECTED GETTERS
- protected String getAppName() { return appName; }
+ // Managers
+ LifecycleManager lifecycleManager;
+ PermissionManager permissionManager;
+ FileManager fileManager;
+ ScreenManager screenManager;
+
+ // INTERNAL INTERFACE
+ /**
+ * This is from the LifeCycleManager directly. In the future if there is a reason to be a man in the middle
+ * the SdlManager could create it's own, however right now it was only a duplication of logic tied to the LCM.
+ */
+ ISdl _internalInterface;
+
+ // Initialize with anonymous lifecycleListener
+ final LifecycleManager.LifecycleListener lifecycleListener = new LifecycleManager.LifecycleListener() {
+ @Override
+ public void onProxyConnected(LifecycleManager lifeCycleManager) {
+ Log.i(TAG, "Proxy is connected. Now initializing.");
+ synchronized (this) {
+ changeRegistrationRetry = 0;
+ checkLifecycleConfiguration();
+ initialize();
+ }
+ }
- protected String getAppId() { return appId; }
+ @Override
+ public void onServiceStarted(SessionType sessionType) {
- protected String getShortAppName() { return shortAppName; }
+ }
- protected Version getMinimumProtocolVersion() { return minimumProtocolVersion; }
+ @Override
+ public void onServiceEnded(SessionType sessionType) {
- protected Version getMinimumRPCVersion() { return minimumRPCVersion; }
+ }
- protected Language getHmiLanguage() { return hmiLanguage; }
+ @Override
+ public void onProxyClosed(LifecycleManager lifeCycleManager, String info, Exception e, SdlDisconnectedReason reason) {
+ BaseSdlManager.this.onProxyClosed(reason);
+ }
- protected Language getLanguage() { return language; }
+ @Override
+ public void onError(LifecycleManager lifeCycleManager, String info, Exception e) {
- protected TemplateColorScheme getDayColorScheme() { return dayColorScheme; }
+ }
+ };
+
+ // Sub manager listener
+ final CompletionListener subManagerListener = new CompletionListener() {
+ @Override
+ public synchronized void onComplete(boolean success) {
+ if (!success) {
+ Log.e(TAG, "Sub manager failed to initialize");
+ }
+ checkState();
+ }
+ };
- protected TemplateColorScheme getNightColorScheme() { return nightColorScheme; }
+ // ABSTRACT METHODS
+ abstract void retryChangeRegistration();
- protected Vector<AppHMIType> getAppTypes() { return hmiTypes; }
+ abstract void onProxyClosed(SdlDisconnectedReason reason);
- protected Vector<String> getVrSynonyms() { return vrSynonyms; }
+ abstract void checkState();
- protected Vector<TTSChunk> getTtsChunks() { return ttsChunks; }
+ abstract void initialize();
- protected BaseTransportConfig getTransport() { return transport; }
+ public abstract void dispose();
+ protected void checkLifecycleConfiguration() {
+ final Language actualLanguage = this.getRegisterAppInterfaceResponse().getLanguage();
+ final Language actualHMILanguage = this.getRegisterAppInterfaceResponse().getHmiDisplayLanguage();
+
+ if ((actualLanguage != null && !actualLanguage.equals(language)) || (actualHMILanguage != null && !actualHMILanguage.equals(hmiLanguage))) {
+
+ LifecycleConfigurationUpdate lcuNew = managerListener.managerShouldUpdateLifecycle(actualLanguage, actualHMILanguage);
+ LifecycleConfigurationUpdate lcuOld = managerListener.managerShouldUpdateLifecycle(actualLanguage);
+ final LifecycleConfigurationUpdate lcu;
+ ChangeRegistration changeRegistration;
+ if (lcuNew == null) {
+ lcu = lcuOld;
+ changeRegistration = new ChangeRegistration(actualLanguage, actualLanguage);
+ } else {
+ lcu = lcuNew;
+ changeRegistration = new ChangeRegistration(actualLanguage, actualHMILanguage);
+ }
+
+ if (lcu != null) {
+ changeRegistration.setAppName(lcu.getAppName());
+ changeRegistration.setNgnMediaScreenAppName(lcu.getShortAppName());
+ changeRegistration.setTtsName(lcu.getTtsName());
+ changeRegistration.setVrSynonyms(lcu.getVoiceRecognitionCommandNames());
+ changeRegistration.setOnRPCResponseListener(new OnRPCResponseListener() {
+ @Override
+ public void onResponse(int correlationId, RPCResponse response) {
+ if (response.getSuccess()) {
+ // go through and change sdlManager properties that were changed via the LCU update
+ hmiLanguage = actualHMILanguage;
+ language = actualLanguage;
+
+ if (lcu.getAppName() != null) {
+ appName = lcu.getAppName();
+ }
+
+ if (lcu.getShortAppName() != null) {
+ shortAppName = lcu.getShortAppName();
+ }
+
+ if (lcu.getTtsName() != null) {
+ ttsChunks = lcu.getTtsName();
+ }
+
+ if (lcu.getVoiceRecognitionCommandNames() != null) {
+ vrSynonyms = lcu.getVoiceRecognitionCommandNames();
+ }
+ }
+ try {
+ DebugTool.logInfo(response.serializeJSON().toString());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onError(int correlationId, Result resultCode, String info) {
+ DebugTool.logError("Change Registration onError: " + resultCode + " | Info: " + info);
+ retryChangeRegistration();
+ }
+ });
+ this.sendRPC(changeRegistration);
+ }
+ }
+ }
/**
* Get the current state for the SdlManager
+ *
* @return int value that represents the current state
* @see BaseSubManager
*/
@@ -126,13 +256,13 @@ abstract class BaseSdlManager {
}
}
- void checkSdlManagerState(){
- if (getState() != BaseSubManager.READY && getState() != BaseSubManager.LIMITED){
+ void checkSdlManagerState() {
+ if (getState() != BaseSubManager.READY && getState() != BaseSubManager.LIMITED) {
Log.e(TAG, "SdlManager is not ready for use, be sure to initialize with start() method, implement callback, and use SubManagers in the SdlManager's callback");
}
}
- void initNotificationQueue(){
+ void initNotificationQueue() {
//Setup the notification queue
if (onRPCNotificationListeners != null) {
Set<FunctionID> functionIDSet = onRPCNotificationListeners.keySet();
@@ -151,7 +281,7 @@ abstract class BaseSdlManager {
}
}
- void handleQueuedNotifications(){
+ void handleQueuedNotifications() {
//Handle queued notifications and add the listeners
if (onRPCNotificationListeners != null) {
Set<FunctionID> functionIDSet = onRPCNotificationListeners.keySet();
@@ -184,39 +314,564 @@ abstract class BaseSdlManager {
}
}
- abstract void checkState();
+ /**
+ * Starts up a SdlManager, and calls provided callback called once all BaseSubManagers are done setting up
+ */
+ @SuppressWarnings("unchecked")
+ public void start() {
+ LifecycleManager.AppConfig appConfig = new LifecycleManager.AppConfig();
+ appConfig.setAppName(appName);
+ //short app name
+ appConfig.setMediaApp(isMediaApp);
+ appConfig.setHmiDisplayLanguageDesired(hmiLanguage);
+ appConfig.setLanguageDesired(hmiLanguage);
+ appConfig.setAppType(hmiTypes);
+ appConfig.setVrSynonyms(vrSynonyms);
+ appConfig.setTtsName(ttsChunks);
+ appConfig.setDayColorScheme(dayColorScheme);
+ appConfig.setNightColorScheme(nightColorScheme);
+ appConfig.setAppID(appId);
+ appConfig.setMinimumProtocolVersion(minimumProtocolVersion);
+ appConfig.setMinimumRPCVersion(minimumRPCVersion);
+
+ lifecycleManager = new LifecycleManager(appConfig, transport, lifecycleListener);
+ _internalInterface = lifecycleManager.getInternalInterface((SdlManager) BaseSdlManager.this);
+
+ if (sdlSecList != null && !sdlSecList.isEmpty()) {
+ lifecycleManager.setSdlSecurity(sdlSecList, serviceEncryptionListener);
+ }
- protected abstract void initialize();
- protected abstract void checkLifecycleConfiguration();
+ //Setup the notification queue
+ initNotificationQueue();
+ }
- //Public abstract API
- public abstract void start();
- public abstract void dispose();
- public abstract void sendRPC(RPCMessage message);
- public abstract void sendSequentialRPCs(final List<? extends RPCMessage> rpcs, final OnMultipleRequestListener listener);
- public abstract void sendRPCs(List<? extends RPCMessage> rpcs, final OnMultipleRequestListener listener);
- public abstract RegisterAppInterfaceResponse getRegisterAppInterfaceResponse();
- public abstract OnHMIStatus getCurrentHMIStatus();
- public abstract String getAuthToken();
+ void onReady() {
+ // Set the app icon
+ if (BaseSdlManager.this.appIcon != null && BaseSdlManager.this.appIcon.getName() != null) {
+ if (fileManager != null && fileManager.getState() == BaseSubManager.READY && !fileManager.hasUploadedFile(BaseSdlManager.this.appIcon)) {
+ fileManager.uploadArtwork(BaseSdlManager.this.appIcon, new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ if (success) {
+ SetAppIcon msg = new SetAppIcon(BaseSdlManager.this.appIcon.getName());
+ _internalInterface.sendRPC(msg);
+ }
+ }
+ });
+ } else {
+ SetAppIcon msg = new SetAppIcon(BaseSdlManager.this.appIcon.getName());
+ _internalInterface.sendRPC(msg);
+ }
+ }
+ }
+
+ // PROTECTED GETTERS
+ protected String getAppName() {
+ return appName;
+ }
- public abstract void addOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener);
+ protected String getAppId() {
+ return appId;
+ }
+
+ protected String getShortAppName() {
+ return shortAppName;
+ }
+
+ protected Version getMinimumProtocolVersion() {
+ return minimumProtocolVersion;
+ }
+
+ protected Version getMinimumRPCVersion() {
+ return minimumRPCVersion;
+ }
+
+ protected Language getHmiLanguage() {
+ return hmiLanguage;
+ }
+
+ protected Language getLanguage() {
+ return language;
+ }
+
+ protected TemplateColorScheme getDayColorScheme() {
+ return dayColorScheme;
+ }
+
+ protected TemplateColorScheme getNightColorScheme() {
+ return nightColorScheme;
+ }
+
+ protected Vector<AppHMIType> getAppTypes() {
+ return hmiTypes;
+ }
+
+ protected Vector<String> getVrSynonyms() {
+ return vrSynonyms;
+ }
+
+ protected Vector<TTSChunk> getTtsChunks() {
+ return ttsChunks;
+ }
+
+ protected BaseTransportConfig getTransport() {
+ return transport;
+ }
+
+ protected FileManagerConfig getFileManagerConfig() {
+ return fileManagerConfig;
+ }
+
+ // MANAGER GETTERS
+
+ /**
+ * Gets the PermissionManager. <br>
+ * <strong>Note: PermissionManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
+ *
+ * @return a PermissionManager object
+ */
+ public PermissionManager getPermissionManager() {
+ if (permissionManager.getState() != BaseSubManager.READY && permissionManager.getState() != BaseSubManager.LIMITED) {
+ Log.e(TAG, "PermissionManager should not be accessed because it is not in READY/LIMITED state");
+ }
+ checkSdlManagerState();
+ return permissionManager;
+ }
+
+ /**
+ * Gets the FileManager. <br>
+ * <strong>Note: FileManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
+ *
+ * @return a FileManager object
+ */
+ public FileManager getFileManager() {
+ if (fileManager.getState() != BaseSubManager.READY && fileManager.getState() != BaseSubManager.LIMITED) {
+ Log.e(TAG, "FileManager should not be accessed because it is not in READY/LIMITED state");
+ }
+ checkSdlManagerState();
+ return fileManager;
+ }
+
+ /**
+ * Gets the ScreenManager. <br>
+ * <strong>Note: ScreenManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
+ *
+ * @return a ScreenManager object
+ */
+ public ScreenManager getScreenManager() {
+ if (screenManager.getState() != BaseSubManager.READY && screenManager.getState() != BaseSubManager.LIMITED) {
+ Log.e(TAG, "ScreenManager should not be accessed because it is not in READY/LIMITED state");
+ }
+ checkSdlManagerState();
+ return screenManager;
+ }
+
+ /**
+ * Gets the SystemCapabilityManager. <br>
+ * <strong>Note: SystemCapabilityManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
+ *
+ * @return a SystemCapabilityManager object
+ */
+ public SystemCapabilityManager getSystemCapabilityManager() {
+ return lifecycleManager.getSystemCapabilityManager((SdlManager) this);
+ }
+
+ /**
+ * Method to retrieve the RegisterAppInterface Response message that was sent back from the
+ * module. It contains various attributes about the connected module and can be used to adapt
+ * to different module types and their supported features.
+ *
+ * @return RegisterAppInterfaceResponse received from the module or null if the app has not yet
+ * registered with the module.
+ */
+ public RegisterAppInterfaceResponse getRegisterAppInterfaceResponse() {
+ if (lifecycleManager != null) {
+ return lifecycleManager.getRegisterAppInterfaceResponse();
+ }
+ return null;
+ }
+
+ /**
+ * Get the current OnHMIStatus
+ *
+ * @return OnHMIStatus object represents the current OnHMIStatus
+ */
+ public OnHMIStatus getCurrentHMIStatus() {
+ if (this.lifecycleManager != null) {
+ return lifecycleManager.getCurrentHMIStatus();
+ }
+ return null;
+ }
+
+ /**
+ * Retrieves the auth token, if any, that was attached to the StartServiceACK for the RPC
+ * service from the module. For example, this should be used to login to a user account.
+ *
+ * @return the string representation of the auth token
+ */
+ public String getAuthToken() {
+ return this.lifecycleManager.getAuthToken();
+ }
+
+ // SENDING REQUESTS
+
+ /**
+ * Send RPC Message <br>
+ *
+ * @param message RPCMessage
+ */
+ public void sendRPC(RPCMessage message) {
+ _internalInterface.sendRPC(message);
+ }
+
+ /**
+ * Takes a list of RPCMessages and sends it to SDL in a synchronous fashion. Responses are captured through callback on OnMultipleRequestListener.
+ * For sending requests asynchronously, use sendRPCs <br>
+ *
+ * <strong>NOTE: This will override any listeners on individual RPCs</strong><br>
+ *
+ * <strong>ADDITIONAL NOTE: This only takes the type of RPCRequest for now, notifications and responses will be thrown out</strong>
+ *
+ * @param rpcs is the list of RPCMessages being sent
+ * @param listener listener for updates and completions
+ */
+ public void sendSequentialRPCs(final List<? extends RPCMessage> rpcs, final OnMultipleRequestListener listener) {
+ List<RPCRequest> rpcRequestList = new ArrayList<>();
+ for (int i = 0; i < rpcs.size(); i++) {
+ if (rpcs.get(i) instanceof RPCRequest) {
+ rpcRequestList.add((RPCRequest) rpcs.get(i));
+ }
+ }
+
+ if (rpcRequestList.size() > 0) {
+ _internalInterface.sendSequentialRPCs(rpcRequestList, listener);
+ }
+ }
+
+ /**
+ * Takes a list of RPCMessages and sends it to SDL. Responses are captured through callback on OnMultipleRequestListener.
+ * For sending requests synchronously, use sendSequentialRPCs <br>
+ *
+ * <strong>NOTE: This will override any listeners on individual RPCs</strong> <br>
+ *
+ * <strong>ADDITIONAL NOTE: This only takes the type of RPCRequest for now, notifications and responses will be thrown out</strong>
+ *
+ * @param rpcs is the list of RPCMessages being sent
+ * @param listener listener for updates and completions
+ */
+ public void sendRPCs(List<? extends RPCMessage> rpcs, final OnMultipleRequestListener listener) {
+ List<RPCRequest> rpcRequestList = new ArrayList<>();
+ for (int i = 0; i < rpcs.size(); i++) {
+ if (rpcs.get(i) instanceof RPCRequest) {
+ rpcRequestList.add((RPCRequest) rpcs.get(i));
+ }
+ }
+
+ if (rpcRequestList.size() > 0) {
+ _internalInterface.sendRPCs(rpcRequestList, listener);
+ }
+ }
+
+ /**
+ * Add an OnRPCNotificationListener
+ *
+ * @param listener listener that will be called when a notification is received
+ */
+ public void addOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {
+ _internalInterface.addOnRPCNotificationListener(notificationId, listener);
+ }
/**
* Remove an OnRPCNotificationListener
+ *
* @param listener listener that was previously added
*/
- public abstract void removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener);
+ public void removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {
+ _internalInterface.removeOnRPCNotificationListener(notificationId, listener);
+ }
/**
* Add an OnRPCRequestListener
+ *
* @param listener listener that will be called when a request is received
*/
- public abstract void addOnRPCRequestListener(FunctionID requestId, OnRPCRequestListener listener);
+ public void addOnRPCRequestListener(FunctionID requestId, OnRPCRequestListener listener) {
+ _internalInterface.addOnRPCRequestListener(requestId, listener);
+ }
/**
* Remove an OnRPCRequestListener
+ *
* @param listener listener that was previously added
*/
- public abstract void removeOnRPCRequestListener(FunctionID requestId, OnRPCRequestListener listener);
+ public void removeOnRPCRequestListener(FunctionID requestId, OnRPCRequestListener listener) {
+ _internalInterface.removeOnRPCRequestListener(requestId, listener);
+ }
+
+ // BUILDER
+ public static class Builder {
+ SdlManager sdlManager;
+
+ Builder(@NonNull final String appId, @NonNull final String appName, @NonNull final SdlManagerListener listener) {
+ sdlManager = new SdlManager();
+ setAppId(appId);
+ setAppName(appName);
+ setManagerListener(listener);
+ }
+
+ /**
+ * Sets the App ID
+ *
+ * @param appId String representation of the App ID retreived from the SDL Developer Portal
+ */
+ public Builder setAppId(@NonNull final String appId) {
+ sdlManager.appId = appId;
+ return this;
+ }
+
+ /**
+ * Sets the Application Name
+ *
+ * @param appName String that will be associated as the app's name
+ */
+ public Builder setAppName(@NonNull final String appName) {
+ sdlManager.appName = appName;
+ return this;
+ }
+
+ /**
+ * Sets the Short Application Name
+ *
+ * @param shortAppName a shorter representation of the app's name for smaller displays
+ */
+ public Builder setShortAppName(final String shortAppName) {
+ sdlManager.shortAppName = shortAppName;
+ return this;
+ }
+
+ /**
+ * Sets the minimum protocol version that will be permitted to connect.
+ * If the protocol version of the head unit connected is below this version,
+ * the app will disconnect with an EndService protocol message and will not register.
+ *
+ * @param minimumProtocolVersion the minimum Protocol spec version that should be accepted
+ */
+ public Builder setMinimumProtocolVersion(final Version minimumProtocolVersion) {
+ sdlManager.minimumProtocolVersion = minimumProtocolVersion;
+ return this;
+ }
+
+ /**
+ * The minimum RPC version that will be permitted to connect.
+ * If the RPC version of the head unit connected is below this version, an UnregisterAppInterface will be sent.
+ *
+ * @param minimumRPCVersion the minimum RPC spec version that should be accepted
+ */
+ public Builder setMinimumRPCVersion(final Version minimumRPCVersion) {
+ sdlManager.minimumRPCVersion = minimumRPCVersion;
+ return this;
+ }
+
+ /**
+ * Sets the Language of the App
+ *
+ * @param hmiLanguage the desired language to be used on the display/HMI of the connected module
+ */
+ public Builder setLanguage(final Language hmiLanguage) {
+ sdlManager.hmiLanguage = hmiLanguage;
+ sdlManager.language = hmiLanguage;
+ return this;
+ }
+
+ /**
+ * Sets the TemplateColorScheme for daytime
+ *
+ * @param dayColorScheme color scheme that will be used (if supported) when the display is in a "Day Mode" or
+ * similar. Should comprise of colors that contrast well during the day under sunlight.
+ */
+ public Builder setDayColorScheme(final TemplateColorScheme dayColorScheme) {
+ sdlManager.dayColorScheme = dayColorScheme;
+ return this;
+ }
+
+ /**
+ * Sets the TemplateColorScheme for nighttime
+ *
+ * @param nightColorScheme color scheme that will be used (if supported) when the display is in a "Night Mode"
+ * or similar. Should comprise of colors that contrast well during the night and are not
+ * brighter than average.
+ */
+ public Builder setNightColorScheme(final TemplateColorScheme nightColorScheme) {
+ sdlManager.nightColorScheme = nightColorScheme;
+ return this;
+ }
+
+ /**
+ * Sets the icon for the app on head unit / In-Vehicle-Infotainment system <br>
+ *
+ * @param sdlArtwork the icon that will be used to represent this application on the connected module
+ */
+ public Builder setAppIcon(final SdlArtwork sdlArtwork) {
+ sdlManager.appIcon = sdlArtwork;
+ return this;
+ }
+
+ /**
+ * Sets the vector of AppHMIType <br>
+ * <strong>Note: This should be an ordered list from most -> least relevant</strong>
+ *
+ * @param hmiTypes HMI types that represent this application. For example, if the app is a music player, the
+ * MEDIA HMIType should be included.
+ */
+ public Builder setAppTypes(final Vector<AppHMIType> hmiTypes) {
+ sdlManager.hmiTypes = hmiTypes;
+
+ if (hmiTypes != null) {
+ sdlManager.isMediaApp = hmiTypes.contains(AppHMIType.MEDIA);
+ }
+
+ return this;
+ }
+
+ /**
+ * Sets the FileManagerConfig for the session.<br>
+ * <strong>Note: If not set, the default configuration value of 1 will be set for
+ * artworkRetryCount and fileRetryCount in FileManagerConfig</strong>
+ *
+ * @param fileManagerConfig - configuration options
+ */
+ public Builder setFileManagerConfig(final FileManagerConfig fileManagerConfig) {
+ sdlManager.fileManagerConfig = fileManagerConfig;
+ return this;
+ }
+
+ /**
+ * Sets the voice recognition synonyms that can be used to identify this application.
+ *
+ * @param vrSynonyms a vector of Strings that can be associated with this app. For example the app's name should
+ * be included as well as any phonetic spellings of the app name that might help the on-board
+ * VR system associated a users spoken word with the supplied synonyms.
+ */
+ public Builder setVrSynonyms(final Vector<String> vrSynonyms) {
+ sdlManager.vrSynonyms = vrSynonyms;
+ return this;
+ }
+
+ /**
+ * Sets the Text-To-Speech Name of the application. These TTSChunks might be used by the module as an audio
+ * representation of the app's name.
+ *
+ * @param ttsChunks the TTS chunks that can represent this app's name
+ */
+ public Builder setTtsName(final Vector<TTSChunk> ttsChunks) {
+ sdlManager.ttsChunks = ttsChunks;
+ return this;
+ }
+
+ /**
+ * This Object type may change with the transport refactor
+ * Sets the BaseTransportConfig
+ *
+ * @param transport the type of transport that should be used for this SdlManager instance.
+ */
+ public Builder setTransportType(@NonNull BaseTransportConfig transport) {
+ sdlManager.transport = transport;
+ return this;
+ }
+
+ /**
+ * Sets the Security libraries
+ *
+ * @param secList The list of security class(es)
+ */
+ @Deprecated
+ public Builder setSdlSecurity(List<Class<? extends SdlSecurityBase>> secList) {
+ sdlManager.sdlSecList = secList;
+ return this;
+ }
+
+ /**
+ * Sets the security libraries and a callback to notify caller when there is update to encryption service
+ *
+ * @param secList The list of security class(es)
+ * @param listener The callback object
+ */
+ public Builder setSdlSecurity(@NonNull List<Class<? extends SdlSecurityBase>> secList, ServiceEncryptionListener listener) {
+ sdlManager.sdlSecList = secList;
+ sdlManager.serviceEncryptionListener = listener;
+ return this;
+ }
+
+ /**
+ * Set the SdlManager Listener
+ *
+ * @param listener the listener
+ */
+ public Builder setManagerListener(@NonNull final SdlManagerListener listener) {
+ sdlManager.managerListener = listener;
+ return this;
+ }
+ /**
+ * Set RPCNotification listeners. SdlManager will preload these listeners before any RPCs are sent/received.
+ *
+ * @param listeners a map of listeners that will be called when a notification is received.
+ * Key represents the FunctionID of the notification and value represents the listener
+ */
+ public Builder setRPCNotificationListeners(Map<FunctionID, OnRPCNotificationListener> listeners) {
+ sdlManager.onRPCNotificationListeners = listeners;
+ return this;
+ }
+
+ public SdlManager build() {
+ if (sdlManager.appName == null) {
+ throw new IllegalArgumentException("You must specify an app name by calling setAppName");
+ }
+
+ if (sdlManager.appId == null) {
+ throw new IllegalArgumentException("You must specify an app ID by calling setAppId");
+ }
+
+ if (sdlManager.managerListener == null) {
+ throw new IllegalArgumentException("You must set a SdlManagerListener object");
+ }
+
+ if (sdlManager.hmiTypes == null) {
+ Vector<AppHMIType> hmiTypesDefault = new Vector<>();
+ hmiTypesDefault.add(AppHMIType.DEFAULT);
+ sdlManager.hmiTypes = hmiTypesDefault;
+ sdlManager.isMediaApp = false;
+ }
+ if (sdlManager.fileManagerConfig == null) {
+ //if FileManagerConfig is not set use default
+ sdlManager.fileManagerConfig = new FileManagerConfig();
+ }
+
+ if (sdlManager.hmiLanguage == null) {
+ sdlManager.hmiLanguage = Language.EN_US;
+ sdlManager.language = Language.EN_US;
+ }
+
+ if (sdlManager.minimumProtocolVersion == null) {
+ sdlManager.minimumProtocolVersion = new Version("1.0.0");
+ }
+
+ if (sdlManager.minimumRPCVersion == null) {
+ sdlManager.minimumRPCVersion = new Version("1.0.0");
+ }
+
+ sdlManager.transitionToState(BaseSubManager.SETTING_UP);
+
+ return sdlManager;
+ }
+ }
+
+ /**
+ * Start a secured RPC service
+ */
+ public void startRPCEncryption() {
+ if (lifecycleManager != null) {
+ lifecycleManager.startRPCEncryption();
+ }
+ }
}
diff --git a/base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseEncryptionLifecycleManager.java b/base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseEncryptionLifecycleManager.java
index 808f4b0cd..eca2ce239 100644
--- a/base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseEncryptionLifecycleManager.java
+++ b/base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseEncryptionLifecycleManager.java
@@ -57,6 +57,7 @@ abstract class BaseEncryptionLifecycleManager {
private HMILevel currentHMILevel;
private Set<String> encryptionRequiredRPCs = new HashSet<>();
private boolean rpcSecuredServiceStarted;
+ ISdlServiceListener securedServiceListener;
BaseEncryptionLifecycleManager(@NonNull ISdl isdl, ServiceEncryptionListener listener) {
internalInterface = isdl;
@@ -94,7 +95,7 @@ abstract class BaseEncryptionLifecycleManager {
}
};
- ISdlServiceListener securedServiceListener = new ISdlServiceListener() {
+ securedServiceListener = new ISdlServiceListener() {
@Override
public void onServiceStarted(SdlSession session, SessionType type, boolean isEncrypted) {
if(SessionType.RPC.equals(type)){
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 254b0d505..0054b7810 100644
--- a/base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseLifecycleManager.java
+++ b/base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseLifecycleManager.java
@@ -32,5 +32,1513 @@
package com.smartdevicelink.managers.lifecycle;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.util.Log;
+
+import com.smartdevicelink.SdlConnection.ISdlConnectionListener;
+import com.smartdevicelink.SdlConnection.SdlSession;
+import com.smartdevicelink.exception.SdlException;
+import com.smartdevicelink.managers.SdlManager;
+import com.smartdevicelink.managers.ServiceEncryptionListener;
+import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.protocol.ProtocolMessage;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.protocol.enums.MessageType;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.proxy.RPCMessage;
+import com.smartdevicelink.proxy.RPCNotification;
+import com.smartdevicelink.proxy.RPCRequest;
+import com.smartdevicelink.proxy.RPCResponse;
+import com.smartdevicelink.proxy.SystemCapabilityManager;
+import com.smartdevicelink.proxy.interfaces.IAudioStreamListener;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.interfaces.ISdlServiceListener;
+import com.smartdevicelink.proxy.interfaces.IVideoStreamListener;
+import com.smartdevicelink.proxy.interfaces.OnSystemCapabilityListener;
+import com.smartdevicelink.proxy.rpc.OnAppInterfaceUnregistered;
+import com.smartdevicelink.proxy.rpc.OnButtonEvent;
+import com.smartdevicelink.proxy.rpc.OnButtonPress;
+import com.smartdevicelink.proxy.rpc.OnHMIStatus;
+import com.smartdevicelink.proxy.rpc.OnSystemRequest;
+import com.smartdevicelink.proxy.rpc.RegisterAppInterface;
+import com.smartdevicelink.proxy.rpc.RegisterAppInterfaceResponse;
+import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
+import com.smartdevicelink.proxy.rpc.SubscribeButton;
+import com.smartdevicelink.proxy.rpc.SystemRequest;
+import com.smartdevicelink.proxy.rpc.TTSChunk;
+import com.smartdevicelink.proxy.rpc.TemplateColorScheme;
+import com.smartdevicelink.proxy.rpc.UnregisterAppInterface;
+import com.smartdevicelink.proxy.rpc.VehicleType;
+import com.smartdevicelink.proxy.rpc.enums.AppHMIType;
+import com.smartdevicelink.proxy.rpc.enums.AppInterfaceUnregisteredReason;
+import com.smartdevicelink.proxy.rpc.enums.ButtonName;
+import com.smartdevicelink.proxy.rpc.enums.FileType;
+import com.smartdevicelink.proxy.rpc.enums.HMILevel;
+import com.smartdevicelink.proxy.rpc.enums.Language;
+import com.smartdevicelink.proxy.rpc.enums.RequestType;
+import com.smartdevicelink.proxy.rpc.enums.Result;
+import com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason;
+import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
+import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
+import com.smartdevicelink.proxy.rpc.listeners.OnPutFileUpdateListener;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCListener;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCRequestListener;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener;
+import com.smartdevicelink.security.SdlSecurityBase;
+import com.smartdevicelink.streaming.audio.AudioStreamingCodec;
+import com.smartdevicelink.streaming.audio.AudioStreamingParams;
+import com.smartdevicelink.streaming.video.VideoStreamingParameters;
+import com.smartdevicelink.transport.BaseTransportConfig;
+import com.smartdevicelink.util.CorrelationIdGenerator;
+import com.smartdevicelink.util.DebugTool;
+import com.smartdevicelink.util.FileUtls;
+import com.smartdevicelink.util.Version;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Vector;
+import java.util.concurrent.CopyOnWriteArrayList;
+
abstract class BaseLifecycleManager {
+
+ static final String TAG = "Lifecycle Manager";
+ public static final Version MAX_SUPPORTED_RPC_VERSION = new Version(6, 0, 0);
+
+ // Protected Correlation IDs
+ private final int REGISTER_APP_INTERFACE_CORRELATION_ID = 65529,
+ UNREGISTER_APP_INTERFACE_CORRELATION_ID = 65530;
+
+ // Sdl Synchronization Objects
+ private static final Object RPC_LISTENER_LOCK = new Object(),
+ ON_UPDATE_LISTENER_LOCK = new Object(),
+ ON_REQUEST_LISTENER_LOCK = new Object(),
+ ON_NOTIFICATION_LISTENER_LOCK = new Object();
+
+ SdlSession session;
+ AppConfig appConfig;
+ Version rpcSpecVersion = MAX_SUPPORTED_RPC_VERSION;
+ HashMap<Integer, CopyOnWriteArrayList<OnRPCListener>> rpcListeners;
+ HashMap<Integer, OnRPCResponseListener> rpcResponseListeners;
+ HashMap<Integer, CopyOnWriteArrayList<OnRPCNotificationListener>> rpcNotificationListeners;
+ HashMap<Integer, CopyOnWriteArrayList<OnRPCRequestListener>> rpcRequestListeners;
+ SystemCapabilityManager systemCapabilityManager;
+ private EncryptionLifecycleManager encryptionLifecycleManager;
+ RegisterAppInterfaceResponse raiResponse = null;
+ private OnHMIStatus currentHMIStatus;
+ boolean firstTimeFull = true;
+ LifecycleListener lifecycleListener;
+ private List<Class<? extends SdlSecurityBase>> _secList = null;
+ private String authToken;
+ Version minimumProtocolVersion;
+ Version minimumRPCVersion;
+ BaseTransportConfig _transportConfig;
+
+ BaseLifecycleManager(AppConfig appConfig, BaseTransportConfig config, LifecycleListener listener) {
+ this.appConfig = appConfig;
+ this._transportConfig = config;
+ this.lifecycleListener = listener;
+ this.minimumProtocolVersion = appConfig.getMinimumProtocolVersion();
+ this.minimumRPCVersion = appConfig.getMinimumRPCVersion();
+ initializeProxy();
+ }
+
+ public void start() {
+ try {
+ session.startSession();
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Start a secured RPC service
+ */
+ public void startRPCEncryption() {
+ if (session != null) {
+ session.startService(SessionType.RPC, session.getSessionId(), true);
+ }
+ }
+
+ public void stop() {
+ session.close();
+ }
+
+ Version getProtocolVersion() {
+ if (session != null && session.getProtocolVersion() != null) {
+ return session.getProtocolVersion();
+ }
+ return new Version(1, 0, 0);
+ }
+
+ private void sendRPCs(List<? extends RPCMessage> messages, final OnMultipleRequestListener listener) {
+ if (messages != null) {
+ for (RPCMessage message : messages) {
+ // Request Specifics
+ if (message instanceof RPCRequest) {
+ RPCRequest request = ((RPCRequest) message);
+ final OnRPCResponseListener devOnRPCResponseListener = request.getOnRPCResponseListener();
+ request.setCorrelationID(CorrelationIdGenerator.generateId());
+ if (listener != null) {
+ listener.addCorrelationId(request.getCorrelationID());
+ request.setOnRPCResponseListener(new OnRPCResponseListener() {
+ @Override
+ public void onResponse(int correlationId, RPCResponse response) {
+ if (devOnRPCResponseListener != null) {
+ devOnRPCResponseListener.onResponse(correlationId, response);
+ }
+ if (listener.getSingleRpcResponseListener() != null) {
+ listener.getSingleRpcResponseListener().onResponse(correlationId, response);
+ }
+ }
+
+ @Override
+ public void onError(int correlationId, Result resultCode, String info) {
+ super.onError(correlationId, resultCode, info);
+ if (devOnRPCResponseListener != null) {
+ devOnRPCResponseListener.onError(correlationId, resultCode, info);
+ }
+ if (listener.getSingleRpcResponseListener() != null) {
+ listener.getSingleRpcResponseListener().onError(correlationId, resultCode, info);
+ }
+ }
+ });
+ }
+ sendRPCMessagePrivate(request, false);
+ } else {
+ // Notifications and Responses
+ sendRPCMessagePrivate(message, false);
+ if (listener != null) {
+ listener.onUpdate(messages.size());
+ if (messages.size() == 0) {
+ listener.onFinished();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void sendSequentialRPCs(final List<? extends RPCMessage> messages, final OnMultipleRequestListener listener) {
+ if (messages != null) {
+ // Break out of recursion, we have finished the requests
+ if (messages.size() == 0) {
+ if (listener != null) {
+ listener.onFinished();
+ }
+ return;
+ }
+
+ RPCMessage rpc = messages.remove(0);
+
+ // Request Specifics
+ if (rpc.getMessageType().equals(RPCMessage.KEY_REQUEST)) {
+ RPCRequest request = (RPCRequest) rpc;
+ request.setCorrelationID(CorrelationIdGenerator.generateId());
+
+ final OnRPCResponseListener devOnRPCResponseListener = request.getOnRPCResponseListener();
+
+ request.setOnRPCResponseListener(new OnRPCResponseListener() {
+ @Override
+ public void onResponse(int correlationId, RPCResponse response) {
+ if (devOnRPCResponseListener != null) {
+ devOnRPCResponseListener.onResponse(correlationId, response);
+ }
+ if (listener != null) {
+ listener.onResponse(correlationId, response);
+ listener.onUpdate(messages.size());
+ }
+ // recurse after onResponse
+ sendSequentialRPCs(messages, listener);
+ }
+
+ @Override
+ public void onError(int correlationId, Result resultCode, String info) {
+ if (devOnRPCResponseListener != null) {
+ devOnRPCResponseListener.onError(correlationId, resultCode, info);
+ }
+ if (listener != null) {
+ listener.onError(correlationId, resultCode, info);
+ listener.onUpdate(messages.size());
+
+ }
+ // recurse after onError
+ sendSequentialRPCs(messages, listener);
+ }
+ });
+ sendRPCMessagePrivate(request, false);
+ } else {
+ // Notifications and Responses
+ sendRPCMessagePrivate(rpc, false);
+ if (listener != null) {
+ listener.onUpdate(messages.size());
+ }
+ // recurse after sending a notification or response as there is no response.
+ sendSequentialRPCs(messages, listener);
+ }
+ }
+ }
+
+ /**
+ * This method is used to ensure all of the methods in this class can remain private and no grantees can be made
+ * to the developer what methods are available or not.
+ *
+ * <b>NOTE: THERE IS NO GURANTEE THIS WILL BE A VALID SYSTEM CAPABILITY MANAGER</b>
+ *
+ * @param sdlManager this must be a working manager instance
+ * @return the system capability manager.
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ public SystemCapabilityManager getSystemCapabilityManager(SdlManager sdlManager) {
+ if (sdlManager != null) {
+ return systemCapabilityManager;
+ }
+ return null;
+ }
+
+ private boolean isConnected() {
+ if (session != null) {
+ return session.getIsConnected();
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Method to retrieve the RegisterAppInterface Response message that was sent back from the
+ * module. It contains various attributes about the connected module and can be used to adapt
+ * to different module types and their supported features.
+ *
+ * @return RegisterAppInterfaceResponse received from the module or null if the app has not yet
+ * registered with the module.
+ */
+ public RegisterAppInterfaceResponse getRegisterAppInterfaceResponse() {
+ return this.raiResponse;
+ }
+
+ /**
+ * Get the current OnHMIStatus
+ *
+ * @return OnHMIStatus object represents the current OnHMIStatus
+ */
+ public OnHMIStatus getCurrentHMIStatus() {
+ return currentHMIStatus;
+ }
+
+ void onClose(String info, Exception e) {
+ Log.i(TAG, "onClose");
+ if (lifecycleListener != null) {
+ lifecycleListener.onProxyClosed((LifecycleManager) this, info, e, null);
+ }
+ }
+
+ /**
+ * This method is used to ensure all of the methods in this class can remain private and no grantees can be made
+ * to the developer what methods are available or not.
+ *
+ * @param sdlManager this must be a working manager instance
+ * @return the internal interface that hooks into this manager
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ public ISdl getInternalInterface(SdlManager sdlManager) {
+ if (sdlManager != null) {
+ return internalInterface;
+ }
+ return null;
+ }
+
+ /* *******************************************************************************************************
+ ********************************** INTERNAL - RPC LISTENERS !! START !! *********************************
+ *********************************************************************************************************/
+
+ private void setupInternalRpcListeners() {
+ addRpcListener(FunctionID.REGISTER_APP_INTERFACE, rpcListener);
+ addRpcListener(FunctionID.ON_HMI_STATUS, rpcListener);
+ addRpcListener(FunctionID.ON_HASH_CHANGE, rpcListener);
+ addRpcListener(FunctionID.ON_SYSTEM_REQUEST, rpcListener);
+ addRpcListener(FunctionID.ON_APP_INTERFACE_UNREGISTERED, rpcListener);
+ addRpcListener(FunctionID.UNREGISTER_APP_INTERFACE, rpcListener);
+ }
+
+ private OnRPCListener rpcListener = new OnRPCListener() {
+ @Override
+ public void onReceived(RPCMessage message) {
+ //Make sure this is a response as expected
+ FunctionID functionID = message.getFunctionID();
+ if (functionID != null) {
+ switch (functionID) {
+ case REGISTER_APP_INTERFACE:
+ //We have begun
+ Log.i(TAG, "RAI Response");
+ raiResponse = (RegisterAppInterfaceResponse) message;
+ SdlMsgVersion rpcVersion = ((RegisterAppInterfaceResponse) message).getSdlMsgVersion();
+ if (rpcVersion != null) {
+ BaseLifecycleManager.this.rpcSpecVersion = new Version(rpcVersion.getMajorVersion(), rpcVersion.getMinorVersion(), rpcVersion.getPatchVersion());
+ } else {
+ BaseLifecycleManager.this.rpcSpecVersion = MAX_SUPPORTED_RPC_VERSION;
+ }
+ if (minimumRPCVersion != null && minimumRPCVersion.isNewerThan(rpcSpecVersion) == 1) {
+ Log.w(TAG, String.format("Disconnecting from head unit, the configured minimum RPC version %s is greater than the supported RPC version %s", minimumRPCVersion, rpcSpecVersion));
+ UnregisterAppInterface msg = new UnregisterAppInterface();
+ msg.setCorrelationID(UNREGISTER_APP_INTERFACE_CORRELATION_ID);
+ sendRPCMessagePrivate(msg, true);
+ cleanProxy();
+ return;
+ }
+ processRaiResponse(raiResponse);
+ systemCapabilityManager.parseRAIResponse(raiResponse);
+ break;
+ case ON_HMI_STATUS:
+ Log.i(TAG, "on hmi status");
+ boolean shouldInit = currentHMIStatus == null;
+ currentHMIStatus = (OnHMIStatus) message;
+ if (lifecycleListener != null && shouldInit) {
+ lifecycleListener.onProxyConnected((LifecycleManager) BaseLifecycleManager.this);
+ }
+ break;
+ case ON_HASH_CHANGE:
+ break;
+ case ON_SYSTEM_REQUEST:
+ final OnSystemRequest onSystemRequest = (OnSystemRequest) message;
+ if ((onSystemRequest.getUrl() != null) &&
+ (((onSystemRequest.getRequestType() == RequestType.PROPRIETARY) && (onSystemRequest.getFileType() == FileType.JSON))
+ || ((onSystemRequest.getRequestType() == RequestType.HTTP) && (onSystemRequest.getFileType() == FileType.BINARY)))) {
+ Thread handleOffboardTransmissionThread = new Thread() {
+ @Override
+ public void run() {
+ RPCRequest request = PoliciesFetcher.fetchPolicies(onSystemRequest);
+ if (request != null && isConnected()) {
+ sendRPCMessagePrivate(request, true);
+ }
+ }
+ };
+ handleOffboardTransmissionThread.start();
+ } else if (onSystemRequest.getRequestType() == RequestType.ICON_URL && onSystemRequest.getUrl() != null) {
+ //Download the icon file and send SystemRequest RPC
+ Thread handleOffBoardTransmissionThread = new Thread() {
+ @Override
+ public void run() {
+ final String urlHttps = onSystemRequest.getUrl().replaceFirst("http://", "https://");
+ byte[] file = FileUtls.downloadFile(urlHttps);
+ if (file != null) {
+ SystemRequest systemRequest = new SystemRequest();
+ systemRequest.setFileName(onSystemRequest.getUrl());
+ systemRequest.setBulkData(file);
+ systemRequest.setRequestType(RequestType.ICON_URL);
+ if (isConnected()) {
+ sendRPCMessagePrivate(systemRequest, true);
+ }
+ } else {
+ DebugTool.logError("File was null at: " + urlHttps);
+ }
+ }
+ };
+ handleOffBoardTransmissionThread.start();
+ }
+ break;
+ case ON_APP_INTERFACE_UNREGISTERED:
+
+ OnAppInterfaceUnregistered onAppInterfaceUnregistered = (OnAppInterfaceUnregistered) message;
+
+ if (!onAppInterfaceUnregistered.getReason().equals(AppInterfaceUnregisteredReason.LANGUAGE_CHANGE)) {
+ Log.v(TAG, "on app interface unregistered");
+ cleanProxy();
+ } else {
+ Log.v(TAG, "re-registering for language change");
+ processLanguageChange();
+ }
+ break;
+ case UNREGISTER_APP_INTERFACE:
+ Log.v(TAG, "unregister app interface");
+ cleanProxy();
+ break;
+ }
+ }
+ }
+
+
+ };
+
+ private void processLanguageChange() {
+ if (session != null) {
+ if (session.getIsConnected()) {
+ session.close();
+ }
+ try {
+ session.startSession();
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /* *******************************************************************************************************
+ ********************************** INTERNAL - RPC LISTENERS !! END !! *********************************
+ *********************************************************************************************************/
+
+
+ /* *******************************************************************************************************
+ ********************************** METHODS - RPC LISTENERS !! START !! **********************************
+ *********************************************************************************************************/
+
+ private boolean onRPCReceived(final RPCMessage message) {
+ synchronized (RPC_LISTENER_LOCK) {
+ if (message == null || message.getFunctionID() == null) {
+ return false;
+ }
+
+ final int id = message.getFunctionID().getId();
+ CopyOnWriteArrayList<OnRPCListener> listeners = rpcListeners.get(id);
+ if (listeners != null && listeners.size() > 0) {
+ for (OnRPCListener listener : listeners) {
+ listener.onReceived(message);
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private void addRpcListener(FunctionID id, OnRPCListener listener) {
+ synchronized (RPC_LISTENER_LOCK) {
+ if (id != null && listener != null) {
+ if (!rpcListeners.containsKey(id.getId())) {
+ rpcListeners.put(id.getId(), new CopyOnWriteArrayList<OnRPCListener>());
+ }
+
+ rpcListeners.get(id.getId()).add(listener);
+ }
+ }
+ }
+
+ private boolean removeOnRPCListener(FunctionID id, OnRPCListener listener) {
+ synchronized (RPC_LISTENER_LOCK) {
+ if (rpcListeners != null
+ && id != null
+ && listener != null
+ && rpcListeners.containsKey(id.getId())) {
+ return rpcListeners.get(id.getId()).remove(listener);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Only call this method for a PutFile response. It will cause a class cast exception if not.
+ *
+ * @param correlationId correlation id of the packet being updated
+ * @param bytesWritten how many bytes were written
+ * @param totalSize the total size in bytes
+ */
+ @SuppressWarnings("unused")
+ private void onPacketProgress(int correlationId, long bytesWritten, long totalSize) {
+ synchronized (ON_UPDATE_LISTENER_LOCK) {
+ if (rpcResponseListeners != null
+ && rpcResponseListeners.containsKey(correlationId)) {
+ ((OnPutFileUpdateListener) rpcResponseListeners.get(correlationId)).onUpdate(correlationId, bytesWritten, totalSize);
+ }
+ }
+
+ }
+
+ /**
+ * Will provide callback to the listener either onFinish or onError depending on the RPCResponses result code,
+ * <p>Will automatically remove the listener for the list of listeners on completion.
+ *
+ * @param msg The RPCResponse message that was received
+ * @return if a listener was called or not
+ */
+ @SuppressWarnings("UnusedReturnValue")
+ private boolean onRPCResponseReceived(RPCResponse msg) {
+ synchronized (ON_UPDATE_LISTENER_LOCK) {
+ int correlationId = msg.getCorrelationID();
+ if (rpcResponseListeners != null
+ && rpcResponseListeners.containsKey(correlationId)) {
+ OnRPCResponseListener listener = rpcResponseListeners.get(correlationId);
+ if (msg.getSuccess()) {
+ listener.onResponse(correlationId, msg);
+ } else {
+ listener.onError(correlationId, msg.getResultCode(), msg.getInfo());
+ }
+ rpcResponseListeners.remove(correlationId);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Add a listener that will receive the response to the specific RPCRequest sent with the corresponding correlation id
+ *
+ * @param listener that will get called back when a response is received
+ * @param correlationId of the RPCRequest that was sent
+ * @param totalSize only include if this is an OnPutFileUpdateListener. Otherwise it will be ignored.
+ */
+ private void addOnRPCResponseListener(OnRPCResponseListener listener, int correlationId, int totalSize) {
+ synchronized (ON_UPDATE_LISTENER_LOCK) {
+ if (rpcResponseListeners != null
+ && listener != null) {
+ if (listener.getListenerType() == OnRPCResponseListener.UPDATE_LISTENER_TYPE_PUT_FILE) {
+ ((OnPutFileUpdateListener) listener).setTotalSize(totalSize);
+ }
+ listener.onStart(correlationId);
+ rpcResponseListeners.put(correlationId, listener);
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private HashMap<Integer, OnRPCResponseListener> getResponseListeners() {
+ synchronized (ON_UPDATE_LISTENER_LOCK) {
+ return this.rpcResponseListeners;
+ }
+ }
+
+ /**
+ * Retrieves the auth token, if any, that was attached to the StartServiceACK for the RPC
+ * service from the module. For example, this should be used to login to a user account.
+ *
+ * @return the string representation of the auth token
+ */
+ public String getAuthToken() {
+ return this.authToken;
+ }
+
+ @SuppressWarnings("UnusedReturnValue")
+ private boolean onRPCNotificationReceived(RPCNotification notification) {
+ if (notification == null) {
+ DebugTool.logError("onRPCNotificationReceived - Notification was null");
+ return false;
+ }
+ DebugTool.logInfo("onRPCNotificationReceived - " + notification.getFunctionName());
+
+ //Before updating any listeners, make sure to do any final updates to the notification RPC now
+ if (FunctionID.ON_HMI_STATUS.toString().equals(notification.getFunctionName())) {
+ OnHMIStatus onHMIStatus = (OnHMIStatus) notification;
+ onHMIStatus.setFirstRun(firstTimeFull);
+ if (onHMIStatus.getHmiLevel() == HMILevel.HMI_FULL) {
+ firstTimeFull = false;
+ }
+ }
+
+ synchronized (ON_NOTIFICATION_LISTENER_LOCK) {
+ CopyOnWriteArrayList<OnRPCNotificationListener> listeners = rpcNotificationListeners.get(FunctionID.getFunctionId(notification.getFunctionName()));
+ if (listeners != null && listeners.size() > 0) {
+ for (OnRPCNotificationListener listener : listeners) {
+ listener.onNotified(notification);
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * This will add a listener for the specific type of notification. As of now it will only allow
+ * a single listener per notification function id
+ *
+ * @param notificationId The notification type that this listener is designated for
+ * @param listener The listener that will be called when a notification of the provided type is received
+ */
+ @SuppressWarnings("unused")
+ private void addOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {
+ synchronized (ON_NOTIFICATION_LISTENER_LOCK) {
+ if (notificationId != null && listener != null) {
+ if (!rpcNotificationListeners.containsKey(notificationId.getId())) {
+ rpcNotificationListeners.put(notificationId.getId(), new CopyOnWriteArrayList<OnRPCNotificationListener>());
+ }
+ rpcNotificationListeners.get(notificationId.getId()).add(listener);
+ }
+ }
+ }
+
+ private boolean removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {
+ synchronized (ON_NOTIFICATION_LISTENER_LOCK) {
+ if (rpcNotificationListeners != null
+ && notificationId != null
+ && listener != null
+ && rpcNotificationListeners.containsKey(notificationId.getId())) {
+ return rpcNotificationListeners.get(notificationId.getId()).remove(listener);
+ }
+ }
+ return false;
+ }
+
+ @SuppressWarnings("UnusedReturnValue")
+ private boolean onRPCRequestReceived(RPCRequest request) {
+ if (request == null) {
+ DebugTool.logError("onRPCRequestReceived - request was null");
+ return false;
+ }
+ DebugTool.logInfo("onRPCRequestReceived - " + request.getFunctionName());
+
+ synchronized (ON_REQUEST_LISTENER_LOCK) {
+ CopyOnWriteArrayList<OnRPCRequestListener> listeners = rpcRequestListeners.get(FunctionID.getFunctionId(request.getFunctionName()));
+ if (listeners != null && listeners.size() > 0) {
+ for (OnRPCRequestListener listener : listeners) {
+ listener.onRequest(request);
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * This will add a listener for the specific type of request. As of now it will only allow
+ * a single listener per request function id
+ *
+ * @param requestId The request type that this listener is designated for
+ * @param listener The listener that will be called when a request of the provided type is received
+ */
+ @SuppressWarnings("unused")
+ private void addOnRPCRequestListener(FunctionID requestId, OnRPCRequestListener listener) {
+ synchronized (ON_REQUEST_LISTENER_LOCK) {
+ if (requestId != null && listener != null) {
+ if (!rpcRequestListeners.containsKey(requestId.getId())) {
+ rpcRequestListeners.put(requestId.getId(), new CopyOnWriteArrayList<OnRPCRequestListener>());
+ }
+ rpcRequestListeners.get(requestId.getId()).add(listener);
+ }
+ }
+ }
+
+ @SuppressWarnings("UnusedReturnValue")
+ private boolean removeOnRPCRequestListener(FunctionID requestId, OnRPCRequestListener listener) {
+ synchronized (ON_REQUEST_LISTENER_LOCK) {
+ if (rpcRequestListeners != null
+ && requestId != null
+ && listener != null
+ && rpcRequestListeners.containsKey(requestId.getId())) {
+ return rpcRequestListeners.get(requestId.getId()).remove(listener);
+ }
+ }
+ return false;
+ }
+
+ /* *******************************************************************************************************
+ **************************************** RPC LISTENERS !! END !! ****************************************
+ *********************************************************************************************************/
+
+ private void sendRPCMessagePrivate(RPCMessage message, boolean isInternalMessage) {
+ try {
+ if (!isInternalMessage && message.getMessageType().equals(RPCMessage.KEY_REQUEST)) {
+ RPCRequest request = (RPCRequest) message;
+ OnRPCResponseListener listener = request.getOnRPCResponseListener();
+
+ // Test for illegal correlation ID
+ if (request.getCorrelationID() == REGISTER_APP_INTERFACE_CORRELATION_ID || request.getCorrelationID() == UNREGISTER_APP_INTERFACE_CORRELATION_ID || request.getCorrelationID() == PoliciesFetcher.POLICIES_CORRELATION_ID) {
+ if (listener != null) {
+ request.getOnRPCResponseListener().onError(request.getCorrelationID(), Result.REJECTED, "Invalid correlation ID. The correlation ID, " + request.getCorrelationID() + " , is a reserved correlation ID.");
+ }
+ return;
+ }
+
+ // Prevent developer from sending RAI or UAI manually
+ if (request.getFunctionName().equals(FunctionID.REGISTER_APP_INTERFACE.toString()) || request.getFunctionName().equals(FunctionID.UNREGISTER_APP_INTERFACE.toString())) {
+ if (listener != null) {
+ request.getOnRPCResponseListener().onError(request.getCorrelationID(), Result.REJECTED, "The RPCRequest, " + message.getFunctionName() + ", is un-allowed to be sent manually by the developer.");
+ }
+ return;
+ }
+ }
+
+ //FIXME this is temporary until the next major release of the library where OK is removed
+ if (message.getMessageType().equals(RPCMessage.KEY_REQUEST)) {
+ RPCRequest request = (RPCRequest) message;
+ if (FunctionID.SUBSCRIBE_BUTTON.toString().equals(request.getFunctionName())
+ || FunctionID.UNSUBSCRIBE_BUTTON.toString().equals(request.getFunctionName())
+ || FunctionID.BUTTON_PRESS.toString().equals(request.getFunctionName())) {
+
+ ButtonName buttonName = (ButtonName) request.getObject(ButtonName.class, SubscribeButton.KEY_BUTTON_NAME);
+
+
+ if (rpcSpecVersion != null) {
+ if (rpcSpecVersion.getMajor() < 5) {
+
+ if (ButtonName.PLAY_PAUSE.equals(buttonName)) {
+ request.setParameters(SubscribeButton.KEY_BUTTON_NAME, ButtonName.OK);
+ }
+ } else { //Newer than version 5.0.0
+ if (ButtonName.OK.equals(buttonName)) {
+ RPCRequest request2 = new RPCRequest(request);
+ request2.setParameters(SubscribeButton.KEY_BUTTON_NAME, ButtonName.PLAY_PAUSE);
+ request2.setOnRPCResponseListener(request.getOnRPCResponseListener());
+ sendRPCMessagePrivate(request2, true);
+ return;
+ }
+ }
+ }
+
+ }
+ }
+
+ message.format(rpcSpecVersion, true);
+ byte[] msgBytes = JsonRPCMarshaller.marshall(message, (byte) getProtocolVersion().getMajor());
+
+ final ProtocolMessage pm = new ProtocolMessage();
+ pm.setData(msgBytes);
+ if (session != null) {
+ pm.setSessionID(session.getSessionId());
+ }
+
+ pm.setMessageType(MessageType.RPC);
+ pm.setSessionType(SessionType.RPC);
+ pm.setFunctionID(FunctionID.getFunctionId(message.getFunctionName()));
+
+ if (encryptionLifecycleManager != null && encryptionLifecycleManager.isEncryptionReady() && encryptionLifecycleManager.getRPCRequiresEncryption(message.getFunctionID())) {
+ pm.setPayloadProtected(true);
+ } else {
+ pm.setPayloadProtected(message.isPayloadProtected());
+ }
+ if (pm.getPayloadProtected() && (encryptionLifecycleManager == null || !encryptionLifecycleManager.isEncryptionReady())) {
+ String errorInfo = "Trying to send an encrypted message and there is no secured service";
+ if (message.getMessageType().equals((RPCMessage.KEY_REQUEST))) {
+ RPCRequest request = (RPCRequest) message;
+ OnRPCResponseListener listener = ((RPCRequest) message).getOnRPCResponseListener();
+ if (listener != null) {
+ listener.onError(request.getCorrelationID(), Result.ABORTED, errorInfo);
+ }
+ }
+ DebugTool.logWarning(errorInfo);
+ return;
+ }
+
+ if (RPCMessage.KEY_REQUEST.equals(message.getMessageType())) { // Request Specifics
+ pm.setRPCType((byte) 0x00);
+ Integer corrId = ((RPCRequest) message).getCorrelationID();
+ if (corrId == null) {
+ Log.e(TAG, "No correlation ID attached to request. Not sending");
+ return;
+ } else {
+ pm.setCorrID(corrId);
+
+ OnRPCResponseListener listener = ((RPCRequest) message).getOnRPCResponseListener();
+ if (listener != null) {
+ addOnRPCResponseListener(listener, corrId, msgBytes.length);
+ }
+ }
+ } else if (RPCMessage.KEY_RESPONSE.equals(message.getMessageType())) { // Response Specifics
+ RPCResponse response = (RPCResponse) message;
+ pm.setRPCType((byte) 0x01);
+ if (response.getCorrelationID() == null) {
+ //Log error here
+ //throw new SdlException("CorrelationID cannot be null. RPC: " + response.getFunctionName(), SdlExceptionCause.INVALID_ARGUMENT);
+ Log.e(TAG, "No correlation ID attached to response. Not sending");
+ return;
+ } else {
+ pm.setCorrID(response.getCorrelationID());
+ }
+ } else if (message.getMessageType().equals(RPCMessage.KEY_NOTIFICATION)) { // Notification Specifics
+ pm.setRPCType((byte) 0x02);
+ }
+
+ if (message.getBulkData() != null) {
+ pm.setBulkData(message.getBulkData());
+ }
+
+ if (message.getFunctionName().equalsIgnoreCase(FunctionID.PUT_FILE.name())) {
+ pm.setPriorityCoefficient(1);
+ }
+
+ session.sendMessage(pm);
+
+ } catch (OutOfMemoryError e) {
+ e.printStackTrace();
+ }
+ }
+
+ /* *******************************************************************************************************
+ *************************************** ISdlConnectionListener START ************************************
+ *********************************************************************************************************/
+
+ final ISdlConnectionListener sdlConnectionListener = new ISdlConnectionListener() {
+ @Override
+ public void onTransportDisconnected(String info) {
+ onClose(info, null);
+
+ }
+
+ @Override
+ public void onTransportDisconnected(String info, boolean availablePrimary, BaseTransportConfig transportConfig) {
+ BaseLifecycleManager.this.onTransportDisconnected(info, availablePrimary, transportConfig);
+
+ }
+
+ @Override
+ public void onTransportError(String info, Exception e) {
+ onClose(info, e);
+
+ }
+
+ @Override
+ public void onProtocolMessageReceived(ProtocolMessage msg) {
+ //Incoming message
+ if (SessionType.RPC.equals(msg.getSessionType())
+ || SessionType.BULK_DATA.equals(msg.getSessionType())) {
+
+ RPCMessage rpc = RpcConverter.extractRpc(msg, session.getProtocolVersion());
+ if (rpc != null) {
+ String messageType = rpc.getMessageType();
+ Log.v(TAG, "RPC received - " + messageType);
+
+ rpc.format(rpcSpecVersion, true);
+
+ onRPCReceived(rpc);
+
+ if (RPCMessage.KEY_RESPONSE.equals(messageType)) {
+
+ onRPCResponseReceived((RPCResponse) rpc);
+
+ } else if (RPCMessage.KEY_NOTIFICATION.equals(messageType)) {
+ FunctionID functionID = rpc.getFunctionID();
+ if (functionID != null && (functionID.equals(FunctionID.ON_BUTTON_PRESS)) || functionID.equals(FunctionID.ON_BUTTON_EVENT)) {
+ RPCNotification notificationCompat = handleButtonNotificationFormatting(rpc);
+ if (notificationCompat != null) {
+ onRPCNotificationReceived((notificationCompat));
+ }
+ }
+
+ onRPCNotificationReceived((RPCNotification) rpc);
+
+ } else if (RPCMessage.KEY_REQUEST.equals(messageType)) {
+
+ onRPCRequestReceived((RPCRequest) rpc);
+
+ }
+ } else {
+ Log.w(TAG, "Shouldn't be here");
+ }
+ }
+
+ }
+
+ @Override
+ public void onProtocolSessionStartedNACKed(SessionType sessionType, byte sessionID, byte version, String correlationID, List<String> rejectedParams) {
+ Log.w(TAG, sessionType + " onProtocolSessionStartedNACKed " + sessionID + " RejectedParams: " + rejectedParams);
+ BaseLifecycleManager.this.onProtocolSessionStartedNACKed(sessionType);
+ }
+
+ @Override
+ public void onProtocolSessionStarted(SessionType sessionType, byte sessionID, byte version, String correlationID, int hashID, boolean isEncrypted) {
+ Log.i(TAG, "on protocol session started");
+ BaseLifecycleManager.this.onProtocolSessionStarted(sessionType);
+ }
+
+ @Override
+ public void onProtocolSessionEnded(SessionType sessionType, byte sessionID, String correlationID) {
+ BaseLifecycleManager.this.onProtocolSessionEnded(sessionType);
+ }
+
+ @Override
+ public void onProtocolSessionEndedNACKed(SessionType sessionType, byte sessionID, String correlationID) {
+ BaseLifecycleManager.this.onProtocolSessionEndedNACKed(sessionType);
+ }
+
+ @Override
+ public void onProtocolError(String info, Exception e) {
+ DebugTool.logError("Protocol Error - " + info, e);
+ }
+
+ @Override
+ public void onHeartbeatTimedOut(byte sessionID) { /* Deprecated */ }
+
+ @Override
+ public void onProtocolServiceDataACK(SessionType sessionType, int dataSize, byte sessionID) {/* Unused */ }
+
+
+ @Override
+ public void onAuthTokenReceived(String token, byte sessionID) {
+ BaseLifecycleManager.this.authToken = token;
+ }
+ };
+
+ /* *******************************************************************************************************
+ *************************************** ISdlConnectionListener END ************************************
+ *********************************************************************************************************/
+
+
+ /* *******************************************************************************************************
+ ******************************************** ISdl - START ***********************************************
+ *********************************************************************************************************/
+
+ final ISdl internalInterface = new ISdl() {
+ @Override
+ public void start() {
+ BaseLifecycleManager.this.start();
+ }
+
+ @Override
+ public void stop() {
+ BaseLifecycleManager.this.stop();
+ }
+
+ @Override
+ public boolean isConnected() {
+ return BaseLifecycleManager.this.session.getIsConnected();
+ }
+
+ @Override
+ public void addServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener) {
+ BaseLifecycleManager.this.session.addServiceListener(serviceType, sdlServiceListener);
+ }
+
+ @Override
+ public void removeServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener) {
+ BaseLifecycleManager.this.session.removeServiceListener(serviceType, sdlServiceListener);
+ }
+
+ @Override
+ public void startVideoService(VideoStreamingParameters parameters, boolean encrypted) {
+ BaseLifecycleManager.this.startVideoService(encrypted, parameters);
+ }
+
+ @Override
+ public void stopVideoService() {
+ BaseLifecycleManager.this.endVideoStream();
+ }
+
+ @Override
+ public IVideoStreamListener startVideoStream(boolean isEncrypted, VideoStreamingParameters parameters) {
+ DebugTool.logWarning("startVideoStream is not currently implemented");
+ return null;
+ }
+
+ @Override
+ public void startAudioService(boolean encrypted, AudioStreamingCodec codec, AudioStreamingParams params) {
+ DebugTool.logWarning("startAudioService is not currently implemented");
+ }
+
+ @Override
+ public void startAudioService(boolean encrypted) {
+ BaseLifecycleManager.this.startAudioService(encrypted);
+ }
+
+ @Override
+ public void stopAudioService() {
+ BaseLifecycleManager.this.endAudioStream();
+ }
+
+ @Override
+ public IAudioStreamListener startAudioStream(boolean isEncrypted, AudioStreamingCodec codec, AudioStreamingParams params) {
+ DebugTool.logWarning("startAudioStream is not currently implemented");
+ return null;
+ }
+
+ @Override
+ public void sendRPCRequest(RPCRequest message) {
+ BaseLifecycleManager.this.sendRPCMessagePrivate(message, false);
+ }
+
+ @Override
+ public void sendRPC(RPCMessage message) {
+ if (isConnected()) {
+ BaseLifecycleManager.this.sendRPCMessagePrivate(message, false);
+ }
+ }
+
+ @Override
+ public void sendRequests(List<? extends RPCRequest> rpcs, OnMultipleRequestListener listener) {
+ BaseLifecycleManager.this.sendRPCs(rpcs, listener);
+ }
+
+ @Override
+ public void sendRPCs(List<? extends RPCMessage> rpcs, OnMultipleRequestListener listener) {
+ BaseLifecycleManager.this.sendRPCs(rpcs, listener);
+ }
+
+ @Override
+ public void sendSequentialRPCs(List<? extends RPCMessage> rpcs, OnMultipleRequestListener listener) {
+ BaseLifecycleManager.this.sendSequentialRPCs(rpcs, listener);
+ }
+
+ @Override
+ public void addOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {
+ BaseLifecycleManager.this.addOnRPCNotificationListener(notificationId, listener);
+ }
+
+ @Override
+ public boolean removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {
+ return BaseLifecycleManager.this.removeOnRPCNotificationListener(notificationId, listener);
+ }
+
+ @Override
+ public void addOnRPCRequestListener(FunctionID notificationId, OnRPCRequestListener listener) {
+ BaseLifecycleManager.this.addOnRPCRequestListener(notificationId, listener);
+ }
+
+ @Override
+ public boolean removeOnRPCRequestListener(FunctionID notificationId, OnRPCRequestListener listener) {
+ return BaseLifecycleManager.this.removeOnRPCRequestListener(notificationId, listener);
+ }
+
+ @Override
+ public void addOnRPCListener(FunctionID responseId, OnRPCListener listener) {
+ BaseLifecycleManager.this.addRpcListener(responseId, listener);
+ }
+
+ @Override
+ public boolean removeOnRPCListener(FunctionID responseId, OnRPCListener listener) {
+ return BaseLifecycleManager.this.removeOnRPCListener(responseId, listener);
+ }
+
+ @Override
+ public Object getCapability(SystemCapabilityType systemCapabilityType) {
+ if (BaseLifecycleManager.this.systemCapabilityManager != null) {
+ return BaseLifecycleManager.this.systemCapabilityManager.getCapability(systemCapabilityType);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void getCapability(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener scListener) {
+ if (BaseLifecycleManager.this.systemCapabilityManager != null) {
+ BaseLifecycleManager.this.systemCapabilityManager.getCapability(systemCapabilityType, scListener);
+ }
+ }
+
+ @Override
+ public Object getCapability(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener scListener, boolean forceUpdate) {
+ if (BaseLifecycleManager.this.systemCapabilityManager != null) {
+ return BaseLifecycleManager.this.systemCapabilityManager.getCapability(systemCapabilityType, scListener, forceUpdate);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public RegisterAppInterfaceResponse getRegisterAppInterfaceResponse() {
+ return raiResponse;
+ }
+
+ @Override
+ public boolean isCapabilitySupported(SystemCapabilityType systemCapabilityType) {
+ if (BaseLifecycleManager.this.systemCapabilityManager != null) {
+ return BaseLifecycleManager.this.systemCapabilityManager.isCapabilitySupported(systemCapabilityType);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void addOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) {
+ if (BaseLifecycleManager.this.systemCapabilityManager != null) {
+ BaseLifecycleManager.this.systemCapabilityManager.addOnSystemCapabilityListener(systemCapabilityType, listener);
+ }
+ }
+
+ @Override
+ public boolean removeOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) {
+ if (BaseLifecycleManager.this.systemCapabilityManager != null) {
+ return BaseLifecycleManager.this.systemCapabilityManager.removeOnSystemCapabilityListener(systemCapabilityType, listener);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean isTransportForServiceAvailable(SessionType serviceType) {
+ return BaseLifecycleManager.this.session.isTransportForServiceAvailable(serviceType);
+ }
+
+ @Override
+ public SdlMsgVersion getSdlMsgVersion() {
+ SdlMsgVersion msgVersion = new SdlMsgVersion(rpcSpecVersion.getMajor(), rpcSpecVersion.getMinor());
+ msgVersion.setPatchVersion(rpcSpecVersion.getPatch());
+ return msgVersion;
+ }
+
+ @Override
+ public Version getProtocolVersion() {
+ return BaseLifecycleManager.this.getProtocolVersion();
+ }
+
+ @Override
+ public void startRPCEncryption() {
+ BaseLifecycleManager.this.startRPCEncryption();
+ }
+ };
+
+ /* *******************************************************************************************************
+ ********************************************* ISdl - END ************************************************
+ *********************************************************************************************************/
+
+ public interface LifecycleListener {
+ void onProxyConnected(LifecycleManager lifeCycleManager);
+
+ void onProxyClosed(LifecycleManager lifeCycleManager, String info, Exception e, SdlDisconnectedReason reason);
+
+ void onServiceStarted(SessionType sessionType);
+
+ void onServiceEnded(SessionType sessionType);
+
+ void onError(LifecycleManager lifeCycleManager, String info, Exception e);
+ }
+
+ public static class AppConfig {
+ private String appID, appName, ngnMediaScreenAppName;
+ private Vector<TTSChunk> ttsName;
+ private Vector<String> vrSynonyms;
+ private boolean isMediaApp = false;
+ private Language languageDesired, hmiDisplayLanguageDesired;
+ private Vector<AppHMIType> appType;
+ private TemplateColorScheme dayColorScheme, nightColorScheme;
+ private Version minimumProtocolVersion;
+ private Version minimumRPCVersion;
+
+ private void prepare() {
+ if (getNgnMediaScreenAppName() == null) {
+ setNgnMediaScreenAppName(getAppName());
+ }
+
+ if (getLanguageDesired() == null) {
+ setLanguageDesired(Language.EN_US);
+ }
+
+ if (getHmiDisplayLanguageDesired() == null) {
+ setHmiDisplayLanguageDesired(Language.EN_US);
+ }
+
+ if (getVrSynonyms() == null) {
+ setVrSynonyms(new Vector<String>());
+ getVrSynonyms().add(getAppName());
+ }
+ }
+
+ public String getAppID() {
+ return appID;
+ }
+
+ public void setAppID(String appID) {
+ this.appID = appID;
+ }
+
+ public String getAppName() {
+ return appName;
+ }
+
+ public void setAppName(String appName) {
+ this.appName = appName;
+ }
+
+ public String getNgnMediaScreenAppName() {
+ return ngnMediaScreenAppName;
+ }
+
+ public void setNgnMediaScreenAppName(String ngnMediaScreenAppName) {
+ this.ngnMediaScreenAppName = ngnMediaScreenAppName;
+ }
+
+ public Vector<TTSChunk> getTtsName() {
+ return ttsName;
+ }
+
+ public void setTtsName(Vector<TTSChunk> ttsName) {
+ this.ttsName = ttsName;
+ }
+
+ public Vector<String> getVrSynonyms() {
+ return vrSynonyms;
+ }
+
+ public void setVrSynonyms(Vector<String> vrSynonyms) {
+ this.vrSynonyms = vrSynonyms;
+ }
+
+ public boolean isMediaApp() {
+ return isMediaApp;
+ }
+
+ public void setMediaApp(boolean mediaApp) {
+ isMediaApp = mediaApp;
+ }
+
+ public Language getLanguageDesired() {
+ return languageDesired;
+ }
+
+ public void setLanguageDesired(Language languageDesired) {
+ this.languageDesired = languageDesired;
+ }
+
+ public Language getHmiDisplayLanguageDesired() {
+ return hmiDisplayLanguageDesired;
+ }
+
+ public void setHmiDisplayLanguageDesired(Language hmiDisplayLanguageDesired) {
+ this.hmiDisplayLanguageDesired = hmiDisplayLanguageDesired;
+ }
+
+ public Vector<AppHMIType> getAppType() {
+ return appType;
+ }
+
+ public void setAppType(Vector<AppHMIType> appType) {
+ this.appType = appType;
+ }
+
+ public TemplateColorScheme getDayColorScheme() {
+ return dayColorScheme;
+ }
+
+ public void setDayColorScheme(TemplateColorScheme dayColorScheme) {
+ this.dayColorScheme = dayColorScheme;
+ }
+
+ public TemplateColorScheme getNightColorScheme() {
+ return nightColorScheme;
+ }
+
+ public void setNightColorScheme(TemplateColorScheme nightColorScheme) {
+ this.nightColorScheme = nightColorScheme;
+ }
+
+ public Version getMinimumProtocolVersion() {
+ return minimumProtocolVersion;
+ }
+
+ /**
+ * Sets the minimum protocol version that will be permitted to connect.
+ * If the protocol version of the head unit connected is below this version,
+ * the app will disconnect with an EndService protocol message and will not register.
+ *
+ * @param minimumProtocolVersion a Version object with the minimally accepted Protocol version
+ */
+ public void setMinimumProtocolVersion(Version minimumProtocolVersion) {
+ this.minimumProtocolVersion = minimumProtocolVersion;
+ }
+
+ public Version getMinimumRPCVersion() {
+ return minimumRPCVersion;
+ }
+
+ /**
+ * The minimum RPC version that will be permitted to connect.
+ * If the RPC version of the head unit connected is below this version, an UnregisterAppInterface will be sent.
+ *
+ * @param minimumRPCVersion a Version object with the minimally accepted RPC spec version
+ */
+ public void setMinimumRPCVersion(Version minimumRPCVersion) {
+ this.minimumRPCVersion = minimumRPCVersion;
+ }
+ }
+
+ /**
+ * Temporary method to bridge the new PLAY_PAUSE and OKAY button functionality with the old
+ * OK button name. This should be removed during the next major release
+ *
+ * @param notification an RPC message object that should be either an ON_BUTTON_EVENT or ON_BUTTON_PRESS otherwise
+ * it will be ignored
+ */
+ private RPCNotification handleButtonNotificationFormatting(RPCMessage notification) {
+ if (FunctionID.ON_BUTTON_EVENT.toString().equals(notification.getFunctionName())
+ || FunctionID.ON_BUTTON_PRESS.toString().equals(notification.getFunctionName())) {
+
+ ButtonName buttonName = (ButtonName) notification.getObject(ButtonName.class, OnButtonEvent.KEY_BUTTON_NAME);
+ ButtonName compatBtnName = null;
+
+ if (rpcSpecVersion != null && rpcSpecVersion.getMajor() >= 5) {
+ if (ButtonName.PLAY_PAUSE.equals(buttonName)) {
+ compatBtnName = ButtonName.OK;
+ }
+ } else { // rpc spec version is either null or less than 5
+ if (ButtonName.OK.equals(buttonName)) {
+ compatBtnName = ButtonName.PLAY_PAUSE;
+ }
+ }
+
+ try {
+ if (compatBtnName != null) { //There is a button name that needs to be swapped out
+ RPCNotification notification2;
+ //The following is done because there is currently no way to make a deep copy
+ //of an RPC. Since this code will be removed, it's ugliness is borderline acceptable.
+ if (notification instanceof OnButtonEvent) {
+ OnButtonEvent onButtonEvent = new OnButtonEvent();
+ onButtonEvent.setButtonEventMode(((OnButtonEvent) notification).getButtonEventMode());
+ onButtonEvent.setCustomButtonID(((OnButtonEvent) notification).getCustomButtonID());
+ notification2 = onButtonEvent;
+ } else if (notification instanceof OnButtonPress) {
+ OnButtonPress onButtonPress = new OnButtonPress();
+ onButtonPress.setButtonPressMode(((OnButtonPress) notification).getButtonPressMode());
+ onButtonPress.setCustomButtonName(((OnButtonPress) notification).getCustomButtonName());
+ notification2 = onButtonPress;
+ } else {
+ return null;
+ }
+
+ notification2.setParameters(OnButtonEvent.KEY_BUTTON_NAME, compatBtnName);
+ return notification2;
+ }
+ } catch (Exception e) {
+ //Should never get here
+ }
+ }
+ return null;
+ }
+
+ void cleanProxy() {
+ firstTimeFull = true;
+ currentHMIStatus = null;
+ if (rpcListeners != null) {
+ rpcListeners.clear();
+ }
+ if (rpcResponseListeners != null) {
+ rpcResponseListeners.clear();
+ }
+ if (rpcNotificationListeners != null) {
+ rpcNotificationListeners.clear();
+ }
+ if (rpcRequestListeners != null) {
+ rpcRequestListeners.clear();
+ }
+ if (session != null && session.getIsConnected()) {
+ session.close();
+ }
+ if (encryptionLifecycleManager != null) {
+ encryptionLifecycleManager.dispose();
+ }
+ }
+
+ @Deprecated
+ public void setSdlSecurityClassList(List<Class<? extends SdlSecurityBase>> list) {
+ _secList = list;
+ }
+
+ /**
+ * Sets the security libraries and a callback to notify caller when there is update to encryption service
+ *
+ * @param secList The list of security class(es)
+ * @param listener The callback object
+ */
+ public void setSdlSecurity(@NonNull List<Class<? extends SdlSecurityBase>> secList, ServiceEncryptionListener listener) {
+ this._secList = secList;
+ this.encryptionLifecycleManager = new EncryptionLifecycleManager(internalInterface, listener);
+ }
+
+ private void processRaiResponse(RegisterAppInterfaceResponse rai) {
+ if (rai == null) return;
+
+ this.raiResponse = rai;
+
+ VehicleType vt = rai.getVehicleType();
+ if (vt == null) return;
+
+ String make = vt.getMake();
+ if (make == null) return;
+
+ if (_secList == null) return;
+
+ setSdlSecurityStaticVars();
+
+ SdlSecurityBase sec;
+
+ for (Class<? extends SdlSecurityBase> cls : _secList) {
+ try {
+ sec = cls.newInstance();
+ } catch (Exception e) {
+ continue;
+ }
+
+ if ((sec != null) && (sec.getMakeList() != null)) {
+ if (sec.getMakeList().contains(make)) {
+ sec.setAppId(appConfig.getAppID());
+ if (session != null) {
+ session.setSdlSecurity(sec);
+ sec.handleSdlSession(session);
+ }
+ return;
+ }
+ }
+ }
+ }
+
+ /* *******************************************************************************************************
+ ********************************** Platform specific methods - START *************************************
+ *********************************************************************************************************/
+
+ void initializeProxy() {
+ this.rpcListeners = new HashMap<>();
+ this.rpcResponseListeners = new HashMap<>();
+ this.rpcNotificationListeners = new HashMap<>();
+ this.rpcRequestListeners = new HashMap<>();
+ this.systemCapabilityManager = new SystemCapabilityManager(internalInterface);
+ setupInternalRpcListeners();
+ }
+
+ void onProtocolSessionStarted(SessionType sessionType) {
+ if (sessionType != null) {
+ if (minimumProtocolVersion != null && minimumProtocolVersion.isNewerThan(getProtocolVersion()) == 1) {
+ Log.w(TAG, String.format("Disconnecting from head unit, the configured minimum protocol version %s is greater than the supported protocol version %s", minimumProtocolVersion, getProtocolVersion()));
+ session.endService(sessionType, session.getSessionId());
+ cleanProxy();
+ return;
+ }
+
+ if (sessionType.equals(SessionType.RPC)) {
+ if (appConfig != null) {
+
+ appConfig.prepare();
+
+ SdlMsgVersion sdlMsgVersion = new SdlMsgVersion();
+ sdlMsgVersion.setMajorVersion(MAX_SUPPORTED_RPC_VERSION.getMajor());
+ sdlMsgVersion.setMinorVersion(MAX_SUPPORTED_RPC_VERSION.getMinor());
+ sdlMsgVersion.setPatchVersion(MAX_SUPPORTED_RPC_VERSION.getPatch());
+
+ RegisterAppInterface rai = new RegisterAppInterface(sdlMsgVersion,
+ appConfig.getAppName(), appConfig.isMediaApp(), appConfig.getLanguageDesired(),
+ appConfig.getHmiDisplayLanguageDesired(), appConfig.getAppID());
+ rai.setCorrelationID(REGISTER_APP_INTERFACE_CORRELATION_ID);
+
+ rai.setTtsName(appConfig.getTtsName());
+ rai.setNgnMediaScreenAppName(appConfig.getNgnMediaScreenAppName());
+ rai.setVrSynonyms(appConfig.getVrSynonyms());
+ rai.setAppHMIType(appConfig.getAppType());
+ rai.setDayColorScheme(appConfig.getDayColorScheme());
+ rai.setNightColorScheme(appConfig.getNightColorScheme());
+
+ //Add device/system info in the future
+ //TODO attach previous hash id
+
+ sendRPCMessagePrivate(rai, true);
+ } else {
+ Log.e(TAG, "App config was null, soo...");
+ }
+ }
+ }
+ }
+
+ void onTransportDisconnected(String info, boolean availablePrimary, BaseTransportConfig transportConfig) {
+ }
+
+ void onProtocolSessionStartedNACKed(SessionType sessionType) {
+ }
+
+ void onProtocolSessionEnded(SessionType sessionType) {
+ }
+
+ void onProtocolSessionEndedNACKed(SessionType sessionType) {
+ }
+
+ void startVideoService(boolean encrypted, VideoStreamingParameters parameters) {
+ }
+
+ boolean endVideoStream() {
+ return false;
+ }
+
+ void startAudioService(boolean encrypted) {
+ }
+
+ boolean endAudioStream() {
+ return false;
+ }
+
+ void setSdlSecurityStaticVars() {
+ }
+
+ /* *******************************************************************************************************
+ ********************************** Platform specific methods - End *************************************
+ *********************************************************************************************************/
}
diff --git a/base/src/main/java/com/smartdevicelink/managers/lifecycle/PoliciesFetcher.java b/base/src/main/java/com/smartdevicelink/managers/lifecycle/PoliciesFetcher.java
index f8d59261a..714686a96 100644
--- a/base/src/main/java/com/smartdevicelink/managers/lifecycle/PoliciesFetcher.java
+++ b/base/src/main/java/com/smartdevicelink/managers/lifecycle/PoliciesFetcher.java
@@ -55,7 +55,7 @@ import java.util.Vector;
class PoliciesFetcher {
private static final String TAG = PoliciesFetcher.class.getSimpleName();
- private static final int POLICIES_CORRELATION_ID = 65535;
+ static final int POLICIES_CORRELATION_ID = 65535;
private static HttpURLConnection getURLConnection(Headers myHeader, String sURLString, int Timeout, int iContentLen) {
String sContentType = "application/json";
diff --git a/base/src/main/java/com/smartdevicelink/util/NativeLogTool.java b/base/src/main/java/com/smartdevicelink/util/NativeLogTool.java
index f125fb5ac..ced98a083 100644
--- a/base/src/main/java/com/smartdevicelink/util/NativeLogTool.java
+++ b/base/src/main/java/com/smartdevicelink/util/NativeLogTool.java
@@ -130,7 +130,7 @@ public class NativeLogTool {
break;
}
if (bytesWritten < chunk.length()) {
- Log.e(TAG, "Calling Log.e: msg length=" + chunk.length() + ", bytesWritten=" + bytesWritten);
+ Log.w(TAG, "Calling Log.e: msg length=" + chunk.length() + ", bytesWritten=" + bytesWritten);
}
}
} catch (Exception ex) {
diff --git a/baseAndroid/src/main/java/com/smartdevicelink/managers/lifecycle b/baseAndroid/src/main/java/com/smartdevicelink/managers/lifecycle
new file mode 120000
index 000000000..d72cada51
--- /dev/null
+++ b/baseAndroid/src/main/java/com/smartdevicelink/managers/lifecycle
@@ -0,0 +1 @@
+../../../../../../../base/src/main/java/com/smartdevicelink/managers/lifecycle/ \ No newline at end of file
diff --git a/baseAndroid/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleConfigurationUpdate.java b/baseAndroid/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleConfigurationUpdate.java
deleted file mode 120000
index 62dacca1e..000000000
--- a/baseAndroid/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleConfigurationUpdate.java
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../../../base/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleConfigurationUpdate.java \ No newline at end of file
diff --git a/baseAndroid/src/main/java/com/smartdevicelink/managers/lifecycle/RpcConverter.java b/baseAndroid/src/main/java/com/smartdevicelink/managers/lifecycle/RpcConverter.java
deleted file mode 120000
index 88f7feccc..000000000
--- a/baseAndroid/src/main/java/com/smartdevicelink/managers/lifecycle/RpcConverter.java
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../../../base/src/main/java/com/smartdevicelink/managers/lifecycle/RpcConverter.java \ No newline at end of file
diff --git a/hello_sdl_java/src/main/java/com/smartdevicelink/java/Main.java b/hello_sdl_java/src/main/java/com/smartdevicelink/java/Main.java
index 446c267ee..f34ab0df2 100644
--- a/hello_sdl_java/src/main/java/com/smartdevicelink/java/Main.java
+++ b/hello_sdl_java/src/main/java/com/smartdevicelink/java/Main.java
@@ -68,8 +68,10 @@ public class Main {
static SdlService.SdlServiceCallback serviceCallback = new SdlService.SdlServiceCallback() {
@Override
public void onEnd() {
- thread.interrupt();
- thread = null;
+ if (thread != null) {
+ thread.interrupt();
+ thread = null;
+ }
synchronized (LOCK) {
LOCK.notify();
}
diff --git a/javaSE/src/main/java/com/smartdevicelink/managers/SdlManager.java b/javaSE/src/main/java/com/smartdevicelink/managers/SdlManager.java
index 6e473c46d..a711438cc 100644
--- a/javaSE/src/main/java/com/smartdevicelink/managers/SdlManager.java
+++ b/javaSE/src/main/java/com/smartdevicelink/managers/SdlManager.java
@@ -36,808 +36,156 @@ import android.support.annotation.NonNull;
import android.util.Log;
import com.smartdevicelink.managers.file.FileManager;
-import com.smartdevicelink.managers.file.FileManagerConfig;
-import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
-import com.smartdevicelink.managers.lifecycle.LifecycleConfigurationUpdate;
-import com.smartdevicelink.managers.lifecycle.LifecycleManager;
import com.smartdevicelink.managers.permission.PermissionManager;
import com.smartdevicelink.managers.screen.ScreenManager;
-import com.smartdevicelink.protocol.enums.FunctionID;
-import com.smartdevicelink.protocol.enums.SessionType;
-import com.smartdevicelink.proxy.RPCMessage;
-import com.smartdevicelink.proxy.RPCRequest;
-import com.smartdevicelink.proxy.RPCResponse;
-import com.smartdevicelink.proxy.SystemCapabilityManager;
-import com.smartdevicelink.proxy.interfaces.ISdl;
-import com.smartdevicelink.proxy.rpc.ChangeRegistration;
-import com.smartdevicelink.proxy.rpc.OnHMIStatus;
-import com.smartdevicelink.proxy.rpc.RegisterAppInterfaceResponse;
-import com.smartdevicelink.proxy.rpc.SetAppIcon;
-import com.smartdevicelink.proxy.rpc.TTSChunk;
-import com.smartdevicelink.proxy.rpc.TemplateColorScheme;
-import com.smartdevicelink.proxy.rpc.enums.AppHMIType;
-import com.smartdevicelink.proxy.rpc.enums.Language;
-import com.smartdevicelink.proxy.rpc.enums.Result;
import com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason;
-import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
-import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
-import com.smartdevicelink.proxy.rpc.listeners.OnRPCRequestListener;
-import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener;
-import com.smartdevicelink.security.SdlSecurityBase;
-import com.smartdevicelink.transport.BaseTransportConfig;
import com.smartdevicelink.transport.enums.TransportType;
import com.smartdevicelink.util.DebugTool;
-import com.smartdevicelink.util.Version;
-
-import org.json.JSONException;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Vector;
-
/**
* <strong>SDLManager</strong> <br>
- *
+ * <p>
* This is the main point of contact between an application and SDL <br>
- *
+ * <p>
* It is broken down to these areas: <br>
- *
+ * <p>
* 1. SDLManagerBuilder <br>
* 2. ISdl Interface along with its overridden methods - This can be passed into attached managers <br>
* 3. Sending Requests <br>
* 4. Helper methods
*/
-public class SdlManager extends BaseSdlManager{
-
- private static final String TAG = "SdlManager";
-
- private SdlArtwork appIcon;
- private SdlManagerListener managerListener;
- private List<Class<? extends SdlSecurityBase>> sdlSecList;
- private ServiceEncryptionListener serviceEncryptionListener;
- private FileManagerConfig fileManagerConfig;
-
- // Managers
- private LifecycleManager lifecycleManager;
- private PermissionManager permissionManager;
- private FileManager fileManager;
- private ScreenManager screenManager;
-
-
- // INTERNAL INTERFACE
- /**
- * This is from the LifeCycleManager directly. In the future if there is a reason to be a man in the middle
- * the SdlManager could create it's own, however right now it was only a duplication of logic tied to the LCM.
- */
- private ISdl _internalInterface;
-
-
- // Initialize proxyBridge with anonymous lifecycleListener
- private final LifecycleManager.LifecycleListener lifecycleListener = new LifecycleManager.LifecycleListener() {
- boolean initStarted = false;
- @Override
- public void onProxyConnected(LifecycleManager lifeCycleManager) {
- Log.i(TAG,"Proxy is connected. Now initializing.");
- synchronized (this){
- if(!initStarted){
- changeRegistrationRetry = 0;
- checkLifecycleConfiguration();
- initialize();
- initStarted = true;
- }
- }
- }
- @Override
- public void onServiceStarted(SessionType sessionType){
-
- }
-
- @Override
- public void onServiceEnded(SessionType sessionType){
-
- }
-
- @Override
- public void onProxyClosed(LifecycleManager lifeCycleManager, String info, Exception e, SdlDisconnectedReason reason) {
- Log.i(TAG,"Proxy is closed.");
- if(managerListener != null){
- managerListener.onDestroy(SdlManager.this);
- }
-
- }
-
-
- @Override
- public void onError(LifecycleManager lifeCycleManager, String info, Exception e) {
-
- }
- };
-
- // Sub manager listener
- private final CompletionListener subManagerListener = new CompletionListener() {
- @Override
- public synchronized void onComplete(boolean success) {
- if(!success){
- Log.e(TAG, "Sub manager failed to initialize");
- }
- checkState();
- }
- };
-
- @Override
- void checkState() {
- if (permissionManager != null && fileManager != null && screenManager != null ){
- if (permissionManager.getState() == BaseSubManager.READY && fileManager.getState() == BaseSubManager.READY && screenManager.getState() == BaseSubManager.READY){
- DebugTool.logInfo("Starting sdl manager, all sub managers are in ready state");
- transitionToState(BaseSubManager.READY);
- handleQueuedNotifications();
- notifyDevListener(null);
- onReady();
- } else if (permissionManager.getState() == BaseSubManager.ERROR && fileManager.getState() == BaseSubManager.ERROR && screenManager.getState() == BaseSubManager.ERROR){
- String info = "ERROR starting sdl manager, all sub managers are in error state";
- Log.e(TAG, info);
- transitionToState(BaseSubManager.ERROR);
- notifyDevListener(info);
- } else if (permissionManager.getState() == BaseSubManager.SETTING_UP || fileManager.getState() == BaseSubManager.SETTING_UP || screenManager.getState() == BaseSubManager.SETTING_UP) {
- DebugTool.logInfo("SETTING UP sdl manager, some sub managers are still setting up");
- transitionToState(BaseSubManager.SETTING_UP);
- // No need to notify developer here!
- } else {
- Log.w(TAG, "LIMITED starting sdl manager, some sub managers are in error or limited state and the others finished setting up");
- transitionToState(BaseSubManager.LIMITED);
- handleQueuedNotifications();
- notifyDevListener(null);
- onReady();
- }
- } else {
- // We should never be here, but somehow one of the sub-sub managers is null
- String info = "ERROR one of the sdl sub managers is null";
- Log.e(TAG, info);
- transitionToState(BaseSubManager.ERROR);
- notifyDevListener(info);
- }
- }
-
- private void notifyDevListener(String info) {
- if (managerListener != null) {
- if (getState() == BaseSubManager.ERROR){
- managerListener.onError(this, info, null);
- } else {
- managerListener.onStart(this);
- }
- }
- }
-
- private void onReady(){
- // Set the app icon
- if (SdlManager.this.appIcon != null && SdlManager.this.appIcon.getName() != null) {
- if (fileManager != null && fileManager.getState() == BaseSubManager.READY && !fileManager.hasUploadedFile(SdlManager.this.appIcon)) {
- fileManager.uploadArtwork(SdlManager.this.appIcon, new CompletionListener() {
- @Override
- public void onComplete(boolean success) {
- if (success) {
- SetAppIcon msg = new SetAppIcon(SdlManager.this.appIcon.getName());
- _internalInterface.sendRPCRequest(msg);
- }
- }
- });
- } else {
- SetAppIcon msg = new SetAppIcon(SdlManager.this.appIcon.getName());
- _internalInterface.sendRPCRequest(msg);
- }
- }
- }
-
- @Override
- protected void checkLifecycleConfiguration(){
- final Language actualLanguage = this.getRegisterAppInterfaceResponse().getLanguage();
- final Language actualHMILanguage = this.getRegisterAppInterfaceResponse().getHmiDisplayLanguage();
-
- if ((actualLanguage != null && !actualLanguage.equals(language)) || (actualHMILanguage != null && !actualHMILanguage.equals(hmiLanguage))) {
-
- LifecycleConfigurationUpdate lcuNew = managerListener.managerShouldUpdateLifecycle(actualLanguage, actualHMILanguage);
- LifecycleConfigurationUpdate lcuOld = managerListener.managerShouldUpdateLifecycle(actualLanguage);
- final LifecycleConfigurationUpdate lcu;
- ChangeRegistration changeRegistration;
- if (lcuNew == null) {
- lcu = lcuOld;
- changeRegistration = new ChangeRegistration(actualLanguage, actualLanguage);
- } else {
- lcu = lcuNew;
- changeRegistration = new ChangeRegistration(actualLanguage, actualHMILanguage);
- }
-
- if (lcu != null) {
- changeRegistration.setAppName(lcu.getAppName());
- changeRegistration.setNgnMediaScreenAppName(lcu.getShortAppName());
- changeRegistration.setTtsName(lcu.getTtsName());
- changeRegistration.setVrSynonyms(lcu.getVoiceRecognitionCommandNames());
- changeRegistration.setOnRPCResponseListener(new OnRPCResponseListener() {
- @Override
- public void onResponse(int correlationId, RPCResponse response) {
- if (response.getSuccess()){
- // go through and change sdlManager properties that were changed via the LCU update
- hmiLanguage = actualHMILanguage;
- language = actualLanguage;
-
- if (lcu.getAppName() != null) {
- appName = lcu.getAppName();
- }
-
- if (lcu.getShortAppName() != null) {
- shortAppName = lcu.getShortAppName();
- }
-
- if (lcu.getTtsName() != null) {
- ttsChunks = lcu.getTtsName();
- }
-
- if (lcu.getVoiceRecognitionCommandNames() != null) {
- vrSynonyms = lcu.getVoiceRecognitionCommandNames();
- }
- }
- try {
- Log.v(TAG, response.serializeJSON().toString());
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void onError(int correlationId, Result resultCode, String info) {
- Log.e(TAG, "Change Registration onError: " + resultCode + " | Info: " + info);
- }
- });
- _internalInterface.sendRPC(changeRegistration);
- }
- }
- }
-
- @Override
- protected void initialize(){
- // Instantiate sub managers
- this.permissionManager = new PermissionManager(_internalInterface);
- this.fileManager = new FileManager(_internalInterface, fileManagerConfig);
- this.screenManager = new ScreenManager(_internalInterface, this.fileManager);
-
- // Start sub managers
- this.permissionManager.start(subManagerListener);
- this.fileManager.start(subManagerListener);
- this.screenManager.start(subManagerListener);
- }
-
- @Override
- public void dispose() {
- if (this.permissionManager != null) {
- this.permissionManager.dispose();
- }
-
- if (this.fileManager != null) {
- this.fileManager.dispose();
- }
-
- if (this.screenManager != null) {
- this.screenManager.dispose();
- }
-
- if (this.lifecycleManager != null) {
- this.lifecycleManager.stop();
- }
-
- if(managerListener != null){
- managerListener.onDestroy(this);
- managerListener = null;
- }
-
- transitionToState(BaseSubManager.SHUTDOWN);
- }
-
-
- // MANAGER GETTERS
- /**
- * Gets the PermissionManager. <br>
- * <strong>Note: PermissionManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
- * @return a PermissionManager object
- */
- public PermissionManager getPermissionManager() {
- if (permissionManager.getState() != BaseSubManager.READY && permissionManager.getState() != BaseSubManager.LIMITED){
- Log.e(TAG,"PermissionManager should not be accessed because it is not in READY/LIMITED state");
- }
- checkSdlManagerState();
- return permissionManager;
- }
-
- /**
- * Gets the FileManager. <br>
- * <strong>Note: FileManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
- * @return a FileManager object
- */
- public FileManager getFileManager() {
- if (fileManager.getState() != BaseSubManager.READY && fileManager.getState() != BaseSubManager.LIMITED){
- Log.e(TAG, "FileManager should not be accessed because it is not in READY/LIMITED state");
- }
- checkSdlManagerState();
- return fileManager;
- }
-
- /**
- * Gets the ScreenManager. <br>
- * <strong>Note: ScreenManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
- * @return a ScreenManager object
- */
- public ScreenManager getScreenManager() {
- if (screenManager.getState() != BaseSubManager.READY && screenManager.getState() != BaseSubManager.LIMITED){
- Log.e(TAG, "ScreenManager should not be accessed because it is not in READY/LIMITED state");
- }
- checkSdlManagerState();
- return screenManager;
- }
-
- /**
- * Gets the SystemCapabilityManager. <br>
- * <strong>Note: SystemCapabilityManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
- * @return a SystemCapabilityManager object
- */
- public SystemCapabilityManager getSystemCapabilityManager(){
- return lifecycleManager.getSystemCapabilityManager(this);
- }
-
- /**
- * Method to retrieve the RegisterAppInterface Response message that was sent back from the
- * module. It contains various attributes about the connected module and can be used to adapt
- * to different module types and their supported features.
- *
- * @return RegisterAppInterfaceResponse received from the module or null if the app has not yet
- * registered with the module.
- */
- @Override
- public RegisterAppInterfaceResponse getRegisterAppInterfaceResponse(){
- if(lifecycleManager != null){
- return lifecycleManager.getRegisterAppInterfaceResponse();
- }
- return null;
- }
-
- /**
- * Get the current OnHMIStatus
- * @return OnHMIStatus object represents the current OnHMIStatus
- */
- @Override
- public OnHMIStatus getCurrentHMIStatus(){
- if(this.lifecycleManager !=null ){
- return lifecycleManager.getCurrentHMIStatus();
- }
- return null;
- }
-
- // PROTECTED GETTERS
-
- protected FileManagerConfig getFileManagerConfig() { return fileManagerConfig; }
-
- /**
- * Retrieves the auth token, if any, that was attached to the StartServiceACK for the RPC
- * service from the module. For example, this should be used to login to a user account.
- * @return the string representation of the auth token
- */
- @Override
- public String getAuthToken(){
- return this.lifecycleManager.getAuthToken();
- }
-
- // SENDING REQUESTS
-
- /**
- * Send RPC Message <br>
- * @param message RPCMessage
- */
- @Override
- public void sendRPC(RPCMessage message) {
- _internalInterface.sendRPC(message);
- }
-
- /**
- * Takes a list of RPCMessages and sends it to SDL in a synchronous fashion. Responses are captured through callback on OnMultipleRequestListener.
- * For sending requests asynchronously, use sendRequests <br>
- *
- * <strong>NOTE: This will override any listeners on individual RPCs</strong><br>
- *
- * <strong>ADDITIONAL NOTE: This only takes the type of RPCRequest for now, notifications and responses will be thrown out</strong>
- *
- * @param rpcs is the list of RPCMessages being sent
- * @param listener listener for updates and completions
- */
- @Override
- public void sendSequentialRPCs(final List<? extends RPCMessage> rpcs, final OnMultipleRequestListener listener){
-
- List<RPCRequest> rpcRequestList = new ArrayList<>();
- for (int i = 0; i < rpcs.size(); i++) {
- if (rpcs.get(i) instanceof RPCRequest){
- rpcRequestList.add((RPCRequest)rpcs.get(i));
- }
- }
-
- if (rpcRequestList.size() > 0) {
- _internalInterface.sendSequentialRPCs(rpcRequestList, listener);
- }
- }
-
- /**
- * Takes a list of RPCMessages and sends it to SDL. Responses are captured through callback on OnMultipleRequestListener.
- * For sending requests synchronously, use sendSequentialRPCs <br>
- *
- * <strong>NOTE: This will override any listeners on individual RPCs</strong> <br>
- *
- * <strong>ADDITIONAL NOTE: This only takes the type of RPCRequest for now, notifications and responses will be thrown out</strong>
- *
- * @param rpcs is the list of RPCMessages being sent
- * @param listener listener for updates and completions
- */
- @Override
- public void sendRPCs(List<? extends RPCMessage> rpcs, final OnMultipleRequestListener listener) {
-
- List<RPCRequest> rpcRequestList = new ArrayList<>();
- for (int i = 0; i < rpcs.size(); i++) {
- if (rpcs.get(i) instanceof RPCRequest){
- rpcRequestList.add((RPCRequest)rpcs.get(i));
- }
- }
-
- if (rpcRequestList.size() > 0) {
- _internalInterface.sendRequests(rpcRequestList,listener);
- }
- }
-
- /**
- * Add an OnRPCNotificationListener
- * @param listener listener that will be called when a notification is received
- */
- @Override
- public void addOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener){
- _internalInterface.addOnRPCNotificationListener(notificationId,listener);
- }
-
- /**
- * Remove an OnRPCNotificationListener
- * @param listener listener that was previously added
- */
- @Override
- public void removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener){
- _internalInterface.removeOnRPCNotificationListener(notificationId, listener);
- }
-
- /**
- * Add an OnRPCRequestListener
- * @param listener listener that will be called when a request is received
- */
- @Override
- public void addOnRPCRequestListener(FunctionID requestId, OnRPCRequestListener listener){
- _internalInterface.addOnRPCRequestListener(requestId,listener);
- }
-
- /**
- * Remove an OnRPCRequestListener
- * @param listener listener that was previously added
- */
- @Override
- public void removeOnRPCRequestListener(FunctionID requestId, OnRPCRequestListener listener){
- _internalInterface.removeOnRPCRequestListener(requestId, listener);
- }
-
- // LIFECYCLE / OTHER
-
- // STARTUP
-
- /**
- * Starts up a SdlManager, and calls provided callback called once all BaseSubManagers are done setting up
- */
- @SuppressWarnings("unchecked")
- @Override
- public void start(){
-
- Runtime.getRuntime().addShutdownHook(new Thread() {
- @Override
- public void run() {
- dispose();
- }
- });
-
- Log.i(TAG, "start");
- if (lifecycleManager == null) {
- if (transport != null
- && (transport.getTransportType().equals(TransportType.WEB_SOCKET_SERVER) || transport.getTransportType().equals(TransportType.CUSTOM))) {
- //Do the thing
-
- LifecycleManager.AppConfig appConfig = new LifecycleManager.AppConfig();
- appConfig.setAppName(appName);
- //short app name
- appConfig.setMediaApp(isMediaApp);
- appConfig.setHmiDisplayLanguageDesired(hmiLanguage);
- appConfig.setLanguageDesired(hmiLanguage);
- appConfig.setAppType(hmiTypes);
- appConfig.setVrSynonyms(vrSynonyms);
- appConfig.setTtsName(ttsChunks);
- appConfig.setDayColorScheme(dayColorScheme);
- appConfig.setNightColorScheme(nightColorScheme);
- appConfig.setAppID(appId);
- appConfig.setMinimumProtocolVersion(minimumProtocolVersion);
- appConfig.setMinimumRPCVersion(minimumRPCVersion);
-
- lifecycleManager = new LifecycleManager(appConfig, transport, lifecycleListener);
- _internalInterface = lifecycleManager.getInternalInterface(SdlManager.this);
-
- if (sdlSecList != null && !sdlSecList.isEmpty()) {
- lifecycleManager.setSdlSecurity(sdlSecList, serviceEncryptionListener);
- }
-
- //Setup the notification queue
- initNotificationQueue();
-
- lifecycleManager.start();
-
-
- }else{
- throw new RuntimeException("No transport provided");
- }
- }
- }
-
-
- // BUILDER
- public static class Builder {
- SdlManager sdlManager;
-
- /**
- * Builder for the SdlManager. Parameters in the constructor are required.
- * @param appId the app's ID
- * @param appName the app's name
- * @param listener a SdlManagerListener object
- */
- public Builder(@NonNull final String appId, @NonNull final String appName, @NonNull final SdlManagerListener listener){
- sdlManager = new SdlManager();
- setAppId(appId);
- setAppName(appName);
- setManagerListener(listener);
- }
-
- /**
- * Sets the App ID
- * @param appId String representation of the App ID retreived from the SDL Developer Portal
- */
- public Builder setAppId(@NonNull final String appId){
- sdlManager.appId = appId;
- return this;
- }
-
- /**
- * Sets the Application Name
- * @param appName String that will be associated as the app's name
- */
- public Builder setAppName(@NonNull final String appName){
- sdlManager.appName = appName;
- return this;
- }
-
- /**
- * Sets the Short Application Name
- * @param shortAppName a shorter representation of the app's name for smaller displays
- */
- public Builder setShortAppName(final String shortAppName) {
- sdlManager.shortAppName = shortAppName;
- return this;
- }
-
- /**
- * Sets the minimum protocol version that will be permitted to connect.
- * If the protocol version of the head unit connected is below this version,
- * the app will disconnect with an EndService protocol message and will not register.
- * @param minimumProtocolVersion the minimum Protocol spec version that should be accepted
- */
- public Builder setMinimumProtocolVersion(final Version minimumProtocolVersion) {
- sdlManager.minimumProtocolVersion = minimumProtocolVersion;
- return this;
- }
-
- /**
- * The minimum RPC version that will be permitted to connect.
- * If the RPC version of the head unit connected is below this version, an UnregisterAppInterface will be sent.
- * @param minimumRPCVersion the minimum RPC spec version that should be accepted
- */
- public Builder setMinimumRPCVersion(final Version minimumRPCVersion) {
- sdlManager.minimumRPCVersion = minimumRPCVersion;
- return this;
- }
-
- /**
- * Sets the Language of the App
- * @param hmiLanguage the desired language to be used on the display/HMI of the connected module
- */
- public Builder setLanguage(final Language hmiLanguage) {
- sdlManager.hmiLanguage = hmiLanguage;
- sdlManager.language = hmiLanguage;
- return this;
- }
-
- /**
- * Sets the TemplateColorScheme for daytime
- * @param dayColorScheme color scheme that will be used (if supported) when the display is in a "Day Mode" or
- * similar. Should comprise of colors that contrast well during the day under sunlight.
- */
- public Builder setDayColorScheme(final TemplateColorScheme dayColorScheme){
- sdlManager.dayColorScheme = dayColorScheme;
- return this;
- }
-
- /**
- * Sets the TemplateColorScheme for nighttime
- * @param nightColorScheme color scheme that will be used (if supported) when the display is in a "Night Mode"
- * or similar. Should comprise of colors that contrast well during the night and are not
- * brighter than average.
- */
- public Builder setNightColorScheme(final TemplateColorScheme nightColorScheme){
- sdlManager.nightColorScheme = nightColorScheme;
- return this;
- }
-
- /**
- * Sets the icon for the app on head unit / In-Vehicle-Infotainment system <br>
- * @param sdlArtwork the icon that will be used to represent this application on the connected module
- */
- public Builder setAppIcon(final SdlArtwork sdlArtwork){
- sdlManager.appIcon = sdlArtwork;
- return this;
- }
-
- /**
- * Sets the vector of AppHMIType <br>
- * <strong>Note: This should be an ordered list from most -> least relevant</strong>
- * @param hmiTypes HMI types that represent this application. For example, if the app is a music player, the
- * MEDIA HMIType should be included.
- */
- public Builder setAppTypes(final Vector<AppHMIType> hmiTypes){
-
- sdlManager.hmiTypes = hmiTypes;
-
- if (hmiTypes != null) {
- sdlManager.isMediaApp = hmiTypes.contains(AppHMIType.MEDIA);
- }
-
- return this;
- }
-
- /**
- * Sets the FileManagerConfig for the session.<br>
- * <strong>Note: If not set, the default configuration value of 1 will be set for
- * artworkRetryCount and fileRetryCount in FileManagerConfig</strong>
- * @param fileManagerConfig - configuration options
- */
- public Builder setFileManagerConfig (final FileManagerConfig fileManagerConfig){
- sdlManager.fileManagerConfig = fileManagerConfig;
- return this;
- }
-
- /**
- * Sets the voice recognition synonyms that can be used to identify this application.
- * @param vrSynonyms a vector of Strings that can be associated with this app. For example the app's name should
- * be included as well as any phonetic spellings of the app name that might help the on-board
- * VR system associated a users spoken word with the supplied synonyms.
- */
- public Builder setVrSynonyms(final Vector<String> vrSynonyms) {
- sdlManager.vrSynonyms = vrSynonyms;
- return this;
- }
-
- /**
- * Sets the Text-To-Speech Name of the application. These TTSChunks might be used by the module as an audio
- * representation of the app's name.
- * @param ttsChunks the TTS chunks that can represent this app's name
- */
- public Builder setTtsName(final Vector<TTSChunk> ttsChunks) {
- sdlManager.ttsChunks = ttsChunks;
- return this;
- }
-
- /**
- * This Object type may change with the transport refactor
- * Sets the BaseTransportConfig
- * @param transport the type of transport that should be used for this SdlManager instance.
- */
- public Builder setTransportType(BaseTransportConfig transport){
- sdlManager.transport = transport;
- return this;
- }
-
- /**
- * Sets the Security libraries
- * @param secList The list of security class(es)
- */
- @Deprecated
- public Builder setSdlSecurity(List<Class<? extends SdlSecurityBase>> secList) {
- sdlManager.sdlSecList = secList;
- return this;
- }
-
- /**
- * Sets the security libraries and a callback to notify caller when there is update to encryption service
- * @param secList The list of security class(es)
- * @param listener The callback object
- */
- public Builder setSdlSecurity(@NonNull List<Class<? extends SdlSecurityBase>> secList, ServiceEncryptionListener listener) {
- sdlManager.sdlSecList = secList;
- sdlManager.serviceEncryptionListener = listener;
- return this;
- }
-
- /**
- * Set the SdlManager Listener
- * @param listener the listener
- */
- public Builder setManagerListener(@NonNull final SdlManagerListener listener){
- sdlManager.managerListener = listener;
- return this;
- }
-
- /**
- * Set RPCNotification listeners. SdlManager will preload these listeners before any RPCs are sent/received.
- * @param listeners a map of listeners that will be called when a notification is received.
- * Key represents the FunctionID of the notification and value represents the listener
- */
- public Builder setRPCNotificationListeners(Map<FunctionID, OnRPCNotificationListener> listeners){
- sdlManager.onRPCNotificationListeners = listeners;
- return this;
- }
-
- public SdlManager build() {
-
- if (sdlManager.appName == null) {
- throw new IllegalArgumentException("You must specify an app name by calling setAppName");
- }
-
- if (sdlManager.appId == null) {
- throw new IllegalArgumentException("You must specify an app ID by calling setAppId");
- }
-
- if (sdlManager.managerListener == null) {
- throw new IllegalArgumentException("You must set a SdlManagerListener object");
- }
-
- if (sdlManager.hmiTypes == null) {
- Vector<AppHMIType> hmiTypesDefault = new Vector<>();
- hmiTypesDefault.add(AppHMIType.DEFAULT);
- sdlManager.hmiTypes = hmiTypesDefault;
- sdlManager.isMediaApp = false;
- }
- if(sdlManager.fileManagerConfig == null){
- //if FileManagerConfig is not set use default
- sdlManager.fileManagerConfig = new FileManagerConfig();
- }
-
- if (sdlManager.hmiLanguage == null) {
- sdlManager.hmiLanguage = Language.EN_US;
- sdlManager.language = Language.EN_US;
- }
-
- if (sdlManager.minimumProtocolVersion == null){
- sdlManager.minimumProtocolVersion = new Version("1.0.0");
- }
-
- if (sdlManager.minimumRPCVersion == null){
- sdlManager.minimumRPCVersion = new Version("1.0.0");
- }
-
- sdlManager.transitionToState(BaseSubManager.SETTING_UP);
-
- return sdlManager;
- }
- }
-
- /**
- * Start a secured RPC service
- */
- public void startRPCEncryption() {
- if (lifecycleManager != null) {
- lifecycleManager.startRPCEncryption();
- }
- }
+public class SdlManager extends BaseSdlManager {
+
+ /**
+ * Starts up a SdlManager, and calls provided callback called once all BaseSubManagers are done setting up
+ */
+ @Override
+ public void start() {
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ dispose();
+ }
+ });
+
+ Log.i(TAG, "start");
+ if (lifecycleManager == null) {
+ if (transport != null && (transport.getTransportType().equals(TransportType.WEB_SOCKET_SERVER) || transport.getTransportType().equals(TransportType.CUSTOM))) {
+ super.start();
+ lifecycleManager.start();
+ } else {
+ throw new RuntimeException("No transport provided");
+ }
+ }
+ }
+
+ @Override
+ protected void initialize() {
+ // Instantiate sub managers
+ this.permissionManager = new PermissionManager(_internalInterface);
+ this.fileManager = new FileManager(_internalInterface, fileManagerConfig);
+ this.screenManager = new ScreenManager(_internalInterface, this.fileManager);
+
+ // Start sub managers
+ this.permissionManager.start(subManagerListener);
+ this.fileManager.start(subManagerListener);
+ this.screenManager.start(subManagerListener);
+ }
+
+ @Override
+ void checkState() {
+ if (permissionManager != null && fileManager != null && screenManager != null) {
+ if (permissionManager.getState() == BaseSubManager.READY && fileManager.getState() == BaseSubManager.READY && screenManager.getState() == BaseSubManager.READY) {
+ DebugTool.logInfo("Starting sdl manager, all sub managers are in ready state");
+ transitionToState(BaseSubManager.READY);
+ handleQueuedNotifications();
+ notifyDevListener(null);
+ onReady();
+ } else if (permissionManager.getState() == BaseSubManager.ERROR && fileManager.getState() == BaseSubManager.ERROR && screenManager.getState() == BaseSubManager.ERROR) {
+ String info = "ERROR starting sdl manager, all sub managers are in error state";
+ Log.e(TAG, info);
+ transitionToState(BaseSubManager.ERROR);
+ notifyDevListener(info);
+ } else if (permissionManager.getState() == BaseSubManager.SETTING_UP || fileManager.getState() == BaseSubManager.SETTING_UP || screenManager.getState() == BaseSubManager.SETTING_UP) {
+ DebugTool.logInfo("SETTING UP sdl manager, some sub managers are still setting up");
+ transitionToState(BaseSubManager.SETTING_UP);
+ // No need to notify developer here!
+ } else {
+ Log.w(TAG, "LIMITED starting sdl manager, some sub managers are in error or limited state and the others finished setting up");
+ transitionToState(BaseSubManager.LIMITED);
+ handleQueuedNotifications();
+ notifyDevListener(null);
+ onReady();
+ }
+ } else {
+ // We should never be here, but somehow one of the sub-sub managers is null
+ String info = "ERROR one of the sdl sub managers is null";
+ Log.e(TAG, info);
+ transitionToState(BaseSubManager.ERROR);
+ notifyDevListener(info);
+ }
+ }
+
+ private void notifyDevListener(String info) {
+ if (managerListener != null) {
+ if (getState() == BaseSubManager.ERROR) {
+ managerListener.onError((SdlManager) this, info, null);
+ } else {
+ managerListener.onStart((SdlManager) this);
+ }
+ }
+ }
+
+ @Override
+ void retryChangeRegistration() {
+ // Do nothing
+ }
+
+ @Override
+ void onProxyClosed(SdlDisconnectedReason reason) {
+ Log.i(TAG, "Proxy is closed.");
+ if (managerListener != null) {
+ managerListener.onDestroy(SdlManager.this);
+ }
+ }
+
+ @Override
+ public void dispose() {
+ if (this.permissionManager != null) {
+ this.permissionManager.dispose();
+ }
+
+ if (this.fileManager != null) {
+ this.fileManager.dispose();
+ }
+
+ if (this.screenManager != null) {
+ this.screenManager.dispose();
+ }
+
+ if (this.lifecycleManager != null) {
+ this.lifecycleManager.stop();
+ }
+
+ if (managerListener != null) {
+ managerListener.onDestroy((SdlManager) this);
+ managerListener = null;
+ }
+
+ transitionToState(BaseSubManager.SHUTDOWN);
+ }
+
+ // BUILDER
+ public static class Builder extends BaseSdlManager.Builder {
+ /**
+ * Builder for the SdlManager. Parameters in the constructor are required.
+ *
+ * @param appId the app's ID
+ * @param appName the app's name
+ * @param listener a SdlManagerListener object
+ */
+ public Builder(@NonNull final String appId, @NonNull final String appName, @NonNull final SdlManagerListener listener) {
+ super(appId, appName, listener);
+ }
+ }
}
diff --git a/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java b/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java
index 0beb1da0e..4a5e3747d 100644
--- a/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java
+++ b/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java
@@ -32,74 +32,10 @@
package com.smartdevicelink.managers.lifecycle;
-import android.support.annotation.NonNull;
import android.support.annotation.RestrictTo;
-import android.util.Log;
-import com.smartdevicelink.SdlConnection.ISdlConnectionListener;
import com.smartdevicelink.SdlConnection.SdlSession;
-import com.smartdevicelink.exception.SdlException;
-import com.smartdevicelink.managers.SdlManager;
-import com.smartdevicelink.managers.ServiceEncryptionListener;
-import com.smartdevicelink.marshal.JsonRPCMarshaller;
-import com.smartdevicelink.protocol.ProtocolMessage;
-import com.smartdevicelink.protocol.enums.FunctionID;
-import com.smartdevicelink.protocol.enums.MessageType;
-import com.smartdevicelink.protocol.enums.SessionType;
-import com.smartdevicelink.proxy.RPCMessage;
-import com.smartdevicelink.proxy.RPCNotification;
-import com.smartdevicelink.proxy.RPCRequest;
-import com.smartdevicelink.proxy.RPCResponse;
-import com.smartdevicelink.proxy.SystemCapabilityManager;
-import com.smartdevicelink.proxy.interfaces.IAudioStreamListener;
-import com.smartdevicelink.proxy.interfaces.ISdl;
-import com.smartdevicelink.proxy.interfaces.ISdlServiceListener;
-import com.smartdevicelink.proxy.interfaces.IVideoStreamListener;
-import com.smartdevicelink.proxy.interfaces.OnSystemCapabilityListener;
-import com.smartdevicelink.proxy.rpc.OnAppInterfaceUnregistered;
-import com.smartdevicelink.proxy.rpc.OnButtonEvent;
-import com.smartdevicelink.proxy.rpc.OnButtonPress;
-import com.smartdevicelink.proxy.rpc.OnHMIStatus;
-import com.smartdevicelink.proxy.rpc.OnSystemRequest;
-import com.smartdevicelink.proxy.rpc.RegisterAppInterface;
-import com.smartdevicelink.proxy.rpc.RegisterAppInterfaceResponse;
-import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
-import com.smartdevicelink.proxy.rpc.SubscribeButton;
-import com.smartdevicelink.proxy.rpc.SystemRequest;
-import com.smartdevicelink.proxy.rpc.TTSChunk;
-import com.smartdevicelink.proxy.rpc.TemplateColorScheme;
-import com.smartdevicelink.proxy.rpc.UnregisterAppInterface;
-import com.smartdevicelink.proxy.rpc.VehicleType;
-import com.smartdevicelink.proxy.rpc.enums.AppHMIType;
-import com.smartdevicelink.proxy.rpc.enums.AppInterfaceUnregisteredReason;
-import com.smartdevicelink.proxy.rpc.enums.ButtonName;
-import com.smartdevicelink.proxy.rpc.enums.FileType;
-import com.smartdevicelink.proxy.rpc.enums.HMILevel;
-import com.smartdevicelink.proxy.rpc.enums.Language;
-import com.smartdevicelink.proxy.rpc.enums.RequestType;
-import com.smartdevicelink.proxy.rpc.enums.Result;
-import com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason;
-import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
-import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
-import com.smartdevicelink.proxy.rpc.listeners.OnPutFileUpdateListener;
-import com.smartdevicelink.proxy.rpc.listeners.OnRPCListener;
-import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
-import com.smartdevicelink.proxy.rpc.listeners.OnRPCRequestListener;
-import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener;
-import com.smartdevicelink.security.SdlSecurityBase;
-import com.smartdevicelink.streaming.audio.AudioStreamingCodec;
-import com.smartdevicelink.streaming.audio.AudioStreamingParams;
-import com.smartdevicelink.streaming.video.VideoStreamingParameters;
import com.smartdevicelink.transport.BaseTransportConfig;
-import com.smartdevicelink.util.CorrelationIdGenerator;
-import com.smartdevicelink.util.DebugTool;
-import com.smartdevicelink.util.FileUtls;
-import com.smartdevicelink.util.Version;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Vector;
-import java.util.concurrent.CopyOnWriteArrayList;
/**
* The lifecycle manager creates a central point for all SDL session logic to converge. It should only be used by
@@ -107,1398 +43,21 @@ import java.util.concurrent.CopyOnWriteArrayList;
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public class LifecycleManager extends BaseLifecycleManager {
-
- private static final String TAG = "Lifecycle Manager";
-
- public static final Version MAX_SUPPORTED_RPC_VERSION = new Version(6, 0, 0);
-
- // Protected Correlation IDs
- private final int REGISTER_APP_INTERFACE_CORRELATION_ID = 65529,
- UNREGISTER_APP_INTERFACE_CORRELATION_ID = 65530;
-
-
- // Sdl Synchronization Objects
- private static final Object RPC_LISTENER_LOCK = new Object(),
- ON_UPDATE_LISTENER_LOCK = new Object(),
- ON_REQUEST_LISTENER_LOCK = new Object(),
- ON_NOTIFICATION_LISTENER_LOCK = new Object();
-
-
-
- SdlSession session;
- AppConfig appConfig;
-
- //protected Version protocolVersion = new Version(1,0,0);
- protected Version rpcSpecVersion = MAX_SUPPORTED_RPC_VERSION;
-
-
- private final HashMap<Integer,CopyOnWriteArrayList<OnRPCListener>> rpcListeners;
- private final HashMap<Integer, OnRPCResponseListener> rpcResponseListeners;
- private final HashMap<Integer, CopyOnWriteArrayList<OnRPCNotificationListener>> rpcNotificationListeners;
- private final HashMap<Integer, CopyOnWriteArrayList<OnRPCRequestListener>> rpcRequestListeners;
-
- protected final SystemCapabilityManager systemCapabilityManager;
- private EncryptionLifecycleManager encryptionLifecycleManager;
-
- protected RegisterAppInterfaceResponse raiResponse = null;
-
- private OnHMIStatus currentHMIStatus;
- protected boolean firstTimeFull = true;
-
- final LifecycleListener lifecycleListener;
-
- private List<Class<? extends SdlSecurityBase>> _secList = null;
- private String authToken;
- private Version minimumProtocolVersion;
- private Version minimumRPCVersion;
-
- public LifecycleManager(AppConfig appConfig, BaseTransportConfig config, LifecycleListener listener){
-
- this.lifecycleListener = listener;
-
- this.rpcListeners = new HashMap<>();
- this.rpcResponseListeners = new HashMap<>();
- this.rpcNotificationListeners = new HashMap<>();
- this.rpcRequestListeners = new HashMap<>();
-
- this.appConfig = appConfig;
- this.minimumProtocolVersion = appConfig.minimumProtocolVersion;
- this.minimumRPCVersion = appConfig.minimumRPCVersion;
- this.session = new SdlSession(sdlConnectionListener, config);
-
- this.systemCapabilityManager = new SystemCapabilityManager(internalInterface);
- }
-
- public void start(){
- try {
- setupInternalRpcListeners();
- session.startSession();
- } catch (SdlException e) {
- e.printStackTrace();
- }
-
- }
-
- /**
- * Start a secured RPC service
- */
- public void startRPCEncryption() {
- if (session != null) {
- session.startService(SessionType.RPC, session.getSessionId(), true);
- }
- }
-
- public void stop(){
- session.close();
- }
-
- private Version getProtocolVersion(){
- if (session != null){
- return session.getProtocolVersion();
- }
- return new Version(1,0,0);
- }
-
- private void sendRPCs(List<? extends RPCMessage> messages, final OnMultipleRequestListener listener){
- if(messages != null ){
- for(RPCMessage message : messages){
- // Request Specifics
- if(message instanceof RPCRequest){
- RPCRequest request = ((RPCRequest) message);
- final OnRPCResponseListener devOnRPCResponseListener = request.getOnRPCResponseListener();
- request.setCorrelationID(CorrelationIdGenerator.generateId());
- if (listener != null) {
- listener.addCorrelationId(request.getCorrelationID());
- request.setOnRPCResponseListener(new OnRPCResponseListener() {
- @Override
- public void onResponse(int correlationId, RPCResponse response) {
- if (devOnRPCResponseListener != null){
- devOnRPCResponseListener.onResponse(correlationId, response);
- }
- if (listener.getSingleRpcResponseListener() != null) {
- listener.getSingleRpcResponseListener().onResponse(correlationId, response);
- }
- }
-
- @Override
- public void onError(int correlationId, Result resultCode, String info) {
- super.onError(correlationId, resultCode, info);
- if (devOnRPCResponseListener != null){
- devOnRPCResponseListener.onError(correlationId, resultCode, info);
- }
- if (listener.getSingleRpcResponseListener() != null) {
- listener.getSingleRpcResponseListener().onError(correlationId, resultCode, info);
- }
- }
- });
- }
- sendRPCMessagePrivate(request);
- }else {
- // Notifications and Responses
- sendRPCMessagePrivate(message);
- if (listener != null){
- listener.onUpdate(messages.size());
- if (messages.size() == 0){
- listener.onFinished();
- }
- }
- }
- }
- }
- }
-
- private void sendSequentialRPCs(final List<? extends RPCMessage> messages, final OnMultipleRequestListener listener){
- if (messages != null){
- // Break out of recursion, we have finished the requests
- if (messages.size() == 0) {
- if(listener != null){
- listener.onFinished();
- }
- return;
- }
-
- RPCMessage rpc = messages.remove(0);
-
- // Request Specifics
- if (rpc.getMessageType().equals(RPCMessage.KEY_REQUEST)) {
- RPCRequest request = (RPCRequest) rpc;
- request.setCorrelationID(CorrelationIdGenerator.generateId());
-
- final OnRPCResponseListener devOnRPCResponseListener = request.getOnRPCResponseListener();
-
- request.setOnRPCResponseListener(new OnRPCResponseListener() {
- @Override
- public void onResponse(int correlationId, RPCResponse response) {
- if (devOnRPCResponseListener != null){
- devOnRPCResponseListener.onResponse(correlationId, response);
- }
- if (listener != null) {
- listener.onResponse(correlationId, response);
- listener.onUpdate(messages.size());
- }
- // recurse after onResponse
- sendSequentialRPCs(messages, listener);
- }
-
- @Override
- public void onError(int correlationId, Result resultCode, String info) {
- if (devOnRPCResponseListener != null){
- devOnRPCResponseListener.onError(correlationId, resultCode, info);
- }
- if (listener != null) {
- listener.onError(correlationId, resultCode, info);
- listener.onUpdate(messages.size());
-
- }
- // recurse after onError
- sendSequentialRPCs(messages, listener);
- }
- });
- sendRPCMessagePrivate(request);
- } else {
- // Notifications and Responses
- sendRPCMessagePrivate(rpc);
- if (listener != null) {
- listener.onUpdate(messages.size());
- }
- // recurse after sending a notification or response as there is no response.
- sendSequentialRPCs(messages, listener);
- }
- }
- }
-
- /**
- * This method is used to ensure all of the methods in this class can remain private and no grantees can be made
- * to the developer what methods are available or not.
- *
- * <b>NOTE: THERE IS NO GURANTEE THIS WILL BE A VALID SYSTEM CAPABILITY MANAGER</b>
- *
- * @param sdlManager this must be a working manager instance
- * @return the system capability manager.
- */
- @RestrictTo(RestrictTo.Scope.LIBRARY)
- public SystemCapabilityManager getSystemCapabilityManager(SdlManager sdlManager){
- if(sdlManager != null){
- return systemCapabilityManager;
- }
- return null;
- }
-
- private boolean isConnected(){
- if(session != null){
- return session.getIsConnected();
- }else{
- return false;
- }
- }
-
- /**
- * Method to retrieve the RegisterAppInterface Response message that was sent back from the
- * module. It contains various attributes about the connected module and can be used to adapt
- * to different module types and their supported features.
- *
- * @return RegisterAppInterfaceResponse received from the module or null if the app has not yet
- * registered with the module.
- */
- public RegisterAppInterfaceResponse getRegisterAppInterfaceResponse(){
- return this.raiResponse;
- }
-
-
- /**
- * Get the current OnHMIStatus
- * @return OnHMIStatus object represents the current OnHMIStatus
- */
- public OnHMIStatus getCurrentHMIStatus() {
- return currentHMIStatus;
- }
-
- private void onClose(String info, Exception e){
- Log.i(TAG, "onClose");
- if(lifecycleListener != null){
- lifecycleListener.onProxyClosed(this, info,e,null);
- }
- }
-
- /**
- * This method is used to ensure all of the methods in this class can remain private and no grantees can be made
- * to the developer what methods are available or not.
- *
- * @param sdlManager this must be a working manager instance
- * @return the internal interface that hooks into this manager
- */
- @RestrictTo(RestrictTo.Scope.LIBRARY)
- public ISdl getInternalInterface(SdlManager sdlManager) {
- if (sdlManager != null) {
- return internalInterface;
- }
- return null;
- }
-
-
- /* *******************************************************************************************************
- ********************************** INTERNAL - RPC LISTENERS !! START !! *********************************
- *********************************************************************************************************/
-
- private void setupInternalRpcListeners(){
- addRpcListener(FunctionID.REGISTER_APP_INTERFACE, rpcListener);
- addRpcListener(FunctionID.ON_HMI_STATUS, rpcListener);
- addRpcListener(FunctionID.ON_HASH_CHANGE, rpcListener);
- addRpcListener(FunctionID.ON_SYSTEM_REQUEST, rpcListener);
- addRpcListener(FunctionID.ON_APP_INTERFACE_UNREGISTERED, rpcListener);
- addRpcListener(FunctionID.UNREGISTER_APP_INTERFACE, rpcListener);
- }
-
-
- private OnRPCListener rpcListener = new OnRPCListener() {
- @Override
- public void onReceived(RPCMessage message) {
- //Make sure this is a response as expected
- FunctionID functionID = message.getFunctionID();
- if (functionID != null) {
- switch (functionID) {
- case REGISTER_APP_INTERFACE:
- //We have begun
- Log.i(TAG, "RAI Response");
- raiResponse = (RegisterAppInterfaceResponse) message;
- SdlMsgVersion rpcVersion = ((RegisterAppInterfaceResponse) message).getSdlMsgVersion();
- if (rpcVersion != null) {
- LifecycleManager.this.rpcSpecVersion = new Version(rpcVersion.getMajorVersion(), rpcVersion.getMinorVersion(), rpcVersion.getPatchVersion());
- } else {
- LifecycleManager.this.rpcSpecVersion = MAX_SUPPORTED_RPC_VERSION;
- }
- if (minimumRPCVersion != null && minimumRPCVersion.isNewerThan(rpcSpecVersion) == 1) {
- Log.w(TAG, String.format("Disconnecting from head unit, the configured minimum RPC version %s is greater than the supported RPC version %s", minimumRPCVersion, rpcSpecVersion));
- UnregisterAppInterface msg = new UnregisterAppInterface();
- msg.setCorrelationID(UNREGISTER_APP_INTERFACE_CORRELATION_ID);
- sendRPCMessagePrivate(msg);
- cleanProxy();
- return;
- }
- processRaiResponse(raiResponse);
- systemCapabilityManager.parseRAIResponse(raiResponse);
- break;
- case ON_HMI_STATUS:
- Log.i(TAG, "on hmi status");
- boolean shouldInit = currentHMIStatus == null;
- currentHMIStatus = (OnHMIStatus) message;
- if (lifecycleListener != null && shouldInit) {
- lifecycleListener.onProxyConnected(LifecycleManager.this);
- }
- break;
- case ON_HASH_CHANGE:
- break;
- case ON_SYSTEM_REQUEST:
- final OnSystemRequest onSystemRequest = (OnSystemRequest) message;
- if ((onSystemRequest.getUrl() != null) &&
- (((onSystemRequest.getRequestType() == RequestType.PROPRIETARY) && (onSystemRequest.getFileType() == FileType.JSON))
- || ((onSystemRequest.getRequestType() == RequestType.HTTP) && (onSystemRequest.getFileType() == FileType.BINARY)))) {
- Thread handleOffboardTransmissionThread = new Thread() {
- @Override
- public void run() {
- RPCRequest request = PoliciesFetcher.fetchPolicies(onSystemRequest);
- if (request != null && isConnected()) {
- sendRPCMessagePrivate(request);
- }
- }
- };
- handleOffboardTransmissionThread.start();
- }else if (onSystemRequest.getRequestType() == RequestType.ICON_URL && onSystemRequest.getUrl() != null) {
- //Download the icon file and send SystemRequest RPC
- Thread handleOffBoardTransmissionThread = new Thread() {
- @Override
- public void run() {
- final String urlHttps = onSystemRequest.getUrl().replaceFirst("http://", "https://");
- byte[] file = FileUtls.downloadFile(urlHttps);
- if (file != null) {
- SystemRequest systemRequest = new SystemRequest();
- systemRequest.setFileName(onSystemRequest.getUrl());
- systemRequest.setBulkData(file);
- systemRequest.setRequestType(RequestType.ICON_URL);
- if (isConnected()) {
- sendRPCMessagePrivate(systemRequest);
- }
- } else {
- DebugTool.logError("File was null at: " + urlHttps);
- }
- }
- };
- handleOffBoardTransmissionThread.start();
- }
- break;
- case ON_APP_INTERFACE_UNREGISTERED:
-
- OnAppInterfaceUnregistered onAppInterfaceUnregistered = (OnAppInterfaceUnregistered) message;
-
- if (!onAppInterfaceUnregistered.getReason().equals(AppInterfaceUnregisteredReason.LANGUAGE_CHANGE)) {
- Log.v(TAG, "on app interface unregistered");
- cleanProxy();
- }else{
- Log.v(TAG, "re-registering for language change");
- processLanguageChange();
- }
- break;
- case UNREGISTER_APP_INTERFACE:
- Log.v(TAG, "unregister app interface");
- cleanProxy();
- break;
- }
- }
- }
-
-
-
- };
-
- private void processLanguageChange(){
- if (session != null) {
- if (session.getIsConnected()) {
- session.close();
- }
- try {
- session.startSession();
- } catch (SdlException e) {
- e.printStackTrace();
- }
- }
- }
-
- /* *******************************************************************************************************
- ********************************** INTERNAL - RPC LISTENERS !! END !! *********************************
- *********************************************************************************************************/
-
-
- /* *******************************************************************************************************
- ********************************** METHODS - RPC LISTENERS !! START !! **********************************
- *********************************************************************************************************/
-
- private boolean onRPCReceived(final RPCMessage message){
- synchronized(RPC_LISTENER_LOCK){
- if(message == null || message.getFunctionID() == null){
- return false;
- }
-
- final int id = message.getFunctionID().getId();
- CopyOnWriteArrayList<OnRPCListener> listeners = rpcListeners.get(id);
- if(listeners!=null && listeners.size()>0) {
- for (OnRPCListener listener : listeners) {
- listener.onReceived(message);
- }
- return true;
- }
- return false;
- }
- }
-
- private void addRpcListener(FunctionID id, OnRPCListener listener){
- synchronized(RPC_LISTENER_LOCK){
- if (id != null && listener != null) {
- if (!rpcListeners.containsKey(id.getId())) {
- rpcListeners.put(id.getId(), new CopyOnWriteArrayList<OnRPCListener>());
- }
-
- rpcListeners.get(id.getId()).add(listener);
- }
- }
- }
-
- private boolean removeOnRPCListener(FunctionID id, OnRPCListener listener){
- synchronized(RPC_LISTENER_LOCK){
- if(rpcListeners!= null
- && id != null
- && listener != null
- && rpcListeners.containsKey(id.getId())){
- return rpcListeners.get(id.getId()).remove(listener);
- }
- }
- return false;
+ public LifecycleManager(AppConfig appConfig, BaseTransportConfig config, LifecycleListener listener) {
+ super(appConfig, config, listener);
}
- /**
- * Only call this method for a PutFile response. It will cause a class cast exception if not.
- * @param correlationId correlation id of the packet being updated
- * @param bytesWritten how many bytes were written
- * @param totalSize the total size in bytes
- */
- @SuppressWarnings("unused")
- private void onPacketProgress(int correlationId, long bytesWritten, long totalSize){
- synchronized(ON_UPDATE_LISTENER_LOCK){
- if(rpcResponseListeners !=null
- && rpcResponseListeners.containsKey(correlationId)){
- ((OnPutFileUpdateListener)rpcResponseListeners.get(correlationId)).onUpdate(correlationId, bytesWritten, totalSize);
- }
- }
-
- }
-
- /**
- * Will provide callback to the listener either onFinish or onError depending on the RPCResponses result code,
- * <p>Will automatically remove the listener for the list of listeners on completion.
- * @param msg The RPCResponse message that was received
- * @return if a listener was called or not
- */
- @SuppressWarnings("UnusedReturnValue")
- private boolean onRPCResponseReceived(RPCResponse msg){
- synchronized(ON_UPDATE_LISTENER_LOCK){
- int correlationId = msg.getCorrelationID();
- if(rpcResponseListeners !=null
- && rpcResponseListeners.containsKey(correlationId)){
- OnRPCResponseListener listener = rpcResponseListeners.get(correlationId);
- if(msg.getSuccess()){
- listener.onResponse(correlationId, msg);
- }else{
- listener.onError(correlationId, msg.getResultCode(), msg.getInfo());
- }
- rpcResponseListeners.remove(correlationId);
- return true;
- }
- return false;
- }
- }
-
- /**
- * Add a listener that will receive the response to the specific RPCRequest sent with the corresponding correlation id
- * @param listener that will get called back when a response is received
- * @param correlationId of the RPCRequest that was sent
- * @param totalSize only include if this is an OnPutFileUpdateListener. Otherwise it will be ignored.
- */
- private void addOnRPCResponseListener(OnRPCResponseListener listener,int correlationId, int totalSize){
- synchronized(ON_UPDATE_LISTENER_LOCK){
- if(rpcResponseListeners!=null
- && listener !=null){
- if(listener.getListenerType() == OnRPCResponseListener.UPDATE_LISTENER_TYPE_PUT_FILE){
- ((OnPutFileUpdateListener)listener).setTotalSize(totalSize);
- }
- listener.onStart(correlationId);
- rpcResponseListeners.put(correlationId, listener);
- }
- }
- }
-
- @SuppressWarnings("unused")
- private HashMap<Integer, OnRPCResponseListener> getResponseListeners(){
- synchronized(ON_UPDATE_LISTENER_LOCK){
- return this.rpcResponseListeners;
- }
- }
-
- /**
- * Retrieves the auth token, if any, that was attached to the StartServiceACK for the RPC
- * service from the module. For example, this should be used to login to a user account.
- * @return the string representation of the auth token
- */
- public String getAuthToken(){
- return this.authToken;
- }
-
- @SuppressWarnings("UnusedReturnValue")
- private boolean onRPCNotificationReceived(RPCNotification notification){
- if(notification == null){
- DebugTool.logError("onRPCNotificationReceived - Notification was null");
- return false;
- }
- DebugTool.logInfo("onRPCNotificationReceived - " + notification.getFunctionName() );
-
- //Before updating any listeners, make sure to do any final updates to the notification RPC now
- if(FunctionID.ON_HMI_STATUS.toString().equals(notification.getFunctionName())){
- OnHMIStatus onHMIStatus = (OnHMIStatus) notification;
- onHMIStatus.setFirstRun(firstTimeFull);
- if (onHMIStatus.getHmiLevel() == HMILevel.HMI_FULL) {
- firstTimeFull = false;
- }
- }
-
- synchronized(ON_NOTIFICATION_LISTENER_LOCK){
- CopyOnWriteArrayList<OnRPCNotificationListener> listeners = rpcNotificationListeners.get(FunctionID.getFunctionId(notification.getFunctionName()));
- if(listeners!=null && listeners.size()>0) {
- for (OnRPCNotificationListener listener : listeners) {
- listener.onNotified(notification);
- }
- return true;
- }
- return false;
- }
- }
-
- /**
- * This will add a listener for the specific type of notification. As of now it will only allow
- * a single listener per notification function id
- * @param notificationId The notification type that this listener is designated for
- * @param listener The listener that will be called when a notification of the provided type is received
- */
- @SuppressWarnings("unused")
- private void addOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener){
- synchronized(ON_NOTIFICATION_LISTENER_LOCK){
- if(notificationId != null && listener != null){
- if(!rpcNotificationListeners.containsKey(notificationId.getId())){
- rpcNotificationListeners.put(notificationId.getId(),new CopyOnWriteArrayList<OnRPCNotificationListener>());
- }
- rpcNotificationListeners.get(notificationId.getId()).add(listener);
- }
- }
- }
-
- private boolean removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener){
- synchronized(ON_NOTIFICATION_LISTENER_LOCK){
- if(rpcNotificationListeners!= null
- && notificationId != null
- && listener != null
- && rpcNotificationListeners.containsKey(notificationId.getId())){
- return rpcNotificationListeners.get(notificationId.getId()).remove(listener);
- }
- }
- return false;
- }
-
- @SuppressWarnings("UnusedReturnValue")
- private boolean onRPCRequestReceived(RPCRequest request){
- if(request == null){
- DebugTool.logError("onRPCRequestReceived - request was null");
- return false;
- }
- DebugTool.logInfo("onRPCRequestReceived - " + request.getFunctionName() );
-
- synchronized(ON_REQUEST_LISTENER_LOCK){
- CopyOnWriteArrayList<OnRPCRequestListener> listeners = rpcRequestListeners.get(FunctionID.getFunctionId(request.getFunctionName()));
- if(listeners!=null && listeners.size()>0) {
- for (OnRPCRequestListener listener : listeners) {
- listener.onRequest(request);
- }
- return true;
- }
- return false;
- }
- }
-
- /**
- * This will add a listener for the specific type of request. As of now it will only allow
- * a single listener per request function id
- * @param requestId The request type that this listener is designated for
- * @param listener The listener that will be called when a request of the provided type is received
- */
- @SuppressWarnings("unused")
- private void addOnRPCRequestListener(FunctionID requestId, OnRPCRequestListener listener){
- synchronized(ON_REQUEST_LISTENER_LOCK){
- if(requestId != null && listener != null){
- if(!rpcRequestListeners.containsKey(requestId.getId())){
- rpcRequestListeners.put(requestId.getId(),new CopyOnWriteArrayList<OnRPCRequestListener>());
- }
- rpcRequestListeners.get(requestId.getId()).add(listener);
- }
- }
- }
-
- @SuppressWarnings("UnusedReturnValue")
- private boolean removeOnRPCRequestListener(FunctionID requestId, OnRPCRequestListener listener){
- synchronized(ON_REQUEST_LISTENER_LOCK){
- if(rpcRequestListeners!= null
- && requestId != null
- && listener != null
- && rpcRequestListeners.containsKey(requestId.getId())){
- return rpcRequestListeners.get(requestId.getId()).remove(listener);
- }
- }
- return false;
- }
-
- /* *******************************************************************************************************
- **************************************** RPC LISTENERS !! END !! ****************************************
- *********************************************************************************************************/
-
-
-
- private void sendRPCMessagePrivate(RPCMessage message){
- try {
- //FIXME this is temporary until the next major release of the library where OK is removed
- if (message.getMessageType().equals(RPCMessage.KEY_REQUEST)) {
- RPCRequest request = (RPCRequest) message;
- if(FunctionID.SUBSCRIBE_BUTTON.toString().equals(request.getFunctionName())
- || FunctionID.UNSUBSCRIBE_BUTTON.toString().equals(request.getFunctionName())
- || FunctionID.BUTTON_PRESS.toString().equals(request.getFunctionName())) {
-
- ButtonName buttonName = (ButtonName) request.getObject(ButtonName.class, SubscribeButton.KEY_BUTTON_NAME);
-
-
- if (rpcSpecVersion != null) {
- if (rpcSpecVersion.getMajor() < 5) {
-
- if (ButtonName.PLAY_PAUSE.equals(buttonName)) {
- request.setParameters(SubscribeButton.KEY_BUTTON_NAME, ButtonName.OK);
- }
- } else { //Newer than version 5.0.0
- if (ButtonName.OK.equals(buttonName)) {
- RPCRequest request2 = new RPCRequest(request);
- request2.setParameters(SubscribeButton.KEY_BUTTON_NAME, ButtonName.PLAY_PAUSE);
- request2.setOnRPCResponseListener(request.getOnRPCResponseListener());
- sendRPCMessagePrivate(request2);
- return;
- }
- }
- }
-
- }
- }
-
-
- message.format(rpcSpecVersion,true);
- byte[] msgBytes = JsonRPCMarshaller.marshall(message, (byte)getProtocolVersion().getMajor());
-
- final ProtocolMessage pm = new ProtocolMessage();
- pm.setData(msgBytes);
- if (session != null){
- pm.setSessionID(session.getSessionId());
- }
-
- pm.setMessageType(MessageType.RPC);
- pm.setSessionType(SessionType.RPC);
- pm.setFunctionID(FunctionID.getFunctionId(message.getFunctionName()));
-
- if (encryptionLifecycleManager != null && encryptionLifecycleManager.isEncryptionReady() && encryptionLifecycleManager.getRPCRequiresEncryption(message.getFunctionID())) {
- pm.setPayloadProtected(true);
- } else {
- pm.setPayloadProtected(message.isPayloadProtected());
- }
- if (pm.getPayloadProtected() && (encryptionLifecycleManager == null || !encryptionLifecycleManager.isEncryptionReady())){
- String errorInfo = "Trying to send an encrypted message and there is no secured service";
- if (message.getMessageType().equals((RPCMessage.KEY_REQUEST))) {
- RPCRequest request = (RPCRequest) message;
- OnRPCResponseListener listener = ((RPCRequest) message).getOnRPCResponseListener();
- if (listener != null) {
- listener.onError(request.getCorrelationID(), Result.ABORTED, errorInfo);
- }
- }
- DebugTool.logWarning(errorInfo);
- return;
- }
-
- if(RPCMessage.KEY_REQUEST.equals(message.getMessageType())){ // Request Specifics
- pm.setRPCType((byte)0x00);
- Integer corrId = ((RPCRequest)message).getCorrelationID();
- if( corrId== null) {
- Log.e(TAG, "No correlation ID attached to request. Not sending");
- return;
- }else{
- pm.setCorrID(corrId);
-
- OnRPCResponseListener listener = ((RPCRequest)message).getOnRPCResponseListener();
- if(listener != null){
- addOnRPCResponseListener(listener, corrId, msgBytes.length);
- }
- }
- }else if (RPCMessage.KEY_RESPONSE.equals(message.getMessageType())){ // Response Specifics
- RPCResponse response = (RPCResponse) message;
- pm.setRPCType((byte)0x01);
- if (response.getCorrelationID() == null) {
- //Log error here
- //throw new SdlException("CorrelationID cannot be null. RPC: " + response.getFunctionName(), SdlExceptionCause.INVALID_ARGUMENT);
- Log.e(TAG, "No correlation ID attached to response. Not sending");
- return;
- } else {
- pm.setCorrID(response.getCorrelationID());
- }
- }else if (message.getMessageType().equals(RPCMessage.KEY_NOTIFICATION)) { // Notification Specifics
- pm.setRPCType((byte)0x02);
- }
-
- if (message.getBulkData() != null){
- pm.setBulkData(message.getBulkData());
- }
-
- if(message.getFunctionName().equalsIgnoreCase(FunctionID.PUT_FILE.name())){
- pm.setPriorityCoefficient(1);
- }
-
- session.sendMessage(pm);
-
- } catch (OutOfMemoryError e) {
- e.printStackTrace();
- }
+ @Override
+ void initializeProxy() {
+ super.initializeProxy();
+ this.session = new SdlSession(sdlConnectionListener, _transportConfig);
}
-
-
- /* *******************************************************************************************************
- *************************************** ISdlConnectionListener START ************************************
- *********************************************************************************************************/
-
- final ISdlConnectionListener sdlConnectionListener = new ISdlConnectionListener() {
- @Override
- public void onTransportDisconnected(String info) {
+ @Override
+ void onTransportDisconnected(String info, boolean availablePrimary, BaseTransportConfig transportConfig) {
+ super.onTransportDisconnected(info, availablePrimary, transportConfig);
+ if (!availablePrimary) {
onClose(info, null);
-
- }
-
- @Override
- public void onTransportDisconnected(String info, boolean availablePrimary, BaseTransportConfig transportConfig) {
- if (!availablePrimary) {
- onClose(info, null);
- }
-
- }
-
- @Override
- public void onTransportError(String info, Exception e) {
- onClose(info, e);
-
- }
-
- @Override
- public void onProtocolMessageReceived(ProtocolMessage msg) {
- //Incoming message
- if (SessionType.RPC.equals(msg.getSessionType())
- || SessionType.BULK_DATA.equals(msg.getSessionType())) {
-
- RPCMessage rpc = RpcConverter.extractRpc(msg, session.getProtocolVersion());
- if (rpc != null) {
- String messageType = rpc.getMessageType();
- Log.v(TAG, "RPC received - " + messageType);
-
- rpc.format(rpcSpecVersion, true);
-
- onRPCReceived(rpc);
-
- if (RPCMessage.KEY_RESPONSE.equals(messageType)) {
-
- onRPCResponseReceived((RPCResponse) rpc);
-
- } else if (RPCMessage.KEY_NOTIFICATION.equals(messageType)) {
- FunctionID functionID = rpc.getFunctionID();
- if (functionID != null && (functionID.equals(FunctionID.ON_BUTTON_PRESS)) || functionID.equals(FunctionID.ON_BUTTON_EVENT)) {
- RPCNotification notificationCompat = handleButtonNotificationFormatting(rpc);
- if(notificationCompat != null){
- onRPCNotificationReceived((notificationCompat));
- }
- }
-
- onRPCNotificationReceived((RPCNotification) rpc);
-
- } else if (RPCMessage.KEY_REQUEST.equals(messageType)) {
-
- onRPCRequestReceived((RPCRequest) rpc);
-
- }
- } else {
- Log.w(TAG, "Shouldn't be here");
- }
- }
-
- }
-
- @Override
- public void onProtocolSessionStartedNACKed(SessionType sessionType, byte sessionID, byte version, String correlationID, List<String> rejectedParams) {
- Log.w(TAG, "onProtocolSessionStartedNACKed " + sessionID);
- }
-
- @Override
- public void onProtocolSessionStarted(SessionType sessionType, byte sessionID, byte version, String correlationID, int hashID, boolean isEncrypted) {
-
- Log.i(TAG, "on protocol session started");
- if (sessionType != null) {
- if (minimumProtocolVersion != null && minimumProtocolVersion.isNewerThan(getProtocolVersion()) == 1) {
- Log.w(TAG, String.format("Disconnecting from head unit, the configured minimum protocol version %s is greater than the supported protocol version %s", minimumProtocolVersion, getProtocolVersion()));
- session.endService(sessionType, session.getSessionId());
- cleanProxy();
- return;
- }
-
- if (sessionType.equals(SessionType.RPC)) {
- if (appConfig != null) {
-
- appConfig.prepare();
-
- SdlMsgVersion sdlMsgVersion = new SdlMsgVersion();
- sdlMsgVersion.setMajorVersion(MAX_SUPPORTED_RPC_VERSION.getMajor());
- sdlMsgVersion.setMinorVersion(MAX_SUPPORTED_RPC_VERSION.getMinor());
- sdlMsgVersion.setPatchVersion(MAX_SUPPORTED_RPC_VERSION.getPatch());
-
- RegisterAppInterface rai = new RegisterAppInterface(sdlMsgVersion,
- appConfig.getAppName(), appConfig.isMediaApp(), appConfig.getLanguageDesired(),
- appConfig.getHmiDisplayLanguageDesired(), appConfig.getAppID());
- rai.setCorrelationID(REGISTER_APP_INTERFACE_CORRELATION_ID);
-
- rai.setTtsName(appConfig.getTtsName());
- rai.setNgnMediaScreenAppName(appConfig.getNgnMediaScreenAppName());
- rai.setVrSynonyms(appConfig.getVrSynonyms());
- rai.setAppHMIType(appConfig.getAppType());
- rai.setDayColorScheme(appConfig.getDayColorScheme());
- rai.setNightColorScheme(appConfig.getNightColorScheme());
-
- //Add device/system info in the future
- //TODO attach previous hash id
-
- sendRPCMessagePrivate(rai);
- } else {
- Log.e(TAG, "App config was null, soo...");
- }
-
-
- } else {
- lifecycleListener.onServiceStarted(sessionType);
- }
- }
- }
-
- @Override
- public void onProtocolSessionEnded(SessionType sessionType, byte sessionID, String correlationID) {
-
- }
-
- @Override
- public void onProtocolSessionEndedNACKed(SessionType sessionType, byte sessionID, String correlationID) {
-
- }
-
- @Override
- public void onProtocolError(String info, Exception e) {
- DebugTool.logError("Protocol Error - " + info, e);
- }
-
- @Override
- public void onHeartbeatTimedOut(byte sessionID) { /* Deprecated */ }
-
- @Override
- public void onProtocolServiceDataACK(SessionType sessionType, int dataSize, byte sessionID) {/* Unused */ }
-
-
- @Override
- public void onAuthTokenReceived(String token, byte sessionID) {
- LifecycleManager.this.authToken = token;
- }
-
- };
- /* *******************************************************************************************************
- *************************************** ISdlConnectionListener END ************************************
- *********************************************************************************************************/
-
-
- /* *******************************************************************************************************
- ******************************************** ISdl - START ***********************************************
- *********************************************************************************************************/
-
- final ISdl internalInterface = new ISdl() {
- @Override
- public void start() {
- LifecycleManager.this.start();
- }
-
- @Override
- public void stop() {
- LifecycleManager.this.stop();
- }
-
- @Override
- public boolean isConnected() {
- return LifecycleManager.this.session.getIsConnected();
- }
-
- @Override
- public void addServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener) {
- LifecycleManager.this.session.addServiceListener(serviceType,sdlServiceListener);
- }
-
- @Override
- public void removeServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener) {
- LifecycleManager.this.session.removeServiceListener(serviceType,sdlServiceListener);
-
- }
-
- @Override
- public void startVideoService(VideoStreamingParameters parameters, boolean encrypted) {
- DebugTool.logWarning("startVideoService is not currently implemented");
-
- }
-
- @Override
- public void stopVideoService() {
- DebugTool.logWarning("stopVideoService is not currently implemented");
-
- }
-
- @Override
- public IVideoStreamListener startVideoStream(boolean isEncrypted, VideoStreamingParameters parameters) {
- DebugTool.logWarning("startVideoStream is not currently implemented");
- return null;
- }
-
- @Override
- public void startAudioService(boolean encrypted, AudioStreamingCodec codec, AudioStreamingParams params) {
- DebugTool.logWarning("startAudioService is not currently implemented");
- }
-
- @Override
- public void startAudioService(boolean encrypted) {
- DebugTool.logWarning("startAudioService is not currently implemented");
-
- }
-
- @Override
- public void stopAudioService() {
- DebugTool.logWarning("stopAudioService is not currently implemented");
- }
-
- @Override
- public IAudioStreamListener startAudioStream(boolean isEncrypted, AudioStreamingCodec codec, AudioStreamingParams params) {
- DebugTool.logWarning("startAudioStream is not currently implemented");
- return null;
- }
-
- @Override
- public void sendRPCRequest(RPCRequest message) {
- LifecycleManager.this.sendRPCMessagePrivate(message);
-
- }
-
- @Override
- public void sendRPC(RPCMessage message) {
- if(isConnected()) {
- LifecycleManager.this.sendRPCMessagePrivate(message);
- }
- }
-
- @Override
- public void sendRequests(List<? extends RPCRequest> rpcs, OnMultipleRequestListener listener) {
- LifecycleManager.this.sendRPCs(rpcs,listener);
- }
-
- @Override
- public void sendRPCs(List<? extends RPCMessage> rpcs, OnMultipleRequestListener listener) {
- LifecycleManager.this.sendRPCs(rpcs,listener);
- }
-
- @Override
- public void sendSequentialRPCs(List<? extends RPCMessage> rpcs, OnMultipleRequestListener listener) {
- LifecycleManager.this.sendSequentialRPCs(rpcs,listener);
- }
-
- @Override
- public void addOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {
- LifecycleManager.this.addOnRPCNotificationListener(notificationId,listener);
- }
-
- @Override
- public boolean removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {
- return LifecycleManager.this.removeOnRPCNotificationListener(notificationId,listener);
- }
-
- @Override
- public void addOnRPCRequestListener(FunctionID notificationId, OnRPCRequestListener listener) {
- LifecycleManager.this.addOnRPCRequestListener(notificationId, listener);
- }
-
- @Override
- public boolean removeOnRPCRequestListener(FunctionID notificationId, OnRPCRequestListener listener) {
- return LifecycleManager.this.removeOnRPCRequestListener(notificationId, listener);
- }
-
- @Override
- public void addOnRPCListener(FunctionID responseId, OnRPCListener listener) {
- LifecycleManager.this.addRpcListener(responseId,listener);
- }
-
- @Override
- public boolean removeOnRPCListener(FunctionID responseId, OnRPCListener listener) {
- return LifecycleManager.this.removeOnRPCListener(responseId,listener);
- }
-
- @Override
- public Object getCapability(SystemCapabilityType systemCapabilityType) {
- if (LifecycleManager.this.systemCapabilityManager != null) {
- return LifecycleManager.this.systemCapabilityManager.getCapability(systemCapabilityType);
- } else {
- return null;
- }
- }
-
- @Override
- public void getCapability(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener scListener) {
- if (LifecycleManager.this.systemCapabilityManager != null) {
- LifecycleManager.this.systemCapabilityManager.getCapability(systemCapabilityType, scListener);
- }
- }
-
- @Override
- public Object getCapability(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener scListener, boolean forceUpdate) {
- if (LifecycleManager.this.systemCapabilityManager != null) {
- return LifecycleManager.this.systemCapabilityManager.getCapability(systemCapabilityType, scListener, forceUpdate);
- } else {
- return null;
- }
- }
-
- @Override
- public RegisterAppInterfaceResponse getRegisterAppInterfaceResponse() {
- return raiResponse;
- }
-
- @Override
- public boolean isCapabilitySupported(SystemCapabilityType systemCapabilityType) {
- if (LifecycleManager.this.systemCapabilityManager != null) {
- return LifecycleManager.this.systemCapabilityManager.isCapabilitySupported(systemCapabilityType);
- } else {
- return false;
- }
- }
-
- @Override
- public void addOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) {
- if (LifecycleManager.this.systemCapabilityManager != null) {
- LifecycleManager.this.systemCapabilityManager.addOnSystemCapabilityListener(systemCapabilityType, listener);
- }
- }
-
- @Override
- public boolean removeOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) {
- if (LifecycleManager.this.systemCapabilityManager != null) {
- return LifecycleManager.this.systemCapabilityManager.removeOnSystemCapabilityListener(systemCapabilityType, listener);
- } else {
- return false;
- }
- }
-
- @Override
- public boolean isTransportForServiceAvailable(SessionType serviceType) {
- return LifecycleManager.this.session.isTransportForServiceAvailable(serviceType);
- }
-
- @Override
- public SdlMsgVersion getSdlMsgVersion() {
- SdlMsgVersion msgVersion = new SdlMsgVersion(rpcSpecVersion.getMajor(), rpcSpecVersion.getMinor());
- msgVersion.setPatchVersion(rpcSpecVersion.getPatch());
- return msgVersion;
- }
-
- @Override
- public Version getProtocolVersion() {
- return LifecycleManager.this.getProtocolVersion();
- }
-
- @Override
- public void startRPCEncryption() {
- LifecycleManager.this.startRPCEncryption();
- }
- };
-
- /* *******************************************************************************************************
- ********************************************* ISdl - END ************************************************
- *********************************************************************************************************/
-
- public interface LifecycleListener{
- void onProxyConnected(LifecycleManager lifeCycleManager);
- void onProxyClosed(LifecycleManager lifeCycleManager, String info, Exception e, SdlDisconnectedReason reason);
- void onServiceStarted(SessionType sessionType);
- void onServiceEnded(SessionType sessionType);
- void onError(LifecycleManager lifeCycleManager, String info, Exception e);
- }
-
- public static class AppConfig{
- private String appID, appName, ngnMediaScreenAppName;
- private Vector<TTSChunk> ttsName;
- private Vector<String> vrSynonyms;
- private boolean isMediaApp = false;
- private Language languageDesired, hmiDisplayLanguageDesired;
- private Vector<AppHMIType> appType;
- private TemplateColorScheme dayColorScheme, nightColorScheme;
- private Version minimumProtocolVersion;
- private Version minimumRPCVersion;
-
- private void prepare(){
- if (getNgnMediaScreenAppName() == null) {
- setNgnMediaScreenAppName(getAppName());
- }
-
- if (getLanguageDesired() == null) {
- setLanguageDesired(Language.EN_US);
- }
-
- if (getHmiDisplayLanguageDesired() == null) {
- setHmiDisplayLanguageDesired(Language.EN_US);
- }
-
- if (getVrSynonyms() == null) {
- setVrSynonyms(new Vector<String>());
- getVrSynonyms().add(getAppName());
- }
- }
-
- public String getAppID() {
- return appID;
- }
-
- public void setAppID(String appID) {
- this.appID = appID;
- }
-
- public String getAppName() {
- return appName;
- }
-
- public void setAppName(String appName) {
- this.appName = appName;
- }
-
- public String getNgnMediaScreenAppName() {
- return ngnMediaScreenAppName;
- }
-
- public void setNgnMediaScreenAppName(String ngnMediaScreenAppName) {
- this.ngnMediaScreenAppName = ngnMediaScreenAppName;
- }
-
- public Vector<TTSChunk> getTtsName() {
- return ttsName;
- }
-
- public void setTtsName(Vector<TTSChunk> ttsName) {
- this.ttsName = ttsName;
- }
-
- public Vector<String> getVrSynonyms() {
- return vrSynonyms;
- }
-
- public void setVrSynonyms(Vector<String> vrSynonyms) {
- this.vrSynonyms = vrSynonyms;
- }
-
- public boolean isMediaApp() {
- return isMediaApp;
- }
-
- public void setMediaApp(boolean mediaApp) {
- isMediaApp = mediaApp;
- }
-
- public Language getLanguageDesired() {
- return languageDesired;
- }
-
- public void setLanguageDesired(Language languageDesired) {
- this.languageDesired = languageDesired;
- }
-
- public Language getHmiDisplayLanguageDesired() {
- return hmiDisplayLanguageDesired;
- }
-
- public void setHmiDisplayLanguageDesired(Language hmiDisplayLanguageDesired) {
- this.hmiDisplayLanguageDesired = hmiDisplayLanguageDesired;
- }
-
- public Vector<AppHMIType> getAppType() {
- return appType;
- }
-
- public void setAppType(Vector<AppHMIType> appType) {
- this.appType = appType;
- }
-
- public TemplateColorScheme getDayColorScheme() {
- return dayColorScheme;
- }
-
- public void setDayColorScheme(TemplateColorScheme dayColorScheme) {
- this.dayColorScheme = dayColorScheme;
- }
-
- public TemplateColorScheme getNightColorScheme() {
- return nightColorScheme;
- }
-
- public void setNightColorScheme(TemplateColorScheme nightColorScheme) {
- this.nightColorScheme = nightColorScheme;
- }
-
- public Version getMinimumProtocolVersion() {
- return minimumProtocolVersion;
- }
-
- /**
- * Sets the minimum protocol version that will be permitted to connect.
- * If the protocol version of the head unit connected is below this version,
- * the app will disconnect with an EndService protocol message and will not register.
- *
- * @param minimumProtocolVersion a Version object with the minimally accepted Protocol version
- */
- public void setMinimumProtocolVersion(Version minimumProtocolVersion) {
- this.minimumProtocolVersion = minimumProtocolVersion;
- }
-
- public Version getMinimumRPCVersion() {
- return minimumRPCVersion;
- }
-
- /**
- * The minimum RPC version that will be permitted to connect.
- * If the RPC version of the head unit connected is below this version, an UnregisterAppInterface will be sent.
- *
- * @param minimumRPCVersion a Version object with the minimally accepted RPC spec version
- */
- public void setMinimumRPCVersion(Version minimumRPCVersion) {
- this.minimumRPCVersion = minimumRPCVersion;
- }
- }
-
-
- /**
- * Temporary method to bridge the new PLAY_PAUSE and OKAY button functionality with the old
- * OK button name. This should be removed during the next major release
- * @param notification an RPC message object that should be either an ON_BUTTON_EVENT or ON_BUTTON_PRESS otherwise
- * it will be ignored
- */
- private RPCNotification handleButtonNotificationFormatting(RPCMessage notification){
- if(FunctionID.ON_BUTTON_EVENT.toString().equals(notification.getFunctionName())
- || FunctionID.ON_BUTTON_PRESS.toString().equals(notification.getFunctionName())){
-
- ButtonName buttonName = (ButtonName)notification.getObject(ButtonName.class, OnButtonEvent.KEY_BUTTON_NAME);
- ButtonName compatBtnName = null;
-
- if(rpcSpecVersion != null && rpcSpecVersion.getMajor() >= 5){
- if(ButtonName.PLAY_PAUSE.equals(buttonName)){
- compatBtnName = ButtonName.OK;
- }
- }else{ // rpc spec version is either null or less than 5
- if(ButtonName.OK.equals(buttonName)){
- compatBtnName = ButtonName.PLAY_PAUSE;
- }
- }
-
- try {
- if (compatBtnName != null) { //There is a button name that needs to be swapped out
- RPCNotification notification2;
- //The following is done because there is currently no way to make a deep copy
- //of an RPC. Since this code will be removed, it's ugliness is borderline acceptable.
- if (notification instanceof OnButtonEvent) {
- OnButtonEvent onButtonEvent = new OnButtonEvent();
- onButtonEvent.setButtonEventMode(((OnButtonEvent) notification).getButtonEventMode());
- onButtonEvent.setCustomButtonID(((OnButtonEvent) notification).getCustomButtonID());
- notification2 = onButtonEvent;
- } else if (notification instanceof OnButtonPress) {
- OnButtonPress onButtonPress = new OnButtonPress();
- onButtonPress.setButtonPressMode(((OnButtonPress) notification).getButtonPressMode());
- onButtonPress.setCustomButtonName(((OnButtonPress) notification).getCustomButtonName());
- notification2 = onButtonPress;
- } else {
- return null;
- }
-
- notification2.setParameters(OnButtonEvent.KEY_BUTTON_NAME, compatBtnName);
- return notification2;
- }
- }catch (Exception e){
- //Should never get here
- }
- }
- return null;
- }
-
- private void cleanProxy(){
- if (rpcListeners != null) {
- rpcListeners.clear();
- }
- if (rpcResponseListeners != null) {
- rpcResponseListeners.clear();
- }
- if (rpcNotificationListeners != null) {
- rpcNotificationListeners.clear();
- }
- if (rpcRequestListeners != null) {
- rpcRequestListeners.clear();
- }
- if (session != null && session.getIsConnected()) {
- session.close();
- }
- if (encryptionLifecycleManager != null){
- encryptionLifecycleManager.dispose();
- }
- }
-
- @Deprecated
- public void setSdlSecurityClassList(List<Class<? extends SdlSecurityBase>> list) {
- _secList = list;
- }
-
- /**
- * Sets the security libraries and a callback to notify caller when there is update to encryption service
- * @param secList The list of security class(es)
- * @param listener The callback object
- */
- public void setSdlSecurity(@NonNull List<Class<? extends SdlSecurityBase>> secList, ServiceEncryptionListener listener) {
- this._secList = secList;
- this.encryptionLifecycleManager = new EncryptionLifecycleManager(internalInterface, listener);
- }
-
- private void processRaiResponse(RegisterAppInterfaceResponse rai) {
- if (rai == null) return;
-
- this.raiResponse = rai;
-
- VehicleType vt = rai.getVehicleType();
- if (vt == null) return;
-
- String make = vt.getMake();
- if (make == null) return;
-
- if (_secList == null) return;
-
- SdlSecurityBase sec;
-
- for (Class<? extends SdlSecurityBase> cls : _secList) {
- try {
- sec = cls.newInstance();
- } catch (Exception e) {
- continue;
- }
-
- if ((sec != null) && (sec.getMakeList() != null)) {
- if (sec.getMakeList().contains(make)) {
- sec.setAppId(appConfig.getAppID());
- if (session != null) {
- session.setSdlSecurity(sec);
- sec.handleSdlSession(session);
- }
- return;
- }
- }
}
}
}