diff options
author | Bilal Alsharifi <bilal.alsharifi@gmail.com> | 2019-03-04 14:42:53 -0500 |
---|---|---|
committer | Bilal Alsharifi <bilal.alsharifi@gmail.com> | 2019-03-04 14:42:53 -0500 |
commit | c562bb19d4727656e047c7223e376a01bce8cca6 (patch) | |
tree | 9847476edf250502ddf6d488c763c7c5a8badf8c | |
parent | 1db257635bfedd22009b814b2f867598178c106c (diff) | |
download | sdl_android-c562bb19d4727656e047c7223e376a01bce8cca6.tar.gz |
Add javaSE project
20 files changed, 3215 insertions, 4 deletions
diff --git a/base/src/main/java/com/smartdevicelink/proxy/rpc/RegisterAppInterfaceResponse.java b/base/src/main/java/com/smartdevicelink/proxy/rpc/RegisterAppInterfaceResponse.java index 746129a85..29b7387cc 100644 --- a/base/src/main/java/com/smartdevicelink/proxy/rpc/RegisterAppInterfaceResponse.java +++ b/base/src/main/java/com/smartdevicelink/proxy/rpc/RegisterAppInterfaceResponse.java @@ -4,7 +4,6 @@ import android.support.annotation.NonNull; import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCResponse;
-import com.smartdevicelink.proxy.Version;
import com.smartdevicelink.proxy.rpc.enums.ButtonName;
import com.smartdevicelink.proxy.rpc.enums.HmiZoneCapabilities;
import com.smartdevicelink.proxy.rpc.enums.Language;
@@ -369,9 +368,9 @@ public class RegisterAppInterfaceResponse extends RPCResponse { setParameters(KEY_PCM_STREAM_CAPABILITIES, pcmStreamingCapabilities);
}
public String getProxyVersionInfo() {
- if (Version.VERSION != null)
- return Version.VERSION;
-
+ /*FIXME if (Version.VERSION != null)
+ return Version.VERSION;*/
+
return null;
}
public void setSupportedDiagModes(List<Integer> supportedDiagModes) {
diff --git a/javaSE/build.gradle b/javaSE/build.gradle new file mode 100644 index 000000000..264be4bf6 --- /dev/null +++ b/javaSE/build.gradle @@ -0,0 +1,37 @@ +plugins { + id 'java-library' +} + +group 'com.smartdevicelink' +version '1.0' + +sourceCompatibility = 1.8 + +repositories { + google() + jcenter() +} + +// This extraLibs solution is explained here: https://discuss.gradle.org/t/how-to-include-dependencies-in-jar/19571/5 +configurations { + // configuration that holds jars to include in the jar + extraLibs +} + +dependencies { + extraLibs fileTree(dir: 'libs', include: ['*.jar']) + extraLibs 'com.android.support:support-annotations:28.0.0' + extraLibs 'org.java-websocket:Java-WebSocket:1.3.9' + configurations.api.extendsFrom(configurations.extraLibs) +} + +sourceSets { + main.java.srcDirs += '../base/src/main/java' +} + +jar { + from { + configurations.extraLibs.collect { it.isDirectory() ? it : zipTree(it) } + } +} + diff --git a/javaSE/gradle/wrapper/gradle-wrapper.jar b/javaSE/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 000000000..87b738cbd --- /dev/null +++ b/javaSE/gradle/wrapper/gradle-wrapper.jar diff --git a/javaSE/gradle/wrapper/gradle-wrapper.properties b/javaSE/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..ca21d83d3 --- /dev/null +++ b/javaSE/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jan 25 17:44:56 EST 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip diff --git a/javaSE/gradlew b/javaSE/gradlew new file mode 100755 index 000000000..af6708ff2 --- /dev/null +++ b/javaSE/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/javaSE/gradlew.bat b/javaSE/gradlew.bat new file mode 100644 index 000000000..0f8d5937c --- /dev/null +++ b/javaSE/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/javaSE/libs/bson_java_lib.jar b/javaSE/libs/bson_java_lib.jar Binary files differnew file mode 100644 index 000000000..0a6e6500e --- /dev/null +++ b/javaSE/libs/bson_java_lib.jar diff --git a/javaSE/settings.gradle b/javaSE/settings.gradle new file mode 100644 index 000000000..f7ac48020 --- /dev/null +++ b/javaSE/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'javaSE' + diff --git a/javaSE/src/main/java/com/smartdevicelink/managers/SdlManager.java b/javaSE/src/main/java/com/smartdevicelink/managers/SdlManager.java new file mode 100644 index 000000000..8d3791b94 --- /dev/null +++ b/javaSE/src/main/java/com/smartdevicelink/managers/SdlManager.java @@ -0,0 +1,1114 @@ +package com.smartdevicelink.managers; + +import android.support.annotation.NonNull; +import android.util.Log; +import com.smartdevicelink.exception.SdlException; +import com.smartdevicelink.managers.file.FileManager; +import com.smartdevicelink.managers.file.filetypes.SdlArtwork; +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.RPCStreamController; +import com.smartdevicelink.proxy.SystemCapabilityManager; +import com.smartdevicelink.proxy.callbacks.OnServiceEnded; +import com.smartdevicelink.proxy.callbacks.OnServiceNACKed; +import com.smartdevicelink.proxy.interfaces.*; +import com.smartdevicelink.proxy.rpc.*; +import com.smartdevicelink.proxy.rpc.enums.*; +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.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.WebSocketServerConfig; +import com.smartdevicelink.transport.enums.TransportType; +import com.smartdevicelink.util.DebugTool; +import com.smartdevicelink.util.Version; + +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; + +/** + * <strong>SDLManager</strong> <br> + * + * This is the main point of contact between an application and SDL <br> + * + * It is broken down to these areas: <br> + * + * 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 LifecycleManager proxy; + private String appId, appName, shortAppName; + private boolean isMediaApp; + private Language hmiLanguage; + private SdlArtwork appIcon; + private Vector<AppHMIType> hmiTypes; + private BaseTransportConfig transport; + //FIXME private Context context; + private Vector<String> vrSynonyms; + private Vector<TTSChunk> ttsChunks; + private TemplateColorScheme dayColorScheme, nightColorScheme; + private SdlManagerListener managerListener; + private int state = -1; + private List<Class<? extends SdlSecurityBase>> sdlSecList; + //FIXME private LockScreenConfig lockScreenConfig; + private final Object STATE_LOCK = new Object(); + + + // Managers + private PermissionManager permissionManager; + private FileManager fileManager; + //private LockScreenManager lockScreenManager; + private ScreenManager screenManager; + //private VideoStreamManager videoStreamManager; + //private AudioStreamManager audioStreamManager; + + + // Initialize proxyBridge with anonymous lifecycleListener + //FIXME changed from proxy bridge + 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){ + initialize(); + initStarted = true; + } + } + } + + @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 onServiceEnded(LifecycleManager lifeCycleManager, OnServiceEnded serviceEnded) { + + } + + @Override + public void onServiceNACKed(LifecycleManager lifeCycleManager, OnServiceNACKed serviceNACKed) { + + } + + @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(); + } + }; + + void checkState() { + if (permissionManager != null && fileManager != null && screenManager != null ){//FIXME && (!lockScreenConfig.isEnabled() || lockScreenManager != null)) { + if (permissionManager.getState() == BaseSubManager.READY && fileManager.getState() == BaseSubManager.READY && screenManager.getState() == BaseSubManager.READY){ //FIXME && (!lockScreenConfig.isEnabled() || lockScreenManager.getState() == BaseSubManager.READY)) { + DebugTool.logInfo("Starting sdl manager, all sub managers are in ready state"); + transitionToState(BaseSubManager.READY); + notifyDevListener(null); + onReady(); + } else if (permissionManager.getState() == BaseSubManager.ERROR && fileManager.getState() == BaseSubManager.ERROR && screenManager.getState() == BaseSubManager.ERROR){ //FIXME && (!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){//FIXME || (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); + 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); + } + } + } + + protected void initialize(){ + // Instantiate sub managers + this.permissionManager = new PermissionManager(_internalInterface); + this.fileManager = new FileManager(_internalInterface); //FIXME ,context); + /* FIXME if (lockScreenConfig.isEnabled()) { + this.lockScreenManager = new LockScreenManager(lockScreenConfig, context, _internalInterface); + }*/ + this.screenManager = new ScreenManager(_internalInterface, this.fileManager); + /* FIXME 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); + + } + + /** + * Get the current state for the SdlManager + * @return int value that represents the current state + * @see BaseSubManager + */ + public int getState() { + synchronized (STATE_LOCK) { + return state; + } + } + + protected void transitionToState(int state) { + synchronized (STATE_LOCK) { + this.state = state; + } + } + + //FIXME @SuppressLint("NewApi") + public void dispose() { + if (this.permissionManager != null) { + this.permissionManager.dispose(); + } + + if (this.fileManager != null) { + this.fileManager.dispose(); + } + + /*FIXME if (this.lockScreenManager != null) { + this.lockScreenManager.dispose(); + }*/ + + if (this.screenManager != null) { + this.screenManager.dispose(); + } + + /* FIXME if(this.videoStreamManager != null) { + this.videoStreamManager.dispose(); + } + + // SuppressLint("NewApi") is used because audioStreamManager is only available on android >= jelly bean + if (this.audioStreamManager != null) { + this.audioStreamManager.dispose(); + }*/ + + if(managerListener != null){ + managerListener.onDestroy(this); + managerListener = null; + } + } + + + private 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"); + } + } + + // 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 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. + * <br><br><strong>Note: VideoStreamManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong> + * @return a VideoStreamManager object attached to shit SdlManager instance + */ + /* FIXME + public @Nullable + VideoStreamManager getVideoStreamManager() { + 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. + * <br><strong>Note: AudioStreamManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong> + * @return a AudioStreamManager object + */ + /* FIXME 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 + */ + /* FIXME 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. + */ + public RegisterAppInterfaceResponse getRegisterAppInterfaceResponse(){ + if(proxy != null){ + return proxy.getRegisterAppInterfaceResponse(); + } + return null; + } + + /** + * Get the current OnHMIStatus + * @return OnHMIStatus object represents the current OnHMIStatus + */ + public OnHMIStatus getCurrentHMIStatus(){ + if(this.proxy !=null ){ + return proxy.getCurrentHMIStatus(); + } + return null; + } + + /* ******************************************************************************************************* + ************************************* FileStream Methods - START **************************************** + *********************************************************************************************************/ + + /** + * Used to push a binary stream of file data onto the module from a mobile device. + * + * @param inputStream The input stream of byte data that will be read from. + * @param fileName The SDL file reference name used by the RPC. + * @param offset The data offset in bytes. A value of zero is used to + * indicate data starting from the beginning of the file and a value greater + * than zero is used for resuming partial data chunks. + * @param length The total length of the file being sent. + */ + public void putFileStream(InputStream inputStream, @NonNull String fileName, Long offset, Long length) { + if (proxy != null){ + proxy.putFileStream(inputStream, fileName, offset, length); + } + } + + /** + * Used to push a binary stream of file data onto the module from a mobile device. + * + * @param inputStream The input stream of byte data that will be read from. + * @param fileName The SDL file reference name used by the RPC. + * @param offset The data offset in bytes. A value of zero is used to + * indicate data starting from the beginning of the file and a value greater + * than zero is used for resuming partial data chunks. + * @param length The total length of the file being sent. + * @param fileType The selected file type. See the {@link FileType} enum for + * details. + * @param isPersistentFile Indicates if the file is meant to persist between + * sessions / ignition cycles. + * @param isSystemFile Indicates if the file is meant to be passed through + * core to elsewhere in the system. + */ + public void putFileStream(InputStream inputStream, @NonNull String fileName, Long offset, Long length, FileType fileType, Boolean isPersistentFile, Boolean isSystemFile, OnPutFileUpdateListener cb) { + if (proxy != null){ + proxy.putFileStream(inputStream, fileName, offset, length, fileType, isPersistentFile, isSystemFile, cb); + } + } + + + /** + * Used to push a binary stream of file data onto the module from a mobile device. + * + * @param fileName The SDL file reference name used by the RPC. + * @param offset The data offset in bytes. A value of zero is used to + * indicate data starting from the beginning of the file and a value greater + * than zero is used for resuming partial data chunks. + * @param length The total length of the file being sent. + */ + public OutputStream putFileStream(@NonNull String fileName, Long offset, Long length) { + if (proxy != null){ + return proxy.putFileStream(fileName, offset, length); + } + return null; + } + + /** + * Used to push a binary stream of file data onto the module from a mobile device. + * + * @param fileName The SDL file reference name used by the RPC. + * @param offset The data offset in bytes. A value of zero is used to + * indicate data starting from the beginning of the file and a value greater + * than zero is used for resuming partial data chunks. + * @param length The total length of the file being sent. + * @param fileType The selected file type. See the {@link FileType} enum for + * details. + * @param isPersistentFile Indicates if the file is meant to persist between + * sessions / ignition cycles. + * @param isSystemFile Indicates if the file is meant to be passed through + * core to elsewhere in the system. + */ + public OutputStream putFileStream(@NonNull String fileName, Long offset, Long length, FileType fileType, Boolean isPersistentFile, Boolean isSystemFile, OnPutFileUpdateListener cb) { + if (proxy != null){ + return proxy.putFileStream(fileName, offset, length, fileType, isPersistentFile, isSystemFile, cb); + } + return null; + } + + /** + * Used to push a binary stream of file data onto the module from a mobile device. + * + * @param path The physical file path on the mobile device. + * @param fileName The SDL file reference name used by the RPC. + * @param offset The data offset in bytes. A value of zero is used to + * indicate data starting from the beginning of the file and a value greater + * than zero is used for resuming partial data chunks. + * @param fileType The selected file type. See the {@link FileType} enum for + * details. + * @param isPersistentFile Indicates if the file is meant to persist between + * sessions / ignition cycles. + * @param isSystemFile Indicates if the file is meant to be passed through + * core to elsewhere in the system. + * @param correlationId A unique id that correlates each RPCRequest and + * RPCResponse. + * @return RPCStreamController If the putFileStream was not started + * successfully null is returned, otherwise a valid object reference is + * returned . + */ + public RPCStreamController putFileStream(String path, @NonNull String fileName, Long offset, @NonNull FileType fileType, Boolean isPersistentFile, Boolean isSystemFile, Boolean isPayloadProtected, Integer correlationId, OnPutFileUpdateListener cb) { + if (proxy != null){ + return proxy.putFileStream(path, fileName, offset, fileType, isPersistentFile, isSystemFile, isPayloadProtected, correlationId, cb); + } + return null; + } + + /** + * Used to push a binary stream of file data onto the module from a mobile device. + * + * @param inputStream The input stream of byte data that will be read from. + * @param fileName The SDL file reference name used by the RPC. + * @param offset The data offset in bytes. A value of zero is used to + * indicate data starting from the beginning of the file and a value greater + * than zero is used for resuming partial data chunks. + * @param length The total length of the file being sent. + * @param fileType The selected file type. See the {@link FileType} enum for + * details. + * @param isPersistentFile Indicates if the file is meant to persist between + * sessions / ignition cycles. + * @param isSystemFile Indicates if the file is meant to be passed through + * core to elsewhere in the system. + * @param correlationId A unique id that correlates each RPCRequest and + * RPCResponse. + */ + public RPCStreamController putFileStream(InputStream inputStream, @NonNull String fileName, Long offset, Long length, @NonNull FileType fileType, Boolean isPersistentFile, Boolean isSystemFile, Boolean isPayloadProtected, Integer correlationId) { + if (proxy != null){ + return proxy.putFileStream(inputStream, fileName, offset, length, fileType, isPersistentFile, isSystemFile, isPayloadProtected, correlationId); + } + return null; + + } + + /** + * Used to end an existing putFileStream that was previously initiated with any putFileStream method. + */ + public void endPutFileStream() { + if (proxy != null){ + proxy.endPutFileStream(); + } + } + + public void endRPCStream() { + if (proxy != null){ + proxy.endRPCStream(); + } + } + + public boolean startRPCStream(InputStream is, RPCRequest msg) { + if (proxy != null){ + return proxy.startRPCStream(is, msg); + } + return false; + } + + public OutputStream startRPCStream(RPCRequest msg) { + if (proxy != null){ + return proxy.startRPCStream(msg); + } + return null; + } + + /* ******************************************************************************************************* + ************************************** FileStream Methods - END ***************************************** + *********************************************************************************************************/ + + + // PROTECTED GETTERS + protected String getAppName() { return appName; } + + protected String getAppId() { return appId; } + + protected String getShortAppName() { return shortAppName; } + + protected Language getHmiLanguage() { return hmiLanguage; } + + 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; } + + //FIXME protected LockScreenConfig getLockScreenConfig() { return lockScreenConfig; } + + // SENDING REQUESTS + + /** + * Send RPC Message <br> + * <strong>Note: Only takes type of RPCRequest for now, notifications and responses will be thrown out</strong> + * @param message RPCMessage + */ + public void sendRPC(RPCMessage message) { + + if (message instanceof RPCRequest){ + proxy.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 + */ + 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) { + proxy.sendRpcsSequentially(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) { + proxy.sendRpcs(rpcRequestList, listener); + } + } + + 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 + */ + public void addOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener){ + proxy.addOnRPCNotificationListener(notificationId,listener); + } + + /** + * Remove an OnRPCNotificationListener + * @param listener listener that was previously added + */ + public void removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener){ + proxy.removeOnRPCNotificationListener(notificationId, listener); + } + + // LIFECYCLE / OTHER + + // STARTUP + + /** + * Starts up a SdlManager, and calls provided callback called once all BaseSubManagers are done setting up + */ + @SuppressWarnings("unchecked") + public void start(){ + Log.i(TAG, "start"); + if (proxy == null) { + //FIXME if(transport!= null && transport.getTransportType() == TransportType.MULTIPLEX){ + if (transport != null && transport.getTransportType().equals(TransportType.WEB_SOCKET_SERVER)) { + //Do the thing + + /*FIXME 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); + } + } + }); + }*/ + + LifecycleManager.AppConfig appConfig = new LifecycleManager.AppConfig(); + appConfig.appName = appName; + //short app name + appConfig.isMediaApp = isMediaApp; + appConfig.hmiDisplayLanguageDesired = hmiLanguage; + appConfig.languageDesired = hmiLanguage; + appConfig.appType = hmiTypes; + appConfig.vrSynonyms = vrSynonyms; + appConfig.ttsName = ttsChunks; + appConfig.dayColorScheme = dayColorScheme; + appConfig.nightColorScheme = nightColorScheme; + appConfig.appID = appId; + + + proxy = new LifecycleManager(appConfig, (WebSocketServerConfig)transport, lifecycleListener); + proxy.start(); + if (sdlSecList != null && !sdlSecList.isEmpty()) { + proxy.setSdlSecurityClassList(sdlSecList); + } + + }else{ + throw new RuntimeException("No transport provided"); + } + } + } + + /* FIXME protected void setProxy(SdlProxyBase proxy){ + this.proxy = proxy; + }*/ + + // INTERNAL INTERFACE + private ISdl _internalInterface = new ISdl() { + @Override + public void start() { + proxy.start(); + } + + @Override + public void stop() { + proxy.stop(); + } + + @Override + public boolean isConnected() { + return proxy.isConnected(); + } + + @Override + public void addServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener) { + //FIXME proxy.addServiceListener(serviceType,sdlServiceListener); + } + + @Override + public void removeServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener) { + //FIXME proxy.removeServiceListener(serviceType,sdlServiceListener); + } + + @Override + public void startVideoService(VideoStreamingParameters parameters, boolean encrypted) { + if(proxy.isConnected()){ + //FIXME proxy.startVideoStream(encrypted,parameters); + } + } + + @Override + public IVideoStreamListener startVideoStream(boolean isEncrypted, VideoStreamingParameters parameters){ + return null; //FIXME proxy.startVideoStream(isEncrypted, parameters); + } + + @Override + public void stopVideoService() { + if(proxy.isConnected()){ + //FIXME proxy.endVideoStream(); + } + } + + @Override + public void startAudioService(boolean isEncrypted, AudioStreamingCodec codec, + AudioStreamingParams params) { + if(proxy.isConnected()){ + //FIXME proxy.startAudioStream(isEncrypted, codec, params); + } + } + + @Override + public void startAudioService(boolean encrypted) { + if(proxy.isConnected()){ + //FIXME proxy.startService(SessionType.PCM, encrypted); + } + } + + @Override + public IAudioStreamListener startAudioStream(boolean isEncrypted, AudioStreamingCodec codec, + AudioStreamingParams params) { + return null; //FIXME proxy.startAudioStream(isEncrypted, codec, params); + } + + @Override + public void stopAudioService() { + if(proxy.isConnected()){ + //FIXME proxy.endAudioStream(); + } + } + + @Override + public void sendRPCRequest(RPCRequest message){ + if(message != null){ + proxy.sendRpc(message); + } + } + + @Override + public void sendRequests(List<? extends RPCRequest> rpcs, OnMultipleRequestListener listener) { + proxy.sendRpcs(rpcs, listener); + } + + @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 addOnRPCListener(final FunctionID responseId, final OnRPCListener listener) { + proxy.addRpcListener(responseId, listener); + } + + @Override + public boolean removeOnRPCListener(final FunctionID responseId, final OnRPCListener listener) { + return proxy.removeOnRPCListener(responseId, listener); + } + + @Override + public Object getCapability(SystemCapabilityType systemCapabilityType){ + return proxy.getSystemCapabilityManager().getCapability(systemCapabilityType); + } + + @Override + public void getCapability(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener scListener) { + proxy.getSystemCapabilityManager().getCapability(systemCapabilityType, scListener); + } + + @Override + public boolean isCapabilitySupported(SystemCapabilityType systemCapabilityType){ + return proxy.getSystemCapabilityManager().isCapabilitySupported(systemCapabilityType); + } + + @Override + public void addOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) { + proxy.getSystemCapabilityManager().addOnSystemCapabilityListener(systemCapabilityType, listener); + } + + @Override + public boolean removeOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) { + return proxy.getSystemCapabilityManager().removeOnSystemCapabilityListener(systemCapabilityType, listener); + } + + @Override + public boolean isTransportForServiceAvailable(SessionType serviceType) { + /* FIXME if(SessionType.NAV.equals(serviceType)){ + return proxy.isVideoStreamTransportAvailable(); + }else if(SessionType.PCM.equals(serviceType)){ + return proxy.isAudioStreamTransportAvailable(); + } */ + return false; + } + + @Override + public SdlMsgVersion getSdlMsgVersion(){ + //FIXME this should be a breaking change to support our version + Version rpcSepcVersion = proxy.getRpcSepcVersion(); + if(rpcSepcVersion != null){ + SdlMsgVersion sdlMsgVersion = new SdlMsgVersion(); + sdlMsgVersion.setMajorVersion(rpcSepcVersion.getMajor()); + sdlMsgVersion.setMinorVersion(rpcSepcVersion.getMinor()); + sdlMsgVersion.setPatchVersion(rpcSepcVersion.getPatch()); + return sdlMsgVersion; + } + + return null; + } + + @Override + public @NonNull Version getProtocolVersion() { + if(proxy.getProtocolVersion() != null){ + return proxy.getProtocolVersion(); + }else{ + return new Version(1,0,0); + } + } + + }; + + + // 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 + */ + //FIXME public Builder(@NonNull Context context, @NonNull final String appId, @NonNull final String appName, @NonNull final SdlManagerListener listener){ + public Builder(@NonNull final String appId, @NonNull final String appName, @NonNull final SdlManagerListener listener){ + sdlManager = new SdlManager(); + //FIXME setContext(context); + setAppId(appId); + setAppName(appName); + 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 Language of the App + * @param hmiLanguage + */ + public Builder setLanguage(final Language hmiLanguage){ + sdlManager.hmiLanguage = hmiLanguage; + return this; + } + + /** + * Sets the TemplateColorScheme for daytime + * @param dayColorScheme + */ + public Builder setDayColorScheme(final TemplateColorScheme dayColorScheme){ + sdlManager.dayColorScheme = dayColorScheme; + return this; + } + + /** + * Sets the TemplateColorScheme for nighttime + * @param nightColorScheme + */ + public Builder setNightColorScheme(final TemplateColorScheme nightColorScheme){ + sdlManager.nightColorScheme = nightColorScheme; + 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 + */ + /*FIXME public Builder setLockScreenConfig (final LockScreenConfig lockScreenConfig){ + sdlManager.lockScreenConfig = lockScreenConfig; + return this; + }*/ + + /** + * Sets the icon for the app on HU <br> + * @param sdlArtwork + */ + 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 + */ + public Builder setAppTypes(final Vector<AppHMIType> hmiTypes){ + + sdlManager.hmiTypes = hmiTypes; + + if (hmiTypes != null) { + sdlManager.isMediaApp = hmiTypes.contains(AppHMIType.MEDIA); + } + + return this; + } + + /** + * Sets the vector of vrSynonyms + * @param vrSynonyms + */ + public Builder setVrSynonyms(final Vector<String> vrSynonyms) { + sdlManager.vrSynonyms = vrSynonyms; + return this; + } + + /** + * Sets the TTS Name + * @param ttsChunks + */ + 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 + */ + public Builder setTransportType(BaseTransportConfig transport){ + sdlManager.transport = transport; + return this; + } + + /** + * Sets the Context + * @param context + */ + /* FIXME public Builder setContext(Context context){ + sdlManager.context = context; + return this; + }*/ + + /** + * Sets the Security library + * @param secList The list of security class(es) + */ + public Builder setSdlSecurity(List<Class<? extends SdlSecurityBase>> secList) { + sdlManager.sdlSecList = secList; + return this; + } + + /** + * Set the SdlManager Listener + * @param listener the listener + */ + public Builder setManagerListener(@NonNull final SdlManagerListener listener){ + sdlManager.managerListener = listener; + 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.lockScreenConfig == null){ + // if lock screen params are not set, use default + sdlManager.lockScreenConfig = new LockScreenConfig(); + }*/ + + if (sdlManager.hmiLanguage == null){ + sdlManager.hmiLanguage = Language.EN_US; + } + + sdlManager.transitionToState(BaseSubManager.SETTING_UP); + + return sdlManager; + } + } + +} diff --git a/javaSE/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java b/javaSE/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java new file mode 100644 index 000000000..f3c95045c --- /dev/null +++ b/javaSE/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java @@ -0,0 +1,21 @@ +package com.smartdevicelink.managers; + +public interface SdlManagerListener extends BaseSdlManagerListener { + + /** + * Called when a manager is ready for use + */ + void onStart(SdlManager manager); + + /** + * Called when the manager is destroyed + */ + void onDestroy(SdlManager manager); + + /** + * Called when the manager encounters an error + * @param info info regarding the error + * @param e the exception + */ + void onError(SdlManager manager, String info, Exception e); +} diff --git a/javaSE/src/main/java/com/smartdevicelink/managers/file/FileManager.java b/javaSE/src/main/java/com/smartdevicelink/managers/file/FileManager.java new file mode 100644 index 000000000..5c6317853 --- /dev/null +++ b/javaSE/src/main/java/com/smartdevicelink/managers/file/FileManager.java @@ -0,0 +1,108 @@ +package com.smartdevicelink.managers.file; + + +import android.support.annotation.NonNull; +import com.smartdevicelink.managers.file.filetypes.SdlFile; +import com.smartdevicelink.proxy.interfaces.ISdl; +import com.smartdevicelink.proxy.rpc.PutFile; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +/** + * <strong>FileManager</strong> <br> + * + * Note: This class must be accessed through the SdlManager. Do not instantiate it by itself. <br> + * + * The SDLFileManager uploads files and keeps track of all the uploaded files names during a session. <br> + * + * We need to add the following struct: SDLFile<br> + * + * It is broken down to these areas: <br> + * + * 1. Getters <br> + * 2. Deletion methods <br> + * 3. Uploading Files / Artwork + */ +public class FileManager extends BaseFileManager { + + public FileManager(ISdl internalInterface) { + + // setup + super(internalInterface); + } + + /** + * Creates and returns a PutFile request that would upload a given SdlFile + * @param file SdlFile with fileName and one of A) fileData, B) Uri, or C) resourceID set + * @return a valid PutFile request if SdlFile contained a fileName and sufficient data + */ + @Override + PutFile createPutFile(@NonNull final SdlFile file){ + PutFile putFile = new PutFile(); + if(file.getName() == null){ + throw new IllegalArgumentException("You must specify an file name in the SdlFile"); + }else{ + putFile.setSdlFileName(file.getName()); + } + + if(file.getFilePath() != null){ + //Attempt to access the file via a path + byte[] data = contentsOfFilePath(file.getFilePath()); + if(data != null ){ + putFile.setFileData(data); + }else{ + throw new IllegalArgumentException("File at path was empty"); + } + }else if(file.getFileData() != null){ + // Use file data (raw bytes) to upload file + putFile.setFileData(file.getFileData()); + }else{ + throw new IllegalArgumentException("The SdlFile to upload does " + + "not specify its resourceId, Uri, or file data"); + } + + if(file.getType() != null){ + putFile.setFileType(file.getType()); + } + putFile.setPersistentFile(file.isPersistent()); + + return putFile; + } + + /** + * + * @param filePath + * @return + */ + private byte[] contentsOfFilePath(String filePath){ + File file = new File(filePath); + if(file.isFile() && file.canRead()){ + FileInputStream fileInputStream = null; + byte[] bytesArray = null; + + try { + bytesArray = new byte[(int) file.length()]; + + //read file into bytes[] + fileInputStream = new FileInputStream(file); + fileInputStream.read(bytesArray); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (fileInputStream != null) { + try { + fileInputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + return bytesArray; + } + return null; + } +} diff --git a/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java b/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java new file mode 100644 index 000000000..aa2671689 --- /dev/null +++ b/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java @@ -0,0 +1,83 @@ +package com.smartdevicelink.managers.file.filetypes; + +import android.support.annotation.NonNull; + +import com.smartdevicelink.proxy.rpc.Image; +import com.smartdevicelink.proxy.rpc.enums.FileType; +import com.smartdevicelink.proxy.rpc.enums.ImageType; +import com.smartdevicelink.proxy.rpc.enums.StaticIconName; + +/** + * A class that extends SdlFile, representing artwork (JPEG, PNG, or BMP) to be uploaded to core + */ +public class SdlArtwork extends SdlFile { + private boolean isTemplate; + private Image imageRPC; + + public SdlArtwork(){} + + public SdlArtwork(@NonNull StaticIconName staticIconName) { + super(staticIconName); + } + + public SdlArtwork(@NonNull String fileName, @NonNull FileType fileType, int id, boolean persistentFile) { + super(fileName, fileType, id, persistentFile); + } + + /* FIXME public SdlArtwork(@NonNull String fileName, @NonNull FileType fileType, Uri uri, boolean persistentFile) { + super(fileName, fileType, uri, persistentFile); + }*/ + + + public SdlArtwork(@NonNull String fileName, @NonNull FileType fileType, String filePath, boolean persistentFile) { + super(fileName, fileType, filePath, persistentFile); + } + + public SdlArtwork(@NonNull String fileName, @NonNull FileType fileType, byte[] data, boolean persistentFile) { + super(fileName, fileType, data, persistentFile); + } + + /** + * Set whether this SdlArtwork is a template image whose coloring should be decided by the HMI + * @param isTemplate boolean that tells whether this SdlArtwork is a template image + */ + public void setTemplateImage(boolean isTemplate){ + this.isTemplate = isTemplate; + } + + /** + * Get whether this SdlArtwork is a template image whose coloring should be decided by the HMI + * @return boolean that tells whether this SdlArtwork is a template image + */ + public boolean isTemplateImage(){ + return isTemplate; + } + + + @Override + public void setType(@NonNull FileType fileType) { + if(fileType.equals(FileType.GRAPHIC_JPEG) || fileType.equals(FileType.GRAPHIC_PNG) + || fileType.equals(FileType.GRAPHIC_BMP)){ + super.setType(fileType); + }else{ + throw new IllegalArgumentException("Only JPEG, PNG, and BMP image types are supported."); + } + } + + /** + * Get the Image RPC representing this artwork. Generally for use internally, you should instead pass an artwork to a Screen Manager method. + * @return The Image RPC representing this artwork. + */ + public Image getImageRPC() { + if (imageRPC == null) { + if (isStaticIcon()) { + imageRPC = new Image(getName(), ImageType.STATIC); + imageRPC.setIsTemplate(true); + } else { + imageRPC = new Image(getName(), ImageType.DYNAMIC); + imageRPC.setIsTemplate(isTemplate); + } + } + return imageRPC; + } +}
\ No newline at end of file diff --git a/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java b/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java new file mode 100644 index 000000000..789515c48 --- /dev/null +++ b/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java @@ -0,0 +1,114 @@ +package com.smartdevicelink.managers.file.filetypes; + +import android.support.annotation.NonNull; + +import com.smartdevicelink.proxy.rpc.enums.FileType; +import com.smartdevicelink.proxy.rpc.enums.StaticIconName; + +/** + * A class representing data to be uploaded to core + */ +public class SdlFile{ + private String fileName; + private int id = -1; + //FIXME private Uri uri; + private String filePath; + private byte[] fileData; + private FileType fileType; + private boolean persistentFile; + private boolean isStaticIcon; + + public SdlFile(){} + + public SdlFile(@NonNull StaticIconName staticIconName){ + this.fileName = staticIconName.toString(); + this.fileData = staticIconName.toString().getBytes(); + this.persistentFile = false; + this.isStaticIcon = true; + } + + public SdlFile(@NonNull String fileName, @NonNull FileType fileType, int id, boolean persistentFile){ + this.fileName = fileName; + this.fileType = fileType; + this.id = id; + this.persistentFile = persistentFile; + } + + /*public SdlFile(@NonNull String fileName, @NonNull FileType fileType, Uri uri, boolean persistentFile){ + this.fileName = fileName; + this.fileType = fileType; + this.uri = uri; + this.persistentFile = persistentFile; + }*/ + + public SdlFile(@NonNull String fileName, @NonNull FileType fileType, byte[] data, boolean persistentFile){ + this.fileName = fileName; + this.fileType = fileType; + this.fileData = data; + this.persistentFile = persistentFile; + } + + public SdlFile(@NonNull String fileName, @NonNull FileType fileType, String filePath, boolean persistentFile){ + this.fileName = fileName; + this.fileType = fileType; + this.filePath = filePath; + this.persistentFile = persistentFile; + } + + public void setName(@NonNull String fileName){ + this.fileName = fileName; + } + public String getName(){ + return fileName; + } + + public void setResourceId(int id){ + this.id = id; + } + public int getResourceId(){ + return id; + } + + /* FIXME public void setUri(Uri uri){ + this.uri = uri; + } + public Uri getUri(){ + return uri; + }*/ + + public void setFilePath(String filePath){ + this.filePath = filePath; + } + + public String getFilePath(){ + return this.filePath; + } + + public void setFileData(byte[] data){ + this.fileData = data; + } + public byte[] getFileData(){ + return fileData; + } + + public void setType(@NonNull FileType fileType){ + this.fileType = fileType; + } + public FileType getType(){ + return fileType; + } + + public void setPersistent(boolean persistentFile){ + this.persistentFile = persistentFile; + } + public boolean isPersistent(){ + return this.persistentFile; + } + + public void setStaticIcon(boolean staticIcon) { + isStaticIcon = staticIcon; + } + public boolean isStaticIcon() { + return isStaticIcon; + } +}
\ No newline at end of file diff --git a/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java b/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java new file mode 100644 index 000000000..81933e588 --- /dev/null +++ b/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java @@ -0,0 +1,1182 @@ +package com.smartdevicelink.managers.lifecycle; + +import android.support.annotation.NonNull; +import android.util.Log; +import com.smartdevicelink.SdlConnection.SdlSession; +import com.smartdevicelink.exception.SdlException; +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.*; +import com.smartdevicelink.proxy.callbacks.OnServiceEnded; +import com.smartdevicelink.proxy.callbacks.OnServiceNACKed; +import com.smartdevicelink.proxy.interfaces.*; +import com.smartdevicelink.proxy.rpc.*; +import com.smartdevicelink.proxy.rpc.enums.*; +import com.smartdevicelink.proxy.rpc.listeners.*; +import com.smartdevicelink.security.SdlSecurityBase; +import com.smartdevicelink.streaming.StreamRPCPacketizer; +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.WebSocketServerConfig; +import com.smartdevicelink.util.CorrelationIdGenerator; +import com.smartdevicelink.util.DebugTool; +import com.smartdevicelink.util.Version; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Vector; +import java.util.concurrent.CopyOnWriteArrayList; + +public class LifecycleManager extends BaseLifecycleManager { + + private static final String TAG = "Lifecycle Manager"; + + public static final Version MAX_SUPPORTED_RPC_VERSION = new Version("5.0.0"); + + // Protected Correlation IDs + private final int REGISTER_APP_INTERFACE_CORRELATION_ID = 65529; + + + // Sdl Synchronization Objects + private static final Object RPC_LISTENER_LOCK = new Object(), + ON_UPDATE_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; + + //FIXME these were sparse arrays in android + protected final HashMap<Integer,CopyOnWriteArrayList<OnRPCListener>> rpcListeners; + protected final HashMap<Integer, OnRPCResponseListener> rpcResponseListeners; + protected final HashMap<Integer, CopyOnWriteArrayList<OnRPCNotificationListener>> rpcNotificationListeners; + + protected final SystemCapabilityManager systemCapabilityManager; + + protected RegisterAppInterfaceResponse raiResponse = null; + + private OnHMIStatus currentHMIStatus; + protected boolean firstTimeFull = true; + + final LifecycleListener lifecycleListener; + + private List<Class<? extends SdlSecurityBase>> _secList = null; + + + public LifecycleManager(AppConfig appConfig, WebSocketServerConfig config, LifecycleListener listener){ + + this.lifecycleListener = listener; + + this.rpcListeners = new HashMap<>(); + this.rpcResponseListeners = new HashMap<>(); + this.rpcNotificationListeners = new HashMap<>(); + + this.appConfig = appConfig; + this.session = new SdlSession(this, config); + + this.systemCapabilityManager = new SystemCapabilityManager(internalInterface); + + + } + + public void start(){ + try { + setupInternalRpcListeners(); + session.startSession(); + } catch (SdlException e) { + e.printStackTrace(); + } + + } + + public void stop(){ + //TODO stop + } + + public Version getProtocolVersion(){ + if (session != null){ + return session.getProtocolVersion(); + } + return new Version(1,0,0); + } + public Version getRpcSepcVersion(){ + return rpcSpecVersion; + } + + public void sendRpc(RPCMessage message){ + this.sendRPCMessagePrivate(message); + } + + public void sendRpcs(List<? extends RPCMessage> messages, OnMultipleRequestListener listener){ + if(messages != null ){ + for(RPCMessage message : messages){ + if(message instanceof RPCRequest){ + RPCRequest request = ((RPCRequest) message); + request.setCorrelationID(CorrelationIdGenerator.generateId()); + if(listener != null){ + listener.addCorrelationId(request.getCorrelationID()); + request.setOnRPCResponseListener(listener.getSingleRpcResponseListener()); + } + this.sendRPCMessagePrivate(request); + + }else{ + this.sendRPCMessagePrivate(message); + } + } + } + } + + //Sequentially + public void sendRpcsSequentially(List<? extends RPCMessage> messages, OnMultipleRequestListener listener){ + //FIXME yea + sendRpcs(messages, listener); + } + + public SystemCapabilityManager getSystemCapabilityManager(){ + return systemCapabilityManager; + } + + public 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); + } + } + + + /* ******************************************************************************************************* + ********************************** 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; + } + 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: + 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(); + } + break; + case ON_APP_INTERFACE_UNREGISTERED: + Log.v(TAG, "on app interface unregistered"); + cleanProxy(); + break; + case UNREGISTER_APP_INTERFACE: + Log.v(TAG, "unregister app interface"); + cleanProxy(); + break; + } + } + } + + + + }; + + /* ******************************************************************************************************* + ********************************** INTERNAL - RPC LISTENERS !! END !! ********************************* + *********************************************************************************************************/ + + + /* ******************************************************************************************************* + ********************************** METHODS - RPC LISTENERS !! START !! ********************************** + *********************************************************************************************************/ + + public 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; + } + } + + //FIXME check if we need this to be public + public 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); + } + } + } + + public 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") + public 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. + */ + public 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") + public HashMap<Integer, OnRPCResponseListener> getResponseListeners(){ + synchronized(ON_UPDATE_LISTENER_LOCK){ + return this.rpcResponseListeners; + } + } + + @SuppressWarnings("UnusedReturnValue") + public 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 ad 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") + public 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); + } + } + } + + /** + * This method is no longer valid and will not remove the listener for the supplied notificaiton id + * @param notificationId n/a + * @see #removeOnRPCNotificationListener(FunctionID, OnRPCNotificationListener) + */ + @SuppressWarnings("unused") + @Deprecated + public void removeOnRPCNotificationListener(FunctionID notificationId){ + synchronized(ON_NOTIFICATION_LISTENER_LOCK){ + //rpcNotificationListeners.delete(notificationId.getId()); + } + } + + public 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; + } + + + + /* ******************************************************************************************************* + **************************************** RPC LISTENERS !! END !! **************************************** + *********************************************************************************************************/ + + + + //FIXME move to SdlSession + private void sendRPCMessagePrivate(RPCMessage message){ + try { + + message.format(rpcSpecVersion,true); + byte[] msgBytes = JsonRPCMarshaller.marshall(message, (byte)getProtocolVersion().getMajor()); + + 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())); + pm.setPayloadProtected(message.isPayloadProtected()); + if(RPCMessage.KEY_REQUEST.equals(message.getMessageType())){ + Integer corrId = ((RPCRequest)message).getCorrelationID(); + if( corrId== null) { + + //FIXME Log error here + //throw new SdlException("CorrelationID cannot be null. RPC: " + message.getFunctionName(), SdlExceptionCause.INVALID_ARGUMENT); + Log.e(TAG, "No correlation ID attatched to request. Not sending"); + }else{ + pm.setCorrID(corrId); + + OnRPCResponseListener listener = ((RPCRequest)message).getOnRPCResponseListener(); + if(listener != null){ + addOnRPCResponseListener(listener, corrId, msgBytes.length); + } + } + } + + 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 ************************************ + *********************************************************************************************************/ + + + @Override + public void onTransportDisconnected(String info) { + 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); + + FunctionID functionID = rpc.getFunctionID(); + if (functionID != null && (functionID.equals(FunctionID.ON_BUTTON_PRESS.toString()) || functionID.equals(FunctionID.ON_BUTTON_EVENT.toString())) ) { + rpc = handleButtonNotificationFormatting(rpc); + } + + onRPCReceived(rpc); + + if(RPCMessage.KEY_RESPONSE.equals(messageType)){ + + onRPCResponseReceived((RPCResponse)rpc); + + }else if(RPCMessage.KEY_NOTIFICATION.equals(messageType)){ + + onRPCNotificationReceived((RPCNotification)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 (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.appName,appConfig.isMediaApp, appConfig.languageDesired, + appConfig.hmiDisplayLanguageDesired,appConfig.appID); + rai.setCorrelationID(REGISTER_APP_INTERFACE_CORRELATION_ID); + + rai.setTtsName(appConfig.ttsName); + rai.setNgnMediaScreenAppName(appConfig.ngnMediaScreenAppName); + rai.setVrSynonyms(appConfig.vrSynonyms); + rai.setAppHMIType(appConfig.appType); + rai.setDayColorScheme(appConfig.dayColorScheme); + rai.setNightColorScheme(appConfig.nightColorScheme); + + //TODO Previous versions have set device info + //TODO attach previous hash id + + sendRPCMessagePrivate(rai); + }else{ + Log.e(TAG, "App config was null, soo..."); + } + + + } else if (sessionType.eq(SessionType.NAV)) { + //FIXME NavServiceStarted(); + } else if (sessionType.eq(SessionType.PCM)) { + //FIXME AudioServiceStarted(); + } + + } + } + + @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) { + //FIXME + } + + @Override + public void onHeartbeatTimedOut(byte sessionID) { + //FIXME + } + + @Override + public void onProtocolServiceDataACK(SessionType sessionType, int dataSize, byte sessionID) { + + } + + /* ******************************************************************************************************* + *************************************** 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) { + + } + + @Override + public void removeServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener) { + + } + + @Override + public void startVideoService(VideoStreamingParameters parameters, boolean encrypted) { + + } + + @Override + public void stopVideoService() { + + } + + @Override + public IVideoStreamListener startVideoStream(boolean isEncrypted, VideoStreamingParameters parameters) { + return null; + } + + @Override + public void startAudioService(boolean encrypted, AudioStreamingCodec codec, AudioStreamingParams params) { + + } + + @Override + public void startAudioService(boolean encrypted) { + + } + + @Override + public void stopAudioService() { + + } + + @Override + public IAudioStreamListener startAudioStream(boolean isEncrypted, AudioStreamingCodec codec, AudioStreamingParams params) { + return null; + } + + @Override + public void sendRPCRequest(RPCRequest message) { + LifecycleManager.this.sendRPCMessagePrivate(message); + + } + + @Override + public void sendRequests(List<? extends RPCRequest> rpcs, OnMultipleRequestListener listener) { + //FIXME + } + + @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 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) { + return LifecycleManager.this.systemCapabilityManager.getCapability(systemCapabilityType); + } + + @Override + public void getCapability(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener scListener) { + LifecycleManager.this.systemCapabilityManager.getCapability(systemCapabilityType,scListener); + + } + + @Override + public boolean isCapabilitySupported(SystemCapabilityType systemCapabilityType) { + return LifecycleManager.this.systemCapabilityManager.isCapabilitySupported(systemCapabilityType); + } + + @Override + public void addOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) { + LifecycleManager.this.systemCapabilityManager.addOnSystemCapabilityListener(systemCapabilityType,listener); + + } + + @Override + public boolean removeOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) { + return LifecycleManager.this.systemCapabilityManager.removeOnSystemCapabilityListener(systemCapabilityType,listener); + } + + @Override + public boolean isTransportForServiceAvailable(SessionType serviceType) { + return LifecycleManager.this.session.isTransportForServiceAvailable(serviceType); + } + + @Override + public SdlMsgVersion getSdlMsgVersion() { + return null; //FIXME should probably be rpc spec version + } + + @Override + public Version getProtocolVersion() { + return LifecycleManager.this.getProtocolVersion(); + } + }; + + /* ******************************************************************************************************* + ********************************************* ISdl - END ************************************************ + *********************************************************************************************************/ + + public interface LifecycleListener{ + void onProxyConnected(LifecycleManager lifeCycleManager); + void onProxyClosed(LifecycleManager lifeCycleManager, String info, Exception e, SdlDisconnectedReason reason); + void onServiceEnded(LifecycleManager lifeCycleManager, OnServiceEnded serviceEnded); + void onServiceNACKed(LifecycleManager lifeCycleManager, OnServiceNACKed serviceNACKed); + void onError(LifecycleManager lifeCycleManager, String info, Exception e); + } + + public static class AppConfig{ + //FIXME change these from public + public String appID, appName, ngnMediaScreenAppName; + public Vector<TTSChunk> ttsName; + public Vector<String> vrSynonyms; + public boolean isMediaApp = false; + public Language languageDesired, hmiDisplayLanguageDesired; + public Vector<AppHMIType> appType; + public TemplateColorScheme dayColorScheme, nightColorScheme; + + private void prepare(){ + if (ngnMediaScreenAppName == null) { + ngnMediaScreenAppName = appName; + } + + if (languageDesired == null) { + languageDesired = Language.EN_US; + } + + if (hmiDisplayLanguageDesired == null) { + hmiDisplayLanguageDesired = Language.EN_US; + } + + if (vrSynonyms == null) { + vrSynonyms = new Vector<>(); + vrSynonyms.add(appName); + } + } + } + + + //FIXME + /** + * 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 + */ + 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 (session != null && session.getIsConnected()) { + session.close(); + } + } + + public void setSdlSecurityClassList(List<Class<? extends SdlSecurityBase>> list) { + _secList = list; + } + + 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.appID); + if (session != null) { + session.setSdlSecurity(sec); + sec.handleSdlSession(session); + } + return; + } + } + } + } + + + /* ******************************************************************************************************* + ************************************* FileStream Methods - START **************************************** + *********************************************************************************************************/ + + /** + * Used to push a binary stream of file data onto the module from a mobile device. + * + * @param inputStream The input stream of byte data that will be read from. + * @param fileName The SDL file reference name used by the RPC. + * @param offset The data offset in bytes. A value of zero is used to + * indicate data starting from the beginning of the file and a value greater + * than zero is used for resuming partial data chunks. + * @param length The total length of the file being sent. + */ + public void putFileStream(InputStream inputStream, @NonNull String fileName, Long offset, Long length) { + PutFile msg = new PutFile(fileName, FileType.BINARY); + msg.setCorrelationID(10000); + msg.setSystemFile(true); + msg.setOffset(offset); + msg.setLength(length); + + startRPCStream(inputStream, msg); + } + + /** + * Used to push a binary stream of file data onto the module from a mobile device. + * + * @param inputStream The input stream of byte data that will be read from. + * @param fileName The SDL file reference name used by the RPC. + * @param offset The data offset in bytes. A value of zero is used to + * indicate data starting from the beginning of the file and a value greater + * than zero is used for resuming partial data chunks. + * @param length The total length of the file being sent. + * @param fileType The selected file type. See the {@link FileType} enum for + * details. + * @param isPersistentFile Indicates if the file is meant to persist between + * sessions / ignition cycles. + * @param isSystemFile Indicates if the file is meant to be passed through + * core to elsewhere in the system. + */ + public void putFileStream(InputStream inputStream, @NonNull String fileName, Long offset, Long length, FileType fileType, Boolean isPersistentFile, Boolean isSystemFile, OnPutFileUpdateListener cb) { + PutFile msg = new PutFile(fileName, FileType.BINARY); + msg.setCorrelationID(10000); + msg.setSystemFile(true); + msg.setOffset(offset); + msg.setLength(length); + msg.setOnPutFileUpdateListener(cb); + startRPCStream(inputStream, msg); + } + + + /** + * Used to push a binary stream of file data onto the module from a mobile device. + * + * @param fileName The SDL file reference name used by the RPC. + * @param offset The data offset in bytes. A value of zero is used to + * indicate data starting from the beginning of the file and a value greater + * than zero is used for resuming partial data chunks. + * @param length The total length of the file being sent. + */ + public OutputStream putFileStream(@NonNull String fileName, Long offset, Long length) { + PutFile msg = new PutFile(fileName, FileType.BINARY); + msg.setCorrelationID(10000); + msg.setSystemFile(true); + msg.setOffset(offset); + msg.setLength(length); + + return startRPCStream(msg); + } + + /** + * Used to push a binary stream of file data onto the module from a mobile device. + * + * @param fileName The SDL file reference name used by the RPC. + * @param offset The data offset in bytes. A value of zero is used to + * indicate data starting from the beginning of the file and a value greater + * than zero is used for resuming partial data chunks. + * @param length The total length of the file being sent. + * @param fileType The selected file type. See the {@link FileType} enum for + * details. + * @param isPersistentFile Indicates if the file is meant to persist between + * sessions / ignition cycles. + * @param isSystemFile Indicates if the file is meant to be passed through + * core to elsewhere in the system. + */ + public OutputStream putFileStream(@NonNull String fileName, Long offset, Long length, FileType fileType, Boolean isPersistentFile, Boolean isSystemFile, OnPutFileUpdateListener cb) { + PutFile msg = new PutFile(fileName, FileType.BINARY); + msg.setCorrelationID(10000); + msg.setSystemFile(true); + msg.setOffset(offset); + msg.setLength(length); + msg.setOnPutFileUpdateListener(cb); + + return startRPCStream(msg); + } + + /** + * Used to push a binary stream of file data onto the module from a mobile device. + * + * @param path The physical file path on the mobile device. + * @param fileName The SDL file reference name used by the RPC. + * @param offset The data offset in bytes. A value of zero is used to + * indicate data starting from the beginning of the file and a value greater + * than zero is used for resuming partial data chunks. + * @param fileType The selected file type. See the {@link FileType} enum for + * details. + * @param isPersistentFile Indicates if the file is meant to persist between + * sessions / ignition cycles. + * @param isSystemFile Indicates if the file is meant to be passed through + * core to elsewhere in the system. + * @param correlationId A unique id that correlates each RPCRequest and + * RPCResponse. + * @return RPCStreamController If the putFileStream was not started + * successfully null is returned, otherwise a valid object reference is + * returned . + */ + public RPCStreamController putFileStream(String path, @NonNull String fileName, Long offset, @NonNull FileType fileType, Boolean isPersistentFile, Boolean isSystemFile, Boolean isPayloadProtected, Integer correlationId, OnPutFileUpdateListener cb) { + PutFile msg = new PutFile(fileName, fileType); + msg.setCorrelationID(correlationId); + msg.setPersistentFile(isPersistentFile); + msg.setSystemFile(isSystemFile); + msg.setOffset(offset); + msg.setLength(0L); + msg.setPayloadProtected(isPayloadProtected); + msg.setOnPutFileUpdateListener(cb); + + if (session == null) return null; + + FileInputStream is = null; + try { + is = new FileInputStream(path); + } catch (IOException e1) { + e1.printStackTrace(); + } + + + if (is == null) return null; + + Long lSize = null; + + try { + lSize = is.getChannel().size(); + } catch (IOException e) { + e.printStackTrace(); + } + + if (lSize == null) { + try { + is.close(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + try { + StreamRPCPacketizer rpcPacketizer = new StreamRPCPacketizer(this, session, is, msg, SessionType.RPC, session.getSessionId(), getProtocolVersion(), rpcSpecVersion, lSize, session); + rpcPacketizer.start(); + return new RPCStreamController(rpcPacketizer, msg.getCorrelationID()); + } catch (Exception e) { + Log.e("SyncConnection", "Unable to start streaming:" + e.toString()); + return null; + } + } + + /** + * Used to push a binary stream of file data onto the module from a mobile device. + * + * @param inputStream The input stream of byte data that will be read from. + * @param fileName The SDL file reference name used by the RPC. + * @param offset The data offset in bytes. A value of zero is used to + * indicate data starting from the beginning of the file and a value greater + * than zero is used for resuming partial data chunks. + * @param length The total length of the file being sent. + * @param fileType The selected file type. See the {@link FileType} enum for + * details. + * @param isPersistentFile Indicates if the file is meant to persist between + * sessions / ignition cycles. + * @param isSystemFile Indicates if the file is meant to be passed through + * core to elsewhere in the system. + * @param correlationId A unique id that correlates each RPCRequest and + * RPCResponse. + */ + public RPCStreamController putFileStream(InputStream inputStream, @NonNull String fileName, Long offset, Long length, @NonNull FileType fileType, Boolean isPersistentFile, Boolean isSystemFile, Boolean isPayloadProtected, Integer correlationId) { + PutFile msg = new PutFile(fileName, fileType); + msg.setCorrelationID(correlationId); + msg.setPersistentFile(isPersistentFile); + msg.setSystemFile(isSystemFile); + msg.setOffset(offset); + msg.setLength(length); + msg.setPayloadProtected(isPayloadProtected); + + if (session == null) return null; + Long lSize = msg.getLength(); + + if (lSize == null) { + return null; + } + + try { + StreamRPCPacketizer rpcPacketizer = new StreamRPCPacketizer(this, session, inputStream, msg, SessionType.RPC, session.getSessionId(), getProtocolVersion(), rpcSpecVersion, lSize, session); + rpcPacketizer.start(); + return new RPCStreamController(rpcPacketizer, msg.getCorrelationID()); + } catch (Exception e) { + Log.e("SyncConnection", "Unable to start streaming:" + e.toString()); + return null; + } + } + + /** + * Used to end an existing putFileStream that was previously initiated with any putFileStream method. + */ + public void endPutFileStream() { + endRPCStream(); + } + + public void endRPCStream() { + if (this.session == null) return; + session.stopRPCStream(); + } + + public boolean startRPCStream(InputStream is, RPCRequest msg) { + if (session == null) return false; + session.startRPCStream(is, msg, SessionType.RPC, session.getSessionId(), (byte) getProtocolVersion().getMajor()); + return true; + } + + public OutputStream startRPCStream(RPCRequest msg) { + if (session == null) return null; + return session.startRPCStream(msg, SessionType.RPC, session.getSessionId(), (byte) getProtocolVersion().getMajor()); + } + + /* ******************************************************************************************************* + ************************************** FileStream Methods - END ***************************************** + *********************************************************************************************************/ + +} diff --git a/javaSE/src/main/java/com/smartdevicelink/managers/permission/PermissionManager.java b/javaSE/src/main/java/com/smartdevicelink/managers/permission/PermissionManager.java new file mode 100644 index 000000000..127aaf0dc --- /dev/null +++ b/javaSE/src/main/java/com/smartdevicelink/managers/permission/PermissionManager.java @@ -0,0 +1,24 @@ +package com.smartdevicelink.managers.permission; + +import android.support.annotation.NonNull; +import com.smartdevicelink.proxy.interfaces.ISdl; + +/** + PermissionManager gives the developer information about what permissions are permitted in specific HMI level + and helps developers setup listeners to be called when specific permissions become allowed.<br> + + This should be used through the {@link com.smartdevicelink.managers.SdlManager} and not be instantiated by itself +**/ + + public class PermissionManager extends BasePermissionManager{ + + + /** + * Creates a new instance of the PermissionManager + * + * @param internalInterface + */ + public PermissionManager(@NonNull ISdl internalInterface) { + super(internalInterface); + } +} diff --git a/javaSE/src/main/java/com/smartdevicelink/managers/screen/ScreenManager.java b/javaSE/src/main/java/com/smartdevicelink/managers/screen/ScreenManager.java new file mode 100644 index 000000000..42e838cd1 --- /dev/null +++ b/javaSE/src/main/java/com/smartdevicelink/managers/screen/ScreenManager.java @@ -0,0 +1,18 @@ +package com.smartdevicelink.managers.screen; + +import android.support.annotation.NonNull; + +import com.smartdevicelink.managers.file.FileManager; +import com.smartdevicelink.proxy.interfaces.ISdl; + +/** + * <strong>ScreenManager</strong> <br> + * + * Note: This class must be accessed through the SdlManager. Do not instantiate it by itself. <br> +*/ +public class ScreenManager extends BaseScreenManager { + + public ScreenManager(@NonNull ISdl internalInterface, @NonNull FileManager fileManager) { + super(internalInterface, fileManager); + } +} diff --git a/javaSE/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java b/javaSE/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java new file mode 100644 index 000000000..23cca49ea --- /dev/null +++ b/javaSE/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java @@ -0,0 +1,24 @@ +package com.smartdevicelink.managers.screen; + +import android.support.annotation.NonNull; + +import com.smartdevicelink.managers.file.FileManager; +import com.smartdevicelink.proxy.interfaces.ISdl; + +/** + * <strong>SoftButtonManager</strong> <br> + * SoftButtonManager gives the developer the ability to control how soft buttons are displayed on the head unit.<br> + * Note: This class must be accessed through the SdlManager->ScreenManager. Do not instantiate it by itself.<br> + */ +class SoftButtonManager extends BaseSoftButtonManager { + + /** + * Creates a new instance of the SoftButtonManager + * + * @param internalInterface + * @param fileManager + */ + SoftButtonManager(@NonNull ISdl internalInterface, @NonNull FileManager fileManager) { + super(internalInterface, fileManager); + } +} diff --git a/javaSE/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java b/javaSE/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java new file mode 100644 index 000000000..c7e9e0965 --- /dev/null +++ b/javaSE/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java @@ -0,0 +1,32 @@ +package com.smartdevicelink.managers.screen; + +import android.support.annotation.NonNull; +import com.smartdevicelink.managers.file.FileManager; +import com.smartdevicelink.managers.file.filetypes.SdlArtwork; +import com.smartdevicelink.proxy.interfaces.ISdl; +import com.smartdevicelink.proxy.rpc.enums.FileType; + +/** + * <strong>TextAndGraphicManager</strong> <br> + * + * Note: This class must be accessed through the SdlManager. Do not instantiate it by itself. <br> + * + */ +class TextAndGraphicManager extends BaseTextAndGraphicManager { + + TextAndGraphicManager(@NonNull ISdl internalInterface, @NonNull FileManager fileManager, @NonNull SoftButtonManager softButtonManager) { + super(internalInterface, fileManager, softButtonManager); + } + + @Override + SdlArtwork getBlankArtwork(){ + if (blankArtwork == null){ + blankArtwork = new SdlArtwork(); + blankArtwork.setType(FileType.GRAPHIC_PNG); + blankArtwork.setName("blankArtwork"); + blankArtwork.setFileData(new byte[50]); + //FIXME blankArtwork.setResourceId(R.drawable.transparent); + } + return blankArtwork; + } +} diff --git a/javaSE/src/main/java/com/smartdevicelink/security/SdlSecurityBase.java b/javaSE/src/main/java/com/smartdevicelink/security/SdlSecurityBase.java new file mode 100644 index 000000000..3d5460aaa --- /dev/null +++ b/javaSE/src/main/java/com/smartdevicelink/security/SdlSecurityBase.java @@ -0,0 +1,5 @@ +package com.smartdevicelink.security;
+
+public abstract class SdlSecurityBase extends BaseSdlSecurityBase{
+
+}
diff --git a/javaSE/src/main/java/hello_sdl/Main.java b/javaSE/src/main/java/hello_sdl/Main.java new file mode 100644 index 000000000..0abcf803d --- /dev/null +++ b/javaSE/src/main/java/hello_sdl/Main.java @@ -0,0 +1,186 @@ +package hello_sdl; + +import android.util.Log; +import com.smartdevicelink.managers.SdlManager; +import com.smartdevicelink.managers.SdlManagerListener; +import com.smartdevicelink.managers.lifecycle.LifecycleManager; +import com.smartdevicelink.marshal.JsonRPCMarshaller; +import com.smartdevicelink.protocol.enums.FunctionID; +import com.smartdevicelink.proxy.RPCNotification; +import com.smartdevicelink.proxy.callbacks.OnServiceEnded; +import com.smartdevicelink.proxy.callbacks.OnServiceNACKed; +import com.smartdevicelink.proxy.rpc.*; +import com.smartdevicelink.proxy.rpc.enums.HMILevel; +import com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason; +import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener; +import com.smartdevicelink.transport.WebSocketServerConfig; +import com.smartdevicelink.util.Version; +import org.json.JSONException; +import org.json.JSONObject; + +public class Main { + + private static final String TAG = "hello_sdl.Main"; + + public static void main(String[] args) { + // testRAIString(); + startSdl(); + } + + public static void testRAI(){ + + + SdlMsgVersion sdlMsgVersion = new SdlMsgVersion(); + sdlMsgVersion.setMajorVersion(5); + sdlMsgVersion.setMinorVersion(0); + sdlMsgVersion.setPatchVersion(0); + + RegisterAppInterface rai = new RegisterAppInterface(sdlMsgVersion, + "AppName",false, null, + null,"78srtv78vt789vs29"); + + rai.setCorrelationID(65529); + + rai.format(new Version(5,0,0),true); + + byte[] msgBytes = JsonRPCMarshaller.marshall(rai, (byte)4); + } + + public static void testRAIString(){ + + String rawRai = "{\r\n \"request\":{\r\n \"name\":\"RegisterAppInterface\",\r\n \"correlationID\":141,\r\n \"parameters\":{\r\n \"ttsName\":[\r\n {\r\n \"text\":\"Phrase 1\",\r\n \"type\":\"TEXT\"\r\n },\r\n {\r\n \"text\":\"Phrase 2\",\r\n \"type\":\"TEXT\"\r\n }\r\n ],\r\n \"hmiDisplayLanguageDesired\":\"EN-US\",\r\n \"appHMIType\":[\r\n \"SOCIAL\",\r\n \"MEDIA\"\r\n ],\r\n \"appID\":\"t4weGRSWY\",\r\n \"languageDesired\":\"PT-BR\",\r\n \"deviceInfo\":{\r\n \"hardware\":\"My Hardware\",\r\n \"firmwareRev\":\"My Firmware Revision\",\r\n \"os\":\"Windows\",\r\n \"osVersion\":\"95\",\r\n \"carrier\":\"nobody\",\r\n \"maxNumberRFCOMMPorts\":2\r\n },\r\n \"appName\":\"Dumb app\",\r\n \"ngnMediaScreenAppName\":\"DA\",\r\n \"isMediaApplication\":true,\r\n \"vrSynonyms\":[\r\n \"dumb\",\r\n \"really dumb app\"\r\n ],\r\n \"syncMsgVersion\":{\r\n \"majorVersion\":3,\r\n \"minorVersion\":64\r\n },\r\n \"hashID\":\"y534htz\"\r\n }\r\n },\r\n \"response\":{\r\n \"name\":\"RegisterAppInterfaceResponse\",\r\n \"correlationID\":142,\r\n \"parameters\":{\r\n \"vehicleType\":{\r\n \"make\":\"Chrysler\",\r\n \"model\":\"Crossfire\",\r\n \"modelYear\":\"1820\",\r\n \"trim\":\"Gold\"\r\n },\r\n \"speechCapabilities\":[\r\n \"SAPI_PHONEMES\",\r\n \"TEXT\",\r\n \"PRE_RECORDED\"\r\n ],\r\n \"vrCapabilities\":[\r\n \"Text\"\r\n ],\r\n \"audioPassThruCapabilities\":[\r\n {\r\n \"samplingRate\":\"16KHZ\",\r\n \"audioType\":\"PCM\",\r\n \"bitsPerSample\":\"16_BIT\"\r\n },\r\n {\r\n \"samplingRate\":\"44KHZ\",\r\n \"audioType\":\"PCM\",\r\n \"bitsPerSample\":\"8_BIT\"\r\n }\r\n ],\r\n \"hmiZoneCapabilities\":[\r\n \"FRONT\",\r\n \"BACK\"\r\n ],\r\n \"prerecordedSpeech\":[\r\n \"HELP_JINGLE\",\r\n \"LISTEN_JINGLE\",\r\n \"NEGATIVE_JINGLE\"\r\n ],\r\n \"supportedDiagModes\":[\r\n 324,\r\n 2356,\r\n 865,\r\n 211,\r\n 8098\r\n ],\r\n \"syncMsgVersion\":{\r\n \"majorVersion\":3,\r\n \"minorVersion\":64\r\n },\r\n \"language\":\"EN-US\",\r\n \"buttonCapabilities\":[\r\n {\r\n \"name\":\"SEEKRIGHT\",\r\n \"shortPressAvailable\":true,\r\n \"longPressAvailable\":false,\r\n \"upDownAvailable\":true\r\n },\r\n {\r\n \"name\":\"TUNEDOWN\",\r\n \"shortPressAvailable\":false,\r\n \"longPressAvailable\":true,\r\n \"upDownAvailable\":false\r\n }\r\n ],\r\n \"displayCapabilities\":{\r\n \"displayType\":\"TYPE2\",\r\n \"mediaClockFormats\":[\r\n \"CLOCKTEXT3\",\r\n \"CLOCK1\"\r\n ],\r\n \"textFields\":[\r\n {\r\n \"width\":480,\r\n \"characterSet\":\"TYPE5SET\",\r\n \"rows\":360,\r\n \"name\":\"alertText2\"\r\n },\r\n {\r\n \"width\":1980,\r\n \"characterSet\":\"CID2SET\",\r\n \"rows\":960,\r\n \"name\":\"scrollableMessageBody\"\r\n },\r\n ],\r\n \"imageFields\":[\r\n {\r\n \"imageTypeSupported\":[\r\n \"GRAPHIC_JPEG\",\r\n \"AUDIO_AAC\"\r\n ],\r\n \"imageResolution\":{\r\n \"resolutionWidth\":640,\r\n \"resolutionHeight\":480\r\n },\r\n \"name\":\"menuIcon\"\r\n },\r\n {\r\n \"imageTypeSupported\":[\r\n \"BINARY\",\r\n \"AUDIO_WAVE\"\r\n ],\r\n \"imageResolution\":{\r\n \"resolutionWidth\":320,\r\n \"resolutionHeight\":240\r\n },\r\n \"name\":\"graphic\"\r\n }\r\n ],\r\n \"graphicSupported\":true,\r\n \"screenParams\":{\r\n \"resolution\":{\r\n \"resolutionWidth\":1200,\r\n \"resolutionHeight\":800\r\n },\r\n \"touchEventAvailable\":{\r\n \"pressAvailable\":true,\r\n \"multiTouchAvailable\":false,\r\n \"doublePressAvailable\":true\r\n }\r\n },\r\n \"templatesAvailable\":[\r\n \"Template 1\",\r\n \"Template 2\",\r\n \"Template 3\"\r\n ],\r\n \"numCustomPresetsAvailable\":5\r\n },\r\n \"hmiDisplayLanguage\":\"ES-ES\",\r\n \"softButtonCapabilities\":[\r\n {\r\n \"imageSupported\":false,\r\n \"shortPressAvailable\":true,\r\n \"longPressAvailable\":false,\r\n \"upDownAvailable\":true\r\n },\r\n {\r\n \"imageSupported\":true,\r\n \"shortPressAvailable\":false,\r\n \"longPressAvailable\":true,\r\n \"upDownAvailable\":false\r\n }\r\n ],\r\n \"presetBankCapabilities\":{\r\n \"OnScreenPresetsAvailable\":false\r\n },\r\n \"bulkData\":[\r\n 0,\r\n 1,\r\n 2\r\n ]\r\n }\r\n }\r\n}"; + System.out.print(rawRai); + System.out.print("\n"); + + try { + JSONObject jsonObject = new JSONObject(rawRai); + if(jsonObject != null){ + System.out.print("The package was accepted"); + + }else{ + System.out.print("The system is down"); + } + } catch (JSONException e) { + e.printStackTrace(); + } + + } + public static void attemptSdlManager(){ + SdlManager.Builder builder = new SdlManager.Builder("234523452345234", "JavaChip", new SdlManagerListener() { + @Override + public void onStart(SdlManager manager) { + Log.i(TAG, "OnStart"); + manager.addOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, new OnRPCNotificationListener() { + @Override + public void onNotified(RPCNotification notification) { + Log.i(TAG, "on notified"); + OnHMIStatus hmiStatus = (OnHMIStatus)notification; + if(HMILevel.HMI_FULL.equals(hmiStatus.getHmiLevel())) { + if (hmiStatus.getFirstRun()) { + //TOD DO a show + Show show = new Show(); + show.setMainField1("There's snake in my boots"); + show.setMainField2("YEET THAT SUCKER!"); + manager.sendRPC(show); + Log.i(TAG, "Attempting sending show"); + + + } + } + } + }); + } + + @Override + public void onDestroy(SdlManager manager) { + Log.i(TAG, "onDestroy"); + + } + + @Override + public void onError(SdlManager manager, String info, Exception e) { + Log.i(TAG, "OnError"); + } + }); + //FIXME have to add websocket setting + SdlManager manager = builder.build(); + manager.start(); + + + } + + public static void startSdl(){ + System.out.println("Hello World!"); + + Thread thread = new Thread(new Runnable() { + boolean end = false; + + @Override + public void run() { + LifecycleManager.AppConfig config = new LifecycleManager.AppConfig(); + config.appID = "234523452345234"; + config.appName = "JavaChip"; + + WebSocketServerConfig serverConfig = new WebSocketServerConfig(5679,0); + LifecycleManager lifer = new LifecycleManager(config, serverConfig, new LifecycleManager.LifecycleListener() { + @Override + public void onProxyConnected(LifecycleManager lifeCycleManager) { + System.out.print("On proxy CONNECTED"); + + lifeCycleManager.addOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, new OnRPCNotificationListener() { + @Override + public void onNotified(RPCNotification notification) { + Log.i(TAG, "on notified"); + OnHMIStatus hmiStatus = (OnHMIStatus)notification; + + if(HMILevel.HMI_FULL.equals(hmiStatus.getHmiLevel())) { + if (true || hmiStatus.getFirstRun()) { + //TOD DO a show + Show show = new Show(); + show.setMainField1("There's snake in my boots"); + show.setMainField2("YEET THAT SUCKER!"); + lifeCycleManager.sendRpc(show); + + + } + } + } + }); + } + + @Override + public void onProxyClosed(LifecycleManager lifeCycleManager, String info, Exception e, SdlDisconnectedReason reason) { + System.out.print("On proxy CLOSED"); + end = true; + } + + @Override + public void onServiceEnded(LifecycleManager lifeCycleManager, OnServiceEnded serviceEnded) { + System.out.print("On service ENDED"); + + } + + @Override + public void onServiceNACKed(LifecycleManager lifeCycleManager, OnServiceNACKed serviceNACKed) { + System.out.print("On service NAKed"); + + } + + @Override + public void onError(LifecycleManager lifeCycleManager, String info, Exception e) { + System.out.print("OnError " + info); + + } + }); + lifer.start(); + while(true || !end){ + + } + } + + }); + + thread.start(); + + } +} |