summaryrefslogtreecommitdiff
path: root/javaSE/javaSE/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'javaSE/javaSE/src/main/java')
-rw-r--r--javaSE/javaSE/src/main/java/com/livio/BSON/BsonEncoder.java118
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/BuildConfig.java36
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/SdlConnection/SdlSession.java111
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/SdlManager.java183
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java69
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/file/FileManager.java145
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java165
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java342
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/EncryptionLifecycleManager.java45
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java77
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/SystemCapabilityManager.java45
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/permission/PermissionManager.java57
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/ScreenManager.java50
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java56
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/SubscribeButtonManager.java19
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java64
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetManager.java56
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/menu/MenuManager.java54
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/menu/VoiceCommandManager.java53
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/protocol/SdlPacket.java57
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java53
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/security/SdlSecurityBase.java36
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/trace/SdlTrace.java48
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/transport/CustomTransport.java171
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/transport/CustomTransportConfig.java53
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/transport/TransportCallback.java44
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/transport/TransportInterface.java47
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/transport/TransportManager.java214
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/transport/WebSocketServer.java198
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/transport/WebSocketServerConfig.java64
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/transport/utl/SSLConfig.java111
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/transport/utl/SSLWebSocketFactoryGenerator.java163
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/transport/utl/TransportRecord.java41
-rw-r--r--javaSE/javaSE/src/main/java/com/smartdevicelink/util/Log.java19
-rw-r--r--javaSE/javaSE/src/main/java/org/json/JSON.java116
-rw-r--r--javaSE/javaSE/src/main/java/org/json/JSONArray.java626
-rw-r--r--javaSE/javaSE/src/main/java/org/json/JSONException.java58
-rw-r--r--javaSE/javaSE/src/main/java/org/json/JSONObject.java829
-rw-r--r--javaSE/javaSE/src/main/java/org/json/JSONStringer.java432
-rw-r--r--javaSE/javaSE/src/main/java/org/json/JSONTokener.java611
40 files changed, 5736 insertions, 0 deletions
diff --git a/javaSE/javaSE/src/main/java/com/livio/BSON/BsonEncoder.java b/javaSE/javaSE/src/main/java/com/livio/BSON/BsonEncoder.java
new file mode 100644
index 000000000..22c47f6cb
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/livio/BSON/BsonEncoder.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2019, Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.livio.BSON;
+
+import com.smartdevicelink.util.DebugTool;
+import org.bson.*;
+
+import java.util.*;
+
+public class BsonEncoder {
+ private static final String TAG = "BsonEncoder";
+
+ public static byte[] encodeToBytes(HashMap<String, Object> map) throws ClassCastException {
+ if(map != null) {
+ BasicBSONObject bson = new BasicBSONObject();
+ bson.putAll(sanitizeMap(map));
+ BasicBSONEncoder encoder = new BasicBSONEncoder();
+
+ return encoder.encode(bson);
+ }
+ DebugTool.logError(TAG, "Something went wrong encoding the map into BSON bytes");
+
+ return null;
+ }
+
+ public static HashMap<String, Object> decodeFromBytes(byte[] bytes) {
+ if(bytes != null) {
+ BasicBSONDecoder decoder = new BasicBSONDecoder();
+ BSONObject object = decoder.readObject(bytes);
+ if (object != null) {
+ Map<String, Object> map = object.toMap();
+ if (map != null) {
+ return sanitizeMap(new HashMap<>(map));
+ }
+ }
+ }
+ DebugTool.logError(TAG, "Something went wrong decoding bytes into BSON");
+ return null;
+ }
+
+ /**
+ * Goes thorugh the map and ensures that all the values included are supported by SDL. If they are not of a supported
+ * value it is removed from the map
+ * @param map the map to be sanitized
+ * @return a sanitized HashMap with non-supported object type removes
+ */
+ private static HashMap<String, Object> sanitizeMap(HashMap<String, Object> map){
+ Set<String> keys = map.keySet();
+ Object value;
+ for(String key : keys){
+ value = map.get(key);
+
+ //First check to see if it value is a valid type used in SDL
+ if(isSupportedType(value)){
+ continue;
+ }else if(value instanceof List){ //Next, check to see if it is a list of values
+ List list = (List)value;
+
+ //If the list is empty, there shouldn't be a problem leaving it in the map
+ if(list.isEmpty()){
+ continue;
+ }
+
+ //Since the list isn't empty, check the first item
+ if(isSupportedType(list.get(0))){
+ continue;
+ }
+ }
+ //If the item isn't valid, remove it from the map
+ map.remove(key);
+
+ }
+ return map;
+ }
+
+ /**
+ * Checks the value to ensure it is of a supported type
+ * @param value the generic object value
+ * @return if the object is an instanceOf one of the supported SDL BSON objects
+ */
+ private static boolean isSupportedType(Object value){
+ return value instanceof Integer
+ || value instanceof Long
+ || value instanceof Double
+ || value instanceof String
+ || value instanceof Boolean;
+ }
+
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/BuildConfig.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/BuildConfig.java
new file mode 100644
index 000000000..ecd7b1f9b
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/BuildConfig.java
@@ -0,0 +1,36 @@
+/*
+* Copyright (c) 2017 - 2020, SmartDeviceLink Consortium, Inc.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* * Redistributions of source code must retain the above copyright notice, this
+* list of conditions and the following disclaimer.
+*
+* * Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+*
+* * Neither the name of SmartDeviceLink Consortium, Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+package com.smartdevicelink;
+
+// THIS FILE IS AUTO GENERATED, DO NOT MODIFY!!
+public final class BuildConfig {
+ public static final String VERSION_NAME = "4.12.0";
+} \ No newline at end of file
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/SdlConnection/SdlSession.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/SdlConnection/SdlSession.java
new file mode 100644
index 000000000..17a961a17
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/SdlConnection/SdlSession.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.SdlConnection;
+
+
+import androidx.annotation.RestrictTo;
+import com.smartdevicelink.protocol.SdlPacket;
+import com.smartdevicelink.protocol.SdlProtocol;
+import com.smartdevicelink.protocol.SdlProtocolBase;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.proxy.interfaces.ISdlServiceListener;
+import com.smartdevicelink.transport.BaseTransportConfig;
+import com.smartdevicelink.util.DebugTool;
+import com.smartdevicelink.util.Version;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class SdlSession extends BaseSdlSession {
+
+ private static final String TAG = "SdlSession";
+
+
+ public SdlSession(ISdlSessionListener listener, BaseTransportConfig config) {
+ super(listener, config);
+ }
+
+ @Override
+ protected SdlProtocolBase getSdlProtocolImplementation() {
+ return new SdlProtocol(this, transportConfig);
+ }
+
+ @Override
+ public void onServiceStarted(SdlPacket packet, SessionType serviceType, int sessionID, Version version, boolean isEncrypted) {
+ DebugTool.logInfo(TAG, serviceType.getName() + " service started");
+
+ if (serviceType != null && serviceType.eq(SessionType.RPC) && this.sessionId == -1) {
+ this.sessionId = sessionID;
+ this.sessionListener.onSessionStarted(sessionID, version);
+ }
+
+ if (isEncrypted) {
+ encryptedServices.addIfAbsent(serviceType);
+ }
+
+ if (serviceListeners != null && serviceListeners.containsKey(serviceType)) {
+ CopyOnWriteArrayList<ISdlServiceListener> listeners = serviceListeners.get(serviceType);
+ for (ISdlServiceListener listener : listeners) {
+ listener.onServiceStarted(this, serviceType, isEncrypted);
+ }
+ }
+ }
+
+ @Override
+ public void onServiceEnded(SdlPacket packet, SessionType serviceType, int sessionID) {
+
+ if (SessionType.RPC.equals(serviceType)) {
+ this.sessionListener.onSessionEnded(sessionID);
+ }
+
+ if (serviceListeners != null && serviceListeners.containsKey(serviceType)) {
+ CopyOnWriteArrayList<ISdlServiceListener> listeners = serviceListeners.get(serviceType);
+ for (ISdlServiceListener listener : listeners) {
+ listener.onServiceEnded(this, serviceType);
+ }
+ }
+
+ encryptedServices.remove(serviceType);
+ }
+
+ @Override
+ public void onServiceError(SdlPacket packet, SessionType sessionType, int sessionID, String error) {
+ if (serviceListeners != null && serviceListeners.containsKey(sessionType)) {
+ CopyOnWriteArrayList<ISdlServiceListener> listeners = serviceListeners.get(sessionType);
+ for (ISdlServiceListener listener : listeners) {
+ listener.onServiceError(this, sessionType, "End " + sessionType.toString() + " Service NACK'ed");
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/SdlManager.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/SdlManager.java
new file mode 100644
index 000000000..4dae813f6
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/SdlManager.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.managers;
+
+import androidx.annotation.NonNull;
+import com.smartdevicelink.util.Log;
+
+import com.smartdevicelink.managers.file.FileManager;
+import com.smartdevicelink.managers.permission.PermissionManager;
+import com.smartdevicelink.managers.screen.ScreenManager;
+import com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.util.DebugTool;
+
+/**
+ * <strong>SDLManager</strong> <br>
+ * <p>
+ * This is the main point of contact between an application and SDL <br>
+ * <p>
+ * It is broken down to these areas: <br>
+ * <p>
+ * 1. SDLManagerBuilder <br>
+ * 2. ISdl Interface along with its overridden methods - This can be passed into attached managers <br>
+ * 3. Sending Requests <br>
+ * 4. Helper methods
+ */
+public class SdlManager extends BaseSdlManager {
+
+ /**
+ * Starts up a SdlManager, and calls provided callback called once all BaseSubManagers are done setting up
+ */
+ @Override
+ public void start() {
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ dispose();
+ }
+ });
+
+ DebugTool.logInfo(TAG, "start");
+ if (lifecycleManager == null) {
+ if (transport != null && (transport.getTransportType().equals(TransportType.WEB_SOCKET_SERVER) || transport.getTransportType().equals(TransportType.CUSTOM))) {
+ super.start();
+ lifecycleManager.start();
+ } else {
+ throw new RuntimeException("No transport provided");
+ }
+ }
+ }
+
+ @Override
+ protected void initialize() {
+ // Instantiate sub managers
+ this.permissionManager = new PermissionManager(_internalInterface);
+ this.fileManager = new FileManager(_internalInterface, fileManagerConfig);
+ this.screenManager = new ScreenManager(_internalInterface, this.fileManager);
+
+ // Start sub managers
+ this.permissionManager.start(subManagerListener);
+ this.fileManager.start(subManagerListener);
+ this.screenManager.start(subManagerListener);
+ }
+
+ @Override
+ void checkState() {
+ if (permissionManager != null && fileManager != null && screenManager != null) {
+ if (permissionManager.getState() == BaseSubManager.READY && fileManager.getState() == BaseSubManager.READY && screenManager.getState() == BaseSubManager.READY) {
+ DebugTool.logInfo(TAG, "Starting sdl manager, all sub managers are in ready state");
+ transitionToState(BaseSubManager.READY);
+ handleQueuedNotifications();
+ notifyDevListener(null);
+ onReady();
+ } else if (permissionManager.getState() == BaseSubManager.ERROR && fileManager.getState() == BaseSubManager.ERROR && screenManager.getState() == BaseSubManager.ERROR) {
+ String info = "ERROR starting sdl manager, all sub managers are in error state";
+ DebugTool.logError(TAG, info);
+ transitionToState(BaseSubManager.ERROR);
+ notifyDevListener(info);
+ } else if (permissionManager.getState() == BaseSubManager.SETTING_UP || fileManager.getState() == BaseSubManager.SETTING_UP || screenManager.getState() == BaseSubManager.SETTING_UP) {
+ DebugTool.logInfo(TAG, "SETTING UP sdl manager, some sub managers are still setting up");
+ transitionToState(BaseSubManager.SETTING_UP);
+ // No need to notify developer here!
+ } else {
+ DebugTool.logWarning(TAG, "LIMITED starting sdl manager, some sub managers are in error or limited state and the others finished setting up");
+ transitionToState(BaseSubManager.LIMITED);
+ handleQueuedNotifications();
+ notifyDevListener(null);
+ onReady();
+ }
+ } else {
+ // We should never be here, but somehow one of the sub-sub managers is null
+ String info = "ERROR one of the sdl sub managers is null";
+ DebugTool.logError(TAG, info);
+ transitionToState(BaseSubManager.ERROR);
+ notifyDevListener(info);
+ }
+ }
+
+ private void notifyDevListener(String info) {
+ if (managerListener != null) {
+ if (getState() == BaseSubManager.ERROR) {
+ managerListener.onError((SdlManager) this, info, null);
+ } else {
+ managerListener.onStart((SdlManager) this);
+ }
+ }
+ }
+
+ @Override
+ void retryChangeRegistration() {
+ // Do nothing
+ }
+
+ @Override
+ public void dispose() {
+ if (this.permissionManager != null) {
+ this.permissionManager.dispose();
+ }
+
+ if (this.fileManager != null) {
+ this.fileManager.dispose();
+ }
+
+ if (this.screenManager != null) {
+ this.screenManager.dispose();
+ }
+
+ if (this.lifecycleManager != null) {
+ this.lifecycleManager.stop();
+ }
+
+ if (managerListener != null) {
+ managerListener.onDestroy((SdlManager) this);
+ managerListener = null;
+ }
+
+ transitionToState(BaseSubManager.SHUTDOWN);
+ }
+
+ // BUILDER
+ public static class Builder extends BaseSdlManager.Builder {
+ /**
+ * Builder for the SdlManager. Parameters in the constructor are required.
+ *
+ * @param appId the app's ID
+ * @param appName the app's name
+ * @param listener a SdlManagerListener object
+ */
+ public Builder(@NonNull final String appId, @NonNull final String appName, @NonNull final SdlManagerListener listener) {
+ super(appId, appName, listener);
+ }
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java
new file mode 100644
index 000000000..43aad3161
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.managers;
+
+import com.smartdevicelink.managers.lifecycle.LifecycleConfigurationUpdate;
+import com.smartdevicelink.proxy.rpc.enums.Language;
+
+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);
+
+ /**
+ * Called when the SDL manager detected a language mismatch. In case of a language mismatch the
+ * manager should change the apps registration by updating the lifecycle configuration to the
+ * specified language. If the app can support the specified language it should return an Object
+ * of LifecycleConfigurationUpdate, otherwise it should return null to indicate that the language
+ * is not supported.
+ *
+ * @param language The VR+TTS language of the connected head unit the manager is trying to update the configuration.
+ * @param hmiLanguage The HMI display language of the connected head unit the manager is trying to update the configuration.
+ * @return An object of LifecycleConfigurationUpdate if the head unit language is supported,
+ * otherwise null to indicate that the language is not supported.
+ */
+ LifecycleConfigurationUpdate managerShouldUpdateLifecycle(Language language, Language hmiLanguage);
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/file/FileManager.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/file/FileManager.java
new file mode 100644
index 000000000..9fb7c7ce3
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/file/FileManager.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.managers.file;
+
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import com.smartdevicelink.managers.file.filetypes.SdlFile;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.rpc.PutFile;
+import com.smartdevicelink.util.DebugTool;
+import com.smartdevicelink.util.FileUtls;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+
+/**
+ * <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 {
+
+ /**
+ * Constructor for FileManager
+ * @param internalInterface an instance of the ISdl interface that can be used for common SDL operations (sendRpc, addRpcListener, etc)
+ * @param fileManagerConfig an instance of the FileManagerConfig gives access to artworkRetryCount and fileRetryCount to let us if those file types can be re-upload if they fail
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ public FileManager(ISdl internalInterface, FileManagerConfig fileManagerConfig) {
+ // setup
+ super(internalInterface, fileManagerConfig);
+ }
+
+ /**
+ * 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 = FileUtls.getFileData(file.getFilePath());
+ if(data != null ){
+ putFile.setFileData(data);
+ }else{
+ throw new IllegalArgumentException("File at path was empty");
+ }
+ }else if(file.getURI() != null){
+ // Use URI to upload file
+ byte[] data = contentsOfUri(file.getURI());
+ if(data != null){
+ putFile.setFileData(data);
+ }else{
+ throw new IllegalArgumentException("Uri 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;
+ }
+
+
+ /**
+ * Helper method to take Uri and turn it into byte array
+ * @param uri Uri for desired file
+ * @return Resulting byte array
+ */
+ private byte[] contentsOfUri(URI uri){
+ InputStream is = null;
+ try{
+ is = uri.toURL().openStream();
+ return contentsOfInputStream(is);
+ } catch (IOException e){
+ DebugTool.logError(TAG, "Can't read from URI", e);
+ return null;
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java
new file mode 100644
index 000000000..a63c3e27b
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.managers.file.filetypes;
+
+import androidx.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;
+import com.smartdevicelink.util.DebugTool;
+
+import java.net.URI;
+
+/**
+ * A class that extends SdlFile, representing artwork (JPEG, PNG, or BMP) to be uploaded to core
+ */
+public class SdlArtwork extends SdlFile implements Cloneable{
+ private boolean isTemplate;
+ private Image imageRPC;
+
+ /**
+ * Creates a new instance of SdlArtwork
+ */
+ public SdlArtwork(){}
+
+ /**
+ * Creates a new instance of SdlArtwork
+ * @param fileName a String value representing the name that will be used to store the file in the head unit. You can pass null if you want the library to auto generate the name
+ * @param fileType a FileType enum value representing the type of the file
+ * @param filePath a String value representing the the location of the file
+ * @param persistentFile a boolean value that indicates if the file is meant to persist between sessions / ignition cycles
+ */
+ public SdlArtwork(String fileName, @NonNull FileType fileType, String filePath, boolean persistentFile) {
+ super(fileName, fileType, filePath, persistentFile);
+ }
+
+ /**
+ * Creates a new instance of SdlArtwork
+ * @param fileName a String value representing the name that will be used to store the file in the head unit. You can pass null if you want the library to auto generate the name
+ * @param fileType a FileType enum value representing the type of the file
+ * @param uri a URI value representing a file's location. Currently, it only supports local files
+ * @param persistentFile a boolean value that indicates if the file is meant to persist between sessions / ignition cycles
+ */
+ public SdlArtwork(String fileName, @NonNull FileType fileType, URI uri, boolean persistentFile) {
+ super(fileName, fileType, uri, persistentFile);
+ }
+
+ /**
+ * Creates a new instance of SdlArtwork
+ * @param fileName a String value representing the name that will be used to store the file in the head unit. You can pass null if you want the library to auto generate the name
+ * @param fileType a FileType enum value representing the type of the file
+ * @param data a byte array representing the data of the file
+ * @param persistentFile a boolean value that indicates if the file is meant to persist between sessions / ignition cycles
+ */
+ public SdlArtwork(String fileName, @NonNull FileType fileType, byte[] data, boolean persistentFile) {
+ super(fileName, fileType, data, persistentFile);
+ }
+
+ /**
+ * Creates a new instance of SdlArtwork
+ * @param staticIconName a StaticIconName enum value representing the name of a static file that comes pre-shipped with the head unit
+ */
+ public SdlArtwork(@NonNull StaticIconName staticIconName) {
+ super(staticIconName);
+ }
+
+ /**
+ * Sets 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;
+ }
+
+ /**
+ * Gets 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(FileType fileType) {
+ if(fileType == null || 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.");
+ }
+ }
+
+ /**
+ * Gets 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) {
+ imageRPC = createImageRPC();
+ }
+ return imageRPC;
+ }
+
+ private Image createImageRPC(){
+ Image image;
+ if (isStaticIcon()) {
+ image = new Image(getName(), ImageType.STATIC);
+ image.setIsTemplate(true);
+ } else {
+ image = new Image(getName(), ImageType.DYNAMIC);
+ image.setIsTemplate(isTemplate);
+ }
+ return image;
+ }
+
+ /**
+ * Creates a deep copy of the object
+ * @return deep copy of the object
+ */
+ @Override
+ public SdlArtwork clone() {
+ try{
+ SdlArtwork artwork = (SdlArtwork) super.clone();
+ if(artwork != null){
+ artwork.imageRPC = artwork.createImageRPC();
+ }
+ return artwork;
+ } catch (CloneNotSupportedException e) {
+ if(DebugTool.isDebugEnabled()){
+ throw new RuntimeException("Clone not supported by super class");
+ }
+ }
+ return null;
+ }
+} \ No newline at end of file
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java
new file mode 100644
index 000000000..bb1c170d4
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.managers.file.filetypes;
+
+import androidx.annotation.NonNull;
+
+import com.smartdevicelink.proxy.rpc.enums.FileType;
+import com.smartdevicelink.proxy.rpc.enums.StaticIconName;
+
+import java.net.URI;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * A class representing data to be uploaded to core
+ */
+public class SdlFile{
+ private String fileName;
+ private String filePath;
+ private URI uri;
+ private byte[] fileData;
+ private FileType fileType;
+ private boolean persistentFile;
+ private boolean isStaticIcon;
+ private boolean shouldAutoGenerateName;
+ // Overwrite property by default is set to true in SdlFile constructors indicating that a file can be overwritten
+ private boolean overwrite = true;
+
+ /**
+ * Creates a new instance of SdlFile
+ */
+ public SdlFile(){}
+
+ /**
+ * Creates a new instance of SdlFile
+ * @param fileName a String value representing the name that will be used to store the file in the head unit. You can pass null if you want the library to auto generate the name
+ * @param fileType a FileType enum value representing the type of the file
+ * @param filePath a String value representing the the location of the file
+ * @param persistentFile a boolean value that indicates if the file is meant to persist between sessions / ignition cycles
+ */
+ public SdlFile(String fileName, @NonNull FileType fileType, String filePath, boolean persistentFile){
+ setName(fileName);
+ setType(fileType);
+ setFilePath(filePath);
+ setPersistent(persistentFile);
+ }
+
+ /**
+ * Creates a new instance of SdlFile
+ * @param fileName a String value representing the name that will be used to store the file in the head unit. You can pass null if you want the library to auto generate the name
+ * @param fileType a FileType enum value representing the type of the file
+ * @param uri a URI value representing a file's location. Currently, it only supports local files
+ * @param persistentFile a boolean value that indicates if the file is meant to persist between sessions / ignition cycles
+ */
+ public SdlFile(String fileName, @NonNull FileType fileType, URI uri, boolean persistentFile){
+ setName(fileName);
+ setType(fileType);
+ setURI(uri);
+ setPersistent(persistentFile);
+ }
+
+ /**
+ * Creates a new instance of SdlFile
+ * @param fileName a String value representing the name that will be used to store the file in the head unit. You can pass null if you want the library to auto generate the name
+ * @param fileType a FileType enum value representing the type of the file
+ * @param data a byte array representing the data of the file
+ * @param persistentFile a boolean value that indicates if the file is meant to persist between sessions / ignition cycles
+ */
+ public SdlFile(String fileName, @NonNull FileType fileType, byte[] data, boolean persistentFile){
+ setName(fileName);
+ setType(fileType);
+ setFileData(data);
+ setPersistent(persistentFile);
+ }
+
+ /**
+ * Creates a new instance of SdlFile
+ * @param staticIconName a StaticIconName enum value representing the name of a static file that comes pre-shipped with the head unit
+ */
+ public SdlFile(@NonNull StaticIconName staticIconName){
+ setName(staticIconName.toString());
+ setFileData(staticIconName.toString().getBytes());
+ setPersistent(false);
+ setStaticIcon(true);
+ }
+
+ /**
+ * Sets the name of the file
+ * @param fileName a String value representing the name that will be used to store the file in the head unit. You can pass null if you want the library to auto generate the name
+ */
+ public void setName(String fileName) {
+ if (fileName != null) {
+ this.shouldAutoGenerateName = false;
+ this.fileName = fileName;
+ } else {
+ this.shouldAutoGenerateName = true;
+ if (this.getFileData() != null) {
+ this.fileName = generateFileNameFromData(this.getFileData());
+ } else if (this.getURI() != null) {
+ this.fileName = generateFileNameFromUri(this.getURI());
+ } else if (this.getFilePath() != null) {
+ this.fileName = generateFileNameFromFilePath(this.getFilePath());
+ }
+ }
+ }
+
+ /**
+ * Gets the name of the file
+ * @return a String value representing the name that will be used to store the file in the head unit
+ */
+ public String getName(){
+ return fileName;
+ }
+
+ /**
+ * Sets the location of the file
+ * @param filePath a String value representing the the location of the file
+ */
+ public void setFilePath(String filePath){
+ this.filePath = filePath;
+ if (shouldAutoGenerateName && filePath != null) {
+ this.fileName = generateFileNameFromFilePath(filePath);
+ }
+ }
+
+ /**
+ * Gets the location of the file
+ * @return
+ */
+ public String getFilePath(){
+ return this.filePath;
+ }
+
+ /**
+ * Sets the uri of the file
+ * @param uri a URI value representing a file's location. Currently, it only supports local files
+ */
+ public void setURI(URI uri){
+ this.uri = uri;
+ if (shouldAutoGenerateName && uri != null) {
+ this.fileName = generateFileNameFromUri(uri);
+ }
+ }
+
+ /**
+ * Gets the uri of the file
+ * @return a URI value representing a file's location. Currently, it only supports local files
+ */
+ public URI getURI(){
+ return uri;
+ }
+
+ /**
+ * Sets the byte array that represents the content of the file
+ * @param data a byte array representing the data of the file
+ */
+ public void setFileData(byte[] data){
+ this.fileData = data;
+ if (shouldAutoGenerateName && data != null) {
+ this.fileName = generateFileNameFromData(data);
+ }
+ }
+
+ /**
+ * Gets the byte array that represents the content of the file
+ * @return a byte array representing the data of the file
+ */
+ public byte[] getFileData(){
+ return fileData;
+ }
+
+ /**
+ * Sets the type of the file
+ * @param fileType a FileType enum value representing the type of the file
+ */
+ public void setType(@NonNull FileType fileType){
+ this.fileType = fileType;
+ }
+
+ /**
+ * Gets the type of the file
+ * @return a FileType enum value representing the type of the file
+ */
+ public FileType getType(){
+ return fileType;
+ }
+
+ /**
+ * Sets whether the file should persist between sessions / ignition cycles
+ * @param persistentFile a boolean value that indicates if the file is meant to persist between sessions / ignition cycles
+ */
+ public void setPersistent(boolean persistentFile){
+ this.persistentFile = persistentFile;
+ }
+
+ /**
+ * Gets whether the file should persist between sessions / ignition cycles
+ * @return a boolean value that indicates if the file is meant to persist between sessions / ignition cycles
+ */
+ public boolean isPersistent(){
+ return this.persistentFile;
+ }
+
+ /**
+ * Sets the the name of the static file. Static files comes pre-shipped with the head unit
+ * @param staticIcon a StaticIconName enum value representing the name of a static file that comes pre-shipped with the head unit
+ */
+ public void setStaticIcon(boolean staticIcon) {
+ isStaticIcon = staticIcon;
+ }
+
+ /**
+ * Gets the the name of the static file. Static files comes pre-shipped with the head unit
+ * @return a StaticIconName enum value representing the name of a static file that comes pre-shipped with the head unit
+ */
+ public boolean isStaticIcon() {
+ return isStaticIcon;
+ }
+
+ /**
+ * Gets the overwrite property for an SdlFile by default its set to true
+ * @return a boolean value that indicates if a file can be overwritten.
+ */
+ public boolean getOverwrite() {
+ return overwrite;
+ }
+
+ /**
+ * Sets the overwrite property for an SdlFile by default its set to true
+ * @param overwrite a boolean value that indicates if a file can be overwritten
+ */
+ public void setOverwrite(boolean overwrite) {
+ this.overwrite = overwrite;
+ }
+
+ /**
+ * Generates a file name from data by hashing the data and returning the last 16 chars
+ * @param data a byte array representing the data of the file
+ * @return a String value representing the name that will be used to store the file in the head unit
+ */
+ private String generateFileNameFromData(@NonNull byte[] data) {
+ String result;
+ MessageDigest messageDigest;
+ try {
+ messageDigest = MessageDigest.getInstance("md5");
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ return null;
+ }
+ byte[] hash = new byte[0];
+ if (messageDigest != null) {
+ hash = messageDigest.digest(data);
+ }
+ StringBuilder stringBuilder = new StringBuilder(2 * hash.length);
+ for (byte b : hash) {
+ stringBuilder.append(String.format("%02x", b & 0xff));
+ }
+ String hashString = stringBuilder.toString();
+ result = hashString.substring(hashString.length() - 16);
+ return result;
+ }
+
+ /**
+ * Generates a file name from filePath by hashing the filePath and returning the last 16 chars
+ * @param filePath a String value representing the the location of the file
+ * @return a String value representing the name that will be used to store the file in the head unit
+ */
+ private String generateFileNameFromFilePath(String filePath) {
+ return generateFileNameFromData(filePath.getBytes());
+ }
+
+ /**
+ * Generates a file name from uri by hashing the uri string and returning the last 16 chars
+ * @param uri a URI value representing a file's location
+ * @return a String value representing the name that will be used to store the file in the head unit
+ */
+ private String generateFileNameFromUri(@NonNull URI uri) {
+ return generateFileNameFromData(uri.toString().getBytes());
+ }
+
+ /**
+ * Used to compile hashcode for SdlFile for use to compare in equals method
+ * @return Custom hashcode of SdlFile variables
+ */
+ @Override
+ public int hashCode() {
+ int result = 1;
+ result += ((getName() == null) ? 0 : Integer.rotateLeft(getName().hashCode(), 1));
+ result += ((getURI() == null) ? 0 : Integer.rotateLeft(getURI().hashCode(), 2));
+ result += ((getFilePath() == null) ? 0 : Integer.rotateLeft(getFilePath().hashCode(), 3));
+ result += ((getFileData() == null) ? 0 : Integer.rotateLeft(getFileData().hashCode(), 4));
+ result += ((getType() == null) ? 0 : Integer.rotateLeft(getType().hashCode(), 5));
+ result += Integer.rotateLeft(Boolean.valueOf(isStaticIcon()).hashCode(), 6);
+ result += Integer.rotateLeft(Boolean.valueOf(isPersistent()).hashCode(), 7);
+ return result;
+ }
+
+ /**
+ * Uses our custom hashCode for SdlFile objects
+ * @param o - The object to compare
+ * @return boolean of whether the objects are the same or not
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) return false;
+ // if this is the same memory address, it's the same
+ if (this == o) return true;
+ // if this is not an instance of SdlFile, not the same
+ if (!(o instanceof SdlFile)) return false;
+ // return comparison
+ return hashCode() == o.hashCode();
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/EncryptionLifecycleManager.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/EncryptionLifecycleManager.java
new file mode 100644
index 000000000..eda411dc5
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/EncryptionLifecycleManager.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.managers.lifecycle;
+
+import androidx.annotation.NonNull;
+
+import com.smartdevicelink.managers.ServiceEncryptionListener;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+
+class EncryptionLifecycleManager extends BaseEncryptionLifecycleManager {
+
+ EncryptionLifecycleManager(@NonNull ISdl internalInterface, ServiceEncryptionListener listener) {
+ super(internalInterface, listener);
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java
new file mode 100644
index 000000000..b7167b81c
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/LifecycleManager.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.managers.lifecycle;
+
+import androidx.annotation.RestrictTo;
+
+import com.smartdevicelink.SdlConnection.SdlSession;
+import com.smartdevicelink.exception.SdlException;
+import com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason;
+import com.smartdevicelink.transport.BaseTransportConfig;
+
+/**
+ * The lifecycle manager creates a central point for all SDL session logic to converge. It should only be used by
+ * the library itself. Usage outside the library is not permitted and will not be protected for in the future.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class LifecycleManager extends BaseLifecycleManager {
+ public LifecycleManager(AppConfig appConfig, BaseTransportConfig config, LifecycleListener listener) {
+ super(appConfig, config, listener);
+ }
+
+ @Override
+ void initialize() {
+ super.initialize();
+ this.session = new SdlSession(this.sdlSessionListener, _transportConfig);
+ }
+
+ @Override
+ void cycle(SdlDisconnectedReason disconnectedReason) {
+ clean();
+ if (session != null) {
+ try {
+ session.startSession();
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ void onTransportDisconnected(String info, boolean availablePrimary, BaseTransportConfig transportConfig) {
+ super.onTransportDisconnected(info, availablePrimary, transportConfig);
+ if (!availablePrimary) {
+ onClose(info, null, null);
+ }
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/SystemCapabilityManager.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/SystemCapabilityManager.java
new file mode 100644
index 000000000..e4e635883
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/lifecycle/SystemCapabilityManager.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.managers.lifecycle;
+
+import com.smartdevicelink.proxy.interfaces.ISdl;
+
+/**
+ * <strong>SystemCapabilityManager</strong> <br>
+ *
+ * Note: This class must be accessed through the SdlManager. Do not instantiate it by itself. <br>
+ */
+public class SystemCapabilityManager extends BaseSystemCapabilityManager {
+ SystemCapabilityManager(ISdl callback) {
+ super(callback);
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/permission/PermissionManager.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/permission/PermissionManager.java
new file mode 100644
index 000000000..b27b00bcb
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/permission/PermissionManager.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.managers.permission;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+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 an instance of the FileManager so that button graphics can be sent
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ public PermissionManager(@NonNull ISdl internalInterface) {
+ super(internalInterface);
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/ScreenManager.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/ScreenManager.java
new file mode 100644
index 000000000..2989be3f2
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/ScreenManager.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.managers.screen;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+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 {
+
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ public ScreenManager(@NonNull ISdl internalInterface, @NonNull FileManager fileManager) {
+ super(internalInterface, fileManager);
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java
new file mode 100644
index 000000000..a7e9d30c2
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.managers.screen;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+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>
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class SoftButtonManager extends BaseSoftButtonManager {
+
+ /**
+ * Creates a new instance of the SoftButtonManager
+ *
+ * @param internalInterface an instance of the ISdl interface that can be used for common SDL operations (sendRpc, addRpcListener, etc)
+ * @param fileManager an instance of the FileManager so that button graphics can be sent
+ */
+ SoftButtonManager(@NonNull ISdl internalInterface, @NonNull FileManager fileManager) {
+ super(internalInterface, fileManager);
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/SubscribeButtonManager.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/SubscribeButtonManager.java
new file mode 100644
index 000000000..8db1cd957
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/SubscribeButtonManager.java
@@ -0,0 +1,19 @@
+package com.smartdevicelink.managers.screen;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+
+/**
+ * <strong>SubscribeButtonManager</strong> <br>
+ *
+ * Note: This class must be accessed through the SdlManager. Do not instantiate it by itself. <br>
+ *
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class SubscribeButtonManager extends BaseSubscribeButtonManager {
+
+ public SubscribeButtonManager(@NonNull ISdl internalInterface) {
+ super(internalInterface);
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java
new file mode 100644
index 000000000..76c142e9a
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.managers.screen;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+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>
+ *
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+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]);
+ }
+ return blankArtwork;
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetManager.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetManager.java
new file mode 100644
index 000000000..cd7f20dfe
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/choiceset/ChoiceSetManager.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.managers.screen.choiceset;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import com.smartdevicelink.managers.file.FileManager;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+
+/**
+ * <strong>ChoiceSetManager</strong> <br>
+ * ChoiceSetManager gives the developer the ability to control how soft choice sets are displayed on the head unit.<br>
+ * Note: This class must be accessed through the SdlManager->ScreenManager. Do not instantiate it by itself.<br>
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class ChoiceSetManager extends BaseChoiceSetManager {
+
+ /**
+ * Creates a new instance of the ChoiceSetManager
+ *
+ * @param internalInterface
+ */
+ public ChoiceSetManager(@NonNull ISdl internalInterface, @NonNull FileManager fileManager) {
+ super(internalInterface, fileManager);
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/menu/MenuManager.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/menu/MenuManager.java
new file mode 100644
index 000000000..ec2ae5fb3
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/menu/MenuManager.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.managers.screen.menu;
+
+import androidx.annotation.RestrictTo;
+import com.smartdevicelink.managers.file.FileManager;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+
+/**
+ * <strong>MenuManager</strong> <br>
+ *
+ * Note: This class must be accessed through the ScreenManager via the SdlManager. Do not instantiate it by itself. <br>
+ *
+ * The MenuManager takes MenuCell objects and creates and sends all necessary RPCs to build out a menu
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class MenuManager extends BaseMenuManager {
+
+ public MenuManager(ISdl internalInterface, FileManager fileManager) {
+ // setup
+ super(internalInterface, fileManager);
+ }
+
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/menu/VoiceCommandManager.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/menu/VoiceCommandManager.java
new file mode 100644
index 000000000..1d2233fb0
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/managers/screen/menu/VoiceCommandManager.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.managers.screen.menu;
+
+import androidx.annotation.RestrictTo;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+
+/**
+ * <strong>VoiceCommandManager</strong> <br>
+ *
+ * Note: This class must be accessed through the ScreenManager via the SdlManager. Do not instantiate it by itself. <br>
+ *
+ * The VoiceCommandManager takes a List of VoiceCommand objects and sets them on the Head unit for you.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class VoiceCommandManager extends BaseVoiceCommandManager {
+
+ public VoiceCommandManager(ISdl internalInterface) {
+ // setup
+ super(internalInterface);
+ }
+
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/protocol/SdlPacket.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/protocol/SdlPacket.java
new file mode 100644
index 000000000..816e70e20
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/protocol/SdlPacket.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the SmartDeviceLink Consortium, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.protocol;
+
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class SdlPacket extends BaseSdlPacket {
+
+ public SdlPacket(int version, boolean encryption, int frameType,
+ int serviceType, int frameInfo, int sessionId,
+ int dataSize, int messageId, byte[] payload) {
+ super(version, encryption, frameType, serviceType, frameInfo, sessionId, dataSize, messageId, payload);
+ }
+
+ public SdlPacket(int version, boolean encryption, int frameType,
+ int serviceType, int frameInfo, int sessionId,
+ int dataSize, int messageId, byte[] payload, int offset, int bytesToWrite) {
+ super(version, encryption, frameType, serviceType, frameInfo, sessionId, dataSize, messageId, payload, offset, bytesToWrite);
+ }
+
+ protected SdlPacket() {
+ super();
+ }
+
+ protected SdlPacket(BaseSdlPacket packet) {
+ super(packet);
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java
new file mode 100644
index 000000000..18343acb0
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.protocol;
+
+
+import androidx.annotation.RestrictTo;
+import com.smartdevicelink.transport.BaseTransportConfig;
+import com.smartdevicelink.transport.TransportManager;
+
+
+@SuppressWarnings("WeakerAccess")
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class SdlProtocol extends SdlProtocolBase {
+ private static final String TAG ="SdlProtocol";
+
+ public SdlProtocol( ISdlProtocol iSdlProtocol, BaseTransportConfig config) {
+ super(iSdlProtocol, config);
+ this.setTransportManager(new TransportManager(config, transportEventListener));
+ }
+
+
+
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/security/SdlSecurityBase.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/security/SdlSecurityBase.java
new file mode 100644
index 000000000..e8ed85b70
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/security/SdlSecurityBase.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the SmartDeviceLink Consortium, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.security;
+
+public abstract class SdlSecurityBase extends AbstractSdlSecurityBase {
+
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/trace/SdlTrace.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/trace/SdlTrace.java
new file mode 100644
index 000000000..482b4a846
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/trace/SdlTrace.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the SmartDeviceLink Consortium, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.trace;
+
+
+/* This class handles the global TraceSettings as requested by the users either through the combination of the following
+ 1. System defaults
+ 2. Application XML config
+ 3. Programmatic requests from application itself
+
+ It is manifested in the <SmartDeviceLink>...</SmartDeviceLink> tags
+ */
+
+public class SdlTrace extends SdlTraceBase{
+ private static String getPid(){
+ //Default implementation is not able to get this information
+ return "UNKNOWN";
+ }
+} // end-class \ No newline at end of file
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/CustomTransport.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/CustomTransport.java
new file mode 100644
index 000000000..ad02f96d2
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/CustomTransport.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.transport;
+
+import com.smartdevicelink.protocol.SdlPacket;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
+import com.smartdevicelink.util.DebugTool;
+
+import java.nio.ByteBuffer;
+
+public abstract class CustomTransport implements TransportInterface{
+ private static final String TAG = "CustomTransport";
+
+ final TransportRecord transportRecord;
+ final SdlPsm psm;
+ TransportCallback transportCallback;
+
+
+
+ public CustomTransport(String address) {
+ //Creates a callback for when packets
+ psm = new SdlPsm();
+ transportRecord = new TransportRecord(TransportType.CUSTOM,address);
+ }
+
+ public TransportRecord getTransportRecord(){
+ return this.transportRecord;
+ }
+
+
+ /**
+ * Call this method when reading a byte array off the transport
+ * @param bytes the bytes read off the transport
+ */
+ public synchronized void onByteArrayReceived (byte[] bytes, int offset, int length) {
+
+ if(bytes != null && bytes.length > 0){
+ boolean stateProgress;
+ for(int i = 0; i < length; i++){
+ stateProgress = psm.handleByte(bytes[i]);
+ if (!stateProgress) {//We are trying to weed through the bad packet info until we get something
+ //Log.w(TAG, "Packet State Machine did not move forward from state - "+ psm.getState()+". PSM being Reset.");
+ psm.reset();
+ }
+
+ if (psm.getState() == SdlPsm.FINISHED_STATE) {
+ SdlPacket packet = psm.getFormedPacket();
+ if (transportCallback != null && packet != null) {
+ packet.setTransportRecord(transportRecord);
+ transportCallback.onPacketReceived(packet);
+ }
+ //We put a trace statement in the message read so we can avoid all the extra bytes
+ psm.reset();
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Call this method when reading a ByteBuffer off the transport
+ * @param message the byte buffer that was read off the transport
+ */
+ public synchronized void onByteBufferReceived (ByteBuffer message) {
+ if(message != null){
+ boolean stateProgress;
+ while (message.hasRemaining()) {
+ stateProgress = psm.handleByte(message.get());
+ if (!stateProgress) {//We are trying to weed through the bad packet info until we get something
+
+ //Log.w(TAG, "Packet State Machine did not move forward from state - "+ psm.getState()+". PSM being Reset.");
+ psm.reset();
+ }
+
+ if (psm.getState() == SdlPsm.FINISHED_STATE) {
+ SdlPacket packet = psm.getFormedPacket();
+ if (transportCallback != null && packet != null) {
+ packet.setTransportRecord(transportRecord);
+ transportCallback.onPacketReceived(packet);
+ }
+ //We put a trace statement in the message read so we can avoid all the extra bytes
+ psm.reset();
+ }
+ }
+
+ }
+ }
+
+ @Override
+ public void start() {
+ if (transportCallback != null) {
+ transportCallback.onConnectionEstablished();
+ }
+ }
+
+ @Override
+ public void stop() {
+ if (transportCallback != null) {
+ transportCallback.onConnectionTerminated("Transport told to stop");
+ }
+ }
+
+ @Override
+ public void write(SdlPacket packet) {
+ byte[] bytes = packet.constructPacket();
+ if(bytes != null && bytes.length > 0) {
+ try {
+ onWrite(bytes, 0, bytes.length);
+ } catch (Exception exc) {
+ DebugTool.logError(TAG, "Error attempting to write packet", exc);
+ }
+ }
+ }
+
+ @Override
+ public void setCallback(TransportCallback transportCallback) {
+ this.transportCallback = transportCallback;
+ }
+
+ public void onError(){
+ if (transportCallback != null) {
+ transportCallback.onError();
+ }
+ }
+
+
+ /**
+ * Integrator should write out these bytes to whatever actual transport there is. This will be called from the
+ * internals of the library.
+ * @param bytes a deconstructed packet into a byte array that needs to be written out
+ * @param offset in bytes
+ * @param length in bytes
+ */
+ public abstract void onWrite(byte[] bytes, int offset, int length);
+
+
+
+
+
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/CustomTransportConfig.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/CustomTransportConfig.java
new file mode 100644
index 000000000..af0613aa1
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/CustomTransportConfig.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.transport;
+
+import com.smartdevicelink.transport.enums.TransportType;
+
+public class CustomTransportConfig extends BaseTransportConfig {
+
+ final CustomTransport customTransport;
+
+ public CustomTransportConfig(CustomTransport customTransport){
+ this.customTransport = customTransport;
+ }
+
+ @Override
+ public TransportType getTransportType() {
+ return TransportType.CUSTOM;
+ }
+
+ public TransportInterface getTransportInterface(){
+ return this.customTransport;
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/TransportCallback.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/TransportCallback.java
new file mode 100644
index 000000000..551ed9d29
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/TransportCallback.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the SmartDeviceLink Consortium, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.transport;
+
+import com.smartdevicelink.protocol.SdlPacket;
+
+/**
+ * This interface is used to receive callbacks from a transport class
+ */
+public interface TransportCallback {
+ void onConnectionEstablished();
+ void onError();
+ void onConnectionTerminated(String reason);
+ void onPacketReceived(SdlPacket packet);
+} \ No newline at end of file
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/TransportInterface.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/TransportInterface.java
new file mode 100644
index 000000000..989b2df33
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/TransportInterface.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.transport;
+
+import com.smartdevicelink.protocol.SdlPacket;
+import com.smartdevicelink.transport.utl.TransportRecord;
+
+/**
+ * This interface defines the basic methods that a transport must implement
+ */
+public interface TransportInterface {
+ void start();
+ void stop();
+ void write(SdlPacket packet);
+ void setCallback(TransportCallback callback);
+ TransportRecord getTransportRecord();
+} \ No newline at end of file
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/TransportManager.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/TransportManager.java
new file mode 100644
index 000000000..c8a07a1cc
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/TransportManager.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2018 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.transport;
+
+
+import com.smartdevicelink.protocol.SdlPacket;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
+import com.smartdevicelink.util.DebugTool;
+
+import java.util.Collections;
+import java.util.List;
+
+@SuppressWarnings("unused")
+public class TransportManager extends TransportManagerBase{
+ private static final String TAG = "TransportManager";
+
+ TransportInterface transport;
+
+ /**
+ * Managing transports
+ * List for status of all transports
+ * If transport is not connected. Request Router service connect to it. Get connected message
+ */
+
+ public TransportManager(BaseTransportConfig config, TransportEventListener listener){
+ super(config, listener);
+
+ //Start the new transport
+ switch (config.getTransportType()){
+ case WEB_SOCKET_SERVER:
+ transport = new WebSocketServer((WebSocketServerConfig)config, new SingleTransportCallbackImpl(new TransportRecord(TransportType.WEB_SOCKET_SERVER,"127.0.0.1:"+((WebSocketServerConfig)config).port)));
+ break;
+ case CUSTOM:
+ transport = ((CustomTransportConfig) config).getTransportInterface();
+ transport.setCallback(new SingleTransportCallbackImpl(transport.getTransportRecord()));
+ break;
+ }
+
+ }
+
+ @Override
+ public void start(){
+ if(transport != null){
+ transport.start();
+ }else{
+ System.out.print("Unable to start transport.");
+ }
+ }
+
+ @Override
+ public void close(long sessionId){
+ if(transport != null) {
+ transport.stop();
+ }
+ }
+
+ @Deprecated
+ @Override
+ public void resetSession(){
+
+ }
+
+ /**
+ * Check to see if a transport is connected.
+ * @param transportType the transport to have its connection status returned. If `null` is
+ * passed in, all transports will be checked and if any are connected a
+ * true value will be returned.
+ * @param address the address associated with the transport type. If null, the first transport
+ * of supplied type will be used to return if connected.
+ * @return if a transport is connected based on included variables
+ */
+ @Override
+ public boolean isConnected(TransportType transportType, String address){
+ synchronized (TRANSPORT_STATUS_LOCK) {
+ if (transportType == null) {
+ return !transportStatus.isEmpty();
+ }
+ for (TransportRecord record : transportStatus) {
+ if (record.getType().equals(transportType)) {
+ if (address != null) {
+ if (address.equals(record.getAddress())) {
+ return true;
+ } // Address doesn't match, move forward
+ } else {
+ //If no address is included, assume any transport of correct type is acceptable
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+ /**
+ * Retrieve a transport record with the supplied params
+ * @param transportType the transport to have its connection status returned.
+ * @param address the address associated with the transport type. If null, the first transport
+ * of supplied type will be returned.
+ * @return the transport record for the transport type and address if supplied
+ */
+ @Override
+ public TransportRecord getTransportRecord(TransportType transportType, String address){
+ synchronized (TRANSPORT_STATUS_LOCK) {
+ if (transportType == null) {
+ return null;
+ }
+ for (TransportRecord record : transportStatus) {
+ if (record.getType().equals(transportType)) {
+ if (address != null) {
+ if (address.equals(record.getAddress())) {
+ return record;
+ } // Address doesn't match, move forward
+ } else {
+ //If no address is included, assume any transport of correct type is acceptable
+ return record;
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+
+ @Override
+ public void sendPacket(SdlPacket packet){
+ if(transport !=null){
+ transport.write(packet);
+ }else {
+
+ }
+ }
+
+ class SingleTransportCallbackImpl implements TransportCallback {
+
+ final List<TransportRecord> finalList;
+ final TransportRecord record;
+ protected SingleTransportCallbackImpl(TransportRecord transportRecord){
+ record = transportRecord;
+ finalList = Collections.singletonList(record);
+ }
+
+ @Override
+ public void onConnectionEstablished() {
+ synchronized (TRANSPORT_STATUS_LOCK){
+ transportStatus.clear();
+ transportStatus.addAll(finalList);
+ }
+ transportListener.onTransportConnected(finalList);
+ }
+
+ @Override
+ public void onError() {
+ DebugTool.logError(TAG, "Error in the transport manager from the web socket server");
+ if(transportListener != null){
+ transportListener.onError("");
+ }
+ }
+
+ @Override
+ public void onConnectionTerminated(String reason) {
+ if(record != null){
+ DebugTool.logInfo(TAG, "Transport disconnected - " + record);
+ }else{
+ DebugTool.logInfo(TAG, "Transport disconnected");
+
+ }
+
+ synchronized (TRANSPORT_STATUS_LOCK){
+ TransportManager.this.transportStatus.remove(record);
+ //Might check connectedTransports vs transportStatus to ensure they are equal
+ }
+ //Inform the transport listener that a transport has disconnected
+ transportListener.onTransportDisconnected(reason, record, Collections.EMPTY_LIST);
+ }
+
+ @Override
+ public void onPacketReceived(SdlPacket packet) {
+ if(packet!=null){
+ transportListener.onPacketReceived(packet);
+ }
+ }
+ }
+
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/WebSocketServer.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/WebSocketServer.java
new file mode 100644
index 000000000..8f5411ce0
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/WebSocketServer.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2019 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.transport;
+
+import com.smartdevicelink.protocol.SdlPacket;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.SSLWebSocketFactoryGenerator;
+import com.smartdevicelink.transport.utl.TransportRecord;
+import com.smartdevicelink.util.DebugTool;
+import org.java_websocket.WebSocket;
+import org.java_websocket.WebSocketServerFactory;
+import org.java_websocket.handshake.ClientHandshake;
+
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+
+public class WebSocketServer extends org.java_websocket.server.WebSocketServer implements TransportInterface{
+ private static final String TAG = "WebSocketServer";
+ TransportCallback callback;
+ WebSocketServerConfig config;
+ WebSocket webSocket;
+ SdlPsm psm;
+
+ final TransportRecord transportRecord;
+
+ public WebSocketServer(WebSocketServerConfig config, TransportCallback callback){
+ super((new InetSocketAddress(config.port)));
+
+ this.config = config;
+ this.callback = callback;
+ transportRecord = new TransportRecord(TransportType.WEB_SOCKET_SERVER,"127.0.0.1:" + config.port); //If changed, change in transport manager as well
+ //This will set the connection lost timeout to not occur. So we might ping, but not pong
+ this.setConnectionLostTimeout(config.connectionLostTimeout);
+ if(config.getSslConfig() != null){
+ WebSocketServerFactory factory = SSLWebSocketFactoryGenerator.generateWebSocketServer(config.getSslConfig());
+ if(factory!=null){
+ this.setWebSocketFactory(factory);
+ }else{
+ DebugTool.logError(TAG, "WebSocketServer: Unable to generate SSL Web Socket Server Factory");
+ }
+ }
+
+ }
+
+ public TransportRecord getTransportRecord(){
+ return this.transportRecord;
+ }
+
+ @Override
+ public void stop(){
+ try {
+ this.stop(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void write(SdlPacket packet){
+ //DebugTool.logInfo(TAG, "Atttempt to write packet " + packet);
+ if(packet != null
+ && this.webSocket != null
+ && this.webSocket.isOpen()) {
+ this.webSocket.send(packet.constructPacket());
+ }
+
+ }
+
+ @Override
+ public void setCallback(TransportCallback callback) {
+
+ }
+
+ @Override
+ public void onOpen(WebSocket webSocket, ClientHandshake clientHandshake) {
+ DebugTool.logInfo(TAG, "onOpen");
+ this.webSocket = webSocket;
+
+ if(callback!=null){
+ callback.onConnectionEstablished();
+ }
+ }
+
+ @Override
+ public void onClose(WebSocket webSocket, int i, String s, boolean b) {
+ DebugTool.logInfo(TAG, "onClose");
+ try{
+ DebugTool.logInfo(TAG, "Closing id - " + i);
+ DebugTool.logInfo(TAG, "Closing string - " + s);
+ DebugTool.logInfo(TAG, "Closing from remote? " + b);
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+
+ if(callback!=null) {
+ callback.onConnectionTerminated(s);
+ }
+ }
+
+
+ @Override
+ public void onWebsocketCloseInitiated(WebSocket conn, int code, String reason) {
+ super.onWebsocketCloseInitiated(conn, code, reason);
+ try{
+ DebugTool.logInfo(TAG, "Code - " + code + " Reason - " + reason);
+ }catch (Exception e){}
+ }
+
+ @Override
+ public void onMessage(WebSocket webSocket, String s) {
+ DebugTool.logError(TAG, "Incorrect message type received, dropping. - String: " + s);
+ }
+
+ @Override
+ public void onMessage(WebSocket conn, ByteBuffer message) {
+ super.onMessage(conn, message);
+ //DebugTool.logInfo(TAG, "on Message - ByteBuffer");
+ byte input;
+
+ if(message != null){
+ synchronized (WebSocketServer.this) {
+ boolean stateProgress;
+ while (message.hasRemaining()) {
+ input = message.get();
+ stateProgress = psm.handleByte(input);
+ if (!stateProgress) {//We are trying to weed through the bad packet info until we get something
+
+ //DebugTool.logWarning("Packet State Machine did not move forward from state - "+ psm.getState()+". PSM being Reset.");
+ psm.reset();
+ }
+
+ if (psm.getState() == SdlPsm.FINISHED_STATE) {
+ synchronized (WebSocketServer.this) {
+ SdlPacket packet = psm.getFormedPacket();
+ if (callback != null && packet != null) {
+ /// DebugTool.logInfo(TAG, "Read a packet: " + packet);
+ packet.setTransportRecord(transportRecord);
+ callback.onPacketReceived(packet);
+ }
+ }
+ //We put a trace statement in the message read so we can avoid all the extra bytes
+ psm.reset();
+ }
+ }
+ }
+
+ }
+
+ }
+
+
+
+ @Override
+ public void onError(WebSocket webSocket, Exception e) {
+ DebugTool.logError(TAG, "bad", e);
+ if(callback!=null) {
+ callback.onError();
+ }
+ }
+
+ @Override
+ public void onStart() {
+ DebugTool.logInfo(TAG, "onStart");
+ psm = new SdlPsm();
+
+ }
+
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/WebSocketServerConfig.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/WebSocketServerConfig.java
new file mode 100644
index 000000000..23e0b25c1
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/WebSocketServerConfig.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019, Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.transport;
+
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.SSLConfig;
+
+public class WebSocketServerConfig extends BaseTransportConfig{
+
+ final int port, connectionLostTimeout;
+ SSLConfig sslConfig;
+ /**
+ * Default constructor for WebsocketConfig
+ * @param port the port this web socket should listen on
+ * @param connectionLostTimeout the timeout for a connection lost, default would be 60 seconds. If a value less than
+ * 0 is used, then the websocket will wait indefinitely.
+ */
+ public WebSocketServerConfig(int port, int connectionLostTimeout){
+ this.port = port;
+ this.connectionLostTimeout = connectionLostTimeout;
+ }
+
+ public SSLConfig getSslConfig() {
+ return sslConfig;
+ }
+
+ public void setSslConfig(SSLConfig sslConfig) {
+ this.sslConfig = sslConfig;
+ }
+
+ @Override
+ public TransportType getTransportType() {
+ return TransportType.WEB_SOCKET_SERVER;
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/utl/SSLConfig.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/utl/SSLConfig.java
new file mode 100644
index 000000000..d46e8aac6
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/utl/SSLConfig.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2019, Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.transport.utl;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.io.File;
+
+public class SSLConfig {
+
+ @IntDef({JKS, PEM})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SSLCertificateType {}
+ public static final int JKS = 0;
+ public static final int PEM = 1;
+
+
+ final @SSLCertificateType int sslCertificateType;
+ String pemCertificate, privateKey, password;
+ String storePassword, keyPassword;
+ File jksFile;
+
+
+ /**
+ * This creates an SSLConfig using a PEM type certificate.
+ * @param pemCertificate string representation of a PEM file that should be used for the SSL session
+ * @param privateKey the private key used with the PEM file
+ * @param password the password used with the PEN file
+ */
+ public SSLConfig(@NonNull String pemCertificate, @NonNull String privateKey, @NonNull String password){
+ this.sslCertificateType = PEM;
+ this.pemCertificate = pemCertificate;
+ this.privateKey = privateKey;
+ this.password = password;
+ }
+
+
+ /**
+ * This creates an SSLConfig using a JKS file.
+ * @param jksFile File that contains the JKS that should be used for the SSL session
+ * @param storePassword the password associated with the JKS
+ * @param keyPassword the key password used with the JKS
+ */
+ public SSLConfig(@NonNull File jksFile, @NonNull String storePassword, @NonNull String keyPassword){
+ this.sslCertificateType = JKS;
+ this.jksFile = jksFile;
+ this.storePassword = storePassword;
+ this.keyPassword = keyPassword;
+ }
+
+ public @SSLCertificateType int getSslCertificateType() {
+ return sslCertificateType;
+ }
+
+ public String getPemCertificate() {
+ return pemCertificate;
+ }
+
+ public String getPrivateKey() {
+ return privateKey;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+
+ public File getJksFile() {
+ return jksFile;
+ }
+
+ public String getStorePassword() {
+ return storePassword;
+ }
+
+ public String getKeyPassword() {
+ return keyPassword;
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/utl/SSLWebSocketFactoryGenerator.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/utl/SSLWebSocketFactoryGenerator.java
new file mode 100644
index 000000000..95d0ceac2
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/utl/SSLWebSocketFactoryGenerator.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2019, Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.transport.utl;
+
+import com.smartdevicelink.util.DebugTool;
+import org.java_websocket.WebSocketServerFactory;
+import org.java_websocket.server.DefaultSSLWebSocketServerFactory;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManagerFactory;
+import javax.xml.bind.DatatypeConverter;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+
+public class SSLWebSocketFactoryGenerator {
+ private static final String TAG = "SSLWebSocketFactoryGenerator";
+ private static final String JAVA_KEY_STORE = "JKS";
+ private static final String TLS = "TLS";
+ private static final String SUNX509 = "SunX509";
+
+ public static WebSocketServerFactory generateWebSocketServer(SSLConfig config){
+ SSLContext context = null;
+ switch (config.getSslCertificateType()){
+ case SSLConfig.JKS:
+ context = getSSLContextFromJKS(config);
+ break;
+ case SSLConfig.PEM:
+ context = getSSLContextFromPem(config);
+ break;
+ default:
+ DebugTool.logError(TAG, "Unable to generateWebSocketServer. Unsupported cert type.");
+ return null;
+ }
+ if(context != null) {
+ return new DefaultSSLWebSocketServerFactory(context);
+ }else{
+ DebugTool.logError(TAG, "SSLWebSocketFactoryGenerator: Unable to create SSL Context");
+ return null;
+ }
+ }
+
+/* ******************************************* JKS ********************************************/
+
+ private static SSLContext getSSLContextFromJKS(SSLConfig config){
+
+ try {
+ KeyStore ks = KeyStore.getInstance(JAVA_KEY_STORE);
+ File kf = config.getJksFile();//= new File(PATHNAME + File.separator + KEYSTORE);
+ ks.load(new FileInputStream(kf), config.getStorePassword().toCharArray());
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(SUNX509);
+ kmf.init(ks, config.getKeyPassword().toCharArray());
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(SUNX509);
+ tmf.init(ks);
+
+ SSLContext sslContext = null;
+ sslContext = SSLContext.getInstance(TLS);
+ sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ return sslContext;
+ }
+ catch(Exception e){
+ DebugTool.logError(TAG, "Issue creating SSLContext with JKS : " , e);
+ }
+ return null;
+ }
+
+ /* ******************************************* PEM ********************************************/
+
+ private static SSLContext getSSLContextFromPem(SSLConfig config) {
+ SSLContext context;
+
+ try {
+ context = SSLContext.getInstance( TLS );
+
+ byte[] certBytes = parseDERFromPEM( config.getPemCertificate().getBytes(), "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----" );
+ byte[] keyBytes = parseDERFromPEM( config.getPrivateKey().getBytes(), "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----" );
+
+ X509Certificate cert = generateCertificateFromDER( certBytes );
+ RSAPrivateKey key = generatePrivateKeyFromDER( keyBytes );
+
+ KeyStore keystore = KeyStore.getInstance( JAVA_KEY_STORE );
+ keystore.load( null );
+ keystore.setCertificateEntry( "cert-alias", cert );
+ keystore.setKeyEntry( "key-alias", key, config.getPassword().toCharArray(), new Certificate[]{ cert } );
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance( SUNX509 );
+ kmf.init( keystore, config.getPassword().toCharArray() );
+
+ KeyManager[] km = kmf.getKeyManagers();
+
+ context.init( km, null, null );
+ } catch ( Exception e ) {
+ context = null;
+ DebugTool.logError(TAG, "Issue creating SSLContext with PEM Cert : " , e);
+ }
+ return context;
+ }
+
+ private static byte[] parseDERFromPEM( byte[] pem, String beginDelimiter, String endDelimiter ) {
+ String data = new String( pem );
+ String[] tokens = data.split( beginDelimiter );
+ tokens = tokens[1].split( endDelimiter );
+ return DatatypeConverter.parseBase64Binary( tokens[0] );
+ }
+
+ private static RSAPrivateKey generatePrivateKeyFromDER( byte[] keyBytes ) throws InvalidKeySpecException, NoSuchAlgorithmException {
+ PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec( keyBytes );
+
+ KeyFactory factory = KeyFactory.getInstance( "RSA" );
+
+ return ( RSAPrivateKey ) factory.generatePrivate( spec );
+ }
+
+ private static X509Certificate generateCertificateFromDER( byte[] certBytes ) throws CertificateException {
+ CertificateFactory factory = CertificateFactory.getInstance( "X.509" );
+
+ return ( X509Certificate ) factory.generateCertificate( new ByteArrayInputStream( certBytes ) );
+ }
+
+
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/utl/TransportRecord.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/utl/TransportRecord.java
new file mode 100644
index 000000000..d8155c2fd
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/transport/utl/TransportRecord.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the SmartDeviceLink Consortium, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.smartdevicelink.transport.utl;
+
+import com.smartdevicelink.transport.enums.TransportType;
+
+public class TransportRecord extends BaseTransportRecord {
+
+ public TransportRecord(TransportType transportType, String address) {
+ super(transportType, address);
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/com/smartdevicelink/util/Log.java b/javaSE/javaSE/src/main/java/com/smartdevicelink/util/Log.java
new file mode 100644
index 000000000..2de00692c
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/com/smartdevicelink/util/Log.java
@@ -0,0 +1,19 @@
+package com.smartdevicelink.util;
+
+public class Log {
+ public static void i(String tag, String message) {
+ System.out.print("\r\nINFO: " + tag + " - " + message);
+ }
+
+ public static void w(String tag, String message) {
+ System.out.print("\r\nWARN: " + tag + " - " + message);
+ }
+
+ public static void e(String tag, String message, Throwable t) {
+ if (t != null) {
+ System.out.print("\r\nERROR: " + tag + " - " + message + " - " + t.getMessage());
+ } else {
+ System.out.print("\r\nERROR: " + tag + " - " + message);
+ }
+ }
+} \ No newline at end of file
diff --git a/javaSE/javaSE/src/main/java/org/json/JSON.java b/javaSE/javaSE/src/main/java/org/json/JSON.java
new file mode 100644
index 000000000..1b32e698d
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/org/json/JSON.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.json;
+
+class JSON {
+ /**
+ * Returns the input if it is a JSON-permissible value; throws otherwise.
+ */
+ static double checkDouble(double d) throws JSONException {
+ if (Double.isInfinite(d) || Double.isNaN(d)) {
+ throw new JSONException("Forbidden numeric value: " + d);
+ }
+ return d;
+ }
+
+ static Boolean toBoolean(Object value) {
+ if (value instanceof Boolean) {
+ return (Boolean) value;
+ } else if (value instanceof String) {
+ String stringValue = (String) value;
+ if ("true".equalsIgnoreCase(stringValue)) {
+ return true;
+ } else if ("false".equalsIgnoreCase(stringValue)) {
+ return false;
+ }
+ }
+ return null;
+ }
+
+ static Double toDouble(Object value) {
+ if (value instanceof Double) {
+ return (Double) value;
+ } else if (value instanceof Number) {
+ return ((Number) value).doubleValue();
+ } else if (value instanceof String) {
+ try {
+ return Double.valueOf((String) value);
+ } catch (NumberFormatException ignored) {
+ }
+ }
+ return null;
+ }
+
+ static Integer toInteger(Object value) {
+ if (value instanceof Integer) {
+ return (Integer) value;
+ } else if (value instanceof Number) {
+ return ((Number) value).intValue();
+ } else if (value instanceof String) {
+ try {
+ return (int) Double.parseDouble((String) value);
+ } catch (NumberFormatException ignored) {
+ }
+ }
+ return null;
+ }
+
+ static Long toLong(Object value) {
+ if (value instanceof Long) {
+ return (Long) value;
+ } else if (value instanceof Number) {
+ return ((Number) value).longValue();
+ } else if (value instanceof String) {
+ try {
+ return (long) Double.parseDouble((String) value);
+ } catch (NumberFormatException ignored) {
+ }
+ }
+ return null;
+ }
+
+ static String toString(Object value) {
+ if (value instanceof String) {
+ return (String) value;
+ } else if (value != null) {
+ return String.valueOf(value);
+ }
+ return null;
+ }
+
+ public static JSONException typeMismatch(Object indexOrName, Object actual,
+ String requiredType) throws JSONException {
+ if (actual == null) {
+ throw new JSONException("Value at " + indexOrName + " is null.");
+ } else {
+ throw new JSONException("Value " + actual + " at " + indexOrName
+ + " of type " + actual.getClass().getName()
+ + " cannot be converted to " + requiredType);
+ }
+ }
+
+ public static JSONException typeMismatch(Object actual, String requiredType)
+ throws JSONException {
+ if (actual == null) {
+ throw new JSONException("Value is null.");
+ } else {
+ throw new JSONException("Value " + actual
+ + " of type " + actual.getClass().getName()
+ + " cannot be converted to " + requiredType);
+ }
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/org/json/JSONArray.java b/javaSE/javaSE/src/main/java/org/json/JSONArray.java
new file mode 100644
index 000000000..996f44909
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/org/json/JSONArray.java
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.json;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+// Note: this class was written without inspecting the non-free org.json sourcecode.
+
+/**
+ * A dense indexed sequence of values. Values may be any mix of
+ * {@link JSONObject JSONObjects}, other {@link JSONArray JSONArrays}, Strings,
+ * Booleans, Integers, Longs, Doubles, {@code null} or {@link JSONObject#NULL}.
+ * Values may not be {@link Double#isNaN() NaNs}, {@link Double#isInfinite()
+ * infinities}, or of any type not listed here.
+ *
+ * <p>{@code JSONArray} has the same type coercion behavior and
+ * optional/mandatory accessors as {@link JSONObject}. See that class'
+ * documentation for details.
+ *
+ * <p><strong>Warning:</strong> this class represents null in two incompatible
+ * ways: the standard Java {@code null} reference, and the sentinel value {@link
+ * JSONObject#NULL}. In particular, {@code get} fails if the requested index
+ * holds the null reference, but succeeds if it holds {@code JSONObject.NULL}.
+ *
+ * <p>Instances of this class are not thread safe. Although this class is
+ * nonfinal, it was not designed for inheritance and should not be subclassed.
+ * In particular, self-use by overridable methods is not specified. See
+ * <i>Effective Java</i> Item 17, "Design and Document or inheritance or else
+ * prohibit it" for further information.
+ */
+public class JSONArray {
+
+ private final List<Object> values;
+
+ /**
+ * Creates a {@code JSONArray} with no values.
+ */
+ public JSONArray() {
+ values = new ArrayList<Object>();
+ }
+
+ /**
+ * Creates a new {@code JSONArray} by copying all values from the given
+ * collection.
+ *
+ * @param copyFrom a collection whose values are of supported types.
+ * Unsupported values are not permitted and will yield an array in an
+ * inconsistent state.
+ */
+ /* Accept a raw type for API compatibility */
+ public JSONArray(Collection copyFrom) {
+ this();
+ if (copyFrom != null) {
+ for (Iterator it = copyFrom.iterator(); it.hasNext();) {
+ put(JSONObject.wrap(it.next()));
+ }
+ }
+ }
+
+ /**
+ * Creates a new {@code JSONArray} with values from the next array in the
+ * tokener.
+ *
+ * @param readFrom a tokener whose nextValue() method will yield a
+ * {@code JSONArray}.
+ * @throws JSONException if the parse fails or doesn't yield a
+ * {@code JSONArray}.
+ */
+ public JSONArray(JSONTokener readFrom) throws JSONException {
+ /*
+ * Getting the parser to populate this could get tricky. Instead, just
+ * parse to temporary JSONArray and then steal the data from that.
+ */
+ Object object = readFrom.nextValue();
+ if (object instanceof JSONArray) {
+ values = ((JSONArray) object).values;
+ } else {
+ throw JSON.typeMismatch(object, "JSONArray");
+ }
+ }
+
+ /**
+ * Creates a new {@code JSONArray} with values from the JSON string.
+ *
+ * @param json a JSON-encoded string containing an array.
+ * @throws JSONException if the parse fails or doesn't yield a {@code
+ * JSONArray}.
+ */
+ public JSONArray(String json) throws JSONException {
+ this(new JSONTokener(json));
+ }
+
+ /**
+ * Creates a new {@code JSONArray} with values from the given primitive array.
+ */
+ public JSONArray(Object array) throws JSONException {
+ if (!array.getClass().isArray()) {
+ throw new JSONException("Not a primitive array: " + array.getClass());
+ }
+ final int length = Array.getLength(array);
+ values = new ArrayList<Object>(length);
+ for (int i = 0; i < length; ++i) {
+ put(JSONObject.wrap(Array.get(array, i)));
+ }
+ }
+
+ /**
+ * Returns the number of values in this array.
+ */
+ public int length() {
+ return values.size();
+ }
+
+ /**
+ * Appends {@code value} to the end of this array.
+ *
+ * @return this array.
+ */
+ public JSONArray put(boolean value) {
+ values.add(value);
+ return this;
+ }
+
+ /**
+ * Appends {@code value} to the end of this array.
+ *
+ * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
+ * {@link Double#isInfinite() infinities}.
+ * @return this array.
+ */
+ public JSONArray put(double value) throws JSONException {
+ values.add(JSON.checkDouble(value));
+ return this;
+ }
+
+ /**
+ * Appends {@code value} to the end of this array.
+ *
+ * @return this array.
+ */
+ public JSONArray put(int value) {
+ values.add(value);
+ return this;
+ }
+
+ /**
+ * Appends {@code value} to the end of this array.
+ *
+ * @return this array.
+ */
+ public JSONArray put(long value) {
+ values.add(value);
+ return this;
+ }
+
+ /**
+ * Appends {@code value} to the end of this array.
+ *
+ * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
+ * Integer, Long, Double, {@link JSONObject#NULL}, or {@code null}. May
+ * not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite()
+ * infinities}. Unsupported values are not permitted and will cause the
+ * array to be in an inconsistent state.
+ * @return this array.
+ */
+ public JSONArray put(Object value) {
+ values.add(value);
+ return this;
+ }
+
+ /**
+ * Same as {@link #put}, with added validity checks.
+ */
+ void checkedPut(Object value) throws JSONException {
+ if (value instanceof Number) {
+ JSON.checkDouble(((Number) value).doubleValue());
+ }
+
+ put(value);
+ }
+
+ /**
+ * Sets the value at {@code index} to {@code value}, null padding this array
+ * to the required length if necessary. If a value already exists at {@code
+ * index}, it will be replaced.
+ *
+ * @return this array.
+ */
+ public JSONArray put(int index, boolean value) throws JSONException {
+ return put(index, (Boolean) value);
+ }
+
+ /**
+ * Sets the value at {@code index} to {@code value}, null padding this array
+ * to the required length if necessary. If a value already exists at {@code
+ * index}, it will be replaced.
+ *
+ * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
+ * {@link Double#isInfinite() infinities}.
+ * @return this array.
+ */
+ public JSONArray put(int index, double value) throws JSONException {
+ return put(index, (Double) value);
+ }
+
+ /**
+ * Sets the value at {@code index} to {@code value}, null padding this array
+ * to the required length if necessary. If a value already exists at {@code
+ * index}, it will be replaced.
+ *
+ * @return this array.
+ */
+ public JSONArray put(int index, int value) throws JSONException {
+ return put(index, (Integer) value);
+ }
+
+ /**
+ * Sets the value at {@code index} to {@code value}, null padding this array
+ * to the required length if necessary. If a value already exists at {@code
+ * index}, it will be replaced.
+ *
+ * @return this array.
+ */
+ public JSONArray put(int index, long value) throws JSONException {
+ return put(index, (Long) value);
+ }
+
+ /**
+ * Sets the value at {@code index} to {@code value}, null padding this array
+ * to the required length if necessary. If a value already exists at {@code
+ * index}, it will be replaced.
+ *
+ * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
+ * Integer, Long, Double, {@link JSONObject#NULL}, or {@code null}. May
+ * not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite()
+ * infinities}.
+ * @return this array.
+ */
+ public JSONArray put(int index, Object value) throws JSONException {
+ if (value instanceof Number) {
+ // deviate from the original by checking all Numbers, not just floats & doubles
+ JSON.checkDouble(((Number) value).doubleValue());
+ }
+ while (values.size() <= index) {
+ values.add(null);
+ }
+ values.set(index, value);
+ return this;
+ }
+
+ /**
+ * Returns true if this array has no value at {@code index}, or if its value
+ * is the {@code null} reference or {@link JSONObject#NULL}.
+ */
+ public boolean isNull(int index) {
+ Object value = opt(index);
+ return value == null || value == JSONObject.NULL;
+ }
+
+ /**
+ * Returns the value at {@code index}.
+ *
+ * @throws JSONException if this array has no value at {@code index}, or if
+ * that value is the {@code null} reference. This method returns
+ * normally if the value is {@code JSONObject#NULL}.
+ */
+ public Object get(int index) throws JSONException {
+ try {
+ Object value = values.get(index);
+ if (value == null) {
+ throw new JSONException("Value at " + index + " is null.");
+ }
+ return value;
+ } catch (IndexOutOfBoundsException e) {
+ throw new JSONException("Index " + index + " out of range [0.." + values.size() + ")", e);
+ }
+ }
+
+ /**
+ * Returns the value at {@code index}, or null if the array has no value
+ * at {@code index}.
+ */
+ public Object opt(int index) {
+ if (index < 0 || index >= values.size()) {
+ return null;
+ }
+ return values.get(index);
+ }
+
+ /**
+ * Removes and returns the value at {@code index}, or null if the array has no value
+ * at {@code index}.
+ */
+ public Object remove(int index) {
+ if (index < 0 || index >= values.size()) {
+ return null;
+ }
+ return values.remove(index);
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is a boolean or can
+ * be coerced to a boolean.
+ *
+ * @throws JSONException if the value at {@code index} doesn't exist or
+ * cannot be coerced to a boolean.
+ */
+ public boolean getBoolean(int index) throws JSONException {
+ Object object = get(index);
+ Boolean result = JSON.toBoolean(object);
+ if (result == null) {
+ throw JSON.typeMismatch(index, object, "boolean");
+ }
+ return result;
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is a boolean or can
+ * be coerced to a boolean. Returns false otherwise.
+ */
+ public boolean optBoolean(int index) {
+ return optBoolean(index, false);
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is a boolean or can
+ * be coerced to a boolean. Returns {@code fallback} otherwise.
+ */
+ public boolean optBoolean(int index, boolean fallback) {
+ Object object = opt(index);
+ Boolean result = JSON.toBoolean(object);
+ return result != null ? result : fallback;
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is a double or can
+ * be coerced to a double.
+ *
+ * @throws JSONException if the value at {@code index} doesn't exist or
+ * cannot be coerced to a double.
+ */
+ public double getDouble(int index) throws JSONException {
+ Object object = get(index);
+ Double result = JSON.toDouble(object);
+ if (result == null) {
+ throw JSON.typeMismatch(index, object, "double");
+ }
+ return result;
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is a double or can
+ * be coerced to a double. Returns {@code NaN} otherwise.
+ */
+ public double optDouble(int index) {
+ return optDouble(index, Double.NaN);
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is a double or can
+ * be coerced to a double. Returns {@code fallback} otherwise.
+ */
+ public double optDouble(int index, double fallback) {
+ Object object = opt(index);
+ Double result = JSON.toDouble(object);
+ return result != null ? result : fallback;
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is an int or
+ * can be coerced to an int.
+ *
+ * @throws JSONException if the value at {@code index} doesn't exist or
+ * cannot be coerced to a int.
+ */
+ public int getInt(int index) throws JSONException {
+ Object object = get(index);
+ Integer result = JSON.toInteger(object);
+ if (result == null) {
+ throw JSON.typeMismatch(index, object, "int");
+ }
+ return result;
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is an int or
+ * can be coerced to an int. Returns 0 otherwise.
+ */
+ public int optInt(int index) {
+ return optInt(index, 0);
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is an int or
+ * can be coerced to an int. Returns {@code fallback} otherwise.
+ */
+ public int optInt(int index, int fallback) {
+ Object object = opt(index);
+ Integer result = JSON.toInteger(object);
+ return result != null ? result : fallback;
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is a long or
+ * can be coerced to a long.
+ *
+ * @throws JSONException if the value at {@code index} doesn't exist or
+ * cannot be coerced to a long.
+ */
+ public long getLong(int index) throws JSONException {
+ Object object = get(index);
+ Long result = JSON.toLong(object);
+ if (result == null) {
+ throw JSON.typeMismatch(index, object, "long");
+ }
+ return result;
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is a long or
+ * can be coerced to a long. Returns 0 otherwise.
+ */
+ public long optLong(int index) {
+ return optLong(index, 0L);
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is a long or
+ * can be coerced to a long. Returns {@code fallback} otherwise.
+ */
+ public long optLong(int index, long fallback) {
+ Object object = opt(index);
+ Long result = JSON.toLong(object);
+ return result != null ? result : fallback;
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists, coercing it if
+ * necessary.
+ *
+ * @throws JSONException if no such value exists.
+ */
+ public String getString(int index) throws JSONException {
+ Object object = get(index);
+ String result = JSON.toString(object);
+ if (result == null) {
+ throw JSON.typeMismatch(index, object, "String");
+ }
+ return result;
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists, coercing it if
+ * necessary. Returns the empty string if no such value exists.
+ */
+ public String optString(int index) {
+ return optString(index, "");
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists, coercing it if
+ * necessary. Returns {@code fallback} if no such value exists.
+ */
+ public String optString(int index, String fallback) {
+ Object object = opt(index);
+ String result = JSON.toString(object);
+ return result != null ? result : fallback;
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is a {@code
+ * JSONArray}.
+ *
+ * @throws JSONException if the value doesn't exist or is not a {@code
+ * JSONArray}.
+ */
+ public JSONArray getJSONArray(int index) throws JSONException {
+ Object object = get(index);
+ if (object instanceof JSONArray) {
+ return (JSONArray) object;
+ } else {
+ throw JSON.typeMismatch(index, object, "JSONArray");
+ }
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is a {@code
+ * JSONArray}. Returns null otherwise.
+ */
+ public JSONArray optJSONArray(int index) {
+ Object object = opt(index);
+ return object instanceof JSONArray ? (JSONArray) object : null;
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is a {@code
+ * JSONObject}.
+ *
+ * @throws JSONException if the value doesn't exist or is not a {@code
+ * JSONObject}.
+ */
+ public JSONObject getJSONObject(int index) throws JSONException {
+ Object object = get(index);
+ if (object instanceof JSONObject) {
+ return (JSONObject) object;
+ } else {
+ throw JSON.typeMismatch(index, object, "JSONObject");
+ }
+ }
+
+ /**
+ * Returns the value at {@code index} if it exists and is a {@code
+ * JSONObject}. Returns null otherwise.
+ */
+ public JSONObject optJSONObject(int index) {
+ Object object = opt(index);
+ return object instanceof JSONObject ? (JSONObject) object : null;
+ }
+
+ /**
+ * Returns a new object whose values are the values in this array, and whose
+ * names are the values in {@code names}. Names and values are paired up by
+ * index from 0 through to the shorter array's length. Names that are not
+ * strings will be coerced to strings. This method returns null if either
+ * array is empty.
+ */
+ public JSONObject toJSONObject(JSONArray names) throws JSONException {
+ JSONObject result = new JSONObject();
+ int length = Math.min(names.length(), values.size());
+ if (length == 0) {
+ return null;
+ }
+ for (int i = 0; i < length; i++) {
+ String name = JSON.toString(names.opt(i));
+ result.put(name, opt(i));
+ }
+ return result;
+ }
+
+ /**
+ * Returns a new string by alternating this array's values with {@code
+ * separator}. This array's string values are quoted and have their special
+ * characters escaped. For example, the array containing the strings '12"
+ * pizza', 'taco' and 'soda' joined on '+' returns this:
+ * <pre>"12\" pizza"+"taco"+"soda"</pre>
+ */
+ public String join(String separator) throws JSONException {
+ JSONStringer stringer = new JSONStringer();
+ stringer.open(JSONStringer.Scope.NULL, "");
+ for (int i = 0, size = values.size(); i < size; i++) {
+ if (i > 0) {
+ stringer.out.append(separator);
+ }
+ stringer.value(values.get(i));
+ }
+ stringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, "");
+ return stringer.out.toString();
+ }
+
+ /**
+ * Encodes this array as a compact JSON string, such as:
+ * <pre>[94043,90210]</pre>
+ */
+ @Override public String toString() {
+ try {
+ JSONStringer stringer = new JSONStringer();
+ writeTo(stringer);
+ return stringer.toString();
+ } catch (JSONException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Encodes this array as a human readable JSON string for debugging, such
+ * as:
+ * <pre>
+ * [
+ * 94043,
+ * 90210
+ * ]</pre>
+ *
+ * @param indentSpaces the number of spaces to indent for each level of
+ * nesting.
+ */
+ public String toString(int indentSpaces) throws JSONException {
+ JSONStringer stringer = new JSONStringer(indentSpaces);
+ writeTo(stringer);
+ return stringer.toString();
+ }
+
+ void writeTo(JSONStringer stringer) throws JSONException {
+ stringer.array();
+ for (Object value : values) {
+ stringer.value(value);
+ }
+ stringer.endArray();
+ }
+
+ @Override public boolean equals(Object o) {
+ return o instanceof JSONArray && ((JSONArray) o).values.equals(values);
+ }
+
+ @Override public int hashCode() {
+ // diverge from the original, which doesn't implement hashCode
+ return values.hashCode();
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/org/json/JSONException.java b/javaSE/javaSE/src/main/java/org/json/JSONException.java
new file mode 100644
index 000000000..05e1dddc9
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/org/json/JSONException.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.json;
+
+// Note: this class was written without inspecting the non-free org.json sourcecode.
+
+/**
+ * Thrown to indicate a problem with the JSON API. Such problems include:
+ * <ul>
+ * <li>Attempts to parse or construct malformed documents
+ * <li>Use of null as a name
+ * <li>Use of numeric types not available to JSON, such as {@link
+ * Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}.
+ * <li>Lookups using an out of range index or nonexistent name
+ * <li>Type mismatches on lookups
+ * </ul>
+ *
+ * <p>Although this is a checked exception, it is rarely recoverable. Most
+ * callers should simply wrap this exception in an unchecked exception and
+ * rethrow:
+ * <pre> public JSONArray toJSONObject() {
+ * try {
+ * JSONObject result = new JSONObject();
+ * ...
+ * } catch (JSONException e) {
+ * throw new RuntimeException(e);
+ * }
+ * }</pre>
+ */
+public class JSONException extends Exception {
+
+ public JSONException(String s) {
+ super(s);
+ }
+
+ public JSONException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public JSONException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/javaSE/javaSE/src/main/java/org/json/JSONObject.java b/javaSE/javaSE/src/main/java/org/json/JSONObject.java
new file mode 100644
index 000000000..74ea973c2
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/org/json/JSONObject.java
@@ -0,0 +1,829 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.json;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+// Note: this class was written without inspecting the non-free org.json sourcecode.
+
+/**
+ * A modifiable set of name/value mappings. Names are unique, non-null strings.
+ * Values may be any mix of {@link JSONObject JSONObjects}, {@link JSONArray
+ * JSONArrays}, Strings, Booleans, Integers, Longs, Doubles or {@link #NULL}.
+ * Values may not be {@code null}, {@link Double#isNaN() NaNs}, {@link
+ * Double#isInfinite() infinities}, or of any type not listed here.
+ *
+ * <p>This class can coerce values to another type when requested.
+ * <ul>
+ * <li>When the requested type is a boolean, strings will be coerced using a
+ * case-insensitive comparison to "true" and "false".
+ * <li>When the requested type is a double, other {@link Number} types will
+ * be coerced using {@link Number#doubleValue() doubleValue}. Strings
+ * that can be coerced using {@link Double#valueOf(String)} will be.
+ * <li>When the requested type is an int, other {@link Number} types will
+ * be coerced using {@link Number#intValue() intValue}. Strings
+ * that can be coerced using {@link Double#valueOf(String)} will be,
+ * and then cast to int.
+ * <li><a name="lossy">When the requested type is a long, other {@link Number} types will
+ * be coerced using {@link Number#longValue() longValue}. Strings
+ * that can be coerced using {@link Double#valueOf(String)} will be,
+ * and then cast to long. This two-step conversion is lossy for very
+ * large values. For example, the string "9223372036854775806" yields the
+ * long 9223372036854775807.</a>
+ * <li>When the requested type is a String, other non-null values will be
+ * coerced using {@link String#valueOf(Object)}. Although null cannot be
+ * coerced, the sentinel value {@link JSONObject#NULL} is coerced to the
+ * string "null".
+ * </ul>
+ *
+ * <p>This class can look up both mandatory and optional values:
+ * <ul>
+ * <li>Use <code>get<i>Type</i>()</code> to retrieve a mandatory value. This
+ * fails with a {@code JSONException} if the requested name has no value
+ * or if the value cannot be coerced to the requested type.
+ * <li>Use <code>opt<i>Type</i>()</code> to retrieve an optional value. This
+ * returns a system- or user-supplied default if the requested name has no
+ * value or if the value cannot be coerced to the requested type.
+ * </ul>
+ *
+ * <p><strong>Warning:</strong> this class represents null in two incompatible
+ * ways: the standard Java {@code null} reference, and the sentinel value {@link
+ * JSONObject#NULL}. In particular, calling {@code put(name, null)} removes the
+ * named entry from the object but {@code put(name, JSONObject.NULL)} stores an
+ * entry whose value is {@code JSONObject.NULL}.
+ *
+ * <p>Instances of this class are not thread safe. Although this class is
+ * nonfinal, it was not designed for inheritance and should not be subclassed.
+ * In particular, self-use by overrideable methods is not specified. See
+ * <i>Effective Java</i> Item 17, "Design and Document or inheritance or else
+ * prohibit it" for further information.
+ */
+public class JSONObject {
+
+ private static final Double NEGATIVE_ZERO = -0d;
+
+ /**
+ * A sentinel value used to explicitly define a name with no value. Unlike
+ * {@code null}, names with this value:
+ * <ul>
+ * <li>show up in the {@link #names} array
+ * <li>show up in the {@link #keys} iterator
+ * <li>return {@code true} for {@link #has(String)}
+ * <li>do not throw on {@link #get(String)}
+ * <li>are included in the encoded JSON string.
+ * </ul>
+ *
+ * <p>This value violates the general contract of {@link Object#equals} by
+ * returning true when compared to {@code null}. Its {@link #toString}
+ * method returns "null".
+ */
+ @NonNull
+ public static final Object NULL = new Object() {
+ @Override public boolean equals(Object o) {
+ return o == this || o == null; // API specifies this broken equals implementation
+ }
+ // at least make the broken equals(null) consistent with Objects.hashCode(null).
+ @Override public int hashCode() { return Objects.hashCode(null); }
+ @Override public String toString() {
+ return "null";
+ }
+ };
+
+
+ private final LinkedHashMap<String, Object> nameValuePairs;
+
+ /**
+ * Creates a {@code JSONObject} with no name/value mappings.
+ */
+ public JSONObject() {
+ nameValuePairs = new LinkedHashMap<String, Object>();
+ }
+
+ /**
+ * Creates a new {@code JSONObject} by copying all name/value mappings from
+ * the given map.
+ *
+ * @param copyFrom a map whose keys are of type {@link String} and whose
+ * values are of supported types.
+ * @throws NullPointerException if any of the map's keys are null.
+ */
+ /* (accept a raw type for API compatibility) */
+ public JSONObject(@NonNull Map copyFrom) {
+ this();
+ Map<?, ?> contentsTyped = (Map<?, ?>) copyFrom;
+ for (Map.Entry<?, ?> entry : contentsTyped.entrySet()) {
+ /*
+ * Deviate from the original by checking that keys are non-null and
+ * of the proper type. (We still defer validating the values).
+ */
+ String key = (String) entry.getKey();
+ if (key == null) {
+ throw new NullPointerException("key == null");
+ }
+ nameValuePairs.put(key, wrap(entry.getValue()));
+ }
+ }
+
+ /**
+ * Creates a new {@code JSONObject} with name/value mappings from the next
+ * object in the tokener.
+ *
+ * @param readFrom a tokener whose nextValue() method will yield a
+ * {@code JSONObject}.
+ * @throws JSONException if the parse fails or doesn't yield a
+ * {@code JSONObject}.
+ */
+ public JSONObject(@NonNull JSONTokener readFrom) throws JSONException {
+ /*
+ * Getting the parser to populate this could get tricky. Instead, just
+ * parse to temporary JSONObject and then steal the data from that.
+ */
+ Object object = readFrom.nextValue();
+ if (object instanceof JSONObject) {
+ this.nameValuePairs = ((JSONObject) object).nameValuePairs;
+ } else {
+ throw JSON.typeMismatch(object, "JSONObject");
+ }
+ }
+
+ /**
+ * Creates a new {@code JSONObject} with name/value mappings from the JSON
+ * string.
+ *
+ * @param json a JSON-encoded string containing an object.
+ * @throws JSONException if the parse fails or doesn't yield a {@code
+ * JSONObject}.
+ */
+ public JSONObject(@NonNull String json) throws JSONException {
+ this(new JSONTokener(json));
+ }
+
+ /**
+ * Creates a new {@code JSONObject} by copying mappings for the listed names
+ * from the given object. Names that aren't present in {@code copyFrom} will
+ * be skipped.
+ */
+ public JSONObject(@NonNull JSONObject copyFrom, @NonNull String [] names) throws JSONException {
+ this();
+ for (String name : names) {
+ Object value = copyFrom.opt(name);
+ if (value != null) {
+ nameValuePairs.put(name, value);
+ }
+ }
+ }
+
+ /**
+ * Returns the number of name/value mappings in this object.
+ */
+ public int length() {
+ return nameValuePairs.size();
+ }
+
+ /**
+ * Maps {@code name} to {@code value}, clobbering any existing name/value
+ * mapping with the same name.
+ *
+ * @return this object.
+ */
+ @NonNull public JSONObject put(@NonNull String name, boolean value) throws JSONException {
+ nameValuePairs.put(checkName(name), value);
+ return this;
+ }
+
+ /**
+ * Maps {@code name} to {@code value}, clobbering any existing name/value
+ * mapping with the same name.
+ *
+ * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
+ * {@link Double#isInfinite() infinities}.
+ * @return this object.
+ */
+ @NonNull public JSONObject put(@NonNull String name, double value) throws JSONException {
+ nameValuePairs.put(checkName(name), JSON.checkDouble(value));
+ return this;
+ }
+
+ /**
+ * Maps {@code name} to {@code value}, clobbering any existing name/value
+ * mapping with the same name.
+ *
+ * @return this object.
+ */
+ @NonNull public JSONObject put(@NonNull String name, int value) throws JSONException {
+ nameValuePairs.put(checkName(name), value);
+ return this;
+ }
+
+ /**
+ * Maps {@code name} to {@code value}, clobbering any existing name/value
+ * mapping with the same name.
+ *
+ * @return this object.
+ */
+ @NonNull public JSONObject put(@NonNull String name, long value) throws JSONException {
+ nameValuePairs.put(checkName(name), value);
+ return this;
+ }
+
+ /**
+ * Maps {@code name} to {@code value}, clobbering any existing name/value
+ * mapping with the same name. If the value is {@code null}, any existing
+ * mapping for {@code name} is removed.
+ *
+ * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
+ * Integer, Long, Double, {@link #NULL}, or {@code null}. May not be
+ * {@link Double#isNaN() NaNs} or {@link Double#isInfinite()
+ * infinities}.
+ * @return this object.
+ */
+ @NonNull public JSONObject put(@NonNull String name, @Nullable Object value) throws JSONException {
+ if (value == null) {
+ nameValuePairs.remove(name);
+ return this;
+ }
+ if (value instanceof Number) {
+ // deviate from the original by checking all Numbers, not just floats & doubles
+ JSON.checkDouble(((Number) value).doubleValue());
+ }
+ nameValuePairs.put(checkName(name), value);
+ return this;
+ }
+
+ /**
+ * Equivalent to {@code put(name, value)} when both parameters are non-null;
+ * does nothing otherwise.
+ */
+ @NonNull public JSONObject putOpt(@Nullable String name, @Nullable Object value) throws JSONException {
+ if (name == null || value == null) {
+ return this;
+ }
+ return put(name, value);
+ }
+
+ /**
+ * Appends {@code value} to the array already mapped to {@code name}. If
+ * this object has no mapping for {@code name}, this inserts a new mapping.
+ * If the mapping exists but its value is not an array, the existing
+ * and new values are inserted in order into a new array which is itself
+ * mapped to {@code name}. In aggregate, this allows values to be added to a
+ * mapping one at a time.
+ *
+ * <p> Note that {@code append(String, Object)} provides better semantics.
+ * In particular, the mapping for {@code name} will <b>always</b> be a
+ * {@link JSONArray}. Using {@code accumulate} will result in either a
+ * {@link JSONArray} or a mapping whose type is the type of {@code value}
+ * depending on the number of calls to it.
+ *
+ * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
+ * Integer, Long, Double, {@link #NULL} or null. May not be {@link
+ * Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}.
+ */
+ // TODO: Change {@code append) to {@link #append} when append is
+ // unhidden.
+ @NonNull public JSONObject accumulate(@NonNull String name, @Nullable Object value) throws JSONException {
+ Object current = nameValuePairs.get(checkName(name));
+ if (current == null) {
+ return put(name, value);
+ }
+
+ if (current instanceof JSONArray) {
+ JSONArray array = (JSONArray) current;
+ array.checkedPut(value);
+ } else {
+ JSONArray array = new JSONArray();
+ array.checkedPut(current);
+ array.checkedPut(value);
+ nameValuePairs.put(name, array);
+ }
+ return this;
+ }
+
+ /**
+ * Appends values to the array mapped to {@code name}. A new {@link JSONArray}
+ * mapping for {@code name} will be inserted if no mapping exists. If the existing
+ * mapping for {@code name} is not a {@link JSONArray}, a {@link JSONException}
+ * will be thrown.
+ *
+ * @throws JSONException if {@code name} is {@code null} or if the mapping for
+ * {@code name} is non-null and is not a {@link JSONArray}.
+ *
+ */
+ public JSONObject append(String name, Object value) throws JSONException {
+ Object current = nameValuePairs.get(checkName(name));
+
+ final JSONArray array;
+ if (current instanceof JSONArray) {
+ array = (JSONArray) current;
+ } else if (current == null) {
+ JSONArray newArray = new JSONArray();
+ nameValuePairs.put(name, newArray);
+ array = newArray;
+ } else {
+ throw new JSONException("Key " + name + " is not a JSONArray");
+ }
+
+ array.checkedPut(value);
+
+ return this;
+ }
+
+ String checkName(String name) throws JSONException {
+ if (name == null) {
+ throw new JSONException("Names must be non-null");
+ }
+ return name;
+ }
+
+ /**
+ * Removes the named mapping if it exists; does nothing otherwise.
+ *
+ * @return the value previously mapped by {@code name}, or null if there was
+ * no such mapping.
+ */
+ @Nullable public Object remove(@Nullable String name) {
+ return nameValuePairs.remove(name);
+ }
+
+ /**
+ * Returns true if this object has no mapping for {@code name} or if it has
+ * a mapping whose value is {@link #NULL}.
+ */
+ public boolean isNull(@Nullable String name) {
+ Object value = nameValuePairs.get(name);
+ return value == null || value == NULL;
+ }
+
+ /**
+ * Returns true if this object has a mapping for {@code name}. The mapping
+ * may be {@link #NULL}.
+ */
+ public boolean has(@Nullable String name) {
+ return nameValuePairs.containsKey(name);
+ }
+
+ /**
+ * Returns the value mapped by {@code name}, or throws if no such mapping exists.
+ *
+ * @throws JSONException if no such mapping exists.
+ */
+ @NonNull public Object get(@NonNull String name) throws JSONException {
+ Object result = nameValuePairs.get(name);
+ if (result == null) {
+ throw new JSONException("No value for " + name);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the value mapped by {@code name}, or null if no such mapping
+ * exists.
+ */
+ @Nullable public Object opt(@Nullable String name) {
+ return nameValuePairs.get(name);
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is a boolean or
+ * can be coerced to a boolean, or throws otherwise.
+ *
+ * @throws JSONException if the mapping doesn't exist or cannot be coerced
+ * to a boolean.
+ */
+ public boolean getBoolean(@NonNull String name) throws JSONException {
+ Object object = get(name);
+ Boolean result = JSON.toBoolean(object);
+ if (result == null) {
+ throw JSON.typeMismatch(name, object, "boolean");
+ }
+ return result;
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is a boolean or
+ * can be coerced to a boolean, or false otherwise.
+ */
+ public boolean optBoolean(@Nullable String name) {
+ return optBoolean(name, false);
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is a boolean or
+ * can be coerced to a boolean, or {@code fallback} otherwise.
+ */
+ public boolean optBoolean(@Nullable String name, boolean fallback) {
+ Object object = opt(name);
+ Boolean result = JSON.toBoolean(object);
+ return result != null ? result : fallback;
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is a double or
+ * can be coerced to a double, or throws otherwise.
+ *
+ * @throws JSONException if the mapping doesn't exist or cannot be coerced
+ * to a double.
+ */
+ public double getDouble(@NonNull String name) throws JSONException {
+ Object object = get(name);
+ Double result = JSON.toDouble(object);
+ if (result == null) {
+ throw JSON.typeMismatch(name, object, "double");
+ }
+ return result;
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is a double or
+ * can be coerced to a double, or {@code NaN} otherwise.
+ */
+ public double optDouble(@Nullable String name) {
+ return optDouble(name, Double.NaN);
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is a double or
+ * can be coerced to a double, or {@code fallback} otherwise.
+ */
+ public double optDouble(@Nullable String name, double fallback) {
+ Object object = opt(name);
+ Double result = JSON.toDouble(object);
+ return result != null ? result : fallback;
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is an int or
+ * can be coerced to an int, or throws otherwise.
+ *
+ * @throws JSONException if the mapping doesn't exist or cannot be coerced
+ * to an int.
+ */
+ public int getInt(@NonNull String name) throws JSONException {
+ Object object = get(name);
+ Integer result = JSON.toInteger(object);
+ if (result == null) {
+ throw JSON.typeMismatch(name, object, "int");
+ }
+ return result;
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is an int or
+ * can be coerced to an int, or 0 otherwise.
+ */
+ public int optInt(@Nullable String name) {
+ return optInt(name, 0);
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is an int or
+ * can be coerced to an int, or {@code fallback} otherwise.
+ */
+ public int optInt(@Nullable String name, int fallback) {
+ Object object = opt(name);
+ Integer result = JSON.toInteger(object);
+ return result != null ? result : fallback;
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is a long or
+ * can be coerced to a long, or throws otherwise.
+ * Note that JSON represents numbers as doubles,
+ * so this is <a href="#lossy">lossy</a>; use strings to transfer numbers via JSON.
+ *
+ * @throws JSONException if the mapping doesn't exist or cannot be coerced
+ * to a long.
+ */
+ public long getLong(@NonNull String name) throws JSONException {
+ Object object = get(name);
+ Long result = JSON.toLong(object);
+ if (result == null) {
+ throw JSON.typeMismatch(name, object, "long");
+ }
+ return result;
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is a long or
+ * can be coerced to a long, or 0 otherwise. Note that JSON represents numbers as doubles,
+ * so this is <a href="#lossy">lossy</a>; use strings to transfer numbers via JSON.
+ */
+ public long optLong(@Nullable String name) {
+ return optLong(name, 0L);
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is a long or
+ * can be coerced to a long, or {@code fallback} otherwise. Note that JSON represents
+ * numbers as doubles, so this is <a href="#lossy">lossy</a>; use strings to transfer
+ * numbers via JSON.
+ */
+ public long optLong(@Nullable String name, long fallback) {
+ Object object = opt(name);
+ Long result = JSON.toLong(object);
+ return result != null ? result : fallback;
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists, coercing it if
+ * necessary, or throws if no such mapping exists.
+ *
+ * @throws JSONException if no such mapping exists.
+ */
+ @NonNull public String getString(@NonNull String name) throws JSONException {
+ Object object = get(name);
+ String result = JSON.toString(object);
+ if (result == null) {
+ throw JSON.typeMismatch(name, object, "String");
+ }
+ return result;
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists, coercing it if
+ * necessary, or the empty string if no such mapping exists.
+ */
+ @NonNull public String optString(@Nullable String name) {
+ return optString(name, "");
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists, coercing it if
+ * necessary, or {@code fallback} if no such mapping exists.
+ */
+ @NonNull public String optString(@Nullable String name, @NonNull String fallback) {
+ Object object = opt(name);
+ String result = JSON.toString(object);
+ return result != null ? result : fallback;
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is a {@code
+ * JSONArray}, or throws otherwise.
+ *
+ * @throws JSONException if the mapping doesn't exist or is not a {@code
+ * JSONArray}.
+ */
+ @NonNull public JSONArray getJSONArray(@NonNull String name) throws JSONException {
+ Object object = get(name);
+ if (object instanceof JSONArray) {
+ return (JSONArray) object;
+ } else {
+ throw JSON.typeMismatch(name, object, "JSONArray");
+ }
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is a {@code
+ * JSONArray}, or null otherwise.
+ */
+ @Nullable public JSONArray optJSONArray(@Nullable String name) {
+ Object object = opt(name);
+ return object instanceof JSONArray ? (JSONArray) object : null;
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is a {@code
+ * JSONObject}, or throws otherwise.
+ *
+ * @throws JSONException if the mapping doesn't exist or is not a {@code
+ * JSONObject}.
+ */
+ @NonNull public JSONObject getJSONObject(@NonNull String name) throws JSONException {
+ Object object = get(name);
+ if (object instanceof JSONObject) {
+ return (JSONObject) object;
+ } else {
+ throw JSON.typeMismatch(name, object, "JSONObject");
+ }
+ }
+
+ /**
+ * Returns the value mapped by {@code name} if it exists and is a {@code
+ * JSONObject}, or null otherwise.
+ */
+ @Nullable public JSONObject optJSONObject(@Nullable String name) {
+ Object object = opt(name);
+ return object instanceof JSONObject ? (JSONObject) object : null;
+ }
+
+ /**
+ * Returns an array with the values corresponding to {@code names}. The
+ * array contains null for names that aren't mapped. This method returns
+ * null if {@code names} is either null or empty.
+ */
+ @Nullable public JSONArray toJSONArray(@Nullable JSONArray names) throws JSONException {
+ JSONArray result = new JSONArray();
+ if (names == null) {
+ return null;
+ }
+ int length = names.length();
+ if (length == 0) {
+ return null;
+ }
+ for (int i = 0; i < length; i++) {
+ String name = JSON.toString(names.opt(i));
+ result.put(opt(name));
+ }
+ return result;
+ }
+
+ /**
+ * Returns an iterator of the {@code String} names in this object. The
+ * returned iterator supports {@link Iterator#remove() remove}, which will
+ * remove the corresponding mapping from this object. If this object is
+ * modified after the iterator is returned, the iterator's behavior is
+ * undefined. The order of the keys is undefined.
+ */
+ @NonNull public Iterator<String> keys() {
+ return nameValuePairs.keySet().iterator();
+ }
+
+ /**
+ * Returns the set of {@code String} names in this object. The returned set
+ * is a view of the keys in this object. {@link Set#remove(Object)} will remove
+ * the corresponding mapping from this object and set iterator behaviour
+ * is undefined if this object is modified after it is returned.
+ *
+ * See {@link #keys()}.
+ *
+ */
+ public Set<String> keySet() {
+ return nameValuePairs.keySet();
+ }
+
+ /**
+ * Returns an array containing the string names in this object. This method
+ * returns null if this object contains no mappings.
+ */
+ @Nullable public JSONArray names() {
+ return nameValuePairs.isEmpty()
+ ? null
+ : new JSONArray(new ArrayList<String>(nameValuePairs.keySet()));
+ }
+
+ /**
+ * Encodes this object as a compact JSON string, such as:
+ * <pre>{"query":"Pizza","locations":[94043,90210]}</pre>
+ */
+ @Override @NonNull public String toString() {
+ try {
+ JSONStringer stringer = new JSONStringer();
+ writeTo(stringer);
+ return stringer.toString();
+ } catch (JSONException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Encodes this object as a human readable JSON string for debugging, such
+ * as:
+ * <pre>
+ * {
+ * "query": "Pizza",
+ * "locations": [
+ * 94043,
+ * 90210
+ * ]
+ * }</pre>
+ *
+ * @param indentSpaces the number of spaces to indent for each level of
+ * nesting.
+ */
+ @NonNull public String toString(int indentSpaces) throws JSONException {
+ JSONStringer stringer = new JSONStringer(indentSpaces);
+ writeTo(stringer);
+ return stringer.toString();
+ }
+
+
+ void writeTo(JSONStringer stringer) throws JSONException {
+ stringer.object();
+ for (Map.Entry<String, Object> entry : nameValuePairs.entrySet()) {
+ stringer.key(entry.getKey()).value(entry.getValue());
+ }
+ stringer.endObject();
+ }
+
+ /**
+ * Encodes the number as a JSON string.
+ *
+ * @param number a finite value. May not be {@link Double#isNaN() NaNs} or
+ * {@link Double#isInfinite() infinities}.
+ */
+ @NonNull public static String numberToString(@NonNull Number number) throws JSONException {
+ if (number == null) {
+ throw new JSONException("Number must be non-null");
+ }
+
+ double doubleValue = number.doubleValue();
+ JSON.checkDouble(doubleValue);
+
+ // the original returns "-0" instead of "-0.0" for negative zero
+ if (number.equals(NEGATIVE_ZERO)) {
+ return "-0";
+ }
+
+ long longValue = number.longValue();
+ if (doubleValue == (double) longValue) {
+ return Long.toString(longValue);
+ }
+
+ return number.toString();
+ }
+
+ /**
+ * Encodes {@code data} as a JSON string. This applies quotes and any
+ * necessary character escaping.
+ *
+ * @param data the string to encode. Null will be interpreted as an empty
+ * string.
+ */
+ @NonNull public static String quote(@Nullable String data) {
+ if (data == null) {
+ return "\"\"";
+ }
+ try {
+ JSONStringer stringer = new JSONStringer();
+ stringer.open(JSONStringer.Scope.NULL, "");
+ stringer.value(data);
+ stringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, "");
+ return stringer.toString();
+ } catch (JSONException e) {
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Wraps the given object if necessary.
+ *
+ * <p>If the object is null or , returns {@link #NULL}.
+ * If the object is a {@code JSONArray} or {@code JSONObject}, no wrapping is necessary.
+ * If the object is {@code NULL}, no wrapping is necessary.
+ * If the object is an array or {@code Collection}, returns an equivalent {@code JSONArray}.
+ * If the object is a {@code Map}, returns an equivalent {@code JSONObject}.
+ * If the object is a primitive wrapper type or {@code String}, returns the object.
+ * Otherwise if the object is from a {@code java} package, returns the result of {@code toString}.
+ * If wrapping fails, returns null.
+ */
+ @Nullable public static Object wrap(@Nullable Object o) {
+ if (o == null) {
+ return NULL;
+ }
+ if (o instanceof JSONArray || o instanceof JSONObject) {
+ return o;
+ }
+ if (o.equals(NULL)) {
+ return o;
+ }
+ try {
+ if (o instanceof Collection) {
+ return new JSONArray((Collection) o);
+ } else if (o.getClass().isArray()) {
+ return new JSONArray(o);
+ }
+ if (o instanceof Map) {
+ return new JSONObject((Map) o);
+ }
+ if (o instanceof Boolean ||
+ o instanceof Byte ||
+ o instanceof Character ||
+ o instanceof Double ||
+ o instanceof Float ||
+ o instanceof Integer ||
+ o instanceof Long ||
+ o instanceof Short ||
+ o instanceof String) {
+ return o;
+ }
+ if (o.getClass().getPackage().getName().startsWith("java.")) {
+ return o.toString();
+ }
+ } catch (Exception ignored) {
+ }
+ return null;
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/org/json/JSONStringer.java b/javaSE/javaSE/src/main/java/org/json/JSONStringer.java
new file mode 100644
index 000000000..dd3b2a7d8
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/org/json/JSONStringer.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.json;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+// Note: this class was written without inspecting the non-free org.json sourcecode.
+
+/**
+ * Implements {@link JSONObject#toString} and {@link JSONArray#toString}. Most
+ * application developers should use those methods directly and disregard this
+ * API. For example:<pre>
+ * JSONObject object = ...
+ * String json = object.toString();</pre>
+ *
+ * <p>Stringers only encode well-formed JSON strings. In particular:
+ * <ul>
+ * <li>The stringer must have exactly one top-level array or object.
+ * <li>Lexical scopes must be balanced: every call to {@link #array} must
+ * have a matching call to {@link #endArray} and every call to {@link
+ * #object} must have a matching call to {@link #endObject}.
+ * <li>Arrays may not contain keys (property names).
+ * <li>Objects must alternate keys (property names) and values.
+ * <li>Values are inserted with either literal {@link #value(Object) value}
+ * calls, or by nesting arrays or objects.
+ * </ul>
+ * Calls that would result in a malformed JSON string will fail with a
+ * {@link JSONException}.
+ *
+ * <p>This class provides no facility for pretty-printing (ie. indenting)
+ * output. To encode indented output, use {@link JSONObject#toString(int)} or
+ * {@link JSONArray#toString(int)}.
+ *
+ * <p>Some implementations of the API support at most 20 levels of nesting.
+ * Attempts to create more than 20 levels of nesting may fail with a {@link
+ * JSONException}.
+ *
+ * <p>Each stringer may be used to encode a single top level value. Instances of
+ * this class are not thread safe. Although this class is nonfinal, it was not
+ * designed for inheritance and should not be subclassed. In particular,
+ * self-use by overrideable methods is not specified. See <i>Effective Java</i>
+ * Item 17, "Design and Document or inheritance or else prohibit it" for further
+ * information.
+ */
+public class JSONStringer {
+
+ /** The output data, containing at most one top-level array or object. */
+ final StringBuilder out = new StringBuilder();
+
+ /**
+ * Lexical scoping elements within this stringer, necessary to insert the
+ * appropriate separator characters (ie. commas and colons) and to detect
+ * nesting errors.
+ */
+ enum Scope {
+
+ /**
+ * An array with no elements requires no separators or newlines before
+ * it is closed.
+ */
+ EMPTY_ARRAY,
+
+ /**
+ * A array with at least one value requires a comma and newline before
+ * the next element.
+ */
+ NONEMPTY_ARRAY,
+
+ /**
+ * An object with no keys or values requires no separators or newlines
+ * before it is closed.
+ */
+ EMPTY_OBJECT,
+
+ /**
+ * An object whose most recent element is a key. The next element must
+ * be a value.
+ */
+ DANGLING_KEY,
+
+ /**
+ * An object with at least one name/value pair requires a comma and
+ * newline before the next element.
+ */
+ NONEMPTY_OBJECT,
+
+ /**
+ * A special bracketless array needed by JSONStringer.join() and
+ * JSONObject.quote() only. Not used for JSON encoding.
+ */
+ NULL,
+ }
+
+ /**
+ * Unlike the original implementation, this stack isn't limited to 20
+ * levels of nesting.
+ */
+ private final List<Scope> stack = new ArrayList<Scope>();
+
+ /**
+ * A string containing a full set of spaces for a single level of
+ * indentation, or null for no pretty printing.
+ */
+ private final String indent;
+
+ public JSONStringer() {
+ indent = null;
+ }
+
+ JSONStringer(int indentSpaces) {
+ char[] indentChars = new char[indentSpaces];
+ Arrays.fill(indentChars, ' ');
+ indent = new String(indentChars);
+ }
+
+ /**
+ * Begins encoding a new array. Each call to this method must be paired with
+ * a call to {@link #endArray}.
+ *
+ * @return this stringer.
+ */
+ public JSONStringer array() throws JSONException {
+ return open(Scope.EMPTY_ARRAY, "[");
+ }
+
+ /**
+ * Ends encoding the current array.
+ *
+ * @return this stringer.
+ */
+ public JSONStringer endArray() throws JSONException {
+ return close(Scope.EMPTY_ARRAY, Scope.NONEMPTY_ARRAY, "]");
+ }
+
+ /**
+ * Begins encoding a new object. Each call to this method must be paired
+ * with a call to {@link #endObject}.
+ *
+ * @return this stringer.
+ */
+ public JSONStringer object() throws JSONException {
+ return open(Scope.EMPTY_OBJECT, "{");
+ }
+
+ /**
+ * Ends encoding the current object.
+ *
+ * @return this stringer.
+ */
+ public JSONStringer endObject() throws JSONException {
+ return close(Scope.EMPTY_OBJECT, Scope.NONEMPTY_OBJECT, "}");
+ }
+
+ /**
+ * Enters a new scope by appending any necessary whitespace and the given
+ * bracket.
+ */
+ JSONStringer open(Scope empty, String openBracket) throws JSONException {
+ if (stack.isEmpty() && out.length() > 0) {
+ throw new JSONException("Nesting problem: multiple top-level roots");
+ }
+ beforeValue();
+ stack.add(empty);
+ out.append(openBracket);
+ return this;
+ }
+
+ /**
+ * Closes the current scope by appending any necessary whitespace and the
+ * given bracket.
+ */
+ JSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSONException {
+ Scope context = peek();
+ if (context != nonempty && context != empty) {
+ throw new JSONException("Nesting problem");
+ }
+
+ stack.remove(stack.size() - 1);
+ if (context == nonempty) {
+ newline();
+ }
+ out.append(closeBracket);
+ return this;
+ }
+
+ /**
+ * Returns the value on the top of the stack.
+ */
+ private Scope peek() throws JSONException {
+ if (stack.isEmpty()) {
+ throw new JSONException("Nesting problem");
+ }
+ return stack.get(stack.size() - 1);
+ }
+
+ /**
+ * Replace the value on the top of the stack with the given value.
+ */
+ private void replaceTop(Scope topOfStack) {
+ stack.set(stack.size() - 1, topOfStack);
+ }
+
+ /**
+ * Encodes {@code value}.
+ *
+ * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
+ * Integer, Long, Double or null. May not be {@link Double#isNaN() NaNs}
+ * or {@link Double#isInfinite() infinities}.
+ * @return this stringer.
+ */
+ public JSONStringer value(Object value) throws JSONException {
+ if (stack.isEmpty()) {
+ throw new JSONException("Nesting problem");
+ }
+
+ if (value instanceof JSONArray) {
+ ((JSONArray) value).writeTo(this);
+ return this;
+
+ } else if (value instanceof JSONObject) {
+ ((JSONObject) value).writeTo(this);
+ return this;
+ }
+
+ beforeValue();
+
+ if (value == null
+ || value instanceof Boolean
+ || value == JSONObject.NULL) {
+ out.append(value);
+
+ } else if (value instanceof Number) {
+ out.append(JSONObject.numberToString((Number) value));
+
+ } else {
+ string(value.toString());
+ }
+
+ return this;
+ }
+
+ /**
+ * Encodes {@code value} to this stringer.
+ *
+ * @return this stringer.
+ */
+ public JSONStringer value(boolean value) throws JSONException {
+ if (stack.isEmpty()) {
+ throw new JSONException("Nesting problem");
+ }
+ beforeValue();
+ out.append(value);
+ return this;
+ }
+
+ /**
+ * Encodes {@code value} to this stringer.
+ *
+ * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
+ * {@link Double#isInfinite() infinities}.
+ * @return this stringer.
+ */
+ public JSONStringer value(double value) throws JSONException {
+ if (stack.isEmpty()) {
+ throw new JSONException("Nesting problem");
+ }
+ beforeValue();
+ out.append(JSONObject.numberToString(value));
+ return this;
+ }
+
+ /**
+ * Encodes {@code value} to this stringer.
+ *
+ * @return this stringer.
+ */
+ public JSONStringer value(long value) throws JSONException {
+ if (stack.isEmpty()) {
+ throw new JSONException("Nesting problem");
+ }
+ beforeValue();
+ out.append(value);
+ return this;
+ }
+
+ private void string(String value) {
+ out.append("\"");
+ for (int i = 0, length = value.length(); i < length; i++) {
+ char c = value.charAt(i);
+
+ /*
+ * From RFC 4627, "All Unicode characters may be placed within the
+ * quotation marks except for the characters that must be escaped:
+ * quotation mark, reverse solidus, and the control characters
+ * (U+0000 through U+001F)."
+ */
+ switch (c) {
+ case '"':
+ case '\\':
+ case '/':
+ out.append('\\').append(c);
+ break;
+
+ case '\t':
+ out.append("\\t");
+ break;
+
+ case '\b':
+ out.append("\\b");
+ break;
+
+ case '\n':
+ out.append("\\n");
+ break;
+
+ case '\r':
+ out.append("\\r");
+ break;
+
+ case '\f':
+ out.append("\\f");
+ break;
+
+ default:
+ if (c <= 0x1F) {
+ out.append(String.format("\\u%04x", (int) c));
+ } else {
+ out.append(c);
+ }
+ break;
+ }
+
+ }
+ out.append("\"");
+ }
+
+ private void newline() {
+ if (indent == null) {
+ return;
+ }
+
+ out.append("\n");
+ for (int i = 0; i < stack.size(); i++) {
+ out.append(indent);
+ }
+ }
+
+ /**
+ * Encodes the key (property name) to this stringer.
+ *
+ * @param name the name of the forthcoming value. May not be null.
+ * @return this stringer.
+ */
+ public JSONStringer key(String name) throws JSONException {
+ if (name == null) {
+ throw new JSONException("Names must be non-null");
+ }
+ beforeKey();
+ string(name);
+ return this;
+ }
+
+ /**
+ * Inserts any necessary separators and whitespace before a name. Also
+ * adjusts the stack to expect the key's value.
+ */
+ private void beforeKey() throws JSONException {
+ Scope context = peek();
+ if (context == Scope.NONEMPTY_OBJECT) { // first in object
+ out.append(',');
+ } else if (context != Scope.EMPTY_OBJECT) { // not in an object!
+ throw new JSONException("Nesting problem");
+ }
+ newline();
+ replaceTop(Scope.DANGLING_KEY);
+ }
+
+ /**
+ * Inserts any necessary separators and whitespace before a literal value,
+ * inline array, or inline object. Also adjusts the stack to expect either a
+ * closing bracket or another element.
+ */
+ private void beforeValue() throws JSONException {
+ if (stack.isEmpty()) {
+ return;
+ }
+
+ Scope context = peek();
+ if (context == Scope.EMPTY_ARRAY) { // first in array
+ replaceTop(Scope.NONEMPTY_ARRAY);
+ newline();
+ } else if (context == Scope.NONEMPTY_ARRAY) { // another in array
+ out.append(',');
+ newline();
+ } else if (context == Scope.DANGLING_KEY) { // value for key
+ out.append(indent == null ? ":" : ": ");
+ replaceTop(Scope.NONEMPTY_OBJECT);
+ } else if (context != Scope.NULL) {
+ throw new JSONException("Nesting problem");
+ }
+ }
+
+ /**
+ * Returns the encoded JSON string.
+ *
+ * <p>If invoked with unterminated arrays or unclosed objects, this method's
+ * return value is undefined.
+ *
+ * <p><strong>Warning:</strong> although it contradicts the general contract
+ * of {@link Object#toString}, this method returns null if the stringer
+ * contains no data.
+ */
+ @Override public String toString() {
+ return out.length() == 0 ? null : out.toString();
+ }
+}
diff --git a/javaSE/javaSE/src/main/java/org/json/JSONTokener.java b/javaSE/javaSE/src/main/java/org/json/JSONTokener.java
new file mode 100644
index 000000000..4bdd9ad37
--- /dev/null
+++ b/javaSE/javaSE/src/main/java/org/json/JSONTokener.java
@@ -0,0 +1,611 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.json;
+
+
+// Note: this class was written without inspecting the non-free org.json sourcecode.
+
+/**
+ * Parses a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
+ * encoded string into the corresponding object. Most clients of
+ * this class will use only need the {@link #JSONTokener(String) constructor}
+ * and {@link #nextValue} method. Example usage: <pre>
+ * String json = "{"
+ * + " \"query\": \"Pizza\", "
+ * + " \"locations\": [ 94043, 90210 ] "
+ * + "}";
+ *
+ * JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
+ * String query = object.getString("query");
+ * JSONArray locations = object.getJSONArray("locations");</pre>
+ *
+ * <p>For best interoperability and performance use JSON that complies with
+ * RFC 4627, such as that generated by {@link JSONStringer}. For legacy reasons
+ * this parser is lenient, so a successful parse does not indicate that the
+ * input string was valid JSON. All of the following syntax errors will be
+ * ignored:
+ * <ul>
+ * <li>End of line comments starting with {@code //} or {@code #} and ending
+ * with a newline character.
+ * <li>C-style comments starting with {@code /*} and ending with
+ * {@code *}{@code /}. Such comments may not be nested.
+ * <li>Strings that are unquoted or {@code 'single quoted'}.
+ * <li>Hexadecimal integers prefixed with {@code 0x} or {@code 0X}.
+ * <li>Octal integers prefixed with {@code 0}.
+ * <li>Array elements separated by {@code ;}.
+ * <li>Unnecessary array separators. These are interpreted as if null was the
+ * omitted value.
+ * <li>Key-value pairs separated by {@code =} or {@code =>}.
+ * <li>Key-value pairs separated by {@code ;}.
+ * </ul>
+ *
+ * <p>Each tokener may be used to parse a single JSON string. Instances of this
+ * class are not thread safe. Although this class is nonfinal, it was not
+ * designed for inheritance and should not be subclassed. In particular,
+ * self-use by overrideable methods is not specified. See <i>Effective Java</i>
+ * Item 17, "Design and Document or inheritance or else prohibit it" for further
+ * information.
+ */
+public class JSONTokener {
+
+ /** The input JSON. */
+ private final String in;
+
+ /**
+ * The index of the next character to be returned by {@link #next}. When
+ * the input is exhausted, this equals the input's length.
+ */
+ private int pos;
+
+ /**
+ * @param in JSON encoded string. Null is not permitted and will yield a
+ * tokener that throws {@code NullPointerExceptions} when methods are
+ * called.
+ */
+ public JSONTokener(String in) {
+ // consume an optional byte order mark (BOM) if it exists
+ if (in != null && in.startsWith("\ufeff")) {
+ in = in.substring(1);
+ }
+ this.in = in;
+ }
+
+ /**
+ * Returns the next value from the input.
+ *
+ * @return a {@link JSONObject}, {@link JSONArray}, String, Boolean,
+ * Integer, Long, Double or {@link JSONObject#NULL}.
+ * @throws JSONException if the input is malformed.
+ */
+ public Object nextValue() throws JSONException {
+ int c = nextCleanInternal();
+ switch (c) {
+ case -1:
+ throw syntaxError("End of input");
+
+ case '{':
+ return readObject();
+
+ case '[':
+ return readArray();
+
+ case '\'':
+ case '"':
+ return nextString((char) c);
+
+ default:
+ pos--;
+ return readLiteral();
+ }
+ }
+
+ private int nextCleanInternal() throws JSONException {
+ while (pos < in.length()) {
+ int c = in.charAt(pos++);
+ switch (c) {
+ case '\t':
+ case ' ':
+ case '\n':
+ case '\r':
+ continue;
+
+ case '/':
+ if (pos == in.length()) {
+ return c;
+ }
+
+ char peek = in.charAt(pos);
+ switch (peek) {
+ case '*':
+ // skip a /* c-style comment */
+ pos++;
+ int commentEnd = in.indexOf("*/", pos);
+ if (commentEnd == -1) {
+ throw syntaxError("Unterminated comment");
+ }
+ pos = commentEnd + 2;
+ continue;
+
+ case '/':
+ // skip a // end-of-line comment
+ pos++;
+ skipToEndOfLine();
+ continue;
+
+ default:
+ return c;
+ }
+
+ case '#':
+ /*
+ * Skip a # hash end-of-line comment. The JSON RFC doesn't
+ * specify this behavior, but it's required to parse
+ * existing documents. See http://b/2571423.
+ */
+ skipToEndOfLine();
+ continue;
+
+ default:
+ return c;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Advances the position until after the next newline character. If the line
+ * is terminated by "\r\n", the '\n' must be consumed as whitespace by the
+ * caller.
+ */
+ private void skipToEndOfLine() {
+ for (; pos < in.length(); pos++) {
+ char c = in.charAt(pos);
+ if (c == '\r' || c == '\n') {
+ pos++;
+ break;
+ }
+ }
+ }
+
+ /**
+ * Returns the string up to but not including {@code quote}, unescaping any
+ * character escape sequences encountered along the way. The opening quote
+ * should have already been read. This consumes the closing quote, but does
+ * not include it in the returned string.
+ *
+ * @param quote either ' or ".
+ */
+ public String nextString(char quote) throws JSONException {
+ /*
+ * For strings that are free of escape sequences, we can just extract
+ * the result as a substring of the input. But if we encounter an escape
+ * sequence, we need to use a StringBuilder to compose the result.
+ */
+ StringBuilder builder = null;
+
+ /* the index of the first character not yet appended to the builder. */
+ int start = pos;
+
+ while (pos < in.length()) {
+ int c = in.charAt(pos++);
+ if (c == quote) {
+ if (builder == null) {
+ // a new string avoids leaking memory
+ return new String(in.substring(start, pos - 1));
+ } else {
+ builder.append(in, start, pos - 1);
+ return builder.toString();
+ }
+ }
+
+ if (c == '\\') {
+ if (pos == in.length()) {
+ throw syntaxError("Unterminated escape sequence");
+ }
+ if (builder == null) {
+ builder = new StringBuilder();
+ }
+ builder.append(in, start, pos - 1);
+ builder.append(readEscapeCharacter());
+ start = pos;
+ }
+ }
+
+ throw syntaxError("Unterminated string");
+ }
+
+ /**
+ * Unescapes the character identified by the character or characters that
+ * immediately follow a backslash. The backslash '\' should have already
+ * been read. This supports both unicode escapes "u000A" and two-character
+ * escapes "\n".
+ */
+ private char readEscapeCharacter() throws JSONException {
+ char escaped = in.charAt(pos++);
+ switch (escaped) {
+ case 'u':
+ if (pos + 4 > in.length()) {
+ throw syntaxError("Unterminated escape sequence");
+ }
+ String hex = in.substring(pos, pos + 4);
+ pos += 4;
+ try {
+ return (char) Integer.parseInt(hex, 16);
+ } catch (NumberFormatException nfe) {
+ throw syntaxError("Invalid escape sequence: " + hex);
+ }
+
+ case 't':
+ return '\t';
+
+ case 'b':
+ return '\b';
+
+ case 'n':
+ return '\n';
+
+ case 'r':
+ return '\r';
+
+ case 'f':
+ return '\f';
+
+ case '\'':
+ case '"':
+ case '\\':
+ default:
+ return escaped;
+ }
+ }
+
+ /**
+ * Reads a null, boolean, numeric or unquoted string literal value. Numeric
+ * values will be returned as an Integer, Long, or Double, in that order of
+ * preference.
+ */
+ private Object readLiteral() throws JSONException {
+ String literal = nextToInternal("{}[]/\\:,=;# \t\f");
+
+ if (literal.length() == 0) {
+ throw syntaxError("Expected literal value");
+ } else if ("null".equalsIgnoreCase(literal)) {
+ return JSONObject.NULL;
+ } else if ("true".equalsIgnoreCase(literal)) {
+ return Boolean.TRUE;
+ } else if ("false".equalsIgnoreCase(literal)) {
+ return Boolean.FALSE;
+ }
+
+ /* try to parse as an integral type... */
+ if (literal.indexOf('.') == -1) {
+ int base = 10;
+ String number = literal;
+ if (number.startsWith("0x") || number.startsWith("0X")) {
+ number = number.substring(2);
+ base = 16;
+ } else if (number.startsWith("0") && number.length() > 1) {
+ number = number.substring(1);
+ base = 8;
+ }
+ try {
+ long longValue = Long.parseLong(number, base);
+ if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {
+ return (int) longValue;
+ } else {
+ return longValue;
+ }
+ } catch (NumberFormatException e) {
+ /*
+ * This only happens for integral numbers greater than
+ * Long.MAX_VALUE, numbers in exponential form (5e-10) and
+ * unquoted strings. Fall through to try floating point.
+ */
+ }
+ }
+
+ /* ...next try to parse as a floating point... */
+ try {
+ return Double.valueOf(literal);
+ } catch (NumberFormatException ignored) {
+ }
+
+ /* ... finally give up. We have an unquoted string */
+ return new String(literal); // a new string avoids leaking memory
+ }
+
+ /**
+ * Returns the string up to but not including any of the given characters or
+ * a newline character. This does not consume the excluded character.
+ */
+ private String nextToInternal(String excluded) {
+ int start = pos;
+ for (; pos < in.length(); pos++) {
+ char c = in.charAt(pos);
+ if (c == '\r' || c == '\n' || excluded.indexOf(c) != -1) {
+ return in.substring(start, pos);
+ }
+ }
+ return in.substring(start);
+ }
+
+ /**
+ * Reads a sequence of key/value pairs and the trailing closing brace '}' of
+ * an object. The opening brace '{' should have already been read.
+ */
+ private JSONObject readObject() throws JSONException {
+ JSONObject result = new JSONObject();
+
+ /* Peek to see if this is the empty object. */
+ int first = nextCleanInternal();
+ if (first == '}') {
+ return result;
+ } else if (first != -1) {
+ pos--;
+ }
+
+ while (true) {
+ Object name = nextValue();
+ if (!(name instanceof String)) {
+ if (name == null) {
+ throw syntaxError("Names cannot be null");
+ } else {
+ throw syntaxError("Names must be strings, but " + name
+ + " is of type " + name.getClass().getName());
+ }
+ }
+
+ /*
+ * Expect the name/value separator to be either a colon ':', an
+ * equals sign '=', or an arrow "=>". The last two are bogus but we
+ * include them because that's what the original implementation did.
+ */
+ int separator = nextCleanInternal();
+ if (separator != ':' && separator != '=') {
+ throw syntaxError("Expected ':' after " + name);
+ }
+ if (pos < in.length() && in.charAt(pos) == '>') {
+ pos++;
+ }
+
+ result.put((String) name, nextValue());
+
+ switch (nextCleanInternal()) {
+ case '}':
+ return result;
+ case ';':
+ case ',':
+ continue;
+ default:
+ throw syntaxError("Unterminated object");
+ }
+ }
+ }
+
+ /**
+ * Reads a sequence of values and the trailing closing brace ']' of an
+ * array. The opening brace '[' should have already been read. Note that
+ * "[]" yields an empty array, but "[,]" returns a two-element array
+ * equivalent to "[null,null]".
+ */
+ private JSONArray readArray() throws JSONException {
+ JSONArray result = new JSONArray();
+
+ /* to cover input that ends with ",]". */
+ boolean hasTrailingSeparator = false;
+
+ while (true) {
+ switch (nextCleanInternal()) {
+ case -1:
+ throw syntaxError("Unterminated array");
+ case ']':
+ if (hasTrailingSeparator) {
+ result.put(null);
+ }
+ return result;
+ case ',':
+ case ';':
+ /* A separator without a value first means "null". */
+ result.put(null);
+ hasTrailingSeparator = true;
+ continue;
+ default:
+ pos--;
+ }
+
+ result.put(nextValue());
+
+ switch (nextCleanInternal()) {
+ case ']':
+ return result;
+ case ',':
+ case ';':
+ hasTrailingSeparator = true;
+ continue;
+ default:
+ throw syntaxError("Unterminated array");
+ }
+ }
+ }
+
+ /**
+ * Returns an exception containing the given message plus the current
+ * position and the entire input string.
+ */
+ public JSONException syntaxError(String message) {
+ return new JSONException(message + this);
+ }
+
+ /**
+ * Returns the current position and the entire input string.
+ */
+ @Override public String toString() {
+ // consistent with the original implementation
+ return " at character " + pos + " of " + in;
+ }
+
+ /*
+ * Legacy APIs.
+ *
+ * None of the methods below are on the critical path of parsing JSON
+ * documents. They exist only because they were exposed by the original
+ * implementation and may be used by some clients.
+ */
+
+ /**
+ * Returns true until the input has been exhausted.
+ */
+ public boolean more() {
+ return pos < in.length();
+ }
+
+ /**
+ * Returns the next available character, or the null character '\0' if all
+ * input has been exhausted. The return value of this method is ambiguous
+ * for JSON strings that contain the character '\0'.
+ */
+ public char next() {
+ return pos < in.length() ? in.charAt(pos++) : '\0';
+ }
+
+ /**
+ * Returns the next available character if it equals {@code c}. Otherwise an
+ * exception is thrown.
+ */
+ public char next(char c) throws JSONException {
+ char result = next();
+ if (result != c) {
+ throw syntaxError("Expected " + c + " but was " + result);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the next character that is not whitespace and does not belong to
+ * a comment. If the input is exhausted before such a character can be
+ * found, the null character '\0' is returned. The return value of this
+ * method is ambiguous for JSON strings that contain the character '\0'.
+ */
+ public char nextClean() throws JSONException {
+ int nextCleanInt = nextCleanInternal();
+ return nextCleanInt == -1 ? '\0' : (char) nextCleanInt;
+ }
+
+ /**
+ * Returns the next {@code length} characters of the input.
+ *
+ * <p>The returned string shares its backing character array with this
+ * tokener's input string. If a reference to the returned string may be held
+ * indefinitely, you should use {@code new String(result)} to copy it first
+ * to avoid memory leaks.
+ *
+ * @throws JSONException if the remaining input is not long enough to
+ * satisfy this request.
+ */
+ public String next(int length) throws JSONException {
+ if (pos + length > in.length()) {
+ throw syntaxError(length + " is out of bounds");
+ }
+ String result = in.substring(pos, pos + length);
+ pos += length;
+ return result;
+ }
+
+ /**
+ * Returns the {@link String#trim trimmed} string holding the characters up
+ * to but not including the first of:
+ * <ul>
+ * <li>any character in {@code excluded}
+ * <li>a newline character '\n'
+ * <li>a carriage return '\r'
+ * </ul>
+ *
+ * <p>The returned string shares its backing character array with this
+ * tokener's input string. If a reference to the returned string may be held
+ * indefinitely, you should use {@code new String(result)} to copy it first
+ * to avoid memory leaks.
+ *
+ * @return a possibly-empty string
+ */
+ public String nextTo(String excluded) {
+ if (excluded == null) {
+ throw new NullPointerException("excluded == null");
+ }
+ return nextToInternal(excluded).trim();
+ }
+
+ /**
+ * Equivalent to {@code nextTo(String.valueOf(excluded))}.
+ */
+ public String nextTo(char excluded) {
+ return nextToInternal(String.valueOf(excluded)).trim();
+ }
+
+ /**
+ * Advances past all input up to and including the next occurrence of
+ * {@code thru}. If the remaining input doesn't contain {@code thru}, the
+ * input is exhausted.
+ */
+ public void skipPast(String thru) {
+ int thruStart = in.indexOf(thru, pos);
+ pos = thruStart == -1 ? in.length() : (thruStart + thru.length());
+ }
+
+ /**
+ * Advances past all input up to but not including the next occurrence of
+ * {@code to}. If the remaining input doesn't contain {@code to}, the input
+ * is unchanged.
+ */
+ public char skipTo(char to) {
+ int index = in.indexOf(to, pos);
+ if (index != -1) {
+ pos = index;
+ return to;
+ } else {
+ return '\0';
+ }
+ }
+
+ /**
+ * Unreads the most recent character of input. If no input characters have
+ * been read, the input is unchanged.
+ */
+ public void back() {
+ if (--pos == -1) {
+ pos = 0;
+ }
+ }
+
+ /**
+ * Returns the integer [0..15] value for the given hex character, or -1
+ * for non-hex input.
+ *
+ * @param hex a character in the ranges [0-9], [A-F] or [a-f]. Any other
+ * character will yield a -1 result.
+ */
+ public static int dehexchar(char hex) {
+ if (hex >= '0' && hex <= '9') {
+ return hex - '0';
+ } else if (hex >= 'A' && hex <= 'F') {
+ return hex - 'A' + 10;
+ } else if (hex >= 'a' && hex <= 'f') {
+ return hex - 'a' + 10;
+ } else {
+ return -1;
+ }
+ }
+}