summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoey Grover <joeygrover@gmail.com>2018-10-19 11:05:41 -0400
committerJoey Grover <joeygrover@gmail.com>2018-10-19 11:05:41 -0400
commitefc9fdc641a55afb7d8331d5cab709f602feebea (patch)
tree15a56a579d31d0557f8f6d4c73b43ba785262d6d
parent42ef06bb9a212371abf778a8f6d4f5ba255a98a0 (diff)
parentc5783315e57de4f7e3db55b5e5954f7683f7aad4 (diff)
downloadsdl_android-efc9fdc641a55afb7d8331d5cab709f602feebea.tar.gz
Merge branch 'release/4.7.0-rc1'4.7.0
-rw-r--r--.travis.yml3
-rw-r--r--CHANGELOG.md106
-rwxr-xr-xhello_sdl_android/build.gradle60
-rwxr-xr-xhello_sdl_android/proguard-rules.pro28
-rwxr-xr-xhello_sdl_android/src/main/AndroidManifest.xml68
-rwxr-xr-xhello_sdl_android/src/main/java/com/sdl/hellosdlandroid/MainActivity.java43
-rwxr-xr-xhello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlReceiver.java51
-rwxr-xr-xhello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlRouterService.java8
-rwxr-xr-xhello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlService.java274
-rwxr-xr-xhello_sdl_android/src/main/res.zipbin0 -> 71117 bytes
-rwxr-xr-xhello_sdl_android/src/main/res/drawable/sdl.pngbin0 -> 3274 bytes
-rwxr-xr-xhello_sdl_android/src/main/res/layout/activity_main.xml16
-rwxr-xr-xhello_sdl_android/src/main/res/menu/main.xml12
-rwxr-xr-xhello_sdl_android/src/main/res/mipmap-hdpi/ic_launcher.pngbin0 -> 6614 bytes
-rwxr-xr-xhello_sdl_android/src/main/res/mipmap-mdpi/ic_launcher.pngbin0 -> 3515 bytes
-rwxr-xr-xhello_sdl_android/src/main/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 9073 bytes
-rwxr-xr-xhello_sdl_android/src/main/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 17100 bytes
-rwxr-xr-xhello_sdl_android/src/main/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 25896 bytes
-rwxr-xr-xhello_sdl_android/src/main/res/values-v11/styles.xml11
-rwxr-xr-xhello_sdl_android/src/main/res/values-v14/styles.xml12
-rwxr-xr-xhello_sdl_android/src/main/res/values-w820dp/dimens.xml10
-rwxr-xr-xhello_sdl_android/src/main/res/values/dimens.xml7
-rwxr-xr-xhello_sdl_android/src/main/res/values/strings.xml8
-rwxr-xr-xhello_sdl_android/src/main/res/values/styles.xml20
-rwxr-xr-xhello_sdl_android/src/main/res/xml/accessory_filter.xml7
-rw-r--r--sdl_android/ROUTER_SERVICE_MESSAGING_PROTOCOL.md70
-rw-r--r--sdl_android/build.gradle13
-rw-r--r--sdl_android/src/androidTest/assets/json/AddSubMenu.json6
-rw-r--r--sdl_android/src/androidTest/assets/json/GetVehicleData.json25
-rw-r--r--sdl_android/src/androidTest/assets/json/PutFile.json1
-rw-r--r--sdl_android/src/androidTest/assets/json/RegisterAppInterface.json40
-rw-r--r--sdl_android/src/androidTest/assets/json/SetDisplayLayout.json36
-rw-r--r--sdl_android/src/androidTest/assets/json/SetMediaClockTimer.json3
-rw-r--r--sdl_android/src/androidTest/assets/json/SubscribeVehicleData.json22
-rw-r--r--sdl_android/src/androidTest/assets/json/SystemRequest.json3
-rw-r--r--sdl_android/src/androidTest/assets/json/UnsubscribeVehicleData.json24
-rw-r--r--sdl_android/src/androidTest/assets/xml/MOBILE_API.xml (renamed from sdl_android/src/androidTest/assets/xml/MOBILE_API_4.5.0.xml)2135
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/AndroidTestCase2.java34
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/SdlConnection/SdlConnectionTest.java5
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/managers/SdlManagerTests.java392
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/managers/audio/AudioStreamManagerTest.java681
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java485
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/managers/lockscreen/LockScreenConfigTests.java45
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/managers/lockscreen/LockScreenManagerTests.java56
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/managers/permission/PermissionManagerTests.java203
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/ScreenManagerTests.java122
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/SoftButtonManagerTests.java239
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/TextAndGraphicManagerTests.java545
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/managers/video/VideoStreamManagerTests.java282
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/protocol/SdlPacketTests.java5
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/protocol/SdlProtocolTests.java372
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/protocol/WiProProtocolTests.java9
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/BaseRpcTests.java5
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/Test.java402
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java776
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/VehicleDataHelper.java51
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/BinaryFrameHeaderTests.java6
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/FrameDataControlFrameTypeTests.java19
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/LockScreenManagerTest.java2
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/RPCRequestTest.java13
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SdlProxyBaseTests.java43
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SystemCapabilityManagerTests.java85
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/RPCConstructorsTests.java9
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/AudioControlCapabilitiesTests.java94
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/AudioControlDataTests.java98
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ChoiceTests.java2
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ClimateControlCapabilitiesTests.java22
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ClimateControlDataTests.java22
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/DisplayCapabilitiesTests.java5
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/EqualizerSettingsTests.java78
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/FuelRangeTests.java71
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/HMISettingsControlCapabilitiesTests.java80
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/HMISettingsControlDataTests.java78
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ImageTests.java5
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightCapabilitiesTests.java81
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightControlCapabilitiesTests.java86
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightControlDataTests.java79
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightStateTests.java94
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/MassageCushionFirmnessTest.java71
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/MassageModeDataTest.java74
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ModuleDataTests.java187
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RGBColorTest.java70
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RadioControlCapabilitiesTests.java17
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RadioControlDataTests.java21
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RemoteControlCapabilitiesTests.java255
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SeatControlCapabilitiesTest.java141
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SeatControlDataTest.java173
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SeatMemoryActionTest.java75
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SingleTireStatusTest.java13
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SisDataTests.java105
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/StationIDNumberTests.java73
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/TemplateColorSchemeTest.java81
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/AudioStreamingIndicatorTests.java80
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/AudioStreamingStateTests.java2
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ButtonNameTests.java3
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/DisplayModeTests.java74
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/DistanceUnitTests.java69
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ElectronicParkBrakeStatusTests.java82
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/FuelTypeTests.java87
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ImageFieldNameTests.java4
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/LightNameTests.java261
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/LightStatusTests.java86
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MassageCushionTests.java81
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MassageModeTests.java73
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MassageZoneTests.java69
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MetadataTypeTests.java14
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ModuleTypeTests.java44
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/PredefinedLayoutTests.java144
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/PrimaryAudioSourceTests.java68
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/RequestTypeTests.java5
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ResultTests.java8
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SdlDisconnectedReasonTests.java3
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SeatMemoryActionTypeTests.java73
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SpeechCapabilitiesTests.java1
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/StaticIconNameTests.java931
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SupportedSeatTests.java69
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/TPMSTests.java95
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/TurnSignalTests.java79
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/VehicleDataTypeTests.java20
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/VideoStreamingStateTests.java71
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnHMIStatusTests.java16
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnRCStatusTests.java92
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnSystemRequestTests.java7
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnVehicleDataTests.java63
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/AddSubmenuTests.java18
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/GetVehicleDataTests.java22
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/PutFileTests.java36
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/RegisterAppInterfaceTests.java57
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetDisplayLayoutTests.java26
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetMediaClockTimerTests.java11
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SubscribeVehicleDataTests.java24
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SystemRequestTests.java8
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/UnsubscribeVehicleDataTests.java30
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/DeleteFileResponseTests.java2
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/GetVehicleDataResponseTests.java62
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/ListFilesResponseTests.java2
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/PutFileResponseTest.java4
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/RegisterAppInterfaceResponseTest.java9
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/SubscribeVehicleDataResponseTest.java42
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/UnsubscribeVehicleDataResponseTest.java44
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/security/SdlSecurityBaseTest.java18
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/MockInterfaceBroker.java10
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/MockPacketizer.java6
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/video/SdlRemoteDisplayTest.java13
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/transport/MultiplexTransportConfigTests.java4
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/transport/WiFiSocketFactoryTest.java354
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/util/DeviceUtil.java5
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java4
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/util/VersionTest.java23
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java4
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/transport/LocalRouterServiceTests.java5
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/transport/MultiplexTransportTest.java5
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/transport/RSVTestCase.java4
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/transport/RegisteredAppTests.java6
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/transport/SdlRouterServiceTests.java14
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/transport/TransportBrokerTest.java4
-rw-r--r--sdl_android/src/androidTest/java/com/smartdevicelink/transport/TransportManagerTests.java129
-rw-r--r--sdl_android/src/androidTest/res/raw/test_audio_square_250hz_80amp_1s.mp3bin0 -> 18803 bytes
-rw-r--r--sdl_android/src/main/AndroidManifest.xml5
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/SdlConnection/ISdlConnectionListener.java10
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlConnection.java13
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession.java1378
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession2.java298
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/encoder/SdlEncoder.java48
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/BaseSubManager.java83
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/CompletionListener.java10
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/ProxyBridge.java560
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java909
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java21
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/StreamingStateMachine.java72
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioDecoder.java90
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioDecoderCompat.java137
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioDecoderListener.java27
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioStreamManager.java447
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/audio/BaseAudioDecoder.java246
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/audio/SampleBuffer.java280
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/file/FileManager.java434
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/file/MultipleFileCompletionListener.java14
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java35
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java83
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenConfig.java114
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java289
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/SDLLockScreenActivity.java130
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/permission/OnPermissionChangeListener.java20
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionElement.java42
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionFilter.java70
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionManager.java350
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionStatus.java68
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/screen/ScreenManager.java361
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java568
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonObject.java272
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonState.java97
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java895
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/managers/video/VideoStreamManager.java621
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/marshal/JsonRPCMarshaller.java9
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/protocol/AbstractProtocol.java8
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/protocol/IProtocolListener.java2
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/protocol/ISdlProtocol.java56
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/protocol/ISecondaryTransportListener.java8
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/protocol/SdlPacket.java45
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/protocol/SdlPacketFactory.java7
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java1437
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/protocol/WiProProtocol.java285
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/protocol/enums/ControlFrameTags.java21
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/protocol/enums/FrameDataControlFrameType.java10
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/protocol/enums/FunctionID.java15
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/RPCRequest.java4
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/RPCRequestFactory.java1
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/RPCStruct.java83
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyALM.java66
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java980
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBuilder.java20
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/SystemCapabilityManager.java90
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/interfaces/IProxyListenerBase.java3
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/interfaces/ISdl.java113
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/AddSubMenu.java26
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/AudioControlCapabilities.java150
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/AudioControlData.java115
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/Choice.java52
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ClimateControlCapabilities.java84
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ClimateControlData.java77
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/DeleteFileResponse.java47
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/DisplayCapabilities.java50
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/EqualizerSettings.java97
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/FuelRange.java66
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GPSData.java53
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GetVehicleData.java76
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GetVehicleDataResponse.java71
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/HMISettingsControlCapabilities.java107
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/HMISettingsControlData.java79
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/Image.java27
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightCapabilities.java113
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightControlCapabilities.java78
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightControlData.java58
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightState.java119
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ListFilesResponse.java42
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/MassageCushionFirmness.java79
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/MassageModeData.java80
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ModuleData.java222
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnHMIStatus.java40
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnRCStatus.java69
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnSystemRequest.java20
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnVehicleData.java79
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/PutFile.java60
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/PutFileResponse.java66
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RGBColor.java141
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RadioControlCapabilities.java63
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RadioControlData.java38
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RegisterAppInterface.java156
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RegisterAppInterfaceResponse.java55
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RemoteControlCapabilities.java226
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SdlMsgVersion.java10
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SeatControlCapabilities.java339
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SeatControlData.java347
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SeatMemoryAction.java95
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetDisplayLayout.java63
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetMediaClockTimer.java25
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SingleTireStatus.java51
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SisData.java123
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/StationIDNumber.java54
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SubscribeVehicleData.java110
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SubscribeVehicleDataResponse.java71
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SystemRequest.java18
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/TemplateColorScheme.java111
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnregisterAppInterface.java2
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnsubscribeVehicleData.java108
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnsubscribeVehicleDataResponse.java71
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/VideoStreamingCapability.java12
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/AppHMIType.java2
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/AudioStreamingIndicator.java48
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ButtonName.java26
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/DisplayMode.java16
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/DistanceUnit.java15
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ElectronicParkBrakeStatus.java38
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/FuelType.java31
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ImageFieldName.java8
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/LightName.java134
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/LightStatus.java19
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/MassageCushion.java21
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/MassageMode.java19
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/MassageZone.java24
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ModuleType.java24
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/PredefinedLayout.java140
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/PrimaryAudioSource.java29
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/RequestType.java6
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/Result.java5
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SdlDisconnectedReason.java3
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SeatMemoryActionType.java25
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SpeechCapabilities.java7
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/StaticIconName.java910
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SupportedSeat.java18
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/TPMS.java51
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/TurnSignal.java35
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/VehicleDataType.java22
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/VideoStreamingState.java23
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/listeners/OnMultipleRequestListener.java14
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/listeners/OnRPCListener.java55
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/listeners/OnRPCResponseListener.java130
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/security/SdlSecurityBase.java21
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/streaming/AbstractPacketizer.java22
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/streaming/StreamPacketizer.java16
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/streaming/StreamRPCPacketizer.java26
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/streaming/video/RTPH264Packetizer.java5
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/streaming/video/VideoStreamingParameters.java4
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/BTTransport.java1
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/BTTransportConfig.java1
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBaseTransport.java120
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java103
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTcpTransport.java413
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTransport.java40
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTransportConfig.java192
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexUsbTransport.java327
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/RouterServiceValidator.java9
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java41
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/SdlPsm.java4
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java1346
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterStatusProvider.java11
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/TransportBroker.java1325
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/TransportConstants.java61
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java381
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java188
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/USBTransport.java1
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/USBTransportConfig.java59
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/UsbTransferProvider.java220
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/enums/TransportType.java2
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/utl/ByteAraryMessageAssembler.java15
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/utl/ByteArrayMessageSpliter.java12
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/utl/TransportRecord.java126
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/transport/utl/WiFiSocketFactory.java96
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java8
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java14
-rw-r--r--sdl_android/src/main/java/com/smartdevicelink/util/Version.java30
-rw-r--r--sdl_android/src/main/res/drawable-hdpi/sdl_lockscreen_icon.pngbin0 -> 2570 bytes
-rw-r--r--sdl_android/src/main/res/drawable-mdpi/sdl_lockscreen_icon.pngbin0 -> 1791 bytes
-rw-r--r--sdl_android/src/main/res/drawable-mdpi/transparent.pngbin0 -> 980 bytes
-rw-r--r--sdl_android/src/main/res/drawable-xhdpi/sdl_lockscreen_icon.pngbin0 -> 3487 bytes
-rw-r--r--sdl_android/src/main/res/drawable-xxhdpi/sdl_lockscreen_icon.pngbin0 -> 5172 bytes
-rw-r--r--sdl_android/src/main/res/drawable-xxxhdpi/sdl_lockscreen_icon.pngbin0 -> 6666 bytes
-rw-r--r--sdl_android/src/main/res/layout/activity_sdllock_screen.xml44
-rw-r--r--sdl_android/src/main/res/values/sdl.xml3
-rw-r--r--sdl_android/src/main/res/values/strings.xml6
-rw-r--r--settings.gradle2
-rw-r--r--third_party.md39
343 files changed, 34677 insertions, 3544 deletions
diff --git a/.travis.yml b/.travis.yml
index 57284b065..22c941f6c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,6 +13,7 @@ android:
- build-tools-27.0.3
# The SDK version used to compile your project
+ - android-28
- android-27
- android-26
- android-22 #For emulator
@@ -44,7 +45,7 @@ before_script:
script:
- android list target
- - ./gradlew connectedCheck
+ - ./gradlew :sdl_android:connectedCheck
before_install:
- echo yes | sdkmanager "build-tools;27.0.3"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6246b922d..794049621 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,24 +1,82 @@
-# 4.6.0 Release Notes
-
-### API New Features & Breaking Changes
-- `RPCRequestFactory` has been deprecated. Please use the desired RPC's constructor instead.
-- The Android Annotations Library has been added to the project to better help and inform developers about the SDK.
-
-### Enhancements
-- The router service foreground lifecycle is improved. The notification should no longer be seen when connecting to non-SDL devices.
-- The SDL notification now links to a webpage to explain what the notification is and how to hide it.
-- The required `intent-filter` entires for the `SdlBroadcastReceiver` has been reduced. It is now only listening for the SDL custom intent, ACL connect, and USB connection if using AOA.
-- RPC classes now contain constructors with the required parameters for that RPC.
-- Moved project to newer version of Gradle. Updated configurations including from `compile` to `api` and `implementation`.
-- `SdlProxyBuilder` was cleaned up to remove redundant variables between the `SdlProxyBuilder.Builder` object and the `SdlProxyBuilder` class.
-
-### Bug Fixes
-- Fixed touch issues with the video streaming feature. A new module was added to handle touch events much more aligned with Android native views.
-- Fixed JavaDoc issue in `UnregisterAppInterface`.
-- Fixed JavaDoc issue in `AddCommand`.
-- Added tags to the string resource xml file to ignore translation
-- Temporary fix to the TCP transport to catch `NetworkOnTheMainThread` exceptions when the connection is closing.
-- Fix issue where the `SdlBroadcastReceiver` was attempting to send implicit intents to ping the `SdlRouterService`. They are now explicit.
-- Fix a potential NPE in the `SdlBroadcastReceiver` while an app is only using USB and does not include an instance of an `SdlRouterService`.
-- Removed reflection usage in bluetooth transports when operating on systems that are newer than Android Oreo in anticipation of Android P.
-- Fix an issue where the `SdlBroadcastReceiver` would throw a false positive regarding whether or not an app had included the correct `intent-filter` in their `SdlRouterService` manifest declaration. \ No newline at end of file
+# 4.7.0 Release Notes
+
+## Summary
+
+- Manager APIs - The manager APIs will closely align with the iOS SDL Library managers, with a few exceptions to match the native platform.
+- Transport layer overhaul - The protocol layer and transport layer have been overhauled to properly match the stack in which they should exist. This also sets up three additional features
+ - AOA multiplexing - SDL apps can now use the multiplexing transport with the AOA/USB transport. Multiple apps can then register on a single AOA connection to SDL Core.
+ - Primary/Secondary transports - apps can now carry their session over multiple transports with the first transport being primary, and a later connected one being a secondary. This means apps can register over bluetooth, then connect over WiFi when necessary (video/audio streaming).
+ - All apps should be using `MultiplexingConfig` at this point unless debugging with TCP.
+- Color Scheme for templates - App developers now have the ability to set color themes for the templates they use
+- New Remote Control modules
+- Additional vehicle data added
+- `SdlProxyALM` has been deprecated - The `SdlProxyALM` will still function for this release but it has now moved into maintenance mode and no new features will be added. The manager APIs should be used from this point forward.
+
+
+## New Features
+
+- [Add enum for `predefinedlayout`](https://github.com/smartdevicelink/sdl_android/pull/851)
+- [Feature/Listen for responses and capability changes in ISdl](https://github.com/smartdevicelink/sdl_android/pull/828)
+- [Add ability for RPCs to be versioned/formatted](https://github.com/smartdevicelink/sdl_android/pull/839)
+- [[SDL 0159] Static SDL Icon Names Enum](https://github.com/smartdevicelink/sdl_android/issues/740)
+
+#### Transport
+
+- [[SDL 0141] Supporting simultaneous multiple transports](https://github.com/smartdevicelink/sdl_android/issues/714)
+- [[SDL 0194] Android Transport Layer Overhaul](https://github.com/smartdevicelink/sdl_android/issues/841)
+
+#### Manager API
+
+- [[SDL 0171] Android Manager APIs](https://github.com/smartdevicelink/sdl_android/issues/782)
+- [[SDL 0113] SDLAudioStreamManager](https://github.com/smartdevicelink/sdl_android/issues/654)
+
+#### RPC Updates
+
+- [Add PLAY_PAUSE to ButtonName enum](https://github.com/smartdevicelink/sdl_android/issues/228)
+- [[SDL 0014] Adding Audio File Playback to TTSChunk](https://github.com/smartdevicelink/sdl_android/issues/419)
+- [[SDL 0037] Expand Mobile `PutFile` RPC](https://github.com/smartdevicelink/sdl_android/issues/452)
+- [[SDL 0041] Provide AppIcon resumption across app registration requests](https://github.com/smartdevicelink/sdl_android/issues/453)
+- [[SDL 0062] Template images](https://github.com/smartdevicelink/sdl_android/issues/533)
+- [[SDL 0064] Choice-VR optional](https://github.com/smartdevicelink/sdl_android/issues/739)
+- [[SDL 0063] Display name parameter](https://github.com/smartdevicelink/sdl_android/issues/534)
+- [[SDL 0163] Make spaceAvailable field non-mandatory ](https://github.com/smartdevicelink/sdl_android/issues/860)
+- [[SDL 0083] Expandable Design for Proprietary Data Exchange](https://github.com/smartdevicelink/sdl_android/issues/594)
+- [[SDL 0085] SubMenu Icon](https://github.com/smartdevicelink/sdl_android/issues/603)
+- [[SDL 0109] SetAudioStreamingIndicator RPC](https://github.com/smartdevicelink/sdl_android/issues/710)
+- [[SDL 0147] Template Improvements: Color Scheme](https://github.com/smartdevicelink/sdl_android/issues/715)
+- [[SDL 0150] Enhancing onHMIStatus with a New Parameter for Video Streaming State](https://github.com/smartdevicelink/sdl_android/issues/734)
+- [[SDL 0151] ImageFieldName for SecondaryImage](https://github.com/smartdevicelink/sdl_android/issues/724)
+- [[SDL 0153] Support for Short and Full UUID App ID](https://github.com/smartdevicelink/sdl_android/issues/738)
+
+#### Remote Control
+
+- [[SDL 0099] New modules LIGHT, AUDIO, HMI_SETTINGS and parameter SIS Data](https://github.com/smartdevicelink/sdl_android/issues/624)
+- [[SDL 0105] New Seat module](https://github.com/smartdevicelink/sdl_android/issues/651)
+- [[SDL 0106] OnRCStatus notification](https://github.com/smartdevicelink/sdl_android/issues/657)
+- [[SDL 0160] Radio Parameter Update](https://github.com/smartdevicelink/sdl_android/issues/741)
+- [[SDL 0165] Lights modules - More Names and Status Values](https://github.com/smartdevicelink/sdl_android/issues/751)
+- [[SDL 0172] Update OnRCStatus with a new allowed parameter](https://github.com/smartdevicelink/sdl_android/issues/783)
+- [[SDL 0182] Audio Source AM/FM/XM/DAB](https://github.com/smartdevicelink/sdl_android/issues/809)
+
+#### Vehicle Data
+
+- [[SDL 0072] FuelRange](https://github.com/smartdevicelink/sdl_android/issues/552)
+- [[SDL 0082] EngineOilLife](https://github.com/smartdevicelink/sdl_android/issues/593)
+- [[SDL 0097] Tire pressure additions](https://github.com/smartdevicelink/sdl_android/issues/613)
+- [[SDL 0102] ElectronicParkBrakeStatus](https://github.com/smartdevicelink/sdl_android/issues/632)
+- [[SDL 0107] TurnSignal](https://github.com/smartdevicelink/sdl_android/issues/650)
+- [[SDL 0175] Updating DOP value range for GPS notification](https://github.com/smartdevicelink/sdl_android/issues/803)
+
+
+## Bug Fixes
+
+- [SystemCapabilityManager false positive issue](https://github.com/smartdevicelink/sdl_android/issues/844)
+- [Optimize video streaming for still graphics](https://github.com/smartdevicelink/sdl_android/issues/806)
+- [sdl.router.startservice broadcast is sent twice unexpectedly](https://github.com/smartdevicelink/sdl_android/issues/884)
+- [maxBitrate in VIDEO_STREAMING capability is read in wrong unit](https://github.com/smartdevicelink/sdl_android/issues/882)
+
+
+## Documentation
+
+- [Add third_party file](https://github.com/smartdevicelink/sdl_android/issues/865)
+
diff --git a/hello_sdl_android/build.gradle b/hello_sdl_android/build.gradle
new file mode 100755
index 000000000..ac8b92278
--- /dev/null
+++ b/hello_sdl_android/build.gradle
@@ -0,0 +1,60 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 28
+ defaultConfig {
+ applicationId "com.sdl.hellosdlandroid"
+ minSdkVersion 14
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ flavorDimensions "default"
+ productFlavors{
+ multi_sec_high {
+ buildConfigField 'String', 'TRANSPORT', '"MULTI"'
+ buildConfigField 'String', 'SECURITY', '"HIGH"'
+ }
+ multi_sec_med {
+ buildConfigField 'String', 'TRANSPORT', '"MULTI"'
+ buildConfigField 'String', 'SECURITY', '"MED"'
+ }
+ multi_sec_low {
+ buildConfigField 'String', 'TRANSPORT', '"MULTI"'
+ buildConfigField 'String', 'SECURITY', '"LOW"'
+ }
+ multi_sec_off {
+ buildConfigField 'String', 'TRANSPORT', '"MULTI"'
+ buildConfigField 'String', 'SECURITY', '"OFF"'
+ }
+ multi_high_bandwidth {
+ buildConfigField 'String', 'TRANSPORT', '"MULTI_HB"'
+ buildConfigField 'String', 'SECURITY', '"OFF"'
+ }
+ tcp {
+ buildConfigField 'String', 'TRANSPORT', '"TCP"'
+ buildConfigField 'String', 'SECURITY', '"OFF"'
+ }
+ }
+ lintOptions {
+ disable 'GoogleAppIndexingWarning'
+ }
+}
+
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
+ exclude group: 'com.android.support', module: 'support-annotations'
+ })
+ implementation 'com.android.support:appcompat-v7:28.0.0'
+ implementation project(path: ':sdl_android')
+ testImplementation 'junit:junit:4.12'
+} \ No newline at end of file
diff --git a/hello_sdl_android/proguard-rules.pro b/hello_sdl_android/proguard-rules.pro
new file mode 100755
index 000000000..7b318e2d1
--- /dev/null
+++ b/hello_sdl_android/proguard-rules.pro
@@ -0,0 +1,28 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/livio/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+-keep class com.smartdevicelink.** { *; }
+-keep class com.livio.** { *; }
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/hello_sdl_android/src/main/AndroidManifest.xml b/hello_sdl_android/src/main/AndroidManifest.xml
new file mode 100755
index 000000000..72a191542
--- /dev/null
+++ b/hello_sdl_android/src/main/AndroidManifest.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.sdl.hellosdlandroid">
+
+ <uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <!-- Required to check if WiFi is enabled -->
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+
+ <!-- Required to use the USB Accessory mode -->
+ <uses-feature android:name="android.hardware.usb.accessory" />
+
+ <application
+ android:allowBackup="false"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme"
+ tools:ignore="DeepLinks">
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="com.smartdevicelink.transport.USBAccessoryAttachmentActivity"
+ android:launchMode="singleTop">
+ <intent-filter>
+ <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+ </intent-filter>
+
+ <meta-data
+ android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+ android:resource="@xml/accessory_filter" />
+ </activity>
+
+ <service android:name="com.sdl.hellosdlandroid.SdlService" >
+ </service>
+ <service
+ android:name=".SdlRouterService"
+ android:exported="true"
+ android:process="com.smartdevicelink.router">
+ <intent-filter>
+ <action android:name="com.smartdevicelink.router.service"/>
+ </intent-filter>
+ <meta-data android:name="@string/sdl_router_service_version_name" android:value="@integer/sdl_router_service_version_value" />
+ </service>
+ <receiver
+ android:name=".SdlReceiver"
+ android:enabled="true"
+ android:exported="true"
+ tools:ignore="ExportedReceiver">
+ <intent-filter>
+ <action android:name="com.smartdevicelink.USB_ACCESSORY_ATTACHED"/> <!--For AOA -->
+ <action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
+ <action android:name="sdl.router.startservice" />
+ </intent-filter>
+ </receiver>
+ <activity android:name="com.smartdevicelink.managers.lockscreen.SDLLockScreenActivity"
+ android:launchMode="singleTop"/>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/MainActivity.java b/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/MainActivity.java
new file mode 100755
index 000000000..6fc9203db
--- /dev/null
+++ b/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/MainActivity.java
@@ -0,0 +1,43 @@
+package com.sdl.hellosdlandroid;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.Menu;
+import android.view.MenuItem;
+
+public class MainActivity extends AppCompatActivity {
+ private static final String TAG = "MainActivity";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ //If we are connected to a module we want to start our SdlService
+ if(BuildConfig.TRANSPORT.equals("MULTI") || BuildConfig.TRANSPORT.equals("MULTI_HB")) {
+ SdlReceiver.queryForConnectedService(this);
+ }else if(BuildConfig.TRANSPORT.equals("TCP")) {
+ Intent proxyIntent = new Intent(this, SdlService.class);
+ startService(proxyIntent);
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ int id = item.getItemId();
+ if (id == R.id.action_settings) {
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlReceiver.java b/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlReceiver.java
new file mode 100755
index 000000000..09cf35a82
--- /dev/null
+++ b/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlReceiver.java
@@ -0,0 +1,51 @@
+package com.sdl.hellosdlandroid;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.util.Log;
+
+import com.smartdevicelink.transport.SdlBroadcastReceiver;
+import com.smartdevicelink.transport.SdlRouterService;
+import com.smartdevicelink.transport.TransportConstants;
+
+public class SdlReceiver extends SdlBroadcastReceiver {
+ private static final String TAG = "SdlBroadcastReciever";
+ public static final String RECONNECT_LANG_CHANGE = "RECONNECT_LANG_CHANGE";
+
+ @Override
+ public void onSdlEnabled(Context context, Intent intent) {
+ Log.d(TAG, "SDL Enabled");
+ intent.setClass(context, SdlService.class);
+
+ // SdlService needs to be foregrounded in Android O and above
+ // This will prevent apps in the background from crashing when they try to start SdlService
+ // Because Android O doesn't allow background apps to start background services
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ context.startForegroundService(intent);
+ } else {
+ context.startService(intent);
+ }
+ }
+
+ @Override
+ public Class<? extends SdlRouterService> defineLocalSdlRouterClass() {
+ return com.sdl.hellosdlandroid.SdlRouterService.class;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ super.onReceive(context, intent); // Required if overriding this method
+
+ if (intent != null) {
+ String action = intent.getAction();
+ if (action != null){
+ if(action.equalsIgnoreCase(TransportConstants.START_ROUTER_SERVICE_ACTION)) {
+ if (intent.getBooleanExtra(RECONNECT_LANG_CHANGE, false)) {
+ onSdlEnabled(context, intent);
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlRouterService.java b/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlRouterService.java
new file mode 100755
index 000000000..b4bec8cde
--- /dev/null
+++ b/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlRouterService.java
@@ -0,0 +1,8 @@
+package com.sdl.hellosdlandroid;
+
+
+public class SdlRouterService extends com.smartdevicelink.transport.SdlRouterService {
+
+
+
+}
diff --git a/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlService.java b/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlService.java
new file mode 100755
index 000000000..2847a3fd6
--- /dev/null
+++ b/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlService.java
@@ -0,0 +1,274 @@
+package com.sdl.hellosdlandroid;
+
+import android.annotation.SuppressLint;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Build;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.smartdevicelink.exception.SdlException;
+import com.smartdevicelink.managers.CompletionListener;
+import com.smartdevicelink.managers.SdlManager;
+import com.smartdevicelink.managers.SdlManagerListener;
+import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCNotification;
+import com.smartdevicelink.proxy.RPCRequest;
+import com.smartdevicelink.proxy.TTSChunkFactory;
+import com.smartdevicelink.proxy.rpc.AddCommand;
+import com.smartdevicelink.proxy.rpc.MenuParams;
+import com.smartdevicelink.proxy.rpc.OnCommand;
+import com.smartdevicelink.proxy.rpc.OnHMIStatus;
+import com.smartdevicelink.proxy.rpc.Speak;
+import com.smartdevicelink.proxy.rpc.enums.AppHMIType;
+import com.smartdevicelink.proxy.rpc.enums.FileType;
+import com.smartdevicelink.proxy.rpc.enums.HMILevel;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
+import com.smartdevicelink.transport.BTTransportConfig;
+import com.smartdevicelink.transport.BaseTransportConfig;
+import com.smartdevicelink.transport.MultiplexTransportConfig;
+import com.smartdevicelink.transport.TCPTransportConfig;
+import com.smartdevicelink.transport.USBTransportConfig;
+
+import java.util.Collections;
+import java.util.Vector;
+
+public class SdlService extends Service {
+
+ private static final String TAG = "SDL Service";
+
+ private static final String APP_NAME = "Hello Sdl";
+ private static final String APP_ID = "8678309";
+
+ private static final String ICON_FILENAME = "hello_sdl_icon.png";
+ private static final String SDL_IMAGE_FILENAME = "sdl_full_image.png";
+
+ private static final String WELCOME_SHOW = "Welcome to HelloSDL";
+ private static final String WELCOME_SPEAK = "Welcome to Hello S D L";
+
+ private static final String TEST_COMMAND_NAME = "Test Command";
+ private static final int TEST_COMMAND_ID = 1;
+
+ private static final int FOREGROUND_SERVICE_ID = 111;
+
+ // TCP/IP transport config
+ // The default port is 12345
+ // The IP is of the machine that is running SDL Core
+ private static final int TCP_PORT = 12345;
+ private static final String DEV_MACHINE_IP_ADDRESS = "192.168.1.78";
+
+ // variable to create and call functions of the SyncProxy
+ private SdlManager sdlManager = null;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onCreate() {
+ Log.d(TAG, "onCreate");
+ super.onCreate();
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ enterForeground();
+ }
+ }
+
+ // Helper method to let the service enter foreground mode
+ @SuppressLint("NewApi")
+ public void enterForeground() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ NotificationChannel channel = new NotificationChannel(APP_ID, "SdlService", NotificationManager.IMPORTANCE_DEFAULT);
+ NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ if (notificationManager != null) {
+ notificationManager.createNotificationChannel(channel);
+ Notification serviceNotification = new Notification.Builder(this, channel.getId())
+ .setContentTitle("Connected through SDL")
+ .setSmallIcon(R.drawable.ic_sdl)
+ .build();
+ startForeground(FOREGROUND_SERVICE_ID, serviceNotification);
+ }
+ }
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ startProxy();
+ return START_STICKY;
+ }
+
+ @Override
+ public void onDestroy() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ stopForeground(true);
+ }
+
+ if (sdlManager != null) {
+ sdlManager.dispose();
+ }
+
+ super.onDestroy();
+ }
+
+ private void startProxy() {
+ // This logic is to select the correct transport and security levels defined in the selected build flavor
+ // Build flavors are selected by the "build variants" tab typically located in the bottom left of Android Studio
+ // Typically in your app, you will only set one of these.
+ if (sdlManager == null) {
+ Log.i(TAG, "Starting SDL Proxy");
+ BaseTransportConfig transport = null;
+ if (BuildConfig.TRANSPORT.equals("MULTI")) {
+ int securityLevel;
+ if (BuildConfig.SECURITY.equals("HIGH")) {
+ securityLevel = MultiplexTransportConfig.FLAG_MULTI_SECURITY_HIGH;
+ } else if (BuildConfig.SECURITY.equals("MED")) {
+ securityLevel = MultiplexTransportConfig.FLAG_MULTI_SECURITY_MED;
+ } else if (BuildConfig.SECURITY.equals("LOW")) {
+ securityLevel = MultiplexTransportConfig.FLAG_MULTI_SECURITY_LOW;
+ } else {
+ securityLevel = MultiplexTransportConfig.FLAG_MULTI_SECURITY_OFF;
+ }
+ transport = new MultiplexTransportConfig(this, APP_ID, securityLevel);
+ } else if (BuildConfig.TRANSPORT.equals("TCP")) {
+ transport = new TCPTransportConfig(TCP_PORT, DEV_MACHINE_IP_ADDRESS, true);
+ } else if (BuildConfig.TRANSPORT.equals("MULTI_HB")) {
+ MultiplexTransportConfig mtc = new MultiplexTransportConfig(this, APP_ID, MultiplexTransportConfig.FLAG_MULTI_SECURITY_OFF);
+ mtc.setRequiresHighBandwidth(true);
+ transport = mtc;
+ }
+
+ // The app type to be used
+ Vector<AppHMIType> appType = new Vector<>();
+ appType.add(AppHMIType.MEDIA);
+
+ // The manager listener helps you know when certain events that pertain to the SDL Manager happen
+ // Here we will listen for ON_HMI_STATUS and ON_COMMAND notifications
+ SdlManagerListener listener = new SdlManagerListener() {
+ @Override
+ public void onStart() {
+ // HMI Status Listener
+ sdlManager.addOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, new OnRPCNotificationListener() {
+ @Override
+ public void onNotified(RPCNotification notification) {
+ OnHMIStatus status = (OnHMIStatus) notification;
+ if (status.getHmiLevel() == HMILevel.HMI_FULL && ((OnHMIStatus) notification).getFirstRun()) {
+ sendCommands();
+ performWelcomeSpeak();
+ performWelcomeShow();
+ }
+ }
+ });
+
+ // Menu Selected Listener
+ sdlManager.addOnRPCNotificationListener(FunctionID.ON_COMMAND, new OnRPCNotificationListener() {
+ @Override
+ public void onNotified(RPCNotification notification) {
+ OnCommand command = (OnCommand) notification;
+ Integer id = command.getCmdID();
+ if(id != null){
+ switch(id){
+ case TEST_COMMAND_ID:
+ showTest();
+ break;
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onDestroy() {
+ SdlService.this.stopSelf();
+ }
+
+ @Override
+ public void onError(String info, Exception e) {
+ }
+ };
+
+ // Create App Icon, this is set in the SdlManager builder
+ SdlArtwork appIcon = new SdlArtwork(ICON_FILENAME, FileType.GRAPHIC_PNG, R.mipmap.ic_launcher, true);
+
+ // The manager builder sets options for your session
+ SdlManager.Builder builder = new SdlManager.Builder(this, APP_ID, APP_NAME, listener);
+ builder.setAppTypes(appType);
+ builder.setTransportType(transport);
+ builder.setAppIcon(appIcon);
+ sdlManager = builder.build();
+ sdlManager.start();
+ }
+ }
+
+ /**
+ * Add commands for the app on SDL.
+ */
+ private void sendCommands(){
+ AddCommand command = new AddCommand();
+ MenuParams params = new MenuParams();
+ params.setMenuName(TEST_COMMAND_NAME);
+ command.setCmdID(TEST_COMMAND_ID);
+ command.setMenuParams(params);
+ command.setVrCommands(Collections.singletonList(TEST_COMMAND_NAME));
+ sendRpcRequest(command);
+ }
+
+ /**
+ * Will speak a sample welcome message
+ */
+ private void performWelcomeSpeak(){
+ sendRpcRequest(new Speak(TTSChunkFactory.createSimpleTTSChunks(WELCOME_SPEAK)));
+ }
+
+ /**
+ * Use the Screen Manager to set the initial screen text and set the image.
+ * Because we are setting multiple items, we will call beginTransaction() first,
+ * and finish with commit() when we are done.
+ */
+ private void performWelcomeShow() {
+ sdlManager.getScreenManager().beginTransaction();
+ sdlManager.getScreenManager().setTextField1(APP_NAME);
+ sdlManager.getScreenManager().setTextField2(WELCOME_SHOW);
+ sdlManager.getScreenManager().setPrimaryGraphic(new SdlArtwork(SDL_IMAGE_FILENAME, FileType.GRAPHIC_PNG, R.drawable.sdl, true));
+ sdlManager.getScreenManager().commit(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ if (success){
+ Log.i(TAG, "welcome show successful");
+ }
+ }
+ });
+ }
+
+ /**
+ * Will show a sample test message on screen as well as speak a sample test message
+ */
+ private void showTest(){
+ sdlManager.getScreenManager().beginTransaction();
+ sdlManager.getScreenManager().setTextField1("Command has been selected");
+ sdlManager.getScreenManager().setTextField2("");
+ sdlManager.getScreenManager().commit(null);
+
+ sendRpcRequest(new Speak(TTSChunkFactory.createSimpleTTSChunks(TEST_COMMAND_NAME)));
+ }
+
+ /**
+ * Sends an RPC Request to the connected head unit. Automatically adds a correlation id.
+ * @param request the rpc request that is to be sent to the module
+ */
+ private void sendRpcRequest(RPCRequest request){
+ try {
+ sdlManager.sendRPC(request);
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+ }
+
+} \ No newline at end of file
diff --git a/hello_sdl_android/src/main/res.zip b/hello_sdl_android/src/main/res.zip
new file mode 100755
index 000000000..16370f43a
--- /dev/null
+++ b/hello_sdl_android/src/main/res.zip
Binary files differ
diff --git a/hello_sdl_android/src/main/res/drawable/sdl.png b/hello_sdl_android/src/main/res/drawable/sdl.png
new file mode 100755
index 000000000..5cfc0f84a
--- /dev/null
+++ b/hello_sdl_android/src/main/res/drawable/sdl.png
Binary files differ
diff --git a/hello_sdl_android/src/main/res/layout/activity_main.xml b/hello_sdl_android/src/main/res/layout/activity_main.xml
new file mode 100755
index 000000000..8da613491
--- /dev/null
+++ b/hello_sdl_android/src/main/res/layout/activity_main.xml
@@ -0,0 +1,16 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ tools:context="com.sdl.hellosdlandroid.MainActivity" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/hello_world" />
+
+</RelativeLayout>
diff --git a/hello_sdl_android/src/main/res/menu/main.xml b/hello_sdl_android/src/main/res/menu/main.xml
new file mode 100755
index 000000000..d74718db3
--- /dev/null
+++ b/hello_sdl_android/src/main/res/menu/main.xml
@@ -0,0 +1,12 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:context="com.sdl.hellosdlandroid.MainActivity" >
+
+ <item
+ android:id="@+id/action_settings"
+ android:orderInCategory="100"
+ android:title="@string/action_settings"
+ app:showAsAction="never"/>
+
+</menu>
diff --git a/hello_sdl_android/src/main/res/mipmap-hdpi/ic_launcher.png b/hello_sdl_android/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100755
index 000000000..d10bd53b0
--- /dev/null
+++ b/hello_sdl_android/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/hello_sdl_android/src/main/res/mipmap-mdpi/ic_launcher.png b/hello_sdl_android/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100755
index 000000000..239564b34
--- /dev/null
+++ b/hello_sdl_android/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/hello_sdl_android/src/main/res/mipmap-xhdpi/ic_launcher.png b/hello_sdl_android/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100755
index 000000000..485ca6880
--- /dev/null
+++ b/hello_sdl_android/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/hello_sdl_android/src/main/res/mipmap-xxhdpi/ic_launcher.png b/hello_sdl_android/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100755
index 000000000..60574c2af
--- /dev/null
+++ b/hello_sdl_android/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/hello_sdl_android/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/hello_sdl_android/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100755
index 000000000..c43021775
--- /dev/null
+++ b/hello_sdl_android/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/hello_sdl_android/src/main/res/values-v11/styles.xml b/hello_sdl_android/src/main/res/values-v11/styles.xml
new file mode 100755
index 000000000..a4a95bc46
--- /dev/null
+++ b/hello_sdl_android/src/main/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+</resources>
diff --git a/hello_sdl_android/src/main/res/values-v14/styles.xml b/hello_sdl_android/src/main/res/values-v14/styles.xml
new file mode 100755
index 000000000..664f4f162
--- /dev/null
+++ b/hello_sdl_android/src/main/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<resources>
+
+ <!--
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/styles.xml and
+ res/values-v11/styles.xml on API 14+ devices.
+ -->
+ <style name="AppBaseTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <!-- API 14 theme customizations can go here. -->
+ </style>
+
+</resources>
diff --git a/hello_sdl_android/src/main/res/values-w820dp/dimens.xml b/hello_sdl_android/src/main/res/values-w820dp/dimens.xml
new file mode 100755
index 000000000..f3e70203b
--- /dev/null
+++ b/hello_sdl_android/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,10 @@
+<resources>
+
+ <!--
+ Example customization of dimensions originally defined in res/values/dimens.xml
+ (such as screen margins) for screens with more than 820dp of available width. This
+ would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively).
+ -->
+ <dimen name="activity_horizontal_margin">64dp</dimen>
+
+</resources>
diff --git a/hello_sdl_android/src/main/res/values/dimens.xml b/hello_sdl_android/src/main/res/values/dimens.xml
new file mode 100755
index 000000000..55c1e5908
--- /dev/null
+++ b/hello_sdl_android/src/main/res/values/dimens.xml
@@ -0,0 +1,7 @@
+<resources>
+
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+
+</resources>
diff --git a/hello_sdl_android/src/main/res/values/strings.xml b/hello_sdl_android/src/main/res/values/strings.xml
new file mode 100755
index 000000000..6f96374c6
--- /dev/null
+++ b/hello_sdl_android/src/main/res/values/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="app_name">Hello Sdl Android</string>
+ <string name="hello_world">Hello SDL!</string>
+ <string name="action_settings">Settings</string>
+
+</resources>
diff --git a/hello_sdl_android/src/main/res/values/styles.xml b/hello_sdl_android/src/main/res/values/styles.xml
new file mode 100755
index 000000000..845fb572b
--- /dev/null
+++ b/hello_sdl_android/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+<resources>
+
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
+ </style>
+
+ <!-- Application theme. -->
+ <style name="AppTheme" parent="AppBaseTheme">
+ <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+ </style>
+
+</resources>
diff --git a/hello_sdl_android/src/main/res/xml/accessory_filter.xml b/hello_sdl_android/src/main/res/xml/accessory_filter.xml
new file mode 100755
index 000000000..4b0ab7c83
--- /dev/null
+++ b/hello_sdl_android/src/main/res/xml/accessory_filter.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resource>
+ <usb-accessory
+ manufacturer="SDL"
+ model="Core"
+ version="1.0"/>
+</resource> \ No newline at end of file
diff --git a/sdl_android/ROUTER_SERVICE_MESSAGING_PROTOCOL.md b/sdl_android/ROUTER_SERVICE_MESSAGING_PROTOCOL.md
new file mode 100644
index 000000000..e641b8be2
--- /dev/null
+++ b/sdl_android/ROUTER_SERVICE_MESSAGING_PROTOCOL.md
@@ -0,0 +1,70 @@
+# Router Service Messaging Protocol
+
+This document should aid in the understanding and change log of the messages sent between the client proxy and the router service.
+
+Modifications between versions will likely be breaking and have to be dealt with accordingly as the binder can't handle new parcelable objects or additions to existing parcelable objects. The router service and transport broker will have to handle this appropriately.
+
+All values included are their constant names in the project, not the actual values.
+
+
+## Version 1
+
+First version of the messaging protocol. There is no versioning negotiation or awareness at this point.
+
+__Notes:__
+
+- This version can only handle a single transport. If a different transport connects/disconnects beyond the one being used by the app during the session the router service will not inform the client.
+
+`ROUTER_REGISTER_CLIENT`
+
+`APP_ID_EXTRA_STRING`
+
+`ROUTER_REGISTER_CLIENT_RESPONSE`
+
+`Message.arg1` will be results. Possible results:
+
+- `ROUTER_REGISTER_ALT_TRANSPORT_RESPONSE_SUCESS`
+- `ROUTER_REGISTER_ALT_TRANSPORT_ALREADY_CONNECTED`
+- `ROUTER_SHUTTING_DOWN_NOTIFICATION`
+- `ROUTER_SHUTTING_DOWN_REASON_NEWER_SERVICE`
+
+### Version 1.1
+
+
+## Version 2
+
+Version 2 adds the ability to perform versioning of the messaging protocol between the client app (TransportBroker) and the router service.
+
+
+### Additions
+
+
+###### TransportRecord
+
+`TransportRecord` is a new parcelable object that contains more in depth information about the transport specifics than simply supplying a `TransportType` enum as a string.
+
+### Modifications
+
+###### ROUTER\_REGISTER\_CLIENT
+
+The `ROUTER_REGISTER_CLIENT ` message now includes an integer value with key `ROUTER_MESSAGING_VERSION` that contains the clients max router service messaging protocol version.
+
+
+
+###### SdlPacket
+
+The `SdlPacket` object will now contain the messaging version and a `TransportRecord` entry. The messaging version will help inform
+
+
+###### HARDWARE\_CONNECTION\_EVENT
+
+The `HARDWARE_CONNECTION_EVENT` message has the following changes:
+
+- `Message.arg1` will now contain the actual type of event:
+ - `HARDWARE_CONNECTION_EVENT_CONNECTED`
+ - `HARDWARE_CONNECTION_EVENT_DISCONNECTED`
+- `CURRENT_HARDWARE_CONNECTED` key has been added which has a value of an `ArrayList<TransportRecord`. It will always contain the currently connected hardware from the router service.
+- During a disconnect, `TRANSPORT_DISCONNECTED` key has been added that contains a `` of the transport that previously disconnected
+- The extra from the `HARDWARE_CONNECTION_EVENT` message has been deprecated in favor of `TRANSPORT_DISCONNECTED`.
+
+
diff --git a/sdl_android/build.gradle b/sdl_android/build.gradle
index aa6c59af2..e7bdc512a 100644
--- a/sdl_android/build.gradle
+++ b/sdl_android/build.gradle
@@ -1,12 +1,12 @@
apply plugin: 'com.android.library'
android {
- compileSdkVersion 27
+ compileSdkVersion 28
defaultConfig {
minSdkVersion 8
- targetSdkVersion 19
- versionCode 7
- versionName "4.6.3"
+ targetSdkVersion 26
+ versionCode 8
+ versionName "4.7.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
resValue "string", "SDL_LIB_VERSION", '\"' + versionName + '\"'
}
@@ -40,7 +40,10 @@ dependencies {
})
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.9.0'
- api 'com.android.support:support-annotations:27.1.1'
+ androidTestImplementation 'org.mockito:mockito-android:2.9.0'
+ api 'com.android.support:support-annotations:28.0.0'
+ api "android.arch.lifecycle:extensions:1.1.1"
+ annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
}
buildscript {
diff --git a/sdl_android/src/androidTest/assets/json/AddSubMenu.json b/sdl_android/src/androidTest/assets/json/AddSubMenu.json
index 5d86c2615..37cc46adb 100644
--- a/sdl_android/src/androidTest/assets/json/AddSubMenu.json
+++ b/sdl_android/src/androidTest/assets/json/AddSubMenu.json
@@ -5,7 +5,11 @@
"parameters":{
"menuID":765,
"position":2,
- "menuName":"Menu Name"
+ "menuName":"Menu Name",
+ "menuIcon":{
+ "value":"cmdImage1.png",
+ "imageType":"DYNAMIC"
+ }
}
},
"response":{
diff --git a/sdl_android/src/androidTest/assets/json/GetVehicleData.json b/sdl_android/src/androidTest/assets/json/GetVehicleData.json
index e27937718..81b25ef87 100644
--- a/sdl_android/src/androidTest/assets/json/GetVehicleData.json
+++ b/sdl_android/src/androidTest/assets/json/GetVehicleData.json
@@ -1,6 +1,6 @@
{
"request":{
- "name":"AddCommand",
+ "name":"GetVehicleData",
"correlationID":129,
"parameters":{
"speed":true,
@@ -11,6 +11,7 @@
"prndl":true,
"tirePressure":true,
"engineTorque":false,
+ "engineOilLife":true,
"odometer":true,
"gps":false,
"fuelLevel_State":true,
@@ -27,11 +28,14 @@
"airbagStatus":true,
"emergencyEvent":false,
"clusterModeStatus":true,
- "myKey":true
+ "myKey":true,
+ "fuelRange":true,
+ "turnSignal":true,
+ "electronicParkBrakeStatus":true
}
},
"response":{
- "name":"AddCommandResponse",
+ "name":"GetVehicleDataResponse",
"correlationID":130,
"parameters":{
"speed":35.6,
@@ -50,6 +54,7 @@
"rightRear":"ALERT"
},
"engineTorque":518.3,
+ "engineOilLife":19.3,
"odometer":140000,
"gps":{
"longitudeDegrees":104.2,
@@ -72,6 +77,7 @@
"speed":30.5
},
"fuelLevel_State":"ALERT",
+ "turnSignal":"OFF",
"instantFuelConsumption":2.76,
"beltStatus":{
"driverBeltDeployed":"NO",
@@ -151,7 +157,18 @@
},
"myKey":{
"e911Override":"NO_DATA_EXISTS"
- }
+ },
+ "electronicParkBrakeStatus":"CLOSED",
+ "fuelRange":[
+ {
+ "type":"GASOLINE",
+ "range":100.0
+ },
+ {
+ "type":"DIESEL",
+ "range":10.0
+ }
+ ]
}
}
} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/assets/json/PutFile.json b/sdl_android/src/androidTest/assets/json/PutFile.json
index 70e80a09a..e989a62aa 100644
--- a/sdl_android/src/androidTest/assets/json/PutFile.json
+++ b/sdl_android/src/androidTest/assets/json/PutFile.json
@@ -9,6 +9,7 @@
"syncFileName":"filename.txt",
"offset":2,
"length":456,
+ "crc":2020,
"bulkData":[
0,
1,
diff --git a/sdl_android/src/androidTest/assets/json/RegisterAppInterface.json b/sdl_android/src/androidTest/assets/json/RegisterAppInterface.json
index fe1edb518..1d13635a9 100644
--- a/sdl_android/src/androidTest/assets/json/RegisterAppInterface.json
+++ b/sdl_android/src/androidTest/assets/json/RegisterAppInterface.json
@@ -18,7 +18,8 @@
"SOCIAL",
"MEDIA"
],
- "appID":"t4weGRSWY",
+ "appID":"123e4567e8",
+ "fullAppID":"123e4567-e89b-12d3-a456-426655440000",
"languageDesired":"PT-BR",
"deviceInfo":{
"hardware":"My Hardware",
@@ -31,6 +32,40 @@
"appName":"Dumb app",
"ngnMediaScreenAppName":"DA",
"isMediaApplication":true,
+ "dayColorScheme": {
+ "backgroundColor": {
+ "blue": 9,
+ "green": 8,
+ "red": 7
+ },
+ "secondaryColor": {
+ "blue": 6,
+ "green": 5,
+ "red": 4
+ },
+ "primaryColor": {
+ "blue": 3,
+ "green": 2,
+ "red": 1
+ }
+ },
+ "nightColorScheme": {
+ "backgroundColor": {
+ "blue": 18,
+ "green": 17,
+ "red": 16
+ },
+ "secondaryColor": {
+ "blue": 15,
+ "green": 14,
+ "red": 13
+ },
+ "primaryColor": {
+ "blue": 12,
+ "green": 11,
+ "red": 10
+ }
+ },
"vrSynonyms":[
"dumb",
"really dumb app"
@@ -192,7 +227,8 @@
0,
1,
2
- ]
+ ],
+ "iconResumed":true
}
}
} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/assets/json/SetDisplayLayout.json b/sdl_android/src/androidTest/assets/json/SetDisplayLayout.json
index 3b80dfb36..ec9e62f54 100644
--- a/sdl_android/src/androidTest/assets/json/SetDisplayLayout.json
+++ b/sdl_android/src/androidTest/assets/json/SetDisplayLayout.json
@@ -3,7 +3,41 @@
"name":"SetDisplayLayout",
"correlationID":149,
"parameters":{
- "displayLayout":"someDisplayLayout"
+ "displayLayout":"someDisplayLayout",
+ "dayColorScheme": {
+ "backgroundColor": {
+ "blue": 9,
+ "green": 8,
+ "red": 7
+ },
+ "secondaryColor": {
+ "blue": 6,
+ "green": 5,
+ "red": 4
+ },
+ "primaryColor": {
+ "blue": 3,
+ "green": 2,
+ "red": 1
+ }
+ },
+ "nightColorScheme": {
+ "backgroundColor": {
+ "blue": 18,
+ "green": 17,
+ "red": 16
+ },
+ "secondaryColor": {
+ "blue": 15,
+ "green": 14,
+ "red": 13
+ },
+ "primaryColor": {
+ "blue": 12,
+ "green": 11,
+ "red": 10
+ }
+ }
}
},
"response":{
diff --git a/sdl_android/src/androidTest/assets/json/SetMediaClockTimer.json b/sdl_android/src/androidTest/assets/json/SetMediaClockTimer.json
index af1671200..e4950d05d 100644
--- a/sdl_android/src/androidTest/assets/json/SetMediaClockTimer.json
+++ b/sdl_android/src/androidTest/assets/json/SetMediaClockTimer.json
@@ -13,7 +13,8 @@
"seconds":19,
"hours":12
},
- "updateMode":"COUNTDOWN"
+ "updateMode":"COUNTDOWN",
+ "audioStreamingIndicator":"PLAY"
}
},
"response":{
diff --git a/sdl_android/src/androidTest/assets/json/SubscribeVehicleData.json b/sdl_android/src/androidTest/assets/json/SubscribeVehicleData.json
index 977057cf1..92cf00a1b 100644
--- a/sdl_android/src/androidTest/assets/json/SubscribeVehicleData.json
+++ b/sdl_android/src/androidTest/assets/json/SubscribeVehicleData.json
@@ -10,6 +10,7 @@
"prndl":true,
"tirePressure":true,
"engineTorque":false,
+ "engineOilLife":true,
"odometer":true,
"gps":false,
"fuelLevel_State":true,
@@ -26,7 +27,10 @@
"airbagStatus":true,
"emergencyEvent":false,
"clusterModeStatus":true,
- "myKey":true
+ "myKey":true,
+ "fuelRange":true,
+ "turnSignal":true,
+ "electronicParkBrakeStatus":true
}
},
"response":{
@@ -61,6 +65,10 @@
"dataType":"VEHICLEDATA_SPEED",
"resultCode":"INVALID_ID"
},
+ "engineOilLife":{
+ "dataType":"VEHICLEDATA_ENGINEOILLIFE",
+ "resultCode":"SUCCESS"
+ },
"odometer":{
"dataType":"VEHICLEDATA_ODOMETER",
"resultCode":"SUCCESS"
@@ -128,6 +136,18 @@
"myKey":{
"dataType":"VEHICLEDATA_MYKEY",
"resultCode":"IGNORED"
+ },
+ "fuelRange":{
+ "dataType":"VEHICLEDATA_FUELRANGE",
+ "resultCode":"SUCCESS"
+ },
+ "turnSignal":{
+ "dataType":"VEHICLEDATA_TURNSIGNAL",
+ "resultCode":"IGNORED"
+ },
+ "electronicParkBrakeStatus":{
+ "dataType":"VEHICLEDATA_ELECTRONICPARKBRAKESTATUS",
+ "resultCode":"SUCCESS"
}
}
}
diff --git a/sdl_android/src/androidTest/assets/json/SystemRequest.json b/sdl_android/src/androidTest/assets/json/SystemRequest.json
index 7768db7e4..44c6d5205 100644
--- a/sdl_android/src/androidTest/assets/json/SystemRequest.json
+++ b/sdl_android/src/androidTest/assets/json/SystemRequest.json
@@ -4,7 +4,8 @@
"correlationID":165,
"parameters":{
"fileName":"fileName.txt",
- "requestType":"AUTH_CHALLENGE",
+ "requestType":"OEM_SPECIFIC",
+ "requestSubType":"TEST",
"data":[
"data1",
"data2",
diff --git a/sdl_android/src/androidTest/assets/json/UnsubscribeVehicleData.json b/sdl_android/src/androidTest/assets/json/UnsubscribeVehicleData.json
index 24b41a0b9..d01b99aa8 100644
--- a/sdl_android/src/androidTest/assets/json/UnsubscribeVehicleData.json
+++ b/sdl_android/src/androidTest/assets/json/UnsubscribeVehicleData.json
@@ -10,6 +10,7 @@
"prndl":true,
"tirePressure":true,
"engineTorque":false,
+ "engineOilLife":true,
"odometer":true,
"gps":false,
"fuelLevel_State":true,
@@ -26,13 +27,16 @@
"airbagStatus":true,
"emergencyEvent":false,
"clusterModeStatus":true,
- "myKey":true
+ "myKey":true,
+ "fuelRange":true,
+ "turnSignal":true,
+ "electronicParkBrakeStatus":true
}
},
"response":{
"name":"UnsubscribeVehicleDataResponse",
"correlationID":172,
- "parameters":{
+ "parameters":{
"speed":{
"dataType":"VEHICLEDATA_SPEED",
"resultCode":"SUCCESS"
@@ -61,6 +65,10 @@
"dataType":"VEHICLEDATA_SPEED",
"resultCode":"INVALID_ID"
},
+ "engineOilLife":{
+ "dataType":"VEHICLEDATA_ENGINEOILLIFE",
+ "resultCode":"SUCCESS"
+ },
"odometer":{
"dataType":"VEHICLEDATA_ODOMETER",
"resultCode":"SUCCESS"
@@ -128,6 +136,18 @@
"myKey":{
"dataType":"VEHICLEDATA_MYKEY",
"resultCode":"IGNORED"
+ },
+ "fuelRange":{
+ "dataType":"VEHICLEDATA_FUELRANGE",
+ "resultCode":"SUCCESS"
+ },
+ "turnSignal":{
+ "dataType":"VEHICLEDATA_TURNSIGNAL",
+ "resultCode":"IGNORED"
+ },
+ "electronicParkBrakeStatus":{
+ "dataType":"VEHICLEDATA_ELECTRONICPARKBRAKESTATUS",
+ "resultCode":"SUCCESS"
}
}
}
diff --git a/sdl_android/src/androidTest/assets/xml/MOBILE_API_4.5.0.xml b/sdl_android/src/androidTest/assets/xml/MOBILE_API.xml
index ffb005ec6..769e87d3c 100644
--- a/sdl_android/src/androidTest/assets/xml/MOBILE_API_4.5.0.xml
+++ b/sdl_android/src/androidTest/assets/xml/MOBILE_API.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" standalone="no"?>
<?xml-stylesheet type="text/xml" href="protocol2html.xsl"?>
-<interface name="SmartDeviceLink RAPI" version="4.5.0" date="2017-09-22">
- <enum name="Result" internal_scope="base">
+<interface name="SmartDeviceLink RAPI" version="5.0.0" minVersion="1.0" date="2018-10-03">
+ <enum name="Result" internal_scope="base" since="1.0">
<element name="SUCCESS">
<description>The request succeeded</description>
</element>
@@ -45,7 +45,7 @@
For example when trying to delete a command set that is currently involved in an interaction.
</description>
</element>
- <element name="VEHICLE_DATA_NOT_AVAILABLE">
+ <element name="VEHICLE_DATA_NOT_AVAILABLE" since="2.0">
<description>The requested vehicle data is not available on this vehicle or is not published.</description>
</element>
<element name="TIMED_OUT">
@@ -99,45 +99,48 @@
<element name="GENERIC_ERROR">
<description>Provided data is valid but something went wrong in the lower layers.</description>
</element>
- <element name="USER_DISALLOWED">
+ <element name="USER_DISALLOWED" since="2.0">
<description>RPC is included in a functional group explicitly blocked by the user.</description>
</element>
<element name="TRUNCATED_DATA">
<description>The RPC (e.g. ReadDID) executed successfully but the data exceeded the platform maximum threshold and thus, only part of the data is available.</description>
</element>
- <element name="UNSUPPORTED_VERSION">
+ <element name="UNSUPPORTED_VERSION" since="2.0">
<description>Sync doesn't support the protocol that is requested by the mobile application</description>
</element>
- <element name="VEHICLE_DATA_NOT_ALLOWED">
+ <element name="VEHICLE_DATA_NOT_ALLOWED" since="2.0">
<description>The user has turned off access to vehicle data, and it is globally unavailable to mobile applications.</description>
</element>
- <element name="FILE_NOT_FOUND">
+ <element name="FILE_NOT_FOUND" since="3.0">
<description>A specified file could not be found on the headunit.</description>
</element>
<element name="CANCEL_ROUTE">
<description>User selected to Cancel Route.</description>
</element>
- <element name="SAVED">
+ <element name="SAVED" since="2.0">
<description>The RPC (e.g. Slider) executed successfully and the user elected to save the current position / value.</description>
</element>
- <element name="INVALID_CERT">
+ <element name="INVALID_CERT" since="3.0">
<description>The certificate provided during authentication is invalid.</description>
</element>
- <element name="EXPIRED_CERT">
+ <element name="EXPIRED_CERT" since="3.0">
<description>The certificate provided during authentication is expired.</description>
</element>
- <element name="RESUME_FAILED">
+ <element name="RESUME_FAILED" since="3.0">
<description>The provided hash ID does not match the hash of the current set of registered data or the core could not resume the previous data.</description>
</element>
- <element name="DATA_NOT_AVAILABLE">
+ <element name="DATA_NOT_AVAILABLE" since="4.5">
<description>The requested information is currently not available. This is different than UNSUPPORTED_RESOURCE because it implies the data is at some point available. </description>
</element>
- <element name="READ_ONLY">
+ <element name="READ_ONLY" since="4.5">
<description>The value being set is read only</description>
</element>
+ <element name="CORRUPTED_DATA" since="5.0">
+ <description>The data sent failed to pass CRC check in receiver end</description>
+ </element>
</enum>
- <enum name="ButtonPressMode">
+ <enum name="ButtonPressMode" since="1.0">
<element name="LONG">
<description>
A button was released, after it was pressed for a long time
@@ -152,7 +155,7 @@
</element>
</enum>
- <enum name="ButtonEventMode">
+ <enum name="ButtonEventMode" since="1.0">
<element name="BUTTONUP">
<description>A button has been released up</description>
</element>
@@ -161,7 +164,7 @@
</element>
</enum>
- <enum name="Language">
+ <enum name="Language" since="1.0">
<element name="EN-US" internal_name="EN_US">
<description>English - US</description>
</element>
@@ -171,117 +174,117 @@
<element name="FR-CA" internal_name="FR_CA">
<description>French - Canada</description>
</element>
- <element name="DE-DE" internal_name="DE_DE">
+ <element name="DE-DE" internal_name="DE_DE" since="2.0">
<description>German - Germany</description>
</element>
- <element name="ES-ES" internal_name="ES_ES">
+ <element name="ES-ES" internal_name="ES_ES" since="2.0">
<description>Spanish - Spain</description>
</element>
- <element name="EN-GB" internal_name="EN_GB">
+ <element name="EN-GB" internal_name="EN_GB" since="2.0">
<description>English - GB</description>
</element>
- <element name="RU-RU" internal_name="RU_RU">
+ <element name="RU-RU" internal_name="RU_RU" since="2.0">
<description>Russian - Russia</description>
</element>
- <element name="TR-TR" internal_name="TR_TR">
+ <element name="TR-TR" internal_name="TR_TR" since="2.0">
<description>Turkish - Turkey</description>
</element>
- <element name="PL-PL" internal_name="PL_PL">
+ <element name="PL-PL" internal_name="PL_PL" since="2.0">
<description>Polish - Poland</description>
</element>
- <element name="FR-FR" internal_name="FR_FR">
+ <element name="FR-FR" internal_name="FR_FR" since="2.0">
<description>French - France</description>
</element>
- <element name="IT-IT" internal_name="IT_IT">
+ <element name="IT-IT" internal_name="IT_IT" since="2.0">
<description>Italian - Italy</description>
</element>
- <element name="SV-SE" internal_name="SV_SE">
+ <element name="SV-SE" internal_name="SV_SE" since="2.0">
<description>Swedish - Sweden</description>
</element>
- <element name="PT-PT" internal_name="PT_PT">
+ <element name="PT-PT" internal_name="PT_PT" since="2.0">
<description>Portuguese - Portugal</description>
</element>
- <element name="NL-NL" internal_name="NL_NL">
+ <element name="NL-NL" internal_name="NL_NL" since="2.0">
<description>Dutch (Standard) - Netherlands</description>
</element>
- <element name="EN-AU" internal_name="EN_AU">
+ <element name="EN-AU" internal_name="EN_AU" since="2.0">
<description>English - Australia</description>
</element>
- <element name="ZH-CN" internal_name="ZH_CN">
+ <element name="ZH-CN" internal_name="ZH_CN" since="2.0">
<description>Mandarin - China</description>
</element>
- <element name="ZH-TW" internal_name="ZH_TW">
+ <element name="ZH-TW" internal_name="ZH_TW" since="2.0">
<description>Mandarin - Taiwan</description>
</element>
- <element name="JA-JP" internal_name="JA_JP">
+ <element name="JA-JP" internal_name="JA_JP" since="2.0">
<description>Japanese - Japan</description>
</element>
- <element name="AR-SA" internal_name="AR_SA">
+ <element name="AR-SA" internal_name="AR_SA" since="2.0">
<description>Arabic - Saudi Arabia</description>
</element>
- <element name="KO-KR" internal_name="KO_KR">
+ <element name="KO-KR" internal_name="KO_KR" since="2.0">
<description>Korean - South Korea</description>
</element>
- <element name="PT-BR" internal_name="PT_BR">
+ <element name="PT-BR" internal_name="PT_BR" since="2.0">
<description>Portuguese - Brazil</description>
</element>
- <element name="CS-CZ" internal_name="CS_CZ">
+ <element name="CS-CZ" internal_name="CS_CZ" since="2.0">
<description>Czech - Czech Republic</description>
</element>
- <element name="DA-DK" internal_name="DA_DK">
+ <element name="DA-DK" internal_name="DA_DK" since="2.0">
<description>Danish - Denmark</description>
</element>
- <element name="NO-NO" internal_name="NO_NO">
+ <element name="NO-NO" internal_name="NO_NO" since="2.0">
<description>Norwegian - Norway</description>
</element>
- <element name="NL-BE" internal_name="NL_BE">
+ <element name="NL-BE" internal_name="NL_BE" since="2.0">
<description>Dutch (Flemish) - Belgium</description>
</element>
- <element name="EL-GR" internal_name="EL_GR">
+ <element name="EL-GR" internal_name="EL_GR" since="2.0">
<description>Greek - Greece</description>
</element>
- <element name="HU-HU" internal_name="HU_HU">
+ <element name="HU-HU" internal_name="HU_HU" since="2.0">
<description>Hungarian - Hungary</description>
</element>
- <element name="FI-FI" internal_name="FI_FI">
+ <element name="FI-FI" internal_name="FI_FI" since="2.0">
<description>Finnish - Finland</description>
</element>
- <element name="SK-SK" internal_name="SK_SK">
+ <element name="SK-SK" internal_name="SK_SK" since="2.0">
<description>Slovak - Slovakia</description>
</element>
- <element name="EN-IN" internal_name="EN_IN">
+ <element name="EN-IN" internal_name="EN_IN" since="4.5">
<description>English - India</description>
</element>
- <element name="TH-TH" internal_name="TH_TH">
+ <element name="TH-TH" internal_name="TH_TH" since="4.5">
<description>Thai - Thailand</description>
</element>
- <element name="EN-SA" internal_name="EN_SA">
+ <element name="EN-SA" internal_name="EN_SA" since="4.5">
<description>English - Middle East</description>
</element>
- <element name="HE-IL" internal_name="HE_IL">
+ <element name="HE-IL" internal_name="HE_IL" since="4.5">
<description>Hebrew - Israel</description>
</element>
- <element name="RO-RO" internal_name="RO_RO">
+ <element name="RO-RO" internal_name="RO_RO" since="4.5">
<description>Romanian - Romania</description>
</element>
- <element name="UK-UA" internal_name="UK_UA">
+ <element name="UK-UA" internal_name="UK_UA" since="4.5">
<description>Ukrainian - Ukraine</description>
</element>
- <element name="ID-ID" internal_name="ID_ID">
+ <element name="ID-ID" internal_name="ID_ID" since="4.5">
<description>Indonesian - Indonesia</description>
</element>
- <element name="VI-VN" internal_name="VI_VN">
+ <element name="VI-VN" internal_name="VI_VN" since="4.5">
<description>Vietnamese - Vietnam</description>
</element>
- <element name="MS-MY" internal_name="MS_MY">
+ <element name="MS-MY" internal_name="MS_MY" since="4.5">
<description>Malay - Malaysia</description>
</element>
- <element name="HI-IN" internal_name="HI_IN">
+ <element name="HI-IN" internal_name="HI_IN" since="4.5">
<description>Hindi - India</description>
</element>
</enum>
- <enum name="UpdateMode">
+ <enum name="UpdateMode" since="1.0">
<description>Describes how the media clock timer should behave on the platform</description>
<element name="COUNTUP" >
<description>Starts the media clock timer counting upwards, as in time elapsed.</description>
@@ -300,7 +303,7 @@
</element>
</enum>
- <enum name="TimerMode">
+ <enum name="TimerMode" since="1.0">
<element name="UP" >
<description>Causes the media clock timer to update from 0:00 to a specified time</description>
</element>
@@ -312,7 +315,7 @@
</element>
</enum>
- <enum name="InteractionMode">
+ <enum name="InteractionMode" since="1.0">
<description>For application-requested interactions, this mode indicates the method in which the user is notified and uses the interaction.</description>
<element name="MANUAL_ONLY" >
<description>This mode causes the interaction to only occur on the display, meaning the choices are provided only via the display. No Voice Interaction.</description>
@@ -325,7 +328,7 @@
</element>
</enum>
- <enum name="LayoutMode">
+ <enum name="LayoutMode" since="3.0">
<description>For touchscreen interactions, the mode of how the choices are presented.</description>
<element name="ICON_ONLY" >
<description>This mode causes the interaction to display the previous set of choices as icons.</description>
@@ -344,7 +347,7 @@
</element>
</enum>
- <enum name="HMILevel">
+ <enum name="HMILevel" since="1.0">
<description>Enumeration that describes current levels of HMI.</description>
<element name="FULL" internal_name="HMI_FULL" />
<element name="LIMITED" internal_name="HMI_LIMITED" />
@@ -352,14 +355,14 @@
<element name="NONE" internal_name="HMI_NONE" />
</enum>
- <enum name="AudioStreamingState">
+ <enum name="AudioStreamingState" since="1.0">
<description>Enumeration that describes possible states of audio streaming.</description>
<element name="AUDIBLE" />
<element name="ATTENUATED" />
<element name="NOT_AUDIBLE" />
</enum>
- <enum name="SystemAction">
+ <enum name="SystemAction" since="1.0">
<description>Enumeration that describes system actions that can be triggered.</description>
<element name="DEFAULT_ACTION">
<description>Default action occurs. Standard behavior (e.g. SoftButton clears overlay).</description>
@@ -372,7 +375,7 @@
</element>
</enum>
- <enum name="SystemContext">
+ <enum name="SystemContext" since="1.0">
<description>Enumeration that describes possible contexts an app's HMI might be in. Communicated to whichever app is in HMI FULL, except Alert.</description>
<element name="MAIN" internal_name="SYSCTXT_MAIN">
<description>The app's persistent display (whether media/non-media/navigation) is fully visible onscreen.</description>
@@ -391,14 +394,20 @@
</element>
</enum>
- <enum name="SoftButtonType">
+ <enum name="VideoStreamingState" since="5.0">
+ <description>Enumeration that describes possible states of video streaming. </description>
+ <element name="STREAMABLE" />
+ <element name="NOT_STREAMABLE" />
+ </enum>
+
+ <enum name="SoftButtonType" since="2.0">
<description>Contains information about the SoftButton capabilities.</description>
<element name="TEXT" internal_name="SBT_TEXT"/>
<element name="IMAGE" internal_name="SBT_IMAGE"/>
<element name="BOTH" internal_name="SBT_BOTH"/>
</enum>
- <enum name="AppInterfaceUnregisteredReason">
+ <enum name="AppInterfaceUnregisteredReason" since="1.0">
<description>Error code, which comes from the module side.</description>
<!-- Deprecate
<element name="USER_EXIT" />
@@ -412,40 +421,41 @@
<element name="LANGUAGE_CHANGE" />
<element name="MASTER_RESET" />
<element name="FACTORY_DEFAULTS" />
- <element name="APP_UNAUTHORIZED" />
- <element name="PROTOCOL_VIOLATION" />
- <element name="UNSUPPORTED_HMI_RESOURCE" />
+ <element name="APP_UNAUTHORIZED" since="2.0" />
+ <element name="PROTOCOL_VIOLATION" since="4.0" />
+ <element name="UNSUPPORTED_HMI_RESOURCE" since="4.1" />
</enum>
- <enum name="TriggerSource">
+ <enum name="TriggerSource" since="1.0">
<description>Indicates the source from where the command was triggered.</description>
<element name="MENU" internal_name="TS_MENU" />
<element name="VR" internal_name="TS_VR" />
- <element name="KEYBOARD" internal_name="TS_KEYBOARD" />
+ <element name="KEYBOARD" internal_name="TS_KEYBOARD" since="3.0" />
</enum>
- <enum name="HmiZoneCapabilities">
+ <enum name="HmiZoneCapabilities" since="1.0">
<description>Contains information about the HMI zone capabilities.</description>
<description>For future use.</description>
<element name="FRONT" />
<element name="BACK" />
</enum>
- <enum name="SpeechCapabilities">
+ <enum name="SpeechCapabilities" since="1.0">
<description>Contains information about the TTS capabilities.</description>
<element name="TEXT" internal_name="SC_TEXT"/>
<element name="SAPI_PHONEMES" />
<element name="LHPLUS_PHONEMES" />
<element name="PRE_RECORDED" />
<element name="SILENCE" />
+ <element name="FILE" since="5.0" />
</enum>
- <enum name="VrCapabilities">
+ <enum name="VrCapabilities" since="1.0">
<description>Contains information about the VR capabilities.</description>
<element name="TEXT" internal_name="VR_TEXT"/>
</enum>
- <enum name="PrerecordedSpeech">
+ <enum name="PrerecordedSpeech" since="1.0">
<description>Contains a list of prerecorded speech items present on the platform.</description>
<element name="HELP_JINGLE" />
<element name="INITIAL_JINGLE" />
@@ -454,36 +464,51 @@
<element name="NEGATIVE_JINGLE" />
</enum>
- <enum name="SamplingRate">
+ <enum name="SamplingRate" since="2.0">
<description>Describes different sampling options for PerformAudioPassThru.</description>
- <element name="8KHZ" internal_name="SamplingRate_8KHZ"/>
- <element name="16KHZ" internal_name="SamplingRate_16KHZ"/>
- <element name="22KHZ" internal_name="SamplingRate_22KHZ"/>
- <element name="44KHZ" internal_name="SamplingRate_44KHZ"/>
+ <element name="8KHZ" internal_name="SamplingRate_8KHZ">
+ <description>Sampling rate of 8000 Hz.</description>
+ </element>
+ <element name="16KHZ" internal_name="SamplingRate_16KHZ">
+ <description>Sampling rate of 16000 Hz.</description>
+ </element>
+ <element name="22KHZ" internal_name="SamplingRate_22KHZ">
+ <description>Sampling rate of 22050 Hz.</description>
+ </element>
+ <element name="44KHZ" internal_name="SamplingRate_44KHZ">
+ <description>Sampling rate of 44100 Hz.</description>
+ </element>
</enum>
- <enum name="BitsPerSample">
+ <enum name="BitsPerSample" since="2.0">
<description>Describes different quality options for PerformAudioPassThru.</description>
- <element name="8_BIT" internal_name="BitsPerSample_8_BIT"/>
- <element name="16_BIT" internal_name="BitsPerSample_16_BIT"/>
+ <element name="8_BIT" internal_name="BitsPerSample_8_BIT">
+ <description>Audio sample is 8 bits wide, unsigned.</description>
+ </element>
+ <element name="16_BIT" internal_name="BitsPerSample_16_BIT">
+ <description>Audio sample is 16 bits wide, signed, and in little endian.</description>
+ </element>
</enum>
- <enum name="AudioType">
+ <enum name="AudioType" since="2.0">
<description>Describes different audio type options for PerformAudioPassThru.</description>
- <element name="PCM" />
+ <element name="PCM">
+ <description>Linear PCM.</description>
+ </element>
</enum>
- <struct name="AudioPassThruCapabilities">
+ <struct name="AudioPassThruCapabilities" since="2.0">
<description>
Describes different audio type configurations for PerformAudioPassThru.
e.g. {8kHz,8-bit,PCM}
+ The audio is recorded in monaural.
</description>
<param name="samplingRate" type="SamplingRate" mandatory="true"/>
<param name="bitsPerSample" type="BitsPerSample" mandatory="true"/>
<param name="audioType" type="AudioType" mandatory="true"/>
</struct>
- <enum name="VehicleDataType">
+ <enum name="VehicleDataType" since="2.0">
<description>Defines the data types that can be published and subscribed to.</description>
<element name="VEHICLEDATA_GPS">
<description>Notifies GPSData may be subscribed</description>
@@ -513,11 +538,25 @@
<element name="VEHICLEDATA_ENGINETORQUE" />
<element name="VEHICLEDATA_ACCPEDAL" />
<element name="VEHICLEDATA_STEERINGWHEEL" />
+ <element name="VEHICLEDATA_TURNSIGNAL" since="5.0" />
+ <element name="VEHICLEDATA_FUELRANGE" since="5.0" />
+ <element name="VEHICLEDATA_ENGINEOILLIFE" since="5.0" />
+ <element name="VEHICLEDATA_ELECTRONICPARKBRAKESTATUS" since="5.0" />
</enum>
- <enum name="ButtonName">
+ <enum name="ButtonName" since="1.0">
<description>Defines the hard (physical) and soft (touchscreen) buttons available from the module</description>
<element name="OK" />
+ <element name="PLAY_PAUSE" since="5.0">
+ <description>
+ The button name for the physical Play/Pause
+ toggle that can be used by media apps.
+ </description>
+ <warning>
+ Please use the physical OK button in order to
+ use a Play/Pause toggle for versions &lt; 4.5.0.
+ </warning>
+ </element>
<element name="SEEKLEFT" />
<element name="SEEKRIGHT" />
<element name="TUNEUP" />
@@ -535,28 +574,28 @@
<element name="CUSTOM_BUTTON" />
<element name="SEARCH" />
<!-- Climate Buttons -->
- <element name="AC_MAX" />
- <element name="AC" />
- <element name="RECIRCULATE" />
- <element name="FAN_UP" />
- <element name="FAN_DOWN" />
- <element name="TEMP_UP" />
- <element name="TEMP_DOWN" />
- <element name="DEFROST_MAX" />
- <element name="DEFROST" />
- <element name="DEFROST_REAR" />
- <element name="UPPER_VENT" />
- <element name="LOWER_VENT" />
+ <element name="AC_MAX" since="4.5" />
+ <element name="AC" since="4.5" />
+ <element name="RECIRCULATE" since="4.5" />
+ <element name="FAN_UP" since="4.5" />
+ <element name="FAN_DOWN" since="4.5" />
+ <element name="TEMP_UP" since="4.5" />
+ <element name="TEMP_DOWN" since="4.5" />
+ <element name="DEFROST_MAX" since="4.5" />
+ <element name="DEFROST" since="4.5" />
+ <element name="DEFROST_REAR" since="4.5" />
+ <element name="UPPER_VENT" since="4.5" />
+ <element name="LOWER_VENT" since="4.5" />
<!-- Radio Buttons -->
- <element name="VOLUME_UP" />
- <element name="VOLUME_DOWN" />
- <element name="EJECT" />
- <element name="SOURCE" />
- <element name="SHUFFLE" />
- <element name="REPEAT" />
+ <element name="VOLUME_UP" since="4.5" />
+ <element name="VOLUME_DOWN" since="4.5" />
+ <element name="EJECT" since="4.5" />
+ <element name="SOURCE" since="4.5" />
+ <element name="SHUFFLE" since="4.5" />
+ <element name="REPEAT" since="4.5" />
</enum>
- <enum name="MediaClockFormat">
+ <enum name="MediaClockFormat" since="1.0">
<element name="CLOCK1">
<description>
minutesFieldWidth = 2;minutesFieldMax = 19;secondsFieldWidth = 2;secondsFieldMax = 99;maxHours = 19;maxMinutes = 59;maxSeconds = 59;
@@ -569,7 +608,7 @@
used for Type V headunit
</description>
</element>
- <element name="CLOCK3">
+ <element name="CLOCK3" since="2.0">
<description>
minutesFieldWidth = 2;minutesFieldMax = 59;secondsFieldWidth = 2;secondsFieldMax = 59;maxHours = 9;maxMinutes = 59;maxSeconds = 59;
used for GEN1.1 MFD3/4/5 headunits
@@ -606,7 +645,7 @@
used for Type V headunit
</description>
</element>
- <element name="CLOCKTEXT4">
+ <element name="CLOCKTEXT4" since="2.0">
<description>
6 chars possible
Format: c :|sp c c : c c
@@ -617,22 +656,25 @@
</element>
</enum>
- <enum name="DisplayType">
+ <enum name="DisplayType" deprecated="true" since="5.0">
<description>See DAES for further infos regarding the displays</description>
<element name="CID"/>
<element name="TYPE2" />
<element name="TYPE5" />
<element name="NGN" />
- <element name="GEN2_8_DMA" />
- <element name="GEN2_6_DMA" />
- <element name="MFD3" />
- <element name="MFD4" />
- <element name="MFD5" />
- <element name="GEN3_8-INCH" internal_name="GEN3_8_INCH" />
- <element name="SDL_GENERIC" />
+ <element name="GEN2_8_DMA" since="3.0" />
+ <element name="GEN2_6_DMA" since="3.0" />
+ <element name="MFD3" since="2.0" />
+ <element name="MFD4" since="2.0" />
+ <element name="MFD5" since="2.0" />
+ <element name="GEN3_8-INCH" internal_name="GEN3_8_INCH" since="3.0" />
+ <element name="SDL_GENERIC" since="4.0" />
+ <history>
+ <enum name="DisplayType" since="1.0" until="5.0"/>
+ </history>
</enum>
- <enum name="TextFieldName">
+ <enum name="TextFieldName" since="1.0">
<element name="mainField1">
<description>The first line of first set of main fields of the persistent display; applies to "Show"</description>
</element>
@@ -665,51 +707,51 @@
<description>The first line of the alert text field; applies to "Alert"</description>
</element>
- <element name="alertText2">
+ <element name="alertText2" since="2.0">
<description>The second line of the alert text field; applies to "Alert"</description>
</element>
- <element name="alertText3">
+ <element name="alertText3" since="2.0">
<description>The third line of the alert text field; applies to "Alert"</description>
</element>
- <element name="scrollableMessageBody">
+ <element name="scrollableMessageBody" since="2.0">
<description>Long form body of text that can include newlines and tabs; applies to "ScrollableMessage"</description>
</element>
- <element name="initialInteractionText">
+ <element name="initialInteractionText" since="2.0">
<description> First line suggestion for a user response (in the case of VR enabled interaction)</description>
</element>
- <element name="navigationText1">
+ <element name="navigationText1" since="2.0">
<description> First line of navigation text</description>
</element>
- <element name="navigationText2">
+ <element name="navigationText2" since="2.0">
<description> Second line of navigation text</description>
</element>
- <element name="ETA">
+ <element name="ETA" since="2.0">
<description> Estimated Time of Arrival time for navigation</description>
</element>
- <element name="totalDistance">
+ <element name="totalDistance" since="2.0">
<description> Total distance to destination for navigation</description>
</element>
- <element name="audioPassThruDisplayText1">
+ <element name="audioPassThruDisplayText1" since="2.0">
<description> First line of text for audio pass thru</description>
</element>
- <element name="audioPassThruDisplayText2">
+ <element name="audioPassThruDisplayText2" since="2.0">
<description> Second line of text for audio pass thru</description>
</element>
- <element name="sliderHeader">
+ <element name="sliderHeader" since="2.0">
<description> Header text for slider</description>
</element>
- <element name="sliderFooter">
+ <element name="sliderFooter" since="2.0">
<description> Footer text for slider</description>
</element>
@@ -729,25 +771,25 @@
<description> Optional text to label an app menu button (for certain touchscreen platforms).</description>
</element>
- <element name="locationName">
+ <element name="locationName" since="4.0">
<description> Optional name / title of intended location for SendLocation.</description>
</element>
- <element name="locationDescription">
+ <element name="locationDescription" since="4.0">
<description> Optional description of intended location / establishment (if applicable) for SendLocation.</description>
</element>
- <element name="addressLines">
+ <element name="addressLines" since="4.0">
<description> Optional location address (if applicable) for SendLocation.</description>
</element>
- <element name="phoneNumber">
+ <element name="phoneNumber" since="4.0">
<description> Optional hone number of intended location / establishment (if applicable) for SendLocation.</description>
</element>
</enum>
- <enum name="ImageFieldName">
+ <enum name="ImageFieldName" since="3.0">
<element name="softButtonImage">
<description>The image field for SoftButton</description>
</element>
@@ -781,7 +823,11 @@
</element>
<element name="graphic">
- <description>The image field for Show</description>
+ <description>The primary image field for Show</description>
+ </element>
+
+ <element name="secondaryGraphic" since="5.0">
+ <description>The secondary image field for Show</description>
</element>
<element name="showConstantTBTIcon">
@@ -792,13 +838,13 @@
<description>The secondary image field for ShowConstantTBT</description>
</element>
- <element name="locationImage">
+ <element name="locationImage" since="4.0">
<description>The optional image of a destination / location</description>
</element>
</enum>
- <enum name="CharacterSet">
+ <enum name="CharacterSet" since="1.0">
<description>The list of potential character sets</description>
<element name="TYPE2SET">
<description>See [@TODO: create file ref]</description>
@@ -814,14 +860,14 @@
</element>
</enum>
- <enum name="TextAlignment">
+ <enum name="TextAlignment" since="1.0">
<description>The list of possible alignments, left, right, or centered</description>
<element name="LEFT_ALIGNED" />
<element name="RIGHT_ALIGNED" />
<element name="CENTERED" />
</enum>
- <enum name="TBTState">
+ <enum name="TBTState" since="2.0">
<description>Enumeration that describes possible states of turn-by-turn client or AppLink app.</description>
<element name="ROUTE_UPDATE_REQUEST" />
<element name="ROUTE_ACCEPTED" />
@@ -835,26 +881,26 @@
<element name="ROUTE_UPDATE_REQUEST_TIMEOUT" />
</enum>
- <enum name="DriverDistractionState">
+ <enum name="DriverDistractionState" since="2.0">
<description>Enumeration that describes possible states of driver distraction.</description>
<element name="DD_ON" />
<element name="DD_OFF" />
</enum>
- <enum name="ImageType">
+ <enum name="ImageType" since="2.0">
<description>Contains information about the type of image.</description>
<element name="STATIC" />
<element name="DYNAMIC" />
</enum>
- <enum name="DeliveryMode">
+ <enum name="DeliveryMode" since="4.1">
<description>The mode in which the SendLocation request is sent</description>
<element name="PROMPT" />
<element name="DESTINATION" />
<element name="QUEUE" />
</enum>
- <enum name="VideoStreamingProtocol">
+ <enum name="VideoStreamingProtocol" since="4.5">
<description>Enum for each type of video streaming protocol type.</description>
<element name="RAW">
<description>Raw stream bytes that contains no timestamp data and is the lowest supported video streaming</description>
@@ -873,7 +919,7 @@
</element>
</enum>
- <enum name="VideoStreamingCodec">
+ <enum name="VideoStreamingCodec" since="4.5">
<description>Enum for each type of video streaming codec.</description>
<element name="H264">
<description>A block-oriented motion-compensation-based video compression standard. As of 2014 it is one of the most commonly used formats for the recording, compression, and distribution of video content.</description>
@@ -892,16 +938,40 @@
</element>
</enum>
- <struct name="Image">
+ <enum name="AudioStreamingIndicator" since="5.0">
+ <element name="PLAY_PAUSE">
+ <description>
+ Default playback indicator.
+ By default the playback indicator should be PLAY_PAUSE when:
+ - the media app is newly registered on the head unit (after RegisterAppInterface)
+ - the media app was closed by the user (App enters HMI_NONE)
+ - the app sends SetMediaClockTimer with audioStreamingIndicator not set to any value
+ </description>
+ </element>
+ <element name="PLAY">
+ <description>Indicates that a button press of the Play/Pause button starts the audio playback.</description>
+ </element>
+ <element name="PAUSE">
+ <description>Indicates that a button press of the Play/Pause button pauses the current audio playback.</description>
+ </element>
+ <element name="STOP">
+ <description>Indicates that a button press of the Play/Pause button stops the current audio playback.</description>
+ </element>
+ </enum>
+
+ <struct name="Image" since="2.0">
<param name="value" minlength="0" maxlength="65535" type="String" mandatory="true">
<description>Either the static hex icon value or the binary image file name identifier (sent by PutFile).</description>
</param>
<param name="imageType" type="ImageType" mandatory="true">
<description>Describes, whether it is a static or dynamic image.</description>
</param>
+ <param name="isTemplate" type="Boolean" mandatory="false" since="5.0">
+ <description>If true, the image is a template image and can be recolored by the HMI</description>
+ </param>
</struct>
- <struct name="SoftButton">
+ <struct name="SoftButton" since="2.0">
<param name="type" type="SoftButtonType" mandatory="true">
<description>Describes, whether it is text, highlighted text, icon, or dynamic image. See softButtonType</description>
</param>
@@ -925,24 +995,28 @@
</param>
</struct>
- <struct name="Choice">
+ <struct name="Choice" since="1.0">
<description>A choice is an option given to the user, which can be selected either by menu, or through voice recognition system.</description>
<param name="choiceID" type="Integer" minvalue="0" maxvalue="65535" mandatory="true"/>
<param name="menuName" type="String" maxlength="500" mandatory="true"/>
- <param name="vrCommands" type="String" minsize="1" maxsize="100" maxlength="99" array="true" mandatory="true"/>
- <param name="image" type="Image" mandatory="false"/>
- <param name="secondaryText" maxlength="500" type="String" mandatory="false">
+ <param name="vrCommands" type="String" minsize="1" maxsize="100" maxlength="99" array="true" mandatory="false" since="5.0">
+ <history>
+ <param name="vrCommands" type="String" minsize="1" maxsize="100" maxlength="99" array="true" mandatory="true" since="1.0" until="5.0"/>
+ </history>
+ </param>
+ <param name="image" type="Image" mandatory="false" since="2.0" />
+ <param name="secondaryText" maxlength="500" type="String" mandatory="false" since="3.0">
<description>Optional secondary text to display; e.g. address of POI in a search result entry</description>
</param>
- <param name="tertiaryText" maxlength="500" type="String" mandatory="false">
+ <param name="tertiaryText" maxlength="500" type="String" mandatory="false" since="3.0">
<description>Optional tertiary text to display; e.g. distance to POI for a search result entry</description>
</param>
- <param name="secondaryImage" type="Image" mandatory="false">
+ <param name="secondaryImage" type="Image" mandatory="false" since="3.0">
<description>Optional secondary image struct for choice</description>
</param>
</struct>
- <struct name="VrHelpItem">
+ <struct name="VrHelpItem" since="2.0">
<param name="text" maxlength="500" type="String" mandatory="true">
<description>Text to display for VR Help item</description>
</param>
@@ -954,7 +1028,7 @@
</param>
</struct>
- <struct name="SyncMsgVersion">
+ <struct name="SyncMsgVersion" since="1.0">
<description>Specifies the version number of the SmartDeviceLink protocol that is supported by the mobile application</description>
<param name="majorVersion" type="Integer" minvalue="1" maxvalue="10" mandatory="true">
@@ -963,37 +1037,37 @@
<param name="minorVersion" type="Integer" minvalue="0" maxvalue="1000" mandatory="true">
<description>The minor version indicates a change to a previous version that should still allow to be run on an older version (with limited functionality)</description>
</param>
- <param name="patchVersion" type="Integer" minvalue="0" maxvalue="1000" mandatory="false">
+ <param name="patchVersion" type="Integer" minvalue="0" maxvalue="1000" mandatory="false" since="4.3">
<description>The patch version indicates a fix to existing functionality in a previous version that should still be able to be run on an older version </description>
</param>
</struct>
- <enum name="GlobalProperty">
+ <enum name="GlobalProperty" since="1.0">
<description>The different global properties.</description>
- <element name="HELPPROMPT">
+ <element name="HELPPROMPT" since="1.0">
<description>The property helpPrompt of setGlobalProperties</description>
</element>
- <element name="TIMEOUTPROMPT">
+ <element name="TIMEOUTPROMPT" since="1.0">
<description>The property timeoutPrompt of setGlobalProperties</description>
</element>
- <element name="VRHELPTITLE">
+ <element name="VRHELPTITLE" since="2.0">
<description>The property vrHelpTitle of setGlobalProperties</description>
</element>
- <element name="VRHELPITEMS">
+ <element name="VRHELPITEMS" since="2.0">
<description>The property array of vrHelp of setGlobalProperties</description>
</element>
- <element name="MENUNAME">
+ <element name="MENUNAME" since="3.0">
<description>The property in-app menu name of setGlobalProperties</description>
</element>
- <element name="MENUICON">
+ <element name="MENUICON" since="3.0">
<description>The property in-app menu icon of setGlobalProperties</description>
</element>
- <element name="KEYBOARDPROPERTIES">
+ <element name="KEYBOARDPROPERTIES" since="3.0">
<description>The on-screen keyboard configuration of setGlobalProperties</description>
</element>
</enum>
- <enum name="CompassDirection">
+ <enum name="CompassDirection" since="2.0">
<description>The list of potential compass directions</description>
<element name="NORTH">
</element>
@@ -1013,7 +1087,7 @@
</element>
</enum>
- <enum name="Dimension">
+ <enum name="Dimension" since="2.0">
<description>The supported dimensions of the GPS</description>
<element name="NO_FIX" internal_name="Dimension_NO_FIX">
<description>No GPS at all</description>
@@ -1026,7 +1100,7 @@
</element>
</enum>
- <enum name="PRNDL">
+ <enum name="PRNDL" since="2.0">
<description>The selected gear.</description>
<element name="PARK">
<description>Parking</description>
@@ -1067,7 +1141,7 @@
</element>
</enum>
- <enum name="ComponentVolumeStatus">
+ <enum name="ComponentVolumeStatus" since="2.0">
<description>The volume status of a vehicle component.</description>
<element name="UNKNOWN" internal_name="CVS_UNKNOWN">
</element>
@@ -1083,13 +1157,106 @@
</element>
</enum>
- <struct name="SingleTireStatus">
+ <enum name="TPMS" since="5.0">
+ <element name="UNKNOWN">
+ <description>If set the status of the tire is not known.</description>
+ </element>
+ <element name="SYSTEM_FAULT">
+ <description>TPMS does not function.</description>
+ </element>
+ <element name="SENSOR_FAULT">
+ <description>The sensor of the tire does not function.</description>
+ </element>
+ <element name="LOW">
+ <description>TPMS is reporting a low tire pressure for the tire.</description>
+ </element>
+ <element name="SYSTEM_ACTIVE">
+ <description>TPMS is active and the tire pressure is monitored.</description>
+ </element>
+ <element name="TRAIN">
+ <description>TPMS is reporting that the tire must be trained.</description>
+ </element>
+ <element name="TRAINING_COMPLETE">
+ <description>TPMS reports the training for the tire is completed.</description>
+ </element>
+ <element name="NOT_TRAINED">
+ <description>TPMS reports the tire is not trained.</description>
+ </element>
+ </enum>
+
+ <enum name="FuelType" since="5.0">
+ <element name="GASOLINE" />
+ <element name="DIESEL" />
+ <element name="CNG">
+ <description>
+ For vehicles using compressed natural gas.
+ </description>
+ </element>
+ <element name="LPG">
+ <description>
+ For vehicles using liquefied petroleum gas.
+ </description>
+ </element>
+ <element name="HYDROGEN">
+ <description>For FCEV (fuel cell electric vehicle).</description>
+ </element>
+ <element name="BATTERY">
+ <description>For BEV (Battery Electric Vehicle), PHEV (Plug-in Hybrid Electric Vehicle), solar vehicles and other vehicles which run on a battery.</description>
+ </element>
+ </enum>
+
+ <struct name="FuelRange" since="5.0">
+ <param name="type" type="FuelType" mandatory="false"/>
+ <param name="range" type="Float" minvalue="0" maxvalue="10000" mandatory="false">
+ <description>
+ The estimate range in KM the vehicle can travel based on fuel level and consumption.
+ </description>
+ </param>
+ </struct>
+
+ <enum name="ElectronicParkBrakeStatus" since="5.0">
+ <element name="CLOSED">
+ <description>
+ Park brake actuators have been fully applied.
+ </description>
+ </element>
+ <element name="TRANSITION">
+ <description>
+ Park brake actuators are transitioning to either Apply/Closed or Release/Open state.
+ </description>
+ </element>
+ <element name="OPEN">
+ <description>
+ Park brake actuators are released.
+ </description>
+ </element>
+ <element name="DRIVE_ACTIVE">
+ <description>
+ When driver pulls the Electronic Park Brake switch while driving "at speed".
+ </description>
+ </element>
+ <element name="FAULT">
+ <description>
+ When system has a fault or is under maintenance.
+ </description>
+ </element>
+ </enum>
+
+ <struct name="SingleTireStatus" since="2.0">
<param name="status" type="ComponentVolumeStatus" mandatory="true">
<description>See ComponentVolumeStatus.</description>
</param>
+ <param name="tpms" type="TPMS" mandatory="false" since="5.0">
+ <description>
+ The status of TPMS according to the particular tire.
+ </description>
+ </param>
+ <param name="pressure" type="Float" mandatory="false" minvalue="0" maxvalue="2000" since="5.0">
+ <description>The pressure value of the particular tire in kilo pascal.</description>
+ </param>
</struct>
- <enum name="WarningLightStatus">
+ <enum name="WarningLightStatus" since="2.0">
<description>Reflects the status of a cluster instrument warning light.</description>
<element name="OFF" internal_name="WLS_OFF">
</element>
@@ -1101,7 +1268,7 @@
</element>
</enum>
- <enum name="VehicleDataNotificationStatus">
+ <enum name="VehicleDataNotificationStatus" since="2.0">
<description>Reflects the status of a vehicle data notification.</description>
<element name="NOT_SUPPORTED" internal_name="VDNS_NOT_SUPPORTED">
</element>
@@ -1113,7 +1280,7 @@
</element>
</enum>
- <enum name="IgnitionStableStatus">
+ <enum name="IgnitionStableStatus" since="2.0">
<description>Reflects the ignition switch stability.</description>
<element name="IGNITION_SWITCH_NOT_STABLE">
</element>
@@ -1123,7 +1290,7 @@
</element>
</enum>
- <enum name="IgnitionStatus">
+ <enum name="IgnitionStatus" since="2.0">
<description>Reflects the status of ignition.</description>
<element name="UNKNOWN" internal_name="IS_UNKNOWN">
</element>
@@ -1139,7 +1306,7 @@
</element>
</enum>
- <enum name="VehicleDataEventStatus">
+ <enum name="VehicleDataEventStatus" since="2.0">
<description>Reflects the status of a vehicle data event; e.g. a seat belt event status.</description>
<element name="NO_EVENT" internal_name="VDES_NO_EVENT">
</element>
@@ -1153,7 +1320,7 @@
</element>
</enum>
- <enum name="DeviceLevelStatus">
+ <enum name="DeviceLevelStatus" since="2.0">
<description>Reflects the reported battery status of the connected device, if reported.</description>
<element name="ZERO_LEVEL_BARS">
</element>
@@ -1169,10 +1336,12 @@
</element>
</enum>
- <enum name="PrimaryAudioSource">
+ <enum name="PrimaryAudioSource" since="2.0">
<description>Reflects the current primary audio source (if selected).</description>
<element name="NO_SOURCE_SELECTED">
</element>
+ <element name="CD" since="5.0">
+ </element>
<element name="USB">
</element>
<element name="USB2">
@@ -1185,9 +1354,17 @@
</element>
<element name="MOBILE_APP">
</element>
+ <element name="AM" since="5.0">
+ </element>
+ <element name="FM" since="5.0">
+ </element>
+ <element name="XM" since="5.0">
+ </element>
+ <element name="DAB" since="5.0">
+ </element>
</enum>
- <enum name="WiperStatus">
+ <enum name="WiperStatus" since="2.0">
<description>Reflects the status of the wipers.</description>
<element name="OFF" />
<element name="AUTO_OFF" />
@@ -1206,7 +1383,7 @@
<element name="NO_DATA_EXISTS" />
</enum>
- <enum name="VehicleDataStatus">
+ <enum name="VehicleDataStatus" since="2.0">
<description>Reflects the status of a binary vehicle data item.</description>
<element name="NO_DATA_EXISTS" internal_name="VDS_NO_DATA_EXISTS">
</element>
@@ -1216,7 +1393,7 @@
</element>
</enum>
- <enum name="MaintenanceModeStatus">
+ <enum name="MaintenanceModeStatus" since="2.0">
<description>Reflects the status of a vehicle maintenance mode.</description>
<element name="NORMAL" internal_name="MMS_NORMAL">
</element>
@@ -1228,7 +1405,7 @@
</element>
</enum>
- <enum name="VehicleDataActiveStatus">
+ <enum name="VehicleDataActiveStatus" since="2.0">
<description>Reflects the status of given vehicle component.</description>
<element name="INACTIVE_NOT_CONFIRMED" internal_name="VDAS_INACTIVE_NOT_CONFIRMED">
</element>
@@ -1242,7 +1419,7 @@
</element>
</enum>
- <enum name="AmbientLightStatus">
+ <enum name="AmbientLightStatus" since="2.0">
<description>Reflects the status of the ambient light sensor.</description>
<element name="NIGHT" />
<element name="TWILIGHT_1" />
@@ -1254,44 +1431,48 @@
<element name="INVALID" />
</enum>
- <enum name="ModuleType">
+ <enum name="ModuleType" since="4.5">
<element name="CLIMATE"/>
<element name="RADIO"/>
+ <element name="SEAT" since="5.0"/>
+ <element name="AUDIO" since="5.0"/>
+ <element name="LIGHT" since="5.0"/>
+ <element name="HMI_SETTINGS" since="5.0"/>
</enum>
- <enum name="DefrostZone">
+ <enum name="DefrostZone" since="4.5">
<element name="FRONT"/>
<element name="REAR"/>
<element name="ALL"/>
<element name="NONE"/>
</enum>
- <enum name="VentilationMode">
+ <enum name="VentilationMode" since="4.5">
<element name="UPPER"/>
<element name="LOWER"/>
<element name="BOTH"/>
<element name="NONE"/>
</enum>
- <enum name="RadioBand">
+ <enum name="RadioBand" since="4.5">
<element name="AM"/>
<element name="FM"/>
<element name="XM"/>
</enum>
- <enum name="RadioState">
+ <enum name="RadioState" since="4.5">
<element name="ACQUIRING"/>
<element name="ACQUIRED"/>
<element name="MULTICAST"/>
<element name="NOT_FOUND"/>
</enum>
- <enum name="TemperatureUnit">
+ <enum name="TemperatureUnit" since="4.5">
<element name="FAHRENHEIT"/>
<element name="CELSIUS"/>
</enum>
- <struct name="BeltStatus">
+ <struct name="BeltStatus" since="2.0">
<param name="driverBeltDeployed" type="VehicleDataEventStatus" mandatory="true">
<description>References signal "VedsDrvBelt_D_Ltchd". See VehicleDataEventStatus.</description>
</param>
@@ -1339,7 +1520,7 @@
</param>
</struct>
- <struct name="BodyInformation">
+ <struct name="BodyInformation" since="2.0">
<param name="parkBrakeActive" type="Boolean" mandatory="true">
<description>References signal "PrkBrkActv_B_Actl".</description>
</param>
@@ -1363,7 +1544,7 @@
</param>
</struct>
- <struct name="DeviceStatus">
+ <struct name="DeviceStatus" since="2.0">
<param name="voiceRecOn" type="Boolean" mandatory="true">
<description>References signal "CPM_VoiceRec_STAT".</description>
</param>
@@ -1399,7 +1580,7 @@
</param>
</struct>
- <struct name="HeadLampStatus">
+ <struct name="HeadLampStatus" since="2.0">
<param name="lowBeamsOn" type="Boolean" mandatory="true">
<description>Status of the low beam lamps. References signal "HeadLampLoActv_B_Stat".</description>
</param>
@@ -1411,7 +1592,7 @@
</param>
</struct>
- <struct name="AppInfo">
+ <struct name="AppInfo" since="4.2">
<description>Contains detailed information about the registered application.</description>
<param name="appDisplayName" type="String" maxlength="100" mandatory="true">
@@ -1434,7 +1615,7 @@
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~ -->
<!-- Ford Specific Data Items -->
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~ -->
- <enum name="FileType">
+ <enum name="FileType" since="2.0">
<description>Enumeration listing possible file types.</description>
<element name="GRAPHIC_BMP" />
<element name="GRAPHIC_JPEG" />
@@ -1446,7 +1627,7 @@
<element name="JSON" />
</enum>
- <enum name="FuelCutoffStatus" >
+ <enum name="FuelCutoffStatus" since="2.0">
<description>Reflects the status of the RCM fuel cutoff.</description>
<element name="TERMINATE_FUEL" internal_name="FCS_TERMINATE_FUEL">
</element>
@@ -1456,7 +1637,7 @@
</element>
</enum>
- <enum name="EmergencyEventType">
+ <enum name="EmergencyEventType" since="2.0">
<description>Reflects the emergency event status of the vehicle.</description>
<element name="NO_EVENT" internal_name="EET_NO_EVENT">
</element>
@@ -1474,7 +1655,7 @@
</element>
</enum>
- <enum name="ECallConfirmationStatus">
+ <enum name="ECallConfirmationStatus" since="2.0">
<description>Reflects the status of the eCall Notification.</description>
<element name="NORMAL" internal_name="ECCS_NORMAL">
</element>
@@ -1492,7 +1673,7 @@
</element>
</enum>
- <enum name="PowerModeQualificationStatus" >
+ <enum name="PowerModeQualificationStatus" since="2.0">
<description>Reflects the status of the current power mode qualification.</description>
<element name="POWER_MODE_UNDEFINED">
</element>
@@ -1504,7 +1685,7 @@
</element>
</enum>
- <enum name="PowerModeStatus">
+ <enum name="PowerModeStatus" since="2.0">
<description>Reflects the status of the current power mode.</description>
<element name="KEY_OUT">
</element>
@@ -1526,7 +1707,7 @@
</element>
</enum>
- <enum name="CarModeStatus">
+ <enum name="CarModeStatus" since="2.0">
<description>Reflects the status of the current car mode.</description>
<element name="NORMAL" internal_name="CMS_NORMAL">
</element>
@@ -1538,7 +1719,7 @@
</element>
</enum>
- <struct name="ECallInfo">
+ <struct name="ECallInfo" since="2.0">
<param name="eCallNotificationStatus" type="VehicleDataNotificationStatus" mandatory="true">
<description>References signal "eCallNotification_4A". See VehicleDataNotificationStatus.</description>
</param>
@@ -1550,7 +1731,7 @@
</param>
</struct>
- <struct name="AirbagStatus">
+ <struct name="AirbagStatus" since="2.0">
<param name="driverAirbagDeployed" type="VehicleDataEventStatus" mandatory="true">
<description>References signal "VedsDrvBag_D_Ltchd". See VehicleDataEventStatus.</description>
</param>
@@ -1577,7 +1758,7 @@
</param>
</struct>
- <struct name="EmergencyEvent">
+ <struct name="EmergencyEvent" since="2.0">
<param name="emergencyEventType" type="EmergencyEventType" mandatory="true">
<description>References signal "VedsEvntType_D_Ltchd". See EmergencyEventType.</description>
</param>
@@ -1600,7 +1781,7 @@
</param>
</struct>
- <struct name="ClusterModeStatus">
+ <struct name="ClusterModeStatus" since="2.0">
<param name="powerModeActive" type="Boolean" mandatory="true">
<description>References signal "PowerMode_UB".</description>
</param>
@@ -1615,7 +1796,7 @@
</param>
</struct>
- <struct name="MyKey">
+ <struct name="MyKey" since="2.0">
<param name="e911Override" type="VehicleDataStatus" mandatory="true">
<description>Indicates whether e911 override is on. References signal "MyKey_e911Override_St". See VehicleDataStatus.</description>
</param>
@@ -1625,7 +1806,7 @@
<!-- / Ford Specific Data Items -->
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
- <enum name="VehicleDataResultCode">
+ <enum name="VehicleDataResultCode" since="2.0">
<description>Enumeration that describes possible result codes of a vehicle data entry request.</description>
<element name="SUCCESS" internal_name="VDRC_SUCCESS">
<description>Individual vehicle data item / DTC / DID request or subscription successful</description>
@@ -1656,7 +1837,7 @@
</element>
</enum>
- <struct name="TireStatus">
+ <struct name="TireStatus" since="2.0">
<description>The status and pressure of the tires.</description>
<param name="pressureTelltale" type="WarningLightStatus" mandatory="true">
@@ -1682,66 +1863,130 @@
</param>
</struct>
- <struct name="GPSData">
+ <enum name="TurnSignal" since="5.0">
+ <description>Enumeration that describes the status of the turn light indicator.</description>
+ <element name="OFF">
+ <description>Turn signal is OFF</description>
+ </element>
+ <element name="LEFT">
+ <description>Left turn signal is on</description>
+ </element>
+ <element name="RIGHT">
+ <description>Right turn signal is on</description>
+ </element>
+ <element name="BOTH">
+ <description>Both signals (left and right) are on.</description>
+ </element>
+ </enum>
+
+ <struct name="GPSData" since="2.0">
<description>Struct with the GPS data.</description>
<param name="longitudeDegrees" type="Float" minvalue="-180" maxvalue="180" mandatory="true">
</param>
<param name="latitudeDegrees" type="Float" minvalue="-90" maxvalue="90" mandatory="true">
</param>
- <param name="utcYear" type="Integer" minvalue="2010" maxvalue="2100" mandatory="true">
+ <param name="utcYear" type="Integer" minvalue="2010" maxvalue="2100" mandatory="false" since="5.0">
<description>The current UTC year.</description>
+ <history>
+ <param name="utcYear" type="Integer" minvalue="2010" maxvalue="2100" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="utcMonth" type="Integer" minvalue="1" maxvalue="12" mandatory="true">
+ <param name="utcMonth" type="Integer" minvalue="1" maxvalue="12" mandatory="false" since="5.0">
<description>The current UTC month.</description>
+ <history>
+ <param name="utcMonth" type="Integer" minvalue="1" maxvalue="12" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="utcDay" type="Integer" minvalue="1" maxvalue="31" mandatory="true">
+ <param name="utcDay" type="Integer" minvalue="1" maxvalue="31" mandatory="false" since="5.0">
<description>The current UTC day.</description>
+ <history>
+ <param name="utcDay" type="Integer" minvalue="1" maxvalue="31" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="utcHours" type="Integer" minvalue="0" maxvalue="23" mandatory="true">
+ <param name="utcHours" type="Integer" minvalue="0" maxvalue="23" mandatory="false" since="5.0">
<description>The current UTC hour.</description>
+ <history>
+ <param name="utcHours" type="Integer" minvalue="0" maxvalue="23" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="utcMinutes" type="Integer" minvalue="0" maxvalue="59" mandatory="true">
+ <param name="utcMinutes" type="Integer" minvalue="0" maxvalue="59" mandatory="false" since="5.0">
<description>The current UTC minute.</description>
+ <history>
+ <param name="utcMinutes" type="Integer" minvalue="0" maxvalue="59" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="utcSeconds" type="Integer" minvalue="0" maxvalue="59" mandatory="true">
+ <param name="utcSeconds" type="Integer" minvalue="0" maxvalue="59" mandatory="false" since="5.0">
<description>The current UTC second.</description>
+ <history>
+ <param name="utcSeconds" type="Integer" minvalue="0" maxvalue="59" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="compassDirection" type="CompassDirection" mandatory="true">
+ <param name="compassDirection" type="CompassDirection" mandatory="false" since="5.0">
<description>See CompassDirection.</description>
+ <history>
+ <param name="compassDirection" type="CompassDirection" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="pdop" type="Float" minvalue="0" maxvalue="10" defvalue="0" mandatory="true">
+ <param name="pdop" type="Float" minvalue="0" maxvalue="1000" defvalue="0" mandatory="false" since="5.0">
<description>PDOP. If undefined or unavailable, then value shall be set to 0.</description>
+ <history>
+ <param name="pdop" type="Float" minvalue="0" maxvalue="10" defvalue="0" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="hdop" type="Float" minvalue="0" maxvalue="10" defvalue="0" mandatory="true">
+ <param name="hdop" type="Float" minvalue="0" maxvalue="1000" defvalue="0" mandatory="false" since="5.0">
<description>HDOP. If value is unknown, value shall be set to 0.</description>
+ <history>
+ <param name="hdop" type="Float" minvalue="0" maxvalue="10" defvalue="0" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="vdop" type="Float" minvalue="0" maxvalue="10" defvalue="0" mandatory="true">
+ <param name="vdop" type="Float" minvalue="0" maxvalue="1000" defvalue="0" mandatory="false" since="5.0">
<description>VDOP. If value is unknown, value shall be set to 0.</description>
+ <history>
+ <param name="vdop" type="Float" minvalue="0" maxvalue="10" defvalue="0" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="actual" type="Boolean" mandatory="true">
+ <param name="actual" type="Boolean" mandatory="false" since="5.0">
<description>
True, if actual.
False, if inferred.
</description>
+ <history>
+ <param name="actual" type="Boolean" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="satellites" type="Integer" minvalue="0" maxvalue="31" mandatory="true">
+ <param name="satellites" type="Integer" minvalue="0" maxvalue="31" mandatory="false" since="5.0">
<description>Number of satellites in view</description>
+ <history>
+ <param name="satellites" type="Integer" minvalue="0" maxvalue="31" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="dimension" type="Dimension" mandatory="true">
+ <param name="dimension" type="Dimension" mandatory="false" since="5.0">
<description>See Dimension</description>
+ <history>
+ <param name="dimension" type="Dimension" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="altitude" type="Float" minvalue="-10000" maxvalue="10000" mandatory="true">
+ <param name="altitude" type="Float" minvalue="-10000" maxvalue="10000" mandatory="false" since="5.0">
<description>Altitude in meters</description>
+ <history>
+ <param name="altitude" type="Float" minvalue="-10000" maxvalue="10000" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="heading" type="Float" minvalue="0" maxvalue="359.99" mandatory="true">
+ <param name="heading" type="Float" minvalue="0" maxvalue="359.99" mandatory="false" since="5.0">
<description>The heading. North is 0. Resolution is 0.01</description>
+ <history>
+ <param name="heading" type="Float" minvalue="0" maxvalue="359.99" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
- <param name="speed" type="Float" minvalue="0" maxvalue="500" mandatory="true">
+ <param name="speed" type="Float" minvalue="0" maxvalue="500" mandatory="false" since="5.0">
<description>The speed in KPH</description>
+ <history>
+ <param name="speed" type="Float" minvalue="0" maxvalue="500" mandatory="true" since="2.0" until="5.0"/>
+ </history>
</param>
</struct>
- <struct name="VehicleDataResult">
+ <struct name="VehicleDataResult" since="2.0">
<description>Individual published data request result</description>
<param name="dataType" type="VehicleDataType" mandatory="true">
<description>Defined published data element type.</description>
@@ -1751,7 +1996,7 @@
</param>
</struct>
- <struct name="DIDResult">
+ <struct name="DIDResult" since="2.0">
<description>Individual requested DID result and data</description>
<param name="resultCode" type="VehicleDataResultCode" mandatory="true">
<description>Individual DID result code.</description>
@@ -1764,7 +2009,7 @@
</param>
</struct>
- <struct name="StartTime">
+ <struct name="StartTime" since="1.0">
<param name="hours" type="Integer" minvalue="0" maxvalue="59" mandatory="true">
<description>
The hour of the media clock.
@@ -1775,7 +2020,7 @@
<param name="seconds" type="Integer" minvalue="0" maxvalue="59" mandatory="true"/>
</struct>
- <struct name="TextField">
+ <struct name="TextField" since="1.0">
<param name="name" type="TextFieldName" mandatory="true">
<description>The name that identifies the field. See TextFieldName.</description>
</param>
@@ -1790,7 +2035,7 @@
</param>
</struct>
- <struct name="ImageResolution">
+ <struct name="ImageResolution" since="3.0">
<param name="resolutionWidth" type="Integer" minvalue="1" maxvalue="10000" mandatory="true">
<description>The image resolution width.</description>
</param>
@@ -1799,7 +2044,7 @@
</param>
</struct>
- <struct name="ImageField">
+ <struct name="ImageField" since="3.0">
<param name="name" type="ImageFieldName" mandatory="true">
<description>The name that identifies the field. See ImageFieldName.</description>
</param>
@@ -1811,7 +2056,7 @@
</param>
</struct>
- <struct name="TouchCoord">
+ <struct name="TouchCoord" since="3.0">
<param name="x" type="Integer" mandatory="true" minvalue="0" maxvalue="10000">
<description>The x coordinate of the touch.</description>
</param>
@@ -1820,14 +2065,14 @@
</param>
</struct>
- <enum name="TouchType">
+ <enum name="TouchType" since="3.0">
<element name="BEGIN"/>
<element name="MOVE"/>
<element name="END"/>
- <element name="CANCEL"/>
+ <element name="CANCEL" since="4.5"/>
</enum>
- <struct name="TouchEvent">
+ <struct name="TouchEvent" since="3.0">
<param name="id" type="Integer" mandatory="true" minvalue="0" maxvalue="9">
<description>
A touch's unique identifier. The application can track the current touch events by id.
@@ -1847,7 +2092,7 @@
</param>
</struct>
- <struct name="TouchEventCapabilities">
+ <struct name="TouchEventCapabilities" since="3.0">
<param name="pressAvailable" type="Boolean" mandatory="true">
</param>
<param name="multiTouchAvailable" type="Boolean" mandatory="true">
@@ -1856,7 +2101,7 @@
</param>
</struct>
- <struct name="ScreenParams">
+ <struct name="ScreenParams" since="3.0">
<param name="resolution" type="ImageResolution" mandatory="true">
<description>The resolution of the prescribed screen area.</description>
</param>
@@ -1865,7 +2110,7 @@
</param>
</struct>
- <enum name="PermissionStatus">
+ <enum name="PermissionStatus" since="2.0">
<description>Enumeration that describes possible permission states of a policy table entry.</description>
<element name="ALLOWED" internal_name="PS_ALLOWED"/>
<element name="DISALLOWED" internal_name="PS_DISALLOWED"/>
@@ -1873,7 +2118,7 @@
<element name="USER_CONSENT_PENDING" internal_name="PS_USER_CONSENT_PENDING"/>
</enum>
- <struct name="HMIPermissions">
+ <struct name="HMIPermissions" since="2.0">
<param name="allowed" type="HMILevel" minsize="0" maxsize="100" array="true" mandatory="true">
<description>A set of all HMI levels that are permitted for this given RPC.</description>
</param>
@@ -1882,7 +2127,7 @@
</param>
</struct>
- <struct name="ParameterPermissions">
+ <struct name="ParameterPermissions" since="2.0">
<param name="allowed" type="String" minsize="0" maxsize="100" maxlength = "100" array="true" mandatory="true">
<description>A set of all parameters that are permitted for this given RPC.</description>
</param>
@@ -1891,7 +2136,7 @@
</param>
</struct>
- <struct name="PermissionItem">
+ <struct name="PermissionItem" since="2.0">
<param name="rpcName" type="String" maxlength="100" mandatory="true">
<description>Name of the individual RPC in the policy table.</description>
</param>
@@ -1899,10 +2144,16 @@
<param name="parameterPermissions" type="ParameterPermissions" mandatory="true"/>
</struct>
- <struct name="DisplayCapabilities">
+ <struct name="DisplayCapabilities" since="1.0">
<description>Contains information about the display capabilities.</description>
- <param name="displayType" type="DisplayType" mandatory="true">
+ <param name="displayType" type="DisplayType" mandatory="true" deprecated="true" since="5.0">
<description>The type of the display. See DisplayType</description>
+ <history>
+ <param name="displayType" type="DisplayType" mandatory="true" since="1.0" until="5.0"/>
+ </history>
+ </param>
+ <param name="displayName" type="String" mandatory="false" since="5.0">
+ <description>The name of the display the app is connected to.</description>
</param>
<param name="textFields" type="TextField" minsize="1" maxsize="100" array="true" mandatory="true">
<description>A set of all fields that support text data. See TextField</description>
@@ -1913,22 +2164,23 @@
<param name="mediaClockFormats" type="MediaClockFormat" minsize="0" maxsize="100" array="true" mandatory="true">
<description>A set of all supported formats of the media clock. See MediaClockFormat</description>
</param>
- <param name="graphicSupported" type="Boolean" mandatory="true">
+ <param name="graphicSupported" type="Boolean" mandatory="true" since="2.0">
<description>The display's persistent screen supports referencing a static or dynamic image.</description>
</param>
- <param name="templatesAvailable" type="String" minsize="0" maxsize="100" maxlength="100" array="true" mandatory="false">
+ <param name="templatesAvailable" type="String" minsize="0" maxsize="100" maxlength="100" array="true" mandatory="false" since="3.0">
<description>A set of all predefined persistent display templates available on headunit. To be referenced in SetDisplayLayout.</description>
</param>
- <param name="screenParams" type="ScreenParams" mandatory="false">
+ <param name="screenParams" type="ScreenParams" mandatory="false" since="3.0">
<description>A set of all parameters related to a prescribed screen area (e.g. for video / touch input).</description>
</param>
- <param name="numCustomPresetsAvailable" type="Integer" minvalue="1" maxvalue="100" mandatory="false">
+ <param name="numCustomPresetsAvailable" type="Integer" minvalue="1" maxvalue="100" mandatory="false" since="3.0">
<description>The number of on-screen custom presets available (if any); otherwise omitted.</description>
</param>
<!-- TODO: Add pixel density? -->
</struct>
- <struct name="ButtonCapabilities">
+
+ <struct name="ButtonCapabilities" since="1.0">
<description>Contains information about a button's capabilities.</description>
<param name="name" type="ButtonName" mandatory="true">
<description>The name of the button. See ButtonName.</description>
@@ -1953,7 +2205,8 @@
</description>
</param>
</struct>
- <struct name="SoftButtonCapabilities">
+
+ <struct name="SoftButtonCapabilities" since="2.0">
<description>Contains information about a SoftButton's capabilities.</description>
<param name="shortPressAvailable" type="Boolean" mandatory="true">
<description>
@@ -1978,27 +2231,30 @@
<description>The button supports referencing a static or dynamic image.</description>
</param>
</struct>
- <struct name="PresetBankCapabilities">
+
+ <struct name="PresetBankCapabilities" since="2.0">
<description>Contains information about on-screen preset capabilities.</description>
<param name="onScreenPresetsAvailable" type="Boolean" mandatory="true">
<description>Onscreen custom presets are available.</description>
</param>
</struct>
- <struct name="HMICapabilities">
+
+ <struct name="HMICapabilities" since="3.0">
<param name="navigation" type="Boolean" mandatory="false">
<description>Availability of build in Nav. True: Available, False: Not Available</description>
</param>
<param name="phoneCall" type="Boolean" mandatory="false">
<description>Availability of build in phone. True: Available, False: Not Available </description>
</param>
- <param name="videoStreaming" type="Boolean" mandatory="false">
+ <param name="videoStreaming" type="Boolean" mandatory="false" since="4.5">
<description>Availability of video streaming. </description>
</param>
- <param name="remoteControl" type="Boolean" mandatory="false">
+ <param name="remoteControl" type="Boolean" mandatory="false" since="4.5">
<description>Availability of remote control feature. True: Available, False: Not Available</description>
</param>
</struct>
- <struct name="MenuParams">
+
+ <struct name="MenuParams" since="1.0">
<param name="parentID" type="Integer" minvalue="0" maxvalue="2000000000" defvalue="0" mandatory="false">
<description>
unique ID of the sub menu, the command will be added to.
@@ -2018,19 +2274,22 @@
<description>Text to show in the menu for this sub menu.</description>
</param>
</struct>
- <struct name="TTSChunk">
- <description>A TTS chunk, that consists of the text/phonemes to speak and the type (like text or SAPI)</description>
+
+ <struct name="TTSChunk" since="1.0">
+ <description>A TTS chunk, that consists of text/phonemes to speak or the name of a file to play, and a TTS type (like text or SAPI)</description>
<param name="text" minlength="0" maxlength="500" type="String" mandatory="true">
<description>
- The text or phonemes to speak.
+ The text or phonemes to speak, or the name of the audio file to play.
May not be empty.
</description>
</param>
+
<param name="type" type="SpeechCapabilities" mandatory="true">
- <description>Describes, whether it is text or a specific phoneme set. See SpeechCapabilities</description>
+ <description>Describes whether the TTS chunk is plain text, a specific phoneme set, or an audio file. See SpeechCapabilities</description>
</param>
</struct>
- <struct name="Turn">
+
+ <struct name="Turn" since="2.0">
<param name="navigationText" type="String" maxlength="500" mandatory="false">
<description>Individual turn text. Must provide at least text or icon for a given turn.</description>
</param>
@@ -2038,7 +2297,8 @@
<description>Individual turn icon. Must provide at least text or icon for a given turn.</description>
</param>
</struct>
- <struct name="VehicleType">
+
+ <struct name="VehicleType" since="2.0">
<param name="make" type="String" maxlength="500" mandatory="false">
<description>Make of the vehicle, e.g. Ford</description>
</param>
@@ -2052,13 +2312,15 @@
<description>Trim of the vehicle, e.g. SE</description>
</param>
</struct>
- <enum name="KeyboardLayout">
+
+ <enum name="KeyboardLayout" since="3.0">
<description>Enumeration listing possible keyboard layouts.</description>
<element name="QWERTY" />
<element name="QWERTZ" />
<element name="AZERTY" />
</enum>
- <enum name="KeyboardEvent" >
+
+ <enum name="KeyboardEvent" since="3.0">
<description>Enumeration listing possible keyboard events.</description>
<element name="KEYPRESS" />
<element name="ENTRY_SUBMITTED" />
@@ -2066,7 +2328,8 @@
<element name="ENTRY_CANCELLED" />
<element name="ENTRY_ABORTED" />
</enum>
- <enum name="KeypressMode">
+
+ <enum name="KeypressMode" since="3.0">
<description>Enumeration listing possible keyboard events.</description>
<element name="SINGLE_KEYPRESS">
<description>Each keypress is individually sent as the user presses the keyboard keys.</description>
@@ -2078,7 +2341,8 @@
<description>The keypresses are queue and a string is sent each time the user presses a keyboard key; the string contains the entire current entry.</description>
</element>
</enum>
- <struct name="KeyboardProperties">
+
+ <struct name="KeyboardProperties" since="3.0">
<description>Configuration of on-screen keyboard (if available).</description>
<param name="language" type="Language" mandatory="false">
<description>The keyboard language.</description>
@@ -2101,7 +2365,8 @@
<description>Allows an app to prepopulate the text field with a suggested or completed entry as the user types</description>
</param>
</struct>
- <struct name="DeviceInfo">
+
+ <struct name="DeviceInfo" since="3.0">
<description>Various information about connecting device.</description>
<param name="hardware" type="String" minlength="0" maxlength="500" mandatory="false">
<description>Device model</description>
@@ -2122,7 +2387,8 @@
<description>Omitted if connected not via BT.</description>
</param>
</struct>
- <enum name="RequestType">
+
+ <enum name="RequestType" since="3.0">
<description>Enumeration listing possible asynchronous requests.</description>
<element name="HTTP" />
<element name="FILE_RESUME" />
@@ -2144,8 +2410,10 @@
<element name="EMERGENCY" />
<element name="MEDIA" />
<element name="FOTA" />
+ <element name="OEM_SPECIFIC" since="5.0" />
</enum>
- <enum name="AppHMIType">
+
+ <enum name="AppHMIType" since="2.0">
<description>Enumeration listing possible app types.</description>
<element name="DEFAULT" />
<element name="COMMUNICATION" />
@@ -2157,10 +2425,11 @@
<element name="BACKGROUND_PROCESS" />
<element name="TESTING" />
<element name="SYSTEM" />
- <element name="PROJECTION" />
- <element name="REMOTE_CONTROL" />
+ <element name="PROJECTION" since="4.5" />
+ <element name="REMOTE_CONTROL" since="4.5" />
</enum>
- <enum name="PredefinedLayout" platform="documentation">
+
+ <enum name="PredefinedLayout" platform="documentation" since="3.0">
<description>Predefined screen layout.</description>
<element name="DEFAULT" rootscreen="true">
<description>
@@ -2283,103 +2552,105 @@
</description>
</element>
</enum>
- <enum name="FunctionID" internal_scope="base">
+
+ <enum name="FunctionID" internal_scope="base" since="1.0">
<description>Enumeration linking function names with function IDs in AppLink protocol. Assumes enumeration starts at value 0.</description>
- <element name="RESERVED" value="0" />
+ <element name="RESERVED" value="0" since="1.0" />
<!--
Base Request / Response RPCs
Range = 0x 0000 0001 - 0x 0000 7FFF
-->
- <element name="RegisterAppInterfaceID" value="1" hexvalue="1" />
- <element name="UnregisterAppInterfaceID" value="2" hexvalue="2" />
- <element name="SetGlobalPropertiesID" value="3" hexvalue="3" />
- <element name="ResetGlobalPropertiesID" value="4" hexvalue="4" />
- <element name="AddCommandID" value="5" hexvalue="5" />
- <element name="DeleteCommandID" value="6" hexvalue="6" />
- <element name="AddSubMenuID" value="7" hexvalue="7" />
- <element name="DeleteSubMenuID" value="8" hexvalue="8" />
- <element name="CreateInteractionChoiceSetID" value="9" hexvalue="9" />
- <element name="PerformInteractionID" value="10" hexvalue="A" />
- <element name="DeleteInteractionChoiceSetID" value="11" hexvalue="B" />
- <element name="AlertID" value="12" hexvalue="C" />
- <element name="ShowID" value="13" hexvalue="D" />
- <element name="SpeakID" value="14" hexvalue="E" />
- <element name="SetMediaClockTimerID" value="15" hexvalue="F" />
- <element name="PerformAudioPassThruID" value="16" hexvalue="10" />
- <element name="EndAudioPassThruID" value="17" hexvalue="11" />
- <element name="SubscribeButtonID" value="18" hexvalue="12" />
- <element name="UnsubscribeButtonID" value="19" hexvalue="13" />
- <element name="SubscribeVehicleDataID" value="20" hexvalue="14" />
- <element name="UnsubscribeVehicleDataID" value="21" hexvalue="15" />
- <element name="GetVehicleDataID" value="22" hexvalue="16" />
- <element name="ReadDIDID" value="23" hexvalue="17" />
- <element name="GetDTCsID" value="24" hexvalue="18" />
- <element name="ScrollableMessageID" value="25" hexvalue="19" />
- <element name="SliderID" value="26" hexvalue="1A" />
- <element name="ShowConstantTBTID" value="27" hexvalue="1B" />
- <element name="AlertManeuverID" value="28" hexvalue="1C" />
- <element name="UpdateTurnListID" value="29" hexvalue="1D" />
- <element name="ChangeRegistrationID" value="30" hexvalue="1E" />
- <element name="GenericResponseID" value="31" hexvalue="1F" />
- <element name="PutFileID" value="32" hexvalue="20" />
- <element name="DeleteFileID" value="33" hexvalue="21" />
- <element name="ListFilesID" value="34" hexvalue="22" />
- <element name="SetAppIconID" value="35" hexvalue="23" />
- <element name="SetDisplayLayoutID" value="36" hexvalue="24" />
- <element name="DiagnosticMessageID" value="37" hexvalue="25" />
- <element name="SystemRequestID" value="38" hexvalue="26" />
- <element name="SendLocationID" value="39" hexvalue="27" />
- <element name="DialNumberID" value="40" hexvalue="28" />
- <element name="ButtonPressID" value="41" hexvalue="29" />
- <element name="GetInteriorVehicleDataID" value="43" hexvalue="2B" />
- <element name="SetInteriorVehicleDataID" value="44" hexvalue="2C" />
- <element name="GetWayPointsID" value="45" hexvalue="2D" />
- <element name="SubscribeWayPointsID" value="46" hexvalue="2E" />
- <element name="UnsubscribeWayPointsID" value="47" hexvalue="2F" />
- <element name="GetSystemCapabilityID" value="48" hexvalue="30" />
- <element name="SendHapticDataID" value="49" hexvalue="31" />
+ <element name="RegisterAppInterfaceID" value="1" hexvalue="1" since="1.0" />
+ <element name="UnregisterAppInterfaceID" value="2" hexvalue="2" since="1.0" />
+ <element name="SetGlobalPropertiesID" value="3" hexvalue="3" since="1.0" />
+ <element name="ResetGlobalPropertiesID" value="4" hexvalue="4" since="1.0" />
+ <element name="AddCommandID" value="5" hexvalue="5" since="1.0" />
+ <element name="DeleteCommandID" value="6" hexvalue="6" since="1.0" />
+ <element name="AddSubMenuID" value="7" hexvalue="7" since="1.0" />
+ <element name="DeleteSubMenuID" value="8" hexvalue="8" since="1.0" />
+ <element name="CreateInteractionChoiceSetID" value="9" hexvalue="9" since="1.0" />
+ <element name="PerformInteractionID" value="10" hexvalue="A" since="1.0" />
+ <element name="DeleteInteractionChoiceSetID" value="11" hexvalue="B" since="1.0" />
+ <element name="AlertID" value="12" hexvalue="C" since="1.0" />
+ <element name="ShowID" value="13" hexvalue="D" since="1.0" />
+ <element name="SpeakID" value="14" hexvalue="E" since="1.0" />
+ <element name="SetMediaClockTimerID" value="15" hexvalue="F" since="1.0" />
+ <element name="PerformAudioPassThruID" value="16" hexvalue="10" since="2.0" />
+ <element name="EndAudioPassThruID" value="17" hexvalue="11" since="2.0" />
+ <element name="SubscribeButtonID" value="18" hexvalue="12" since="1.0" />
+ <element name="UnsubscribeButtonID" value="19" hexvalue="13" since="1.0" />
+ <element name="SubscribeVehicleDataID" value="20" hexvalue="14" since="2.0" />
+ <element name="UnsubscribeVehicleDataID" value="21" hexvalue="15" since="2.0" />
+ <element name="GetVehicleDataID" value="22" hexvalue="16" since="2.0" />
+ <element name="ReadDIDID" value="23" hexvalue="17" since="2.0" />
+ <element name="GetDTCsID" value="24" hexvalue="18" since="2.0" />
+ <element name="ScrollableMessageID" value="25" hexvalue="19" since="2.0" />
+ <element name="SliderID" value="26" hexvalue="1A" since="2.0" />
+ <element name="ShowConstantTBTID" value="27" hexvalue="1B" since="2.0" />
+ <element name="AlertManeuverID" value="28" hexvalue="1C" since="2.0" />
+ <element name="UpdateTurnListID" value="29" hexvalue="1D" since="2.0" />
+ <element name="ChangeRegistrationID" value="30" hexvalue="1E" since="2.0" />
+ <element name="GenericResponseID" value="31" hexvalue="1F" since="1.0" />
+ <element name="PutFileID" value="32" hexvalue="20" since="3.0" />
+ <element name="DeleteFileID" value="33" hexvalue="21" since="3.0" />
+ <element name="ListFilesID" value="34" hexvalue="22" since="3.0" />
+ <element name="SetAppIconID" value="35" hexvalue="23" since="3.0" />
+ <element name="SetDisplayLayoutID" value="36" hexvalue="24" since="3.0" />
+ <element name="DiagnosticMessageID" value="37" hexvalue="25" since="3.0" />
+ <element name="SystemRequestID" value="38" hexvalue="26" since="3.0" />
+ <element name="SendLocationID" value="39" hexvalue="27" since="3.0" />
+ <element name="DialNumberID" value="40" hexvalue="28" since="3.0" />
+ <element name="ButtonPressID" value="41" hexvalue="29" since="4.5" />
+ <element name="GetInteriorVehicleDataID" value="43" hexvalue="2B" since="4.5" />
+ <element name="SetInteriorVehicleDataID" value="44" hexvalue="2C" since="4.5" />
+ <element name="GetWayPointsID" value="45" hexvalue="2D" since="4.1" />
+ <element name="SubscribeWayPointsID" value="46" hexvalue="2E" since="4.1" />
+ <element name="UnsubscribeWayPointsID" value="47" hexvalue="2F" since="4.1" />
+ <element name="GetSystemCapabilityID" value="48" hexvalue="30" since="4.5" />
+ <element name="SendHapticDataID" value="49" hexvalue="31" since="4.5" />
<!--
Base Notifications
Range = 0x 0000 8000 - 0x 0000 FFFF
-->
- <element name="OnHMIStatusID" value="32768" hexvalue="8000" />
- <element name="OnAppInterfaceUnregisteredID" value="32769" hexvalue="8001" />
- <element name="OnButtonEventID" value="32770" hexvalue="8002" />
- <element name="OnButtonPressID" value="32771" hexvalue="8003" />
- <element name="OnVehicleDataID" value="32772" hexvalue="8004" />
- <element name="OnCommandID" value="32773" hexvalue="8005" />
- <element name="OnTBTClientStateID" value="32774" hexvalue="8006" />
- <element name="OnDriverDistractionID" value="32775" hexvalue="8007" />
- <element name="OnPermissionsChangeID" value="32776" hexvalue="8008" />
- <element name="OnAudioPassThruID" value="32777" hexvalue="8009" />
- <element name="OnLanguageChangeID" value="32778" hexvalue="800A" />
- <element name="OnKeyboardInputID" value="32779" hexvalue="800B" />
- <element name="OnTouchEventID" value="32780" hexvalue="800C" />
- <element name="OnSystemRequestID" value="32781" hexvalue="800D" />
- <element name="OnHashChangeID" value="32782" hexvalue="800E" />
- <element name="OnInteriorVehicleDataID" value="32783" hexvalue="800F" />
- <element name="OnWayPointChangeID" value="32784" hexvalue="8010" />
+ <element name="OnHMIStatusID" value="32768" hexvalue="8000" since="1.0" />
+ <element name="OnAppInterfaceUnregisteredID" value="32769" hexvalue="8001" since="1.0" />
+ <element name="OnButtonEventID" value="32770" hexvalue="8002" since="1.0" />
+ <element name="OnButtonPressID" value="32771" hexvalue="8003" since="1.0" />
+ <element name="OnVehicleDataID" value="32772" hexvalue="8004" since="2.0" />
+ <element name="OnCommandID" value="32773" hexvalue="8005" since="1.0" />
+ <element name="OnTBTClientStateID" value="32774" hexvalue="8006" since="1.0" />
+ <element name="OnDriverDistractionID" value="32775" hexvalue="8007" since="1.0" />
+ <element name="OnPermissionsChangeID" value="32776" hexvalue="8008" since="2.0" />
+ <element name="OnAudioPassThruID" value="32777" hexvalue="8009" since="2.0" />
+ <element name="OnLanguageChangeID" value="32778" hexvalue="800A" since="2.0" />
+ <element name="OnKeyboardInputID" value="32779" hexvalue="800B" since="3.0" />
+ <element name="OnTouchEventID" value="32780" hexvalue="800C" since="3.0" />
+ <element name="OnSystemRequestID" value="32781" hexvalue="800D" since="3.0" />
+ <element name="OnHashChangeID" value="32782" hexvalue="800E" since="3.0" />
+ <element name="OnInteriorVehicleDataID" value="32783" hexvalue="800F" since="4.5" />
+ <element name="OnWayPointChangeID" value="32784" hexvalue="8010" since="4.1" />
+ <element name="OnRCStatusID" value="32785" hexvalue="8011" since="5.0" />
<!--
Ford Specific Request / Response RPCs
Range = 0x 0001 0000 - 0x 0001 7FFF
-->
- <element name="EncodedSyncPDataID" value="65536" hexvalue="10000" />
- <element name="SyncPDataID" value="65537" hexvalue="10001" />
+ <element name="EncodedSyncPDataID" value="65536" hexvalue="10000" since="1.0" />
+ <element name="SyncPDataID" value="65537" hexvalue="10001" since="1.0" />
<!--
Ford Specific Notifications
Range = 0x 0001 8000 - 0x 0001 FFFF
-->
- <element name="OnEncodedSyncPDataID" value="98304" hexvalue="18000" />
- <element name="OnSyncPDataID" value="98305" hexvalue="18001" />
+ <element name="OnEncodedSyncPDataID" value="98304" hexvalue="18000" since="1.0" />
+ <element name="OnSyncPDataID" value="98305" hexvalue="18001" since="1.0" />
</enum>
- <enum name="messageType">
+ <enum name="messageType" since="1.0">
<description>
Enumeration linking message types with function types in WiPro protocol.
Assumes enumeration starts at value 0.
@@ -2389,43 +2660,67 @@
<element name="notification" value="2" />
</enum>
- <struct name="DateTime">
- <param name="millisecond" type="Integer" minvalue="0" maxvalue="999" mandatory="false">
+ <struct name="DateTime" since="4.1">
+ <param name="millisecond" type="Integer" minvalue="0" maxvalue="999" mandatory="false" since="4.2.2">
<description>Milliseconds </description>
</param>
- <param name="second" type="Integer" minvalue="0" maxvalue="60" mandatory="false">
+ <param name="second" type="Integer" minvalue="0" maxvalue="60" mandatory="false" since="4.2.2">
<description>Seconds part of time</description>
+ <history>
+ <param name="second" type="Integer" minvalue="0" maxvalue="60" mandatory="true" since="4.1" until="4.2.1" />
+ </history>
</param>
- <param name="minute" type="Integer" minvalue="0" maxvalue="59" mandatory="false">
+ <param name="minute" type="Integer" minvalue="0" maxvalue="59" mandatory="false" since="4.2.2">
<description>Minutes part of time</description>
+ <history>
+ <param name="minute" type="Integer" minvalue="0" maxvalue="59" mandatory="true" since="4.1" until="4.2.1" />
+ </history>
</param>
- <param name="hour" type="Integer" minvalue="0" maxvalue="23" mandatory="false">
+ <param name="hour" type="Integer" minvalue="0" maxvalue="23" mandatory="false" since="4.2.2">
<description>Hours part of time. Note that this structure accepts time only in 24 Hr format</description>
+ <history>
+ <param name="hour" type="Integer" minvalue="0" maxvalue="23" mandatory="true" since="4.1" until="4.2.1" />
+ </history>
</param>
- <param name="day" type="Integer" minvalue="1" maxvalue="31" mandatory="false">
+ <param name="day" type="Integer" minvalue="1" maxvalue="31" mandatory="false" since="4.2.2">
<description>Day of the month</description>
+ <history>
+ <param name="day" type="Integer" minvalue="1" maxvalue="31" mandatory="true" since="4.1" until="4.2.1" />
+ </history>
</param>
- <param name="month" type="Integer" minvalue="1" maxvalue="12" mandatory="false">
+ <param name="month" type="Integer" minvalue="1" maxvalue="12" mandatory="false" since="4.2.2">
<description>Month of the year</description>
+ <history>
+ <param name="month" type="Integer" minvalue="1" maxvalue="12" mandatory="true" since="4.1" until="4.2.1" />
+ </history>
</param>
- <param name="year" type="Integer" maxvalue="4095" mandatory="false">
+ <param name="year" type="Integer" maxvalue="4095" mandatory="false" since="4.2.2">
<description>The year in YYYY format</description>
+ <history>
+ <param name="year" type="Integer" maxvalue="4095" mandatory="true" since="4.1" until="4.2.1" />
+ </history>
</param>
- <param name="tz_hour" type="Integer" minvalue="-12" maxvalue="14" defvalue="0" mandatory="false">
+ <param name="tz_hour" type="Integer" minvalue="-12" maxvalue="14" defvalue="0" mandatory="false" since="4.2.2">
<description>Time zone offset in Hours wrt UTC.</description>
+ <history>
+ <param name="tz_hour" type="Integer" minvalue="-12" maxvalue="14" defvalue="0" mandatory="true" since="4.1" until="4.2.1" />
+ </history>
</param>
- <param name="tz_minute" type="Integer" minvalue="0" maxvalue="59" defvalue="0" mandatory="false">
+ <param name="tz_minute" type="Integer" minvalue="0" maxvalue="59" defvalue="0" mandatory="false" since="4.2.2">
<description>Time zone offset in Min wrt UTC.</description>
+ <history>
+ <param name="tz_minute" type="Integer" minvalue="0" maxvalue="59" defvalue="0" mandatory="true" since="4.1" until="4.2.1" />
+ </history>
</param>
</struct>
- <enum name="WayPointType">
+ <enum name="WayPointType" since="4.1">
<description>Describes what kind of waypoint is requested/provided.</description>
<element name="ALL" />
<element name="DESTINATION" />
</enum>
- <struct name="Coordinate">
+ <struct name="Coordinate" since="4.1">
<param name="latitudeDegrees" minvalue="-90" maxvalue="90" type="Float" mandatory="true">
<description>Latitude of the location.</description>
</param>
@@ -2434,7 +2729,7 @@
</param>
</struct>
- <struct name="OASISAddress">
+ <struct name="OASISAddress" since="4.1">
<param name="countryName" minlength="0" maxlength="200" type="String" mandatory="false">
<description>Name of the country (localized)</description>
</param>
@@ -2464,7 +2759,7 @@
</param>
</struct>
- <struct name="LocationDetails">
+ <struct name="LocationDetails" since="4.1">
<param name="coordinate" type="Coordinate" mandatory="false">
<description>Latitude/Longitude of the location.</description>
</param>
@@ -2488,7 +2783,7 @@
</param>
</struct>
- <enum name="SystemCapabilityType">
+ <enum name="SystemCapabilityType" since="4.5">
<description>Enumerations of all available system capability types</description>
<element name="NAVIGATION"/>
<element name="PHONE_CALL"/>
@@ -2496,7 +2791,7 @@
<element name="REMOTE_CONTROL"/>
</enum>
- <struct name="NavigationCapability">
+ <struct name="NavigationCapability" since="4.5">
<description>Extended capabilities for an onboard navigation system</description>
<param name="sendLocationEnabled" type="Boolean" mandatory="false">
<description>If the module has the ability to add locations to the onboard nav</description>
@@ -2506,14 +2801,14 @@
</param>
</struct>
- <struct name="PhoneCapability">
+ <struct name="PhoneCapability" since="4.5">
<description>Extended capabilities of the module's phone feature</description>
<param name="dialNumberEnabled" type="Boolean" mandatory="false">
<description>If the module has the ability to perform dial number</description>
</param>
</struct>
- <struct name="VideoStreamingFormat">
+ <struct name="VideoStreamingFormat" since="4.5">
<description>Video streaming formats and their specifications.</description>
<param name="protocol" type="VideoStreamingProtocol" mandatory="true">
<description>Protocol type, see VideoStreamingProtocol</description>
@@ -2523,7 +2818,7 @@
</param>
</struct>
- <struct name="VideoStreamingCapability">
+ <struct name="VideoStreamingCapability" since="4.5">
<description>Contains information about this system's video streaming capabilities.</description>
<param name="preferredResolution" type="ImageResolution" mandatory="false">
<description>The preferred resolution of a video stream for decoding and rendering on HMI.</description>
@@ -2539,9 +2834,156 @@
</param>
</struct>
+ <struct name="RGBColor" since="5.0">
+ <param name="red" type="Integer" minvalue="0" maxvalue="255" mandatory="true" />
+ <param name="green" type="Integer" minvalue="0" maxvalue="255" mandatory="true" />
+ <param name="blue" type="Integer" minvalue="0" maxvalue="255" mandatory="true" />
+ </struct>
+
+ <struct name="TemplateColorScheme" since="5.0">
+ <description>
+ A color scheme for all display layout templates.
+ </description>
+ <param name="primaryColor" type="RGBColor" mandatory="false">
+ <description>The primary "accent" color</description>
+ </param>
+ <param name="secondaryColor" type="RGBColor" mandatory="false">
+ <description>The secondary "accent" color</description>
+ </param>
+ <param name="backgroundColor" type="RGBColor" mandatory="false">
+ <description>The color of the background</description>
+ </param>
+ </struct>
+
<!---Remote control -->
- <struct name="Temperature">
+ <enum name="MassageZone" since="5.0">
+ <description>List possible zones of a multi-contour massage seat.</description>
+ <element name="LUMBAR">
+ <description>The back of a multi-contour massage seat. or SEAT_BACK</description>
+ </element>
+ <element name="SEAT_CUSHION">
+ <description>The bottom a multi-contour massage seat. or SEAT_BOTTOM </description>
+ </element>
+ </enum>
+
+ <enum name="MassageMode" since="5.0">
+ <description>List possible modes of a massage zone.</description>
+ <element name="OFF"/>
+ <element name="LOW"/>
+ <element name="HIGH"/>
+ </enum>
+
+ <struct name="MassageModeData" since="5.0">
+ <description>Specify the mode of a massage zone.</description>
+ <param name="massageZone" type="MassageZone" mandatory="true"></param>
+ <param name="massageMode" type="MassageMode" mandatory="true"></param>
+ </struct>
+
+ <enum name="MassageCushion" since="5.0">
+ <description>List possible cushions of a multi-contour massage seat.</description>
+ <element name="TOP_LUMBAR"/>
+ <element name="MIDDLE_LUMBAR"/>
+ <element name="BOTTOM_LUMBAR"/>
+ <element name="BACK_BOLSTERS"/>
+ <element name="SEAT_BOLSTERS"/>
+ </enum>
+
+ <struct name="MassageCushionFirmness" since="5.0">
+ <description>The intensity or firmness of a cushion.</description>
+ <param name="cushion" type="MassageCushion" mandatory="true"></param>
+ <param name="firmness" type="Integer" minvalue="0" maxvalue="100" mandatory="true"></param>
+ </struct>
+
+ <enum name="SeatMemoryActionType" since="5.0">
+ <element name="SAVE">
+ <description>Save current seat postions and settings to seat memory.</description>
+ </element>
+ <element name="RESTORE">
+ <description>Restore / apply the seat memory settings to the current seat. </description>
+ </element>
+ <element name="NONE">
+ <description>No action to be performed.</description>
+ </element>
+ </enum>
+
+ <struct name="SeatMemoryAction" since="5.0">
+ <param name="id" type="Integer" minvalue="1" maxvalue="10" mandatory="true"/>
+ <param name="label" type="String" maxlength="100" mandatory="false"/>
+ <param name="action" type="SeatMemoryActionType" mandatory="true"/>
+ </struct>
+
+ <enum name="SupportedSeat" since="5.0">
+ <description>List possible seats that is a remote controllable seat.</description>
+ <element name="DRIVER"/>
+ <element name="FRONT_PASSENGER"/>
+ </enum>
+
+ <struct name="SeatControlData" since="5.0">
+ <description>Seat control data corresponds to "SEAT" ModuleType. </description>
+ <param name="id" type="SupportedSeat" mandatory="true"></param>
+
+ <param name="heatingEnabled" type="Boolean" mandatory="false"></param>
+ <param name="coolingEnabled" type="Boolean" mandatory="false"></param>
+ <param name="heatingLevel" type="Integer" minvalue="0" maxvalue="100" mandatory="false"></param>
+ <param name="coolingLevel" type="Integer" minvalue="0" maxvalue="100" mandatory="false"></param>
+
+ <param name="horizontalPosition" type="Integer" minvalue="0" maxvalue="100" mandatory="false"></param>
+ <param name="verticalPosition" type="Integer" minvalue="0" maxvalue="100" mandatory="false"></param>
+ <param name="frontVerticalPosition" type="Integer" minvalue="0" maxvalue="100" mandatory="false"></param>
+ <param name="backVerticalPosition" type="Integer" minvalue="0" maxvalue="100" mandatory="false"></param>
+ <param name="backTiltAngle" type="Integer" minvalue="0" maxvalue="100" mandatory="false"></param>
+
+ <param name="headSupportHorizontalPosition" type="Integer" minvalue="0" maxvalue="100" mandatory="false"></param>
+ <param name="headSupportVerticalPosition" type="Integer" minvalue="0" maxvalue="100" mandatory="false"></param>
+
+ <param name="massageEnabled" type="Boolean" mandatory="false"></param>
+ <param name="massageMode" type="MassageModeData" minsize="1" maxsize="2" array="true" mandatory="false"></param>
+ <param name="massageCushionFirmness" type="MassageCushionFirmness" minsize="1" maxsize="5" array="true" mandatory="false"></param>
+
+ <param name="memory" type="SeatMemoryAction" mandatory="false"></param>
+ </struct>
+
+ <struct name="SeatControlCapabilities" since="5.0">
+ <param name="moduleName" type="String" maxlength="100" mandatory="true">
+ <description>
+ The short friendly name of the light control module.
+ It should not be used to identify a module by mobile application.
+ </description>
+ </param>
+ <param name="heatingEnabledAvailable" type="Boolean" mandatory="false">
+ </param>
+ <param name="coolingEnabledAvailable" type="Boolean" mandatory="false">
+ </param>
+ <param name="heatingLevelAvailable" type="Boolean" mandatory="false">
+ </param>
+ <param name="coolingLevelAvailable" type="Boolean" mandatory="false">
+ </param>
+ <param name="horizontalPositionAvailable" type="Boolean" mandatory="false">
+ </param>
+ <param name="verticalPositionAvailable" type="Boolean" mandatory="false">
+ </param>
+ <param name="frontVerticalPositionAvailable" type="Boolean" mandatory="false">
+ </param>
+ <param name="backVerticalPositionAvailable" type="Boolean" mandatory="false">
+ </param>
+ <param name="backTiltAngleAvailable" type="Boolean" mandatory="false">
+ </param>
+ <param name="headSupportHorizontalPositionAvailable" type="Boolean" mandatory="false">
+ </param>
+ <param name="headSupportVerticalPositionAvailable" type="Boolean" mandatory="false">
+ </param>
+ <param name="massageEnabledAvailable" type="Boolean" mandatory="false">
+ </param>
+ <param name="massageModeAvailable" type="Boolean" mandatory="false">
+ </param>
+ <param name="massageCushionFirmnessAvailable" type="Boolean" mandatory="false">
+ </param>
+ <param name="memoryAvailable" type="Boolean" mandatory="false">
+ </param>
+ </struct>
+
+ <struct name="Temperature" since="4.5">
<param name="unit" type="TemperatureUnit" mandatory="true">
<description>Temperature Unit</description>
</param>
@@ -2550,7 +2992,7 @@
</param>
</struct>
- <struct name="RdsData">
+ <struct name="RdsData" since="4.5">
<param name="PS" type="String" minlength="0" maxlength="8" mandatory="false">
<description>Program Service Name</description>
</param>
@@ -2577,7 +3019,34 @@
</param>
</struct>
- <struct name="RadioControlData">
+ <struct name="StationIDNumber" since="5.0">
+ <param name="countryCode" type="Integer" minvalue="0" maxvalue="999" mandatory="false">
+ <description>Binary Representation of ITU Country Code. USA Code is 001.</description>
+ </param>
+ <param name="fccFacilityId" type="Integer" minvalue="0" maxvalue="999999" mandatory="false">
+ <description>Binary representation of unique facility ID assigned by the FCC; FCC controlled for U.S. territory</description>
+ </param>
+ </struct>
+
+ <struct name="SisData" since="5.0">
+ <param name="stationShortName" type="String" minlength="4" maxlength="7" mandatory="false">
+ <description>Identifies the 4-alpha-character station call sign plus an optional (-FM) extension</description>
+ </param>
+ <param name="stationIDNumber" type="StationIDNumber" mandatory="false">
+ <description>Used for network Application. Consists of Country Code and FCC Facility ID.</description>
+ </param>
+ <param name="stationLongName" type="String" minlength="0" maxlength="56" mandatory="false">
+ <description>Identifies the station call sign or other identifying information in the long format.</description>
+ </param>
+ <param name="stationLocation" type="GPSData" mandatory="false">
+ <description>Provides the 3-dimensional geographic station location.</description>
+ </param>
+ <param name="stationMessage" type="String" minlength="0" maxlength="56" mandatory="false">
+ <description>May be used to convey textual information of general interest to the consumer such as weather forecasts or public service announcements. Includes a high priority delivery feature to convey emergencies that may be in the listening area.</description>
+ </param>
+ </struct>
+
+ <struct name="RadioControlData" since="4.5">
<param name="frequencyInteger" type="Integer" minvalue="0" maxvalue="1710" mandatory="false">
<description>The integer part of the frequency ie for 101.7 this value should be 101</description>
</param>
@@ -2588,11 +3057,20 @@
</param>
<param name="rdsData" type="RdsData" mandatory="false">
</param>
- <param name="availableHDs" type="Integer" minvalue="1" maxvalue="3" mandatory="false">
+ <param name="hdRadioEnable" type="Boolean" mandatory="false" since="5.0">
+ <description> True if the hd radio is on, false if the radio is off</description>
+ </param>
+ <param name="availableHDs" type="Integer" minvalue="1" maxvalue="7" mandatory="false" since="5.0">
<description>number of HD sub-channels if available</description>
+ <history>
+ <param name="availableHDs" type="Integer" minvalue="1" maxvalue="3" mandatory="false" since="4.5" until="5.0"/>
+ </history>
</param>
- <param name="hdChannel" type="Integer" minvalue="1" maxvalue="3" mandatory="false">
+ <param name="hdChannel" type="Integer" minvalue="1" maxvalue="7" mandatory="false" since="5.0">
<description>Current HD sub-channel if available</description>
+ <history>
+ <param name="hdChannel" type="Integer" minvalue="1" maxvalue="3" mandatory="false" since="4.5" until="5.0"/>
+ </history>
</param>
<param name="signalStrength" type="Integer" minvalue="0" maxvalue="100" mandatory="false">
</param>
@@ -2600,13 +3078,16 @@
<description>If the signal strength falls below the set value for this parameter, the radio will tune to an alternative frequency</description>
</param>
<param name="radioEnable" type="Boolean" mandatory="false">
- <description> True if the radio is on, false is the radio is off. If set to false, no other data will be included.</description>
+ <description> True if the radio is on, false if the radio is off. If set to false, no other data will be included.</description>
</param>
<param name="state" type="RadioState" mandatory="false">
</param>
+ <param name="sisData" type="SisData" mandatory="false" since="5.0">
+ <description>Read-only Station Information Service (SIS) data provides basic information about the station such as call sign, as well as information not displayable to the consumer such as the station identification number</description>
+ </param>
</struct>
- <struct name="ClimateControlData">
+ <struct name="ClimateControlData" since="4.5">
<param name="fanSpeed" type="Integer" minvalue="0" maxvalue="100" mandatory="false">
</param>
<param name="currentTemperature" type="Temperature" mandatory="false">
@@ -2627,19 +3108,21 @@
</param>
<param name="ventilationMode" type="VentilationMode" mandatory="false">
</param>
- </struct>
-
- <struct name="ModuleData">
- <description>The moduleType indicates which type of data should be changed and identifies which data object exists in this struct. For example, if the moduleType is CLIMATE then a "climateControlData" should exist</description>
- <param name="moduleType" type="ModuleType" mandatory="true">
+ <param name="heatedSteeringWheelEnable" type="Boolean" mandatory="false" since="5.0">
+ <description>value false means disabled/turn off, value true means enabled/turn on.</description>
</param>
- <param name="radioControlData" type="RadioControlData" mandatory="false">
+ <param name="heatedWindshieldEnable" type="Boolean" mandatory="false" since="5.0">
+ <description>value false means disabled, value true means enabled.</description>
</param>
- <param name="climateControlData" type="ClimateControlData" mandatory="false">
+ <param name="heatedRearWindowEnable" type="Boolean" mandatory="false" since="5.0">
+ <description>value false means disabled, value true means enabled.</description>
+ </param>
+ <param name="heatedMirrorsEnable" type="Boolean" mandatory="false" since="5.0">
+ <description>value false means disabled, value true means enabled.</description>
</param>
</struct>
- <struct name="RadioControlCapabilities">
+ <struct name="RadioControlCapabilities" since="4.5">
<description>Contains information about a radio control module's capabilities.</description>
<!-- need an ID in the future -->
<param name="moduleName" type="String" maxlength="100" mandatory="true">
@@ -2702,15 +3185,39 @@
True: Available, False: Not Available, Not present: Not Available.
</description>
</param>
+ <param name="sisDataAvailable" type="Boolean" mandatory="false" since="5.0">
+ <description>
+ Availability of the getting HD radio Station Information Service (SIS) data.
+ True: Available, False: Not Available, Not present: Not Available.
+ </description>
+ </param>
+ <param name="hdRadioEnableAvailable" type="Boolean" mandatory="false" since="5.0">
+ <description>
+ Availability of the control of enable/disable HD radio.
+ True: Available, False: Not Available, Not present: Not Available.
+ </description>
+ </param>
+ <param name="siriusxmRadioAvailable" type="Boolean" mandatory="false" since="5.0">
+ <description>
+ Availability of sirius XM radio.
+ True: Available, False: Not Available, Not present: Not Available.
+ </description>
+ </param>
</struct>
- <struct name="ClimateControlCapabilities">
+ <struct name="ClimateControlCapabilities" since="4.5">
<description>Contains information about a climate control module's capabilities.</description>
<!-- need an ID in the future -->
<param name="moduleName" type="String" maxlength="100" mandatory="true">
<description>The short friendly name of the climate control module.
It should not be used to identify a module by mobile application.</description>
</param>
+ <param name="currentTemperatureAvailable" type="Boolean" mandatory="false" since="5.0">
+ <description>
+ Availability of the reading of current temperature.
+ True: Available, False: Not Available, Not present: Not Available.
+ </description>
+ </param>
<param name="fanSpeedAvailable" type="Boolean" mandatory="false">
<description>
Availability of the control of fan speed.
@@ -2775,22 +3282,327 @@
A set of all ventilation modes that are controllable.
</description>
</param>
+ <param name="heatedSteeringWheelAvailable" type="Boolean" mandatory="false" since="5.0">
+ <description>
+ Availability of the control (enable/disable) of heated Steering Wheel.
+ True: Available, False: Not Available, Not present: Not Available.
+ </description>
+ </param>
+ <param name="heatedWindshieldAvailable" type="Boolean" mandatory="false" since="5.0">
+ <description>
+ Availability of the control (enable/disable) of heated Windshield.
+ True: Available, False: Not Available, Not present: Not Available.
+ </description>
+ </param>
+ <param name="heatedRearWindowAvailable" type="Boolean" mandatory="false" since="5.0">
+ <description>
+ Availability of the control (enable/disable) of heated Rear Window.
+ True: Available, False: Not Available, Not present: Not Available.
+ </description>
+ </param>
+ <param name="heatedMirrorsAvailable" type="Boolean" mandatory="false" since="5.0">
+ <description>
+ Availability of the control (enable/disable) of heated Mirrors.
+ True: Available, False: Not Available, Not present: Not Available.
+ </description>
+ </param>
+ </struct>
+
+ <struct name="EqualizerSettings" since="5.0">
+ <description>Defines the each Equalizer channel settings.</description>
+ <param name="channelId" type="Integer" minvalue="1" maxvalue="100" mandatory="true"></param>
+ <param name="channelName" type="String" mandatory="false" maxlength="50">
+ <description>read-only channel / frequency name (e.i. "Treble, Midrange, Bass" or "125 Hz")</description>
+ </param>
+ <param name="channelSetting" type="Integer" minvalue="0" maxvalue="100" mandatory="true">
+ <description>Reflects the setting, from 0%-100%.</description>
+ </param>
+ </struct>
+
+ <struct name="AudioControlData" since="5.0">
+ <param name="source" type="PrimaryAudioSource" mandatory="false">
+ <description>
+ In a getter response or a notification, it is the current primary audio source of the system.
+ In a setter request, it is the target audio source that the system shall switch to.
+ If the value is MOBILE_APP, the system shall switch to the mobile media app that issues the setter RPC.
+ </description>
+ </param>
+ <param name="keepContext" type="Boolean" mandatory="false">
+ <description>
+ This parameter shall not be present in any getter responses or notifications.
+ This parameter is optional in a setter request. The default value is false if it is not included.
+ If it is false, the system not only changes the audio source but also brings the default application or
+ system UI associated with the audio source to foreground.
+ If it is true, the system only changes the audio source, but keeps the current application in foreground.
+ </description>
+ </param>
+ <param name="volume" type="Integer" mandatory="false" minvalue="0" maxvalue="100">
+ <description>Reflects the volume of audio, from 0%-100%.</description>
+ </param>
+ <param name="equalizerSettings" type="EqualizerSettings" minsize="1" maxsize="100" mandatory="false" array="true">
+ <description>Defines the list of supported channels (band) and their current/desired settings on HMI</description>
+ </param>
</struct>
- <struct name="RemoteControlCapabilities">
+ <struct name="AudioControlCapabilities" since="5.0">
+ <param name="moduleName" type="String" maxlength="100" mandatory="true">
+ <description>
+ The short friendly name of the light control module.
+ It should not be used to identify a module by mobile application.
+ </description>
+ </param>
+ <param name="sourceAvailable" type="Boolean" mandatory="false">
+ <description>Availability of the control of audio source. </description>
+ </param>
+ <param name="keepContextAvailable" type="Boolean" mandatory="false">
+ <description>Availability of the keepContext parameter. </description>
+ </param>
+ <param name="volumeAvailable" type="Boolean" mandatory="false">
+ <description>Availability of the control of audio volume.</description>
+ </param>
+ <param name="equalizerAvailable" type="Boolean" mandatory="false">
+ <description>Availability of the control of Equalizer Settings.</description>
+ </param>
+ <param name="equalizerMaxChannelId" type="Integer" minvalue="1" maxvalue="100" mandatory="false">
+ <description>Must be included if equalizerAvailable=true, and assume all IDs starting from 1 to this value are valid</description>
+ </param>
+ </struct>
+
+ <enum name="LightName" since="5.0">
+ <!-- Common Single Light 0~500 -->
+ <element name="FRONT_LEFT_HIGH_BEAM" value="0"/>
+ <element name="FRONT_RIGHT_HIGH_BEAM" value="1"/>
+ <element name="FRONT_LEFT_LOW_BEAM" value="2"/>
+ <element name="FRONT_RIGHT_LOW_BEAM" value="3"/>
+ <element name="FRONT_LEFT_PARKING_LIGHT" value="4"/>
+ <element name="FRONT_RIGHT_PARKING_LIGHT" value="5"/>
+ <element name="FRONT_LEFT_FOG_LIGHT" value="6"/>
+ <element name="FRONT_RIGHT_FOG_LIGHT" value="7"/>
+ <element name="FRONT_LEFT_DAYTIME_RUNNING_LIGHT" value="8"/>
+ <element name="FRONT_RIGHT_DAYTIME_RUNNING_LIGHT" value="9"/>
+ <element name="FRONT_LEFT_TURN_LIGHT" value="10"/>
+ <element name="FRONT_RIGHT_TURN_LIGHT" value="11"/>
+ <element name="REAR_LEFT_FOG_LIGHT" value="12"/>
+ <element name="REAR_RIGHT_FOG_LIGHT" value="13"/>
+ <element name="REAR_LEFT_TAIL_LIGHT" value="14"/>
+ <element name="REAR_RIGHT_TAIL_LIGHT" value="15"/>
+ <element name="REAR_LEFT_BRAKE_LIGHT" value="16"/>
+ <element name="REAR_RIGHT_BRAKE_LIGHT" value="17"/>
+ <element name="REAR_LEFT_TURN_LIGHT" value="18"/>
+ <element name="REAR_RIGHT_TURN_LIGHT" value="19"/>
+ <element name="REAR_REGISTRATION_PLATE_LIGHT" value="20"/>
+
+ <!-- Exterior Lights by common function groups 501~800 -->
+ <element name="HIGH_BEAMS" value="501">
+ <description>Include all high beam lights: front_left and front_right.</description>
+ </element>
+ <element name="LOW_BEAMS" value="502">
+ <description>Include all low beam lights: front_left and front_right.</description>
+ </element>
+ <element name="FOG_LIGHTS" value="503">
+ <description>Include all fog lights: front_left, front_right, rear_left and rear_right.</description>
+ </element>
+ <element name="RUNNING_LIGHTS" value="504">
+ <description>Include all daytime running lights: front_left and front_right.</description>
+ </element>
+ <element name="PARKING_LIGHTS" value="505">
+ <description>Include all parking lights: front_left and front_right.</description>
+ </element>
+ <element name="BRAKE_LIGHTS" value="506">
+ <description>Include all brake lights: rear_left and rear_right.</description>
+ </element>
+ <element name="REAR_REVERSING_LIGHTS" value="507"/>
+ <element name="SIDE_MARKER_LIGHTS" value="508"/>
+ <element name="LEFT_TURN_LIGHTS" value="509">
+ <description>Include all left turn signal lights: front_left, rear_left, left_side and mirror_mounted.</description>
+ </element>
+ <element name="RIGHT_TURN_LIGHTS" value="510">
+ <description>Include all right turn signal lights: front_right, rear_right, right_side and mirror_mounted.</description>
+ </element>
+ <element name="HAZARD_LIGHTS" value="511">
+ <description>Include all hazard lights: front_left, front_right, rear_left and rear_right.</description>
+ </element>
+ <element name="REAR_CARGO_LIGHTS" value="512">
+ <description>Cargo lamps illuminate the cargo area.</description>
+ </element>
+ <element name="REAR_TRUCK_BED_LIGHTS" value="513">
+ <description>Truck bed lamps light up the bed of the truck.</description>
+ </element>
+ <element name="REAR_TRAILER_LIGHTS" value="514">
+ <description>Trailer lights are lamps mounted on a trailer hitch.</description>
+ </element>
+ <element name="LEFT_SPOT_LIGHTS" value="515">
+ <description>It is the spotlights mounted on the left side of a vehicle.</description>
+ </element>
+ <element name="RIGHT_SPOT_LIGHTS" value="516">
+ <description>It is the spotlights mounted on the right side of a vehicle.</description>
+ </element>
+ <element name="LEFT_PUDDLE_LIGHTS" value="517">
+ <description>Puddle lamps illuminate the ground beside the door as the customer is opening or approaching the door.</description>
+ </element>
+ <element name="RIGHT_PUDDLE_LIGHTS" value="518">
+ <description>Puddle lamps illuminate the ground beside the door as the customer is opening or approaching the door.</description>
+ </element>
+
+ <!-- Interior Lights by common function groups 801~900 -->
+ <element name="AMBIENT_LIGHTS" value="801"/>
+ <element name="OVERHEAD_LIGHTS" value="802"/>
+ <element name="READING_LIGHTS" value="803"/>
+ <element name="TRUNK_LIGHTS" value="804"/>
+
+ <!-- Lights by location 901~1000-->
+ <element name="EXTERIOR_FRONT_LIGHTS" value="901">
+ <description>Include exterior lights located in front of the vehicle. For example, fog lights and low beams.</description>
+ </element>
+ <element name="EXTERIOR_REAR_LIGHTS" value="902">
+ <description>Include exterior lights located at the back of the vehicle. For example, license plate lights, reverse lights, cargo lights, bed lights and trailer assist lights.</description>
+ </element>
+ <element name="EXTERIOR_LEFT_LIGHTS" value="903">
+ <description>Include exterior lights located at the left side of the vehicle. For example, left puddle lights and spot lights.</description>
+ </element>
+ <element name="EXTERIOR_RIGHT_LIGHTS" value="904">
+ <description>Include exterior lights located at the right side of the vehicle. For example, right puddle lights and spot lights.</description>
+ </element>
+ <element name="EXTERIOR_ALL_LIGHTS" value="905">
+ <description> Include all exterior lights around the vehicle.</description>
+ </element>
+ </enum>
+
+ <enum name="LightStatus" since="5.0">
+ <element name="ON"/>
+ <element name="OFF"/>
+ <element name="RAMP_UP"/>
+ <element name="RAMP_DOWN"/>
+ <element name="UNKNOWN"/>
+ <element name="INVALID"/>
+ </enum>
+
+ <struct name="LightCapabilities" since="5.0">
+ <param name="name" type="LightName" mandatory="true" />
+ <param name="statusAvailable" type="Boolean" mandatory="false">
+ <description>
+ Indicates if the status (ON/OFF) can be set remotely. App shall not use read-only values (RAMP_UP/RAMP_DOWN/UNKNOWN/INVALID) in a setInteriorVehicleData request.
+ </description>
+ </param>
+ <param name="densityAvailable" type="Boolean" mandatory="false">
+ <description>
+ Indicates if the light's density can be set remotely (similar to a dimmer).
+ </description>
+ </param>
+ <param name="rgbColorSpaceAvailable" type="Boolean" mandatory="false">
+ <description>
+ Indicates if the light's color can be set remotely by using the sRGB color space.
+ </description>
+ </param>
+ </struct>
+
+ <struct name="LightControlCapabilities" since="5.0">
+ <param name="moduleName" type="String" maxlength="100" mandatory="true">
+ <description>
+ The short friendly name of the light control module.
+ It should not be used to identify a module by mobile application.
+ </description>
+ </param>
+ <param name="supportedLights" type="LightCapabilities" minsize="1" maxsize="100" array="true" mandatory="true">
+ <description> An array of available LightCapabilities that are controllable. </description>
+ </param>
+ </struct>
+
+ <struct name="LightState" since="5.0">
+ <param name="id" type="LightName" mandatory="true">
+ <description>The name of a light or a group of lights. </description>
+ </param>
+ <param name="status" type="LightStatus" mandatory="true"/>
+ <param name="density" type="Float" minvalue="0" maxvalue="1" mandatory="false" />
+ <param name="color" type="RGBColor" mandatory="false" />
+ </struct>
+
+ <struct name="LightControlData" since="5.0">
+ <param name="lightState" type="LightState" mandatory="true" minsize="1" maxsize="100" array="true">
+ <description>An array of LightNames and their current or desired status. No change to the status of the LightNames that are not listed in the array.</description>
+ </param>
+ </struct>
+
+ <enum name="DisplayMode" since="5.0">
+ <element name="DAY"/>
+ <element name="NIGHT"/>
+ <element name="AUTO"/>
+ </enum>
+
+ <enum name="DistanceUnit" since="5.0">
+ <element name="MILES"/>
+ <element name="KILOMETERS"/>
+ </enum>
+
+ <struct name="HMISettingsControlData" since="5.0">
+ <description>Corresponds to "HMI_SETTINGS" ModuleType</description>
+ <param name="displayMode" type="DisplayMode" mandatory="false"></param>
+ <param name="temperatureUnit" type="TemperatureUnit" mandatory="false"></param>
+ <param name="distanceUnit" type="DistanceUnit" mandatory="false"></param>
+ </struct>
+
+ <struct name="HMISettingsControlCapabilities" since="5.0">
+ <param name="moduleName" type="String" maxlength="100" mandatory="true">
+ <description>
+ The short friendly name of the hmi setting module.
+ It should not be used to identify a module by mobile application.
+ </description>
+ </param>
+ <param name="distanceUnitAvailable" type="Boolean" mandatory="false">
+ <description>Availability of the control of distance unit. </description>
+ </param>
+ <param name="temperatureUnitAvailable" type="Boolean" mandatory="false">
+ <description>Availability of the control of temperature unit. </description>
+ </param>
+ <param name="displayModeUnitAvailable" type="Boolean" mandatory="false">
+ <description>Availability of the control of HMI display mode. </description>
+ </param>
+ </struct>
+
+ <struct name="ModuleData" since="4.5">
+ <description>The moduleType indicates which type of data should be changed and identifies which data object exists in this struct. For example, if the moduleType is CLIMATE then a "climateControlData" should exist</description>
+ <param name="moduleType" type="ModuleType" mandatory="true">
+ </param>
+ <param name="radioControlData" type="RadioControlData" mandatory="false">
+ </param>
+ <param name="climateControlData" type="ClimateControlData" mandatory="false">
+ </param>
+ <param name="seatControlData" type="SeatControlData" mandatory="false" since="5.0">
+ </param>
+ <param name="audioControlData" type="AudioControlData" mandatory="false" since="5.0">
+ </param>
+ <param name="lightControlData" type="LightControlData" mandatory="false" since="5.0">
+ </param>
+ <param name="hmiSettingsControlData" type="HMISettingsControlData" mandatory="false" since="5.0">
+ </param>
+ </struct>
+
+ <struct name="RemoteControlCapabilities" since="4.5">
<param name="climateControlCapabilities" type="ClimateControlCapabilities" mandatory="false" minsize="1" maxsize="100" array="true">
- <description>If included, the platform supports RC climate controls. For this baseline version, maxsize=1. i.e. only one climate control module is supported.</description >
+ <description>If included, the platform supports RC climate controls. For this baseline version, maxsize=1. i.e. only one climate control module is supported.</description>
</param>
<param name="radioControlCapabilities" type="RadioControlCapabilities" mandatory="false" minsize="1" maxsize="100" array="true">
- <description>If included, the platform supports RC radio controls.For this baseline version, maxsize=1. i.e. only one radio control module is supported.</description >
+ <description>If included, the platform supports RC radio controls.For this baseline version, maxsize=1. i.e. only one radio control module is supported.</description>
</param>
- <param name="buttonCapabilities" type="ButtonCapabilities" mandatory="false" minsize="1" maxsize="100" array="true" >
- <description>If included, the platform supports RC button controls with the included button names.</description >
+ <param name="buttonCapabilities" type="ButtonCapabilities" mandatory="false" minsize="1" maxsize="100" array="true">
+ <description>If included, the platform supports RC button controls with the included button names.</description>
+ </param>
+ <param name="audioControlCapabilities" type="AudioControlCapabilities" mandatory="false" minsize="1" maxsize="100" array="true" since="5.0">
+ <description>If included, the platform supports audio controls.</description>
+ </param>
+ <param name="hmiSettingsControlCapabilities" type="HMISettingsControlCapabilities" mandatory="false" since="5.0">
+ <description>If included, the platform supports hmi setting controls.</description>
+ </param>
+ <param name="lightControlCapabilities" type="LightControlCapabilities" mandatory="false" since="5.0">
+ <description>If included, the platform supports light controls.</description>
+ </param>
+ <param name="seatControlCapabilities" type="SeatControlCapabilities" mandatory="false" minsize="1" maxsize="100" array="true" since="5.0">
+ <description>If included, the platform supports seat controls.</description>
</param>
</struct>
<!-- End of RC -->
- <struct name="SystemCapability">
+ <struct name="SystemCapability" since="4.5">
<description>The systemCapabilityType indicates which type of data should be changed and identifies which data object exists in this struct. For example, if the SystemCapability Type is NAVIGATION then a "navigationCapability" should exist</description>
<param name="systemCapabilityType" type="SystemCapabilityType" mandatory="true">
<description>Used as a descriptor of what data to expect in this struct. The corresponding param to this enum should be included and the only other para included.</description>
@@ -2809,7 +3621,7 @@
</param>
</struct>
- <enum name="MetadataType">
+ <enum name="MetadataType" since="4.5">
<element name="mediaTitle">
<description>The data in this field contains the title of the currently playing audio track.</description>
</element>
@@ -2848,7 +3660,7 @@
</element>
</enum>
- <struct name="MetadataTags">
+ <struct name="MetadataTags" since="4.5">
<param name="mainField1" type="MetadataType" minsize="0" maxsize="5" array="true" mandatory="false">
<description>The type of data contained in the "mainField1" text field.</description>
</param>
@@ -2863,7 +3675,7 @@
</param>
</struct>
- <struct name="Rectangle">
+ <struct name="Rectangle" since="4.5">
<param name="x" type="Float" mandatory="true">
<description>The upper left X-coordinate of the rectangle</description>
</param>
@@ -2878,7 +3690,7 @@
</param>
</struct>
- <struct name="HapticRect">
+ <struct name="HapticRect" since="4.5">
<description>Defines haptic data for each user control object for video streaming application</description>
<param name="id" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="true">
<description>A user control spatial identifier</description>
@@ -2890,17 +3702,17 @@
<!-- Requests/Responses -->
- <function name="RegisterAppInterface" functionID="RegisterAppInterfaceID" messagetype="request">
+ <function name="RegisterAppInterface" functionID="RegisterAppInterfaceID" messagetype="request" since="1.0">
<description>
Establishes an interface with a mobile application.
Before registerAppInterface no other commands will be accepted/executed.
</description>
- <param name="syncMsgVersion" type="SyncMsgVersion" mandatory="true">
+ <param name="syncMsgVersion" type="SyncMsgVersion" mandatory="true" since="1.0">
<description>See SyncMsgVersion</description>
</param>
- <param name="appName" type="String" maxlength="100" mandatory="true">
+ <param name="appName" type="String" maxlength="100" mandatory="true" since="1.0">
<description>
The mobile application name, e.g. "Ford Drive Green".
Needs to be unique over all applications.
@@ -2912,7 +3724,7 @@
</description>
</param>
- <param name="ttsName" type="TTSChunk" minsize="1" maxsize="100" array="true" mandatory="false" >
+ <param name="ttsName" type="TTSChunk" minsize="1" maxsize="100" array="true" mandatory="false" since="2.0">
<description>
TTS string for VR recognition of the mobile application name, e.g. "Ford Drive Green".
Meant to overcome any failing on speech engine in properly pronouncing / understanding app name.
@@ -2923,7 +3735,7 @@
</description>
</param>
- <param name="ngnMediaScreenAppName" type="String" maxlength="100" mandatory="false">
+ <param name="ngnMediaScreenAppName" type="String" maxlength="100" mandatory="false" since="1.0">
<description>
Provides an abbreviated version of the app name (if needed), that will be displayed on the NGN media screen.
If not provided, the appName is used instead (and will be truncated if too long)
@@ -2931,7 +3743,7 @@
</description>
</param>
- <param name="vrSynonyms" type="String" maxlength="40" minsize="1" maxsize="100" array="true" mandatory="false">
+ <param name="vrSynonyms" type="String" maxlength="40" minsize="1" maxsize="100" array="true" mandatory="false" since="1.0">
<description>
Defines an additional voice recognition command.
May not interfere with any app name of previously registered applications and any predefined blacklist of words (global commands)
@@ -2939,20 +3751,20 @@
</description>
</param>
- <param name="isMediaApplication" type="Boolean" mandatory="true">
+ <param name="isMediaApplication" type="Boolean" mandatory="true" since="1.0">
<description>
Indicates if the application is a media or a non-media application.
Only media applications will be able to stream audio to the module that is audible outside of the BT media source.
</description>
</param>
- <param name="languageDesired" type="Language" mandatory="true">
+ <param name="languageDesired" type="Language" mandatory="true" since="1.0">
<description>
See Language
Current app's expected VR+TTS language
If there is a mismatch with the module, the app will be able to change this registration with changeRegistration prior to app being brought into focus.
</description>
</param>
- <param name="hmiDisplayLanguageDesired" type="Language" mandatory="true">
+ <param name="hmiDisplayLanguageDesired" type="Language" mandatory="true" since="2.0">
<description>
See Language
Current app's expected display language
@@ -2960,14 +3772,14 @@
</description>
</param>
- <param name="appHMIType" type="AppHMIType" minsize="1" maxsize="100" array="true" mandatory="false">
+ <param name="appHMIType" type="AppHMIType" minsize="1" maxsize="100" array="true" mandatory="false" since="2.0">
<description>
See AppHMIType
List of all applicable app HMI types stating which HMI classifications to be given to the app.
</description>
</param>
- <param name="hashID" type="String" maxlength="100" mandatory="false">
+ <param name="hashID" type="String" maxlength="100" mandatory="false" since="3.0">
<description>
ID used to uniquely identify current state of all app data that can persist through connection cycles (e.g. ignition cycles).
This registered data (commands, submenus, choice sets, etc.) can be reestablished without needing to explicitly reregister each piece.
@@ -2975,22 +3787,27 @@
When sending hashID, all RegisterAppInterface parameters should still be provided (e.g. ttsName, etc.).
</description>
</param>
- <param name="deviceInfo" type="DeviceInfo" mandatory="false">
+ <param name="deviceInfo" type="DeviceInfo" mandatory="false" since="3.0">
<description>
See DeviceInfo.
</description>
</param>
- <param name="appID" type="String" maxlength="100" mandatory="true">
+ <param name="appID" type="String" maxlength="100" mandatory="true" since="2.0">
+ <description>ID used to validate app with policy table entries</description>
+ </param>
+ <param name="fullAppID" type="String" maxlength="100" mandatory="false" since="5.0">
<description>ID used to validate app with policy table entries</description>
</param>
- <param name="appInfo" type="AppInfo" mandatory="false">
+ <param name="appInfo" type="AppInfo" mandatory="false" since="2.0">
<description>
See AppInfo.
</description>
</param>
+ <param name="dayColorScheme" type="TemplateColorScheme" mandatory="false" since="5.0"/>
+ <param name="nightColorScheme" type="TemplateColorScheme" mandatory="false" since="5.0"/>
</function>
- <function name="RegisterAppInterface" functionID="RegisterAppInterfaceID" messagetype="response">
+ <function name="RegisterAppInterface" functionID="RegisterAppInterfaceID" messagetype="response" since="1.0">
<description>The response to registerAppInterface</description>
<param name="success" type="Boolean" platform="documentation" mandatory="true">
@@ -3026,7 +3843,7 @@
<description>The currently active VR+TTS language on the module. See "Language" for options.</description>
</param>
- <param name="hmiDisplayLanguage" type="Language" mandatory="false">
+ <param name="hmiDisplayLanguage" type="Language" mandatory="false" since="2.0">
<description>The currently active display language on the module. See "Language" for options.</description>
</param>
@@ -3038,61 +3855,68 @@
<description>See ButtonCapabilities</description >
</param>
- <param name="softButtonCapabilities" type="SoftButtonCapabilities" minsize="1" maxsize="100" array="true" mandatory="false">
+ <param name="softButtonCapabilities" type="SoftButtonCapabilities" minsize="1" maxsize="100" array="true" mandatory="false" since="2.0">
<description>If returned, the platform supports on-screen SoftButtons; see SoftButtonCapabilities.</description >
</param>
- <param name="presetBankCapabilities" type="PresetBankCapabilities" mandatory="false">
+ <param name="presetBankCapabilities" type="PresetBankCapabilities" mandatory="false" since="2.0">
<description>If returned, the platform supports custom on-screen Presets; see PresetBankCapabilities.</description >
</param>
- <param name="hmiZoneCapabilities" type="HmiZoneCapabilities" minsize="1" maxsize="100" array="true" mandatory="false">
+ <param name="hmiZoneCapabilities" type="HmiZoneCapabilities" minsize="1" maxsize="100" array="true" mandatory="false" since="1.0">
<description>See HmiZoneCapabilities</description>
</param>
- <param name="speechCapabilities" type="SpeechCapabilities" minsize="1" maxsize="100" array="true" mandatory="false">
+ <param name="speechCapabilities" type="SpeechCapabilities" minsize="1" maxsize="100" array="true" mandatory="false" since="1.0">
<description>See SpeechCapabilities</description>
</param>
- <param name="prerecordedSpeech" type="PrerecordedSpeech" minsize="1" maxsize="100" array="true" mandatory="false">
+ <param name="prerecordedSpeech" type="PrerecordedSpeech" minsize="1" maxsize="100" array="true" mandatory="false" since="3.0">
<description>See PrerecordedSpeech</description>
</param>
- <param name="vrCapabilities" type="VrCapabilities" minsize="1" maxsize="100" array="true" mandatory="false">
+ <param name="vrCapabilities" type="VrCapabilities" minsize="1" maxsize="100" array="true" mandatory="false" since="1.0">
<description>See VrCapabilities</description>
</param>
- <param name="audioPassThruCapabilities" type="AudioPassThruCapabilities" minsize="1" maxsize="100" array="true" mandatory="false">
+ <param name="audioPassThruCapabilities" type="AudioPassThruCapabilities" minsize="1" maxsize="100" array="true" mandatory="false" since="2.0">
<description>See AudioPassThruCapability</description>
</param>
- <param name="pcmStreamCapabilities" type="AudioPassThruCapabilities" array="false" mandatory="false">
+ <param name="pcmStreamCapabilities" type="AudioPassThruCapabilities" array="false" mandatory="false" since="4.1">
<description>See AudioPassThruCapability</description>
</param>
- <param name="vehicleType" type="VehicleType" mandatory="false">
+ <param name="vehicleType" type="VehicleType" mandatory="false" since="2.0">
<description>Specifies the vehicle's type. See VehicleType.</description>
</param>
- <param name="supportedDiagModes" type="Integer" minvalue="0" maxvalue="255" array="true" minsize="1" maxsize="100" mandatory="false" >
+ <param name="supportedDiagModes" type="Integer" minvalue="0" maxvalue="255" array="true" minsize="1" maxsize="100" mandatory="false" since="3.0">
<description>
Specifies the white-list of supported diagnostic modes (0x00-0xFF) capable for DiagnosticMessage requests.
If a mode outside this list is requested, it will be rejected.
</description>
</param>
- <param name="hmiCapabilities" type="HMICapabilities" mandatory="false">
+ <param name="hmiCapabilities" type="HMICapabilities" mandatory="false" since="3.0">
<description>Specifies the HMI’s capabilities. See HMICapabilities.</description>
</param>
- <param name="sdlVersion" type="String" maxlength="100" mandatory="false" platform="documentation">
+ <param name="sdlVersion" type="String" maxlength="100" mandatory="false" platform="documentation" since="3.0">
<description>The SmartDeviceLink version.</description>
</param>
- <param name="systemSoftwareVersion" type="String" maxlength="100" mandatory="false" platform="documentation">
+ <param name="systemSoftwareVersion" type="String" maxlength="100" mandatory="false" platform="documentation" since="3.0">
<description>The software version of the system that implements the SmartDeviceLink core.</description>
</param>
+
+ <param name="iconResumed" type="Boolean" mandatory="false" since="5.0">
+ <description>
+ Existence of apps icon at system. If true, apps icon
+ was resumed at system. If false, apps icon is not resumed at system
+ </description>
+ </param>
</function>
- <function name="UnregisterAppInterface" functionID="UnregisterAppInterfaceID" messagetype="request">
+ <function name="UnregisterAppInterface" functionID="UnregisterAppInterfaceID" messagetype="request" since="1.0">
<description>
Closes an interface from a mobile application.
After unregisterAppInterface, no commands other than registerAppInterface will be accepted/executed.
@@ -3100,7 +3924,7 @@
</description>
</function>
- <function name="UnregisterAppInterface" functionID="UnregisterAppInterfaceID" messagetype="response">
+ <function name="UnregisterAppInterface" functionID="UnregisterAppInterfaceID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
@@ -3122,10 +3946,10 @@
</function>
- <function name="SetGlobalProperties" functionID="SetGlobalPropertiesID" messagetype="request">
+ <function name="SetGlobalProperties" functionID="SetGlobalPropertiesID" messagetype="request" since="1.0">
<description>Allows setting global properties.</description>
- <param name="helpPrompt" type="TTSChunk" minsize="1" maxsize="100" array="true" mandatory="false" >
+ <param name="helpPrompt" type="TTSChunk" minsize="1" maxsize="100" array="true" mandatory="false" since="1.0">
<description>
The help prompt.
An array of text chunks of type TTSChunk. See TTSChunk.
@@ -3133,7 +3957,7 @@
</description>
</param>
- <param name="timeoutPrompt" type="TTSChunk" minsize="1" maxsize="100" array="true" mandatory="false" >
+ <param name="timeoutPrompt" type="TTSChunk" minsize="1" maxsize="100" array="true" mandatory="false" since="1.0">
<description>
Help text for a wait timeout.
An array of text chunks of type TTSChunk. See TTSChunk.
@@ -3141,7 +3965,7 @@
</description>
</param>
- <param name="vrHelpTitle" type="String" maxlength="500" mandatory="false">
+ <param name="vrHelpTitle" type="String" maxlength="500" mandatory="false" since="2.0">
<description>
VR Help Title text.
If omitted on supported displays, the default module help title shall be used.
@@ -3149,7 +3973,7 @@
</description>
</param>
- <param name="vrHelp" type="VrHelpItem" minsize="1" maxsize="100" array="true" mandatory="false">
+ <param name="vrHelp" type="VrHelpItem" minsize="1" maxsize="100" array="true" mandatory="false" since="2.0">
<description>
VR Help Items.
If omitted on supported displays, the default AppLink VR help / What Can I Say? screen shall be used.
@@ -3157,20 +3981,20 @@
If omitted and a vrHelpTitle is provided, the request will be rejected.
</description>
</param>
- <param name="menuTitle" maxlength="500" type="String" mandatory="false">
+ <param name="menuTitle" maxlength="500" type="String" mandatory="false" since="3.0">
<description>Optional text to label an app menu button (for certain touchscreen platforms).</description>
</param>
- <param name="menuIcon" type="Image" mandatory="false">
- <description>>Optional icon to draw on an app menu button (for certain touchscreen platforms).</description>
+ <param name="menuIcon" type="Image" mandatory="false" since="3.0">
+ <description>Optional icon to draw on an app menu button (for certain touchscreen platforms).</description>
</param>
- <param name="keyboardProperties" type="KeyboardProperties" mandatory="false">
+ <param name="keyboardProperties" type="KeyboardProperties" mandatory="false" since="3.0">
<description>On-screen keyboard configuration (if available).</description>
</param>
</function>
- <function name="SetGlobalProperties" functionID="SetGlobalPropertiesID" messagetype="response">
+ <function name="SetGlobalProperties" functionID="SetGlobalPropertiesID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
@@ -3196,7 +4020,7 @@
</function>
- <function name="ResetGlobalProperties" functionID="ResetGlobalPropertiesID" messagetype="request">
+ <function name="ResetGlobalProperties" functionID="ResetGlobalPropertiesID" messagetype="request" since="1.0">
<description>Allows resetting global properties.</description>
<param name="properties" type="GlobalProperty" minsize="1" maxsize="100" array="true" mandatory="true">
@@ -3204,7 +4028,7 @@
</param>
</function>
- <function name="ResetGlobalProperties" functionID="ResetGlobalPropertiesID" messagetype="response">
+ <function name="ResetGlobalProperties" functionID="ResetGlobalPropertiesID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
@@ -3227,7 +4051,7 @@
</param>
</function>
- <function name="AddCommand" functionID="AddCommandID" messagetype="request">
+ <function name="AddCommand" functionID="AddCommandID" messagetype="request" since="1.0">
<description>
Adds a command to the in application menu.
Either menuParams or vrCommands must be provided.
@@ -3248,7 +4072,7 @@
</description>
</param>
- <param name="cmdIcon" type="Image" mandatory="false">
+ <param name="cmdIcon" type="Image" mandatory="false" since="2.0">
<description>
Image struct determining whether static or dynamic icon.
If omitted on supported displays, no (or the default if applicable) icon shall be displayed.
@@ -3257,7 +4081,7 @@
</function>
- <function name="AddCommand" functionID="AddCommandID" messagetype="response">
+ <function name="AddCommand" functionID="AddCommandID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
@@ -3285,7 +4109,7 @@
</function>
- <function name="DeleteCommand" functionID="DeleteCommandID" messagetype="request">
+ <function name="DeleteCommand" functionID="DeleteCommandID" messagetype="request" since="1.0">
<description>Deletes all commands from the in-application menu with the specified command id.</description>
<param name="cmdID" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="true">
@@ -3294,7 +4118,7 @@
</function>
- <function name="DeleteCommand" functionID="DeleteCommandID" messagetype="response">
+ <function name="DeleteCommand" functionID="DeleteCommandID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
</param>
@@ -3318,7 +4142,7 @@
</function>
- <function name="AddSubMenu" functionID="AddSubMenuID" messagetype="request">
+ <function name="AddSubMenu" functionID="AddSubMenuID" messagetype="request" since="1.0">
<description>Adds a sub menu to the in-application menu.</description>
<param name="menuID" type="Integer" minvalue="1" maxvalue="2000000000" mandatory="true">
@@ -3339,9 +4163,13 @@
<param name="menuName" maxlength="500" type="String" mandatory="true">
<description>Text to show in the menu for this sub menu.</description>
</param>
+
+ <param name="menuIcon" type="Image" mandatory="false" since="5.0">
+ <description>The image field for AddSubMenu</description>
+ </param>
</function>
- <function name="AddSubMenu" functionID="AddSubMenuID" messagetype="response">
+ <function name="AddSubMenu" functionID="AddSubMenuID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
</param>
@@ -3364,7 +4192,7 @@
</param>
</function>
- <function name="DeleteSubMenu" functionID="DeleteSubMenuID" messagetype="request">
+ <function name="DeleteSubMenu" functionID="DeleteSubMenuID" messagetype="request" since="1.0">
<description>Deletes a submenu from the in-application menu.</description>
<param name="menuID" type="Integer" minvalue="1" maxvalue="2000000000" mandatory="true">
@@ -3373,7 +4201,7 @@
</function>
- <function name="DeleteSubMenu" functionID="DeleteSubMenuID" messagetype="response">
+ <function name="DeleteSubMenu" functionID="DeleteSubMenuID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
@@ -3398,7 +4226,7 @@
</function>
- <function name="CreateInteractionChoiceSet" functionID="CreateInteractionChoiceSetID" messagetype="request">
+ <function name="CreateInteractionChoiceSet" functionID="CreateInteractionChoiceSetID" messagetype="request" since="1.0">
<description>creates interaction choice set to be used later by performInteraction</description>
<param name="interactionChoiceSetID" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="true">
@@ -3408,7 +4236,7 @@
<param name="choiceSet" type="Choice" minsize="1" maxsize="100" array="true" mandatory="true"/>
</function>
- <function name="CreateInteractionChoiceSet" functionID="CreateInteractionChoiceSetID" messagetype="response">
+ <function name="CreateInteractionChoiceSet" functionID="CreateInteractionChoiceSetID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
</param>
@@ -3432,7 +4260,7 @@
</param>
</function>
- <function name="PerformInteraction" functionID="PerformInteractionID" messagetype="request">
+ <function name="PerformInteraction" functionID="PerformInteractionID" messagetype="request" since="1.0">
<description>Triggers an interaction (e.g. "Permit GPS?" - Yes, no, Always Allow).</description>
<param name="initialText" type="String" maxlength="500" mandatory="true">
@@ -3481,21 +4309,20 @@
</description>
</param>
- <param name="vrHelp" type="VrHelpItem" minsize="1" maxsize="100" array="true" mandatory="false">
+ <param name="vrHelp" type="VrHelpItem" minsize="1" maxsize="100" array="true" mandatory="false" since="2.0">
<description>
Ability to send suggested VR Help Items to display on-screen during Perform Interaction.
If omitted on supported displays, the default generated list of suggested choices shall be displayed.
</description>
</param>
- <param name="interactionLayout" type="LayoutMode" mandatory="false">
+ <param name="interactionLayout" type="LayoutMode" mandatory="false" since="3.0">
<description>See LayoutMode.</description>
</param>
</function>
- <function name="PerformInteraction" functionID="PerformInteractionID" messagetype="response">
-
+ <function name="PerformInteraction" functionID="PerformInteractionID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
</param>
@@ -3528,7 +4355,7 @@
</description>
</param>
- <param name="manualTextEntry" type="String" maxlength="500" mandatory="false">
+ <param name="manualTextEntry" type="String" maxlength="500" mandatory="false" since="3.0">
<description>
Manually entered text selection, e.g. through keyboard
Can be returned in lieu of choiceID, depending on trigger source
@@ -3544,7 +4371,7 @@
</function>
- <function name="DeleteInteractionChoiceSet" functionID="DeleteInteractionChoiceSetID" messagetype="request">
+ <function name="DeleteInteractionChoiceSet" functionID="DeleteInteractionChoiceSetID" messagetype="request" since="1.0">
<description>Deletes interaction choice set that has been created with "CreateInteractionChoiceSet".</description>
<description>The interaction may only be deleted when not currently in use by a "performInteraction".</description>
@@ -3553,7 +4380,7 @@
</param>
</function>
- <function name="DeleteInteractionChoiceSet" functionID="DeleteInteractionChoiceSetID" messagetype="response">
+ <function name="DeleteInteractionChoiceSet" functionID="DeleteInteractionChoiceSetID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
</param>
@@ -3576,7 +4403,7 @@
</param>
</function>
- <function name="Alert" functionID="AlertID" messagetype="request">
+ <function name="Alert" functionID="AlertID" messagetype="request" since="1.0">
<description>Shows an alert which typically consists of text-to-speech message and text on the display. At least either alertText1, alertText2 or TTSChunks need to be provided.</description>
<param name="alertText1" type="String" maxlength="500" mandatory="false">
@@ -3587,7 +4414,7 @@
<description>The second line of the alert text field</description>
</param>
- <param name="alertText3" type="String" maxlength="500" mandatory="false">
+ <param name="alertText3" type="String" maxlength="500" mandatory="false" since="2.0">
<description>The optional third line of the alert text field</description>
</param>
@@ -3613,13 +4440,13 @@
</description>
</param>
- <param name="progressIndicator" type="Boolean" mandatory="false">
+ <param name="progressIndicator" type="Boolean" mandatory="false" since="3.0">
<description>
If supported on the given platform, the alert GUI will include some sort of animation indicating that loading of a feature is progressing. e.g. a spinning wheel or hourglass, etc.
</description>
</param>
- <param name="softButtons" type="SoftButton" minsize="0" maxsize="4" array="true" mandatory="false">
+ <param name="softButtons" type="SoftButton" minsize="0" maxsize="4" array="true" mandatory="false" since="2.0">
<description>
App defined SoftButtons.
If omitted on supported displays, the displayed alert shall not have any SoftButtons.
@@ -3628,7 +4455,7 @@
</function>
- <function name="Alert" functionID="AlertID" messagetype="response">
+ <function name="Alert" functionID="AlertID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
@@ -3654,7 +4481,7 @@
<description>Provides additional human readable info regarding the result.</description>
</param>
- <param name="tryAgainTime" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="false">
+ <param name="tryAgainTime" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="false" since="2.0">
<description>
Amount of time (in seconds) that an app must wait before resending an alert.
If provided, another system event or overlay currently has a higher priority than this alert.
@@ -3664,10 +4491,10 @@
</function>
- <function name="Show" functionID="ShowID" messagetype="request">
+ <function name="Show" functionID="ShowID" messagetype="request" since="1.0">
<description>Updates the persistent display. Supported fields depend on display capabilities.</description>
- <param name="mainField1" type="String" minlength="0" maxlength="500" mandatory="false">
+ <param name="mainField1" type="String" minlength="0" maxlength="500" mandatory="false" since="1.0">
<description>
The text that should be displayed in a single or upper display line.
If this text is not set, the text of mainField1 stays unchanged.
@@ -3675,7 +4502,7 @@
</description>
</param>
- <param name="mainField2" type="String" minlength="0" maxlength="500" mandatory="false">
+ <param name="mainField2" type="String" minlength="0" maxlength="500" mandatory="false" since="1.0">
<description>
The text that should be displayed on the second display line.
If this text is not set, the text of mainField2 stays unchanged.
@@ -3683,7 +4510,7 @@
</description>
</param>
- <param name="mainField3" type="String" minlength="0" maxlength="500" mandatory="false">
+ <param name="mainField3" type="String" minlength="0" maxlength="500" mandatory="false" since="2.0">
<description>
The text that should be displayed on the second "page" first display line.
If this text is not set, the text of mainField3 stays unchanged.
@@ -3691,7 +4518,7 @@
</description>
</param>
- <param name="mainField4" type="String" minlength="0" maxlength="500" mandatory="false">
+ <param name="mainField4" type="String" minlength="0" maxlength="500" mandatory="false" since="2.0">
<description>
The text that should be displayed on the second "page" second display line.
If this text is not set, the text of mainField4 stays unchanged.
@@ -3699,25 +4526,25 @@
</description>
</param>
- <param name="alignment" type="TextAlignment" mandatory="false">
+ <param name="alignment" type="TextAlignment" mandatory="false" since="1.0">
<description>
Specifies how mainField1 and mainField2 texts should be aligned on display.
If omitted, texts will be centered.
</description>
</param>
- <param name="statusBar" type="String" minlength="0" maxlength="500" mandatory="false">
+ <param name="statusBar" type="String" minlength="0" maxlength="500" mandatory="false" since="1.0">
<description>Requires investigation regarding the nav display capabilities. Potentially lower lowerStatusBar, upperStatusBar, titleBar, etc.</description>
</param>
- <param name="mediaClock" type="String" minlength="0" maxlength="500" mandatory="false">
+ <param name="mediaClock" type="String" minlength="0" maxlength="500" mandatory="false" since="1.0">
<description>
Text value for MediaClock field. Has to be properly formatted by Mobile App according to the module's capabilities.
If this text is set, any automatic media clock updates previously set with SetMediaClockTimer will be stopped.
</description>
</param>
- <param name="mediaTrack" type="String" minlength="0" maxlength="500" mandatory="false">
+ <param name="mediaTrack" type="String" minlength="0" maxlength="500" mandatory="false" since="1.0">
<description>
The text that should be displayed in the track field.
If this text is not set, the text of mediaTrack stays unchanged.
@@ -3725,43 +4552,42 @@
</description>
</param>
- <param name="graphic" type="Image" mandatory="false">
+ <param name="graphic" type="Image" mandatory="false" since="3.0">
<description>
Image struct determining whether static or dynamic image to display in app.
If omitted on supported displays, the displayed graphic shall not change.
</description>
</param>
- <param name="secondaryGraphic" type="Image" mandatory="false">
+ <param name="secondaryGraphic" type="Image" mandatory="false" since="3.0">
<description>
Image struct determining whether static or dynamic secondary image to display in app.
If omitted on supported displays, the displayed secondary graphic shall not change.
</description>
</param>
-
- <param name="softButtons" type="SoftButton" minsize="0" maxsize="8" array="true" mandatory="false">
+ <param name="softButtons" type="SoftButton" minsize="0" maxsize="8" array="true" mandatory="false" since="2.0">
<description>
App defined SoftButtons.
If omitted on supported displays, the currently displayed SoftButton values will not change.
</description>
</param>
- <param name="customPresets" type="String" maxlength="500" minsize="0" maxsize="10" array="true" mandatory="false">
+ <param name="customPresets" type="String" maxlength="500" minsize="0" maxsize="10" array="true" mandatory="false" since="3.0">
<description>
App labeled on-screen presets (i.e. on-screen media presets or dynamic search suggestions).
If omitted on supported displays, the presets will be shown as not defined.
</description>
</param>
- <param name="metadataTags" type="MetadataTags" mandatory="false">
+ <param name="metadataTags" type="MetadataTags" mandatory="false" since="4.5">
<description>App defined metadata information. See MetadataStruct. Uses mainField1, mainField2, mainField3, mainField4.
If omitted on supported displays, the currently set metadata tags will not change.
If any text field contains no tags or the none tag, the metadata tag for that textfield should be removed.</description>
</param>
</function>
- <function name="Show" functionID="ShowID" messagetype="response">
+ <function name="Show" functionID="ShowID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
@@ -3787,7 +4613,7 @@
</param>
</function>
- <function name="Speak" functionID="SpeakID" messagetype="request">
+ <function name="Speak" functionID="SpeakID" messagetype="request" since="1.0">
<description>Speaks a text.</description>
<param name="ttsChunks" type="TTSChunk" minsize="1" maxsize="100" array="true" mandatory="true">
@@ -3799,7 +4625,7 @@
</function>
- <function name="Speak" functionID="SpeakID" messagetype="response">
+ <function name="Speak" functionID="SpeakID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
@@ -3825,7 +4651,7 @@
</function>
- <function name="SetMediaClockTimer" functionID="SetMediaClockTimerID" messagetype="request">
+ <function name="SetMediaClockTimer" functionID="SetMediaClockTimerID" messagetype="request" since="1.0">
<description>Sets the initial media clock value and automatic update method.</description>
<param name="startTime" type="StartTime" mandatory="false">
@@ -3837,7 +4663,7 @@
</description>
</param>
- <param name="endTime" type="StartTime" mandatory="false">
+ <param name="endTime" type="StartTime" mandatory="false" since="3.0">
<description>
See StartTime.
endTime can be provided for "COUNTUP" and "COUNTDOWN"; to be used to calculate any visual progress bar (if not provided, this feature is ignored)
@@ -3853,9 +4679,15 @@
In case of pause, resume, or clear, the start time value is ignored and shall be left out. For resume, the time continues with the same value as it was when paused.
</description>
</param>
+
+ <param name="audioStreamingIndicator" type="AudioStreamingIndicator" mandatory="false" since="5.0">
+ <description>
+ Enumeration for the indicator icon on a play/pause button. see AudioStreamingIndicator.
+ </description>
+ </param>
</function>
- <function name="SetMediaClockTimer" functionID="SetMediaClockTimerID" messagetype="response">
+ <function name="SetMediaClockTimer" functionID="SetMediaClockTimerID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
</param>
@@ -3877,7 +4709,7 @@
</param>
</function>
- <function name="PerformAudioPassThru" functionID="PerformAudioPassThruID" messagetype="request">
+ <function name="PerformAudioPassThru" functionID="PerformAudioPassThruID" messagetype="request" since="2.0">
<description>Starts audio pass thru session </description>
<param name="initialPrompt" type="TTSChunk" minsize="1" maxsize="100" array="true" mandatory="false">
<description>
@@ -3913,7 +4745,7 @@
</param>
</function>
- <function name="PerformAudioPassThru" functionID="PerformAudioPassThruID" messagetype="response">
+ <function name="PerformAudioPassThru" functionID="PerformAudioPassThruID" messagetype="response" since="2.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
</param>
@@ -3938,11 +4770,11 @@
</param>
</function>
- <function name="EndAudioPassThru" functionID="EndAudioPassThruID" messagetype="request">
+ <function name="EndAudioPassThru" functionID="EndAudioPassThruID" messagetype="request" since="2.0">
<description>When this request is invoked, the audio capture stops.</description>
</function>
- <function name="EndAudioPassThru" functionID="EndAudioPassThruID" messagetype="response">
+ <function name="EndAudioPassThru" functionID="EndAudioPassThruID" messagetype="response" since="2.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
</param>
@@ -3964,7 +4796,7 @@
</param>
</function>
- <function name="SubscribeButton" functionID="SubscribeButtonID" messagetype="request">
+ <function name="SubscribeButton" functionID="SubscribeButtonID" messagetype="request" since="1.0">
<description>
Subscribes to built-in HMI buttons.
The application will be notified by the OnButtonEvent and OnButtonPress.
@@ -3976,7 +4808,7 @@
</param>
</function>
- <function name="SubscribeButton" functionID="SubscribeButtonID" messagetype="response">
+ <function name="SubscribeButton" functionID="SubscribeButtonID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
</param>
@@ -3999,7 +4831,7 @@
</param>
</function>
- <function name="UnsubscribeButton" functionID="UnsubscribeButtonID" messagetype="request">
+ <function name="UnsubscribeButton" functionID="UnsubscribeButtonID" messagetype="request" since="1.0">
<description>Unsubscribes from built-in HMI buttons.</description>
<param name="buttonName" type="ButtonName" mandatory="true">
@@ -4007,7 +4839,7 @@
</param>
</function>
- <function name="UnsubscribeButton" functionID="UnsubscribeButtonID" messagetype="response">
+ <function name="UnsubscribeButton" functionID="UnsubscribeButtonID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false, if failed </description>
</param>
@@ -4030,7 +4862,7 @@
</param>
</function>
- <function name="SubscribeVehicleData" functionID="SubscribeVehicleDataID" messagetype="request">
+ <function name="SubscribeVehicleData" functionID="SubscribeVehicleDataID" messagetype="request" since="2.0">
<description>
Subscribes for specific published data items.
The data will be only sent if it has changed.
@@ -4056,9 +4888,15 @@
<param name="instantFuelConsumption" type="Boolean" mandatory="false">
<description>The instantaneous fuel consumption in microlitres</description>
</param>
+ <param name="fuelRange" type="Boolean" mandatory="false" since="5.0">
+ <description>The estimate range in KM the vehicle can travel based on fuel level and consumption</description>
+ </param>
<param name="externalTemperature" type="Boolean" mandatory="false">
<description>The external temperature in degrees celsius</description>
</param>
+ <param name="turnSignal" type="Boolean" mandatory="false" since="5.0">
+ <description>See TurnSignal</description>
+ </param>
<param name="prndl" type="Boolean" mandatory="false">
<description>See PRNDL</description>
</param>
@@ -4095,6 +4933,12 @@
<param name="steeringWheelAngle" type="Boolean" mandatory="false">
<description>Current angle of the steering wheel (in deg)</description>
</param>
+ <param name="engineOilLife" type="Boolean" mandatory="false" since="5.0">
+ <description>The estimated percentage of remaining oil life of the engine.</description>
+ </param>
+ <param name="electronicParkBrakeStatus" type="Boolean" mandatory="false" since="5.0">
+ <description>The status of the park brake as provided by Electric Park Brake (EPB) system.</description>
+ </param>
<!-- Ford Specific Data Items -->
<param name="eCallInfo" type="Boolean" mandatory="false">
@@ -4117,7 +4961,7 @@
</function>
- <function name="SubscribeVehicleData" functionID="SubscribeVehicleDataID" messagetype="response">
+ <function name="SubscribeVehicleData" functionID="SubscribeVehicleDataID" messagetype="response" since="2.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
</param>
@@ -4159,9 +5003,15 @@
<param name="instantFuelConsumption" type="VehicleDataResult" mandatory="false">
<description>The instantaneous fuel consumption in microlitres</description>
</param>
+ <param name="fuelRange" type="VehicleDataResult" mandatory="false" since="5.0">
+ <description>The estimate range in KM the vehicle can travel based on fuel level and consumption</description>
+ </param>
<param name="externalTemperature" type="VehicleDataResult" mandatory="false">
<description>The external temperature in degrees celsius.</description>
</param>
+ <param name="turnSignal" type="VehicleDataResult" mandatory="false" since="5.0">
+ <description>See TurnSignal</description>
+ </param>
<param name="prndl" type="VehicleDataResult" mandatory="false">
<description>See PRNDL</description>
</param>
@@ -4198,6 +5048,12 @@
<param name="steeringWheelAngle" type="VehicleDataResult" mandatory="false">
<description>Current angle of the steering wheel (in deg)</description>
</param>
+ <param name="engineOilLife" type="VehicleDataResult" mandatory="false" since="5.0">
+ <description>The estimated percentage of remaining oil life of the engine.</description>
+ </param>
+ <param name="electronicParkBrakeStatus" type="VehicleDataResult" mandatory="false" since="5.0">
+ <description>The status of the park brake as provided by Electric Park Brake (EPB) system.</description>
+ </param>
<!-- Ford Specific Data Items -->
<param name="eCallInfo" type="VehicleDataResult" mandatory="false">
@@ -4219,7 +5075,7 @@
</function>
- <function name="UnsubscribeVehicleData" functionID="UnsubscribeVehicleDataID" messagetype="request">
+ <function name="UnsubscribeVehicleData" functionID="UnsubscribeVehicleDataID" messagetype="request" since="2.0">
<description>This function is used to unsubscribe the notifications from the subscribeVehicleData function.</description>
<param name="gps" type="Boolean" mandatory="false">
@@ -4240,9 +5096,15 @@
<param name="instantFuelConsumption" type="Boolean" mandatory="false">
<description>The instantaneous fuel consumption in microlitres</description>
</param>
+ <param name="fuelRange" type="Boolean" mandatory="false" since="5.0">
+ <description>The estimate range in KM the vehicle can travel based on fuel level and consumption</description>
+ </param>
<param name="externalTemperature" type="Boolean" mandatory="false">
<description>The external temperature in degrees celsius.</description>
</param>
+ <param name="turnSignal" type="Boolean" mandatory="false" since="5.0">
+ <description>See TurnSignal</description>
+ </param>
<param name="prndl" type="Boolean" mandatory="false">
<description>See PRNDL</description>
</param>
@@ -4279,6 +5141,12 @@
<param name="steeringWheelAngle" type="Boolean" mandatory="false">
<description>Current angle of the steering wheel (in deg)</description>
</param>
+ <param name="engineOilLife" type="Boolean" mandatory="false" since="5.0">
+ <description>The estimated percentage of remaining oil life of the engine.</description>
+ </param>
+ <param name="electronicParkBrakeStatus" type="Boolean" mandatory="false" since="5.0">
+ <description>The status of the park brake as provided by Electric Park Brake (EPB) system.</description>
+ </param>
<!-- Ford Specific Data Items -->
<param name="eCallInfo" type="Boolean" mandatory="false">
@@ -4300,7 +5168,7 @@
</function>
- <function name="UnsubscribeVehicleData" functionID="UnsubscribeVehicleDataID" messagetype="response">
+ <function name="UnsubscribeVehicleData" functionID="UnsubscribeVehicleDataID" messagetype="response" since="2.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
</param>
@@ -4341,9 +5209,15 @@
<param name="instantFuelConsumption" type="VehicleDataResult" mandatory="false">
<description>The instantaneous fuel consumption in microlitres</description>
</param>
+ <param name="fuelRange" type="VehicleDataResult" mandatory="false" since="5.0">
+ <description>The estimate range in KM the vehicle can travel based on fuel level and consumption</description>
+ </param>
<param name="externalTemperature" type="VehicleDataResult" mandatory="false">
<description>The external temperature in degrees celsius</description>
</param>
+ <param name="turnSignal" type="VehicleDataResult" mandatory="false" since="5.0">
+ <description>See TurnSignal</description>
+ </param>
<param name="prndl" type="VehicleDataResult" mandatory="false">
<description>See PRNDL</description>
</param>
@@ -4380,6 +5254,12 @@
<param name="steeringWheelAngle" type="VehicleDataResult" mandatory="false">
<description>Current angle of the steering wheel (in deg)</description>
</param>
+ <param name="engineOilLife" type="VehicleDataResult" mandatory="false" since="5.0">
+ <description>The estimated percentage of remaining oil life of the engine.</description>
+ </param>
+ <param name="electronicParkBrakeStatus" type="VehicleDataResult" mandatory="false" since="5.0">
+ <description>The status of the park brake as provided by Electric Park Brake (EPB) system.</description>
+ </param>
<!-- Ford Specific Data Items -->
<param name="eCallInfo" type="VehicleDataResult" mandatory="false">
@@ -4401,7 +5281,7 @@
</function>
- <function name="GetVehicleData" functionID="GetVehicleDataID" messagetype="request">
+ <function name="GetVehicleData" functionID="GetVehicleDataID" messagetype="request" since="2.0">
<description>Non periodic vehicle data read request.</description>
<param name="gps" type="Boolean" mandatory="false">
@@ -4422,9 +5302,15 @@
<param name="instantFuelConsumption" type="Boolean" mandatory="false">
<description>The instantaneous fuel consumption in microlitres</description>
</param>
+ <param name="fuelRange" type="Boolean" mandatory="false" since="5.0">
+ <description>The estimate range in KM the vehicle can travel based on fuel level and consumption</description>
+ </param>
<param name="externalTemperature" type="Boolean" mandatory="false">
<description>The external temperature in degrees celsius</description>
</param>
+ <param name="turnSignal" type="Boolean" mandatory="false" since="5.0">
+ <description>See TurnSignal</description>
+ </param>
<param name="vin" type="Boolean" mandatory="false">
<description>Vehicle identification number</description>
</param>
@@ -4464,6 +5350,12 @@
<param name="steeringWheelAngle" type="Boolean" mandatory="false">
<description>Current angle of the steering wheel (in deg)</description>
</param>
+ <param name="engineOilLife" type="Boolean" mandatory="false" since="5.0">
+ <description>The estimated percentage of remaining oil life of the engine.</description>
+ </param>
+ <param name="electronicParkBrakeStatus" type="Boolean" mandatory="false" since="5.0">
+ <description>The status of the park brake as provided by Electric Park Brake (EPB) system.</description>
+ </param>
<!-- Ford Specific Data Items -->
<param name="eCallInfo" type="Boolean" mandatory="false">
@@ -4485,7 +5377,7 @@
</function>
- <function name="GetVehicleData" functionID="GetVehicleDataID" messagetype="response">
+ <function name="GetVehicleData" functionID="GetVehicleDataID" messagetype="response" since="2.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
@@ -4527,9 +5419,15 @@
<param name="instantFuelConsumption" type="Float" minvalue="0" maxvalue="25575" mandatory="false">
<description>The instantaneous fuel consumption in microlitres</description>
</param>
+ <param name="fuelRange" type="FuelRange" minsize="0" maxsize="100" array="true" mandatory="false" since="5.0">
+ <description>The estimate range in KM the vehicle can travel based on fuel level and consumption</description>
+ </param>
<param name="externalTemperature" type="Float" minvalue="-40" maxvalue="100" mandatory="false">
<description>The external temperature in degrees celsius</description>
</param>
+ <param name="turnSignal" type="TurnSignal" mandatory="false" since="5.0">
+ <description>See TurnSignal</description>
+ </param>
<param name="vin" type="String" maxlength="17" mandatory="false">
<description>Vehicle identification number</description>
</param>
@@ -4569,6 +5467,12 @@
<param name="steeringWheelAngle" type="Float" minvalue="-2000" maxvalue="2000" mandatory="false">
<description>Current angle of the steering wheel (in deg)</description>
</param>
+ <param name="engineOilLife" type="Float" minvalue="0" maxvalue="100" mandatory="false" since="5.0">
+ <description>The estimated percentage of remaining oil life of the engine.</description>
+ </param>
+ <param name="electronicParkBrakeStatus" type="ElectronicParkBrakeStatus" mandatory="false" since="5.0">
+ <description>The status of the park brake as provided by Electric Park Brake (EPB) system.</description>
+ </param>
<!-- Ford Specific Data Items -->
<param name="eCallInfo" type="ECallInfo" mandatory="false">
@@ -4590,7 +5494,7 @@
</function>
- <function name="ReadDID" functionID="ReadDIDID" messagetype="request">
+ <function name="ReadDID" functionID="ReadDIDID" messagetype="request" since="2.0">
<description>Non periodic vehicle data read request</description>
<param name="ecuName" type="Integer" minvalue="0" maxvalue="65535" mandatory="true">
@@ -4601,7 +5505,7 @@
</param>
</function>
- <function name="ReadDID" functionID="ReadDIDID" messagetype="response">
+ <function name="ReadDID" functionID="ReadDIDID" messagetype="response" since="2.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
@@ -4631,7 +5535,7 @@
</function>
- <function name="GetDTCs" functionID="GetDTCsID" messagetype="request">
+ <function name="GetDTCs" functionID="GetDTCsID" messagetype="request" since="2.0">
<description>Vehicle module diagnostic trouble code request.</description>
<param name="ecuName" type="Integer" minvalue="0" maxvalue="65535" mandatory="true">
@@ -4644,7 +5548,7 @@
</function>
- <function name="GetDTCs" functionID="GetDTCsID" messagetype="response">
+ <function name="GetDTCs" functionID="GetDTCsID" messagetype="response" since="2.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
@@ -4681,7 +5585,7 @@
</function>
- <function name="DiagnosticMessage" functionID="DiagnosticMessageID" messagetype="request">
+ <function name="DiagnosticMessage" functionID="DiagnosticMessageID" messagetype="request" since="3.0">
<description>Non periodic vehicle diagnostic request</description>
<param name="targetID" type="Integer" minvalue="0" maxvalue="65535" mandatory="true">
@@ -4699,7 +5603,7 @@
</param>
</function>
- <function name="DiagnosticMessage" functionID="DiagnosticMessageID" messagetype="response">
+ <function name="DiagnosticMessage" functionID="DiagnosticMessageID" messagetype="response" since="3.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
@@ -4731,7 +5635,7 @@
</function>
- <function name="ScrollableMessage" functionID="ScrollableMessageID" messagetype="request">
+ <function name="ScrollableMessage" functionID="ScrollableMessageID" messagetype="request" since="2.0">
<description>Creates a full screen overlay containing a large block of formatted text that can be scrolled with up to 8 SoftButtons defined</description>
<param name="scrollableMessageBody" type="String" maxlength="500" mandatory="true">
<description>Body of text that can include newlines and tabs.</description>
@@ -4747,7 +5651,7 @@
</param>
</function>
- <function name="ScrollableMessage" functionID="ScrollableMessageID" messagetype="response">
+ <function name="ScrollableMessage" functionID="ScrollableMessageID" messagetype="response" since="2.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
</param>
@@ -4773,7 +5677,7 @@
</function>
- <function name="Slider" functionID="SliderID" messagetype="request">
+ <function name="Slider" functionID="SliderID" messagetype="request" since="2.0">
<description>Creates a full screen or pop-up overlay (depending on platform) with a single user controlled slider.</description>
<param name="numTicks" type="Integer" minvalue="2" maxvalue="26" mandatory="true">
<description>Number of selectable items on a horizontal axis</description>
@@ -4801,7 +5705,7 @@
</param>
</function>
- <function name="Slider" functionID="SliderID" messagetype="response">
+ <function name="Slider" functionID="SliderID" messagetype="response" since="2.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
</param>
@@ -4834,40 +5738,40 @@
</param>
</function>
- <function name="ShowConstantTBT" functionID="ShowConstantTBTID" messagetype="request">
- <param name="navigationText1" type="String" minlength="0" maxlength="500" mandatory="false">
+ <function name="ShowConstantTBT" functionID="ShowConstantTBTID" messagetype="request" since="2.0">
+ <param name="navigationText1" type="String" minlength="0" maxlength="500" mandatory="false" since="2.0">
</param>
- <param name="navigationText2" type="String" minlength="0" maxlength="500" mandatory="false">
+ <param name="navigationText2" type="String" minlength="0" maxlength="500" mandatory="false" since="2.0">
</param>
- <param name="eta" type="String" minlength="0" maxlength="500" mandatory="false">
+ <param name="eta" type="String" minlength="0" maxlength="500" mandatory="false" since="2.0">
</param>
- <param name="timeToDestination" type="String" minlength="0" maxlength="500" mandatory="false">
+ <param name="timeToDestination" type="String" minlength="0" maxlength="500" mandatory="false" since="3.0">
</param>
- <param name="totalDistance" type="String" minlength="0" maxlength="500" mandatory="false">
+ <param name="totalDistance" type="String" minlength="0" maxlength="500" mandatory="false" since="2.0">
</param>
- <param name="turnIcon" type="Image" mandatory="false">
+ <param name="turnIcon" type="Image" mandatory="false" since="2.0">
</param>
- <param name="nextTurnIcon" type="Image" mandatory="false">
+ <param name="nextTurnIcon" type="Image" mandatory="false" since="3.0">
</param>
- <param name="distanceToManeuver" type="Float" minvalue="0" maxvalue="1000000000" mandatory="false">
+ <param name="distanceToManeuver" type="Float" minvalue="0" maxvalue="1000000000" mandatory="false" since="2.0">
<description>
Fraction of distance till next maneuver (starting from when AlertManeuver is triggered).
Used to calculate progress bar.
</description>
</param>
- <param name="distanceToManeuverScale" type="Float" minvalue="0" maxvalue="1000000000" mandatory="false">
+ <param name="distanceToManeuverScale" type="Float" minvalue="0" maxvalue="1000000000" mandatory="false" since="2.0">
<description>
Distance till next maneuver (starting from) from previous maneuver.
Used to calculate progress bar.
</description>
</param>
- <param name="maneuverComplete" type="Boolean" mandatory="false">
+ <param name="maneuverComplete" type="Boolean" mandatory="false" since="2.0">
<description>
If and when a maneuver has completed while an AlertManeuver is active, the app must send this value set to TRUE in order to clear the AlertManeuver overlay.
If omitted the value will be assumed as FALSE.
</description>
</param>
- <param name="softButtons" type="SoftButton" minsize="0" maxsize="3" array="true" mandatory="false">
+ <param name="softButtons" type="SoftButton" minsize="0" maxsize="3" array="true" mandatory="false" since="2.0">
<description>
Three dynamic SoftButtons available (first SoftButton is fixed to "Turns").
If omitted on supported displays, the currently displayed SoftButton values will not change.
@@ -4875,7 +5779,7 @@
</param>
</function>
- <function name="ShowConstantTBT" functionID="ShowConstantTBTID" messagetype="response">
+ <function name="ShowConstantTBT" functionID="ShowConstantTBTID" messagetype="response" since="2.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
</param>
@@ -4897,7 +5801,7 @@
</param>
</function>
- <function name="AlertManeuver" functionID="AlertManeuverID" messagetype="request">
+ <function name="AlertManeuver" functionID="AlertManeuverID" messagetype="request" since="2.0">
<param name="ttsChunks" type="TTSChunk" minsize="1" maxsize="100" array="true" mandatory="false">
<description>An array of text chunks of type TTSChunk. See TTSChunk</description>
</param>
@@ -4906,7 +5810,7 @@
</param>
</function>
- <function name="AlertManeuver" functionID="AlertManeuverID" messagetype="response">
+ <function name="AlertManeuver" functionID="AlertManeuverID" messagetype="response" since="2.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
</param>
@@ -4931,7 +5835,7 @@
</param>
</function>
- <function name="UpdateTurnList" functionID="UpdateTurnListID" messagetype="request">
+ <function name="UpdateTurnList" functionID="UpdateTurnListID" messagetype="request" since="2.0">
<param name="turnList" type="Turn" minsize="1" maxsize="100" array="true" mandatory="false">
</param>
<param name="softButtons" type="SoftButton" minsize="0" maxsize="1" array="true" mandatory="false">
@@ -4939,7 +5843,7 @@
</param>
</function>
- <function name="UpdateTurnList" functionID="UpdateTurnListID" messagetype="response">
+ <function name="UpdateTurnList" functionID="UpdateTurnListID" messagetype="response" since="2.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
</param>
@@ -4961,32 +5865,29 @@
</param>
</function>
- <function name="ChangeRegistration" functionID="ChangeRegistrationID" messagetype="request">
+ <function name="ChangeRegistration" functionID="ChangeRegistrationID" messagetype="request" since="2.0">
<param name="language" type="Language" mandatory="true">
<description>Requested voice engine (VR+TTS) language registration</description>
</param>
<param name="hmiDisplayLanguage" type="Language" mandatory="true">
<description>Request display language registration</description>
</param>
- <param name="appName" type="String" maxlength="100" mandatory="false">
+ <param name="appName" type="String" maxlength="100" mandatory="false" since="3.0">
<description>Request new app name registration</description>
</param>
- <param name="ttsName" type="TTSChunk" minsize="1" maxsize="100" array="true" mandatory="false" >
+ <param name="ttsName" type="TTSChunk" minsize="1" maxsize="100" array="true" mandatory="false" since="3.0">
<description>Request new ttsName registration</description>
</param>
- <param name="ngnMediaScreenAppName" type="String" maxlength="100" mandatory="false">
+ <param name="ngnMediaScreenAppName" type="String" maxlength="100" mandatory="false" since="3.0">
<description>Request new app short name registration</description>
</param>
- <param name="vrSynonyms" type="String" maxlength="40" minsize="1" maxsize="100" array="true" mandatory="false">
+ <param name="vrSynonyms" type="String" maxlength="40" minsize="1" maxsize="100" array="true" mandatory="false" since="3.0">
<description>Request new VR synonyms registration</description>
</param>
</function>
-
-
- <function name="ChangeRegistration" functionID="ChangeRegistrationID" messagetype="response">
-
+ <function name="ChangeRegistration" functionID="ChangeRegistrationID" messagetype="response" since="2.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description>
true, if successful
@@ -5012,7 +5913,7 @@
</function>
- <function name="GenericResponse" functionID="GenericResponseID" messagetype="response">
+ <function name="GenericResponse" functionID="GenericResponseID" messagetype="response" since="1.0">
<description>
Generic Response is sent, when the name of a received msg cannot be retrieved. Only used in case of an error.
Currently, only resultCode INVALID_DATA is used.
@@ -5031,7 +5932,7 @@
</param>
</function>
- <function name="PutFile" functionID="PutFileID" messagetype="request">
+ <function name="PutFile" functionID="PutFileID" messagetype="request" since="3.0">
<description>
Used to push a binary data onto the module from a mobile device, such as icons and album art
Not supported on first generation of SDL enabled modules.
@@ -5073,9 +5974,12 @@
If offset is set to 0, then length is the total length of the file to be downloaded
</description>
</param>
+ <param name="crc" type="Integer" minvalue="0" maxvalue="4294967295" mandatory="false" since="5.0">
+ <description> Additional CRC32 checksum to protect data integrity up to 512 Mbits </description>
+ </param>
</function>
- <function name="PutFile" functionID="PutFileID" messagetype="response">
+ <function name="PutFile" functionID="PutFileID" messagetype="response" since="3.0">
<description>Response is sent, when the file data was copied (success case). Or when an error occurred.</description>
<description>Not supported on first generation SDL enabled vehicles. </description>
<param name="success" type="Boolean" platform="documentation" mandatory="true">
@@ -5092,13 +5996,17 @@
<element name="GENERIC_ERROR"/>
<element name="REJECTED"/>
<element name="UNSUPPORTED_REQUEST"/>
+ <element name="CORRUPTED_DATA"/>
</param>
- <param name="spaceAvailable" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="true">
+ <param name="spaceAvailable" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="false" since="5.0">
<description>
Provides the total local space available in SDL Core for the registered app.
If the transfer has systemFile enabled, then the value will be set to 0 automatically.
</description>
+ <history>
+ <param name="spaceAvailable" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="true" since="3.0" until="5.0"/>
+ </history>
</param>
<param name="info" type="String" maxlength="1000" mandatory="false" platform="documentation">
@@ -5106,7 +6014,7 @@
</param>
</function>
- <function name="DeleteFile" functionID="DeleteFileID" messagetype="request">
+ <function name="DeleteFile" functionID="DeleteFileID" messagetype="request" since="3.0">
<description>
Used to delete a file resident on the module in the app's local cache.
Not supported on first generation SDL enabled vehicles.
@@ -5118,7 +6026,7 @@
</function>
- <function name="DeleteFile" functionID="DeleteFileID" messagetype="response">
+ <function name="DeleteFile" functionID="DeleteFileID" messagetype="response" since="3.0">
<description>
Response is sent, when the file data was deleted (success case). Or when an error occurred.
Not supported on First generation SDL enabled vehicles.
@@ -5139,8 +6047,11 @@
<element name="UNSUPPORTED_REQUEST"/>
</param>
- <param name="spaceAvailable" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="true">
+ <param name="spaceAvailable" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="false" since="5.0">
<description>Provides the total local space available on the module for the registered app.</description>
+ <history>
+ <param name="spaceAvailable" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="true" since="3.0" until="5.0"/>
+ </history>
</param>
<param name="info" type="String" maxlength="1000" mandatory="false" platform="documentation">
@@ -5148,14 +6059,14 @@
</param>
</function>
- <function name="ListFiles" functionID="ListFilesID" messagetype="request">
+ <function name="ListFiles" functionID="ListFilesID" messagetype="request" since="3.0">
<description>
Requests the current list of resident filenames for the registered app.
Not supported on first generation SDL enabled vehicles.
</description>
</function>
- <function name="ListFiles" functionID="ListFilesID" messagetype="response">
+ <function name="ListFiles" functionID="ListFilesID" messagetype="response" since="3.0">
<description>
Returns the current list of resident filenames for the registered app along with the current space available
Not supported on First generation SDL enabled vehicles.
@@ -5183,8 +6094,11 @@
</description>
</param>
- <param name="spaceAvailable" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="true">
+ <param name="spaceAvailable" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="false" since="5.0">
<description>Provides the total local space available on the module for the registered app.</description>
+ <history>
+ <param name="spaceAvailable" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="true" since="3.0" until="5.0"/>
+ </history>
</param>
<param name="info" type="String" maxlength="1000" mandatory="false" platform="documentation">
@@ -5192,7 +6106,7 @@
</param>
</function>
- <function name="SetAppIcon" functionID="SetAppIconID" messagetype="request">
+ <function name="SetAppIcon" functionID="SetAppIconID" messagetype="request" since="3.0">
<description>
Used to set existing local file on the module as the app's icon
Not supported on first generation SDL enabled vehicles.
@@ -5204,7 +6118,7 @@
</function>
- <function name="SetAppIcon" functionID="SetAppIconID" messagetype="response">
+ <function name="SetAppIcon" functionID="SetAppIconID" messagetype="response" since="3.0">
<description>
Response is sent, when the file data was copied (success case). Or when an error occurred.
Not supported on First generation SDL enabled vehicles.
@@ -5232,7 +6146,7 @@
</function>
- <function name="SetDisplayLayout" functionID="SetDisplayLayoutID" messagetype="request">
+ <function name="SetDisplayLayout" functionID="SetDisplayLayoutID" messagetype="request" since="3.0">
<description>
Used to set an alternate display layout.
If not sent, default screen for given platform will be shown
@@ -5245,9 +6159,12 @@
</description>
</param>
+ <param name="dayColorScheme" type="TemplateColorScheme" mandatory="false" since="5.0"/>
+
+ <param name="nightColorScheme" type="TemplateColorScheme" mandatory="false" since="5.0"/>
</function>
- <function name="SetDisplayLayout" functionID="SetDisplayLayoutID" messagetype="response">
+ <function name="SetDisplayLayout" functionID="SetDisplayLayoutID" messagetype="response" since="3.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
@@ -5274,11 +6191,11 @@
</param>
<param name="softButtonCapabilities" type="SoftButtonCapabilities" minsize="1" maxsize="100" array="true" mandatory="false">
- <description>If returned, the platform supports on-screen SoftButtons; see SoftButtonCapabilities.</description >
+ <description>If returned, the platform supports on-screen SoftButtons; see SoftButtonCapabilities.</description>
</param>
<param name="presetBankCapabilities" type="PresetBankCapabilities" mandatory="false">
- <description>If returned, the platform supports custom on-screen Presets; see PresetBankCapabilities.</description >
+ <description>If returned, the platform supports custom on-screen Presets; see PresetBankCapabilities.</description>
</param>
<param name="info" type="String" maxlength="1000" mandatory="false" platform="documentation">
@@ -5287,7 +6204,7 @@
</function>
- <function name="SystemRequest" functionID="SystemRequestID" messagetype="request" >
+ <function name="SystemRequest" functionID="SystemRequestID" messagetype="request" since="3.0">
<description>An asynchronous request from the device; binary data can be included in hybrid part of message for some requests (such as HTTP, Proprietary, or Authentication requests)</description>
<param name="requestType" type="RequestType" mandatory="true">
<description>
@@ -5295,6 +6212,11 @@
Note that Proprietary requests should forward the binary data to the known proprietary module on the system.
</description>
</param>
+ <param name="requestSubType" type="String" maxlength="255" mandatory="false" since="5.0">
+ <description>
+ This parameter is filled for supporting OEM proprietary data exchanges.
+ </description>
+ </param>
<param name="fileName" type="String" maxlength="255" mandatory="false">
<description>
Filename of HTTP data to store in predefined system staging area.
@@ -5304,7 +6226,7 @@
</param>
</function>
- <function name="SystemRequest" functionID="SystemRequestID" messagetype="response" >
+ <function name="SystemRequest" functionID="SystemRequestID" messagetype="response" since="3.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
</param>
@@ -5330,7 +6252,7 @@
</param>
</function>
- <function name="SendLocation" functionID="SendLocationID" messagetype="request">
+ <function name="SendLocation" functionID="SendLocationID" messagetype="request" since="3.0">
<param name="longitudeDegrees" type="Float" minvalue="-180" maxvalue="180" mandatory="false">
</param>
<param name="latitudeDegrees" type="Float" minvalue="-90" maxvalue="90" mandatory="false">
@@ -5361,21 +6283,21 @@
</description>
</param>
- <param name="timeStamp" type="DateTime" mandatory="false">
+ <param name="timeStamp" type="DateTime" mandatory="false" since="4.1">
<description>
timestamp in ISO 8601 format
</description>
</param>
- <param name="address" type="OASISAddress" mandatory="false">
+ <param name="address" type="OASISAddress" mandatory="false" since="4.1">
<description>Address to be used for setting destination</description>
</param>
- <param name="deliveryMode" type="DeliveryMode" mandatory="false">
+ <param name="deliveryMode" type="DeliveryMode" mandatory="false" since="4.1">
<description>Defines the mode of prompt for user</description>
</param>
</function>
- <function name="SendLocation" functionID="SendLocationID" messagetype="response" >
+ <function name="SendLocation" functionID="SendLocationID" messagetype="response" since="3.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
</param>
@@ -5398,7 +6320,7 @@
</param>
</function>
- <function name="DialNumber" functionID="DialNumberID" messagetype="request">
+ <function name="DialNumber" functionID="DialNumberID" messagetype="request" since="3.0">
<description>Dials a phone number and switches to phone application.</description>
<param name="number" type="String" maxlength="40" mandatory="true">
@@ -5409,7 +6331,7 @@
</param>
</function>
- <function name="DialNumber" functionID="DialNumberID" messagetype="response">
+ <function name="DialNumber" functionID="DialNumberID" messagetype="response" since="3.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description>true, if successful</description>
<description>false, if failed</description>
@@ -5431,7 +6353,7 @@
</param>
</function>
- <function name="ButtonPress" functionID="ButtonPressID" messagetype="request">
+ <function name="ButtonPress" functionID="ButtonPressID" messagetype="request" since="4.5">
<param name="moduleType" type="ModuleType" mandatory="true">
<description>The module where the button should be pressed</description>
</param>
@@ -5443,7 +6365,7 @@
</param>
</function>
- <function name="ButtonPress" functionID="ButtonPressID" messagetype="response">
+ <function name="ButtonPress" functionID="ButtonPressID" messagetype="response" since="4.5">
<param name="resultCode" type="Result" platform="documentation" mandatory="true">
<description>See Result</description>
<element name="SUCCESS"/>
@@ -5464,22 +6386,26 @@
</param>
</function>
- <function name="GetInteriorVehicleData" functionID="GetInteriorVehicleDataID" messagetype="request">
+ <function name="GetInteriorVehicleData" functionID="GetInteriorVehicleDataID" messagetype="request" since="4.5">
<param name="moduleType" type="ModuleType" mandatory="true">
<description>
The type of a RC module to retrieve module data from the vehicle.
In the future, this should be the Identification of a module.
</description>
</param>
- <param name="subscribe" type="Boolean" mandatory="false" defvalue="false">
+ <param name="subscribe" type="Boolean" mandatory="false" since="4.5.1">
<description>
- If subscribe is true, the head unit will register onInteriorVehicleData notifications for the requested moduelType.
- If subscribe is false, the head unit will unregister onInteriorVehicleData notifications for the requested moduelType.
+ If subscribe is true, the head unit will register onInteriorVehicleData notifications for the requested moduleType.
+ If subscribe is false, the head unit will unregister onInteriorVehicleData notifications for the requested moduleType.
+ If subscribe is not included, the subscription status of the app for the requested moduleType will remain unchanged.
</description>
+ <history>
+ <param name="subscribe" type="Boolean" mandatory="false" defvalue="false" since="4.5" until="4.5.1"/>
+ </history>
</param>
</function>
- <function name="GetInteriorVehicleData" functionID="GetInteriorVehicleDataID" messagetype="response">
+ <function name="GetInteriorVehicleData" functionID="GetInteriorVehicleDataID" messagetype="response" since="4.5">
<param name="moduleData" type="ModuleData" mandatory="true">
</param>
<param name="resultCode" type="Result" platform="documentation" mandatory="true">
@@ -5510,13 +6436,13 @@
</param>
</function>
- <function name="SetInteriorVehicleData" functionID="SetInteriorVehicleDataID" messagetype="request">
+ <function name="SetInteriorVehicleData" functionID="SetInteriorVehicleDataID" messagetype="request" since="4.5">
<param name="moduleData" type="ModuleData" mandatory="true">
<description>The module data to set for the requested RC module.</description>
</param>
</function>
- <function name="SetInteriorVehicleData" functionID="SetInteriorVehicleDataID" messagetype="response">
+ <function name="SetInteriorVehicleData" functionID="SetInteriorVehicleDataID" messagetype="response" since="4.5">
<description>Used to set the values of one remote control module </description>
<param name="moduleData" type="ModuleData" mandatory="true">
</param>
@@ -5543,11 +6469,11 @@
</param>
</function>
- <function name="SubscribeWayPoints" functionID="SubscribeWayPointsID" messagetype="request">
+ <function name="SubscribeWayPoints" functionID="SubscribeWayPointsID" messagetype="request" since="4.1">
<description>To subscribe in getting changes for Waypoints/destinations</description>
</function>
- <function name="SubscribeWayPoints" functionID="SubscribeWayPointsID" messagetype="response">
+ <function name="SubscribeWayPoints" functionID="SubscribeWayPointsID" messagetype="response" since="4.1">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
</param>
@@ -5566,14 +6492,14 @@
</param>
</function>
- <function name="GetWayPoints" functionID="GetWayPointsID" messagetype="request">
+ <function name="GetWayPoints" functionID="GetWayPointsID" messagetype="request" since="4.1">
<description>Request for getting waypoint/destination data.</description>
<param name="wayPointType" type="WayPointType" mandatory="true">
<description>To request for either the destination only or for all waypoints including destination</description>
</param>
</function>
- <function name="GetWayPoints" functionID="GetWayPointsID" messagetype="response">
+ <function name="GetWayPoints" functionID="GetWayPointsID" messagetype="response" since="4.1">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
</param>
@@ -5597,11 +6523,11 @@
</param>
</function>
- <function name="UnsubscribeWayPoints" functionID="UnsubscribeWayPointsID" messagetype="request">
+ <function name="UnsubscribeWayPoints" functionID="UnsubscribeWayPointsID" messagetype="request" since="4.1">
<description>Request to unsubscribe from WayPoints and Destination</description>
</function>
- <function name="UnsubscribeWayPoints" functionID="UnsubscribeWayPointsID" messagetype="response">
+ <function name="UnsubscribeWayPoints" functionID="UnsubscribeWayPointsID" messagetype="response" since="4.1">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
</param>
@@ -5623,14 +6549,14 @@
</param>
</function>
- <function name="GetSystemCapability" functionID="GetSystemCapabilityID" messagetype="request">
+ <function name="GetSystemCapability" functionID="GetSystemCapabilityID" messagetype="request" since="4.5">
<description>Request for expanded information about a supported system/HMI capability</description>
<param name="systemCapabilityType" type="SystemCapabilityType" mandatory="true">
<description>The type of system capability to get more information on</description>
</param>
</function>
- <function name="GetSystemCapability" functionID="GetSystemCapabilityID" messagetype="response">
+ <function name="GetSystemCapability" functionID="GetSystemCapabilityID" messagetype="response" since="4.5">
<param name="systemCapability" type="SystemCapability" mandatory="true">
</param>
<param name="resultCode" type="Result" platform="documentation" mandatory="true">
@@ -5660,14 +6586,14 @@
</param>
</function>
- <function name="SendHapticData" functionID="SendHapticDataID" messagetype="request">
+ <function name="SendHapticData" functionID="SendHapticDataID" messagetype="request" since="4.5">
<description>Send the spatial data gathered from SDLCarWindow or VirtualDisplayEncoder to the HMI. This data will be utilized by the HMI to determine how and when haptic events should occur</description>
<param name="hapticRectData" type="HapticRect" minsize="0" maxsize="1000" mandatory="false" array="true">
<description>Array of spatial data structures that represent the locations of all user controls present on the HMI. This data should be updated if/when the application presents a new screen. When a request is sent, if successful, it will replace all spatial data previously sent through RPC. If an empty array is sent, the existing spatial data will be cleared</description>
</param>
</function>
- <function name="SendHapticData" functionID="SendHapticDataID" messagetype="response">
+ <function name="SendHapticData" functionID="SendHapticDataID" messagetype="response" since="4.5">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true if successful; false if failed </description>
</param>
@@ -5683,7 +6609,7 @@
<!-- Notifications -->
- <function name="OnHMIStatus" functionID="OnHMIStatusID" messagetype="notification">
+ <function name="OnHMIStatus" functionID="OnHMIStatusID" messagetype="notification" since="1.0">
<param name="hmiLevel" type="HMILevel" mandatory="true">
<description>See HMILevel</description>
</param>
@@ -5695,37 +6621,44 @@
<param name="systemContext" type="SystemContext" mandatory="true">
<description>See SystemContext</description>
</param>
+
+ <param name="videoStreamingState" type="VideoStreamingState" mandatory="false" defvalue="STREAMABLE" since="5.0">
+ <description>
+ See VideoStreamingState.
+ If it is NOT_STREAMABLE, the app must stop streaming video to SDL Core(stop service).
+ </description>
+ </param>
</function>
- <function name="OnAppInterfaceUnregistered" functionID="OnAppInterfaceUnregisteredID" messagetype="notification">
+ <function name="OnAppInterfaceUnregistered" functionID="OnAppInterfaceUnregisteredID" messagetype="notification" since="1.0">
<param name="reason" type="AppInterfaceUnregisteredReason" mandatory="true">
<description>See AppInterfaceUnregisteredReason</description>
</param>
</function>
- <function name="OnButtonEvent" functionID="OnButtonEventID" messagetype="notification">
+ <function name="OnButtonEvent" functionID="OnButtonEventID" messagetype="notification" since="1.0">
<description>Notifies application of UP/DOWN events for buttons to which the application is subscribed.</description>
<param name="buttonName" type="ButtonName" mandatory="true"/>
<param name="buttonEventMode" type="ButtonEventMode" mandatory="true">
<description>Indicates whether this is an UP or DOWN event.</description>
</param>
- <param name="customButtonID" type="Integer" minvalue="0" maxvalue="65536" mandatory="false">
+ <param name="customButtonID" type="Integer" minvalue="0" maxvalue="65536" mandatory="false" since="2.0">
<description>If ButtonName is "CUSTOM_BUTTON", this references the integer ID passed by a custom button. (e.g. softButton ID)</description>
</param>
</function>
- <function name="OnButtonPress" functionID="OnButtonPressID" messagetype="notification">
+ <function name="OnButtonPress" functionID="OnButtonPressID" messagetype="notification" since="1.0">
<description>Notifies application of LONG/SHORT press events for buttons to which the application is subscribed.</description>
<param name="buttonName" type="ButtonName" mandatory="true"/>
<param name="buttonPressMode" type="ButtonPressMode" mandatory="true">
<description>Indicates whether this is a LONG or SHORT button press event.</description>
</param>
- <param name="customButtonID" type="Integer" minvalue="0" maxvalue="65536" mandatory="false">
+ <param name="customButtonID" type="Integer" minvalue="0" maxvalue="65536" mandatory="false" since="2.0">
<description>If ButtonName is "CUSTOM_BUTTON", this references the integer ID passed by a custom button. (e.g. softButton ID)</description>
</param>
</function>
- <function name="OnVehicleData" functionID="OnVehicleDataID" messagetype="notification">
+ <function name="OnVehicleData" functionID="OnVehicleDataID" messagetype="notification" since="2.0">
<description>Callback for the periodic and non periodic vehicle data read function.</description>
<param name="gps" type="GPSData" mandatory="false">
<description>See GPSData</description>
@@ -5745,9 +6678,15 @@
<param name="instantFuelConsumption" type="Float" minvalue="0" maxvalue="25575" mandatory="false">
<description>The instantaneous fuel consumption in microlitres</description>
</param>
+ <param name="fuelRange" type="FuelRange" minsize="0" maxsize="100" array="true" mandatory="false" since="5.0">
+ <description>The estimate range in KM the vehicle can travel based on fuel level and consumption</description>
+ </param>
<param name="externalTemperature" type="Float" minvalue="-40" maxvalue="100" mandatory="false">
<description>The external temperature in degrees celsius</description>
</param>
+ <param name="turnSignal" type="TurnSignal" mandatory="false" since="5.0">
+ <description>See TurnSignal</description>
+ </param>
<param name="vin" type="String" maxlength="17" mandatory="false">
<description>Vehicle identification number.</description>
</param>
@@ -5787,6 +6726,12 @@
<param name="steeringWheelAngle" type="Float" minvalue="-2000" maxvalue="2000" mandatory="false">
<description>Current angle of the steering wheel (in deg)</description>
</param>
+ <param name="engineOilLife" type="Float" minvalue="0" maxvalue="100" mandatory="false" since="5.0">
+ <description>The estimated percentage of remaining oil life of the engine.</description>
+ </param>
+ <param name="electronicParkBrakeStatus" type="ElectronicParkBrakeStatus" mandatory="false" since="5.0">
+ <description>The status of the park brake as provided by Electric Park Brake (EPB) system.</description>
+ </param>
<!-- Ford Specific Vehicle Data -->
<param name="eCallInfo" type="ECallInfo" mandatory="false">
@@ -5808,7 +6753,7 @@
</function>
- <function name="OnCommand" functionID="OnCommandID" messagetype="notification">
+ <function name="OnCommand" functionID="OnCommandID" messagetype="notification" since="1.0">
<param name="cmdID" type="Integer" minvalue="0" maxvalue="2000000000" mandatory="true">
<description>Command ID, which is related to a specific menu entry</description>
</param>
@@ -5818,32 +6763,32 @@
</param>
</function>
- <function name="OnTBTClientState" functionID="OnTBTClientStateID" messagetype="notification" >
+ <function name="OnTBTClientState" functionID="OnTBTClientStateID" messagetype="notification" since="1.0">
<description>Provides applications with notifications specific to the current TBT client status on the module</description>
<param name="state" type="TBTState" mandatory="true">
<description>Current State of TBT client</description>
</param>
</function>
- <function name="OnDriverDistraction" functionID="OnDriverDistractionID" messagetype="notification" >
+ <function name="OnDriverDistraction" functionID="OnDriverDistractionID" messagetype="notification" since="1.0">
<description>Provides driver distraction state to mobile applications</description>
<param name="state" type="DriverDistractionState" mandatory="true">
<description>Current State of Driver Distraction</description>
</param>
</function>
- <function name="OnPermissionsChange" functionID="OnPermissionsChangeID" messagetype="notification" >
+ <function name="OnPermissionsChange" functionID="OnPermissionsChangeID" messagetype="notification" since="2.0">
<description>Provides update to app of which policy-table-enabled functions are available</description>
<param name="permissionItem" type="PermissionItem" minsize="0" maxsize="500" array="true" mandatory="true">
<description>Change in permissions for a given set of RPCs</description>
</param>
</function>
- <function name="OnAudioPassThru" functionID="OnAudioPassThruID" messagetype="notification">
+ <function name="OnAudioPassThru" functionID="OnAudioPassThruID" messagetype="notification" since="2.0">
<description>Binary data is in binary part of hybrid msg</description>
</function>
- <function name="OnLanguageChange" functionID="OnLanguageChangeID" messagetype="notification">
+ <function name="OnLanguageChange" functionID="OnLanguageChangeID" messagetype="notification" since="2.0">
<param name="language" type="Language" mandatory="true">
<description>Current SDL voice engine (VR+TTS) language</description>
</param>
@@ -5852,7 +6797,7 @@
</param>
</function>
- <function name="OnKeyboardInput" functionID="OnKeyboardInputID" messagetype="notification" >
+ <function name="OnKeyboardInput" functionID="OnKeyboardInputID" messagetype="notification" since="3.0">
<description>On-screen keyboard event.</description>
<description>Can be full string or individual keypresses depending on keyboard mode.</description>
@@ -5870,7 +6815,7 @@
</function>
- <function name="OnTouchEvent" functionID="OnTouchEventID" messagetype="notification" >
+ <function name="OnTouchEvent" functionID="OnTouchEventID" messagetype="notification" since="3.0">
<description>Notifies about touch events on the screen's prescribed area</description>
<param name="type" type="TouchType" mandatory="true">
<description>The type of touch event.</description>
@@ -5880,7 +6825,7 @@
</param>
</function>
- <function name="OnSystemRequest" functionID="OnSystemRequestID" messagetype="notification" >
+ <function name="OnSystemRequest" functionID="OnSystemRequestID" messagetype="notification" since="3.0">
<description>
An asynchronous request from the system for specific data from the device or the cloud or response to a request from the device or cloud
Binary data can be included in hybrid part of message for some requests (such as Authentication request responses)
@@ -5888,6 +6833,11 @@
<param name="requestType" type="RequestType" mandatory="true">
<description>The type of system request.</description>
</param>
+ <param name="requestSubType" type="String" maxlength="255" mandatory="false" since="5.0">
+ <description>
+ This parameter is filled for supporting OEM proprietary data exchanges.
+ </description>
+ </param>
<param name="url" type="String" maxlength="1000" mandatory="false">
<description>
Optional URL for HTTP requests.
@@ -5912,7 +6862,7 @@
</param>
</function>
- <function name="OnHashChange" functionID="OnHashChangeID" messagetype="notification">
+ <function name="OnHashChange" functionID="OnHashChangeID" messagetype="notification" since="3.0">
<description>
Notification containing an updated hashID which can be used over connection cycles (i.e. loss of connection, ignition cycles, etc.).
Sent after initial registration and subsequently after any change in the calculated hash of all persisted app data.
@@ -5922,23 +6872,36 @@
</param>
</function>
- <function name="OnWayPointChange" functionID="OnWayPointChangeID" messagetype="notification">
+ <function name="OnWayPointChange" functionID="OnWayPointChangeID" messagetype="notification" since="4.1">
<description>Notification which provides the entire LocationDetails when there is a change to any waypoints or destination.</description>
<param name="wayPoints" type="LocationDetails" mandatory="true" array="true" minsize="1" maxsize="10">
<description>See LocationDetails</description>
</param>
</function>
- <function name="OnInteriorVehicleData" functionID="OnInteriorVehicleDataID" messagetype="notification">
+ <function name="OnInteriorVehicleData" functionID="OnInteriorVehicleDataID" messagetype="notification" since="4.5">
<param name="moduleData" type="ModuleData" mandatory="true">
</param>
</function>
+ <function name="OnRCStatus" functionID="OnRCStatusID" messagetype="notification" since="5.0">
+ <description>Issued by SDL to notify the application about remote control status change on SDL</description>
+ <param name="allowed" type="Boolean" mandatory="false">
+ <description>If "true" - RC is allowed; if "false" - RC is disallowed.</description>
+ </param>
+ <param name="allocatedModules" type="ModuleData" minsize="0" maxsize="100" array="true" mandatory="true">
+ <description>Contains a list (zero or more) of module types that are allocated to the application.</description>
+ </param>
+ <param name="freeModules" type="ModuleData" minsize="0" maxsize="100" array="true" mandatory="true">
+ <description>Contains a list (zero or more) of module types that are free to access for the application.</description>
+ </param>
+ </function>
+
<!-- ~~~~~~~~~~~~~~~~~~ -->
<!-- Ford Specific APIs -->
<!-- ~~~~~~~~~~~~~~~~~~ -->
- <function name="EncodedSyncPData" functionID="EncodedSyncPDataID" messagetype="request" >
+ <function name="EncodedSyncPData" functionID="EncodedSyncPDataID" messagetype="request" since="1.0">
<description>
Allows encoded data in the form of SyncP packets to be sent to the SYNC module.
Legacy / v1 Protocol implementation; use SyncPData instead.
@@ -5951,7 +6914,7 @@
</param>
</function>
- <function name="EncodedSyncPData" functionID="EncodedSyncPDataID" messagetype="response" >
+ <function name="EncodedSyncPData" functionID="EncodedSyncPDataID" messagetype="response" since="1.0">
<param name="success" type="Boolean" platform="documentation" mandatory="true">
<description> true, if successful; false, if failed </description>
</param>
@@ -6002,7 +6965,7 @@
</function>
-->
- <function name="OnEncodedSyncPData" functionID="OnEncodedSyncPDataID" messagetype="notification" >
+ <function name="OnEncodedSyncPData" functionID="OnEncodedSyncPDataID" messagetype="notification" since="1.0">
<description>
Callback including encoded data of any SyncP packets that SYNC needs to send back to the mobile device.
Legacy / v1 Protocol implementation; responds to EncodedSyncPData.
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/AndroidTestCase2.java b/sdl_android/src/androidTest/java/com/smartdevicelink/AndroidTestCase2.java
new file mode 100644
index 000000000..1aafa19b6
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/AndroidTestCase2.java
@@ -0,0 +1,34 @@
+package com.smartdevicelink;
+
+import android.content.Context;
+import android.net.Uri;
+import android.support.test.InstrumentationRegistry;
+
+import junit.framework.TestCase;
+
+
+public class AndroidTestCase2 extends TestCase {
+
+ public Context mContext;
+
+ public AndroidTestCase2(){
+ mContext = InstrumentationRegistry.getTargetContext();
+ }
+
+ public Context getContext(){
+ return mContext;
+ }
+
+ public void setContext(Context context){}
+
+
+ public void assertActivityRequiresPermission(String packageName, String className, String permission){}
+ public void assertReadingContentUriRequiresPermission(Uri uri, String permission){}
+ public void assertWritingContentUriRequiresPermission(Uri uri, String permission){}
+
+
+ protected void scrubClass(Class<?> testCaseClass){}
+ protected void setUp() throws Exception{}
+ protected void tearDown() throws Exception{}
+
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/SdlConnection/SdlConnectionTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/SdlConnection/SdlConnectionTest.java
index 0b8e37ea0..776da6ccc 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/SdlConnection/SdlConnectionTest.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/SdlConnection/SdlConnectionTest.java
@@ -1,7 +1,6 @@
package com.smartdevicelink.SdlConnection;
-import android.test.AndroidTestCase;
-
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.test.SdlUnitTestContants;
import com.smartdevicelink.test.util.DeviceUtil;
import com.smartdevicelink.transport.BTTransportConfig;
@@ -11,7 +10,7 @@ import com.smartdevicelink.transport.RouterServiceValidator;
import com.smartdevicelink.transport.USBTransportConfig;
import com.smartdevicelink.transport.enums.TransportType;
-public class SdlConnectionTest extends AndroidTestCase {
+public class SdlConnectionTest extends AndroidTestCase2 {
private static final String TAG = "SdlConnection Tests";
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/SdlManagerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/SdlManagerTests.java
new file mode 100644
index 000000000..61626251b
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/SdlManagerTests.java
@@ -0,0 +1,392 @@
+package com.smartdevicelink.managers;
+
+import android.content.Context;
+
+import com.smartdevicelink.AndroidTestCase2;
+import com.smartdevicelink.exception.SdlException;
+import com.smartdevicelink.managers.lockscreen.LockScreenConfig;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCRequest;
+import com.smartdevicelink.proxy.RPCResponse;
+import com.smartdevicelink.proxy.SdlProxyBase;
+import com.smartdevicelink.proxy.rpc.GetVehicleData;
+import com.smartdevicelink.proxy.rpc.Show;
+import com.smartdevicelink.proxy.rpc.TemplateColorScheme;
+import com.smartdevicelink.proxy.rpc.enums.AppHMIType;
+import com.smartdevicelink.proxy.rpc.enums.Language;
+import com.smartdevicelink.proxy.rpc.enums.Result;
+import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener;
+import com.smartdevicelink.test.Test;
+import com.smartdevicelink.transport.BaseTransportConfig;
+import com.smartdevicelink.transport.TCPTransportConfig;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Vector;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library manager class :
+ * {@link com.smartdevicelink.managers.SdlManager}
+ */
+public class SdlManagerTests extends AndroidTestCase2 {
+
+ public static BaseTransportConfig transport = null;
+ private Context mTestContext;
+ private Vector<AppHMIType> appType;
+ private TemplateColorScheme templateColorScheme;
+ private int listenerCalledCounter;
+ private SdlManager sdlManager;
+ private SdlProxyBase sdlProxyBase;
+
+ // transport related
+ @SuppressWarnings("FieldCanBeLocal")
+ private int TCP_PORT = 12345;
+ @SuppressWarnings("FieldCanBeLocal")
+ private String DEV_MACHINE_IP_ADDRESS = "0.0.0.0";
+
+ @Override
+ public void setUp() throws Exception{
+ super.setUp();
+
+ // set transport
+ transport = new TCPTransportConfig(TCP_PORT, DEV_MACHINE_IP_ADDRESS, true);
+
+ // add AppTypes
+ appType = new Vector<>();
+ appType.add(AppHMIType.DEFAULT);
+
+ // Color Scheme
+ templateColorScheme = new TemplateColorScheme();
+ templateColorScheme.setBackgroundColor(Test.GENERAL_RGBCOLOR);
+ templateColorScheme.setPrimaryColor(Test.GENERAL_RGBCOLOR);
+ templateColorScheme.setSecondaryColor(Test.GENERAL_RGBCOLOR);
+
+ sdlManager = createSampleManager("heyApp", "123456", Test.GENERAL_LOCKSCREENCONFIG);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ // SETUP / HELPERS
+
+ private Context getTestContext() {
+ return mTestContext;
+ }
+
+ private SdlManager createSampleManager(String appName, String appId, LockScreenConfig lockScreenConfig){
+ SdlManager manager;
+
+ SdlManagerListener listener = new SdlManagerListener() {
+ @Override
+ public void onStart() {
+ listenerCalledCounter++;
+ }
+
+ @Override
+ public void onDestroy() {
+
+ }
+
+ @Override
+ public void onError(String info, Exception e) {
+
+ }
+ };
+
+ // build manager object - use all setters, will test using getters below
+ SdlManager.Builder builder = new SdlManager.Builder(getTestContext(),appId,appName,listener);
+ builder.setShortAppName(appName);
+ builder.setAppTypes(appType);
+ builder.setTransportType(transport);
+ builder.setLanguage(Language.EN_US);
+ builder.setDayColorScheme(templateColorScheme);
+ builder.setNightColorScheme(templateColorScheme);
+ builder.setVrSynonyms(Test.GENERAL_VECTOR_STRING);
+ builder.setTtsName(Test.GENERAL_VECTOR_TTS_CHUNKS);
+ builder.setLockScreenConfig(lockScreenConfig);
+ manager = builder.build();
+
+ // mock SdlProxyBase and set it manually
+ sdlProxyBase = mock(SdlProxyBase.class);
+ manager.setProxy(sdlProxyBase);
+
+ return manager;
+ }
+
+ // TESTS
+
+ public void testNotNull(){
+ assertNotNull(createSampleManager("app","123456", Test.GENERAL_LOCKSCREENCONFIG));
+ }
+
+ public void testMissingAppName() {
+ try {
+ createSampleManager(null,"123456", Test.GENERAL_LOCKSCREENCONFIG);
+ } catch (IllegalArgumentException ex) {
+ assertSame(ex.getMessage(), "You must specify an app name by calling setAppName");
+ }
+ }
+
+ public void testMissingAppId() {
+ try {
+ createSampleManager("app",null, Test.GENERAL_LOCKSCREENCONFIG);
+ } catch (IllegalArgumentException ex) {
+ assertSame(ex.getMessage(), "You must specify an app ID by calling setAppId");
+ }
+ }
+
+ public void testManagerSetters() {
+ assertEquals("123456", sdlManager.getAppId());
+ assertEquals("heyApp", sdlManager.getAppName());
+ assertEquals("heyApp", sdlManager.getShortAppName());
+ assertEquals(appType, sdlManager.getAppTypes());
+ assertEquals(Language.EN_US, sdlManager.getHmiLanguage());
+ assertEquals(transport, sdlManager.getTransport());
+ assertEquals(templateColorScheme, sdlManager.getDayColorScheme());
+ assertEquals(templateColorScheme, sdlManager.getNightColorScheme());
+ assertEquals(Test.GENERAL_VECTOR_STRING, sdlManager.getVrSynonyms());
+ assertEquals(Test.GENERAL_VECTOR_TTS_CHUNKS, sdlManager.getTtsChunks());
+ assertEquals(Test.GENERAL_LOCKSCREENCONFIG, sdlManager.getLockScreenConfig());
+ }
+
+ public void testStartingManager(){
+ listenerCalledCounter = 0;
+
+ sdlManager.start();
+
+ // Create and force all sub managers to be ready manually. Because SdlManager will not start until all sub managers are ready.
+ // Note: SdlManager.initialize() will not be called automatically by proxy as in real life because we have mock proxy not a real one
+ sdlManager.initialize();
+
+ // Set all sub managers' states to ready
+ sdlManager.getPermissionManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getFileManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getScreenManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getLockScreenManager().transitionToState(BaseSubManager.READY);
+
+ // Make sure the listener is called exactly once
+ assertEquals("Listener was not called or called more/less frequently than expected", listenerCalledCounter, 1);
+ }
+
+ public void testManagerStates() {
+ SdlManager sdlManager = createSampleManager("test", "00000", new LockScreenConfig());
+ sdlManager.initialize();
+
+
+ // Case 1-A:
+ sdlManager.getPermissionManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getFileManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getScreenManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getLockScreenConfig().setEnabled(true);
+ sdlManager.getLockScreenManager().transitionToState(BaseSubManager.READY);
+ sdlManager.checkState();
+ assertEquals(BaseSubManager.READY, sdlManager.getState());
+
+
+ // Case 1-B:
+ sdlManager.getPermissionManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getFileManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getScreenManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getLockScreenConfig().setEnabled(false);
+ sdlManager.getLockScreenManager().transitionToState(BaseSubManager.SETTING_UP);
+ sdlManager.checkState();
+ assertEquals(BaseSubManager.READY, sdlManager.getState());
+
+
+ // Case 2-A:
+ sdlManager.getPermissionManager().transitionToState(BaseSubManager.ERROR);
+ sdlManager.getFileManager().transitionToState(BaseSubManager.ERROR);
+ sdlManager.getScreenManager().transitionToState(BaseSubManager.ERROR);
+ sdlManager.getLockScreenConfig().setEnabled(true);
+ sdlManager.getLockScreenManager().transitionToState(BaseSubManager.ERROR);
+ sdlManager.checkState();
+ assertEquals(BaseSubManager.ERROR, sdlManager.getState());
+
+
+ // Case 1-B:
+ sdlManager.getPermissionManager().transitionToState(BaseSubManager.ERROR);
+ sdlManager.getFileManager().transitionToState(BaseSubManager.ERROR);
+ sdlManager.getScreenManager().transitionToState(BaseSubManager.ERROR);
+ sdlManager.getLockScreenConfig().setEnabled(false);
+ sdlManager.getLockScreenManager().transitionToState(BaseSubManager.SETTING_UP);
+ sdlManager.checkState();
+ assertEquals(BaseSubManager.ERROR, sdlManager.getState());
+
+
+ // Case 3-A:
+ sdlManager.getPermissionManager().transitionToState(BaseSubManager.ERROR);
+ sdlManager.getFileManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getScreenManager().transitionToState(BaseSubManager.SETTING_UP);
+ sdlManager.getLockScreenConfig().setEnabled(true);
+ sdlManager.getLockScreenManager().transitionToState(BaseSubManager.LIMITED);
+ sdlManager.checkState();
+ assertEquals(BaseSubManager.SETTING_UP, sdlManager.getState());
+
+
+ // Case 3-B:
+ sdlManager.getPermissionManager().transitionToState(BaseSubManager.ERROR);
+ sdlManager.getFileManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getScreenManager().transitionToState(BaseSubManager.SETTING_UP);
+ sdlManager.getLockScreenConfig().setEnabled(false);
+ sdlManager.getLockScreenManager().transitionToState(BaseSubManager.SETTING_UP);
+ sdlManager.checkState();
+ assertEquals(BaseSubManager.SETTING_UP, sdlManager.getState());
+
+
+ // Case 4-A:
+ sdlManager.getPermissionManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getFileManager().transitionToState(BaseSubManager.ERROR);
+ sdlManager.getScreenManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getLockScreenConfig().setEnabled(true);
+ sdlManager.getLockScreenManager().transitionToState(BaseSubManager.READY);
+ sdlManager.checkState();
+ assertEquals(BaseSubManager.LIMITED, sdlManager.getState());
+
+
+ // Case 4-B:
+ sdlManager.getPermissionManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getFileManager().transitionToState(BaseSubManager.ERROR);
+ sdlManager.getScreenManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getLockScreenConfig().setEnabled(false);
+ sdlManager.getLockScreenManager().transitionToState(BaseSubManager.SETTING_UP);
+ sdlManager.checkState();
+ assertEquals(BaseSubManager.LIMITED, sdlManager.getState());
+
+
+ // Case 5-A:
+ sdlManager.getPermissionManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getFileManager().transitionToState(BaseSubManager.LIMITED);
+ sdlManager.getScreenManager().transitionToState(BaseSubManager.ERROR);
+ sdlManager.getLockScreenConfig().setEnabled(true);
+ sdlManager.getLockScreenManager().transitionToState(BaseSubManager.READY);
+ sdlManager.checkState();
+ assertEquals(BaseSubManager.LIMITED, sdlManager.getState());
+
+
+ // Case 5-B:
+ sdlManager.getPermissionManager().transitionToState(BaseSubManager.READY);
+ sdlManager.getFileManager().transitionToState(BaseSubManager.LIMITED);
+ sdlManager.getScreenManager().transitionToState(BaseSubManager.ERROR);
+ sdlManager.getLockScreenConfig().setEnabled(false);
+ sdlManager.getLockScreenManager().transitionToState(BaseSubManager.SETTING_UP);
+ sdlManager.checkState();
+ assertEquals(BaseSubManager.LIMITED, sdlManager.getState());
+ }
+
+ public void testSendRPC(){
+ listenerCalledCounter = 0;
+
+ // When sdlProxyBase.sendRPCRequest() is called, create a fake success response
+ Answer<Void> answer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ RPCRequest request = (RPCRequest) args[0];
+ RPCResponse response = new RPCResponse(FunctionID.GET_VEHICLE_DATA.toString());
+ response.setSuccess(true);
+ request.getOnRPCResponseListener().onResponse(0, response);
+ return null;
+ }
+ };
+ try {
+ doAnswer(answer).when(sdlProxyBase).sendRPCRequest(any(RPCRequest.class));
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+
+
+ // Test send RPC request
+ final GetVehicleData request = new GetVehicleData();
+ request.setGps(true);
+ request.setOnRPCResponseListener(new OnRPCResponseListener() {
+ @Override
+ public void onResponse(int correlationId, RPCResponse response) {
+ assertTrue(response.getSuccess());
+ listenerCalledCounter++;
+ }
+ });
+ try {
+ sdlManager.sendRPC(request);
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+
+ // Make sure the listener is called exactly once
+ assertEquals("Listener was not called or called more/less frequently than expected", listenerCalledCounter, 1);
+ }
+
+ public void testSendRPCs(){
+ testSendMultipleRPCs(false);
+ }
+
+ public void testSendSequentialRPCs(){
+ testSendMultipleRPCs(true);
+ }
+
+ private void testSendMultipleRPCs(boolean sequentialSend){
+ listenerCalledCounter = 0;
+
+ // When sdlProxyBase.sendRPCRequests() is called, call listener.onFinished() to fake the response
+ final Answer<Void> answer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ OnMultipleRequestListener listener = (OnMultipleRequestListener) args[1];
+ listener.onFinished();
+ return null;
+ }
+ };
+ try {
+ if (sequentialSend){
+ doAnswer(answer).when(sdlProxyBase).sendSequentialRequests(any(List.class), any(OnMultipleRequestListener.class));
+
+ } else {
+ doAnswer(answer).when(sdlProxyBase).sendRequests(any(List.class), any(OnMultipleRequestListener.class));
+ }
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+
+
+ // Test send RPC requests
+ List<RPCRequest> rpcsList = Arrays.asList(new GetVehicleData(), new Show());
+ OnMultipleRequestListener onMultipleRequestListener = new OnMultipleRequestListener() {
+ @Override
+ public void onUpdate(int remainingRequests) { }
+
+ @Override
+ public void onFinished() {
+ listenerCalledCounter++;
+ }
+
+ @Override
+ public void onError(int correlationId, Result resultCode, String info) {}
+
+ @Override
+ public void onResponse(int correlationId, RPCResponse response) {}
+ };
+ try {
+ if (sequentialSend) {
+ sdlManager.sendSequentialRPCs(rpcsList, onMultipleRequestListener);
+ } else {
+ sdlManager.sendRPCs(rpcsList, onMultipleRequestListener);
+ }
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+
+ // Make sure the listener is called exactly once
+ assertEquals("Listener was not called or called more/less frequently than expected", listenerCalledCounter, 1);
+ }
+
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/audio/AudioStreamManagerTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/audio/AudioStreamManagerTest.java
new file mode 100644
index 000000000..35c57a4c3
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/audio/AudioStreamManagerTest.java
@@ -0,0 +1,681 @@
+package com.smartdevicelink.managers.audio;
+
+import android.content.Context;
+import android.media.AudioFormat;
+import android.media.MediaFormat;
+import android.media.MediaPlayer;
+import android.os.Build;
+import android.support.test.InstrumentationRegistry;
+import android.util.Log;
+
+import com.smartdevicelink.SdlConnection.SdlSession;
+import com.smartdevicelink.managers.CompletionListener;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.proxy.interfaces.IAudioStreamListener;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.managers.audio.AudioStreamManager.SampleType;
+import com.smartdevicelink.proxy.interfaces.ISdlServiceListener;
+import com.smartdevicelink.proxy.rpc.AudioPassThruCapabilities;
+import com.smartdevicelink.proxy.rpc.enums.AudioType;
+import com.smartdevicelink.proxy.rpc.enums.BitsPerSample;
+import com.smartdevicelink.proxy.rpc.enums.SamplingRate;
+import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
+
+import junit.framework.TestCase;
+
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+public class AudioStreamManagerTest extends TestCase {
+ public static final String TAG = AudioStreamManagerTest.class.getSimpleName();
+ private Context mContext;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mContext = InstrumentationRegistry.getContext();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ mContext = null;
+ }
+
+ public void testCreatingAudioStreamManager() {
+ ISdl internalInterface = mock(ISdl.class);
+ AudioPassThruCapabilities audioCapabilities = new AudioPassThruCapabilities(SamplingRate._16KHZ, BitsPerSample._16_BIT, AudioType.PCM);
+ doReturn(true).when(internalInterface).isConnected();
+ doReturn(audioCapabilities).when(internalInterface).getCapability(SystemCapabilityType.PCM_STREAMING);
+
+ new AudioStreamManager(internalInterface, mContext);
+ }
+
+ public void testStartAudioStreamManager() {
+ final SdlSession mockSession = mock(SdlSession.class);
+
+ Answer<Void> audioServiceAnswer = new Answer<Void>() {
+ ISdlServiceListener serviceListener = null;
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Method method = invocation.getMethod();
+ Object[] args = invocation.getArguments();
+
+ switch (method.getName()) {
+ case "addServiceListener":
+ // parameters (SessionType serviceType, ISdlServiceListener sdlServiceListener);
+ SessionType sessionType = (SessionType) args[0];
+ assertEquals(sessionType, SessionType.PCM);
+ serviceListener = (ISdlServiceListener) args[1];
+ break;
+ case "startAudioService":
+ // parameters (boolean encrypted, AudioStreamingCodec codec, AudioStreamingParams params);
+ Boolean encrypted = (Boolean) args[0];
+ serviceListener.onServiceStarted(mockSession, SessionType.PCM, encrypted);
+ break;
+ case "stopAudioService":
+ // parameters ()
+ serviceListener.onServiceEnded(mockSession, SessionType.PCM);
+ break;
+ }
+
+ return null;
+ }
+ };
+
+ ISdl internalInterface = mock(ISdl.class);
+ AudioPassThruCapabilities audioCapabilities = new AudioPassThruCapabilities(SamplingRate._16KHZ, BitsPerSample._16_BIT, AudioType.PCM);
+ doReturn(true).when(internalInterface).isConnected();
+ doReturn(audioCapabilities).when(internalInterface).getCapability(SystemCapabilityType.PCM_STREAMING);
+ doAnswer(audioServiceAnswer).when(internalInterface).addServiceListener(any(SessionType.class), any(ISdlServiceListener.class));
+ doAnswer(audioServiceAnswer).when(internalInterface).startAudioService(any(Boolean.class));
+ doAnswer(audioServiceAnswer).when(internalInterface).stopAudioService();
+
+ CompletionListener completionListener = new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertEquals(true, success);
+ }
+ };
+
+ CompletionListener mockListener = spy(completionListener);
+ AudioStreamManager manager = new AudioStreamManager(internalInterface, mContext);
+
+ manager.startAudioStream(false, mockListener);
+ manager.stopAudioStream(mockListener);
+ verify(mockListener, timeout(10000).times(2)).onComplete(any(Boolean.class));
+ }
+
+ public void testWithSquareSampleAudio16BitAnd8KhzApi16() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 16);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._8KHZ, BitsPerSample._16_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(8000, SampleType.SIGNED_16_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio16BitAnd16KhzApi16() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 16);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._16KHZ, BitsPerSample._16_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(16000, SampleType.SIGNED_16_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio16BitAnd22KhzApi16() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 16);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._22KHZ, BitsPerSample._16_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(22050, SampleType.SIGNED_16_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio16BitAnd44KhzApi16() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 16);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._44KHZ, BitsPerSample._16_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(44100, SampleType.SIGNED_16_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio8BitAnd8KhzApi16() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 16);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._8KHZ, BitsPerSample._8_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(8000, SampleType.UNSIGNED_8_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio8BitAnd16KhzApi16() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 16);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._16KHZ, BitsPerSample._8_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(16000, SampleType.UNSIGNED_8_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio8BitAnd22KhzApi16() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 16);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._22KHZ, BitsPerSample._8_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(22050, SampleType.UNSIGNED_8_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio8BitAnd44KhzApi16() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 16);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._44KHZ, BitsPerSample._8_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(44100, SampleType.UNSIGNED_8_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio16BitAnd8KhzApi21() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 21);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._8KHZ, BitsPerSample._16_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(8000, SampleType.SIGNED_16_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio16BitAnd16KhzApi21() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 21);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._16KHZ, BitsPerSample._16_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(16000, SampleType.SIGNED_16_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio16BitAnd22KhzApi21() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 21);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._22KHZ, BitsPerSample._16_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(22050, SampleType.SIGNED_16_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio16BitAnd44KhzApi21() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 21);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._44KHZ, BitsPerSample._16_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(44100, SampleType.SIGNED_16_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio8BitAnd8KhzApi21() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 21);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._8KHZ, BitsPerSample._8_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(8000, SampleType.UNSIGNED_8_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio8BitAnd16KhzApi21() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 21);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._16KHZ, BitsPerSample._8_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(16000, SampleType.UNSIGNED_8_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio8BitAnd22KhzApi21() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 21);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._22KHZ, BitsPerSample._8_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(22050, SampleType.UNSIGNED_8_BIT, audioPassThruCapabilities);
+ }
+
+ public void testWithSquareSampleAudio8BitAnd44KhzApi21() throws Exception {
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 21);
+ AudioPassThruCapabilities audioPassThruCapabilities = new AudioPassThruCapabilities(SamplingRate._44KHZ, BitsPerSample._8_BIT, AudioType.PCM);
+ runFullAudioManagerDecodeFlowWithSquareSampleAudio(44100, SampleType.UNSIGNED_8_BIT, audioPassThruCapabilities);
+ }
+
+ private int testFullAudioManagerDecodeFlowCorrectCounter = 0;
+ private int testFullAudioManagerDecodeFlowWrongCounter = 0;
+ private void runFullAudioManagerDecodeFlowWithSquareSampleAudio(final int sampleRate, final @SampleType int sampleType, final AudioPassThruCapabilities audioCapabilities) {
+ testFullAudioManagerDecodeFlowCorrectCounter = 0;
+ testFullAudioManagerDecodeFlowWrongCounter = 0;
+
+ IAudioStreamListener audioStreamListener = new IAudioStreamListener() {
+ @Override
+ public void sendAudio(byte[] data, int offset, int length, long presentationTimeUs) throws ArrayIndexOutOfBoundsException {
+ ByteBuffer buffer = ByteBuffer.wrap(data, offset, length);
+ this.sendAudio(buffer, presentationTimeUs);
+ }
+
+ @Override
+ public void sendAudio(ByteBuffer data, long presentationTimeUs) {
+ SampleBuffer samples = SampleBuffer.wrap(data, sampleType, presentationTimeUs);
+ double timeUs = presentationTimeUs;
+ double sampleDurationUs = 1000000.0 / sampleRate;
+
+ for (int i = 0; i < samples.limit(); ++i) {
+ double sample = samples.get(i);
+ double edge = timeUs % 4000.0;
+
+ if (edge > 2000.0) {
+ // swap sample as it's negative expected
+ sample = sample * -1.0;
+ }
+
+ edge = edge % 2000.0;
+
+ // at the edge of a wave the sample can be lower than 0.7
+ if ((sample > 0.7 && sample < 0.95) || (edge < sampleDurationUs || (2000.0 - sampleDurationUs) < edge)) {
+ testFullAudioManagerDecodeFlowCorrectCounter++;
+ } else {
+ testFullAudioManagerDecodeFlowWrongCounter++;
+ }
+
+ timeUs += sampleDurationUs;
+ }
+ }
+ };
+
+ final SdlSession mockSession = mock(SdlSession.class);
+ doReturn(audioStreamListener).when(mockSession).startAudioStream();
+
+ Answer<Void> audioServiceAnswer = new Answer<Void>() {
+ ISdlServiceListener serviceListener = null;
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Method method = invocation.getMethod();
+ Object[] args = invocation.getArguments();
+
+ switch (method.getName()) {
+ case "addServiceListener":
+ // (SessionType serviceType, ISdlServiceListener sdlServiceListener);
+ SessionType sessionType = (SessionType) args[0];
+ assertEquals(sessionType, SessionType.PCM);
+
+ serviceListener = (ISdlServiceListener) args[1];
+ break;
+ case "startAudioService":
+ //(boolean encrypted, AudioStreamingCodec codec, AudioStreamingParams params);
+ Boolean encrypted = (Boolean) args[0];
+ serviceListener.onServiceStarted(mockSession, SessionType.PCM, encrypted);
+ break;
+ case "stopAudioService":
+ // parameters ()
+ serviceListener.onServiceEnded(mockSession, SessionType.PCM);
+ break;
+ }
+
+ return null;
+ }
+ };
+
+ ISdl internalInterface = mock(ISdl.class);
+ doReturn(true).when(internalInterface).isConnected();
+ doReturn(audioCapabilities).when(internalInterface).getCapability(any(SystemCapabilityType.class));
+ doAnswer(audioServiceAnswer).when(internalInterface).addServiceListener(any(SessionType.class), any(ISdlServiceListener.class));
+ doAnswer(audioServiceAnswer).when(internalInterface).startAudioService(any(Boolean.class));
+ doAnswer(audioServiceAnswer).when(internalInterface).stopAudioService();
+
+ CompletionListener fileCompletionListener = new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertEquals(true, success);
+
+ // not more than 2.5 percent samples must be wrong
+ double relation = 100.0 * (double)testFullAudioManagerDecodeFlowWrongCounter / (double)testFullAudioManagerDecodeFlowCorrectCounter;
+ Log.v(TAG, "Validating number of correct samples (" + Math.round(relation) + "%)");
+ if (relation > 2.5) {
+ fail("Validating raw audio failed. " + Math.round(relation) + " % wrong samples detected. Correct: " + testFullAudioManagerDecodeFlowCorrectCounter + ", Wrong: " + testFullAudioManagerDecodeFlowWrongCounter);
+ }
+ }
+ };
+
+ final CompletionListener mockFileListener = spy(fileCompletionListener);
+
+ final AudioStreamManager manager = new AudioStreamManager(internalInterface, mContext);
+ manager.startAudioStream(false, new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertEquals(true, success);
+
+ manager.pushResource(com.smartdevicelink.test.R.raw.test_audio_square_250hz_80amp_1s, mockFileListener);
+ }
+ });
+
+ verify(mockFileListener, timeout(10000)).onComplete(any(Boolean.class));
+ }
+
+ public void testSampleAtTargetTimeReturnNull() {
+ BaseAudioDecoder mockDecoder = mock(BaseAudioDecoder.class, Mockito.CALLS_REAL_METHODS);
+ Method sampleAtTargetMethod = getSampleAtTargetMethod();
+ SampleBuffer sample = SampleBuffer.allocate(1, SampleType.SIGNED_16_BIT, ByteOrder.LITTLE_ENDIAN, 1);
+ Double result;
+ try {
+ result = (Double) sampleAtTargetMethod.invoke(mockDecoder, 1.0, sample, 1, 3, 2);
+ assertNull(result);
+ result = (Double) sampleAtTargetMethod.invoke(mockDecoder, 1.0, sample, 5, 3, 1);
+ assertNull(result);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ public void testSampleAtTargetTimeReturnLastOutputSample() {
+ BaseAudioDecoder mockDecoder = mock(BaseAudioDecoder.class, Mockito.CALLS_REAL_METHODS);
+ Method sampleAtTargetMethod = getSampleAtTargetMethod();
+ SampleBuffer sample = SampleBuffer.allocate(1, SampleType.SIGNED_16_BIT, ByteOrder.LITTLE_ENDIAN, 1);
+ Double result;
+ Double lastOutputSample = 15.0;
+ try {
+ result = (Double) sampleAtTargetMethod.invoke(mockDecoder, lastOutputSample, sample, 6, 1, 5);
+ assertTrue(result.doubleValue() == lastOutputSample);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ public void testSampleAtTargetTimeReturnOutputSampleGet() {
+ BaseAudioDecoder mockDecoder = mock(BaseAudioDecoder.class, Mockito.CALLS_REAL_METHODS);
+ Method sampleAtTargetMethod = getSampleAtTargetMethod();
+ SampleBuffer sample = SampleBuffer.allocate(10, SampleType.SIGNED_16_BIT, ByteOrder.LITTLE_ENDIAN, 1);
+ Double result;
+ try {
+ result = (Double) sampleAtTargetMethod.invoke(mockDecoder, 1.0, sample, 1, 1, 2);
+ assertTrue(result == sample.get(1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ public void testSampleAtTargetTime() {
+ BaseAudioDecoder mockDecoder = mock(BaseAudioDecoder.class, Mockito.CALLS_REAL_METHODS);
+ Method sampleAtTargetMethod = getSampleAtTargetMethod();
+ SampleBuffer sample = SampleBuffer.allocate(10, SampleType.SIGNED_16_BIT, ByteOrder.LITTLE_ENDIAN, 1);
+ Double result;
+ try {
+ result = (Double) sampleAtTargetMethod.invoke(mockDecoder, 1.0, sample, 1, 3, 2);
+ assertNotNull(result);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ public void testOutputFormatChanged() {
+ BaseAudioDecoder mockDecoder = mock(BaseAudioDecoder.class, Mockito.CALLS_REAL_METHODS);
+
+ try {
+ Field outputChannelCountField = BaseAudioDecoder.class.getDeclaredField("outputChannelCount");
+ Field outputSampleRateField = BaseAudioDecoder.class.getDeclaredField("outputSampleRate");
+ Field outputSampleTypeField = BaseAudioDecoder.class.getDeclaredField("outputSampleType");
+
+ outputChannelCountField.setAccessible(true);
+ outputSampleRateField.setAccessible(true);
+ outputSampleTypeField.setAccessible(true);
+
+ // channel count, sample rate, sample type
+ int key_channel_count = 0, key_sample_rate = 1, key_sample_type = 2, key_sample_type_result = 3;
+ int[][] tests = new int[][] {
+ { 47, 42000, AudioFormat.ENCODING_PCM_8BIT, SampleType.UNSIGNED_8_BIT },
+ { 2, 16000, AudioFormat.ENCODING_PCM_16BIT, SampleType.SIGNED_16_BIT },
+ { 1, 22050, AudioFormat.ENCODING_PCM_FLOAT, SampleType.FLOAT },
+ { 3, 48000, AudioFormat.ENCODING_INVALID, SampleType.SIGNED_16_BIT },
+ };
+
+ for (int[] test : tests) {
+ int channel_count = test[key_channel_count];
+ int sample_rate = test[key_sample_rate];
+ int sample_type = test[key_sample_type];
+ int sample_type_result = test[key_sample_type_result];
+
+ MediaFormat format = new MediaFormat();
+
+ format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, channel_count);
+ format.setInteger(MediaFormat.KEY_SAMPLE_RATE, sample_rate);
+ format.setInteger(MediaFormat.KEY_PCM_ENCODING, sample_type);
+
+ // in case the phone version is old the method does not take sample type into account but
+ // always expected 16 bit. See https://developer.android.com/reference/android/media/MediaFormat.html#KEY_PCM_ENCODING
+ if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.N) {
+ sample_type_result = SampleType.SIGNED_16_BIT;
+ }
+
+ mockDecoder.onOutputFormatChanged(format);
+
+ int output_channel_count = outputChannelCountField.getInt(mockDecoder);
+ int output_sample_rate = outputSampleRateField.getInt(mockDecoder);
+ int output_sample_type = outputSampleTypeField.getInt(mockDecoder);
+
+ // changing from assertEquals to if and fail so travis gives better results
+
+ if (channel_count != output_channel_count) {
+ fail("AssertEqualsFailed: channel_count == output_channel_count (" + channel_count + " == " + output_channel_count + ")");
+ }
+
+ if (sample_rate != output_sample_rate) {
+ fail("AssertEqualsFailed: sample_rate == output_sample_rate (" + sample_rate + " == " + output_sample_rate + ")");
+ }
+
+ if (sample_type_result != output_sample_type) {
+ fail("Assert: sample_type_result == output_sample_type (" + sample_type_result + " == " + output_sample_type + ")");
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ public void testPlayAudioFileForManualTest() throws IOException {
+ AudioPassThruCapabilities audioCapabilities = new AudioPassThruCapabilities(SamplingRate._16KHZ, BitsPerSample._16_BIT, AudioType.PCM);
+ final int sampleType = SampleType.SIGNED_16_BIT;
+ final int sampleRate = 16000;
+
+ final File outputFile = new File(mContext.getCacheDir(), "test_audio_file.wav");
+ assertNotNull((outputFile));
+ final FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
+ assertNotNull(fileOutputStream);
+ writeWaveHeader(fileOutputStream, sampleRate, sampleType << 3);
+
+ IAudioStreamListener audioStreamListener = new IAudioStreamListener() {
+ long audioLength = 0;
+
+ @Override
+ public void sendAudio(byte[] data, int offset, int length, long presentationTimeUs) throws ArrayIndexOutOfBoundsException {
+ ByteBuffer buffer = ByteBuffer.wrap(data, offset, length);
+ this.sendAudio(buffer, presentationTimeUs);
+ }
+
+ @Override
+ public void sendAudio(ByteBuffer data, long presentationTimeUs) {
+ try {
+ long length = data.limit();
+ byte[] d = data.array();
+ fileOutputStream.write(d, 0, (int) length);
+
+ audioLength += length;
+ RandomAccessFile raf = new RandomAccessFile(outputFile, "rw");
+ updateWaveHeaderLength(raf, audioLength);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ };
+
+ final SdlSession mockSession = mock(SdlSession.class);
+ doReturn(audioStreamListener).when(mockSession).startAudioStream();
+
+ Answer<Void> audioServiceAnswer = new Answer<Void>() {
+ ISdlServiceListener serviceListener = null;
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Method method = invocation.getMethod();
+ Object[] args = invocation.getArguments();
+
+ switch (method.getName()) {
+ case "addServiceListener":
+ // (SessionType serviceType, ISdlServiceListener sdlServiceListener);
+ SessionType sessionType = (SessionType) args[0];
+ assertEquals(sessionType, SessionType.PCM);
+
+ serviceListener = (ISdlServiceListener) args[1];
+ break;
+ case "startAudioService":
+ //(boolean encrypted, AudioStreamingCodec codec, AudioStreamingParams params);
+ Boolean encrypted = (Boolean) args[0];
+ serviceListener.onServiceStarted(mockSession, SessionType.PCM, encrypted);
+ break;
+ case "stopAudioService":
+ // parameters ()
+ serviceListener.onServiceEnded(mockSession, SessionType.PCM);
+ break;
+ }
+
+ return null;
+ }
+ };
+
+ ISdl internalInterface = mock(ISdl.class);
+ doReturn(true).when(internalInterface).isConnected();
+ doReturn(audioCapabilities).when(internalInterface).getCapability(any(SystemCapabilityType.class));
+ doAnswer(audioServiceAnswer).when(internalInterface).addServiceListener(any(SessionType.class), any(ISdlServiceListener.class));
+ doAnswer(audioServiceAnswer).when(internalInterface).startAudioService(any(Boolean.class));
+ doAnswer(audioServiceAnswer).when(internalInterface).stopAudioService();
+
+ final MediaPlayer.OnCompletionListener mockPlayerCompletionListener = mock(MediaPlayer.OnCompletionListener.class);
+ final MediaPlayer player = new MediaPlayer();
+ player.setOnCompletionListener(mockPlayerCompletionListener);
+
+ CompletionListener fileCompletionListener = new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ try {
+ fileOutputStream.flush();
+ fileOutputStream.close();
+
+ player.setDataSource(outputFile.getPath());
+ player.prepare();
+ player.start();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ };
+
+ final CompletionListener mockFileListener = spy(fileCompletionListener);
+
+ final AudioStreamManager manager = new AudioStreamManager(internalInterface, mContext);
+ manager.startAudioStream(false, new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertEquals(true, success);
+
+ manager.pushResource(com.smartdevicelink.test.R.raw.test_audio_square_250hz_80amp_1s, mockFileListener);
+ }
+ });
+
+ verify(mockFileListener, timeout(10000)).onComplete(any(Boolean.class));
+ verify(mockPlayerCompletionListener, timeout(10000)).onCompletion(any(MediaPlayer.class));
+ }
+
+ private Method getSampleAtTargetMethod() {
+ Method method = null;
+ try {
+ method = BaseAudioDecoder.class.getDeclaredMethod("sampleAtTargetTime",
+ double.class, SampleBuffer.class, double.class, double.class, double.class);
+ method.setAccessible(true);
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ fail();
+ }
+ return method;
+ }
+
+ private void setFinalStatic(Field field, Object newValue) throws Exception {
+ field.setAccessible(true);
+ field.set(null, newValue);
+ }
+
+ private void writeWaveHeader(OutputStream stream, long samplerate, long bitspersample) throws IOException {
+ byte[] header = new byte[44];
+ // the data header is 36 bytes large
+ long datalength = 36;
+ long audiolength = 0;
+ long format = 1; // 1 = PCM
+ long channels = 1;
+ long blockalign = (channels * bitspersample) >> 3;
+ long byterate = (samplerate * channels * bitspersample) >> 3;
+
+ // RIFF header.
+ header[0] = 'R';
+ header[1] = 'I';
+ header[2] = 'F';
+ header[3] = 'F';
+ // Total data length (UInt32).
+ header[4] = (byte)((datalength) & 0xff);
+ header[5] = (byte)((datalength >> 8) & 0xff);
+ header[6] = (byte)((datalength >> 16) & 0xff);
+ header[7] = (byte)((datalength >> 24) & 0xff);
+ // WAVE header.
+ header[8] = 'W';
+ header[9] = 'A';
+ header[10] = 'V';
+ header[11] = 'E';
+ // Format (fmt) header.
+ header[12] = 'f';
+ header[13] = 'm';
+ header[14] = 't';
+ header[15] = ' ';
+ // Format header size (UInt32).
+ header[16] = 16;
+ header[17] = 0;
+ header[18] = 0;
+ header[19] = 0;
+ // Format type (UInt16). Set 1 for PCM.
+ header[20] = (byte)((format) & 0xff);
+ header[21] = (byte)((format >> 8) & 0xff);
+ // Channels
+ header[22] = (byte)((channels) & 0xff);
+ header[23] = (byte)((channels >> 8) & 0xff);
+ // Sample rate (UInt32).
+ header[24] = (byte)((samplerate) & 0xff);
+ header[25] = (byte)((samplerate >> 8) & 0xff);
+ header[26] = (byte)((samplerate >> 16) & 0xff);
+ header[27] = (byte)((samplerate >> 24) & 0xff);
+ // Byte rate (UInt32).
+ header[28] = (byte)((byterate) & 0xff);
+ header[29] = (byte)((byterate >> 8) & 0xff);
+ header[30] = (byte)((byterate >> 16) & 0xff);
+ header[31] = (byte)((byterate >> 24) & 0xff);
+ // Block alignment (UInt16).
+ header[32] = (byte)((blockalign) & 0xff);
+ header[33] = (byte)((blockalign >> 8) & 0xff);
+ // Bits per sample (UInt16).
+ header[34] = (byte)((bitspersample) & 0xff);
+ header[35] = (byte)((bitspersample >> 8) & 0xff);
+ // Data header
+ header[36] = 'd';
+ header[37] = 'a';
+ header[38] = 't';
+ header[39] = 'a';
+ // Total audio length (UInt32).
+ header[40] = (byte)((audiolength) & 0xff);
+ header[41] = (byte)((audiolength >> 8) & 0xff);
+ header[42] = (byte)((audiolength >> 16) & 0xff);
+ header[43] = (byte)((audiolength >> 24) & 0xff);
+
+ stream.write(header, 0, header.length);
+ }
+
+ /** Updates the data length and audio length of an existing RIFF/WAVE header in the file pointed by the RandomAccessFile object. */
+ private void updateWaveHeaderLength(RandomAccessFile stream, long audiolength) throws IOException {
+ // the data header is 36 bytes large
+ long datalength = 36 + audiolength;
+
+ // Seek from the beginning to data length
+ stream.seek(4);
+ // Overwrite total data length
+ stream.write((int)((datalength) & 0xff));
+ stream.write((int)((datalength >> 8) & 0xff));
+ stream.write((int)((datalength >> 16) & 0xff));
+ stream.write((int)((datalength >> 24) & 0xff));
+ // Seek from the end of data length to audio length
+ stream.seek(40);
+ // overwrite total audio length
+ stream.write((int)((audiolength) & 0xff));
+ stream.write((int)((audiolength >> 8) & 0xff));
+ stream.write((int)((audiolength >> 16) & 0xff));
+ stream.write((int)((audiolength >> 24) & 0xff));
+ }
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java
new file mode 100644
index 000000000..05838d727
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java
@@ -0,0 +1,485 @@
+package com.smartdevicelink.managers.file;
+
+import android.content.Context;
+import android.net.Uri;
+
+import com.smartdevicelink.AndroidTestCase2;
+import com.smartdevicelink.managers.BaseSubManager;
+import com.smartdevicelink.managers.CompletionListener;
+import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
+import com.smartdevicelink.managers.file.filetypes.SdlFile;
+import com.smartdevicelink.proxy.RPCRequest;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.rpc.ListFiles;
+import com.smartdevicelink.proxy.rpc.ListFilesResponse;
+import com.smartdevicelink.proxy.rpc.PutFile;
+import com.smartdevicelink.proxy.rpc.PutFileResponse;
+import com.smartdevicelink.proxy.rpc.enums.FileType;
+import com.smartdevicelink.proxy.rpc.enums.Result;
+import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
+import com.smartdevicelink.test.Test;
+
+import junit.framework.Assert;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library manager class :
+ * {@link FileManager}
+ */
+public class FileManagerTests extends AndroidTestCase2 {
+ public static final String TAG = "FileManagerTests";
+ private FileManager fileManager;
+ private Context mTestContext;
+ private SdlFile validFile;
+
+ // SETUP / HELPERS
+
+ @Override
+ public void setUp() throws Exception{
+ super.setUp();
+ mTestContext = this.getContext();
+ validFile = new SdlFile();
+ validFile.setName(Test.GENERAL_STRING);
+ validFile.setFileData(Test.GENERAL_BYTE_ARRAY);
+ validFile.setPersistent(false);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ private Answer<Void> onListFilesSuccess = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ RPCRequest message = (RPCRequest) args[0];
+ if(message instanceof ListFiles){
+ int correlationId = message.getCorrelationID();
+ ListFilesResponse listFilesResponse = new ListFilesResponse();
+ listFilesResponse.setFilenames(Test.GENERAL_STRING_LIST);
+ listFilesResponse.setSpaceAvailable(Test.GENERAL_INT);
+ listFilesResponse.setSuccess(true);
+ message.getOnRPCResponseListener().onResponse(correlationId, listFilesResponse);
+ }
+ return null;
+ }
+ };
+
+ private Answer<Void> onListFilesFailure = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ RPCRequest message = (RPCRequest) args[0];
+ if(message instanceof ListFiles){
+ int correlationId = message.getCorrelationID();
+ ListFilesResponse listFilesResponse = new ListFilesResponse();
+ listFilesResponse.setSuccess(false);
+ message.getOnRPCResponseListener().onResponse(correlationId, listFilesResponse);
+ }
+ return null;
+ }
+ };
+
+ private Answer<Void> onPutFileSuccess = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ RPCRequest message = (RPCRequest) args[0];
+ if(message instanceof PutFile){
+ int correlationId = message.getCorrelationID();
+ PutFileResponse putFileResponse = new PutFileResponse();
+ putFileResponse.setSuccess(true);
+ message.getOnRPCResponseListener().onResponse(correlationId, putFileResponse);
+ }
+ return null;
+ }
+ };
+
+ private Answer<Void> onPutFileFailure = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ RPCRequest message = (RPCRequest) args[0];
+ if(message instanceof PutFile){
+ int correlationId = message.getCorrelationID();
+ PutFileResponse putFileResponse = new PutFileResponse();
+ putFileResponse.setSuccess(false);
+ message.getOnRPCResponseListener().onResponse(correlationId, putFileResponse);
+ }
+ return null;
+ }
+ };
+
+ private Answer<Void> onSendRequestsSuccess = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ List<RPCRequest> rpcs = (List<RPCRequest>) args[0];
+ OnMultipleRequestListener listener = (OnMultipleRequestListener) args[1];
+ if(rpcs.get(0) instanceof PutFile){
+ for(RPCRequest message : rpcs){
+ int correlationId = message.getCorrelationID();
+ listener.addCorrelationId(correlationId);
+ PutFileResponse putFileResponse = new PutFileResponse();
+ putFileResponse.setSuccess(true);
+ listener.onResponse(correlationId, putFileResponse);
+ }
+ }
+ return null;
+ }
+ };
+
+ // TESTS
+
+ public void testInitializationSuccess(){
+ ISdl internalInterface = mock(ISdl.class);
+
+ doAnswer(onListFilesSuccess).when(internalInterface).sendRPCRequest(any(ListFiles.class));
+
+ final FileManager fileManager = new FileManager(internalInterface, mTestContext);
+ fileManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertTrue(success);
+ Assert.assertEquals(fileManager.getState(), BaseSubManager.READY);
+ assertEquals(fileManager.getRemoteFileNames(), Test.GENERAL_STRING_LIST);
+ }
+ });
+ }
+
+ public void testInitializationFailure(){
+ ISdl internalInterface = mock(ISdl.class);
+
+ doAnswer(onListFilesFailure).when(internalInterface).sendRPCRequest(any(ListFiles.class));
+
+ final FileManager fileManager = new FileManager(internalInterface, mTestContext);
+ fileManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertFalse(success);
+ assertEquals(fileManager.getState(), BaseSubManager.ERROR);
+ }
+ });
+ }
+
+ public void testFileUploadSuccess(){
+ ISdl internalInterface = mock(ISdl.class);
+
+ doAnswer(onListFilesSuccess).when(internalInterface).sendRPCRequest(any(ListFiles.class));
+ doAnswer(onPutFileSuccess).when(internalInterface).sendRPCRequest(any(PutFile.class));
+
+ final FileManager fileManager = new FileManager(internalInterface, mTestContext);
+ fileManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertTrue(success);
+ fileManager.uploadFile(validFile, new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertTrue(success);
+ assertTrue(fileManager.getRemoteFileNames().contains(validFile.getName()));
+ assertTrue(fileManager.hasUploadedFile(validFile));
+ }
+ });
+ }
+ });
+ }
+
+ public void testFileUploadFailure(){
+ ISdl internalInterface = mock(ISdl.class);
+
+ doAnswer(onListFilesSuccess).when(internalInterface).sendRPCRequest(any(ListFiles.class));
+ doAnswer(onPutFileFailure).when(internalInterface).sendRPCRequest(any(PutFile.class));
+
+ final FileManager fileManager = new FileManager(internalInterface, mTestContext);
+ fileManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertTrue(success);
+ fileManager.uploadFile(validFile, new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertFalse(success);
+ assertFalse(fileManager.getRemoteFileNames().contains(validFile.getName()));
+ assertFalse(fileManager.hasUploadedFile(validFile));
+ }
+ });
+ }
+ });
+ }
+
+ public void testInvalidSdlFileInput(){
+ ISdl internalInterface = mock(ISdl.class);
+
+ doAnswer(onListFilesSuccess).when(internalInterface).sendRPCRequest(any(ListFiles.class));
+
+ final FileManager fileManager = new FileManager(internalInterface, mTestContext);
+ fileManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertTrue(success);
+ SdlFile sdlFile = new SdlFile();
+ // Don't set name
+ sdlFile.setFileData(Test.GENERAL_BYTE_ARRAY);
+ checkForUploadFailure(fileManager, sdlFile);
+
+ sdlFile = new SdlFile();
+ sdlFile.setName(Test.GENERAL_STRING);
+ // Don't set data
+ checkForUploadFailure(fileManager, sdlFile);
+
+ sdlFile = new SdlFile();
+ sdlFile.setName(Test.GENERAL_STRING);
+ // Give an invalid resource ID
+ sdlFile.setResourceId(Test.GENERAL_INT);
+ checkForUploadFailure(fileManager, sdlFile);
+
+ sdlFile = new SdlFile();
+ sdlFile.setName(Test.GENERAL_STRING);
+ // Set invalid Uri
+ Uri testUri = Uri.parse("http://www.google.com");
+ sdlFile.setUri(testUri);
+ checkForUploadFailure(fileManager, sdlFile);
+ }
+ });
+ }
+
+ private void checkForUploadFailure(FileManager fileManager, SdlFile sdlFile){
+ boolean error = false;
+
+ try {
+ fileManager.uploadFile(sdlFile, new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {}
+ });
+ }catch (IllegalArgumentException e){
+ error = true;
+ }
+
+ assertTrue(error);
+ }
+
+ public void testInvalidSdlArtworkInput(){
+ SdlArtwork sdlArtwork = new SdlArtwork();
+ // Set invalid type
+ for(FileType fileType : FileType.values()){
+ boolean shouldError = true, didError = false;
+ if(fileType.equals(FileType.GRAPHIC_BMP) || fileType.equals(FileType.GRAPHIC_PNG)
+ || fileType.equals(FileType.GRAPHIC_JPEG)){
+ shouldError = false;
+ }
+ try{
+ sdlArtwork.setType(fileType);
+ }catch(IllegalArgumentException e){
+ didError = true;
+ }
+ assertEquals(shouldError, didError);
+ }
+ }
+
+ public void testMultipleFileUploadThenDeleteSuccess(){
+ ISdl internalInterface = mock(ISdl.class);
+
+ doAnswer(onListFilesSuccess).when(internalInterface).sendRPCRequest(any(ListFiles.class));
+ doAnswer(onSendRequestsSuccess).when(internalInterface).sendRequests(any(List.class), any(OnMultipleRequestListener.class));
+
+ final FileManager fileManager = new FileManager(internalInterface, mTestContext);
+ fileManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertTrue(success);
+ int fileNum = 1;
+ final List<SdlFile> filesToUpload = new ArrayList<>();
+ SdlFile sdlFile = new SdlFile();
+ sdlFile.setName("file" + fileNum++);
+ Uri uri = Uri.parse("android.resource://" + mTestContext.getPackageName() + "/drawable/ic_sdl");
+ sdlFile.setUri(uri);
+ filesToUpload.add(sdlFile);
+
+ sdlFile = new SdlFile();
+ sdlFile.setName("file" + fileNum++);
+ sdlFile.setResourceId(com.smartdevicelink.test.R.drawable.ic_sdl);
+ filesToUpload.add(sdlFile);
+
+ fileManager.uploadFiles(filesToUpload,
+ new MultipleFileCompletionListener() {
+ @Override
+ public void onComplete(Map<String, String> errors) {
+ assertNull(errors);
+ List <String> uploadedFileNames = fileManager.getRemoteFileNames();
+ for(SdlFile file : filesToUpload){
+ assertTrue(uploadedFileNames.contains(file.getName()));
+ }
+ fileManager.deleteRemoteFilesWithNames(uploadedFileNames, new MultipleFileCompletionListener() {
+ @Override
+ public void onComplete(Map<String, String> errors) {
+ assertNull(errors);
+ List <String> uploadedFileNames = fileManager.getRemoteFileNames();
+ for(SdlFile file : filesToUpload){
+ assertFalse(uploadedFileNames.contains(file.getName()));
+ }
+ }
+ });
+ }
+ });
+ }
+ });
+ }
+
+ public void testMultipleFileUploadPartialFailure(){
+ final String failureReason = "No space available";
+
+ ISdl internalInterface = mock(ISdl.class);
+
+ doAnswer(onListFilesSuccess).when(internalInterface).sendRPCRequest(any(ListFiles.class));
+
+ Answer<Void> onSendRequestsFailure = new Answer<Void>() {
+ private int responseNum = 0;
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ List<RPCRequest> rpcs = (List<RPCRequest>) args[0];
+ OnMultipleRequestListener listener = (OnMultipleRequestListener) args[1];
+ if(rpcs.get(0) instanceof PutFile){
+ for(RPCRequest message : rpcs){
+ int correlationId = message.getCorrelationID();
+ listener.addCorrelationId(correlationId);
+ PutFileResponse putFileResponse = new PutFileResponse();
+ if(responseNum++ % 2 == 0){
+ listener.onError(correlationId, Result.OUT_OF_MEMORY, failureReason);
+ }else{
+ putFileResponse.setSuccess(true);
+ listener.onResponse(correlationId, putFileResponse);
+ }
+ }
+ }
+ return null;
+ }
+ };
+ doAnswer(onSendRequestsFailure).when(internalInterface).sendRequests(any(List.class), any(OnMultipleRequestListener.class));
+
+ final FileManager fileManager = new FileManager(internalInterface, mTestContext);
+ fileManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertTrue(success);
+ final String baseFileName = "file";
+ int fileNum = 0;
+ final List<SdlFile> filesToUpload = new ArrayList<>();
+ SdlFile sdlFile = new SdlFile();
+ sdlFile.setName(baseFileName + fileNum++);
+ Uri uri = Uri.parse("android.resource://" + mTestContext.getPackageName() + "/drawable/ic_sdl");
+ sdlFile.setUri(uri);
+ filesToUpload.add(sdlFile);
+
+ sdlFile = new SdlFile();
+ sdlFile.setName(baseFileName + fileNum++);
+ sdlFile.setResourceId(com.smartdevicelink.test.R.drawable.ic_sdl);
+ filesToUpload.add(sdlFile);
+
+ sdlFile = new SdlFile();
+ sdlFile.setName(baseFileName + fileNum++);
+ sdlFile.setFileData(Test.GENERAL_BYTE_ARRAY);
+ sdlFile.setPersistent(true);
+ sdlFile.setType(FileType.BINARY);
+ filesToUpload.add(sdlFile);
+
+ fileManager.uploadFiles(filesToUpload,
+ new MultipleFileCompletionListener() {
+ @Override
+ public void onComplete(Map<String, String> errors) {
+ assertNotNull(errors);
+ for(int i = 0; i < filesToUpload.size(); i++){
+ if(i % 2 == 0){
+ assertTrue(errors.containsKey(filesToUpload.get(i).getName()));
+ assertEquals(FileManager.buildErrorString(Result.OUT_OF_MEMORY,
+ failureReason), errors.get(filesToUpload.get(i).getName()));
+ }else{
+ assertFalse(errors.containsKey(filesToUpload.get(i).getName()));
+ }
+ }
+ List <String> uploadedFileNames = fileManager.getRemoteFileNames();
+ for(int i = 0; i < filesToUpload.size(); i++){
+ if(i % 2 == 0){
+ assertFalse(uploadedFileNames.contains(filesToUpload.get(i).getName()));
+ }else{
+ assertTrue(uploadedFileNames.contains(filesToUpload.get(i).getName()));
+ }
+ }
+ }
+ });
+ }
+ });
+ }
+
+ public void testMultipleArtworkUploadSuccess(){
+ ISdl internalInterface = mock(ISdl.class);
+
+ doAnswer(onListFilesSuccess).when(internalInterface).sendRPCRequest(any(ListFiles.class));
+ doAnswer(onSendRequestsSuccess).when(internalInterface).sendRequests(any(List.class), any(OnMultipleRequestListener.class));
+
+ final FileManager fileManager = new FileManager(internalInterface, mTestContext);
+ fileManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertTrue(success);
+ int fileNum = 1;
+ final List<SdlArtwork> artworkToUpload = new ArrayList<>();
+ SdlArtwork sdlArtwork = new SdlArtwork();
+ sdlArtwork.setName("art" + fileNum++);
+ Uri uri = Uri.parse("android.resource://" + mTestContext.getPackageName() + "/drawable/ic_sdl");
+ sdlArtwork.setUri(uri);
+ sdlArtwork.setType(FileType.GRAPHIC_PNG);
+ artworkToUpload.add(sdlArtwork);
+
+ sdlArtwork = new SdlArtwork();
+ sdlArtwork.setName("art" + fileNum++);
+ uri = Uri.parse("android.resource://" + mTestContext.getPackageName() + "/drawable/sdl_tray_icon");
+ sdlArtwork.setUri(uri);
+ sdlArtwork.setType(FileType.GRAPHIC_PNG);
+ artworkToUpload.add(sdlArtwork);
+
+ fileManager.uploadFiles(artworkToUpload,
+ new MultipleFileCompletionListener() {
+ @Override
+ public void onComplete(Map<String, String> errors) {
+ assertNull(errors);
+ List < String > uploadedFileNames = fileManager.getRemoteFileNames();
+ for(SdlArtwork artwork : artworkToUpload){
+ assertTrue(uploadedFileNames.contains(artwork.getName()));
+ }
+ }
+ });
+ }
+ });
+ }
+
+ public void testPersistentFileUploaded(){
+ ISdl internalInterface = mock(ISdl.class);
+
+ doAnswer(onListFilesSuccess).when(internalInterface).sendRPCRequest(any(ListFiles.class));
+
+ final SdlFile file = new SdlFile();
+ file.setName(Test.GENERAL_STRING_LIST.get(0));
+ file.setPersistent(true);
+
+ final FileManager fileManager = new FileManager(internalInterface, mTestContext);
+ fileManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertTrue(fileManager.hasUploadedFile(file));
+ }
+ });
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/lockscreen/LockScreenConfigTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/lockscreen/LockScreenConfigTests.java
new file mode 100644
index 000000000..c2d4066ce
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/lockscreen/LockScreenConfigTests.java
@@ -0,0 +1,45 @@
+package com.smartdevicelink.managers.lockscreen;
+
+import com.smartdevicelink.AndroidTestCase2;
+import com.smartdevicelink.test.Test;
+
+
+/**
+ * This is a unit test class for the SmartDeviceLink library manager class :
+ * {@link com.smartdevicelink.managers.lockscreen.LockScreenConfig}
+ *
+ * We currently do not need to test null values, as each currently is a primitive
+ */
+public class LockScreenConfigTests extends AndroidTestCase2 {
+
+ private LockScreenConfig lockScreenConfig;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ // set info for all the setters
+ lockScreenConfig = new LockScreenConfig();
+ lockScreenConfig.setCustomView(Test.GENERAL_INT);
+ lockScreenConfig.setAppIcon(Test.GENERAL_INT);
+ lockScreenConfig.setBackgroundColor(Test.GENERAL_INT);
+ lockScreenConfig.showDeviceLogo(true);
+ lockScreenConfig.setEnabled(true);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testLockScreenConfig() {
+
+ // get the info and make sure its correct
+ assertEquals(Test.GENERAL_INT, lockScreenConfig.getCustomView());
+ assertEquals(Test.GENERAL_INT, lockScreenConfig.getAppIcon());
+ assertEquals(Test.GENERAL_INT, lockScreenConfig.getBackgroundColor());
+ assertEquals(true, lockScreenConfig.isEnabled());
+ assertEquals(true, lockScreenConfig.isDeviceLogoEnabled());
+ }
+
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/lockscreen/LockScreenManagerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/lockscreen/LockScreenManagerTests.java
new file mode 100644
index 000000000..69e0aa898
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/lockscreen/LockScreenManagerTests.java
@@ -0,0 +1,56 @@
+package com.smartdevicelink.managers.lockscreen;
+
+import android.content.Context;
+
+import com.smartdevicelink.AndroidTestCase2;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.rpc.enums.LockScreenStatus;
+import com.smartdevicelink.test.Test;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library manager class :
+ * {@link com.smartdevicelink.managers.lockscreen.LockScreenManager}
+ */
+public class LockScreenManagerTests extends AndroidTestCase2 {
+
+ private LockScreenManager lockScreenManager;
+
+ @Override
+ public void setUp() throws Exception{
+ super.setUp();
+
+ ISdl internalInterface = mock(ISdl.class);
+
+ Context context = getContext();
+ // create config
+ LockScreenConfig lockScreenConfig = new LockScreenConfig();
+ lockScreenConfig.setCustomView(Test.GENERAL_INT);
+ lockScreenConfig.setAppIcon(Test.GENERAL_INT);
+ lockScreenConfig.setBackgroundColor(Test.GENERAL_INT);
+ lockScreenConfig.showDeviceLogo(true);
+ lockScreenConfig.setEnabled(true);
+
+ lockScreenManager = new LockScreenManager(lockScreenConfig, context, internalInterface);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testVariables() {
+ assertEquals(Test.GENERAL_INT, lockScreenManager.customView);
+ assertEquals(Test.GENERAL_INT, lockScreenManager.lockScreenIcon);
+ assertEquals(Test.GENERAL_INT, lockScreenManager.lockScreenColor);
+ assertEquals(true, lockScreenManager.deviceLogoEnabled);
+ assertEquals(true, lockScreenManager.lockScreenEnabled);
+ assertNull(lockScreenManager.deviceLogo);
+ }
+
+ public void testGetLockScreenStatus(){
+ assertEquals(LockScreenStatus.OFF, lockScreenManager.getLockScreenStatus());
+ }
+
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/permission/PermissionManagerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/permission/PermissionManagerTests.java
new file mode 100644
index 000000000..6a66a3092
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/permission/PermissionManagerTests.java
@@ -0,0 +1,203 @@
+package com.smartdevicelink.managers.permission;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.AndroidTestCase2;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.rpc.HMIPermissions;
+import com.smartdevicelink.proxy.rpc.OnHMIStatus;
+import com.smartdevicelink.proxy.rpc.OnPermissionsChange;
+import com.smartdevicelink.proxy.rpc.ParameterPermissions;
+import com.smartdevicelink.proxy.rpc.PermissionItem;
+import com.smartdevicelink.proxy.rpc.enums.HMILevel;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static com.smartdevicelink.managers.permission.PermissionManager.PERMISSION_GROUP_STATUS_ALLOWED;
+import static com.smartdevicelink.managers.permission.PermissionManager.PERMISSION_GROUP_STATUS_MIXED;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+
+public class PermissionManagerTests extends AndroidTestCase2 {
+
+ private OnRPCNotificationListener onHMIStatusListener, onPermissionsChangeListener;
+ private PermissionManager permissionManager;
+ private int listenerCalledCounter;
+
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Mock Isdl and its behaviour to use it for PermissionManager testing
+ ISdl internalInterface = mock(ISdl.class);
+
+
+ // When internalInterface.addOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, OnRPCNotificationListener) is called
+ // inside PermissionManager's constructor, then keep a reference to the OnRPCNotificationListener so we can trigger it later
+ // to emulate what Core does when it sends OnHMIStatus notification
+ Answer<Void> onHMIStatusAnswer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ onHMIStatusListener = (OnRPCNotificationListener) args[1];
+ return null;
+ }
+ };
+ doAnswer(onHMIStatusAnswer).when(internalInterface).addOnRPCNotificationListener(eq(FunctionID.ON_HMI_STATUS), any(OnRPCNotificationListener.class));
+
+
+ // When internalInterface.addOnRPCNotificationListener(FunctionID.ON_PERMISSIONS_CHANGE, OnRPCNotificationListener) is called
+ // inside PermissionManager's constructor, then keep a reference to the onPermissionsChangeListener so we can trigger it later
+ // to emulate what Core does when it sends OnPermissionsChange notification
+ Answer<Void> onPermissionsChangeAnswer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ onPermissionsChangeListener = (OnRPCNotificationListener) args[1];
+ return null;
+ }
+ };
+ doAnswer(onPermissionsChangeAnswer).when(internalInterface).addOnRPCNotificationListener(eq(FunctionID.ON_PERMISSIONS_CHANGE), any(OnRPCNotificationListener.class));
+
+
+ // Initialize PermissionManager
+ permissionManager = new PermissionManager(internalInterface);
+ }
+
+ // Emulate what happens when Core sends OnHMIStatus notification
+ private void sendFakeCoreOnHMIStatusNotifications(HMILevel hmiLevel) {
+ if (hmiLevel != null) {
+ OnHMIStatus onHMIStatusFakeNotification = new OnHMIStatus();
+ onHMIStatusFakeNotification.setHmiLevel(hmiLevel);
+ onHMIStatusListener.onNotified(onHMIStatusFakeNotification);
+ }
+ }
+
+ // Emulate what happens when Core sends OnPermissionsChange notification
+ private void sendFakeCoreOnPermissionsChangeNotifications(List<PermissionItem> permissionItems) {
+ if (permissionItems != null) {
+ OnPermissionsChange onPermissionChangeFakeNotification = new OnPermissionsChange();
+ onPermissionChangeFakeNotification.setPermissionItem(permissionItems);
+ onPermissionsChangeListener.onNotified(onPermissionChangeFakeNotification);
+ }
+ }
+
+ // Test adding a listener to be called when ALL of the specified permissions become allowed
+ public void testListenersAllAllowed() {
+ listenerCalledCounter = 0;
+
+
+ // Test how developers can add listeners through PermissionManager
+ List<PermissionElement> permissionElements = new ArrayList<>();
+ permissionElements.add(new PermissionElement(FunctionID.SHOW, null));
+ permissionElements.add(new PermissionElement(FunctionID.GET_VEHICLE_DATA, Arrays.asList("rpm", "airbagStatus")));
+ permissionManager.addListener(permissionElements, PermissionManager.PERMISSION_GROUP_TYPE_ALL_ALLOWED, new OnPermissionChangeListener() {
+ @Override
+ public void onPermissionsChange(@NonNull Map<FunctionID, PermissionStatus> allowedPermissions, @NonNull int permissionGroupStatus) {
+ // Make sure is the actual result matches the expected one
+ assertEquals(permissionGroupStatus, PERMISSION_GROUP_STATUS_ALLOWED);
+ assertTrue(allowedPermissions.get(FunctionID.SHOW).getIsRPCAllowed());
+ assertTrue(allowedPermissions.get(FunctionID.GET_VEHICLE_DATA).getIsRPCAllowed());
+ assertTrue(allowedPermissions.get(FunctionID.GET_VEHICLE_DATA).getAllowedParameters().get("rpm"));
+ assertTrue(allowedPermissions.get(FunctionID.GET_VEHICLE_DATA).getAllowedParameters().get("airbagStatus"));
+ listenerCalledCounter++;
+ }
+ });
+
+
+ // Emulate Core's behaviour by sending OnHMIStatus notification
+ sendFakeCoreOnHMIStatusNotifications(HMILevel.HMI_LIMITED);
+
+
+ // Emulate Core's behaviour by sending OnPermissionsChange notification
+ List<PermissionItem> permissionItems = new ArrayList<>();
+ PermissionItem permissionItem1 = new PermissionItem();
+ permissionItem1.setRpcName(FunctionID.SHOW.toString());
+ permissionItem1.setHMIPermissions(new HMIPermissions(Arrays.asList(HMILevel.HMI_BACKGROUND, HMILevel.HMI_FULL, HMILevel.HMI_LIMITED), new ArrayList<HMILevel>()));
+ permissionItem1.setParameterPermissions(new ParameterPermissions(new ArrayList<String>(), new ArrayList<String>()));
+ permissionItems.add(permissionItem1);
+ PermissionItem permissionItem2 = new PermissionItem();
+ permissionItem2.setRpcName(FunctionID.GET_VEHICLE_DATA.toString());
+ permissionItem2.setHMIPermissions(new HMIPermissions(Arrays.asList(HMILevel.HMI_BACKGROUND, HMILevel.HMI_FULL), new ArrayList<HMILevel>()));
+ permissionItem2.setParameterPermissions(new ParameterPermissions(Arrays.asList("rpm", "airbagStatus"), new ArrayList<String>()));
+ permissionItems.add(permissionItem2);
+ sendFakeCoreOnPermissionsChangeNotifications(permissionItems);
+
+
+ // Emulate Core's behaviour by sending OnHMIStatus notification
+ sendFakeCoreOnHMIStatusNotifications(HMILevel.HMI_FULL);
+
+
+ // Make sure the listener is called exactly once
+ assertEquals("Listener was not called or called more/less frequently than expected", listenerCalledCounter, 1);
+ }
+
+
+ // Test adding a listener to be called when ANY of the specified permissions become allowed
+ public void testListenersAnyAllowed() {
+ listenerCalledCounter = 0;
+
+ // Test how developers can add listeners through PermissionManager
+ List<PermissionElement> permissionElements = new ArrayList<>();
+ permissionElements.add(new PermissionElement(FunctionID.SHOW, null));
+ permissionElements.add(new PermissionElement(FunctionID.GET_VEHICLE_DATA, Arrays.asList("rpm", "airbagStatus")));
+ permissionManager.addListener(permissionElements, PermissionManager.PERMISSION_GROUP_TYPE_ANY, new OnPermissionChangeListener() {
+ @Override
+ public void onPermissionsChange(@NonNull Map<FunctionID, PermissionStatus> allowedPermissions, @NonNull int permissionGroupStatus) {
+ // Make sure is the actual result matches the expected one
+ if (listenerCalledCounter == 0) { // Listener called for the first time
+ assertEquals(permissionGroupStatus, PERMISSION_GROUP_STATUS_MIXED);
+ assertTrue(allowedPermissions.get(FunctionID.SHOW).getIsRPCAllowed());
+ assertTrue(!allowedPermissions.get(FunctionID.GET_VEHICLE_DATA).getIsRPCAllowed());
+ assertTrue(!allowedPermissions.get(FunctionID.GET_VEHICLE_DATA).getAllowedParameters().get("rpm"));
+ assertTrue(!allowedPermissions.get(FunctionID.GET_VEHICLE_DATA).getAllowedParameters().get("airbagStatus"));
+ } else if (listenerCalledCounter == 1) { // Listener called for the second time
+ assertEquals(permissionGroupStatus, PERMISSION_GROUP_STATUS_ALLOWED);
+ assertTrue(allowedPermissions.get(FunctionID.SHOW).getIsRPCAllowed());
+ assertTrue(allowedPermissions.get(FunctionID.GET_VEHICLE_DATA).getIsRPCAllowed());
+ assertTrue(allowedPermissions.get(FunctionID.GET_VEHICLE_DATA).getAllowedParameters().get("rpm"));
+ assertTrue(allowedPermissions.get(FunctionID.GET_VEHICLE_DATA).getAllowedParameters().get("airbagStatus"));
+ }
+ listenerCalledCounter++;
+ }
+ });
+
+
+ // Emulate Core's behaviour by sending OnHMIStatus notification
+ sendFakeCoreOnHMIStatusNotifications(HMILevel.HMI_LIMITED);
+
+
+ // Emulate Core's behaviour by sending OnPermissionsChange notification
+ List<PermissionItem> permissionItems = new ArrayList<>();
+ PermissionItem permissionItem1 = new PermissionItem();
+ permissionItem1.setRpcName(FunctionID.SHOW.toString());
+ permissionItem1.setHMIPermissions(new HMIPermissions(Arrays.asList(HMILevel.HMI_BACKGROUND, HMILevel.HMI_FULL, HMILevel.HMI_LIMITED), new ArrayList<HMILevel>()));
+ permissionItem1.setParameterPermissions(new ParameterPermissions(new ArrayList<String>(), new ArrayList<String>()));
+ permissionItems.add(permissionItem1);
+ PermissionItem permissionItem2 = new PermissionItem();
+ permissionItem2.setRpcName(FunctionID.GET_VEHICLE_DATA.toString());
+ permissionItem2.setHMIPermissions(new HMIPermissions(Arrays.asList(HMILevel.HMI_BACKGROUND, HMILevel.HMI_FULL), new ArrayList<HMILevel>()));
+ permissionItem2.setParameterPermissions(new ParameterPermissions(Arrays.asList("rpm", "airbagStatus"), new ArrayList<String>()));
+ permissionItems.add(permissionItem2);
+ sendFakeCoreOnPermissionsChangeNotifications(permissionItems);
+
+
+ // Emulate Core's behaviour by sending OnHMIStatus notification
+ sendFakeCoreOnHMIStatusNotifications(HMILevel.HMI_FULL);
+
+
+ // Make sure the the listener is called exactly twice
+ assertEquals("Listener was not called or called more/less frequently than expected", listenerCalledCounter, 2);
+ }
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/ScreenManagerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/ScreenManagerTests.java
new file mode 100644
index 000000000..8c0c1e9c0
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/ScreenManagerTests.java
@@ -0,0 +1,122 @@
+package com.smartdevicelink.managers.screen;
+
+import com.smartdevicelink.AndroidTestCase2;
+import com.smartdevicelink.managers.BaseSubManager;
+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;
+import com.smartdevicelink.proxy.rpc.enums.MetadataType;
+import com.smartdevicelink.proxy.rpc.enums.TextAlignment;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library manager class :
+ * {@link ScreenManager}
+ */
+public class ScreenManagerTests extends AndroidTestCase2 {
+ private ScreenManager screenManager;
+ private SdlArtwork testArtwork;
+
+ @Override
+ public void setUp() throws Exception{
+ super.setUp();
+
+ ISdl internalInterface = mock(ISdl.class);
+ FileManager fileManager = mock(FileManager.class);
+ screenManager = new ScreenManager(internalInterface, fileManager);
+
+
+ testArtwork = new SdlArtwork("testFile", FileType.GRAPHIC_PNG, 1, false);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testInstantiation(){
+ assertNull(screenManager.getTextField1());
+ assertNull(screenManager.getTextField2());
+ assertNull(screenManager.getTextField3());
+ assertNull(screenManager.getTextField4());
+ assertNull(screenManager.getMediaTrackTextField());
+ assertNull(screenManager.getPrimaryGraphic());
+ assertNull(screenManager.getSecondaryGraphic());
+ assertEquals(screenManager.getTextAlignment(), TextAlignment.CENTERED);
+ assertNull(screenManager.getTextField1Type());
+ assertNull(screenManager.getTextField2Type());
+ assertNull(screenManager.getTextField3Type());
+ assertNull(screenManager.getTextField4Type());
+ assertTrue(screenManager.getSoftButtonObjects().isEmpty());
+ assertNull(screenManager.getSoftButtonObjectByName("test"));
+ assertNull(screenManager.getSoftButtonObjectById(1));
+ assertEquals(screenManager.getState(), BaseSubManager.READY);
+ }
+
+ public void testSetTextField() {
+ screenManager.setTextField1("It is");
+ screenManager.setTextField2("Wednesday");
+ screenManager.setTextField3("My");
+ screenManager.setTextField4("Dudes");
+ assertEquals(screenManager.getTextField1(), "It is");
+ assertEquals(screenManager.getTextField2(), "Wednesday");
+ assertEquals(screenManager.getTextField3(), "My");
+ assertEquals(screenManager.getTextField4(), "Dudes");
+ }
+
+ public void testMediaTrackTextFields() {
+ String songTitle = "Wild For The Night";
+ screenManager.setMediaTrackTextField(songTitle);
+ assertEquals(screenManager.getMediaTrackTextField(), songTitle);
+ }
+
+ public void testSetPrimaryGraphic() {
+ screenManager.setPrimaryGraphic(testArtwork);
+ assertEquals(screenManager.getPrimaryGraphic(), testArtwork);
+ }
+
+ public void testSetSecondaryGraphic() {
+ screenManager.setSecondaryGraphic(testArtwork);
+ assertEquals(screenManager.getSecondaryGraphic(), testArtwork);
+ }
+
+ public void testAlignment() {
+ screenManager.setTextAlignment(TextAlignment.LEFT_ALIGNED);
+ assertEquals(screenManager.getTextAlignment(), TextAlignment.LEFT_ALIGNED);
+ }
+
+ public void testSetTextFieldTypes() {
+ screenManager.setTextField1Type(MetadataType.MEDIA_TITLE);
+ screenManager.setTextField2Type(MetadataType.MEDIA_ALBUM);
+ screenManager.setTextField3Type(MetadataType.MEDIA_ARTIST);
+ screenManager.setTextField4Type(MetadataType.MEDIA_GENRE);
+ assertEquals(screenManager.getTextField1Type(), MetadataType.MEDIA_TITLE);
+ assertEquals(screenManager.getTextField2Type(), MetadataType.MEDIA_ALBUM);
+ assertEquals(screenManager.getTextField3Type(), MetadataType.MEDIA_ARTIST);
+ assertEquals(screenManager.getTextField4Type(), MetadataType.MEDIA_GENRE);
+ }
+
+ public void testSetSoftButtonObjects(){
+ // Create softButtonObject1
+ SoftButtonState softButtonState1 = new SoftButtonState("object1-state1", "it is", testArtwork);
+ SoftButtonState softButtonState2 = new SoftButtonState("object1-state2", "Wed", testArtwork);
+ SoftButtonObject softButtonObject1 = new SoftButtonObject("object1", Arrays.asList(softButtonState1, softButtonState2), softButtonState1.getName(),null);
+
+ // Create softButtonObject2
+ SoftButtonState softButtonState3 = new SoftButtonState("object2-state1", "my", testArtwork);
+ SoftButtonState softButtonState4 = new SoftButtonState("object2-state2", "dudes!", null);
+ SoftButtonObject softButtonObject2 = new SoftButtonObject("object2", Arrays.asList(softButtonState3, softButtonState4), softButtonState3.getName(), null);
+
+ List<SoftButtonObject> softButtonObjects = Arrays.asList(softButtonObject1, softButtonObject2);
+ screenManager.setSoftButtonObjects(Arrays.asList(softButtonObject1, softButtonObject2));
+ assertEquals(screenManager.getSoftButtonObjects(), softButtonObjects);
+ assertEquals(screenManager.getSoftButtonObjectByName("object2"), softButtonObject2);
+ assertEquals(screenManager.getSoftButtonObjectById(100), softButtonObject2);
+ }
+
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/SoftButtonManagerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/SoftButtonManagerTests.java
new file mode 100644
index 000000000..3198bc116
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/SoftButtonManagerTests.java
@@ -0,0 +1,239 @@
+package com.smartdevicelink.managers.screen;
+
+
+import com.smartdevicelink.AndroidTestCase2;
+import com.smartdevicelink.managers.CompletionListener;
+import com.smartdevicelink.managers.file.FileManager;
+import com.smartdevicelink.managers.file.MultipleFileCompletionListener;
+import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.rpc.Image;
+import com.smartdevicelink.proxy.rpc.OnHMIStatus;
+import com.smartdevicelink.proxy.rpc.Show;
+import com.smartdevicelink.proxy.rpc.SoftButton;
+import com.smartdevicelink.proxy.rpc.enums.FileType;
+import com.smartdevicelink.proxy.rpc.enums.HMILevel;
+import com.smartdevicelink.proxy.rpc.enums.ImageType;
+import com.smartdevicelink.proxy.rpc.enums.SoftButtonType;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
+import com.smartdevicelink.test.Validator;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library manager class :
+ * {@link SoftButtonManager}
+ */
+public class SoftButtonManagerTests extends AndroidTestCase2 {
+
+ private SoftButtonManager softButtonManager;
+ private boolean fileManagerUploadArtworksGotCalled;
+ private boolean internalInterfaceSendRPCRequestGotCalled;
+ private boolean softButtonMangerUpdateCompleted;
+ private SoftButtonObject softButtonObject1, softButtonObject2;
+ private SoftButtonState softButtonState1, softButtonState2, softButtonState3, softButtonState4;
+
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ // When internalInterface.addOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, OnRPCNotificationListener) is called
+ // inside SoftButtonManager, respond with a fake HMILevel.HMI_FULL response to let the SoftButtonManager continue working.
+ ISdl internalInterface = mock(ISdl.class);
+ Answer<Void> onHMIStatusAnswer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ OnRPCNotificationListener onHMIStatusListener = (OnRPCNotificationListener) args[1];
+ OnHMIStatus onHMIStatusFakeNotification = new OnHMIStatus();
+ onHMIStatusFakeNotification.setHmiLevel(HMILevel.HMI_FULL);
+ onHMIStatusListener.onNotified(onHMIStatusFakeNotification);
+ return null;
+ }
+ };
+ doAnswer(onHMIStatusAnswer).when(internalInterface).addOnRPCNotificationListener(eq(FunctionID.ON_HMI_STATUS), any(OnRPCNotificationListener.class));
+
+
+ // When fileManager.uploadArtworks() is called inside the SoftButtonManager, respond with
+ // a fake onComplete() callback to let the SoftButtonManager continue working.
+ FileManager fileManager = mock(FileManager.class);
+ Answer<Void> onFileManagerUploadAnswer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ fileManagerUploadArtworksGotCalled = true;
+ Object[] args = invocation.getArguments();
+ MultipleFileCompletionListener multipleFileCompletionListener = (MultipleFileCompletionListener) args[1];
+ multipleFileCompletionListener.onComplete(null);
+ return null;
+ }
+ };
+ doAnswer(onFileManagerUploadAnswer).when(fileManager).uploadArtworks(any(List.class), any(MultipleFileCompletionListener.class));
+
+
+ // Create softButtonManager
+ softButtonManager = new SoftButtonManager(internalInterface, fileManager);
+
+
+ // When internalInterface.sendRPCRequest() is called inside SoftButtonManager:
+ // 1) respond with a fake onResponse() callback to let the SoftButtonManager continue working
+ // 2) assert that the Show RPC values (ie: MainField1 & SoftButtons) that are created by the SoftButtonManager, match the ones that are provided by the developer
+ Answer<Void> onSendShowRPCAnswer = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ internalInterfaceSendRPCRequestGotCalled = true;
+ Object[] args = invocation.getArguments();
+ Show show = (Show) args[0];
+
+ show.getOnRPCResponseListener().onResponse(0, null);
+
+ assertEquals(show.getMainField1(), softButtonManager.getCurrentMainField1());
+ assertEquals(show.getSoftButtons().size(), softButtonManager.createSoftButtonsForCurrentState().size());
+
+ return null;
+ }
+ };
+ doAnswer(onSendShowRPCAnswer).when(internalInterface).sendRPCRequest(any(Show.class));
+
+
+ // Create soft button objects
+ softButtonState1 = new SoftButtonState("object1-state1", "o1s1", new SdlArtwork("image1", FileType.GRAPHIC_PNG, 1, true));
+ softButtonState2 = new SoftButtonState("object1-state2", "o1s2", new SdlArtwork("image2", FileType.GRAPHIC_PNG, 2, true));
+ softButtonObject1 = new SoftButtonObject("object1", Arrays.asList(softButtonState1, softButtonState2), softButtonState1.getName(), null);
+ softButtonState3 = new SoftButtonState("object2-state1", "o2s1", null);
+ softButtonState4 = new SoftButtonState("object2-state2", "o2s2", new SdlArtwork("image3", FileType.GRAPHIC_PNG, 3, true));
+ softButtonObject2 = new SoftButtonObject("object2", Arrays.asList(softButtonState3, softButtonState4), softButtonState3.getName(), null);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testSoftButtonManagerUpdate() {
+ // Reset the boolean variables
+ fileManagerUploadArtworksGotCalled = false;
+ internalInterfaceSendRPCRequestGotCalled = false;
+ softButtonMangerUpdateCompleted = false;
+
+
+ // Test batch update
+ softButtonManager.setBatchUpdates(true);
+ List<SoftButtonObject> softButtonObjects = Arrays.asList(softButtonObject1, softButtonObject2);
+ softButtonManager.setSoftButtonObjects(Arrays.asList(softButtonObject1, softButtonObject2));
+ softButtonManager.setBatchUpdates(false);
+ softButtonManager.update(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ softButtonMangerUpdateCompleted = true;
+ }
+ });
+
+
+ // Test single update, setCurrentMainField1, and transitionToNextState
+ softButtonManager.setCurrentMainField1("It is Wednesday my dudes!");
+ softButtonObject1.transitionToNextState();
+
+
+ // Check that everything got called as expected
+ assertTrue("FileManager.uploadArtworks() did not get called", fileManagerUploadArtworksGotCalled);
+ assertTrue("InternalInterface.sendRPCRequest() did not get called", internalInterfaceSendRPCRequestGotCalled);
+ assertTrue("SoftButtonManger update onComplete() did not get called", softButtonMangerUpdateCompleted);
+
+
+ // Test getSoftButtonObjects
+ assertEquals("Returned softButtonObjects value doesn't match the expected value", softButtonObjects, softButtonManager.getSoftButtonObjects());
+ }
+
+ public void testSoftButtonManagerGetSoftButtonObject() {
+ softButtonManager.setSoftButtonObjects(Arrays.asList(softButtonObject1, softButtonObject2));
+
+
+ // Test get by valid name
+ assertEquals("Returned SoftButtonObject doesn't match the expected value", softButtonObject2, softButtonManager.getSoftButtonObjectByName("object2"));
+
+
+ // Test get by invalid name
+ assertNull("Returned SoftButtonObject doesn't match the expected value", softButtonManager.getSoftButtonObjectByName("object300"));
+
+
+ // Test get by valid id
+ assertEquals("Returned SoftButtonObject doesn't match the expected value", softButtonObject2, softButtonManager.getSoftButtonObjectById(100));
+
+
+ // Test get by invalid id
+ assertNull("Returned SoftButtonObject doesn't match the expected value", softButtonManager.getSoftButtonObjectById(500));
+ }
+
+ public void testSoftButtonState(){
+ // Test SoftButtonState.getName()
+ String nameExpectedValue = "object1-state1";
+ assertEquals("Returned state name doesn't match the expected value", nameExpectedValue, softButtonState1.getName());
+
+
+ // Test SoftButtonState.getArtwork()
+ SdlArtwork artworkExpectedValue = new SdlArtwork("image1", FileType.GRAPHIC_PNG, 1, true);
+ assertTrue("Returned SdlArtwork doesn't match the expected value", Validator.validateSdlFile(artworkExpectedValue, softButtonState1.getArtwork()));
+
+
+ // Test SoftButtonState.getSoftButton()
+ SoftButton softButtonExpectedValue = new SoftButton(SoftButtonType.SBT_BOTH, 0);
+ softButtonExpectedValue.setText("o1s1");
+ softButtonExpectedValue.setImage(new Image(artworkExpectedValue.getName(), ImageType.DYNAMIC));
+ assertTrue("Returned SoftButton doesn't match the expected value", Validator.validateSoftButton(softButtonExpectedValue, softButtonState1.getSoftButton()));
+ }
+
+ public void testSoftButtonObject(){
+ // Test SoftButtonObject.getName()
+ assertEquals("Returned object name doesn't match the expected value", "object1", softButtonObject1.getName());
+
+
+ // Test SoftButtonObject.getCurrentState()
+ assertEquals("Returned current state doesn't match the expected value", softButtonState1, softButtonObject1.getCurrentState());
+
+
+ // Test SoftButtonObject.getCurrentStateName()
+ assertEquals("Returned current state name doesn't match the expected value", softButtonState1.getName(), softButtonObject1.getCurrentStateName());
+
+
+ // Test SoftButtonObject.getButtonId()
+ assertEquals("Returned button Id doesn't match the expected value", 0, softButtonObject1.getButtonId());
+
+
+ // Test SoftButtonObject.getCurrentStateSoftButton()
+ SoftButton softButtonExpectedValue = new SoftButton(SoftButtonType.SBT_TEXT, 0);
+ softButtonExpectedValue.setText("o2s1");
+ assertTrue("Returned current state SoftButton doesn't match the expected value", Validator.validateSoftButton(softButtonExpectedValue, softButtonObject2.getCurrentStateSoftButton()));
+
+
+ // Test SoftButtonObject.getStates()
+ assertEquals("Returned object states doesn't match the expected value", Arrays.asList(softButtonState1, softButtonState2), softButtonObject1.getStates());
+
+
+ // Test SoftButtonObject.transitionToNextState()
+ assertEquals(softButtonState1, softButtonObject1.getCurrentState());
+ softButtonObject1.transitionToNextState();
+ assertEquals(softButtonState2, softButtonObject1.getCurrentState());
+
+
+ // Test SoftButtonObject.transitionToStateByName() - transitioning to a none existing state
+ boolean success = softButtonObject1.transitionToStateByName("none existing name");
+ assertFalse(success);
+
+
+ // Test SoftButtonObject.transitionToStateByName() - transitioning to an existing state
+ success = softButtonObject1.transitionToStateByName("object1-state1");
+ assertTrue(success);
+ assertEquals(softButtonState1, softButtonObject1.getCurrentState());
+ }
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/TextAndGraphicManagerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/TextAndGraphicManagerTests.java
new file mode 100644
index 000000000..aaad2df24
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/TextAndGraphicManagerTests.java
@@ -0,0 +1,545 @@
+package com.smartdevicelink.managers.screen;
+
+import android.content.Context;
+import android.net.Uri;
+
+import com.smartdevicelink.AndroidTestCase2;
+import com.smartdevicelink.managers.BaseSubManager;
+import com.smartdevicelink.managers.file.FileManager;
+import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.rpc.DisplayCapabilities;
+import com.smartdevicelink.proxy.rpc.MetadataTags;
+import com.smartdevicelink.proxy.rpc.Show;
+import com.smartdevicelink.proxy.rpc.TextField;
+import com.smartdevicelink.proxy.rpc.enums.FileType;
+import com.smartdevicelink.proxy.rpc.enums.HMILevel;
+import com.smartdevicelink.proxy.rpc.enums.MetadataType;
+import com.smartdevicelink.proxy.rpc.enums.TextAlignment;
+import com.smartdevicelink.proxy.rpc.enums.TextFieldName;
+
+import org.json.JSONException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library manager class :
+ * {@link com.smartdevicelink.managers.screen.TextAndGraphicManager}
+ */
+public class TextAndGraphicManagerTests extends AndroidTestCase2 {
+
+ // SETUP / HELPERS
+ private TextAndGraphicManager textAndGraphicManager;
+ private SdlArtwork testArtwork;
+
+ @Override
+ public void setUp() throws Exception{
+ super.setUp();
+ Context mTestContext = this.getContext();
+ // mock things
+ ISdl internalInterface = mock(ISdl.class);
+ FileManager fileManager = mock(FileManager.class);
+ SoftButtonManager softButtonManager = mock(SoftButtonManager.class);
+
+ testArtwork = new SdlArtwork();
+ testArtwork.setName("testFile");
+ Uri uri = Uri.parse("android.resource://" + mTestContext.getPackageName() + "/drawable/ic_sdl");
+ testArtwork.setUri(uri);
+ testArtwork.setType(FileType.GRAPHIC_PNG);
+
+ textAndGraphicManager = new TextAndGraphicManager(internalInterface, fileManager, softButtonManager);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ private DisplayCapabilities getDisplayCapability(int numberOfMainFields){
+
+ TextField mainField1 = new TextField();
+ mainField1.setName(TextFieldName.mainField1);
+ TextField mainField2 = new TextField();
+ mainField2.setName(TextFieldName.mainField2);
+ TextField mainField3 = new TextField();
+ mainField3.setName(TextFieldName.mainField3);
+ TextField mainField4 = new TextField();
+ mainField4.setName(TextFieldName.mainField4);
+
+ List<TextField> textFieldList = new ArrayList<>();
+
+ textFieldList.add(mainField1);
+ textFieldList.add(mainField2);
+ textFieldList.add(mainField3);
+ textFieldList.add(mainField4);
+
+ List<TextField> returnList = new ArrayList<>();
+
+ if (numberOfMainFields > 0){
+ for (int i = 0; i < numberOfMainFields; i++) {
+ returnList.add(textFieldList.get(i));
+ }
+ }
+
+ DisplayCapabilities displayCapabilities = new DisplayCapabilities();
+ displayCapabilities.setTextFields(returnList);
+
+ return displayCapabilities;
+ }
+
+ public void testInstantiation(){
+
+ assertNull(textAndGraphicManager.getTextField1());
+ assertNull(textAndGraphicManager.getTextField2());
+ assertNull(textAndGraphicManager.getTextField3());
+ assertNull(textAndGraphicManager.getTextField4());
+ assertNull(textAndGraphicManager.getMediaTrackTextField());
+ assertNull(textAndGraphicManager.getPrimaryGraphic());
+ assertNull(textAndGraphicManager.getSecondaryGraphic());
+ assertEquals(textAndGraphicManager.getTextAlignment(), TextAlignment.CENTERED);
+ assertNull(textAndGraphicManager.getTextField1Type());
+ assertNull(textAndGraphicManager.getTextField2Type());
+ assertNull(textAndGraphicManager.getTextField3Type());
+ assertNull(textAndGraphicManager.getTextField4Type());
+
+ assertNotNull(textAndGraphicManager.currentScreenData);
+ assertNull(textAndGraphicManager.inProgressUpdate);
+ assertNull(textAndGraphicManager.queuedImageUpdate);
+ assertFalse(textAndGraphicManager.hasQueuedUpdate);
+ assertNull(textAndGraphicManager.displayCapabilities);
+ assertEquals(textAndGraphicManager.currentHMILevel, HMILevel.HMI_NONE);
+ assertFalse(textAndGraphicManager.isDirty);
+ assertEquals(textAndGraphicManager.getState(), BaseSubManager.SETTING_UP);
+ }
+
+ public void testGetMainLines(){
+
+ // We want to test that the looping works. By default, it will return 4 if display cap is null
+
+ // Null test
+ assertEquals(textAndGraphicManager.getNumberOfLines(), 4);
+
+ // The tests.java class has an example of this, but we must build it to do what
+ // we need it to do. Build display cap w/ 3 main fields and test that it returns 3
+ textAndGraphicManager.displayCapabilities = getDisplayCapability(3);
+ assertEquals(textAndGraphicManager.getNumberOfLines(), 3);
+ }
+
+ public void testAssemble1Line(){
+
+ Show inputShow = new Show();
+
+ // Force it to return display with support for only 1 line of text
+ textAndGraphicManager.displayCapabilities = getDisplayCapability(1);
+
+ textAndGraphicManager.setTextField1("It is");
+ textAndGraphicManager.setTextField1Type(MetadataType.HUMIDITY);
+
+ Show assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is");
+
+ // test tags (just 1)
+ MetadataTags tags = assembledShow.getMetadataTags();
+ List<MetadataType> tagsList = new ArrayList<>();
+ tagsList.add(MetadataType.HUMIDITY);
+ assertEquals(tags.getMainField1(), tagsList);
+
+ textAndGraphicManager.setTextField2("Wednesday");
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is - Wednesday");
+
+ textAndGraphicManager.setTextField3("My");
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is - Wednesday - My");
+
+ textAndGraphicManager.setTextField4("Dudes");
+ textAndGraphicManager.setTextField4Type(MetadataType.CURRENT_TEMPERATURE);
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is - Wednesday - My - Dudes");
+
+ // test tags
+ tags = assembledShow.getMetadataTags();
+ tagsList = new ArrayList<>();
+ tagsList.add(MetadataType.HUMIDITY);
+ tagsList.add(MetadataType.CURRENT_TEMPERATURE);
+ assertEquals(tags.getMainField1(), tagsList);
+
+ // For some obscurity, lets try setting just fields 2 and 4 for a 1 line display
+ textAndGraphicManager.setTextField1(null);
+ textAndGraphicManager.setTextField3(null);
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "Wednesday - Dudes");
+ }
+
+ public void testAssemble2Lines() {
+
+ Show inputShow = new Show();
+
+ // Force it to return display with support for only 2 lines of text
+ textAndGraphicManager.displayCapabilities = getDisplayCapability(2);
+
+ textAndGraphicManager.setTextField1("It is");
+ textAndGraphicManager.setTextField1Type(MetadataType.HUMIDITY);
+
+ Show assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is");
+
+ // test tags
+ MetadataTags tags = assembledShow.getMetadataTags();
+ List<MetadataType> tagsList = new ArrayList<>();
+ tagsList.add(MetadataType.HUMIDITY);
+ assertEquals(tags.getMainField1(), tagsList);
+
+ textAndGraphicManager.setTextField2("Wednesday");
+ textAndGraphicManager.setTextField2Type(MetadataType.CURRENT_TEMPERATURE);
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is");
+ assertEquals(assembledShow.getMainField2(), "Wednesday");
+
+ // test tags
+ tags = assembledShow.getMetadataTags();
+ tagsList = new ArrayList<>();
+ List<MetadataType> tagsList2 = new ArrayList<>();
+ tagsList.add(MetadataType.HUMIDITY);
+ tagsList2.add(MetadataType.CURRENT_TEMPERATURE);
+ assertEquals(tags.getMainField1(), tagsList);
+ assertEquals(tags.getMainField2(), tagsList2);
+
+ textAndGraphicManager.setTextField3("My");
+ textAndGraphicManager.setTextField3Type(MetadataType.MEDIA_ALBUM);
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is - Wednesday");
+ assertEquals(assembledShow.getMainField2(), "My");
+
+ // test tags
+ tags = assembledShow.getMetadataTags();
+ tagsList = new ArrayList<>();
+ tagsList2 = new ArrayList<>();
+ tagsList.add(MetadataType.CURRENT_TEMPERATURE);
+ tagsList.add(MetadataType.HUMIDITY);
+ tagsList2.add(MetadataType.MEDIA_ALBUM);
+ assertEquals(tags.getMainField1(), tagsList);
+ assertEquals(tags.getMainField2(), tagsList2);
+
+ textAndGraphicManager.setTextField4("Dudes");
+ textAndGraphicManager.setTextField4Type(MetadataType.MEDIA_STATION);
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is - Wednesday");
+ assertEquals(assembledShow.getMainField2(), "My - Dudes");
+
+ // test tags
+ tags = assembledShow.getMetadataTags();
+ tagsList = new ArrayList<>();
+ tagsList2 = new ArrayList<>();
+ tagsList.add(MetadataType.CURRENT_TEMPERATURE);
+ tagsList.add(MetadataType.HUMIDITY);
+ tagsList2.add(MetadataType.MEDIA_STATION);
+ tagsList2.add(MetadataType.MEDIA_ALBUM);
+ assertEquals(tags.getMainField1(), tagsList);
+ assertEquals(tags.getMainField2(), tagsList2);
+
+ // For some obscurity, lets try setting just fields 2 and 4 for a 2 line display
+ textAndGraphicManager.setTextField1(null);
+ textAndGraphicManager.setTextField3(null);
+ textAndGraphicManager.setTextField1Type(null);
+ textAndGraphicManager.setTextField3Type(null);
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "Wednesday");
+ assertEquals(assembledShow.getMainField2(), "Dudes");
+
+ // And 3 fields without setting 1
+ textAndGraphicManager.setTextField3("My");
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "Wednesday");
+ assertEquals(assembledShow.getMainField2(), "My - Dudes");
+
+ // test tags
+ tags = assembledShow.getMetadataTags();
+ tagsList = new ArrayList<>();
+ tagsList2 = new ArrayList<>();
+ tagsList.add(MetadataType.CURRENT_TEMPERATURE);
+ tagsList2.add(MetadataType.MEDIA_STATION);
+ assertEquals(tags.getMainField1(), tagsList);
+ assertEquals(tags.getMainField2(), tagsList2);
+ }
+
+ public void testAssemble3Lines() {
+
+ Show inputShow = new Show();
+
+ // Force it to return display with support for only 3 lines of text
+ textAndGraphicManager.displayCapabilities = getDisplayCapability(3);
+
+ textAndGraphicManager.setTextField1("It is");
+ textAndGraphicManager.setTextField1Type(MetadataType.HUMIDITY);
+
+ Show assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is");
+ assertEquals(assembledShow.getMainField2(), "");
+ assertEquals(assembledShow.getMainField3(), "");
+
+ // test tags
+ MetadataTags tags = assembledShow.getMetadataTags();
+ List<MetadataType> tagsList = new ArrayList<>();
+ tagsList.add(MetadataType.HUMIDITY);
+ assertEquals(tags.getMainField1(), tagsList);
+
+ textAndGraphicManager.setTextField2("Wednesday");
+ textAndGraphicManager.setTextField2Type(MetadataType.CURRENT_TEMPERATURE);
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is");
+ assertEquals(assembledShow.getMainField2(), "Wednesday");
+ assertEquals(assembledShow.getMainField3(), "");
+
+ // test tags
+ tags = assembledShow.getMetadataTags();
+ tagsList = new ArrayList<>();
+ List<MetadataType> tagsList2 = new ArrayList<>();
+ tagsList.add(MetadataType.HUMIDITY);
+ tagsList2.add(MetadataType.CURRENT_TEMPERATURE);
+ assertEquals(tags.getMainField1(), tagsList);
+ assertEquals(tags.getMainField2(), tagsList2);
+
+ textAndGraphicManager.setTextField3("My");
+ textAndGraphicManager.setTextField3Type(MetadataType.MEDIA_ALBUM);
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is");
+ assertEquals(assembledShow.getMainField2(), "Wednesday");
+ assertEquals(assembledShow.getMainField3(), "My");
+
+ // test tags
+ tags = assembledShow.getMetadataTags();
+ tagsList = new ArrayList<>();
+ tagsList2 = new ArrayList<>();
+ List<MetadataType> tagsList3 = new ArrayList<>();
+ tagsList.add(MetadataType.HUMIDITY);
+ tagsList2.add(MetadataType.CURRENT_TEMPERATURE);
+ tagsList3.add(MetadataType.MEDIA_ALBUM);
+ assertEquals(tags.getMainField1(), tagsList);
+ assertEquals(tags.getMainField2(), tagsList2);
+ assertEquals(tags.getMainField3(), tagsList3);
+
+ textAndGraphicManager.setTextField4("Dudes");
+ textAndGraphicManager.setTextField4Type(MetadataType.MEDIA_STATION);
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is");
+ assertEquals(assembledShow.getMainField2(), "Wednesday");
+ assertEquals(assembledShow.getMainField3(), "My - Dudes");
+
+ // test tags
+ tags = assembledShow.getMetadataTags();
+ tagsList = new ArrayList<>();
+ tagsList2 = new ArrayList<>();
+ tagsList3 = new ArrayList<>();
+ tagsList.add(MetadataType.HUMIDITY);
+ tagsList2.add(MetadataType.CURRENT_TEMPERATURE);
+ tagsList3.add(MetadataType.MEDIA_ALBUM);
+ tagsList3.add(MetadataType.MEDIA_STATION);
+ assertEquals(tags.getMainField1(), tagsList);
+ assertEquals(tags.getMainField2(), tagsList2);
+ assertEquals(tags.getMainField3(), tagsList3);
+
+ // Someone might not want to set the fields in order? We should handle that
+ textAndGraphicManager.setTextField1(null);
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ try {
+ System.out.println(assembledShow.serializeJSON().toString());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ assertEquals(assembledShow.getMainField2(), "Wednesday");
+ assertEquals(assembledShow.getMainField3(), "My - Dudes");
+ }
+
+ public void testAssemble4Lines() {
+
+ Show inputShow = new Show();
+
+ // Force it to return display with support for only 4 lines of text
+ textAndGraphicManager.displayCapabilities = getDisplayCapability(4);
+
+ textAndGraphicManager.setTextField1("It is");
+ textAndGraphicManager.setTextField1Type(MetadataType.HUMIDITY);
+
+ Show assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+
+ assertEquals(assembledShow.getMainField1(), "It is");
+ assertEquals(assembledShow.getMainField2(), "");
+ assertEquals(assembledShow.getMainField3(), "");
+ assertEquals(assembledShow.getMainField4(), "");
+
+ // test tags
+ MetadataTags tags = assembledShow.getMetadataTags();
+ List<MetadataType> tagsList = new ArrayList<>();
+ tagsList.add(MetadataType.HUMIDITY);
+ assertEquals(tags.getMainField1(), tagsList);
+
+ textAndGraphicManager.setTextField2("Wednesday");
+ textAndGraphicManager.setTextField2Type(MetadataType.CURRENT_TEMPERATURE);
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is");
+ assertEquals(assembledShow.getMainField2(), "Wednesday");
+ assertEquals(assembledShow.getMainField3(), "");
+ assertEquals(assembledShow.getMainField4(), "");
+
+ // test tags
+ tags = assembledShow.getMetadataTags();
+ tagsList = new ArrayList<>();
+ List<MetadataType> tagsList2 = new ArrayList<>();
+ tagsList.add(MetadataType.HUMIDITY);
+ tagsList2.add(MetadataType.CURRENT_TEMPERATURE);
+ assertEquals(tags.getMainField1(), tagsList);
+ assertEquals(tags.getMainField2(), tagsList2);
+
+ textAndGraphicManager.setTextField3("My");
+ textAndGraphicManager.setTextField3Type(MetadataType.MEDIA_ALBUM);
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is");
+ assertEquals(assembledShow.getMainField2(), "Wednesday");
+ assertEquals(assembledShow.getMainField3(), "My");
+ assertEquals(assembledShow.getMainField4(), "");
+
+ // test tags
+ tags = assembledShow.getMetadataTags();
+ tagsList = new ArrayList<>();
+ tagsList2 = new ArrayList<>();
+ List<MetadataType> tagsList3 = new ArrayList<>();
+ tagsList.add(MetadataType.HUMIDITY);
+ tagsList2.add(MetadataType.CURRENT_TEMPERATURE);
+ tagsList3.add(MetadataType.MEDIA_ALBUM);
+ assertEquals(tags.getMainField1(), tagsList);
+ assertEquals(tags.getMainField2(), tagsList2);
+ assertEquals(tags.getMainField3(), tagsList3);
+
+ textAndGraphicManager.setTextField4("Dudes");
+ textAndGraphicManager.setTextField4Type(MetadataType.MEDIA_STATION);
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is");
+ assertEquals(assembledShow.getMainField2(), "Wednesday");
+ assertEquals(assembledShow.getMainField3(), "My");
+ assertEquals(assembledShow.getMainField4(), "Dudes");
+
+ // test tags
+ tags = assembledShow.getMetadataTags();
+ tagsList = new ArrayList<>();
+ tagsList2 = new ArrayList<>();
+ tagsList3 = new ArrayList<>();
+ List<MetadataType> tagsList4 = new ArrayList<>();
+ tagsList.add(MetadataType.HUMIDITY);
+ tagsList2.add(MetadataType.CURRENT_TEMPERATURE);
+ tagsList3.add(MetadataType.MEDIA_ALBUM);
+ tagsList4.add(MetadataType.MEDIA_STATION);
+ assertEquals(tags.getMainField1(), tagsList);
+ assertEquals(tags.getMainField2(), tagsList2);
+ assertEquals(tags.getMainField3(), tagsList3);
+ assertEquals(tags.getMainField4(), tagsList4);
+
+ // try just setting line 1 and 4
+ textAndGraphicManager.setTextField2(null);
+ textAndGraphicManager.setTextField3(null);
+ textAndGraphicManager.setTextField2Type(null);
+ textAndGraphicManager.setTextField3Type(null);
+
+ assembledShow = textAndGraphicManager.assembleShowText(inputShow);
+ assertEquals(assembledShow.getMainField1(), "It is");
+ assertEquals(assembledShow.getMainField2(), "");
+ assertEquals(assembledShow.getMainField3(), "");
+ assertEquals(assembledShow.getMainField4(), "Dudes");
+
+ // test tags
+ tags = assembledShow.getMetadataTags();
+ tagsList = new ArrayList<>();
+ tagsList4 = new ArrayList<>();
+ tagsList.add(MetadataType.HUMIDITY);
+ tagsList4.add(MetadataType.MEDIA_STATION);
+ assertEquals(tags.getMainField1(), tagsList);
+ assertEquals(tags.getMainField4(), tagsList4);
+ }
+
+ public void testMediaTrackTextField() {
+
+ String songTitle = "Wild For The Night";
+ textAndGraphicManager.setMediaTrackTextField(songTitle);
+ assertEquals(textAndGraphicManager.getMediaTrackTextField(), songTitle);
+ }
+
+ public void testAlignment() {
+
+ textAndGraphicManager.setTextAlignment(TextAlignment.LEFT_ALIGNED);
+ assertEquals(textAndGraphicManager.getTextAlignment(), TextAlignment.LEFT_ALIGNED);
+ }
+
+ public void testExtractTextFromShow(){
+
+ Show mainShow = new Show();
+ mainShow.setMainField1("test");
+ mainShow.setMainField3("Sauce");
+ mainShow.setMainField4("");
+
+ Show newShow = textAndGraphicManager.extractTextFromShow(mainShow);
+
+ assertEquals(newShow.getMainField1(), "test");
+ assertEquals(newShow.getMainField3(), "Sauce");
+ assertEquals(newShow.getMainField4(), "");
+ assertNull(newShow.getMainField2());
+ }
+
+ // TEST IMAGES
+
+ public void testSetPrimaryGraphic() {
+ textAndGraphicManager.setPrimaryGraphic(testArtwork);
+ assertEquals(textAndGraphicManager.getPrimaryGraphic(), testArtwork);
+ }
+
+ public void testSetSecondaryGraphic() {
+ textAndGraphicManager.setSecondaryGraphic(testArtwork);
+ assertEquals(textAndGraphicManager.getSecondaryGraphic(), testArtwork);
+ }
+
+ // TEST DISPOSE
+
+ public void testDispose() {
+ textAndGraphicManager.dispose();
+
+ assertNull(textAndGraphicManager.getTextField1());
+ assertNull(textAndGraphicManager.getTextField2());
+ assertNull(textAndGraphicManager.getTextField3());
+ assertNull(textAndGraphicManager.getTextField4());
+ assertNull(textAndGraphicManager.getMediaTrackTextField());
+ assertNull(textAndGraphicManager.getPrimaryGraphic());
+ assertNull(textAndGraphicManager.getSecondaryGraphic());
+ assertNull(textAndGraphicManager.getTextAlignment());
+ assertNull(textAndGraphicManager.getTextField1Type());
+ assertNull(textAndGraphicManager.getTextField2Type());
+ assertNull(textAndGraphicManager.getTextField3Type());
+ assertNull(textAndGraphicManager.getTextField4Type());
+ assertNull(textAndGraphicManager.getBlankArtwork());
+ assertNull(textAndGraphicManager.currentScreenData);
+ assertNull(textAndGraphicManager.inProgressUpdate);
+ assertNull(textAndGraphicManager.queuedImageUpdate);
+ assertFalse(textAndGraphicManager.hasQueuedUpdate);
+ assertNull(textAndGraphicManager.displayCapabilities);
+ assertFalse(textAndGraphicManager.isDirty);
+ assertEquals(textAndGraphicManager.getState(), BaseSubManager.SHUTDOWN);
+ }
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/managers/video/VideoStreamManagerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/video/VideoStreamManagerTests.java
new file mode 100644
index 000000000..e0febdb51
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/managers/video/VideoStreamManagerTests.java
@@ -0,0 +1,282 @@
+package com.smartdevicelink.managers.video;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.view.Display;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.smartdevicelink.AndroidTestCase2;
+import com.smartdevicelink.managers.CompletionListener;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.interfaces.ISdlServiceListener;
+import com.smartdevicelink.proxy.interfaces.IVideoStreamListener;
+import com.smartdevicelink.proxy.interfaces.OnSystemCapabilityListener;
+import com.smartdevicelink.proxy.rpc.OnHMIStatus;
+import com.smartdevicelink.proxy.rpc.OnTouchEvent;
+import com.smartdevicelink.proxy.rpc.TouchEvent;
+import com.smartdevicelink.proxy.rpc.enums.HMILevel;
+import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
+import com.smartdevicelink.proxy.rpc.enums.TouchType;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
+import com.smartdevicelink.streaming.video.SdlRemoteDisplay;
+import com.smartdevicelink.streaming.video.VideoStreamingParameters;
+import com.smartdevicelink.test.Test;
+import com.smartdevicelink.util.Version;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * This is a unit test class for the SmartDeviceLink video streaming manager class :
+ * {@link VideoStreamManager}
+ */
+public class VideoStreamManagerTests extends AndroidTestCase2 {
+ public static final String TAG = "VideoStreamManagerTests";
+ private Context mTestContext;
+ private static boolean touchEventOccured = false;
+
+ // SETUP / HELPERS
+
+ @Override
+ public void setUp() throws Exception{
+ super.setUp();
+ mTestContext = this.getContext();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ // TEST CLASSES
+
+ public static class TestPresentation extends SdlRemoteDisplay {
+ View simulatedView = new View(this.getContext());
+
+ public TestPresentation(Context context, Display display) {
+ super(context, display);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(simulatedView);
+ }
+
+ @Override
+ public boolean onTouchEvent(@NonNull MotionEvent event) {
+ touchEventOccured = true;
+ return super.onTouchEvent(event);
+ }
+ }
+
+ // TESTS
+
+ public void testInitialization(){
+ ISdl internalInterface = mock(ISdl.class);
+ when(internalInterface.getProtocolVersion()).thenReturn(new Version(5,1,0));
+
+ Answer<Void> onAddServiceListener = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ SessionType sessionType = (SessionType) args[0];
+ ISdlServiceListener sdlServiceListener = (ISdlServiceListener) args[1];
+ assertEquals(sessionType, SessionType.NAV);
+ assertNotNull(sdlServiceListener);
+ return null;
+ }
+ };
+
+ doAnswer(onAddServiceListener).when(internalInterface).addServiceListener(any(SessionType.class), any(ISdlServiceListener.class));
+
+ VideoStreamManager videoStreamManager = new VideoStreamManager(internalInterface);
+ videoStreamManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertTrue(success);
+ }
+ });
+ }
+
+ public void testHMILevelNotFull(){
+ ISdl internalInterface = mock(ISdl.class);
+
+ when(internalInterface.getProtocolVersion()).thenReturn((new Version(5,0,0)));
+ when(internalInterface.isCapabilitySupported(SystemCapabilityType.VIDEO_STREAMING)).thenReturn(true);
+
+ final VideoStreamManager videoStreamManager = new VideoStreamManager(internalInterface);
+ videoStreamManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertNull(videoStreamManager.startVideoService(
+ new VideoStreamingParameters(), false));
+ }
+ });
+ }
+
+ public void testRemoteDisplayStream(){
+ ISdl internalInterface = mock(ISdl.class);
+
+ final Set<Object> listenerSet = new HashSet<>();
+
+ when(internalInterface.getProtocolVersion()).thenReturn(new Version(5,0,0));
+ when(internalInterface.isCapabilitySupported(SystemCapabilityType.VIDEO_STREAMING)).thenReturn(true);
+
+ Answer<Void> onGetCapability = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ OnSystemCapabilityListener systemCapabilityListener = (OnSystemCapabilityListener) args[1];
+ systemCapabilityListener.onCapabilityRetrieved(Test.GENERAL_VIDEOSTREAMINGCAPABILITY);
+ return null;
+ }
+ };
+
+ doAnswer(onGetCapability).when(internalInterface).getCapability(eq(SystemCapabilityType.VIDEO_STREAMING), any(OnSystemCapabilityListener.class));
+
+ Answer<Void> onAddServiceListener = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ listenerSet.add(args[1]);
+ return null;
+ }
+ };
+
+ doAnswer(onAddServiceListener).when(internalInterface).addServiceListener(eq(SessionType.NAV), any(ISdlServiceListener.class));
+
+ final OnRPCNotificationListener[] hmiListener = {null};
+
+ Answer<Void> onAddHMIListener = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ hmiListener[0] = (OnRPCNotificationListener) args[1];
+ listenerSet.add(args[1]);
+ return null;
+ }
+ };
+
+ doAnswer(onAddHMIListener).when(internalInterface).addOnRPCNotificationListener(eq(FunctionID.ON_HMI_STATUS), any(OnRPCNotificationListener.class));
+
+ Answer<Void> onAddTouchListener = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ listenerSet.add(args[1]);
+ return null;
+ }
+ };
+
+ doAnswer(onAddTouchListener).when(internalInterface).addOnRPCNotificationListener(eq(FunctionID.ON_TOUCH_EVENT), any(OnRPCNotificationListener.class));
+
+ Answer<Void> onRemoveRPCNotificationListener = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ listenerSet.remove(args[1]);
+ return null;
+ }
+ };
+
+ doAnswer(onRemoveRPCNotificationListener).when(internalInterface).removeOnRPCNotificationListener(eq(FunctionID.ON_HMI_STATUS), any(OnRPCNotificationListener.class));
+ doAnswer(onRemoveRPCNotificationListener).when(internalInterface).removeOnRPCNotificationListener(eq(FunctionID.ON_TOUCH_EVENT), any(OnRPCNotificationListener.class));
+
+ Answer<Void> onRemoveServiceListener = new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ listenerSet.remove(args[1]);
+ return null;
+ }
+ };
+
+ doAnswer(onRemoveServiceListener).when(internalInterface).removeServiceListener(eq(SessionType.NAV), any(ISdlServiceListener.class));
+
+ when(internalInterface.startVideoStream(anyBoolean(), any(VideoStreamingParameters.class))).thenReturn(new IVideoStreamListener() {
+ @Override
+ public void sendFrame(byte[] data, int offset, int length, long presentationTimeUs) throws ArrayIndexOutOfBoundsException {}
+ @Override
+ public void sendFrame(ByteBuffer data, long presentationTimeUs) {}
+ });
+
+ when(internalInterface.getCapability(SystemCapabilityType.VIDEO_STREAMING)).thenReturn(Test.GENERAL_VIDEOSTREAMINGCAPABILITY);
+
+ final VideoStreamManager videoStreamManager = new VideoStreamManager(internalInterface);
+ videoStreamManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertTrue(success);
+ assertTrue(listenerSet.size() == 3);
+
+ OnHMIStatus fullNotification = new OnHMIStatus();
+ fullNotification.setHmiLevel(HMILevel.HMI_FULL);
+ hmiListener[0].onNotified(fullNotification);
+
+ videoStreamManager.startRemoteDisplayStream(mTestContext, TestPresentation.class, null, false);
+
+ //assertTrue(touchEventOccured);
+
+ videoStreamManager.dispose();
+ assertTrue(listenerSet.isEmpty());
+ }
+ });
+
+ }
+
+ public void testConvertTouchEvent(){
+ ISdl internalInterface = mock(ISdl.class);
+ when(internalInterface.getProtocolVersion()).thenReturn(new Version(5,1,0));
+
+ final VideoStreamManager videoStreamManager = new VideoStreamManager(internalInterface);
+ videoStreamManager.start(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ assertTrue(success);
+ OnTouchEvent testOnTouchEvent = new OnTouchEvent();
+ TouchEvent touchEvent = Test.GENERAL_TOUCHEVENT;
+ testOnTouchEvent.setEvent(Collections.singletonList(touchEvent));
+ testOnTouchEvent.setType(Test.GENERAL_TOUCHTYPE);
+ MotionEvent motionEvent;
+
+ // Touch one pointer (100)
+ motionEvent = videoStreamManager.convertTouchEvent(testOnTouchEvent);
+ assertEquals(motionEvent.getAction(), MotionEvent.ACTION_DOWN);
+
+ // Touch another pointer (101) without release
+ touchEvent.setId(Test.GENERAL_INT + 1);
+ testOnTouchEvent.setEvent(Collections.singletonList(touchEvent));
+ motionEvent = videoStreamManager.convertTouchEvent(testOnTouchEvent);
+ assertEquals(motionEvent.getAction(), MotionEvent.ACTION_POINTER_DOWN);
+
+ // Release one of the pointers (101)
+ testOnTouchEvent.setType(TouchType.END);
+ motionEvent = videoStreamManager.convertTouchEvent(testOnTouchEvent);
+ assertEquals(motionEvent.getAction(), MotionEvent.ACTION_POINTER_UP);
+
+ // Release the other pointer (100)
+ touchEvent.setId(Test.GENERAL_INT);
+ testOnTouchEvent.setEvent(Collections.singletonList(touchEvent));
+ motionEvent = videoStreamManager.convertTouchEvent(testOnTouchEvent);
+ assertEquals(motionEvent.getAction(), MotionEvent.ACTION_UP);
+ }
+ });
+ }
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/protocol/SdlPacketTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/protocol/SdlPacketTests.java
index c3e39ce5a..a9bc03bb0 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/protocol/SdlPacketTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/protocol/SdlPacketTests.java
@@ -1,14 +1,13 @@
package com.smartdevicelink.protocol;
-import android.test.AndroidTestCase;
-
import com.livio.BSON.BsonEncoder;
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.protocol.enums.ControlFrameTags;
import java.util.HashMap;
import java.util.Map;
-public class SdlPacketTests extends AndroidTestCase {
+public class SdlPacketTests extends AndroidTestCase2 {
//TODO: Add tests to cover other parts of SdlPacket class
// Test variables
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/protocol/SdlProtocolTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/protocol/SdlProtocolTests.java
new file mode 100644
index 000000000..675ecb4f2
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/protocol/SdlProtocolTests.java
@@ -0,0 +1,372 @@
+package com.smartdevicelink.protocol;
+
+import android.util.Log;
+
+import com.smartdevicelink.AndroidTestCase2;
+import com.smartdevicelink.SdlConnection.SdlConnection;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.protocol.SdlProtocol.MessageFrameAssembler;
+import com.smartdevicelink.security.SdlSecurityBase;
+import com.smartdevicelink.streaming.video.VideoStreamingParameters;
+import com.smartdevicelink.test.SampleRpc;
+import com.smartdevicelink.test.SdlUnitTestContants;
+import com.smartdevicelink.transport.BaseTransportConfig;
+import com.smartdevicelink.transport.MultiplexTransportConfig;
+import com.smartdevicelink.transport.RouterServiceValidator;
+
+import junit.framework.Assert;
+
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.Method;
+import java.util.List;
+
+import static org.mockito.Mockito.mock;
+
+public class SdlProtocolTests extends AndroidTestCase2 {
+
+ int max_int = 2147483647;
+ byte[] payload;
+ MultiplexTransportConfig config;
+ SdlProtocol protocol;
+
+ ISdlProtocol defaultListener = mock(ISdlProtocol.class);
+
+ public static class DidReceiveListener implements ISdlProtocol{
+ boolean didReceive = false;
+
+ public void reset(){
+ didReceive = false;
+ }
+ public boolean didReceive(){
+ return didReceive;
+ }
+ @Override
+ public void onProtocolMessageBytesToSend(SdlPacket packet) {}
+ @Override
+ public void onProtocolMessageReceived(ProtocolMessage msg) {
+ didReceive = true;
+ Log.d("DidReceiveListener", "RPC Type: " + msg.getRPCType());
+ Log.d("DidReceiveListener", "Function Id: " + msg.getFunctionID());
+ Log.d("DidReceiveListener", "JSON Size: " + msg.getJsonSize());
+ }
+ @Override
+ public void onProtocolSessionStarted(SessionType sessionType,byte sessionID, byte version, String correlationID, int hashID,boolean isEncrypted){}
+ @Override
+ public void onProtocolSessionNACKed(SessionType sessionType,byte sessionID, byte version, String correlationID, List<String> rejectedParams) {}
+ @Override
+ public void onProtocolSessionEnded(SessionType sessionType,byte sessionID, String correlationID) {}
+ @Override
+ public void onProtocolSessionEndedNACKed(SessionType sessionType,byte sessionID, String correlationID) {}
+ @Override
+ public void onProtocolHeartbeat(SessionType sessionType, byte sessionID) {}
+ @Override
+ public void onProtocolHeartbeatACK(SessionType sessionType,byte sessionID) {}
+ @Override
+ public void onProtocolServiceDataACK(SessionType sessionType,int dataSize, byte sessionID) {}
+ @Override
+ public void onResetOutgoingHeartbeat(SessionType sessionType,byte sessionID) {}
+ @Override
+ public void onResetIncomingHeartbeat(SessionType sessionType,byte sessionID) {}
+ @Override
+ public void onProtocolError(String info, Exception e) {}
+ @Override
+ public byte getSessionId() {return 0;}
+ @Override
+ public void shutdown(String info) {}
+ @Override
+ public void onTransportDisconnected(String info, boolean altTransportAvailable, MultiplexTransportConfig transportConfig) {}
+ @Override
+ public SdlSecurityBase getSdlSecurity() {return null;}
+ @Override
+ public VideoStreamingParameters getDesiredVideoParams() {return null; }
+ @Override
+ public void setAcceptedVideoParams(VideoStreamingParameters acceptedVideoParams) {}
+ @Override
+ public void stopStream(SessionType serviceType) {}
+ };
+
+ DidReceiveListener onProtocolMessageReceivedListener = new DidReceiveListener();
+
+
+ public void setUp(){
+ config = new MultiplexTransportConfig(this.mContext, SdlUnitTestContants.TEST_APP_ID);
+ protocol = new SdlProtocol(defaultListener,config);
+ }
+
+
+ public void testBase(){
+ SdlProtocol sdlProtocol = new SdlProtocol(defaultListener,config);
+
+ }
+
+ public void testVersion(){
+ SdlProtocol sdlProtocol = new SdlProtocol(defaultListener,config);
+
+ sdlProtocol.setVersion((byte)0x01);
+ assertEquals((byte)0x01,sdlProtocol.getProtocolVersion().getMajor());
+
+ sdlProtocol = new SdlProtocol(defaultListener,config);
+ sdlProtocol.setVersion((byte)0x02);
+ assertEquals((byte)0x02,sdlProtocol.getProtocolVersion().getMajor());
+
+ sdlProtocol = new SdlProtocol(defaultListener,config);
+ sdlProtocol.setVersion((byte)0x03);
+ assertEquals((byte)0x03,sdlProtocol.getProtocolVersion().getMajor());
+
+ sdlProtocol = new SdlProtocol(defaultListener,config);
+ sdlProtocol.setVersion((byte)0x04);
+ assertEquals((byte)0x04,sdlProtocol.getProtocolVersion().getMajor());
+
+ sdlProtocol = new SdlProtocol(defaultListener,config);
+ sdlProtocol.setVersion((byte)0x05);
+ assertEquals((byte)0x05,sdlProtocol.getProtocolVersion().getMajor());
+
+ //If we get newer than 5, it should fall back to 5
+ sdlProtocol = new SdlProtocol(defaultListener,config);
+ sdlProtocol.setVersion((byte)0x06);
+ assertEquals((byte)0x05,sdlProtocol.getProtocolVersion().getMajor());
+
+ //Is this right?
+ sdlProtocol = new SdlProtocol(defaultListener,config);
+ sdlProtocol.setVersion((byte)0x00);
+ assertEquals((byte)0x01,sdlProtocol.getProtocolVersion().getMajor());
+ }
+
+ public void testMtu(){
+ SdlProtocol sdlProtocol = new SdlProtocol(defaultListener,config);
+
+ sdlProtocol.setVersion((byte)0x01);
+
+ try{
+ assertEquals(sdlProtocol.getMtu(), 1500-8);
+
+ //Version 2
+ sdlProtocol.setVersion((byte)0x02);
+ assertEquals(sdlProtocol.getMtu(), 1500-12);
+
+ //Version 3
+ sdlProtocol.setVersion((byte)0x03);
+ assertEquals(sdlProtocol.getMtu(), 131072);
+
+ //Version 4
+ sdlProtocol.setVersion((byte)0x04);
+ assertEquals(sdlProtocol.getMtu(), 131072);
+
+ //Version 5
+ sdlProtocol.setVersion((byte)0x05);
+ assertEquals(sdlProtocol.getMtu(), 131072);
+
+ //Version 5+
+ sdlProtocol.setVersion((byte)0x06);
+ assertEquals(sdlProtocol.getMtu(), 131072);
+
+ }catch(Exception e){
+ Assert.fail("Exceptin during reflection");
+ }
+
+ }
+
+ public void testHandleFrame(){
+ SampleRpc sampleRpc = new SampleRpc(4);
+ SdlProtocol sdlProtocol = new SdlProtocol(defaultListener,config);
+ MessageFrameAssembler assembler = sdlProtocol.new MessageFrameAssembler();
+ try{
+ assembler.handleFrame(sampleRpc.toSdlPacket());
+ }catch(Exception e){
+ Assert.fail("Exceptin during handleFrame - " + e.toString());
+ }
+ }
+ public void testHandleFrameCorrupt(){
+ SampleRpc sampleRpc = new SampleRpc(4);
+ BinaryFrameHeader header = sampleRpc.getBinaryFrameHeader(true);
+ header.setJsonSize(Integer.MAX_VALUE);
+ sampleRpc.setBinaryFrameHeader(header);
+ SdlProtocol sdlProtocol = new SdlProtocol(defaultListener,config);
+ MessageFrameAssembler assembler = sdlProtocol.new MessageFrameAssembler();
+ try{
+ assembler.handleFrame(sampleRpc.toSdlPacket());
+ }catch(Exception e){
+ Assert.fail("Exceptin during handleFrame - " + e.toString());
+ }
+ }
+
+ public void testHandleSingleFrameMessageFrame(){
+ SampleRpc sampleRpc = new SampleRpc(4);
+ SdlProtocol sdlProtocol = new SdlProtocol(defaultListener,config);
+ MessageFrameAssembler assembler = sdlProtocol.new MessageFrameAssembler();
+
+
+ try{
+ Method method = assembler.getClass().getDeclaredMethod ("handleSingleFrameMessageFrame", SdlPacket.class);
+ method.setAccessible(true);
+ method.invoke (assembler, sampleRpc.toSdlPacket());
+ }catch(Exception e){
+ Assert.fail("Exceptin during handleSingleFrameMessageFrame - " + e.toString());
+ }
+ }
+
+ public void testHandleSingleFrameMessageFrameCorruptBfh(){
+ SampleRpc sampleRpc = new SampleRpc(4);
+
+ //Create a corrupted header
+ BinaryFrameHeader header = sampleRpc.getBinaryFrameHeader(true);
+ header.setJsonSize(5);
+ header.setJsonData(new byte[5]);
+ header.setJsonSize(Integer.MAX_VALUE);
+ sampleRpc.setBinaryFrameHeader(header);
+
+ SdlPacket packet = sampleRpc.toSdlPacket();
+
+ BinaryFrameHeader binFrameHeader = BinaryFrameHeader.parseBinaryHeader(packet.payload);
+ assertNull(binFrameHeader);
+
+ SdlProtocol sdlProtocol = new SdlProtocol(defaultListener,config);
+
+
+ sdlProtocol.handlePacketReceived(packet);
+ assertFalse(onProtocolMessageReceivedListener.didReceive());
+
+ onProtocolMessageReceivedListener.reset();
+ SdlProtocol.MessageFrameAssembler assembler =sdlProtocol.getFrameAssemblerForFrame(packet);// sdlProtocol.new MessageFrameAssembler();
+ assertNotNull(assembler);
+ assembler.handleFrame(packet);
+ assertFalse(onProtocolMessageReceivedListener.didReceive());
+
+ try{
+ Method method = assembler.getClass().getDeclaredMethod("handleSingleFrameMessageFrame", SdlPacket.class);
+ method.setAccessible(true);
+ method.invoke (assembler, sampleRpc.toSdlPacket());
+ }catch(Exception e){
+ Assert.fail("Exceptin during handleSingleFrameMessageFrame - " + e.toString());
+ }
+ }
+
+
+
+
+
+ public void testNormalCase(){
+ setUp();
+ payload = new byte[]{0x00,0x02,0x05,0x01,0x01,0x01,0x05,0x00};
+ byte sessionID = 1, version = 1;
+ int messageID = 1;
+ boolean encrypted = false;
+ SdlPacket sdlPacket = SdlPacketFactory.createMultiSendDataFirst(SessionType.RPC, sessionID, messageID, version, payload, encrypted);
+ MessageFrameAssembler assembler = protocol.getFrameAssemblerForFrame(sdlPacket);
+
+ assertNotNull(assembler);
+
+ OutOfMemoryError oom_error = null;
+ NullPointerException np_exception = null;
+ try{
+ assembler.handleMultiFrameMessageFrame(sdlPacket);
+ }catch(OutOfMemoryError e){
+ oom_error = e;
+ }catch(NullPointerException z){
+ np_exception = z;
+ }catch(Exception e){
+ e.printStackTrace();
+ assertNotNull(null);
+ }
+
+ assertNull(np_exception);
+ assertNull(oom_error);
+
+ payload = new byte[23534];
+ sdlPacket = SdlPacketFactory.createMultiSendDataRest(SessionType.RPC, sessionID, payload.length, (byte) 3, messageID, version, payload, 0, 1500, encrypted);
+ assembler = protocol.getFrameAssemblerForFrame(sdlPacket);
+ try{
+ assembler.handleMultiFrameMessageFrame(sdlPacket);
+ }catch(OutOfMemoryError e){
+ oom_error = e;
+ }catch(NullPointerException z){
+ np_exception = z;
+ }catch(Exception e){
+ assertNotNull(null);
+ }
+
+ assertNull(np_exception);
+ assertNull(oom_error);
+ }
+
+ public void testOverallocatingAccumulator(){
+ setUp();
+ ByteArrayOutputStream builder = new ByteArrayOutputStream();
+ for(int i = 0; i < 8; i++){
+ builder.write(0x0F);
+ }
+ payload = builder.toByteArray();
+ byte sessionID = 1, version = 1;
+ int messageID = 1;
+ boolean encrypted = false;
+ SdlPacket sdlPacket = SdlPacketFactory.createMultiSendDataFirst(SessionType.RPC, sessionID, messageID, version, payload, encrypted);
+ MessageFrameAssembler assembler = protocol.getFrameAssemblerForFrame(sdlPacket);
+
+ OutOfMemoryError oom_error = null;
+ NullPointerException np_exception = null;
+ try{
+ assembler.handleMultiFrameMessageFrame(sdlPacket);
+ }catch(OutOfMemoryError e){
+ oom_error = e;
+ }catch(NullPointerException z){
+ np_exception = z;
+ }catch(Exception e){
+ assertNotNull(null);
+ }
+
+ assertNull(np_exception);
+ assertNull(oom_error);
+
+ payload = new byte[23534];
+ sdlPacket = SdlPacketFactory.createMultiSendDataRest(SessionType.RPC, sessionID, payload.length, (byte) 3, messageID, version, payload, 0, 1500, encrypted);
+ assembler = protocol.getFrameAssemblerForFrame(sdlPacket);
+
+ try{
+ assembler.handleMultiFrameMessageFrame(sdlPacket);
+ }catch(OutOfMemoryError e){
+ oom_error = e;
+ }catch(NullPointerException z){
+ np_exception = z;
+ }catch(Exception e){
+ assertNotNull(null);
+ }
+
+ assertNull(np_exception);
+ assertNull(oom_error);
+
+ }
+
+ protected class SdlConnectionTestClass extends SdlConnection {
+ protected boolean connected = false;
+ public SdlConnectionTestClass(BaseTransportConfig transportConfig) {
+ super(transportConfig);
+ }
+
+ protected SdlConnectionTestClass(BaseTransportConfig transportConfig,RouterServiceValidator rsvp){
+ super(transportConfig,rsvp);
+ }
+
+ @Override
+ public void onTransportConnected() {
+ super.onTransportConnected();
+ connected = true;
+ }
+
+ @Override
+ public void onTransportDisconnected(String info) {
+ connected = false;
+ //Grab a currently running router service
+ RouterServiceValidator rsvp2 = new RouterServiceValidator(mContext);
+ rsvp2.setFlags(RouterServiceValidator.FLAG_DEBUG_NONE);
+ assertTrue(rsvp2.validate());
+ assertNotNull(rsvp2.getService());
+ super.onTransportDisconnected(info);
+ }
+
+ @Override
+ public void onTransportError(String info, Exception e) {
+ connected = false;
+ super.onTransportError(info, e);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/protocol/WiProProtocolTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/protocol/WiProProtocolTests.java
index 1055f5deb..bec4a6d92 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/protocol/WiProProtocolTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/protocol/WiProProtocolTests.java
@@ -1,8 +1,9 @@
package com.smartdevicelink.protocol;
-import android.test.AndroidTestCase;
+import android.os.Bundle;
import android.util.Log;
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.SdlConnection.SdlConnection;
import com.smartdevicelink.protocol.WiProProtocol.MessageFrameAssembler;
import com.smartdevicelink.protocol.enums.SessionType;
@@ -11,18 +12,21 @@ import com.smartdevicelink.test.SdlUnitTestContants;
import com.smartdevicelink.transport.BaseTransportConfig;
import com.smartdevicelink.transport.MultiplexTransportConfig;
import com.smartdevicelink.transport.RouterServiceValidator;
+import com.smartdevicelink.transport.enums.TransportType;
import junit.framework.Assert;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* This is a unit test class for the SmartDeviceLink library project class :
* {@link com.smartdevicelink.protocol.BinaryFrameHeader}
*/
-public class WiProProtocolTests extends AndroidTestCase {
+public class WiProProtocolTests extends AndroidTestCase2 {
int max_int = 2147483647;
byte[] payload;
@@ -55,6 +59,7 @@ public class WiProProtocolTests extends AndroidTestCase {
public void onResetIncomingHeartbeat(SessionType sessionType,byte sessionID) {}
@Override
public void onProtocolError(String info, Exception e) {}
+
};
public static class DidReceiveListener implements IProtocolListener{
boolean didReceive = false;
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/BaseRpcTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/BaseRpcTests.java
index c30f26a7f..8b9d5f3f7 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/BaseRpcTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/BaseRpcTests.java
@@ -6,13 +6,12 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
-import android.test.AndroidTestCase;
-
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.proxy.RPCMessage;
import com.smartdevicelink.proxy.RPCRequest;
import com.smartdevicelink.proxy.RPCResponse;
-public abstract class BaseRpcTests extends AndroidTestCase {
+public abstract class BaseRpcTests extends AndroidTestCase2 {
public static final int SDL_VERSION_UNDER_TEST = Config.SDL_VERSION_UNDER_TEST;
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/Test.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/Test.java
index 68869c6a1..eaa7bf4c9 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/Test.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/Test.java
@@ -1,8 +1,12 @@
package com.smartdevicelink.test;
+import android.graphics.Color;
import android.util.Log;
+import com.smartdevicelink.managers.lockscreen.LockScreenConfig;
import com.smartdevicelink.proxy.TTSChunkFactory;
+import com.smartdevicelink.proxy.rpc.AudioControlCapabilities;
+import com.smartdevicelink.proxy.rpc.AudioControlData;
import com.smartdevicelink.proxy.rpc.AudioPassThruCapabilities;
import com.smartdevicelink.proxy.rpc.ButtonCapabilities;
import com.smartdevicelink.proxy.rpc.Choice;
@@ -12,37 +16,53 @@ import com.smartdevicelink.proxy.rpc.Coordinate;
import com.smartdevicelink.proxy.rpc.DIDResult;
import com.smartdevicelink.proxy.rpc.DeviceInfo;
import com.smartdevicelink.proxy.rpc.DisplayCapabilities;
+import com.smartdevicelink.proxy.rpc.EqualizerSettings;
import com.smartdevicelink.proxy.rpc.HMICapabilities;
import com.smartdevicelink.proxy.rpc.HMIPermissions;
+import com.smartdevicelink.proxy.rpc.HMISettingsControlCapabilities;
+import com.smartdevicelink.proxy.rpc.HMISettingsControlData;
import com.smartdevicelink.proxy.rpc.HapticRect;
import com.smartdevicelink.proxy.rpc.Image;
import com.smartdevicelink.proxy.rpc.ImageField;
import com.smartdevicelink.proxy.rpc.ImageResolution;
import com.smartdevicelink.proxy.rpc.KeyboardProperties;
+import com.smartdevicelink.proxy.rpc.LightCapabilities;
+import com.smartdevicelink.proxy.rpc.LightControlCapabilities;
+import com.smartdevicelink.proxy.rpc.LightControlData;
+import com.smartdevicelink.proxy.rpc.LightState;
import com.smartdevicelink.proxy.rpc.LocationDetails;
+import com.smartdevicelink.proxy.rpc.MassageCushionFirmness;
+import com.smartdevicelink.proxy.rpc.MassageModeData;
import com.smartdevicelink.proxy.rpc.MenuParams;
+import com.smartdevicelink.proxy.rpc.MetadataTags;
import com.smartdevicelink.proxy.rpc.ModuleData;
import com.smartdevicelink.proxy.rpc.NavigationCapability;
-import com.smartdevicelink.proxy.rpc.MetadataTags;
import com.smartdevicelink.proxy.rpc.OasisAddress;
import com.smartdevicelink.proxy.rpc.ParameterPermissions;
import com.smartdevicelink.proxy.rpc.PermissionItem;
import com.smartdevicelink.proxy.rpc.PhoneCapability;
import com.smartdevicelink.proxy.rpc.PresetBankCapabilities;
+import com.smartdevicelink.proxy.rpc.RGBColor;
import com.smartdevicelink.proxy.rpc.RadioControlCapabilities;
import com.smartdevicelink.proxy.rpc.RadioControlData;
import com.smartdevicelink.proxy.rpc.RdsData;
-import com.smartdevicelink.proxy.rpc.RemoteControlCapabilities;
import com.smartdevicelink.proxy.rpc.Rectangle;
+import com.smartdevicelink.proxy.rpc.RemoteControlCapabilities;
import com.smartdevicelink.proxy.rpc.ScreenParams;
import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
+import com.smartdevicelink.proxy.rpc.SeatControlCapabilities;
+import com.smartdevicelink.proxy.rpc.SeatControlData;
+import com.smartdevicelink.proxy.rpc.SeatMemoryAction;
import com.smartdevicelink.proxy.rpc.SingleTireStatus;
+import com.smartdevicelink.proxy.rpc.SisData;
import com.smartdevicelink.proxy.rpc.SoftButton;
import com.smartdevicelink.proxy.rpc.SoftButtonCapabilities;
import com.smartdevicelink.proxy.rpc.StartTime;
+import com.smartdevicelink.proxy.rpc.StationIDNumber;
import com.smartdevicelink.proxy.rpc.SystemCapability;
import com.smartdevicelink.proxy.rpc.TTSChunk;
import com.smartdevicelink.proxy.rpc.Temperature;
+import com.smartdevicelink.proxy.rpc.TemplateColorScheme;
import com.smartdevicelink.proxy.rpc.TextField;
import com.smartdevicelink.proxy.rpc.TouchCoord;
import com.smartdevicelink.proxy.rpc.TouchEvent;
@@ -56,6 +76,7 @@ import com.smartdevicelink.proxy.rpc.VrHelpItem;
import com.smartdevicelink.proxy.rpc.enums.AmbientLightStatus;
import com.smartdevicelink.proxy.rpc.enums.AppHMIType;
import com.smartdevicelink.proxy.rpc.enums.AppInterfaceUnregisteredReason;
+import com.smartdevicelink.proxy.rpc.enums.AudioStreamingIndicator;
import com.smartdevicelink.proxy.rpc.enums.AudioStreamingState;
import com.smartdevicelink.proxy.rpc.enums.AudioType;
import com.smartdevicelink.proxy.rpc.enums.BitsPerSample;
@@ -69,12 +90,15 @@ import com.smartdevicelink.proxy.rpc.enums.ComponentVolumeStatus;
import com.smartdevicelink.proxy.rpc.enums.DefrostZone;
import com.smartdevicelink.proxy.rpc.enums.DeviceLevelStatus;
import com.smartdevicelink.proxy.rpc.enums.Dimension;
+import com.smartdevicelink.proxy.rpc.enums.DisplayMode;
import com.smartdevicelink.proxy.rpc.enums.DisplayType;
+import com.smartdevicelink.proxy.rpc.enums.DistanceUnit;
import com.smartdevicelink.proxy.rpc.enums.DriverDistractionState;
import com.smartdevicelink.proxy.rpc.enums.ECallConfirmationStatus;
import com.smartdevicelink.proxy.rpc.enums.EmergencyEventType;
import com.smartdevicelink.proxy.rpc.enums.FileType;
import com.smartdevicelink.proxy.rpc.enums.FuelCutoffStatus;
+import com.smartdevicelink.proxy.rpc.enums.FuelType;
import com.smartdevicelink.proxy.rpc.enums.GlobalProperty;
import com.smartdevicelink.proxy.rpc.enums.HMILevel;
import com.smartdevicelink.proxy.rpc.enums.HmiZoneCapabilities;
@@ -88,8 +112,14 @@ import com.smartdevicelink.proxy.rpc.enums.KeyboardLayout;
import com.smartdevicelink.proxy.rpc.enums.KeypressMode;
import com.smartdevicelink.proxy.rpc.enums.Language;
import com.smartdevicelink.proxy.rpc.enums.LayoutMode;
+import com.smartdevicelink.proxy.rpc.enums.LightName;
+import com.smartdevicelink.proxy.rpc.enums.LightStatus;
import com.smartdevicelink.proxy.rpc.enums.LockScreenStatus;
+import com.smartdevicelink.proxy.rpc.enums.MassageCushion;
+import com.smartdevicelink.proxy.rpc.enums.MassageMode;
+import com.smartdevicelink.proxy.rpc.enums.MassageZone;
import com.smartdevicelink.proxy.rpc.enums.MediaClockFormat;
+import com.smartdevicelink.proxy.rpc.enums.MetadataType;
import com.smartdevicelink.proxy.rpc.enums.ModuleType;
import com.smartdevicelink.proxy.rpc.enums.PowerModeQualificationStatus;
import com.smartdevicelink.proxy.rpc.enums.PowerModeStatus;
@@ -100,16 +130,18 @@ import com.smartdevicelink.proxy.rpc.enums.RadioState;
import com.smartdevicelink.proxy.rpc.enums.RequestType;
import com.smartdevicelink.proxy.rpc.enums.Result;
import com.smartdevicelink.proxy.rpc.enums.SamplingRate;
+import com.smartdevicelink.proxy.rpc.enums.SeatMemoryActionType;
import com.smartdevicelink.proxy.rpc.enums.SoftButtonType;
import com.smartdevicelink.proxy.rpc.enums.SpeechCapabilities;
+import com.smartdevicelink.proxy.rpc.enums.SupportedSeat;
import com.smartdevicelink.proxy.rpc.enums.SystemAction;
import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
import com.smartdevicelink.proxy.rpc.enums.SystemContext;
import com.smartdevicelink.proxy.rpc.enums.TBTState;
+import com.smartdevicelink.proxy.rpc.enums.TPMS;
import com.smartdevicelink.proxy.rpc.enums.TemperatureUnit;
import com.smartdevicelink.proxy.rpc.enums.TextAlignment;
import com.smartdevicelink.proxy.rpc.enums.TextFieldName;
-import com.smartdevicelink.proxy.rpc.enums.MetadataType;
import com.smartdevicelink.proxy.rpc.enums.TouchType;
import com.smartdevicelink.proxy.rpc.enums.TriggerSource;
import com.smartdevicelink.proxy.rpc.enums.UpdateMode;
@@ -121,6 +153,7 @@ import com.smartdevicelink.proxy.rpc.enums.VehicleDataType;
import com.smartdevicelink.proxy.rpc.enums.VentilationMode;
import com.smartdevicelink.proxy.rpc.enums.VideoStreamingCodec;
import com.smartdevicelink.proxy.rpc.enums.VideoStreamingProtocol;
+import com.smartdevicelink.proxy.rpc.enums.VideoStreamingState;
import com.smartdevicelink.proxy.rpc.enums.VrCapabilities;
import com.smartdevicelink.proxy.rpc.enums.WarningLightStatus;
import com.smartdevicelink.proxy.rpc.enums.WayPointType;
@@ -131,10 +164,12 @@ import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
+import java.util.Vector;
public class Test {
-
+
// Test Failure Messages
public static final String NULL = "Value should be null.";
public static final String MATCH = "Values should match.";
@@ -143,18 +178,20 @@ public class Test {
public static final String FALSE = "Value should be false.";
public static final String NOT_NULL = "Value should not be null.";
public static final String JSON_FAIL = "Json testing failed.";
-
+
// RPC Request/Response/Notification/Datatype Test Values
public static final int GENERAL_INT = 100;
public static final Integer GENERAL_INTEGER = 100;
public static final Long GENERAL_LONG = 100L;
public static final Turn GENERAL_TURN = new Turn();
public static final Float GENERAL_FLOAT = 100f;
- public static final Image GENERAL_IMAGE = new Image();
+ public static final Image GENERAL_IMAGE = new Image();
public static final Choice GENERAL_CHOICE = new Choice();
public static final String GENERAL_STRING = "test";
public static final Double GENERAL_DOUBLE = 10.01;
public static final boolean GENERAL_BOOLEAN = true;
+ public static final byte[] GENERAL_BYTE_ARRAY = new byte[0];
+ public static final TPMS GENERAL_TPMS = TPMS.UNKNOWN;
public static final TBTState GENERAL_TBTSTATE = TBTState.NEXT_TURN_REQUEST;
public static final FileType GENERAL_FILETYPE = FileType.BINARY;
public static final Language GENERAL_LANGUAGE = Language.EN_US;
@@ -179,9 +216,11 @@ public class Test {
public static final ButtonName GENERAL_BUTTONNAME = ButtonName.OK;
public static final UpdateMode GENERAL_UPDATEMODE = UpdateMode.RESUME;
public static final TouchCoord GENERAL_TOUCHCOORD = new TouchCoord();
+ public static final MassageModeData GENERAL_MASSAGEMODEDATA = new MassageModeData();
+ public static final MassageCushionFirmness GENERAL_MASSAGECUSHIONFIRMNESS = new MassageCushionFirmness();
public static final DisplayType GENERAL_DISPLAYTYPE = DisplayType.CID;
public static final VehicleType GENERAL_VEHICLETYPE = new VehicleType();
- public static final RequestType GENERAL_REQUESTTYPE = RequestType.AUTH_REQUEST;
+ public static final RequestType GENERAL_REQUESTTYPE = RequestType.AUTH_REQUEST;
public static final SystemAction GENERAL_SYSTEMACTION = SystemAction.DEFAULT_ACTION;
public static final CharacterSet GENERAL_CHARACTERSET = CharacterSet.CID1SET;
public static final SamplingRate GENERAL_SAMPLINGRATE = SamplingRate._8KHZ;
@@ -197,6 +236,11 @@ public class Test {
public static final SdlMsgVersion GENERAL_SDLMSGVERSION = new SdlMsgVersion();
public static final PermissionItem GENERAL_PERMISSIONITEM = new PermissionItem();
public static final SoftButtonType GENERAL_SOFTBUTTONTYPE = SoftButtonType.SBT_BOTH;
+ public static final MassageZone GENERAL_MASSAGEZONE = MassageZone.LUMBAR;
+ public static final MassageMode GENERAL_MASSAGEMODE = MassageMode.HIGH;
+ public static final MassageCushion GENERAL_MASSAGECUSHION = MassageCushion.BACK_BOLSTERS;
+ public static final SeatMemoryActionType GENERAL_SEATMEMORYACTIONTYPE = SeatMemoryActionType.SAVE;
+ public static final SupportedSeat GENERAL_SUPPORTEDSEAT = SupportedSeat.DRIVER;
public static final KeyboardLayout GENERAL_KEYBOARDLAYOUT = KeyboardLayout.QWERTY;
public static final ImageFieldName GENERAL_IMAGEFIELDNAME = ImageFieldName.graphic;
public static final HMIPermissions GENERAL_HMIPERMISSIONS = new HMIPermissions();
@@ -206,7 +250,7 @@ public class Test {
public static final PowerModeStatus GENERAL_POWERMODESTATUS = PowerModeStatus.RUNNING_2;
public static final VehicleDataType GENERAL_VEHICLEDATATYPE = VehicleDataType.VEHICLEDATA_BRAKING;
public static final InteractionMode GENERAL_INTERACTIONMODE = InteractionMode.BOTH;
- public static final ImageResolution GENERAL_IMAGERESOLUTION = new ImageResolution();
+ public static final ImageResolution GENERAL_IMAGERESOLUTION = new ImageResolution();
public static final FuelCutoffStatus GENERAL_FUELCUTOFFSTATUS = FuelCutoffStatus.NORMAL_OPERATION;
public static final CompassDirection GENERAL_COMPASSDIRECTION = CompassDirection.EAST;
public static final LockScreenStatus GENERAL_LOCKSCREENSTATUS = LockScreenStatus.REQUIRED;
@@ -214,23 +258,25 @@ public class Test {
public static final DeviceLevelStatus GENERAL_DEVICELEVELSTATUS = DeviceLevelStatus.FOUR_LEVEL_BARS;
public static final ButtonCapabilities GENERAL_BUTTONCAPABILITIES = new ButtonCapabilities();
public static final EmergencyEventType GENERAL_EMERGENCYEVENTTYPE = EmergencyEventType.FAULT;
- public static final AmbientLightStatus GENERAL_AMBIENTLIGHTSTATUS = AmbientLightStatus.NIGHT;
+ public static final AmbientLightStatus GENERAL_AMBIENTLIGHTSTATUS = AmbientLightStatus.NIGHT;
public static final SpeechCapabilities GENERAL_SPEECHCAPABILITIES = SpeechCapabilities.TEXT;
public static final WarningLightStatus GENERAL_WARNINGLIGHTSTATUS = WarningLightStatus.OFF;
- public static final KeyboardProperties GENERAL_KEYBOARDPROPERTIES = new KeyboardProperties();
+ public static final KeyboardProperties GENERAL_KEYBOARDPROPERTIES = new KeyboardProperties();
public static final PrimaryAudioSource GENERAL_PRIMARYAUDIOSOURCE = PrimaryAudioSource.BLUETOOTH_STEREO_BTST;
public static final AudioStreamingState GENERAL_AUDIOSTREAMINGSTATE = AudioStreamingState.AUDIBLE;
+ public static final VideoStreamingState GENERAL_VIDEOSTREAMINGSTATE = VideoStreamingState.STREAMABLE;
public static final DisplayCapabilities GENERAL_DISPLAYCAPABILITIES = new DisplayCapabilities();
- public static final ParameterPermissions GENERAL_PARAMETERPERMISSIONS = new ParameterPermissions();
- public static final IgnitionStableStatus GENERAL_IGNITIONSTABLESTATUS = IgnitionStableStatus.IGNITION_SWITCH_STABLE;
+ public static final ParameterPermissions GENERAL_PARAMETERPERMISSIONS = new ParameterPermissions();
+ public static final IgnitionStableStatus GENERAL_IGNITIONSTABLESTATUS = IgnitionStableStatus.IGNITION_SWITCH_STABLE;
public static final VehicleDataResultCode GENERAL_VEHICLEDATARESULTCODE = VehicleDataResultCode.IGNORED;
public static final ComponentVolumeStatus GENERAL_COMPONENTVOLUMESTATUS = ComponentVolumeStatus.LOW;
public static final PresetBankCapabilities GENERAL_PRESETBANKCAPABILITIES = new PresetBankCapabilities();
public static final VehicleDataEventStatus GENERAL_VEHCILEDATAEVENTSTATUS = VehicleDataEventStatus.YES;
public static final VehicleDataEventStatus GENERAL_VEHICLEDATAEVENTSTATUS = VehicleDataEventStatus.YES;
public static final TouchEventCapabilities GENERAL_TOUCHEVENTCAPABILITIES = new TouchEventCapabilities();
+ public static final SeatMemoryAction GENERAL_SEATMEMORYACTION = new SeatMemoryAction();
public static final SoftButtonCapabilities GENERAL_SOFTBUTTONCAPABILITIES = new SoftButtonCapabilities();
- public static final ECallConfirmationStatus GENERAL_ECALLCONFIRMATIONSTATUS = ECallConfirmationStatus.CALL_IN_PROGRESS;
+ public static final ECallConfirmationStatus GENERAL_ECALLCONFIRMATIONSTATUS = ECallConfirmationStatus.CALL_IN_PROGRESS;
public static final AudioPassThruCapabilities GENERAL_AUDIOPASSTHRUCAPABILITIES = new AudioPassThruCapabilities();
public static final PowerModeQualificationStatus GENERAL_POWERMODEQUALIFICATIONSTATUS = PowerModeQualificationStatus.POWER_MODE_OK;
public static final VehicleDataNotificationStatus GENERAL_VEHICLEDATANOTIFICATIONSTATUS = VehicleDataNotificationStatus.NORMAL;
@@ -244,31 +290,56 @@ public class Test {
public static final VideoStreamingCodec GENERAL_VIDEOSTREAMINGCODEC = VideoStreamingCodec.H264;
public static final VideoStreamingCapability GENERAL_VIDEOSTREAMINGCAPABILITY = new VideoStreamingCapability();
public static final VideoStreamingFormat GENERAL_VIDEOSTREAMINGFORMAT = new VideoStreamingFormat();
+ public static final RGBColor GENERAL_RGBCOLOR = new RGBColor();
+ public static final TemplateColorScheme GENERAL_DAYCOLORSCHEME = new TemplateColorScheme();
+ public static final TemplateColorScheme GENERAL_NIGHTCOLORSCHEME = new TemplateColorScheme();
public static final Result GENERAL_RESULT = Result.SUCCESS;
public static final WayPointType GENERAL_WAYPOINTTYPE = WayPointType.DESTINATION;
public static final SingleTireStatus GENERAL_SINGLETIRESTATUS = new SingleTireStatus();
public static final DriverDistractionState GENERAL_DRIVERDISTRACTIONSTATE = DriverDistractionState.DD_ON;
public static final List<LocationDetails> GENERAL_LOCATIONDETAILS_LIST = Arrays.asList(new LocationDetails[] { Test.GENERAL_LOCATIONDETAILS, Test.GENERAL_LOCATIONDETAILS});
+ public static final AudioStreamingIndicator GENERAL_AUDIO_STREAMING_INDICATOR = AudioStreamingIndicator.PLAY;
+ public static final String GENERAL_APP_ID = "123e4567e8";
+ public static final String GENERAL_FULL_APP_ID = "123e4567-e89b-12d3-a456-426655440000";
public static final ModuleType GENERAL_MODULETYPE = ModuleType.CLIMATE;
public static final Temperature GENERAL_TEMPERATURE = new Temperature();
public static final TemperatureUnit GENERAL_TEMPERATUREUNIT = TemperatureUnit.CELSIUS;
public static final DefrostZone GENERAL_DEFROSTZONE = DefrostZone.ALL;
public static final VentilationMode GENERAL_VENTILATIONMODE = VentilationMode.BOTH;
+ public static final LightName GENERAL_LIGHTNAME = LightName.AMBIENT_LIGHTS;
+ public static final DisplayMode GENERAL_DISPLAYMODE = DisplayMode.AUTO;
+ public static final DistanceUnit GENERAL_DISTANCEUNIT = DistanceUnit.KILOMETERS;
+ public static final LightStatus GENERAL_LIGHTSTATUS = LightStatus.OFF;
public static final RadioBand GENERAL_RADIOBAND = RadioBand.AM;
public static final ClimateControlData GENERAL_CLIMATECONTROLDATA = new ClimateControlData();
+ public static final SeatControlData GENERAL_SEATCONTROLDATA = new SeatControlData();
public static final RdsData GENERAL_RDSDATA = new RdsData();
+ public static final StationIDNumber GENERAL_STATIONIDNUMBER = new StationIDNumber();
+ public static final SisData GENERAL_SISDATA = new SisData();
public static final RadioState GENERAL_RADIOSTATE = RadioState.ACQUIRED;
public static final RadioControlData GENERAL_RADIOCONTROLDATA = new RadioControlData();
public static final ModuleData GENERAL_MODULEDATA = new ModuleData();
public static final ClimateControlCapabilities GENERAL_CLIMATECONTROLCAPABILITIES = new ClimateControlCapabilities();
public static final RadioControlCapabilities GENERAL_RADIOCONTROLCAPABILITIES = new RadioControlCapabilities();
+ public static final SeatControlCapabilities GENERAL_SEATCONTROLCAPABILITIES = new SeatControlCapabilities();
+ public static final EqualizerSettings GENERAL_EQUALIZERSETTINGS = new EqualizerSettings();
+ public static final LightCapabilities GENERAL_LIGHTCAPABILITIES = new LightCapabilities();
+ public static final LightState GENERAL_LIGHTSTATE = new LightState();
+ public static final AudioControlCapabilities GENERAL_AUDIOCONTROLCAPABILITIES = new AudioControlCapabilities();
+ public static final HMISettingsControlCapabilities GENERAL_HMISETTINGSCONTROLCAPABILITIES = new HMISettingsControlCapabilities();
+ public static final LightControlCapabilities GENERAL_LIGHTCONTROLCAPABILITIES = new LightControlCapabilities();
+ public static final AudioControlData GENERAL_AUDIOCONTROLDATA = new AudioControlData();
+ public static final LightControlData GENERAL_LIGHTCONTROLDATA = new LightControlData();
+ public static final HMISettingsControlData GENERAL_HMISETTINGSCONTROLDATA = new HMISettingsControlData();
public static final HMICapabilities GENERAL_HMICAPABILITIES = new HMICapabilities();
public static final MetadataTags GENERAL_METADATASTRUCT = new MetadataTags();
public static final Rectangle GENERAL_RECTANGLE = new Rectangle();
public static final HapticRect GENERAL_HAPTIC_RECT = new HapticRect();
+ public static final FuelType GENERAL_FUELTYPE = FuelType.GASOLINE;
+ public static final LockScreenConfig GENERAL_LOCKSCREENCONFIG = new LockScreenConfig();
public static final List<Long> GENERAL_LONG_LIST = Arrays.asList(new Long[]{ 1L, 2L });
public static final List<Turn> GENERAL_TURN_LIST = new ArrayList<Turn>();
@@ -281,6 +352,8 @@ public class Test {
public static final List<TextField> GENERAL_TEXTFIELD_LIST = new ArrayList<TextField>(1);
public static final List<DIDResult> GENERAL_DIDRESULT_LIST = new ArrayList<DIDResult>(1);
public static final List<TouchCoord> GENERAL_TOUCHCOORD_LIST = new ArrayList<TouchCoord>(1);
+ public static final List<MassageModeData> GENERAL_MASSAGEMODEDATA_LIST = new ArrayList<MassageModeData>(1);
+ public static final List<MassageCushionFirmness> GENERAL_MASSAGECUSHIONFIRMNESS_LIST = new ArrayList<MassageCushionFirmness>(1);
public static final List<AppHMIType> GENERAL_APPHMITYPE_LIST = new ArrayList<AppHMIType>(2);
public static final List<VrHelpItem> GENERAL_VRHELPITEM_LIST = new ArrayList<VrHelpItem>(2);
public static final List<SoftButton> GENERAL_SOFTBUTTON_LIST = new ArrayList<SoftButton>(1);
@@ -302,16 +375,24 @@ public class Test {
public static final List<VentilationMode> GENERAL_VENTILATIONMODE_LIST = Arrays.asList(new VentilationMode[]{VentilationMode.LOWER, VentilationMode.UPPER});
public static final List<ClimateControlCapabilities> GENERAL_CLIMATECONTROLCAPABILITIES_LIST = new ArrayList<ClimateControlCapabilities>(1);
public static final List<RadioControlCapabilities> GENERAL_RADIOCONTROLCAPABILITIES_LIST = new ArrayList<RadioControlCapabilities>(1);
+ public static final Vector<String> GENERAL_VECTOR_STRING = new Vector<>(Arrays.asList(new String[] { "a", "b"}));
+ public static final Vector<TTSChunk> GENERAL_VECTOR_TTS_CHUNKS = new Vector<>(Arrays.asList(TTSChunkFactory.createChunk(SpeechCapabilities.TEXT, "Welcome to the jungle")));
+ public static final List<SeatControlCapabilities> GENERAL_SEATCONTROLCAPABILITIES_LIST = new ArrayList<SeatControlCapabilities>(1);
+ public static final List<EqualizerSettings> GENERAL_EQUALIZERSETTINGS_LIST = new ArrayList<EqualizerSettings>(1);
+ public static final List<LightCapabilities> GENERAL_LIGHTCAPABILITIES_LIST = new ArrayList<LightCapabilities>(1);
+ public static final List<LightState> GENERAL_LIGHTSTATE_LIST = new ArrayList<LightState>(1);
+ public static final List<AudioControlCapabilities> GENERAL_AUDIOCONTROLCAPABILITIES_LIST = new ArrayList<AudioControlCapabilities>(1);
+ public static final List<ModuleData> GENERAL_MODULEDATA_LIST = Collections.singletonList(GENERAL_MODULEDATA);
public static final JSONArray JSON_TURNS = new JSONArray();
- public static final JSONArray JSON_CHOICES = new JSONArray();
+ public static final JSONArray JSON_CHOICES = new JSONArray();
public static final JSONArray JSON_HMILEVELS = new JSONArray();
public static final JSONArray JSON_TTSCHUNKS = new JSONArray();
public static final JSONArray JSON_DIDRESULTS = new JSONArray();
public static final JSONArray JSON_TEXTFIELDS = new JSONArray();
public static final JSONArray JSON_TOUCHCOORDS = new JSONArray();
public static final JSONArray JSON_VRHELPITEMS = new JSONArray();
- public static final JSONArray JSON_SOFTBUTTONS = new JSONArray();
+ public static final JSONArray JSON_SOFTBUTTONS = new JSONArray();
public static final JSONArray JSON_IMAGEFIELDS = new JSONArray();
public static final JSONArray JSON_TOUCHEVENTS = new JSONArray();
public static final JSONArray JSON_PERMISSIONITEMS = new JSONArray();
@@ -334,23 +415,30 @@ public class Test {
public static final JSONObject JSON_MENUPARAMS = new JSONObject();
public static final JSONObject JSON_DEVICEINFO = new JSONObject();
public static final JSONObject JSON_VRHELPITEM = new JSONObject();
- public static final JSONObject JSON_SCREENPARAMS = new JSONObject();
+ public static final JSONObject JSON_SCREENPARAMS = new JSONObject();
public static final JSONObject JSON_SDLMSGVERSION = new JSONObject();
public static final JSONObject JSON_PERMISSIONITEM = new JSONObject();
public static final JSONObject JSON_HMIPERMISSIONS = new JSONObject();
- public static final JSONObject JSON_IMAGERESOLUTION = new JSONObject();
+ public static final JSONObject JSON_IMAGERESOLUTION = new JSONObject();
public static final JSONObject JSON_KEYBOARDPROPERTIES = new JSONObject();
public static final JSONObject JSON_DISPLAYCAPABILITIES = new JSONObject();
public static final JSONObject JSON_PARAMETERPERMISSIONS = new JSONObject();
public static final JSONObject JSON_PRESETBANKCAPABILITIES = new JSONObject();
public static final JSONObject JSON_TOUCHEVENTCAPABILITIES = new JSONObject();
public static final JSONObject JSON_PCMSTREAMCAPABILITIES = new JSONObject();
+ public static final JSONObject JSON_RGBCOLOR = new JSONObject();
+ public static final JSONObject JSON_DAYCOLORSCHEME = new JSONObject();
+ public static final JSONObject JSON_NIGHTCOLORSCHEME = new JSONObject();
static {
GENERAL_TOUCHEVENTCAPABILITIES.setDoublePressAvailable(GENERAL_BOOLEAN);
GENERAL_TOUCHEVENTCAPABILITIES.setMultiTouchAvailable(GENERAL_BOOLEAN);
GENERAL_TOUCHEVENTCAPABILITIES.setPressAvailable(GENERAL_BOOLEAN);
-
+
+ GENERAL_SEATMEMORYACTION.setAction(GENERAL_SEATMEMORYACTIONTYPE);
+ GENERAL_SEATMEMORYACTION.setLabel(GENERAL_STRING);
+ GENERAL_SEATMEMORYACTION.setId(GENERAL_INT);
+
GENERAL_IMAGERESOLUTION.setResolutionHeight(GENERAL_INT);
GENERAL_IMAGERESOLUTION.setResolutionWidth(GENERAL_INT);
@@ -368,6 +456,44 @@ public class Test {
GENERAL_CLIMATECONTROLDATA.setDefrostZone(GENERAL_DEFROSTZONE);
GENERAL_CLIMATECONTROLDATA.setVentilationMode(GENERAL_VENTILATIONMODE);
+ GENERAL_SEATCONTROLDATA.setMemory(GENERAL_SEATMEMORYACTION);
+ GENERAL_SEATCONTROLDATA.setMassageCushionFirmness(GENERAL_MASSAGECUSHIONFIRMNESS_LIST);
+ GENERAL_SEATCONTROLDATA.setMassageMode(GENERAL_MASSAGEMODEDATA_LIST);
+ GENERAL_SEATCONTROLDATA.setMassageEnabled(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLDATA.setHeadSupportHorizontalPosition(GENERAL_INT);
+ GENERAL_SEATCONTROLDATA.setHeadSupportVerticalPosition(GENERAL_INT);
+ GENERAL_SEATCONTROLDATA.setBackTiltAngle(GENERAL_INT);
+ GENERAL_SEATCONTROLDATA.setBackVerticalPosition(GENERAL_INT);
+ GENERAL_SEATCONTROLDATA.setFrontVerticalPosition(GENERAL_INT);
+ GENERAL_SEATCONTROLDATA.setVerticalPosition(GENERAL_INT);
+ GENERAL_SEATCONTROLDATA.setHorizontalPosition(GENERAL_INT);
+ GENERAL_SEATCONTROLDATA.setCoolingLevel(GENERAL_INT);
+ GENERAL_SEATCONTROLDATA.setHeatingLevel(GENERAL_INT);
+ GENERAL_SEATCONTROLDATA.setHeatingEnabled(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLDATA.setCoolingEnabled(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLDATA.setId(GENERAL_SUPPORTEDSEAT);
+
+ GENERAL_AUDIOCONTROLDATA.setSource(GENERAL_PRIMARYAUDIOSOURCE);
+ GENERAL_AUDIOCONTROLDATA.setVolume(GENERAL_INT);
+ GENERAL_AUDIOCONTROLDATA.setKeepContext(GENERAL_BOOLEAN);
+ GENERAL_AUDIOCONTROLDATA.setEqualizerSettings(GENERAL_EQUALIZERSETTINGS_LIST);
+
+ GENERAL_HMISETTINGSCONTROLDATA.setDistanceUnit(GENERAL_DISTANCEUNIT);
+ GENERAL_HMISETTINGSCONTROLDATA.setTemperatureUnit(GENERAL_TEMPERATUREUNIT);
+ GENERAL_HMISETTINGSCONTROLDATA.setDisplayMode(GENERAL_DISPLAYMODE);
+
+ GENERAL_LIGHTCONTROLDATA.setLightState(GENERAL_LIGHTSTATE_LIST);
+
+ GENERAL_STATIONIDNUMBER.setCountryCode(GENERAL_INT);
+ GENERAL_STATIONIDNUMBER.setFccFacilityId(GENERAL_INT);
+
+ GENERAL_SISDATA.setStationMessage(GENERAL_STRING);
+ GENERAL_SISDATA.setStationLocation(VehicleDataHelper.GPS);
+
+ GENERAL_SISDATA.setStationLongName(GENERAL_STRING);
+ GENERAL_SISDATA.setStationIDNumber(GENERAL_STATIONIDNUMBER);
+ GENERAL_SISDATA.setStationShortName(GENERAL_STRING);
+
GENERAL_RDSDATA.setProgramService(GENERAL_STRING);
GENERAL_RDSDATA.setRadioText(GENERAL_STRING);
GENERAL_RDSDATA.setClockText(GENERAL_STRING);
@@ -398,16 +524,24 @@ public class Test {
GENERAL_CHOICE.setImage(GENERAL_IMAGE);
GENERAL_CHOICE.setSecondaryImage(GENERAL_IMAGE);
GENERAL_CHOICE.setVrCommands(GENERAL_STRING_LIST);
-
+
+ GENERAL_MASSAGEMODEDATA.setMassageMode(GENERAL_MASSAGEMODE);
+ GENERAL_MASSAGEMODEDATA.setMassageZone(GENERAL_MASSAGEZONE);
+ GENERAL_MASSAGEMODEDATA_LIST.add(GENERAL_MASSAGEMODEDATA);
+
+ GENERAL_MASSAGECUSHIONFIRMNESS.setCushion(GENERAL_MASSAGECUSHION);
+ GENERAL_MASSAGECUSHIONFIRMNESS.setFirmness(GENERAL_INT);
+ GENERAL_MASSAGECUSHIONFIRMNESS_LIST.add(GENERAL_MASSAGECUSHIONFIRMNESS);
+
GENERAL_TOUCHCOORD.setX(GENERAL_INT);
- GENERAL_TOUCHCOORD.setY(GENERAL_INT);
+ GENERAL_TOUCHCOORD.setY(GENERAL_INT);
GENERAL_TOUCHCOORD_LIST.add(GENERAL_TOUCHCOORD);
-
+
GENERAL_TOUCHEVENT.setId(GENERAL_INT);
GENERAL_TOUCHEVENT.setTs(GENERAL_LONG_LIST);
- GENERAL_TOUCHEVENT.setC(GENERAL_TOUCHCOORD_LIST);
+ GENERAL_TOUCHEVENT.setC(GENERAL_TOUCHCOORD_LIST);
GENERAL_TOUCHEVENT_LIST.add(GENERAL_TOUCHEVENT);
-
+
GENERAL_TEXTFIELD.setName(GENERAL_TEXTFIELDNAME);
GENERAL_TEXTFIELD.setRows(GENERAL_INT);
GENERAL_TEXTFIELD.setWidth(GENERAL_INT);
@@ -434,23 +568,24 @@ public class Test {
GENERAL_LOCATIONDETAILS.setLocationName(GENERAL_STRING);
GENERAL_LOCATIONDETAILS.setSearchAddress(GENERAL_OASISADDRESS);
GENERAL_LOCATIONDETAILS.setPhoneNumber(GENERAL_STRING);
-
+
GENERAL_FILETYPE_LIST.add(GENERAL_FILETYPE);
-
+
GENERAL_IMAGEFIELD.setImageResolution(GENERAL_IMAGERESOLUTION);
GENERAL_IMAGEFIELD.setName(GENERAL_IMAGEFIELDNAME);
GENERAL_IMAGEFIELD.setImageTypeSupported(GENERAL_FILETYPE_LIST);
GENERAL_IMAGEFIELD_LIST.add(GENERAL_IMAGEFIELD);
-
+
GENERAL_SCREENPARAMS.setImageResolution(GENERAL_IMAGERESOLUTION);
GENERAL_SCREENPARAMS.setTouchEventAvailable(GENERAL_TOUCHEVENTCAPABILITIES);
-
+
GENERAL_MEDIACLOCKFORMAT_LIST.add(MediaClockFormat.CLOCK1);
GENERAL_MEDIACLOCKFORMAT_LIST.add(MediaClockFormat.CLOCK2);
-
+
GENERAL_IMAGE.setValue(GENERAL_STRING);
GENERAL_IMAGE.setImageType(GENERAL_IMAGETYPE);
-
+ GENERAL_IMAGE.setIsTemplate(GENERAL_BOOLEAN);
+
GENERAL_SOFTBUTTON.setIsHighlighted(GENERAL_BOOLEAN);
GENERAL_SOFTBUTTON.setSoftButtonID(GENERAL_INT);
GENERAL_SOFTBUTTON.setSystemAction(SystemAction.STEAL_FOCUS);
@@ -458,64 +593,65 @@ public class Test {
GENERAL_SOFTBUTTON.setType(SoftButtonType.SBT_TEXT);
GENERAL_SOFTBUTTON.setImage(GENERAL_IMAGE);
GENERAL_SOFTBUTTON_LIST.add(GENERAL_SOFTBUTTON);
-
+
GENERAL_TURN.setNavigationText(GENERAL_STRING);
GENERAL_TURN.setTurnIcon(GENERAL_IMAGE);
GENERAL_TURN_LIST.add(GENERAL_TURN);
-
+
GENERAL_MENUPARAMS.setMenuName(GENERAL_STRING);
GENERAL_MENUPARAMS.setParentID(GENERAL_INT);
GENERAL_MENUPARAMS.setPosition(GENERAL_INT);
-
+
GENERAL_VRHELPITEM.setText(GENERAL_STRING);
GENERAL_VRHELPITEM.setImage(GENERAL_IMAGE);
- GENERAL_VRHELPITEM.setPosition(100);
+ GENERAL_VRHELPITEM.setPosition(100);
GENERAL_VRHELPITEM_LIST.add(GENERAL_VRHELPITEM);
-
+
GENERAL_TTSCHUNK_LIST.add(TTSChunkFactory.createChunk(SpeechCapabilities.TEXT, "Welcome to the jungle"));
GENERAL_TTSCHUNK_LIST.add(TTSChunkFactory.createChunk(SpeechCapabilities.TEXT, "Say a command"));
-
+
GENERAL_KEYBOARDPROPERTIES.setAutoCompleteText(GENERAL_STRING);
GENERAL_KEYBOARDPROPERTIES.setKeypressMode(KeypressMode.SINGLE_KEYPRESS);
GENERAL_KEYBOARDPROPERTIES.setKeyboardLayout(KeyboardLayout.QWERTY);
GENERAL_KEYBOARDPROPERTIES.setLanguage(Language.EN_US);
GENERAL_KEYBOARDPROPERTIES.setLimitedCharacterList(Test.GENERAL_STRING_LIST);
-
+
GENERAL_STARTTIME.setHours(GENERAL_INT);
GENERAL_STARTTIME.setMinutes(GENERAL_INT);
GENERAL_STARTTIME.setSeconds(GENERAL_INT);
-
+
GENERAL_CHOICE_LIST.add(GENERAL_CHOICE);
-
+
GENERAL_DEVICEINFO.setCarrier(GENERAL_STRING);
GENERAL_DEVICEINFO.setFirmwareRev(GENERAL_STRING);
GENERAL_DEVICEINFO.setHardware(GENERAL_STRING);
GENERAL_DEVICEINFO.setMaxNumberRFCOMMPorts(GENERAL_INT);
GENERAL_DEVICEINFO.setOs(GENERAL_STRING);
GENERAL_DEVICEINFO.setOsVersion(GENERAL_STRING);
-
+
GENERAL_SDLMSGVERSION.setMajorVersion(GENERAL_INT);
GENERAL_SDLMSGVERSION.setMinorVersion(GENERAL_INT);
-
+
GENERAL_APPHMITYPE_LIST.add(AppHMIType.BACKGROUND_PROCESS);
GENERAL_APPHMITYPE_LIST.add(AppHMIType.COMMUNICATION);
-
+
GENERAL_GLOBALPROPERTY_LIST.add(GlobalProperty.HELPPROMPT);
GENERAL_GLOBALPROPERTY_LIST.add(GlobalProperty.MENUICON);
-
+
for (VehicleDataType data : VehicleDataType.values()) {
VehicleDataResult result = new VehicleDataResult();
result.setResultCode(VehicleDataResultCode.SUCCESS);
result.setDataType(data);
GENERAL_VEHICLEDATARESULT_LIST.add(result);
}
-
+
GENERAL_DIDRESULT.setData(GENERAL_STRING);
GENERAL_DIDRESULT.setDidLocation(GENERAL_INT);
GENERAL_DIDRESULT.setResultCode(VehicleDataResultCode.SUCCESS);
GENERAL_DIDRESULT_LIST.add(GENERAL_DIDRESULT);
-
+
GENERAL_DISPLAYCAPABILITIES.setDisplayType(GENERAL_DISPLAYTYPE);
+ GENERAL_DISPLAYCAPABILITIES.setDisplayName(GENERAL_STRING);
GENERAL_DISPLAYCAPABILITIES.setGraphicSupported(GENERAL_BOOLEAN);
GENERAL_DISPLAYCAPABILITIES.setImageFields(GENERAL_IMAGEFIELD_LIST);
GENERAL_DISPLAYCAPABILITIES.setMediaClockFormats(GENERAL_MEDIACLOCKFORMAT_LIST);
@@ -523,48 +659,48 @@ public class Test {
GENERAL_DISPLAYCAPABILITIES.setScreenParams(GENERAL_SCREENPARAMS);
GENERAL_DISPLAYCAPABILITIES.setTemplatesAvailable(GENERAL_STRING_LIST);
GENERAL_DISPLAYCAPABILITIES.setTextFields(GENERAL_TEXTFIELD_LIST);
-
+
GENERAL_PRESETBANKCAPABILITIES.setOnScreenPresetsAvailable(GENERAL_BOOLEAN);
-
+
GENERAL_BUTTONCAPABILITIES.setLongPressAvailable(false);
GENERAL_BUTTONCAPABILITIES.setShortPressAvailable(true);
GENERAL_BUTTONCAPABILITIES.setUpDownAvailable(true);
- GENERAL_BUTTONCAPABILITIES.setName(ButtonName.SEEKRIGHT);
+ GENERAL_BUTTONCAPABILITIES.setName(ButtonName.SEEKRIGHT);
GENERAL_BUTTONCAPABILITIES_LIST.add(GENERAL_BUTTONCAPABILITIES);
-
+
GENERAL_SOFTBUTTONCAPABILITIES.setLongPressAvailable(GENERAL_BOOLEAN);
GENERAL_SOFTBUTTONCAPABILITIES.setShortPressAvailable(GENERAL_BOOLEAN);
GENERAL_SOFTBUTTONCAPABILITIES.setUpDownAvailable(GENERAL_BOOLEAN);
GENERAL_SOFTBUTTONCAPABILITIES.setImageSupported(GENERAL_BOOLEAN);
- GENERAL_SOFTBUTTONCAPABILITIES_LIST.add(GENERAL_SOFTBUTTONCAPABILITIES);
-
+ GENERAL_SOFTBUTTONCAPABILITIES_LIST.add(GENERAL_SOFTBUTTONCAPABILITIES);
+
GENERAL_VEHICLETYPE.setMake(GENERAL_STRING);
GENERAL_VEHICLETYPE.setModel(GENERAL_STRING);
GENERAL_VEHICLETYPE.setModelYear(GENERAL_STRING);
GENERAL_VEHICLETYPE.setTrim(GENERAL_STRING);
-
+
GENERAL_AUDIOPASSTHRUCAPABILITIES.setAudioType(GENERAL_AUDIOTYPE);
GENERAL_AUDIOPASSTHRUCAPABILITIES.setBitsPerSample(GENERAL_BITSPERSAMPLE);
GENERAL_AUDIOPASSTHRUCAPABILITIES.setSamplingRate(GENERAL_SAMPLINGRATE);
GENERAL_AUDIOPASSTHRUCAPABILITIES_LIST.add(GENERAL_AUDIOPASSTHRUCAPABILITIES);
-
+
GENERAL_PRERECORDEDSPEECH_LIST.add(PrerecordedSpeech.HELP_JINGLE);
GENERAL_PRERECORDEDSPEECH_LIST.add(PrerecordedSpeech.INITIAL_JINGLE);
-
+
GENERAL_HMIZONECAPABILITIES_LIST.add(HmiZoneCapabilities.BACK);
GENERAL_HMIZONECAPABILITIES_LIST.add(HmiZoneCapabilities.FRONT);
-
+
GENERAL_SPEECHCAPABILITIES_LIST.add(SpeechCapabilities.SILENCE);
GENERAL_SPEECHCAPABILITIES_LIST.add(SpeechCapabilities.TEXT);
-
+
GENERAL_VRCAPABILITIES_LIST.add(VrCapabilities.TEXT);
-
+
GENERAL_HMIPERMISSIONS.setAllowed(GENERAL_HMILEVEL_LIST);
GENERAL_HMIPERMISSIONS.setUserDisallowed(GENERAL_HMILEVEL_LIST);
-
+
GENERAL_PARAMETERPERMISSIONS.setAllowed(GENERAL_STRING_LIST);
GENERAL_PARAMETERPERMISSIONS.setUserDisallowed(GENERAL_STRING_LIST);
-
+
GENERAL_PERMISSIONITEM.setRpcName(GENERAL_STRING);
GENERAL_PERMISSIONITEM.setHMIPermissions(GENERAL_HMIPERMISSIONS);
GENERAL_PERMISSIONITEM.setParameterPermissions(GENERAL_PARAMETERPERMISSIONS);
@@ -586,6 +722,7 @@ public class Test {
GENERAL_VIDEOSTREAMINGCAPABILITY.setMaxBitrate(GENERAL_INT);
GENERAL_VIDEOSTREAMINGCAPABILITY.setPreferredResolution(GENERAL_IMAGERESOLUTION);
GENERAL_VIDEOSTREAMINGCAPABILITY.setSupportedFormats(GENERAL_VIDEOSTREAMINGFORMAT_LIST);
+ GENERAL_VIDEOSTREAMINGCAPABILITY.setIsHapticSpatialDataSupported(GENERAL_BOOLEAN);
GENERAL_CLIMATECONTROLCAPABILITIES.setModuleName(GENERAL_STRING);
GENERAL_CLIMATECONTROLCAPABILITIES.setFanSpeedAvailable(GENERAL_BOOLEAN);
@@ -613,6 +750,56 @@ public class Test {
GENERAL_RADIOCONTROLCAPABILITIES.setSignalChangeThresholdAvailable(GENERAL_BOOLEAN);
GENERAL_RADIOCONTROLCAPABILITIES_LIST.add(GENERAL_RADIOCONTROLCAPABILITIES);
+ GENERAL_SEATCONTROLCAPABILITIES.setMemoryAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setMassageCushionFirmnessAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setMassageModeAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setMassageEnabledAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setHeadSupportVerticalPositionAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setHeadSupportHorizontalPositionAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setBackTiltAngleAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setBackVerticalPositionAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setFrontVerticalPositionAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setVerticalPositionAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setHorizontalPositionAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setCoolingLevelAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setHeatingLevelAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setCoolingEnabledAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setHeatingEnabledAvailable(GENERAL_BOOLEAN);
+ GENERAL_SEATCONTROLCAPABILITIES.setModuleName(GENERAL_STRING);
+ GENERAL_SEATCONTROLCAPABILITIES_LIST.add(GENERAL_SEATCONTROLCAPABILITIES);
+
+ GENERAL_AUDIOCONTROLCAPABILITIES.setEqualizerMaxChannelId(GENERAL_INT);
+ GENERAL_AUDIOCONTROLCAPABILITIES.setEqualizerAvailable(GENERAL_BOOLEAN);
+ GENERAL_AUDIOCONTROLCAPABILITIES.setVolumeAvailable(GENERAL_BOOLEAN);
+ GENERAL_AUDIOCONTROLCAPABILITIES.setSourceAvailable(GENERAL_BOOLEAN);
+ GENERAL_AUDIOCONTROLCAPABILITIES.setKeepContextAvailable(GENERAL_BOOLEAN);
+ GENERAL_AUDIOCONTROLCAPABILITIES.setModuleName(GENERAL_STRING);
+ GENERAL_AUDIOCONTROLCAPABILITIES_LIST.add(GENERAL_AUDIOCONTROLCAPABILITIES);
+
+ GENERAL_HMISETTINGSCONTROLCAPABILITIES.setDisplayModeUnitAvailable(GENERAL_BOOLEAN);
+ GENERAL_HMISETTINGSCONTROLCAPABILITIES.setDistanceUnitAvailable(GENERAL_BOOLEAN);
+ GENERAL_HMISETTINGSCONTROLCAPABILITIES.setTemperatureUnitAvailable(GENERAL_BOOLEAN);
+ GENERAL_HMISETTINGSCONTROLCAPABILITIES.setModuleName(GENERAL_STRING);
+
+ GENERAL_LIGHTCONTROLCAPABILITIES.setSupportedLights(GENERAL_LIGHTCAPABILITIES_LIST);
+ GENERAL_LIGHTCONTROLCAPABILITIES.setModuleName(GENERAL_STRING);
+
+ GENERAL_EQUALIZERSETTINGS.setChannelSetting(GENERAL_INT);
+ GENERAL_EQUALIZERSETTINGS.setChannelName(GENERAL_STRING);
+ GENERAL_EQUALIZERSETTINGS.setChannelId(GENERAL_INT);
+ GENERAL_EQUALIZERSETTINGS_LIST.add(GENERAL_EQUALIZERSETTINGS);
+
+ GENERAL_LIGHTCAPABILITIES.setName(GENERAL_LIGHTNAME);
+ GENERAL_LIGHTCAPABILITIES.setDensityAvailable(GENERAL_BOOLEAN);
+ GENERAL_LIGHTCAPABILITIES.setRGBColorSpaceAvailable(GENERAL_BOOLEAN);
+ GENERAL_LIGHTCAPABILITIES_LIST.add(GENERAL_LIGHTCAPABILITIES);
+
+ GENERAL_LIGHTSTATE.setId(GENERAL_LIGHTNAME);
+ GENERAL_LIGHTSTATE.setDensity(GENERAL_FLOAT);
+ GENERAL_LIGHTSTATE.setStatus(GENERAL_LIGHTSTATUS);
+ GENERAL_LIGHTSTATE.setColor(GENERAL_RGBCOLOR);
+ GENERAL_LIGHTSTATE_LIST.add(GENERAL_LIGHTSTATE);
+
GENERAL_REMOTECONTROLCAPABILITIES.setButtonCapabilities(GENERAL_BUTTONCAPABILITIES_LIST);
GENERAL_REMOTECONTROLCAPABILITIES.setClimateControlCapabilities(GENERAL_CLIMATECONTROLCAPABILITIES_LIST);
GENERAL_REMOTECONTROLCAPABILITIES.setRadioControlCapabilities(GENERAL_RADIOCONTROLCAPABILITIES_LIST);
@@ -639,7 +826,24 @@ public class Test {
GENERAL_HAPTIC_RECT.setId(GENERAL_INTEGER);
GENERAL_HAPTIC_RECT.setRect(GENERAL_RECTANGLE);
-
+ GENERAL_RGBCOLOR.setRed(GENERAL_INTEGER);
+ GENERAL_RGBCOLOR.setGreen(GENERAL_INTEGER);
+ GENERAL_RGBCOLOR.setBlue(GENERAL_INTEGER);
+
+ GENERAL_NIGHTCOLORSCHEME.setPrimaryColor(GENERAL_RGBCOLOR);
+ GENERAL_NIGHTCOLORSCHEME.setSecondaryColor(GENERAL_RGBCOLOR);
+ GENERAL_NIGHTCOLORSCHEME.setBackgroundColor(GENERAL_RGBCOLOR);
+
+ GENERAL_DAYCOLORSCHEME.setPrimaryColor(GENERAL_RGBCOLOR);
+ GENERAL_DAYCOLORSCHEME.setSecondaryColor(GENERAL_RGBCOLOR);
+ GENERAL_DAYCOLORSCHEME.setBackgroundColor(GENERAL_RGBCOLOR);
+
+ GENERAL_LOCKSCREENCONFIG.setAppIcon(R.drawable.sdl_lockscreen_icon);
+ GENERAL_LOCKSCREENCONFIG.setBackgroundColor(Color.BLUE);
+ GENERAL_LOCKSCREENCONFIG.setEnabled(true);
+ GENERAL_LOCKSCREENCONFIG.setCustomView(R.layout.activity_sdllock_screen);
+
+
try {
JSON_HMIPERMISSIONS.put(HMIPermissions.KEY_ALLOWED, GENERAL_HMILEVEL_LIST);
JSON_HMIPERMISSIONS.put(HMIPermissions.KEY_USER_DISALLOWED, GENERAL_HMILEVEL_LIST);
@@ -647,14 +851,14 @@ public class Test {
JSON_PCMSTREAMCAPABILITIES.put(AudioPassThruCapabilities.KEY_AUDIO_TYPE, GENERAL_AUDIOTYPE);
JSON_PCMSTREAMCAPABILITIES.put(AudioPassThruCapabilities.KEY_BITS_PER_SAMPLE, GENERAL_BITSPERSAMPLE);
JSON_PCMSTREAMCAPABILITIES.put(AudioPassThruCapabilities.KEY_SAMPLING_RATE, GENERAL_SAMPLINGRATE);
-
+
JSON_TOUCHEVENTCAPABILITIES.put(TouchEventCapabilities.KEY_DOUBLE_PRESS_AVAILABLE, GENERAL_BOOLEAN);
JSON_TOUCHEVENTCAPABILITIES.put(TouchEventCapabilities.KEY_MULTI_TOUCH_AVAILABLE, GENERAL_BOOLEAN);
JSON_TOUCHEVENTCAPABILITIES.put(TouchEventCapabilities.KEY_PRESS_AVAILABLE, GENERAL_BOOLEAN);
-
+
JSON_IMAGERESOLUTION.put(ImageResolution.KEY_RESOLUTION_HEIGHT, GENERAL_INT);
JSON_IMAGERESOLUTION.put(ImageResolution.KEY_RESOLUTION_WIDTH, GENERAL_INT);
-
+
JSON_CHOICE.put(Choice.KEY_MENU_NAME, GENERAL_STRING);
JSON_CHOICE.put(Choice.KEY_SECONDARY_TEXT, GENERAL_STRING);
JSON_CHOICE.put(Choice.KEY_TERTIARY_TEXT, GENERAL_STRING);
@@ -662,24 +866,25 @@ public class Test {
JSON_CHOICE.put(Choice.KEY_IMAGE, JSON_IMAGE);
JSON_CHOICE.put(Choice.KEY_SECONDARY_IMAGE, JSON_IMAGE);
JSON_CHOICE.put(Choice.KEY_VR_COMMANDS, JsonUtils.createJsonArray(GENERAL_STRING_LIST));
-
+
JSON_HMILEVELS.put(HMILevel.HMI_FULL);
JSON_HMILEVELS.put(HMILevel.HMI_BACKGROUND);
-
+
JSON_HMIPERMISSIONS.put(HMIPermissions.KEY_ALLOWED, JSON_HMILEVELS);
JSON_HMIPERMISSIONS.put(HMIPermissions.KEY_USER_DISALLOWED, JSON_HMILEVELS);
-
+
JSON_PARAMETERPERMISSIONS.put(ParameterPermissions.KEY_ALLOWED, JsonUtils.createJsonArray(GENERAL_STRING_LIST));
JSON_PARAMETERPERMISSIONS.put(ParameterPermissions.KEY_USER_DISALLOWED, JsonUtils.createJsonArray(GENERAL_STRING_LIST));
-
+
JSON_PERMISSIONITEM.put(PermissionItem.KEY_HMI_PERMISSIONS, JSON_HMIPERMISSIONS);
JSON_PERMISSIONITEM.put(PermissionItem.KEY_PARAMETER_PERMISSIONS, JSON_PARAMETERPERMISSIONS);
JSON_PERMISSIONITEM.put(PermissionItem.KEY_RPC_NAME, GENERAL_STRING);
JSON_PERMISSIONITEMS.put(JSON_PERMISSIONITEM);
-
+
JSON_IMAGE.put(Image.KEY_IMAGE_TYPE, GENERAL_IMAGETYPE);
JSON_IMAGE.put(Image.KEY_VALUE, GENERAL_STRING);
-
+ JSON_IMAGE.put(Image.KEY_IS_TEMPLATE, GENERAL_BOOLEAN);
+
JSON_SOFTBUTTON.put(SoftButton.KEY_IS_HIGHLIGHTED , GENERAL_BOOLEAN);
JSON_SOFTBUTTON.put(SoftButton.KEY_SOFT_BUTTON_ID, GENERAL_INT);
JSON_SOFTBUTTON.put(SoftButton.KEY_SYSTEM_ACTION, SystemAction.STEAL_FOCUS);
@@ -687,20 +892,20 @@ public class Test {
JSON_SOFTBUTTON.put(SoftButton.KEY_TYPE, SoftButtonType.SBT_TEXT);
JSON_SOFTBUTTON.put(SoftButton.KEY_IMAGE, GENERAL_IMAGE.serializeJSON());
JSON_SOFTBUTTONS.put(JSON_SOFTBUTTON);
-
+
JSON_TURN.put(Turn.KEY_NAVIGATION_TEXT, GENERAL_STRING);
JSON_TURN.put(Turn.KEY_TURN_IMAGE, GENERAL_IMAGE.serializeJSON());
JSON_TURNS.put(JSON_TURN);
-
+
JSON_MENUPARAMS.put(MenuParams.KEY_MENU_NAME, GENERAL_STRING);
JSON_MENUPARAMS.put(MenuParams.KEY_PARENT_ID, GENERAL_INT);
JSON_MENUPARAMS.put(MenuParams.KEY_POSITION, GENERAL_INT);
-
+
JSON_VRHELPITEM.put(VrHelpItem.KEY_TEXT, GENERAL_STRING);
JSON_VRHELPITEM.put(VrHelpItem.KEY_IMAGE, JSON_IMAGE);
JSON_VRHELPITEM.put(VrHelpItem.KEY_POSITION, GENERAL_INT);
JSON_VRHELPITEMS.put(JSON_VRHELPITEM);
-
+
JSONObject jsonTtsChunk = new JSONObject();
jsonTtsChunk.put(TTSChunk.KEY_TEXT, "Welcome to the jungle");
jsonTtsChunk.put(TTSChunk.KEY_TYPE, SpeechCapabilities.TEXT);
@@ -709,36 +914,48 @@ public class Test {
jsonTtsChunk.put(TTSChunk.KEY_TEXT, "Say a command");
jsonTtsChunk.put(TTSChunk.KEY_TYPE, SpeechCapabilities.TEXT);
JSON_TTSCHUNKS.put(jsonTtsChunk);
-
+
JSON_KEYBOARDPROPERTIES.put(KeyboardProperties.KEY_AUTO_COMPLETE_TEXT, GENERAL_STRING);
JSON_KEYBOARDPROPERTIES.put(KeyboardProperties.KEY_KEYPRESS_MODE, KeypressMode.SINGLE_KEYPRESS);
JSON_KEYBOARDPROPERTIES.put(KeyboardProperties.KEY_KEYBOARD_LAYOUT, KeyboardLayout.QWERTY);
JSON_KEYBOARDPROPERTIES.put(KeyboardProperties.KEY_LANGUAGE, Language.EN_US);
JSON_KEYBOARDPROPERTIES.put(KeyboardProperties.KEY_LIMITED_CHARACTER_LIST, JsonUtils.createJsonArray(GENERAL_STRING_LIST));
-
+
JSON_STARTTIME.put(StartTime.KEY_HOURS, GENERAL_STARTTIME.getHours());
JSON_STARTTIME.put(StartTime.KEY_MINUTES, GENERAL_STARTTIME.getMinutes());
JSON_STARTTIME.put(StartTime.KEY_SECONDS, GENERAL_STARTTIME.getSeconds());
-
+
JSON_CHOICES.put(JSON_CHOICE);
-
+
JSON_DEVICEINFO.put(DeviceInfo.KEY_CARRIER, GENERAL_STRING);
JSON_DEVICEINFO.put(DeviceInfo.KEY_FIRMWARE_REV, GENERAL_STRING);
JSON_DEVICEINFO.put(DeviceInfo.KEY_HARDWARE, GENERAL_STRING);
JSON_DEVICEINFO.put(DeviceInfo.KEY_MAX_NUMBER_RFCOMM_PORTS, GENERAL_INT);
JSON_DEVICEINFO.put(DeviceInfo.KEY_OS, GENERAL_STRING);
JSON_DEVICEINFO.put(DeviceInfo.KEY_OS_VERSION, GENERAL_STRING);
-
+
+ JSON_RGBCOLOR.put(RGBColor.KEY_RED, GENERAL_INT);
+ JSON_RGBCOLOR.put(RGBColor.KEY_GREEN, GENERAL_INT);
+ JSON_RGBCOLOR.put(RGBColor.KEY_BLUE, GENERAL_INT);
+
+ JSON_DAYCOLORSCHEME.put(TemplateColorScheme.KEY_PRIMARY_COLOR, JSON_RGBCOLOR);
+ JSON_DAYCOLORSCHEME.put(TemplateColorScheme.KEY_SECONDARY_COLOR, JSON_RGBCOLOR);
+ JSON_DAYCOLORSCHEME.put(TemplateColorScheme.KEY_BACKGROUND_COLOR, JSON_RGBCOLOR);
+
+ JSON_NIGHTCOLORSCHEME.put(TemplateColorScheme.KEY_PRIMARY_COLOR, JSON_RGBCOLOR);
+ JSON_NIGHTCOLORSCHEME.put(TemplateColorScheme.KEY_SECONDARY_COLOR, JSON_RGBCOLOR);
+ JSON_NIGHTCOLORSCHEME.put(TemplateColorScheme.KEY_BACKGROUND_COLOR, JSON_RGBCOLOR);
+
JSON_SDLMSGVERSION.put(SdlMsgVersion.KEY_MAJOR_VERSION, GENERAL_INT);
- JSON_SDLMSGVERSION.put(SdlMsgVersion.KEY_MINOR_VERSION, GENERAL_INT);
-
+ JSON_SDLMSGVERSION.put(SdlMsgVersion.KEY_MINOR_VERSION, GENERAL_INT);
+
JSON_DIDRESULT.put(DIDResult.KEY_DATA, GENERAL_STRING);
JSON_DIDRESULT.put(DIDResult.KEY_DID_LOCATION, GENERAL_INT);
JSON_DIDRESULT.put(DIDResult.KEY_RESULT_CODE, VehicleDataResultCode.SUCCESS);
JSON_DIDRESULTS.put(JSON_DIDRESULT);
-
+
JSON_PRESETBANKCAPABILITIES.put(PresetBankCapabilities.KEY_ON_SCREEN_PRESETS_AVAILABLE, GENERAL_BOOLEAN);
-
+
JSONObject jsonButton = new JSONObject();
jsonButton.put(ButtonCapabilities.KEY_LONG_PRESS_AVAILABLE, false);
jsonButton.put(ButtonCapabilities.KEY_SHORT_PRESS_AVAILABLE, GENERAL_BOOLEAN);
@@ -780,33 +997,34 @@ public class Test {
jsonButton.put(SoftButtonCapabilities.KEY_UP_DOWN_AVAILABLE, GENERAL_BOOLEAN);
jsonButton.put(SoftButtonCapabilities.KEY_IMAGE_SUPPORTED, GENERAL_BOOLEAN);
JSON_SOFTBUTTONCAPABILITIES.put(jsonButton);
-
+
jsonButton = new JSONObject();
jsonButton.put(AudioPassThruCapabilities.KEY_AUDIO_TYPE, GENERAL_AUDIOTYPE);
jsonButton.put(AudioPassThruCapabilities.KEY_BITS_PER_SAMPLE, GENERAL_BITSPERSAMPLE);
jsonButton.put(AudioPassThruCapabilities.KEY_SAMPLING_RATE, GENERAL_SAMPLINGRATE);
JSON_AUDIOPASSTHRUCAPABILITIES.put(jsonButton);
-
+
JSON_TEXTFIELD.put(TextField.KEY_CHARACTER_SET, CharacterSet.CID1SET);
JSON_TEXTFIELD.put(TextField.KEY_NAME, TextFieldName.ETA);
JSON_TEXTFIELD.put(TextField.KEY_ROWS, GENERAL_INT);
JSON_TEXTFIELD.put(TextField.KEY_WIDTH, GENERAL_INT);
JSON_TEXTFIELDS.put(JSON_TEXTFIELD);
-
+
JSON_IMAGEFIELD.put(ImageField.KEY_IMAGE_RESOLUTION, JSON_IMAGERESOLUTION);
JSON_IMAGEFIELD.put(ImageField.KEY_IMAGE_TYPE_SUPPORTED, JsonUtils.createJsonArray(Test.GENERAL_FILETYPE_LIST));
JSON_IMAGEFIELD.put(ImageField.KEY_NAME, ImageFieldName.graphic);
JSON_IMAGEFIELDS.put(JSON_IMAGEFIELD);
-
+
JSONObject jsonTEC = new JSONObject();
jsonTEC.put(TouchEventCapabilities.KEY_DOUBLE_PRESS_AVAILABLE, GENERAL_BOOLEAN);
jsonTEC.put(TouchEventCapabilities.KEY_MULTI_TOUCH_AVAILABLE, GENERAL_BOOLEAN);
jsonTEC.put(TouchEventCapabilities.KEY_PRESS_AVAILABLE, GENERAL_BOOLEAN);
-
+
JSON_SCREENPARAMS.put(ScreenParams.KEY_RESOLUTION, JSON_IMAGERESOLUTION);
JSON_SCREENPARAMS.put(ScreenParams.KEY_TOUCH_EVENT_AVAILABLE, jsonTEC);
-
+
JSON_DISPLAYCAPABILITIES.put(DisplayCapabilities.KEY_DISPLAY_TYPE, GENERAL_DISPLAYTYPE);
+ JSON_DISPLAYCAPABILITIES.put(DisplayCapabilities.KEY_DISPLAY_NAME, GENERAL_STRING);
JSON_DISPLAYCAPABILITIES.put(DisplayCapabilities.KEY_GRAPHIC_SUPPORTED, GENERAL_BOOLEAN);
JSON_DISPLAYCAPABILITIES.put(DisplayCapabilities.KEY_IMAGE_FIELDS, JSON_IMAGEFIELDS);
JSON_DISPLAYCAPABILITIES.put(DisplayCapabilities.KEY_MEDIA_CLOCK_FORMATS, JsonUtils.createJsonArray(GENERAL_MEDIACLOCKFORMAT_LIST));
@@ -814,11 +1032,11 @@ public class Test {
JSON_DISPLAYCAPABILITIES.put(DisplayCapabilities.KEY_SCREEN_PARAMS, JSON_SCREENPARAMS);
JSON_DISPLAYCAPABILITIES.put(DisplayCapabilities.KEY_TEMPLATES_AVAILABLE, JsonUtils.createJsonArray(GENERAL_STRING_LIST));
JSON_DISPLAYCAPABILITIES.put(DisplayCapabilities.KEY_TEXT_FIELDS, JSON_TEXTFIELDS);
-
+
JSON_TOUCHCOORD.put(TouchCoord.KEY_X, GENERAL_INT);
JSON_TOUCHCOORD.put(TouchCoord.KEY_Y, GENERAL_INT);
JSON_TOUCHCOORDS.put(JSON_TOUCHCOORD);
-
+
JSON_TOUCHEVENT.put(TouchEvent.KEY_C, JSON_TOUCHCOORDS);
JSON_TOUCHEVENT.put(TouchEvent.KEY_ID, GENERAL_INT);
JSON_TOUCHEVENT.put(TouchEvent.KEY_TS, JsonUtils.createJsonArray(GENERAL_LONG_LIST));
@@ -827,9 +1045,9 @@ public class Test {
JSON_TEXTFIELDTYPES.put(MetadataType.CURRENT_TEMPERATURE);
JSON_TEXTFIELDTYPES.put(MetadataType.MEDIA_ALBUM);
JSON_TEXTFIELDTYPES.put(MetadataType.MEDIA_ARTIST);
-
+
} catch (JSONException e) {
Log.e("Test", "Static Json Construction Failed.", e);
}
- }
-} \ No newline at end of file
+ }
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java
index 8ab861a0a..66112be33 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java
@@ -3,11 +3,14 @@ package com.smartdevicelink.test;
import java.util.Iterator;
import java.util.List;
+import com.smartdevicelink.managers.file.filetypes.SdlFile;
import com.smartdevicelink.protocol.enums.FrameData;
import com.smartdevicelink.protocol.enums.FrameDataControlFrameType;
import com.smartdevicelink.protocol.enums.FrameType;
import com.smartdevicelink.protocol.enums.SessionType;
import com.smartdevicelink.proxy.rpc.AirbagStatus;
+import com.smartdevicelink.proxy.rpc.AudioControlCapabilities;
+import com.smartdevicelink.proxy.rpc.AudioControlData;
import com.smartdevicelink.proxy.rpc.AudioPassThruCapabilities;
import com.smartdevicelink.proxy.rpc.BeltStatus;
import com.smartdevicelink.proxy.rpc.BodyInformation;
@@ -23,15 +26,25 @@ import com.smartdevicelink.proxy.rpc.DeviceStatus;
import com.smartdevicelink.proxy.rpc.DisplayCapabilities;
import com.smartdevicelink.proxy.rpc.ECallInfo;
import com.smartdevicelink.proxy.rpc.EmergencyEvent;
+import com.smartdevicelink.proxy.rpc.EqualizerSettings;
+import com.smartdevicelink.proxy.rpc.FuelRange;
import com.smartdevicelink.proxy.rpc.GPSData;
import com.smartdevicelink.proxy.rpc.HMICapabilities;
import com.smartdevicelink.proxy.rpc.HMIPermissions;
+import com.smartdevicelink.proxy.rpc.HMISettingsControlCapabilities;
+import com.smartdevicelink.proxy.rpc.HMISettingsControlData;
import com.smartdevicelink.proxy.rpc.HeadLampStatus;
import com.smartdevicelink.proxy.rpc.Headers;
import com.smartdevicelink.proxy.rpc.Image;
import com.smartdevicelink.proxy.rpc.ImageField;
import com.smartdevicelink.proxy.rpc.ImageResolution;
import com.smartdevicelink.proxy.rpc.KeyboardProperties;
+import com.smartdevicelink.proxy.rpc.LightCapabilities;
+import com.smartdevicelink.proxy.rpc.LightControlCapabilities;
+import com.smartdevicelink.proxy.rpc.LightControlData;
+import com.smartdevicelink.proxy.rpc.LightState;
+import com.smartdevicelink.proxy.rpc.MassageCushionFirmness;
+import com.smartdevicelink.proxy.rpc.MassageModeData;
import com.smartdevicelink.proxy.rpc.MenuParams;
import com.smartdevicelink.proxy.rpc.ModuleData;
import com.smartdevicelink.proxy.rpc.MyKey;
@@ -41,19 +54,26 @@ import com.smartdevicelink.proxy.rpc.ParameterPermissions;
import com.smartdevicelink.proxy.rpc.PermissionItem;
import com.smartdevicelink.proxy.rpc.PhoneCapability;
import com.smartdevicelink.proxy.rpc.PresetBankCapabilities;
+import com.smartdevicelink.proxy.rpc.RGBColor;
import com.smartdevicelink.proxy.rpc.RadioControlCapabilities;
import com.smartdevicelink.proxy.rpc.RadioControlData;
import com.smartdevicelink.proxy.rpc.RdsData;
-import com.smartdevicelink.proxy.rpc.RemoteControlCapabilities;
import com.smartdevicelink.proxy.rpc.Rectangle;
+import com.smartdevicelink.proxy.rpc.RemoteControlCapabilities;
import com.smartdevicelink.proxy.rpc.ScreenParams;
import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
+import com.smartdevicelink.proxy.rpc.SeatControlCapabilities;
+import com.smartdevicelink.proxy.rpc.SeatControlData;
+import com.smartdevicelink.proxy.rpc.SeatMemoryAction;
import com.smartdevicelink.proxy.rpc.SingleTireStatus;
+import com.smartdevicelink.proxy.rpc.SisData;
import com.smartdevicelink.proxy.rpc.SoftButton;
import com.smartdevicelink.proxy.rpc.SoftButtonCapabilities;
import com.smartdevicelink.proxy.rpc.StartTime;
+import com.smartdevicelink.proxy.rpc.StationIDNumber;
import com.smartdevicelink.proxy.rpc.TTSChunk;
import com.smartdevicelink.proxy.rpc.Temperature;
+import com.smartdevicelink.proxy.rpc.TemplateColorScheme;
import com.smartdevicelink.proxy.rpc.TextField;
import com.smartdevicelink.proxy.rpc.TireStatus;
import com.smartdevicelink.proxy.rpc.TouchCoord;
@@ -68,9 +88,9 @@ import com.smartdevicelink.proxy.rpc.VrHelpItem;
import com.smartdevicelink.proxy.rpc.enums.DefrostZone;
import com.smartdevicelink.proxy.rpc.enums.FileType;
import com.smartdevicelink.proxy.rpc.enums.HMILevel;
-import com.smartdevicelink.proxy.rpc.enums.VentilationMode;
import com.smartdevicelink.proxy.rpc.enums.HmiZoneCapabilities;
import com.smartdevicelink.proxy.rpc.enums.SpeechCapabilities;
+import com.smartdevicelink.proxy.rpc.enums.VentilationMode;
public class Validator{
@@ -240,6 +260,42 @@ public class Validator{
return true;
}
+ public static boolean validateSdlFile(SdlFile sdlFile1, SdlFile sdlFile2){
+ if(sdlFile1 == null){
+ return ( sdlFile2 == null );
+ }
+ if(sdlFile2 == null){
+ return ( sdlFile1 == null );
+ }
+
+ if(!( sdlFile1.getName().equals(sdlFile2.getName()) )){
+ log("validateSdlFile",
+ "sdlFile1 name \"" + sdlFile1.getName() + "\" didn't match sdlFile2 name \"" + sdlFile2.getName() + "\".");
+ return false;
+ }
+
+ if(sdlFile1.getResourceId() != sdlFile2.getResourceId() ){
+ log("validateSdlFile",
+ "sdlFile1 resourceId \"" + sdlFile1.getName() + "\" didn't match sdlFile2 resourceId \"" + sdlFile2.getName() + "\".");
+ return false;
+ }
+
+ if(!( sdlFile1.getType().equals(sdlFile2.getType()) )){
+ log("validateSdlFile",
+ "sdlFile1 type \"" + sdlFile1.getType() + "\" didn't match sdlFile2 type \"" + sdlFile2.getType() + "\".");
+ return false;
+ }
+
+ if( (sdlFile1.getUri() != sdlFile2.getUri()) && !( sdlFile1.getUri().equals(sdlFile2.getUri()) )){
+ log("validateSdlFile",
+ "sdlFile1 uri \"" + sdlFile1.getUri() + "\" didn't match sdlFile2 uri \"" + sdlFile2.getUri() + "\".");
+ return false;
+ }
+
+
+ return true;
+ }
+
public static boolean validateStringList(List<String> vrCommands1, List<String> vrCommands2){
if(vrCommands1 == null){
return ( vrCommands2 == null );
@@ -291,6 +347,15 @@ public class Validator{
return true;
}
+ public static boolean validateSoftButton(SoftButton button1, SoftButton button2){
+ return validateImage(button1.getImage(), button2.getImage())
+ && validateText(button1.getText(), button2.getText())
+ && button1.getIsHighlighted() == button2.getIsHighlighted()
+ && button1.getSoftButtonID() == button2.getSoftButtonID()
+ && button1.getSystemAction() == button2.getSystemAction()
+ && button1.getType() == button2.getType();
+ }
+
public static boolean validateSoftButtons(List<SoftButton> list1, List<SoftButton> list2){
if(list1 == null){
return ( list2 == null );
@@ -306,11 +371,7 @@ public class Validator{
SoftButton button1 = iterator1.next();
SoftButton button2 = iterator2.next();
- if(!validateImage(button1.getImage(), button2.getImage())
- || !validateText(button1.getText(), button2.getText())
- || button1.getIsHighlighted() != button2.getIsHighlighted()
- || button1.getSoftButtonID() != button2.getSoftButtonID()
- || button1.getSystemAction() != button2.getSystemAction() || button1.getType() != button2.getType()){
+ if(!validateSoftButton(button1, button2)){
return false;
}
}
@@ -629,6 +690,52 @@ public class Validator{
return true;
}
+ public static boolean validateHMISettingsControlCapabilities(HMISettingsControlCapabilities hmiSettingsControlCapabilities1, HMISettingsControlCapabilities hmiSettingsControlCapabilities2){
+ if(hmiSettingsControlCapabilities1 == null){
+ return ( hmiSettingsControlCapabilities2 == null );
+ }
+ if(hmiSettingsControlCapabilities2 == null){
+ return ( hmiSettingsControlCapabilities1 == null );
+ }
+
+ if(hmiSettingsControlCapabilities1.getModuleName() != hmiSettingsControlCapabilities2.getModuleName()){
+ return false;
+ }
+
+ if(hmiSettingsControlCapabilities1.getDisplayModeUnitAvailable() != hmiSettingsControlCapabilities2.getDisplayModeUnitAvailable()){
+ return false;
+ }
+
+ if(hmiSettingsControlCapabilities1.getDistanceUnitAvailable() != hmiSettingsControlCapabilities2.getDistanceUnitAvailable()){
+ return false;
+ }
+
+ if(hmiSettingsControlCapabilities1.getTemperatureUnitAvailable() != hmiSettingsControlCapabilities2.getTemperatureUnitAvailable()){
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean validateLightControlCapabilities(LightControlCapabilities lightControlCapabilities1, LightControlCapabilities lightControlCapabilities2){
+ if(lightControlCapabilities1 == null){
+ return ( lightControlCapabilities2 == null );
+ }
+ if(lightControlCapabilities2 == null){
+ return ( lightControlCapabilities1 == null );
+ }
+
+ if(lightControlCapabilities1.getModuleName() != lightControlCapabilities2.getModuleName()){
+ return false;
+ }
+
+ if(!( validateLightCapabilitiesList(lightControlCapabilities1.getSupportedLights(), lightControlCapabilities2.getSupportedLights()) )){
+ return false;
+ }
+
+ return true;
+ }
+
public static boolean validateClimateControlData(ClimateControlData climateControlData1, ClimateControlData climateControlData2){
if(climateControlData1 == null){
return ( climateControlData2 == null );
@@ -705,6 +812,128 @@ public class Validator{
return true;
}
+ public static boolean validateSeatControlData(SeatControlData seatControlData1, SeatControlData seatControlData2) {
+ if (seatControlData1 == null) {
+ return (seatControlData2 == null);
+ }
+ if (seatControlData2 == null) {
+ return (seatControlData1 == null);
+ }
+
+ if (seatControlData1.getCoolingEnabled() != seatControlData2.getCoolingEnabled()) {
+ return false;
+ }
+ if (seatControlData1.getHeatingEnabled() != seatControlData2.getHeatingEnabled()) {
+ return false;
+ }
+ if (seatControlData1.getMassageEnabled() != seatControlData2.getMassageEnabled()) {
+ return false;
+ }
+ if (seatControlData1.getBackTiltAngle() != seatControlData2.getBackTiltAngle()) {
+ return false;
+ }
+ if (seatControlData1.getBackVerticalPosition() != seatControlData2.getBackVerticalPosition()) {
+ return false;
+ }
+ if (seatControlData1.getCoolingLevel() != seatControlData2.getCoolingLevel()) {
+ return false;
+ }
+ if (seatControlData1.getFrontVerticalPosition() != seatControlData2.getFrontVerticalPosition()) {
+ return false;
+ }
+ if (seatControlData1.getHeadSupportHorizontalPosition() != seatControlData2.getHeadSupportHorizontalPosition()) {
+ return false;
+ }
+ if (seatControlData1.getHeadSupportVerticalPosition() != seatControlData2.getHeadSupportVerticalPosition()) {
+ return false;
+ }
+ if (seatControlData1.getHeatingLevel() != seatControlData2.getHeatingLevel()) {
+ return false;
+ }
+ if (seatControlData1.getHorizontalPosition() != seatControlData2.getHorizontalPosition()) {
+ return false;
+ }
+ if (seatControlData1.getId() != seatControlData2.getId()) {
+ return false;
+ }
+
+ if (!(validateSeatMemoryAction(seatControlData1.getMemory(), seatControlData2.getMemory()))) {
+ return false;
+ }
+
+ if (!(validateSeatMemoryAction(seatControlData1.getMemory(), seatControlData2.getMemory()))) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean validateAudioControlData(AudioControlData audioControlData1, AudioControlData audioControlData2) {
+ if (audioControlData1 == null) {
+ return (audioControlData2 == null);
+ }
+ if (audioControlData2 == null) {
+ return (audioControlData1 == null);
+ }
+
+ if (audioControlData1.getKeepContext() != audioControlData2.getKeepContext()) {
+ return false;
+ }
+
+ if (audioControlData1.getSource() != audioControlData2.getSource()) {
+ return false;
+ }
+
+ if (audioControlData1.getVolume() != audioControlData2.getVolume()) {
+ return false;
+ }
+
+ if (!(validateEqualizerSettingsList(audioControlData1.getEqualizerSettings(), audioControlData2.getEqualizerSettings()))) {
+ return false;
+ }
+
+
+ return true;
+ }
+
+ public static boolean validateHMISettingsControlData(HMISettingsControlData hmiSettingsControlData1, HMISettingsControlData hmiSettingsControlData2) {
+ if (hmiSettingsControlData1 == null) {
+ return (hmiSettingsControlData2 == null);
+ }
+ if (hmiSettingsControlData2 == null) {
+ return (hmiSettingsControlData1 == null);
+ }
+
+ if (hmiSettingsControlData1.getDisplayMode() != hmiSettingsControlData2.getDisplayMode()) {
+ return false;
+ }
+
+ if (hmiSettingsControlData1.getDistanceUnit() != hmiSettingsControlData2.getDistanceUnit()) {
+ return false;
+ }
+
+ if (hmiSettingsControlData1.getTemperatureUnit() != hmiSettingsControlData2.getTemperatureUnit()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean validateLightControlData(LightControlData lightControlData1, LightControlData lightControlData2) {
+ if (lightControlData1 == null) {
+ return (lightControlData2 == null);
+ }
+ if (lightControlData2 == null) {
+ return (lightControlData1 == null);
+ }
+
+ if (!(validateLightStateList(lightControlData1.getLightState(), lightControlData2.getLightState()))) {
+ return false;
+ }
+
+ return true;
+ }
+
public static boolean validateModuleData(ModuleData moduleData1, ModuleData moduleData2){
if(moduleData1 == null){
return ( moduleData2 == null );
@@ -731,6 +960,56 @@ public class Validator{
return true;
}
+ public static boolean validateSisData(SisData sisData1, SisData sisData2) {
+ if (sisData1 == null) {
+ return (sisData2 == null);
+ }
+ if (sisData2 == null) {
+ return (sisData1 == null);
+ }
+
+ if (sisData1.getStationShortName() != sisData2.getStationShortName()) {
+ return false;
+ }
+
+ if (!(validateStationIDNumber(sisData1.getStationIDNumber(), sisData2.getStationIDNumber()))) {
+ return false;
+ }
+
+ if (sisData1.getStationLongName() != sisData2.getStationLongName()) {
+ return false;
+ }
+
+ if (!(validateGpsData(sisData1.getStationLocation(), sisData2.getStationLocation()))) {
+ return false;
+ }
+
+ if (sisData1.getStationMessage() != sisData2.getStationMessage()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean validateStationIDNumber(StationIDNumber stationIDNumber1, StationIDNumber stationIDNumber2){
+ if(stationIDNumber1 == null){
+ return ( stationIDNumber2 == null );
+ }
+ if(stationIDNumber2 == null){
+ return ( stationIDNumber1 == null );
+ }
+
+ if(stationIDNumber1.getCountryCode() != stationIDNumber2.getCountryCode()){
+ return false;
+ }
+
+ if(stationIDNumber1.getFccFacilityId() != stationIDNumber2.getFccFacilityId()){
+ return false;
+ }
+
+ return true;
+ }
+
public static boolean validateRemoteControlCapabilities(RemoteControlCapabilities remoteControlCapabilities1, RemoteControlCapabilities remoteControlCapabilities2){
if(remoteControlCapabilities1 == null){
return ( remoteControlCapabilities2 == null );
@@ -903,6 +1182,33 @@ public class Validator{
return true;
}
+ public static boolean validateSeatMemoryAction(SeatMemoryAction item1, SeatMemoryAction item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.getAction() == null) {
+ return (item2.getAction() == null);
+ }
+
+ if (item1.getAction() != item2.getAction()) {
+ return false;
+ }
+
+ if (item1.getId() != item2.getId()) {
+ return false;
+ }
+
+ if (item1.getLabel() != item2.getLabel()) {
+ return false;
+ }
+
+ return true;
+ }
+
public static boolean validateTextFields(TextField item1, TextField item2){
if(item1 == null){
return ( item2 == null );
@@ -1364,6 +1670,30 @@ public class Validator{
return true;
}
+ public static boolean validateFuelRange (List<FuelRange> item1, List<FuelRange> item2) {
+ if (item1 == null) {
+ return ( item2 == null );
+ }
+ if (item2 == null) {
+ return ( item1 == null );
+ }
+
+ if (item1.size() != item2.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < item1.size(); i++) {
+ if (item1.get(i).getType() != item2.get(i).getType()) {
+ return false;
+ }
+ if (item1.get(i).getRange() != item2.get(i).getRange()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
public static boolean validatePermissionItem(PermissionItem item1, PermissionItem item2){
if(item1 == null){
return ( item2 == null );
@@ -1514,6 +1844,86 @@ public class Validator{
return true;
}
+ public static boolean validateMassageModeData(MassageModeData item1, MassageModeData item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.getMassageMode() != item2.getMassageMode()) {
+ return false;
+ }
+
+ if (item1.getMassageZone() != item2.getMassageZone()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean validateMassageModeDataList(List<MassageModeData> item1, List<MassageModeData> item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.size() != item2.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < item1.size(); i++) {
+ if (!validateMassageModeData(item1.get(i), item2.get(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean validateMassageCushionFirmness(MassageCushionFirmness item1, MassageCushionFirmness item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.getCushion() != item2.getCushion()) {
+ return false;
+ }
+
+ if (item1.getFirmness() != item2.getFirmness()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean validateMassageCushionFirmnessList(List<MassageCushionFirmness> item1, List<MassageCushionFirmness> item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.size() != item2.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < item1.size(); i++) {
+ if (!validateMassageCushionFirmness(item1.get(i), item2.get(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
public static void log(String tag, String msg){
Logger.log(tag, msg);
}
@@ -1533,25 +1943,67 @@ public class Validator{
return true;
}
-
+
public static boolean validateDeviceInfo (DeviceInfo item1, DeviceInfo item2) {
- if (item1 == null) {
- return ( item2 == null );
- }
- if (item2 == null) {
- return ( item1 == null );
- }
-
- if (item1.getOs() != item2.getOs() ||
- item1.getCarrier() != item2.getCarrier() ||
- item1.getHardware() != item2.getHardware() ||
- item1.getOsVersion() != item2.getOsVersion() ||
- item1.getFirmwareRev() != item2.getFirmwareRev() ||
- item1.getMaxNumberRFCOMMPorts() != item2.getMaxNumberRFCOMMPorts()) {
- return false;
- }
-
- return true;
+ if (item1 == null) {
+ return ( item2 == null );
+ }
+ if (item2 == null) {
+ return ( item1 == null );
+ }
+
+ if (item1.getOs() != item2.getOs() ||
+ item1.getCarrier() != item2.getCarrier() ||
+ item1.getHardware() != item2.getHardware() ||
+ item1.getOsVersion() != item2.getOsVersion() ||
+ item1.getFirmwareRev() != item2.getFirmwareRev() ||
+ item1.getMaxNumberRFCOMMPorts() != item2.getMaxNumberRFCOMMPorts()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean validateTemplateColorScheme (TemplateColorScheme item1, TemplateColorScheme item2) {
+ if (item1 == null) {
+ return ( item2 == null );
+ }
+ if (item2 == null) {
+ return ( item1 == null );
+ }
+
+ if (item1.getPrimaryColor().getRed() != item2.getPrimaryColor().getRed()
+ || item1.getPrimaryColor().getGreen() != item2.getPrimaryColor().getGreen()
+ || item1.getPrimaryColor().getBlue() != item2.getPrimaryColor().getBlue()
+ || item1.getSecondaryColor().getRed() != item2.getSecondaryColor().getRed()
+ || item1.getSecondaryColor().getGreen() != item2.getSecondaryColor().getGreen()
+ || item1.getSecondaryColor().getBlue() != item2.getSecondaryColor().getBlue()
+ || item1.getBackgroundColor().getRed() != item2.getBackgroundColor().getRed()
+ || item1.getBackgroundColor().getGreen() != item2.getBackgroundColor().getGreen()
+ || item1.getBackgroundColor().getBlue() != item2.getBackgroundColor().getBlue()
+
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean validateRGBColor(RGBColor item1, RGBColor item2) {
+ if (item1 == null) {
+ return ( item2 == null );
+ }
+ if (item2 == null) {
+ return ( item1 == null );
+ }
+
+ if (item1.getRed() != item2.getRed()
+ || item1.getGreen() != item2.getGreen()
+ || item1.getBlue() != item2.getBlue() ) {
+ return false;
+ }
+
+ return true;
}
public static boolean validateSupportedFormats (VideoStreamingFormat vsf1, VideoStreamingFormat vsf2) {
@@ -1565,7 +2017,7 @@ public class Validator{
return true;
}
-
+
public static boolean validateDisplayCapabilities (DisplayCapabilities item1, DisplayCapabilities item2) {
if (item1 == null) {
return ( item2 == null );
@@ -1581,6 +2033,10 @@ public class Validator{
if (item1.getDisplayType() != item2.getDisplayType()) {
return false;
}
+
+ if (!item1.getDisplayName().equals(item2.getDisplayName())) {
+ return false;
+ }
if (item1.getGraphicSupported() != item2.getGraphicSupported()) {
return false;
@@ -1823,6 +2279,274 @@ public class Validator{
return true;
}
+ public static boolean validateSeatControlCapabilities(SeatControlCapabilities item1, SeatControlCapabilities item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.getModuleName() != item2.getModuleName()) {
+ return false;
+ }
+ if (item1.getHeatingEnabledAvailable() != item2.getHeatingEnabledAvailable()) {
+ return false;
+ }
+ if (item1.getCoolingEnabledAvailable() != item2.getCoolingEnabledAvailable()) {
+ return false;
+ }
+ if (item1.getHeatingLevelAvailable() != item2.getHeatingLevelAvailable()) {
+ return false;
+ }
+ if (item1.getCoolingLevelAvailable() != item2.getCoolingLevelAvailable()) {
+ return false;
+ }
+ if (item1.getHorizontalPositionAvailable() != item2.getHorizontalPositionAvailable()) {
+ return false;
+ }
+ if (item1.getVerticalPositionAvailable() != item2.getVerticalPositionAvailable()) {
+ return false;
+ }
+ if (item1.getFrontVerticalPositionAvailable() != item2.getFrontVerticalPositionAvailable()) {
+ return false;
+ }
+ if (item1.getBackVerticalPositionAvailable() != item2.getBackVerticalPositionAvailable()) {
+ return false;
+ }
+ if (item1.getBackTiltAngleAvailable() != item2.getBackTiltAngleAvailable()) {
+ return false;
+ }
+ if (item1.getHeadSupportVerticalPositionAvailable() != item2.getHeadSupportVerticalPositionAvailable()) {
+ return false;
+ }
+ if (item1.getHeadSupportHorizontalPositionAvailable() != item2.getHeadSupportHorizontalPositionAvailable()) {
+ return false;
+ }
+ if (item1.getMassageEnabledAvailable() != item2.getMassageEnabledAvailable()) {
+ return false;
+ }
+ if (item1.getMassageModeAvailable() != item2.getMassageModeAvailable()) {
+ return false;
+ }
+ if (item1.getMassageCushionFirmnessAvailable() != item2.getMassageCushionFirmnessAvailable()) {
+ return false;
+ }
+ if (item1.getMemoryAvailable() != item2.getMemoryAvailable()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean validateSeatControlCapabilitiesList(List<SeatControlCapabilities> item1, List<SeatControlCapabilities> item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.size() != item2.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < item1.size(); i++) {
+ if (!validateSeatControlCapabilities(item1.get(i), item2.get(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean validateAudioControlCapabilities(AudioControlCapabilities item1, AudioControlCapabilities item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.getModuleName() != item2.getModuleName()) {
+ return false;
+ }
+ if (item1.getSourceAvailable() != item2.getSourceAvailable()) {
+ return false;
+ }
+ if (item1.getKeepContextAvailable() != item2.getKeepContextAvailable()) {
+ return false;
+ }
+ if (item1.getVolumeAvailable() != item2.getVolumeAvailable()) {
+ return false;
+ }
+ if (item1.getEqualizerAvailable() != item2.getEqualizerAvailable()) {
+ return false;
+ }
+ if (item1.getEqualizerMaxChannelId() != item2.getEqualizerMaxChannelId()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean validateEqualizerSettingsList(List<EqualizerSettings> item1, List<EqualizerSettings> item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.size() != item2.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < item1.size(); i++) {
+ if (!validateEqualizerSettings(item1.get(i), item2.get(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean validateEqualizerSettings(EqualizerSettings item1, EqualizerSettings item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.getChannelId() != item2.getChannelId()) {
+ return false;
+ }
+
+ if (item1.getChannelName() != item2.getChannelName()) {
+ return false;
+ }
+
+ if (item1.getChannelSetting() != item2.getChannelSetting()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean validateLightStateList(List<LightState> item1, List<LightState> item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.size() != item2.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < item1.size(); i++) {
+ if (!validateLightState(item1.get(i), item2.get(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean validateLightState(LightState item1, LightState item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.getId() != item2.getId()) {
+ return false;
+ }
+
+ if (item1.getStatus() != item2.getStatus()) {
+ return false;
+ }
+
+ if (item1.getDensity() != item2.getDensity()) {
+ return false;
+ }
+
+ if (!(validateRGBColor(item1.getColor(), item2.getColor()))) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean validateLightCapabilitiesList(List<LightCapabilities> item1, List<LightCapabilities> item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.size() != item2.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < item1.size(); i++) {
+ if (!validateLightCapabilities(item1.get(i), item2.get(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean validateLightCapabilities(LightCapabilities item1, LightCapabilities item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.getName() != item2.getName()) {
+ return false;
+ }
+
+ if (item1.getDensityAvailable() != item2.getDensityAvailable()) {
+ return false;
+ }
+
+ if (item1.getRGBColorSpaceAvailable() != item2.getRGBColorSpaceAvailable()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean validateAudioControlCapabilitiesList(List<AudioControlCapabilities> item1, List<AudioControlCapabilities> item2) {
+ if (item1 == null) {
+ return (item2 == null);
+ }
+ if (item2 == null) {
+ return (item1 == null);
+ }
+
+ if (item1.size() != item2.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < item1.size(); i++) {
+ if (!validateAudioControlCapabilities(item1.get(i), item2.get(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
public static boolean validateDefrostZones (List<DefrostZone> item1, List<DefrostZone> item2) {
if (item1 == null) {
return ( item2 == null );
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/VehicleDataHelper.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/VehicleDataHelper.java
index ef19542fa..22ce7a15b 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/VehicleDataHelper.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/VehicleDataHelper.java
@@ -7,6 +7,7 @@ import com.smartdevicelink.proxy.rpc.ClusterModeStatus;
import com.smartdevicelink.proxy.rpc.DeviceStatus;
import com.smartdevicelink.proxy.rpc.ECallInfo;
import com.smartdevicelink.proxy.rpc.EmergencyEvent;
+import com.smartdevicelink.proxy.rpc.FuelRange;
import com.smartdevicelink.proxy.rpc.GPSData;
import com.smartdevicelink.proxy.rpc.GetVehicleDataResponse;
import com.smartdevicelink.proxy.rpc.HeadLampStatus;
@@ -21,20 +22,30 @@ import com.smartdevicelink.proxy.rpc.enums.ComponentVolumeStatus;
import com.smartdevicelink.proxy.rpc.enums.DeviceLevelStatus;
import com.smartdevicelink.proxy.rpc.enums.Dimension;
import com.smartdevicelink.proxy.rpc.enums.ECallConfirmationStatus;
+import com.smartdevicelink.proxy.rpc.enums.ElectronicParkBrakeStatus;
import com.smartdevicelink.proxy.rpc.enums.EmergencyEventType;
import com.smartdevicelink.proxy.rpc.enums.FuelCutoffStatus;
+import com.smartdevicelink.proxy.rpc.enums.FuelType;
import com.smartdevicelink.proxy.rpc.enums.IgnitionStableStatus;
import com.smartdevicelink.proxy.rpc.enums.IgnitionStatus;
import com.smartdevicelink.proxy.rpc.enums.PRNDL;
import com.smartdevicelink.proxy.rpc.enums.PowerModeQualificationStatus;
import com.smartdevicelink.proxy.rpc.enums.PowerModeStatus;
import com.smartdevicelink.proxy.rpc.enums.PrimaryAudioSource;
+import com.smartdevicelink.proxy.rpc.enums.TurnSignal;
import com.smartdevicelink.proxy.rpc.enums.VehicleDataEventStatus;
import com.smartdevicelink.proxy.rpc.enums.VehicleDataNotificationStatus;
import com.smartdevicelink.proxy.rpc.enums.VehicleDataStatus;
import com.smartdevicelink.proxy.rpc.enums.WarningLightStatus;
import com.smartdevicelink.proxy.rpc.enums.WiperStatus;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
public class VehicleDataHelper{
//top level variables for OnVehicleData
public static final double SPEED = 35.6;
@@ -45,6 +56,7 @@ public class VehicleDataHelper{
public static final PRNDL PRNDL_FINAL = PRNDL.SECOND;
public static final TireStatus TIRE_PRESSURE = new TireStatus();
public static final double ENGINE_TORQUE = 518.3;
+ public static final float ENGINE_OIL_LIFE = 19.3f;
public static final int ODOMETER = 140000;
public static final GPSData GPS = new GPSData();
public static final ComponentVolumeStatus FUEL_LEVEL_STATE = ComponentVolumeStatus.ALERT;
@@ -62,7 +74,11 @@ public class VehicleDataHelper{
public static final EmergencyEvent EMERGENCY_EVENT = new EmergencyEvent();
public static final ClusterModeStatus CLUSTER_MODE_STATUS = new ClusterModeStatus();
public static final MyKey MY_KEY = new MyKey();
-
+ public static final FuelRange FUEL_RANGE = new FuelRange();
+ public static final List<FuelRange> FUEL_RANGE_LIST = new ArrayList<FuelRange>(1);
+ public static final TurnSignal TURN_SIGNAL = TurnSignal.OFF;
+ public static final ElectronicParkBrakeStatus ELECTRONIC_PARK_BRAKE_STATUS = ElectronicParkBrakeStatus.CLOSED;
+
//other variables inside some of the above objects
// tire status
public static final WarningLightStatus TIRE_PRESSURE_TELL_TALE = WarningLightStatus.ON;
@@ -168,7 +184,13 @@ public class VehicleDataHelper{
// my key
public static final VehicleDataStatus MY_KEY_E_911_OVERRIDE = VehicleDataStatus.NO_DATA_EXISTS;
-
+
+ // fuel range
+ public static final FuelType FUEL_RANGE_TYPE = FuelType.GASOLINE;
+ public static final Float FUEL_RANGE_RANGE = Test.GENERAL_FLOAT;
+
+ public static final JSONArray JSON_FUEL_RANGE = new JSONArray();
+
//the OnVehicleData which stores all the information above
public static final OnVehicleData VEHICLE_DATA = new OnVehicleData();
//GetVehicleDataResponse data which stores the same things
@@ -290,9 +312,20 @@ public class VehicleDataHelper{
//MY_KEY set up
MY_KEY.setE911Override(MY_KEY_E_911_OVERRIDE);
-
-
- //set up the OnVehicleData object
+
+ // FUEL_RANGE and FUEL_RANGE_LIST set up
+ FUEL_RANGE.setType(FUEL_RANGE_TYPE);
+ FUEL_RANGE.setRange(FUEL_RANGE_RANGE);
+ FUEL_RANGE_LIST.add(FUEL_RANGE);
+
+ // FUEL_RANGE json array set up
+ try {
+ JSON_FUEL_RANGE.put(FUEL_RANGE.serializeJSON());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ //set up the OnVehicleData object
VEHICLE_DATA.setSpeed(SPEED);
VEHICLE_DATA.setRpm(RPM);
VEHICLE_DATA.setExternalTemperature(EXTERNAL_TEMPERATURE);
@@ -301,6 +334,7 @@ public class VehicleDataHelper{
VEHICLE_DATA.setPrndl(PRNDL_FINAL);
VEHICLE_DATA.setTirePressure(TIRE_PRESSURE);
VEHICLE_DATA.setEngineTorque(ENGINE_TORQUE);
+ VEHICLE_DATA.setEngineOilLife(ENGINE_OIL_LIFE);
VEHICLE_DATA.setOdometer(ODOMETER);
VEHICLE_DATA.setGps(GPS);
VEHICLE_DATA.setFuelLevelState(FUEL_LEVEL_STATE);
@@ -318,6 +352,9 @@ public class VehicleDataHelper{
VEHICLE_DATA.setEmergencyEvent(EMERGENCY_EVENT);
VEHICLE_DATA.setClusterModeStatus(CLUSTER_MODE_STATUS);
VEHICLE_DATA.setMyKey(MY_KEY);
+ VEHICLE_DATA.setFuelRange(FUEL_RANGE_LIST);
+ VEHICLE_DATA.setTurnSignal(TURN_SIGNAL);
+ VEHICLE_DATA.setElectronicParkBrakeStatus(ELECTRONIC_PARK_BRAKE_STATUS);
//set up the GetVehicleDataResponse object
VEHICLE_DATA_RESPONSE.setSpeed(SPEED);
@@ -328,6 +365,7 @@ public class VehicleDataHelper{
VEHICLE_DATA_RESPONSE.setPrndl(PRNDL_FINAL);
VEHICLE_DATA_RESPONSE.setTirePressure(TIRE_PRESSURE);
VEHICLE_DATA_RESPONSE.setEngineTorque(ENGINE_TORQUE);
+ VEHICLE_DATA_RESPONSE.setEngineOilLife(ENGINE_OIL_LIFE);
VEHICLE_DATA_RESPONSE.setOdometer(ODOMETER);
VEHICLE_DATA_RESPONSE.setGps(GPS);
VEHICLE_DATA_RESPONSE.setFuelLevelState(FUEL_LEVEL_STATE);
@@ -345,6 +383,9 @@ public class VehicleDataHelper{
VEHICLE_DATA_RESPONSE.setEmergencyEvent(EMERGENCY_EVENT);
VEHICLE_DATA_RESPONSE.setClusterModeStatus(CLUSTER_MODE_STATUS);
VEHICLE_DATA_RESPONSE.setMyKey(MY_KEY);
+ VEHICLE_DATA_RESPONSE.setFuelRange(FUEL_RANGE_LIST);
+ VEHICLE_DATA_RESPONSE.setTurnSignal(TURN_SIGNAL);
+ VEHICLE_DATA_RESPONSE.setElectronicParkBrakeStatus(ELECTRONIC_PARK_BRAKE_STATUS);
}
private VehicleDataHelper(){}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/BinaryFrameHeaderTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/BinaryFrameHeaderTests.java
index 60a97a35c..a1b108fea 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/BinaryFrameHeaderTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/BinaryFrameHeaderTests.java
@@ -2,14 +2,12 @@ package com.smartdevicelink.test.protocol;
import junit.framework.Assert;
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.protocol.BinaryFrameHeader;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.test.SampleRpc;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-public class BinaryFrameHeaderTests extends AndroidTestCase {
+public class BinaryFrameHeaderTests extends AndroidTestCase2 {
public static final byte RPC_TYPE_REQUEST = 0x00;
public static final byte RPC_TYPE_RESPONSE = 0x01;
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/FrameDataControlFrameTypeTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/FrameDataControlFrameTypeTests.java
index 89d040c90..76090277a 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/FrameDataControlFrameTypeTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/FrameDataControlFrameTypeTests.java
@@ -134,7 +134,11 @@ public class FrameDataControlFrameTypeTests extends TestCase {
enumTestList.add(FrameDataControlFrameType.EndSessionNACK);
enumTestList.add(FrameDataControlFrameType.ServiceDataACK);
enumTestList.add(FrameDataControlFrameType.HeartbeatACK);
-
+ enumTestList.add(FrameDataControlFrameType.RegisterSecondaryTransport);
+ enumTestList.add(FrameDataControlFrameType.RegisterSecondaryTransportACK);
+ enumTestList.add(FrameDataControlFrameType.RegisterSecondaryTransportNACK);
+ enumTestList.add(FrameDataControlFrameType.TransportEventUpdate);
+
assertTrue("List does not match enum test list.",
list.containsAll(enumTestList) &&
enumTestList.containsAll(list));
@@ -142,11 +146,14 @@ public class FrameDataControlFrameTypeTests extends TestCase {
// Test Array
FrameDataControlFrameType[] enumValueArray = FrameDataControlFrameType.values();
FrameDataControlFrameType[] enumTestArray = {
- FrameDataControlFrameType.Heartbeat, FrameDataControlFrameType.StartSession,
- FrameDataControlFrameType.StartSessionACK, FrameDataControlFrameType.StartSessionNACK,
- FrameDataControlFrameType.EndSession, FrameDataControlFrameType.EndSessionACK,
- FrameDataControlFrameType.EndSessionNACK, FrameDataControlFrameType.ServiceDataACK,
- FrameDataControlFrameType.HeartbeatACK, };
+ FrameDataControlFrameType.Heartbeat, FrameDataControlFrameType.StartSession,
+ FrameDataControlFrameType.StartSessionACK, FrameDataControlFrameType.StartSessionNACK,
+ FrameDataControlFrameType.EndSession, FrameDataControlFrameType.EndSessionACK,
+ FrameDataControlFrameType.EndSessionNACK, FrameDataControlFrameType.RegisterSecondaryTransport,
+ FrameDataControlFrameType.RegisterSecondaryTransportACK, FrameDataControlFrameType.RegisterSecondaryTransportNACK,
+ FrameDataControlFrameType.TransportEventUpdate, FrameDataControlFrameType.ServiceDataACK,
+ FrameDataControlFrameType.HeartbeatACK,
+ };
assertTrue("Array does not match enum values array.",
Validator.validateFrameDataControlFrameTypeArray(enumValueArray, enumTestArray));
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/LockScreenManagerTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/LockScreenManagerTest.java
index ceba82f36..1d02875b1 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/LockScreenManagerTest.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/LockScreenManagerTest.java
@@ -12,7 +12,7 @@ import com.smartdevicelink.test.Test;
* This is a unit test class for the SmartDeviceLink library project class :
* {@link com.smartdevicelink.proxy.LockScreenManager}
*/
-public class LockScreenManagerTest extends TestCase{
+public class LockScreenManagerTest extends TestCase {
/**
* This is a unit test for the following methods :
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/RPCRequestTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/RPCRequestTest.java
index 5c1b9436d..eea733631 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/RPCRequestTest.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/RPCRequestTest.java
@@ -1,22 +1,15 @@
package com.smartdevicelink.test.proxy;
-import android.test.AndroidTestCase;
-import com.smartdevicelink.protocol.enums.FunctionID;
-import com.smartdevicelink.proxy.RPCMessage;
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.proxy.RPCRequest;
-import com.smartdevicelink.proxy.RPCResponse;
import com.smartdevicelink.proxy.rpc.GetSystemCapability;
import com.smartdevicelink.test.Config;
-import com.smartdevicelink.test.JsonUtils;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
+import junit.framework.TestCase;
-import java.util.Iterator;
-public class RPCRequestTest extends AndroidTestCase {
+public class RPCRequestTest extends AndroidTestCase2 {
public static final int SDL_VERSION_UNDER_TEST = Config.SDL_VERSION_UNDER_TEST;
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SdlProxyBaseTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SdlProxyBaseTests.java
index b50f6f48d..aecbb44f0 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SdlProxyBaseTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SdlProxyBaseTests.java
@@ -1,11 +1,10 @@
package com.smartdevicelink.test.proxy;
import android.content.Context;
-import android.os.Bundle;
import android.telephony.TelephonyManager;
-import android.test.AndroidTestCase;
import android.util.Log;
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.exception.SdlException;
import com.smartdevicelink.exception.SdlExceptionCause;
import com.smartdevicelink.proxy.RPCRequest;
@@ -50,6 +49,7 @@ import com.smartdevicelink.proxy.rpc.OnKeyboardInput;
import com.smartdevicelink.proxy.rpc.OnLanguageChange;
import com.smartdevicelink.proxy.rpc.OnLockScreenStatus;
import com.smartdevicelink.proxy.rpc.OnPermissionsChange;
+import com.smartdevicelink.proxy.rpc.OnRCStatus;
import com.smartdevicelink.proxy.rpc.OnStreamRPC;
import com.smartdevicelink.proxy.rpc.OnSystemRequest;
import com.smartdevicelink.proxy.rpc.OnTBTClientState;
@@ -97,7 +97,7 @@ import java.util.ArrayList;
import java.util.List;
-public class SdlProxyBaseTests extends AndroidTestCase{
+public class SdlProxyBaseTests extends AndroidTestCase2 {
public static final String TAG = "SdlProxyBaseTests";
@Override
@@ -117,7 +117,7 @@ public class SdlProxyBaseTests extends AndroidTestCase{
public void testNullSdlProxyConfigurationResources() {
SdlProxyALM proxy = null;
SdlProxyBuilder.Builder builder = new SdlProxyBuilder.Builder(new ProxyListenerTest(), "appId", "appName", true, getContext());
- SdlProxyConfigurationResources config = new SdlProxyConfigurationResources("path", (TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE));
+ SdlProxyConfigurationResources config = new SdlProxyConfigurationResources("path", (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE));
//Construct with a non-null SdlProxyConfigurationResources
builder.setSdlProxyConfigurationResources(config);
try {
@@ -125,7 +125,17 @@ public class SdlProxyBaseTests extends AndroidTestCase{
} catch (Exception e) {
Log.v(TAG, "Exception in testNullSdlProxyConfigurationResources, testing non null SdlProxyConfigurationResources");
if (!(e instanceof SdlException) || !((SdlException) e).getSdlExceptionCause().equals(SdlExceptionCause.BLUETOOTH_ADAPTER_NULL)) {
- Assert.fail("Exception in testNullSdlProxyConfigurationResources");
+ e.printStackTrace();
+ Assert.fail("Exception in testNullSdlProxyConfigurationResources - \n" + e.toString());
+ }
+ }
+
+ if (proxy != null) {
+ try {
+ proxy.dispose();
+ proxy = null;
+ }catch(SdlException e){
+ e.printStackTrace();
}
}
@@ -136,9 +146,18 @@ public class SdlProxyBaseTests extends AndroidTestCase{
} catch (Exception e) {
Log.v(TAG, "Exception in testNullSdlProxyConfigurationResources, testing null SdlProxyConfigurationResources");
if (!(e instanceof SdlException) || !((SdlException) e).getSdlExceptionCause().equals(SdlExceptionCause.BLUETOOTH_ADAPTER_NULL)) {
+ e.printStackTrace();
Assert.fail("Exception in testNullSdlProxyConfigurationResources, testing null SdlProxyConfigurationResources");
}
}
+ if (proxy != null) {
+ try {
+ proxy.dispose();
+ proxy = null;
+ }catch(SdlException e){
+ e.printStackTrace();
+ }
+ }
//Construct with a non-null SdlProxyConfigurationResources and a null TelephonyManager
config.setTelephonyManager(null);
@@ -151,6 +170,14 @@ public class SdlProxyBaseTests extends AndroidTestCase{
Assert.fail("Exception in testNullSdlProxyConfigurationResources, testing null TelephonyManager");
}
}
+ if (proxy != null) {
+ try {
+ proxy.dispose();
+ proxy = null;
+ }catch(SdlException e){
+ e.printStackTrace();
+ }
+ }
}
public void testRemoteDisplayStreaming(){
@@ -619,5 +646,9 @@ public class SdlProxyBaseTests extends AndroidTestCase{
public void onSendHapticDataResponse(SendHapticDataResponse response) {
Log.i(TAG, "SendHapticDataResponse response from SDL: " + response);
}
- }
+
+ @Override
+ public void onOnRCStatus(OnRCStatus notification) {
+ }
+ }
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SystemCapabilityManagerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SystemCapabilityManagerTests.java
index 8d2ef8d20..91bd19d34 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SystemCapabilityManagerTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/proxy/SystemCapabilityManagerTests.java
@@ -1,13 +1,14 @@
package com.smartdevicelink.test.proxy;
-import android.test.AndroidTestCase;
-
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.protocol.enums.SessionType;
import com.smartdevicelink.proxy.RPCRequest;
import com.smartdevicelink.proxy.SystemCapabilityManager;
+import com.smartdevicelink.proxy.interfaces.IAudioStreamListener;
import com.smartdevicelink.proxy.interfaces.ISdl;
import com.smartdevicelink.proxy.interfaces.ISdlServiceListener;
+import com.smartdevicelink.proxy.interfaces.IVideoStreamListener;
import com.smartdevicelink.proxy.interfaces.OnSystemCapabilityListener;
import com.smartdevicelink.proxy.rpc.AudioPassThruCapabilities;
import com.smartdevicelink.proxy.rpc.ButtonCapabilities;
@@ -16,21 +17,27 @@ import com.smartdevicelink.proxy.rpc.GetSystemCapabilityResponse;
import com.smartdevicelink.proxy.rpc.HMICapabilities;
import com.smartdevicelink.proxy.rpc.PresetBankCapabilities;
import com.smartdevicelink.proxy.rpc.RegisterAppInterfaceResponse;
+import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
import com.smartdevicelink.proxy.rpc.SoftButtonCapabilities;
import com.smartdevicelink.proxy.rpc.SystemCapability;
import com.smartdevicelink.proxy.rpc.VideoStreamingCapability;
import com.smartdevicelink.proxy.rpc.enums.HmiZoneCapabilities;
import com.smartdevicelink.proxy.rpc.enums.SpeechCapabilities;
import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
+import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCListener;
import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
+import com.smartdevicelink.streaming.audio.AudioStreamingCodec;
+import com.smartdevicelink.streaming.audio.AudioStreamingParams;
import com.smartdevicelink.streaming.video.VideoStreamingParameters;
import com.smartdevicelink.test.Test;
import com.smartdevicelink.test.Validator;
import com.smartdevicelink.util.CorrelationIdGenerator;
+import com.smartdevicelink.util.Version;
import java.util.List;
-public class SystemCapabilityManagerTests extends AndroidTestCase {
+public class SystemCapabilityManagerTests extends AndroidTestCase2 {
public static final String TAG = "SystemCapabilityManagerTests";
public static SystemCapabilityManager systemCapabilityManager;
@@ -131,6 +138,12 @@ public class SystemCapabilityManagerTests extends AndroidTestCase {
}
+ public void testFalsePositive(){
+ SystemCapabilityManager systemCapabilityManager = createSampleManager();
+ systemCapabilityManager.setCapability(SystemCapabilityType.AUDIO_PASSTHROUGH, null);
+ assertFalse(systemCapabilityManager.isCapabilitySupported(SystemCapabilityType.AUDIO_PASSTHROUGH));
+ }
+
private class InternalSDLInterface implements ISdl{
@Override
public void start(){}
@@ -154,19 +167,79 @@ public class SystemCapabilityManagerTests extends AndroidTestCase {
public void stopVideoService() {}
@Override
- public void startAudioService(boolean encrypted) {}
-
- @Override
public void stopAudioService() {}
@Override
public void sendRPCRequest(RPCRequest message) {}
@Override
+ public void sendRequests(List<? extends RPCRequest> rpcs, OnMultipleRequestListener listener) {
+
+ }
+
+ @Override
public void addOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {}
@Override
public boolean removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {return false;}
+
+ @Override
+ public void addOnRPCListener(FunctionID responseId, OnRPCListener listener) { }
+
+ @Override
+ public boolean removeOnRPCListener(FunctionID responseId, OnRPCListener listener) { return false; }
+
+ @Override
+ public Object getCapability(SystemCapabilityType systemCapabilityType){return null;}
+
+ @Override
+ public void getCapability(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener scListener) { }
+
+ @Override
+ public SdlMsgVersion getSdlMsgVersion(){
+ return null;
+ }
+
+ @Override
+ public Version getProtocolVersion() {
+ return new Version(1,0,0);
+ }
+
+
+ @Override
+ public boolean isCapabilitySupported(SystemCapabilityType systemCapabilityType){
+ return false;
+ }
+
+ @Override
+ public void addOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) { }
+
+ @Override
+ public boolean removeOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) { return false; }
+
+ @Override
+ public boolean isTransportForServiceAvailable(SessionType serviceType) {
+ return false;
+ }
+
+ @Override
+ public void startAudioService(boolean isEncrypted, AudioStreamingCodec codec,
+ AudioStreamingParams params) {}
+
+ @Override
+ public IVideoStreamListener startVideoStream(boolean isEncrypted, VideoStreamingParameters parameters){
+ return null;
+ }
+
+ @Override
+ public IAudioStreamListener startAudioStream(boolean isEncrypted, AudioStreamingCodec codec,
+ AudioStreamingParams params) {
+ return null;
+ }
+
+ @Override
+ public void startAudioService(boolean encrypted){}
+
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/RPCConstructorsTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/RPCConstructorsTests.java
index 028f5dd30..7b497310e 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/RPCConstructorsTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/RPCConstructorsTests.java
@@ -1,6 +1,7 @@
package com.smartdevicelink.test.rpc;
-import android.test.AndroidTestCase;
+
+import com.smartdevicelink.AndroidTestCase2;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -23,9 +24,9 @@ import java.util.Map;
* It makes sure that for each RPC, all mandatory parameters are set in a constructor
*/
-public class RPCConstructorsTests extends AndroidTestCase {
+public class RPCConstructorsTests extends AndroidTestCase2 {
- private final String XML_FILE_NAME = "xml/MOBILE_API_4.5.0.xml";
+ private final String XML_FILE_NAME = "xml/MOBILE_API.xml";
private final String RPC_PACKAGE_PREFIX = "com.smartdevicelink.proxy.rpc.";
private Map<String, List<Parameter>> rpcMandatoryParamsMapFromXml;
@@ -97,7 +98,7 @@ public class RPCConstructorsTests extends AndroidTestCase {
}
}
// Store the mandatory params for the current RPC in the map
- if(name.equals("param") && !ignoreRPC){
+ if(name.equals("param") && myParser.getAttributeValue(null, "until") == null && !ignoreRPC){
boolean mandatory = Boolean.valueOf(myParser.getAttributeValue(null,"mandatory"));
if (mandatory) {
String paramName = myParser.getAttributeValue(null, "name");
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/AudioControlCapabilitiesTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/AudioControlCapabilitiesTests.java
new file mode 100644
index 000000000..524a6bde2
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/AudioControlCapabilitiesTests.java
@@ -0,0 +1,94 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.proxy.rpc.AudioControlCapabilities;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.proxy.rpc.AudioControlCapabilities}
+ */
+public class AudioControlCapabilitiesTests extends TestCase {
+
+ private AudioControlCapabilities msg;
+
+ @Override
+ public void setUp() {
+ msg = new AudioControlCapabilities();
+
+ msg.setModuleName(Test.GENERAL_STRING);
+ msg.setSourceAvailable(Test.GENERAL_BOOLEAN);
+ msg.setKeepContextAvailable(Test.GENERAL_BOOLEAN);
+ msg.setVolumeAvailable(Test.GENERAL_BOOLEAN);
+ msg.setEqualizerAvailable(Test.GENERAL_BOOLEAN);
+ msg.setVolumeAvailable(Test.GENERAL_BOOLEAN);
+ msg.setEqualizerMaxChannelId(Test.GENERAL_INT);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+
+ String moduleName = msg.getModuleName();
+ Boolean sourceAvailable = msg.getSourceAvailable();
+ Boolean keepContextAvailable = msg.getKeepContextAvailable();
+ Boolean volumeAvailable = msg.getVolumeAvailable();
+ Boolean equalizerAvailable = msg.getEqualizerAvailable();
+ int equalizerMaxChannelId = msg.getEqualizerMaxChannelId();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_STRING, moduleName);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, (boolean) sourceAvailable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, (boolean) keepContextAvailable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, (boolean) volumeAvailable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, (boolean) equalizerAvailable);
+ assertEquals(Test.MATCH, Test.GENERAL_INT, equalizerMaxChannelId);
+
+ // Invalid/Null Tests
+ AudioControlCapabilities msg = new AudioControlCapabilities();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getModuleName());
+ assertNull(Test.NULL, msg.getSourceAvailable());
+ assertNull(Test.NULL, msg.getKeepContextAvailable());
+ assertNull(Test.NULL, msg.getVolumeAvailable());
+ assertNull(Test.NULL, msg.getEqualizerAvailable());
+ assertNull(Test.NULL, msg.getEqualizerMaxChannelId());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+
+ reference.put(AudioControlCapabilities.KEY_MODULE_NAME, Test.GENERAL_STRING);
+ reference.put(AudioControlCapabilities.KEY_SOURCE_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(AudioControlCapabilities.KEY_KEEP_CONTEXT_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(AudioControlCapabilities.KEY_VOLUME_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(AudioControlCapabilities.KEY_EQUALIZER_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(AudioControlCapabilities.KEY_EQUALIZER_MAX_CHANNEL_ID, Test.GENERAL_INT);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/AudioControlDataTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/AudioControlDataTests.java
new file mode 100644
index 000000000..4dba080ac
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/AudioControlDataTests.java
@@ -0,0 +1,98 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.proxy.rpc.AudioControlData;
+import com.smartdevicelink.proxy.rpc.EqualizerSettings;
+import com.smartdevicelink.proxy.rpc.enums.PrimaryAudioSource;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+import com.smartdevicelink.test.Validator;
+
+import junit.framework.TestCase;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.AudioControlData}
+ */
+public class AudioControlDataTests extends TestCase {
+
+ private AudioControlData msg;
+
+ @Override
+ public void setUp() {
+ msg = new AudioControlData();
+
+ msg.setSource(Test.GENERAL_PRIMARYAUDIOSOURCE);
+ msg.setKeepContext(Test.GENERAL_BOOLEAN);
+ msg.setVolume(Test.GENERAL_INT);
+ msg.setEqualizerSettings(Test.GENERAL_EQUALIZERSETTINGS_LIST);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+ PrimaryAudioSource source = msg.getSource();
+ Boolean keepContext = msg.getKeepContext();
+ int volume = msg.getVolume();
+ List<EqualizerSettings> equalizerSettings = msg.getEqualizerSettings();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_PRIMARYAUDIOSOURCE, source);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, (boolean) keepContext);
+ assertEquals(Test.MATCH, Test.GENERAL_INT, volume);
+ assertEquals(Test.MATCH, Test.GENERAL_EQUALIZERSETTINGS_LIST.size(), equalizerSettings.size());
+
+ assertTrue(Test.TRUE, Validator.validateEqualizerSettingsList(Test.GENERAL_EQUALIZERSETTINGS_LIST, equalizerSettings));
+
+ // Invalid/Null Tests
+ AudioControlData msg = new AudioControlData();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getSource());
+ assertNull(Test.NULL, msg.getVolume());
+ assertNull(Test.NULL, msg.getKeepContext());
+ assertNull(Test.NULL, msg.getEqualizerSettings());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(AudioControlData.KEY_SOURCE, Test.GENERAL_PRIMARYAUDIOSOURCE);
+ reference.put(AudioControlData.KEY_KEEP_CONTEXT, Test.GENERAL_BOOLEAN);
+ reference.put(AudioControlData.KEY_VOLUME, Test.GENERAL_INT);
+ reference.put(AudioControlData.KEY_EQUALIZER_SETTINGS, Test.GENERAL_EQUALIZERSETTINGS_LIST);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ if (key.equals(AudioControlData.KEY_EQUALIZER_SETTINGS)) {
+ List<EqualizerSettings> esReference = (List<EqualizerSettings>) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONArray esArray = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
+ int i = 0;
+ for (EqualizerSettings es : esReference) {
+ assertTrue(Validator.validateEqualizerSettings(es, new EqualizerSettings(JsonRPCMarshaller.deserializeJSONObject(esArray.getJSONObject(i++)))));
+ }
+ } else {
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+ }
+
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ChoiceTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ChoiceTests.java
index e53ea8c2a..0df50f405 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ChoiceTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ChoiceTests.java
@@ -18,7 +18,7 @@ import com.smartdevicelink.test.Validator;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.Choice}
+ * {@link com.smartdevicelink.proxy.rpc.Choice}
*/
public class ChoiceTests extends TestCase{
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ClimateControlCapabilitiesTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ClimateControlCapabilitiesTests.java
index 33f9d2631..c391eb4eb 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ClimateControlCapabilitiesTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ClimateControlCapabilitiesTests.java
@@ -17,7 +17,7 @@ import java.util.Iterator;
import java.util.List;
/**
- * This is a unit test class for the SmartDeviceLink library project class :
+ * This is a unit test class for the SmartDeviceLink library project class :
* {@link com.smartdevicelink.rpc.ClimateControlCapabilities}
*/
public class ClimateControlCapabilitiesTests extends TestCase{
@@ -40,6 +40,10 @@ public class ClimateControlCapabilitiesTests extends TestCase{
msg.setDefrostZone(Test.GENERAL_DEFROSTZONE_LIST);
msg.setVentilationModeAvailable(Test.GENERAL_BOOLEAN);
msg.setVentilationMode(Test.GENERAL_VENTILATIONMODE_LIST);
+ msg.setHeatedSteeringWheelAvailable(Test.GENERAL_BOOLEAN);
+ msg.setHeatedWindshieldAvailable(Test.GENERAL_BOOLEAN);
+ msg.setHeatedRearWindowAvailable(Test.GENERAL_BOOLEAN);
+ msg.setHeatedMirrorsAvailable(Test.GENERAL_BOOLEAN);
}
/**
@@ -59,6 +63,10 @@ public class ClimateControlCapabilitiesTests extends TestCase{
List<DefrostZone> defrostZone = msg.getDefrostZone();
boolean ventilationModeAvailable = msg.getVentilationModeAvailable();
List<VentilationMode> ventilationMode = msg.getVentilationMode();
+ boolean heatedSteeringWheelAvailable = msg.getHeatedSteeringWheelAvailable();
+ boolean heatedWindshieldAvailable = msg.getHeatedWindshieldAvailable();
+ boolean heatedRearWindowAvailable = msg.getHeatedRearWindowAvailable();
+ boolean heatedMirrorsAvailable = msg.getHeatedMirrorsAvailable();
// Valid Tests
assertEquals(Test.MATCH, Test.GENERAL_STRING, moduleName);
@@ -82,6 +90,10 @@ public class ClimateControlCapabilitiesTests extends TestCase{
assertEquals(Test.MATCH, Test.GENERAL_VENTILATIONMODE_LIST.get(i), ventilationMode.get(i));
}
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, heatedSteeringWheelAvailable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, heatedWindshieldAvailable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, heatedRearWindowAvailable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, heatedMirrorsAvailable);
// Invalid/Null Tests
ClimateControlCapabilities msg = new ClimateControlCapabilities();
assertNotNull(Test.NOT_NULL, msg);
@@ -97,6 +109,10 @@ public class ClimateControlCapabilitiesTests extends TestCase{
assertNull(Test.NULL, msg.getDefrostZone());
assertNull(Test.NULL, msg.getVentilationModeAvailable());
assertNull(Test.NULL, msg.getVentilationMode());
+ assertNull(Test.NULL, msg.getHeatedSteeringWheelAvailable());
+ assertNull(Test.NULL, msg.getHeatedWindshieldAvailable());
+ assertNull(Test.NULL, msg.getHeatedRearWindowAvailable());
+ assertNull(Test.NULL, msg.getHeatedMirrorsAvailable());
}
public void testJson(){
@@ -115,6 +131,10 @@ public class ClimateControlCapabilitiesTests extends TestCase{
reference.put(ClimateControlCapabilities.KEY_VENTILATION_MODE_AVAILABLE, Test.GENERAL_BOOLEAN);
reference.put(ClimateControlCapabilities.KEY_DEFROST_ZONE, JsonUtils.createJsonArray(Test.GENERAL_DEFROSTZONE_LIST));
reference.put(ClimateControlCapabilities.KEY_VENTILATION_MODE, JsonUtils.createJsonArray(Test.GENERAL_VENTILATIONMODE_LIST));
+ reference.put(ClimateControlCapabilities.KEY_HEATED_STEERING_WHEEL_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(ClimateControlCapabilities.KEY_HEATED_WIND_SHIELD_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(ClimateControlCapabilities.KEY_HEATED_REAR_WINDOW_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(ClimateControlCapabilities.KEY_HEATED_MIRRORS_AVAILABLE, Test.GENERAL_BOOLEAN);
JSONObject underTest = msg.serializeJSON();
assertEquals(Test.MATCH, reference.length(), underTest.length());
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ClimateControlDataTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ClimateControlDataTests.java
index 5b0eefa9f..99d5c3285 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ClimateControlDataTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ClimateControlDataTests.java
@@ -18,7 +18,7 @@ import java.util.Hashtable;
import java.util.Iterator;
/**
- * This is a unit test class for the SmartDeviceLink library project class :
+ * This is a unit test class for the SmartDeviceLink library project class :
* {@link com.smartdevicelink.rpc.ClimateControlData}
*/
public class ClimateControlDataTests extends TestCase{
@@ -39,6 +39,10 @@ public class ClimateControlDataTests extends TestCase{
msg.setDualModeEnable(Test.GENERAL_BOOLEAN);
msg.setAcMaxEnable(Test.GENERAL_BOOLEAN);
msg.setVentilationMode(Test.GENERAL_VENTILATIONMODE);
+ msg.setHeatedSteeringWheelEnable(Test.GENERAL_BOOLEAN);
+ msg.setHeatedWindshieldEnable(Test.GENERAL_BOOLEAN);
+ msg.setHeatedRearWindowEnable(Test.GENERAL_BOOLEAN);
+ msg.setHeatedMirrorsEnable(Test.GENERAL_BOOLEAN);
}
/**
@@ -56,6 +60,10 @@ public class ClimateControlDataTests extends TestCase{
boolean dualModeEnable = msg.getDualModeEnable();
boolean acMaxEnable = msg.getAcMaxEnable();
VentilationMode ventilationMode = msg.getVentilationMode();
+ boolean heatedSteeringWheelEnable = msg.getHeatedSteeringWheelEnable();
+ boolean heatedWindshieldEnable = msg.getHeatedWindshieldEnable();
+ boolean heatedRearWindowEnable = msg.getHeatedRearWindowEnable();
+ boolean heatedMirrorsEnable = msg.getHeatedMirrorsEnable();
// Valid Tests
assertEquals(Test.MATCH, Test.GENERAL_INT, fanSpeed);
@@ -68,6 +76,10 @@ public class ClimateControlDataTests extends TestCase{
assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, dualModeEnable);
assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, acMaxEnable);
assertEquals(Test.MATCH, Test.GENERAL_VENTILATIONMODE, ventilationMode);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, heatedSteeringWheelEnable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, heatedWindshieldEnable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, heatedRearWindowEnable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, heatedMirrorsEnable);
// Invalid/Null Tests
ClimateControlData msg = new ClimateControlData();
@@ -83,6 +95,10 @@ public class ClimateControlDataTests extends TestCase{
assertNull(Test.NULL, msg.getDualModeEnable());
assertNull(Test.NULL, msg.getAcMaxEnable());
assertNull(Test.NULL, msg.getVentilationMode());
+ assertNull(Test.NULL, msg.getHeatedSteeringWheelEnable());
+ assertNull(Test.NULL, msg.getHeatedWindshieldEnable());
+ assertNull(Test.NULL, msg.getHeatedRearWindowEnable());
+ assertNull(Test.NULL, msg.getHeatedMirrorsEnable());
}
public void testJson(){
@@ -99,6 +115,10 @@ public class ClimateControlDataTests extends TestCase{
reference.put(ClimateControlData.KEY_AC_MAX_ENABLE, Test.GENERAL_BOOLEAN);
reference.put(ClimateControlData.KEY_DEFROST_ZONE, Test.GENERAL_DEFROSTZONE);
reference.put(ClimateControlData.KEY_VENTILATION_MODE, Test.GENERAL_VENTILATIONMODE);
+ reference.put(ClimateControlData.KEY_HEATED_STEERING_WHEEL_ENABLE, Test.GENERAL_BOOLEAN);
+ reference.put(ClimateControlData.KEY_HEATED_WIND_SHIELD_ENABLE, Test.GENERAL_BOOLEAN);
+ reference.put(ClimateControlData.KEY_HEATED_REAR_WINDOW_ENABLE, Test.GENERAL_BOOLEAN);
+ reference.put(ClimateControlData.KEY_HEATED_MIRRORS_ENABLE, Test.GENERAL_BOOLEAN);
JSONObject underTest = msg.serializeJSON();
assertEquals(Test.MATCH, reference.length(), underTest.length());
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/DisplayCapabilitiesTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/DisplayCapabilitiesTests.java
index 689c3948f..9e627c217 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/DisplayCapabilitiesTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/DisplayCapabilitiesTests.java
@@ -36,6 +36,7 @@ public class DisplayCapabilitiesTests extends TestCase{
msg.setGraphicSupported(Test.GENERAL_BOOLEAN);
msg.setNumCustomPresetsAvailable(Test.GENERAL_INT);
msg.setDisplayType(Test.GENERAL_DISPLAYTYPE);
+ msg.setDisplayName(Test.GENERAL_STRING);
msg.setImageFields(Test.GENERAL_IMAGEFIELD_LIST);
msg.setTextFields(Test.GENERAL_TEXTFIELD_LIST);
msg.setMediaClockFormats(Test.GENERAL_MEDIACLOCKFORMAT_LIST);
@@ -51,6 +52,7 @@ public class DisplayCapabilitiesTests extends TestCase{
boolean graphicSupported = msg.getGraphicSupported();
int numPresets = msg.getNumCustomPresetsAvailable();
DisplayType displayType = msg.getDisplayType();
+ String displayName = msg.getDisplayName();
ScreenParams screenParams = msg.getScreenParams();
List<String> templatesAvailable = msg.getTemplatesAvailable();
List<MediaClockFormat> mediaClock = msg.getMediaClockFormats();
@@ -61,6 +63,7 @@ public class DisplayCapabilitiesTests extends TestCase{
assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, graphicSupported);
assertEquals(Test.MATCH, Test.GENERAL_INT, numPresets);
assertEquals(Test.MATCH, Test.GENERAL_DISPLAYTYPE, displayType);
+ assertEquals(Test.MATCH, Test.GENERAL_STRING, displayName);
assertTrue(Test.TRUE, Validator.validateScreenParams(Test.GENERAL_SCREENPARAMS, screenParams));
assertEquals(Test.MATCH, Test.GENERAL_STRING_LIST.size(), templatesAvailable.size());
assertEquals(Test.MATCH, Test.GENERAL_MEDIACLOCKFORMAT_LIST.size(), mediaClock.size());
@@ -88,6 +91,7 @@ public class DisplayCapabilitiesTests extends TestCase{
assertNotNull(Test.NOT_NULL, msg);
assertNull(Test.NULL, msg.getDisplayType());
+ assertNull(Test.NULL, msg.getDisplayName());
assertNull(Test.NULL, msg.getGraphicSupported());
assertNull(Test.NULL, msg.getImageFields());
assertNull(Test.NULL, msg.getMediaClockFormats());
@@ -104,6 +108,7 @@ public class DisplayCapabilitiesTests extends TestCase{
reference.put(DisplayCapabilities.KEY_NUM_CUSTOM_PRESETS_AVAILABLE, Test.GENERAL_INT);
reference.put(DisplayCapabilities.KEY_GRAPHIC_SUPPORTED, Test.GENERAL_BOOLEAN);
reference.put(DisplayCapabilities.KEY_DISPLAY_TYPE, Test.GENERAL_DISPLAYTYPE);
+ reference.put(DisplayCapabilities.KEY_DISPLAY_NAME, Test.GENERAL_STRING);
reference.put(DisplayCapabilities.KEY_TEMPLATES_AVAILABLE, JsonUtils.createJsonArray(Test.GENERAL_STRING_LIST));
reference.put(DisplayCapabilities.KEY_MEDIA_CLOCK_FORMATS, JsonUtils.createJsonArray(Test.GENERAL_MEDIACLOCKFORMAT_LIST));
reference.put(DisplayCapabilities.KEY_TEXT_FIELDS, Test.JSON_TEXTFIELDS);
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/EqualizerSettingsTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/EqualizerSettingsTests.java
new file mode 100644
index 000000000..a803b1ded
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/EqualizerSettingsTests.java
@@ -0,0 +1,78 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.proxy.rpc.EqualizerSettings;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.EqualizerSettings}
+ */
+public class EqualizerSettingsTests extends TestCase {
+
+ private EqualizerSettings msg;
+
+ @Override
+ public void setUp() {
+ msg = new EqualizerSettings();
+
+ msg.setChannelId(Test.GENERAL_INT);
+ msg.setChannelName(Test.GENERAL_STRING);
+ msg.setChannelSetting(Test.GENERAL_INT);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+
+ int channelId = msg.getChannelId();
+ String channelName = msg.getChannelName();
+ int channelSetting = msg.getChannelSetting();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_INT, channelId);
+ assertEquals(Test.MATCH, Test.GENERAL_STRING, channelName);
+ assertEquals(Test.MATCH, Test.GENERAL_INT, channelSetting);
+
+ // Invalid/Null Tests
+ EqualizerSettings msg = new EqualizerSettings();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getChannelId());
+ assertNull(Test.NULL, msg.getChannelName());
+ assertNull(Test.NULL, msg.getChannelSetting());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+
+ reference.put(EqualizerSettings.KEY_CHANNEL_ID, Test.GENERAL_INT);
+ reference.put(EqualizerSettings.KEY_CHANNEL_NAME, Test.GENERAL_STRING);
+ reference.put(EqualizerSettings.KEY_CHANNEL_SETTING, Test.GENERAL_INT);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/FuelRangeTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/FuelRangeTests.java
new file mode 100644
index 000000000..2dffd2f5b
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/FuelRangeTests.java
@@ -0,0 +1,71 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.proxy.rpc.FuelRange;
+import com.smartdevicelink.proxy.rpc.enums.FuelType;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.FuelRange}
+ */
+public class FuelRangeTests extends TestCase{
+
+ private FuelRange msg;
+
+ @Override
+ public void setUp(){
+ msg = new FuelRange();
+
+ msg.setType(Test.GENERAL_FUELTYPE);
+ msg.setRange(Test.GENERAL_FLOAT);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues () {
+ // Test Values
+ FuelType fuelType = msg.getType();
+ float range = msg.getRange();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_FLOAT, range);
+ assertEquals(Test.MATCH, Test.GENERAL_FUELTYPE, fuelType);
+
+ // Invalid/Null Tests
+ FuelRange msg = new FuelRange();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getType());
+ assertNull(Test.NULL, msg.getRange());
+ }
+
+ public void testJson(){
+ JSONObject reference = new JSONObject();
+
+ try{
+ reference.put(FuelRange.KEY_TYPE, Test.GENERAL_FUELTYPE);
+ reference.put(FuelRange.KEY_RANGE, (Float) Test.GENERAL_FLOAT);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while(iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+ }
+ }catch(JSONException e){
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/HMISettingsControlCapabilitiesTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/HMISettingsControlCapabilitiesTests.java
new file mode 100644
index 000000000..620868b40
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/HMISettingsControlCapabilitiesTests.java
@@ -0,0 +1,80 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.proxy.rpc.HMISettingsControlCapabilities;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.HMISettingsControlCapabilities}
+ */
+public class HMISettingsControlCapabilitiesTests extends TestCase {
+
+ private HMISettingsControlCapabilities msg;
+
+ @Override
+ public void setUp() {
+ msg = new HMISettingsControlCapabilities();
+
+ msg.setModuleName(Test.GENERAL_STRING);
+ msg.setDistanceUnitAvailable(Test.GENERAL_BOOLEAN);
+ msg.setTemperatureUnitAvailable(Test.GENERAL_BOOLEAN);
+ msg.setDisplayModeUnitAvailable(Test.GENERAL_BOOLEAN);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+ String moduleName = msg.getModuleName();
+ Boolean distanceUnitAvailable = msg.getDistanceUnitAvailable();
+ Boolean temperatureUnitAvailable = msg.getTemperatureUnitAvailable();
+ Boolean displayModeUnitAvailable = msg.getDisplayModeUnitAvailable();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_STRING, moduleName);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, (boolean) distanceUnitAvailable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, (boolean) temperatureUnitAvailable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, (boolean) displayModeUnitAvailable);
+
+ // Invalid/Null Tests
+ HMISettingsControlCapabilities msg = new HMISettingsControlCapabilities();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getModuleName());
+ assertNull(Test.NULL, msg.getDistanceUnitAvailable());
+ assertNull(Test.NULL, msg.getTemperatureUnitAvailable());
+ assertNull(Test.NULL, msg.getDisplayModeUnitAvailable());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(HMISettingsControlCapabilities.KEY_MODULE_NAME, Test.GENERAL_STRING);
+ reference.put(HMISettingsControlCapabilities.KEY_DISTANCE_UNIT_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(HMISettingsControlCapabilities.KEY_TEMPERATURE_UNIT_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(HMISettingsControlCapabilities.KEY_DISPLAY_MODE_UNIT_AVAILABLE, Test.GENERAL_BOOLEAN);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/HMISettingsControlDataTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/HMISettingsControlDataTests.java
new file mode 100644
index 000000000..85205f617
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/HMISettingsControlDataTests.java
@@ -0,0 +1,78 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.proxy.rpc.HMISettingsControlData;
+import com.smartdevicelink.proxy.rpc.enums.DisplayMode;
+import com.smartdevicelink.proxy.rpc.enums.DistanceUnit;
+import com.smartdevicelink.proxy.rpc.enums.TemperatureUnit;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.HMISettingsControlData}
+ */
+public class HMISettingsControlDataTests extends TestCase {
+
+ private HMISettingsControlData msg;
+
+ @Override
+ public void setUp() {
+ msg = new HMISettingsControlData();
+
+ msg.setDisplayMode(Test.GENERAL_DISPLAYMODE);
+ msg.setTemperatureUnit(Test.GENERAL_TEMPERATUREUNIT);
+ msg.setDistanceUnit(Test.GENERAL_DISTANCEUNIT);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+ DisplayMode displayMode = msg.getDisplayMode();
+ TemperatureUnit temperatureUnit = msg.getTemperatureUnit();
+ DistanceUnit distanceUnit = msg.getDistanceUnit();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_DISPLAYMODE, displayMode);
+ assertEquals(Test.MATCH, Test.GENERAL_TEMPERATUREUNIT, temperatureUnit);
+ assertEquals(Test.MATCH, Test.GENERAL_DISTANCEUNIT, distanceUnit);
+
+ // Invalid/Null Tests
+ HMISettingsControlData msg = new HMISettingsControlData();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getDisplayMode());
+ assertNull(Test.NULL, msg.getTemperatureUnit());
+ assertNull(Test.NULL, msg.getDistanceUnit());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(HMISettingsControlData.KEY_DISPLAY_MODE, Test.GENERAL_DISPLAYMODE);
+ reference.put(HMISettingsControlData.KEY_TEMPERATURE_UNIT, Test.GENERAL_TEMPERATUREUNIT);
+ reference.put(HMISettingsControlData.KEY_DISTANCE_UNIT, Test.GENERAL_DISTANCEUNIT);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ImageTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ImageTests.java
index fdbcc8590..53f5bf435 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ImageTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ImageTests.java
@@ -26,6 +26,7 @@ public class ImageTests extends TestCase{
msg.setImageType(Test.GENERAL_IMAGETYPE);
msg.setValue(Test.GENERAL_STRING);
+ msg.setIsTemplate(Test.GENERAL_BOOLEAN);
}
/**
@@ -35,10 +36,12 @@ public class ImageTests extends TestCase{
// Test Values
ImageType imageType = msg.getImageType();
String value = msg.getValue();
+ Boolean isTemplate = msg.getIsTemplate();
// Valid Tests
assertEquals(Test.MATCH, Test.GENERAL_IMAGETYPE, imageType);
assertEquals(Test.MATCH, Test.GENERAL_STRING, value);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, isTemplate);
// Invalid/Null Tests
Image msg = new Image();
@@ -47,6 +50,7 @@ public class ImageTests extends TestCase{
assertNull(Test.NULL, msg.getImageType());
assertNull(Test.NULL, msg.getValue());
assertNull(Test.NULL, msg.getBulkData());
+ assertNull(Test.NULL, msg.getIsTemplate());
}
public void testJson(){
@@ -55,6 +59,7 @@ public class ImageTests extends TestCase{
try{
reference.put(Image.KEY_IMAGE_TYPE, Test.GENERAL_IMAGETYPE);
reference.put(Image.KEY_VALUE, Test.GENERAL_STRING);
+ reference.put(Image.KEY_IS_TEMPLATE, Test.GENERAL_BOOLEAN);
JSONObject underTest = msg.serializeJSON();
assertEquals(Test.MATCH, reference.length(), underTest.length());
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightCapabilitiesTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightCapabilitiesTests.java
new file mode 100644
index 000000000..6122f4305
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightCapabilitiesTests.java
@@ -0,0 +1,81 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.proxy.rpc.LightCapabilities;
+import com.smartdevicelink.proxy.rpc.enums.LightName;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.LightCapabilities}
+ */
+public class LightCapabilitiesTests extends TestCase {
+
+ private LightCapabilities msg;
+
+ @Override
+ public void setUp() {
+ msg = new LightCapabilities();
+
+ msg.setName(Test.GENERAL_LIGHTNAME);
+ msg.setDensityAvailable(Test.GENERAL_BOOLEAN);
+ msg.setRGBColorSpaceAvailable(Test.GENERAL_BOOLEAN);
+ msg.setStatusAvailable(Test.GENERAL_BOOLEAN);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+ LightName name = msg.getName();
+ Boolean densityAvailable = msg.getDensityAvailable();
+ Boolean rgbColorSpaceAvailable = msg.getRGBColorSpaceAvailable();
+ Boolean statusAvailable = msg.getStatusAvailable();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_LIGHTNAME, name);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, (boolean) densityAvailable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, (boolean) rgbColorSpaceAvailable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, (boolean) statusAvailable);
+
+ // Invalid/Null Tests
+ LightCapabilities msg = new LightCapabilities();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getName());
+ assertNull(Test.NULL, msg.getDensityAvailable());
+ assertNull(Test.NULL, msg.getRGBColorSpaceAvailable());
+ assertNull(Test.NULL, msg.getStatusAvailable());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(LightCapabilities.KEY_NAME, Test.GENERAL_LIGHTNAME);
+ reference.put(LightCapabilities.KEY_DENSITY_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(LightCapabilities.KEY_RGB_COLOR_SPACE_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(LightCapabilities.KEY_STATUS_AVAILABLE, Test.GENERAL_BOOLEAN);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightControlCapabilitiesTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightControlCapabilitiesTests.java
new file mode 100644
index 000000000..4ebd7f467
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightControlCapabilitiesTests.java
@@ -0,0 +1,86 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.proxy.rpc.LightCapabilities;
+import com.smartdevicelink.proxy.rpc.LightControlCapabilities;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+import com.smartdevicelink.test.Validator;
+
+import junit.framework.TestCase;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.LightControlCapabilities}
+ */
+public class LightControlCapabilitiesTests extends TestCase {
+
+ private LightControlCapabilities msg;
+
+ @Override
+ public void setUp() {
+ msg = new LightControlCapabilities();
+
+ msg.setModuleName(Test.GENERAL_STRING);
+ msg.setSupportedLights(Test.GENERAL_LIGHTCAPABILITIES_LIST);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+ String moduleName = msg.getModuleName();
+ List<LightCapabilities> supportedLights = msg.getSupportedLights();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_STRING, moduleName);
+ assertEquals(Test.MATCH, Test.GENERAL_LIGHTCAPABILITIES_LIST.size(), supportedLights.size());
+
+ assertTrue(Test.TRUE, Validator.validateLightCapabilitiesList(Test.GENERAL_LIGHTCAPABILITIES_LIST, supportedLights));
+
+ // Invalid/Null Tests
+ LightControlCapabilities msg = new LightControlCapabilities();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getModuleName());
+ assertNull(Test.NULL, msg.getSupportedLights());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(LightControlCapabilities.KEY_MODULE_NAME, Test.GENERAL_STRING);
+ reference.put(LightControlCapabilities.KEY_SUPPORTED_LIGHTS, Test.GENERAL_LIGHTCAPABILITIES_LIST);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ if (key.equals(LightControlCapabilities.KEY_SUPPORTED_LIGHTS)) {
+ List<LightCapabilities> lcReference = (List<LightCapabilities>) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONArray lsArray = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
+ int i = 0;
+ for (LightCapabilities lc : lcReference) {
+ assertTrue(Validator.validateLightCapabilities(lc, new LightCapabilities(JsonRPCMarshaller.deserializeJSONObject(lsArray.getJSONObject(i++)))));
+ }
+ } else {
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+ }
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightControlDataTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightControlDataTests.java
new file mode 100644
index 000000000..c891e0769
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightControlDataTests.java
@@ -0,0 +1,79 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.proxy.rpc.LightControlData;
+import com.smartdevicelink.proxy.rpc.LightState;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+import com.smartdevicelink.test.Validator;
+
+import junit.framework.TestCase;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.LightControlData}
+ */
+public class LightControlDataTests extends TestCase {
+
+ private LightControlData msg;
+
+ @Override
+ public void setUp() {
+ msg = new LightControlData();
+
+ msg.setLightState(Test.GENERAL_LIGHTSTATE_LIST);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+ List<LightState> lightState = msg.getLightState();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_LIGHTSTATE_LIST.size(), lightState.size());
+
+ assertTrue(Test.TRUE, Validator.validateLightStateList(Test.GENERAL_LIGHTSTATE_LIST, lightState));
+
+ // Invalid/Null Tests
+ LightControlData msg = new LightControlData();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getLightState());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(LightControlData.KEY_LIGHT_STATE, Test.GENERAL_LIGHTSTATE_LIST);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ if (key.equals(LightControlData.KEY_LIGHT_STATE)) {
+ List<LightState> lsReference = (List<LightState>) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONArray lsArray = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
+ int i = 0;
+ for (LightState ls : lsReference) {
+ assertTrue(Validator.validateLightState(ls, new LightState(JsonRPCMarshaller.deserializeJSONObject(lsArray.getJSONObject(i++)))));
+ }
+ }
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightStateTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightStateTests.java
new file mode 100644
index 000000000..196769e00
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/LightStateTests.java
@@ -0,0 +1,94 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.proxy.rpc.LightState;
+import com.smartdevicelink.proxy.rpc.RGBColor;
+import com.smartdevicelink.proxy.rpc.enums.LightName;
+import com.smartdevicelink.proxy.rpc.enums.LightStatus;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+import com.smartdevicelink.test.Validator;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.LightState}
+ */
+public class LightStateTests extends TestCase {
+
+ private LightState msg;
+
+ @Override
+ public void setUp() {
+ msg = new LightState();
+
+ msg.setId(Test.GENERAL_LIGHTNAME);
+ msg.setStatus(Test.GENERAL_LIGHTSTATUS);
+ msg.setDensity(Test.GENERAL_FLOAT);
+ msg.setColor(Test.GENERAL_RGBCOLOR);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+ LightName id = msg.getId();
+ LightStatus status = msg.getStatus();
+ Float density = msg.getDensity();
+ RGBColor color = msg.getColor();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_LIGHTNAME, id);
+ assertEquals(Test.MATCH, Test.GENERAL_LIGHTSTATUS, status);
+ assertEquals(Test.MATCH, Test.GENERAL_FLOAT, (float) density);
+ assertEquals(Test.MATCH, Test.GENERAL_RGBCOLOR, color);
+
+ // Invalid/Null Tests
+ LightState msg = new LightState();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getId());
+ assertNull(Test.NULL, msg.getStatus());
+ assertNull(Test.NULL, msg.getDensity());
+ assertNull(Test.NULL, msg.getColor());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(LightState.KEY_ID, Test.GENERAL_LIGHTNAME);
+ reference.put(LightState.KEY_STATUS, Test.GENERAL_LIGHTSTATUS);
+ reference.put(LightState.KEY_DENSITY, Test.GENERAL_FLOAT);
+ reference.put(LightState.KEY_COLOR, JsonRPCMarshaller.serializeHashtable(Test.GENERAL_RGBCOLOR.getStore()));
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ if (key.equals(LightState.KEY_COLOR)) {
+ JSONObject objectEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
+ assertTrue(Test.TRUE, Validator.validateRGBColor(new RGBColor(hashReference), new RGBColor(hashTest)));
+ } else {
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+ }
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/MassageCushionFirmnessTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/MassageCushionFirmnessTest.java
new file mode 100644
index 000000000..da8a7cbfe
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/MassageCushionFirmnessTest.java
@@ -0,0 +1,71 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.proxy.rpc.MassageCushionFirmness;
+import com.smartdevicelink.proxy.rpc.enums.MassageCushion;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.MassageCushionFirmness}
+ */
+public class MassageCushionFirmnessTest extends TestCase {
+
+ private MassageCushionFirmness msg;
+
+ @Override
+ public void setUp() {
+ msg = new MassageCushionFirmness();
+
+ msg.setCushion(Test.GENERAL_MASSAGECUSHION);
+ msg.setFirmness(Test.GENERAL_INT);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+ MassageCushion cushion = msg.getCushion();
+ Integer firmness = msg.getFirmness();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_MASSAGECUSHION, cushion);
+ assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, firmness);
+
+ // Invalid/Null Tests
+ MassageCushionFirmness msg = new MassageCushionFirmness();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getCushion());
+ assertNull(Test.NULL, msg.getFirmness());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(MassageCushionFirmness.KEY_CUSHION, Test.GENERAL_MASSAGECUSHION);
+ reference.put(MassageCushionFirmness.KEY_FIRMNESS, Test.GENERAL_INT);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/MassageModeDataTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/MassageModeDataTest.java
new file mode 100644
index 000000000..958de9fa2
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/MassageModeDataTest.java
@@ -0,0 +1,74 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.proxy.rpc.MassageModeData;
+import com.smartdevicelink.proxy.rpc.enums.MassageMode;
+import com.smartdevicelink.proxy.rpc.enums.MassageZone;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.MassageModeData}
+ */
+public class MassageModeDataTest extends TestCase {
+
+ private MassageModeData msg;
+
+ @Override
+ public void setUp() {
+ msg = new MassageModeData();
+
+ msg.setMassageZone(Test.GENERAL_MASSAGEZONE);
+ msg.setMassageMode(Test.GENERAL_MASSAGEMODE);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+ MassageZone massageZone = msg.getMassageZone();
+ MassageMode massageMode = msg.getMassageMode();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_MASSAGEZONE, massageZone);
+ assertEquals(Test.MATCH, Test.GENERAL_MASSAGEMODE, massageMode);
+
+
+ // Invalid/Null Tests
+ MassageModeData msg = new MassageModeData();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getMassageMode());
+ assertNull(Test.NULL, msg.getMassageZone());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(MassageModeData.KEY_MASSAGE_MODE, Test.GENERAL_MASSAGEMODE);
+ reference.put(MassageModeData.KEY_MASSAGE_ZONE, Test.GENERAL_MASSAGEZONE);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ModuleDataTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ModuleDataTests.java
index ea71dfc8a..b553587ad 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ModuleDataTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/ModuleDataTests.java
@@ -1,9 +1,13 @@
package com.smartdevicelink.test.rpc.datatypes;
import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.proxy.rpc.AudioControlData;
import com.smartdevicelink.proxy.rpc.ClimateControlData;
+import com.smartdevicelink.proxy.rpc.HMISettingsControlData;
+import com.smartdevicelink.proxy.rpc.LightControlData;
import com.smartdevicelink.proxy.rpc.ModuleData;
import com.smartdevicelink.proxy.rpc.RadioControlData;
+import com.smartdevicelink.proxy.rpc.SeatControlData;
import com.smartdevicelink.proxy.rpc.enums.ModuleType;
import com.smartdevicelink.test.JsonUtils;
import com.smartdevicelink.test.Test;
@@ -18,78 +22,121 @@ import java.util.Hashtable;
import java.util.Iterator;
/**
- * This is a unit test class for the SmartDeviceLink library project class :
+ * This is a unit test class for the SmartDeviceLink library project class :
* {@link com.smartdevicelink.rpc.ModuleData}
*/
-public class ModuleDataTests extends TestCase{
-
- private ModuleData msg;
-
- @Override
- public void setUp(){
- msg = new ModuleData();
-
- msg.setModuleType(Test.GENERAL_MODULETYPE);
- msg.setRadioControlData(Test.GENERAL_RADIOCONTROLDATA);
- msg.setClimateControlData(Test.GENERAL_CLIMATECONTROLDATA);
- }
-
- /**
+public class ModuleDataTests extends TestCase {
+
+ private ModuleData msg;
+
+ @Override
+ public void setUp() {
+ msg = new ModuleData();
+ msg.setModuleType(Test.GENERAL_MODULETYPE);
+ msg.setRadioControlData(Test.GENERAL_RADIOCONTROLDATA);
+ msg.setClimateControlData(Test.GENERAL_CLIMATECONTROLDATA);
+ msg.setSeatControlData(Test.GENERAL_SEATCONTROLDATA);
+ msg.setAudioControlData(Test.GENERAL_AUDIOCONTROLDATA);
+ msg.setHmiSettingsControlData(Test.GENERAL_HMISETTINGSCONTROLDATA);
+ msg.setLightControlData(Test.GENERAL_LIGHTCONTROLDATA);
+ }
+
+ /**
* Tests the expected values of the RPC message.
*/
- public void testRpcValues () {
- // Test Values
- ModuleType moduleType = msg.getModuleType();
- RadioControlData radioControlData = msg.getRadioControlData();
- ClimateControlData climateControlData = msg.getClimateControlData();
-
- // Valid Tests
- assertEquals(Test.MATCH, Test.GENERAL_MODULETYPE, moduleType);
- assertTrue(Test.TRUE, Validator.validateRadioControlData(Test.GENERAL_RADIOCONTROLDATA, radioControlData));
- assertTrue(Test.TRUE, Validator.validateClimateControlData(Test.GENERAL_CLIMATECONTROLDATA, climateControlData));
-
- // Invalid/Null Tests
- ModuleData msg = new ModuleData();
- assertNotNull(Test.NOT_NULL, msg);
-
- assertNull(Test.NULL, msg.getModuleType());
- assertNull(Test.NULL, msg.getRadioControlData());
- assertNull(Test.NULL, msg.getClimateControlData());
- }
-
- public void testJson(){
- JSONObject reference = new JSONObject();
-
- try{
- reference.put(ModuleData.KEY_MODULE_TYPE, Test.GENERAL_MODULETYPE);
- reference.put(ModuleData.KEY_RADIO_CONTROL_DATA, JsonRPCMarshaller.serializeHashtable(Test.GENERAL_RADIOCONTROLDATA.getStore()));
- reference.put(ModuleData.KEY_CLIMATE_CONTROL_DATA, JsonRPCMarshaller.serializeHashtable(Test.GENERAL_CLIMATECONTROLDATA.getStore()));
-
- JSONObject underTest = msg.serializeJSON();
- assertEquals(Test.MATCH, reference.length(), underTest.length());
-
- Iterator<?> iterator = reference.keys();
- while(iterator.hasNext()){
- String key = (String) iterator.next();
-
- if(key.equals(ModuleData.KEY_RADIO_CONTROL_DATA)){
- JSONObject objectEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(reference, key);
- JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
- Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
- Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
- assertTrue(Test.TRUE, Validator.validateRadioControlData( new RadioControlData(hashReference), new RadioControlData(hashTest)));
- } else if(key.equals(ModuleData.KEY_CLIMATE_CONTROL_DATA)){
- JSONObject objectEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(reference, key);
- JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
- Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
- Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
- assertTrue(Test.TRUE, Validator.validateClimateControlData( new ClimateControlData(hashReference), new ClimateControlData(hashTest)));
- } else{
- assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
- }
- }
- } catch(JSONException e){
- fail(Test.JSON_FAIL);
- }
- }
+ public void testRpcValues() {
+ // Test Values
+ ModuleType moduleType = msg.getModuleType();
+ RadioControlData radioControlData = msg.getRadioControlData();
+ ClimateControlData climateControlData = msg.getClimateControlData();
+ SeatControlData seatControlData = msg.getSeatControlData();
+ AudioControlData audioControlData = msg.getAudioControlData();
+ HMISettingsControlData hmiSettingsControlData = msg.getHmiSettingsControlData();
+ LightControlData lightControlData = msg.getLightControlData();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_MODULETYPE, moduleType);
+ assertTrue(Test.TRUE, Validator.validateRadioControlData(Test.GENERAL_RADIOCONTROLDATA, radioControlData));
+ assertTrue(Test.TRUE, Validator.validateClimateControlData(Test.GENERAL_CLIMATECONTROLDATA, climateControlData));
+ assertTrue(Test.TRUE, Validator.validateSeatControlData(Test.GENERAL_SEATCONTROLDATA, seatControlData));
+ assertTrue(Test.TRUE, Validator.validateAudioControlData(Test.GENERAL_AUDIOCONTROLDATA, audioControlData));
+ assertTrue(Test.TRUE, Validator.validateHMISettingsControlData(Test.GENERAL_HMISETTINGSCONTROLDATA, hmiSettingsControlData));
+ assertTrue(Test.TRUE, Validator.validateLightControlData(Test.GENERAL_LIGHTCONTROLDATA, lightControlData));
+
+ // Invalid/Null Tests
+ ModuleData msg = new ModuleData();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getModuleType());
+ assertNull(Test.NULL, msg.getRadioControlData());
+ assertNull(Test.NULL, msg.getClimateControlData());
+ assertNull(Test.NULL, msg.getSeatControlData());
+ assertNull(Test.NULL, msg.getAudioControlData());
+ assertNull(Test.NULL, msg.getHmiSettingsControlData());
+ assertNull(Test.NULL, msg.getLightControlData());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(ModuleData.KEY_MODULE_TYPE, Test.GENERAL_MODULETYPE);
+ reference.put(ModuleData.KEY_RADIO_CONTROL_DATA, JsonRPCMarshaller.serializeHashtable(Test.GENERAL_RADIOCONTROLDATA.getStore()));
+ reference.put(ModuleData.KEY_CLIMATE_CONTROL_DATA, JsonRPCMarshaller.serializeHashtable(Test.GENERAL_CLIMATECONTROLDATA.getStore()));
+ reference.put(ModuleData.KEY_SEAT_CONTROL_DATA, JsonRPCMarshaller.serializeHashtable(Test.GENERAL_SEATCONTROLDATA.getStore()));
+ reference.put(ModuleData.KEY_AUDIO_CONTROL_DATA, JsonRPCMarshaller.serializeHashtable(Test.GENERAL_AUDIOCONTROLDATA.getStore()));
+ reference.put(ModuleData.KEY_HMI_SETTINGS_CONTROL_DATA, JsonRPCMarshaller.serializeHashtable(Test.GENERAL_HMISETTINGSCONTROLDATA.getStore()));
+ reference.put(ModuleData.KEY_LIGHT_CONTROL_DATA, JsonRPCMarshaller.serializeHashtable(Test.GENERAL_LIGHTCONTROLDATA.getStore()));
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ if (key.equals(ModuleData.KEY_RADIO_CONTROL_DATA)) {
+ JSONObject objectEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
+ assertTrue(Test.TRUE, Validator.validateRadioControlData(new RadioControlData(hashReference), new RadioControlData(hashTest)));
+ } else if (key.equals(ModuleData.KEY_CLIMATE_CONTROL_DATA)) {
+ JSONObject objectEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
+ assertTrue(Test.TRUE, Validator.validateClimateControlData(new ClimateControlData(hashReference), new ClimateControlData(hashTest)));
+ } else if (key.equals(ModuleData.KEY_SEAT_CONTROL_DATA)) {
+ JSONObject objectEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
+ assertTrue(Test.TRUE, Validator.validateSeatControlData(new SeatControlData(hashReference), new SeatControlData(hashTest)));
+ } else if (key.equals(ModuleData.KEY_AUDIO_CONTROL_DATA)) {
+ JSONObject objectEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
+ assertTrue(Test.TRUE, Validator.validateAudioControlData(new AudioControlData(hashReference), new AudioControlData(hashTest)));
+ } else if (key.equals(ModuleData.KEY_HMI_SETTINGS_CONTROL_DATA)) {
+ JSONObject objectEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
+ assertTrue(Test.TRUE, Validator.validateHMISettingsControlData(new HMISettingsControlData(hashReference), new HMISettingsControlData(hashTest)));
+ } else if (key.equals(ModuleData.KEY_LIGHT_CONTROL_DATA)) {
+ JSONObject objectEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
+ assertTrue(Test.TRUE, Validator.validateLightControlData(new LightControlData(hashReference), new LightControlData(hashTest)));
+ } else {
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+ }
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RGBColorTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RGBColorTest.java
new file mode 100644
index 000000000..a9c0033a0
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RGBColorTest.java
@@ -0,0 +1,70 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.proxy.rpc.RGBColor;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.proxy.rpc.RGBColor}
+ */
+public class RGBColorTest extends TestCase {
+
+ private RGBColor msg;
+
+ @Override
+ public void setUp() {
+ msg = new RGBColor(Test.GENERAL_INT, Test.GENERAL_INT, Test.GENERAL_INT);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues () {
+ // Test Values
+ Integer red = msg.getRed();
+ Integer green = msg.getGreen();
+ Integer blue = msg.getBlue();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, red);
+ assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, green);
+ assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, blue);
+
+ // Invalid/Null Tests
+ RGBColor msg = new RGBColor();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertEquals(Test.MATCH, msg.getRed(), (Integer) 0);
+ assertEquals(Test.MATCH, msg.getGreen(), (Integer) 0);
+ assertEquals(Test.MATCH, msg.getBlue(), (Integer) 0);
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(RGBColor.KEY_RED, Test.GENERAL_INT);
+ reference.put(RGBColor.KEY_GREEN, Test.GENERAL_INT);
+ reference.put(RGBColor.KEY_BLUE, Test.GENERAL_INT);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RadioControlCapabilitiesTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RadioControlCapabilitiesTests.java
index 28c1d2c5b..915e779a7 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RadioControlCapabilitiesTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RadioControlCapabilitiesTests.java
@@ -12,7 +12,7 @@ import org.json.JSONObject;
import java.util.Iterator;
/**
- * This is a unit test class for the SmartDeviceLink library project class :
+ * This is a unit test class for the SmartDeviceLink library project class :
* {@link com.smartdevicelink.rpc.RadioControlCapabilities}
*/
public class RadioControlCapabilitiesTests extends TestCase{
@@ -33,6 +33,9 @@ public class RadioControlCapabilitiesTests extends TestCase{
msg.setStateAvailable(Test.GENERAL_BOOLEAN);
msg.setSignalStrengthAvailable(Test.GENERAL_BOOLEAN);
msg.setSignalChangeThresholdAvailable(Test.GENERAL_BOOLEAN);
+ msg.setHdRadioEnableAvailable(Test.GENERAL_BOOLEAN);
+ msg.setSiriusXMRadioAvailable(Test.GENERAL_BOOLEAN);
+ msg.setSisDataAvailable(Test.GENERAL_BOOLEAN);
}
/**
@@ -50,6 +53,9 @@ public class RadioControlCapabilitiesTests extends TestCase{
boolean stateAvailable = msg.getStateAvailable();
boolean signalStrengthAvailable = msg.getSignalStrengthAvailable();
boolean signalChangeThresholdAvailable = msg.getSignalChangeThresholdAvailable();
+ boolean hdRadioEnableAvailable = msg.getHdRadioEnableAvailable();
+ boolean siriusXMRadioAvailable = msg.getSiriusXMRadioAvailable();
+ boolean sisDataAvailable = msg.getSisDataAvailable();
// Valid Tests
@@ -63,6 +69,9 @@ public class RadioControlCapabilitiesTests extends TestCase{
assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, stateAvailable);
assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, signalStrengthAvailable);
assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, signalChangeThresholdAvailable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, hdRadioEnableAvailable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, siriusXMRadioAvailable);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, sisDataAvailable);
// Invalid/Null Tests
RadioControlCapabilities msg = new RadioControlCapabilities();
@@ -78,6 +87,9 @@ public class RadioControlCapabilitiesTests extends TestCase{
assertNull(Test.NULL, msg.getStateAvailable());
assertNull(Test.NULL, msg.getSignalStrengthAvailable());
assertNull(Test.NULL, msg.getSignalChangeThresholdAvailable());
+ assertNull(Test.NULL, msg.getHdRadioEnableAvailable());
+ assertNull(Test.NULL, msg.getSiriusXMRadioAvailable());
+ assertNull(Test.NULL, msg.getSisDataAvailable());
}
public void testJson(){
@@ -94,6 +106,9 @@ public class RadioControlCapabilitiesTests extends TestCase{
reference.put(RadioControlCapabilities.KEY_STATE_AVAILABLE, Test.GENERAL_BOOLEAN);
reference.put(RadioControlCapabilities.KEY_SIGNAL_STRENGTH_AVAILABLE, Test.GENERAL_BOOLEAN);
reference.put(RadioControlCapabilities.KEY_SIGNAL_CHANGE_THRESHOLD_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(RadioControlCapabilities.KEY_HD_RADIO_ENABLE_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(RadioControlCapabilities.KEY_SIRIUS_XM_RADIO_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(RadioControlCapabilities.KEY_SIS_DATA_AVAILABLE, Test.GENERAL_BOOLEAN);
JSONObject underTest = msg.serializeJSON();
assertEquals(Test.MATCH, reference.length(), underTest.length());
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RadioControlDataTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RadioControlDataTests.java
index b42145e8f..a560827c4 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RadioControlDataTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RadioControlDataTests.java
@@ -3,6 +3,7 @@ package com.smartdevicelink.test.rpc.datatypes;
import com.smartdevicelink.marshal.JsonRPCMarshaller;
import com.smartdevicelink.proxy.rpc.RadioControlData;
import com.smartdevicelink.proxy.rpc.RdsData;
+import com.smartdevicelink.proxy.rpc.SisData;
import com.smartdevicelink.proxy.rpc.enums.RadioBand;
import com.smartdevicelink.proxy.rpc.enums.RadioState;
import com.smartdevicelink.test.JsonUtils;
@@ -18,7 +19,7 @@ import java.util.Hashtable;
import java.util.Iterator;
/**
- * This is a unit test class for the SmartDeviceLink library project class :
+ * This is a unit test class for the SmartDeviceLink library project class :
* {@link com.smartdevicelink.rpc.RadioControlData}
*/
public class RadioControlDataTests extends TestCase{
@@ -39,6 +40,8 @@ public class RadioControlDataTests extends TestCase{
msg.setSignalChangeThreshold(Test.GENERAL_INT);
msg.setRadioEnable(Test.GENERAL_BOOLEAN);
msg.setState(Test.GENERAL_RADIOSTATE);
+ msg.setHdRadioEnable(Test.GENERAL_BOOLEAN);
+ msg.setSisData(Test.GENERAL_SISDATA);
}
/**
@@ -56,6 +59,8 @@ public class RadioControlDataTests extends TestCase{
int signalChangeThreshold = msg.getSignalChangeThreshold();
boolean radioEnable = msg.getRadioEnable();
RadioState state = msg.getState();
+ boolean hdRadioEnable = msg.getHdRadioEnable();
+ SisData sisData = msg.getSisData();
// Valid Tests
assertEquals(Test.MATCH, Test.GENERAL_INT, frequencyInteger);
@@ -68,6 +73,8 @@ public class RadioControlDataTests extends TestCase{
assertEquals(Test.MATCH, Test.GENERAL_INT, signalChangeThreshold);
assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, radioEnable);
assertEquals(Test.MATCH, Test.GENERAL_RADIOSTATE, state);
+ assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, hdRadioEnable);
+ assertTrue(Test.TRUE, Validator.validateSisData(Test.GENERAL_SISDATA, sisData));
// Invalid/Null Tests
RadioControlData msg = new RadioControlData();
@@ -83,6 +90,8 @@ public class RadioControlDataTests extends TestCase{
assertNull(Test.NULL, msg.getSignalChangeThreshold());
assertNull(Test.NULL, msg.getRadioEnable());
assertNull(Test.NULL, msg.getState());
+ assertNull(Test.NULL, msg.getHdRadioEnable());
+ assertNull(Test.NULL, msg.getSisData());
}
public void testJson(){
@@ -99,6 +108,8 @@ public class RadioControlDataTests extends TestCase{
reference.put(RadioControlData.KEY_SIGNAL_CHANGE_THRESHOLD, Test.GENERAL_INT);
reference.put(RadioControlData.KEY_RADIO_ENABLE, Test.GENERAL_BOOLEAN);
reference.put(RadioControlData.KEY_STATE, Test.GENERAL_RADIOSTATE);
+ reference.put(RadioControlData.KEY_HD_RADIO_ENABLE, Test.GENERAL_BOOLEAN);
+ reference.put(RadioControlData.KEY_SIS_DATA, JsonRPCMarshaller.serializeHashtable(Test.GENERAL_SISDATA.getStore()));
JSONObject underTest = msg.serializeJSON();
assertEquals(Test.MATCH, reference.length(), underTest.length());
@@ -112,7 +123,13 @@ public class RadioControlDataTests extends TestCase{
JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
- assertTrue(Test.TRUE, Validator.validateRadioControlData( new RadioControlData(hashReference), new RadioControlData(hashTest)));
+ assertTrue(Test.TRUE, Validator.validateRdsData(new RdsData(hashReference), new RdsData(hashTest)));
+ } else if (key.equals(RadioControlData.KEY_SIS_DATA)) {
+ JSONObject objectEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
+ assertTrue(Test.TRUE, Validator.validateSisData(new SisData(hashReference), new SisData(hashTest)));
} else{
assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RemoteControlCapabilitiesTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RemoteControlCapabilitiesTests.java
index a15179b8f..e6a2d2b9a 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RemoteControlCapabilitiesTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/RemoteControlCapabilitiesTests.java
@@ -1,10 +1,14 @@
package com.smartdevicelink.test.rpc.datatypes;
import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.proxy.rpc.AudioControlCapabilities;
import com.smartdevicelink.proxy.rpc.ButtonCapabilities;
import com.smartdevicelink.proxy.rpc.ClimateControlCapabilities;
+import com.smartdevicelink.proxy.rpc.HMISettingsControlCapabilities;
+import com.smartdevicelink.proxy.rpc.LightControlCapabilities;
import com.smartdevicelink.proxy.rpc.RadioControlCapabilities;
import com.smartdevicelink.proxy.rpc.RemoteControlCapabilities;
+import com.smartdevicelink.proxy.rpc.SeatControlCapabilities;
import com.smartdevicelink.test.JsonUtils;
import com.smartdevicelink.test.Test;
import com.smartdevicelink.test.Validator;
@@ -21,111 +25,156 @@ import java.util.Iterator;
import java.util.List;
/**
- * This is a unit test class for the SmartDeviceLink library project class :
+ * This is a unit test class for the SmartDeviceLink library project class :
* {@link com.smartdevicelink.rpc.RemoteControlCapabilities}
*/
-public class RemoteControlCapabilitiesTests extends TestCase{
-
- private RemoteControlCapabilities msg;
-
- @Override
- public void setUp(){
- msg = new RemoteControlCapabilities();
-
- msg.setButtonCapabilities(Test.GENERAL_BUTTONCAPABILITIES_LIST);
- msg.setRadioControlCapabilities(Test.GENERAL_RADIOCONTROLCAPABILITIES_LIST);
- msg.setClimateControlCapabilities(Test.GENERAL_CLIMATECONTROLCAPABILITIES_LIST);
- }
-
- /**
+public class RemoteControlCapabilitiesTests extends TestCase {
+
+ private RemoteControlCapabilities msg;
+
+ @Override
+ public void setUp() {
+ msg = new RemoteControlCapabilities();
+ msg.setButtonCapabilities(Test.GENERAL_BUTTONCAPABILITIES_LIST);
+ msg.setRadioControlCapabilities(Test.GENERAL_RADIOCONTROLCAPABILITIES_LIST);
+ msg.setClimateControlCapabilities(Test.GENERAL_CLIMATECONTROLCAPABILITIES_LIST);
+ msg.setSeatControlCapabilities(Test.GENERAL_SEATCONTROLCAPABILITIES_LIST);
+ msg.setAudioControlCapabilities(Test.GENERAL_AUDIOCONTROLCAPABILITIES_LIST);
+ msg.setHmiSettingsControlCapabilities(Test.GENERAL_HMISETTINGSCONTROLCAPABILITIES);
+ msg.setLightControlCapabilities(Test.GENERAL_LIGHTCONTROLCAPABILITIES);
+ }
+
+ /**
* Tests the expected values of the RPC message.
*/
- public void testRpcValues () {
- // Test Values
- List<ButtonCapabilities> buttonCapabilities = msg.getButtonCapabilities();
- List<RadioControlCapabilities> radioControlCapabilities = msg.getRadioControlCapabilities();
- List<ClimateControlCapabilities> climateControlCapabilities = msg.getClimateControlCapabilities();
-
- // Valid Tests
- assertEquals(Test.MATCH, Test.GENERAL_BUTTONCAPABILITIES_LIST.size(), buttonCapabilities.size());
- assertEquals(Test.MATCH, Test.GENERAL_RADIOCONTROLCAPABILITIES_LIST.size(), radioControlCapabilities.size());
- assertEquals(Test.MATCH, Test.GENERAL_CLIMATECONTROLCAPABILITIES_LIST.size(), climateControlCapabilities.size());
-
- assertTrue(Test.TRUE, Validator.validateButtonCapabilities(Test.GENERAL_BUTTONCAPABILITIES_LIST, buttonCapabilities));
- assertTrue(Test.TRUE, Validator.validateRadioControlCapabilities(Test.GENERAL_RADIOCONTROLCAPABILITIES_LIST, radioControlCapabilities));
- assertTrue(Test.TRUE, Validator.validateClimateControlCapabilities(Test.GENERAL_CLIMATECONTROLCAPABILITIES_LIST, climateControlCapabilities));
-
- // Invalid/Null Tests
- RemoteControlCapabilities msg = new RemoteControlCapabilities();
- assertNotNull(Test.NOT_NULL, msg);
-
- assertNull(Test.NULL, msg.getButtonCapabilities());
- assertNull(Test.NULL, msg.getRadioControlCapabilities());
- assertNull(Test.NULL, msg.getClimateControlCapabilities());
-
- }
-
- public void testJson(){
- JSONObject reference = new JSONObject();
-
- try{
- reference.put(RemoteControlCapabilities.KEY_BUTTON_CAPABILITIES, Test.JSON_BUTTONCAPABILITIES);
- reference.put(RemoteControlCapabilities.KEY_RADIO_CONTROL_CAPABILITIES, Test.JSON_RADIOCONTROLCAPABILITIES);
- reference.put(RemoteControlCapabilities.KEY_CLIMATE_CONTROL_CAPABILITIES, Test.JSON_CLIMATECONTROLCAPABILITIES);
-
- JSONObject underTest = msg.serializeJSON();
- assertEquals(Test.MATCH, reference.length(), underTest.length());
-
- Iterator<?> iterator = reference.keys();
- while(iterator.hasNext()){
- String key = (String) iterator.next();
-
- if(key.equals(RemoteControlCapabilities.KEY_BUTTON_CAPABILITIES)){
- JSONArray referenceArray = JsonUtils.readJsonArrayFromJsonObject(reference, key);
- JSONArray underTestArray = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
- assertEquals(Test.MATCH, referenceArray.length(), underTestArray.length());
-
- List<ButtonCapabilities> referenceList = new ArrayList<ButtonCapabilities>();
- List<ButtonCapabilities> testList = new ArrayList<ButtonCapabilities>();
- for(int i = 0; i < referenceArray.length(); i++){
- Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(referenceArray.getJSONObject(i));
- referenceList.add(new ButtonCapabilities(hashReference));
- Hashtable<String, Object> hashTest= JsonRPCMarshaller.deserializeJSONObject(underTestArray.getJSONObject(i));
- testList.add(new ButtonCapabilities(hashTest));
- }
- assertTrue(Test.TRUE, Validator.validateButtonCapabilities(referenceList, testList));
- } else if(key.equals(RemoteControlCapabilities.KEY_RADIO_CONTROL_CAPABILITIES)){
- JSONArray referenceArray = JsonUtils.readJsonArrayFromJsonObject(reference, key);
- JSONArray underTestArray = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
- assertEquals(Test.MATCH, referenceArray.length(), underTestArray.length());
-
- List<RadioControlCapabilities> referenceList = new ArrayList<RadioControlCapabilities>();
- List<RadioControlCapabilities> testList = new ArrayList<RadioControlCapabilities>();
- for(int i = 0; i < referenceArray.length(); i++){
- Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(referenceArray.getJSONObject(i));
- referenceList.add(new RadioControlCapabilities(hashReference));
- Hashtable<String, Object> hashTest= JsonRPCMarshaller.deserializeJSONObject(underTestArray.getJSONObject(i));
- testList.add(new RadioControlCapabilities(hashTest));
- }
- assertTrue(Test.TRUE, Validator.validateRadioControlCapabilities(referenceList, testList));
- } else if(key.equals(RemoteControlCapabilities.KEY_CLIMATE_CONTROL_CAPABILITIES)){
- JSONArray referenceArray = JsonUtils.readJsonArrayFromJsonObject(reference, key);
- JSONArray underTestArray = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
- assertEquals(Test.MATCH, referenceArray.length(), underTestArray.length());
-
- List<ClimateControlCapabilities> referenceList = new ArrayList<ClimateControlCapabilities>();
- List<ClimateControlCapabilities> testList = new ArrayList<ClimateControlCapabilities>();
- for(int i = 0; i < referenceArray.length(); i++){
- Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(referenceArray.getJSONObject(i));
- referenceList.add(new ClimateControlCapabilities(hashReference));
- Hashtable<String, Object> hashTest= JsonRPCMarshaller.deserializeJSONObject(underTestArray.getJSONObject(i));
- testList.add(new ClimateControlCapabilities(hashTest));
- }
- assertTrue(Test.TRUE, Validator.validateClimateControlCapabilities(referenceList, testList));
- }
- }
- } catch(JSONException e){
- fail(Test.JSON_FAIL);
- }
- }
+ public void testRpcValues() {
+ // Test Values
+ List<ButtonCapabilities> buttonCapabilities = msg.getButtonCapabilities();
+ List<RadioControlCapabilities> radioControlCapabilities = msg.getRadioControlCapabilities();
+ List<ClimateControlCapabilities> climateControlCapabilities = msg.getClimateControlCapabilities();
+ List<SeatControlCapabilities> seatControlCapabilities = msg.getSeatControlCapabilities();
+ List<AudioControlCapabilities> audioControlCapabilities = msg.getAudioControlCapabilities();
+ HMISettingsControlCapabilities hmiSettingsControlCapabilities = msg.getHmiSettingsControlCapabilities();
+ LightControlCapabilities lightControlCapabilities = msg.getLightControlCapabilities();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_BUTTONCAPABILITIES_LIST.size(), buttonCapabilities.size());
+ assertEquals(Test.MATCH, Test.GENERAL_RADIOCONTROLCAPABILITIES_LIST.size(), radioControlCapabilities.size());
+ assertEquals(Test.MATCH, Test.GENERAL_CLIMATECONTROLCAPABILITIES_LIST.size(), climateControlCapabilities.size());
+ assertEquals(Test.MATCH, Test.GENERAL_SEATCONTROLCAPABILITIES_LIST.size(), seatControlCapabilities.size());
+
+ assertTrue(Test.TRUE, Validator.validateButtonCapabilities(Test.GENERAL_BUTTONCAPABILITIES_LIST, buttonCapabilities));
+ assertTrue(Test.TRUE, Validator.validateRadioControlCapabilities(Test.GENERAL_RADIOCONTROLCAPABILITIES_LIST, radioControlCapabilities));
+ assertTrue(Test.TRUE, Validator.validateClimateControlCapabilities(Test.GENERAL_CLIMATECONTROLCAPABILITIES_LIST, climateControlCapabilities));
+ assertTrue(Test.TRUE, Validator.validateSeatControlCapabilitiesList(Test.GENERAL_SEATCONTROLCAPABILITIES_LIST, seatControlCapabilities));
+ assertTrue(Test.TRUE, Validator.validateAudioControlCapabilitiesList(Test.GENERAL_AUDIOCONTROLCAPABILITIES_LIST, audioControlCapabilities));
+ assertTrue(Test.TRUE, Validator.validateHMISettingsControlCapabilities(Test.GENERAL_HMISETTINGSCONTROLCAPABILITIES, hmiSettingsControlCapabilities));
+ assertTrue(Test.TRUE, Validator.validateLightControlCapabilities(Test.GENERAL_LIGHTCONTROLCAPABILITIES, lightControlCapabilities));
+
+ // Invalid/Null Tests
+ RemoteControlCapabilities msg = new RemoteControlCapabilities();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getButtonCapabilities());
+ assertNull(Test.NULL, msg.getRadioControlCapabilities());
+ assertNull(Test.NULL, msg.getClimateControlCapabilities());
+ assertNull(Test.NULL, msg.getSeatControlCapabilities());
+ assertNull(Test.NULL, msg.getAudioControlCapabilities());
+ assertNull(Test.NULL, msg.getHmiSettingsControlCapabilities());
+ assertNull(Test.NULL, msg.getLightControlCapabilities());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(RemoteControlCapabilities.KEY_BUTTON_CAPABILITIES, Test.JSON_BUTTONCAPABILITIES);
+ reference.put(RemoteControlCapabilities.KEY_RADIO_CONTROL_CAPABILITIES, Test.JSON_RADIOCONTROLCAPABILITIES);
+ reference.put(RemoteControlCapabilities.KEY_CLIMATE_CONTROL_CAPABILITIES, Test.JSON_CLIMATECONTROLCAPABILITIES);
+ reference.put(RemoteControlCapabilities.KEY_SEAT_CONTROL_CAPABILITIES, Test.GENERAL_SEATCONTROLCAPABILITIES_LIST);
+ reference.put(RemoteControlCapabilities.KEY_AUDIO_CONTROL_CAPABILITIES, Test.GENERAL_AUDIOCONTROLCAPABILITIES_LIST);
+ reference.put(RemoteControlCapabilities.KEY_HMI_SETTINGS_CONTROL_CAPABILITIES, JsonRPCMarshaller.serializeHashtable(Test.GENERAL_HMISETTINGSCONTROLCAPABILITIES.getStore()));
+ reference.put(RemoteControlCapabilities.KEY_LIGHT_CONTROL_CAPABILITIES, JsonRPCMarshaller.serializeHashtable(Test.GENERAL_LIGHTCONTROLCAPABILITIES.getStore()));
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ if (key.equals(RemoteControlCapabilities.KEY_BUTTON_CAPABILITIES)) {
+ JSONArray referenceArray = JsonUtils.readJsonArrayFromJsonObject(reference, key);
+ JSONArray underTestArray = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
+ assertEquals(Test.MATCH, referenceArray.length(), underTestArray.length());
+
+ List<ButtonCapabilities> referenceList = new ArrayList<ButtonCapabilities>();
+ List<ButtonCapabilities> testList = new ArrayList<ButtonCapabilities>();
+ for (int i = 0; i < referenceArray.length(); i++) {
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(referenceArray.getJSONObject(i));
+ referenceList.add(new ButtonCapabilities(hashReference));
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(underTestArray.getJSONObject(i));
+ testList.add(new ButtonCapabilities(hashTest));
+ }
+ assertTrue(Test.TRUE, Validator.validateButtonCapabilities(referenceList, testList));
+ } else if (key.equals(RemoteControlCapabilities.KEY_RADIO_CONTROL_CAPABILITIES)) {
+ JSONArray referenceArray = JsonUtils.readJsonArrayFromJsonObject(reference, key);
+ JSONArray underTestArray = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
+ assertEquals(Test.MATCH, referenceArray.length(), underTestArray.length());
+
+ List<RadioControlCapabilities> referenceList = new ArrayList<RadioControlCapabilities>();
+ List<RadioControlCapabilities> testList = new ArrayList<RadioControlCapabilities>();
+ for (int i = 0; i < referenceArray.length(); i++) {
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(referenceArray.getJSONObject(i));
+ referenceList.add(new RadioControlCapabilities(hashReference));
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(underTestArray.getJSONObject(i));
+ testList.add(new RadioControlCapabilities(hashTest));
+ }
+ assertTrue(Test.TRUE, Validator.validateRadioControlCapabilities(referenceList, testList));
+ } else if (key.equals(RemoteControlCapabilities.KEY_CLIMATE_CONTROL_CAPABILITIES)) {
+ JSONArray referenceArray = JsonUtils.readJsonArrayFromJsonObject(reference, key);
+ JSONArray underTestArray = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
+ assertEquals(Test.MATCH, referenceArray.length(), underTestArray.length());
+
+ List<ClimateControlCapabilities> referenceList = new ArrayList<ClimateControlCapabilities>();
+ List<ClimateControlCapabilities> testList = new ArrayList<ClimateControlCapabilities>();
+ for (int i = 0; i < referenceArray.length(); i++) {
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(referenceArray.getJSONObject(i));
+ referenceList.add(new ClimateControlCapabilities(hashReference));
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(underTestArray.getJSONObject(i));
+ testList.add(new ClimateControlCapabilities(hashTest));
+ }
+ assertTrue(Test.TRUE, Validator.validateClimateControlCapabilities(referenceList, testList));
+ } else if (key.equals(RemoteControlCapabilities.KEY_SEAT_CONTROL_CAPABILITIES)) {
+ List<SeatControlCapabilities> sccReference = (List<SeatControlCapabilities>) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONArray sccArray = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
+ int i = 0;
+ for (SeatControlCapabilities scc : sccReference) {
+ assertTrue(Validator.validateSeatControlCapabilities(scc, new SeatControlCapabilities(JsonRPCMarshaller.deserializeJSONObject(sccArray.getJSONObject(i++)))));
+ }
+ } else if (key.equals(RemoteControlCapabilities.KEY_AUDIO_CONTROL_CAPABILITIES)) {
+ List<AudioControlCapabilities> accReference = (List<AudioControlCapabilities>) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONArray accArray = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
+ int i = 0;
+ for (AudioControlCapabilities acc : accReference) {
+ assertTrue(Validator.validateAudioControlCapabilities(acc, new AudioControlCapabilities(JsonRPCMarshaller.deserializeJSONObject(accArray.getJSONObject(i++)))));
+ }
+ } else if (key.equals(RemoteControlCapabilities.KEY_HMI_SETTINGS_CONTROL_CAPABILITIES)) {
+ JSONObject objectEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
+ assertTrue(Test.TRUE, Validator.validateHMISettingsControlCapabilities(new HMISettingsControlCapabilities(hashReference), new HMISettingsControlCapabilities(hashTest)));
+ } else if (key.equals(RemoteControlCapabilities.KEY_LIGHT_CONTROL_CAPABILITIES)) {
+ JSONObject objectEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
+ assertTrue(Test.TRUE, Validator.validateLightControlCapabilities(new LightControlCapabilities(hashReference), new LightControlCapabilities(hashTest)));
+ }
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SeatControlCapabilitiesTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SeatControlCapabilitiesTest.java
new file mode 100644
index 000000000..d988fa991
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SeatControlCapabilitiesTest.java
@@ -0,0 +1,141 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.proxy.rpc.SeatControlCapabilities;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.SeatControlCapabilities}
+ */
+public class SeatControlCapabilitiesTest extends TestCase {
+
+ private SeatControlCapabilities msg;
+
+ @Override
+ public void setUp() {
+ msg = new SeatControlCapabilities();
+ msg.setModuleName(Test.GENERAL_STRING);
+ msg.setHeatingEnabledAvailable(Test.GENERAL_BOOLEAN);
+ msg.setCoolingEnabledAvailable(Test.GENERAL_BOOLEAN);
+ msg.setHeatingLevelAvailable(Test.GENERAL_BOOLEAN);
+ msg.setCoolingLevelAvailable(Test.GENERAL_BOOLEAN);
+ msg.setHorizontalPositionAvailable(Test.GENERAL_BOOLEAN);
+ msg.setVerticalPositionAvailable(Test.GENERAL_BOOLEAN);
+ msg.setFrontVerticalPositionAvailable(Test.GENERAL_BOOLEAN);
+ msg.setBackVerticalPositionAvailable(Test.GENERAL_BOOLEAN);
+ msg.setBackTiltAngleAvailable(Test.GENERAL_BOOLEAN);
+ msg.setHeadSupportVerticalPositionAvailable(Test.GENERAL_BOOLEAN);
+ msg.setHeadSupportHorizontalPositionAvailable(Test.GENERAL_BOOLEAN);
+ msg.setMassageEnabledAvailable(Test.GENERAL_BOOLEAN);
+ msg.setMassageModeAvailable(Test.GENERAL_BOOLEAN);
+ msg.setMassageCushionFirmnessAvailable(Test.GENERAL_BOOLEAN);
+ msg.setMemoryAvailable(Test.GENERAL_BOOLEAN);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+ String moduleName = msg.getModuleName();
+ Boolean heatingEnabledAvailable = msg.getHeatingEnabledAvailable();
+ Boolean coolingEnabledAvailable = msg.getCoolingEnabledAvailable();
+ Boolean heatingLevelAvailable = msg.getHeatingLevelAvailable();
+ Boolean coolingLevelAvailable = msg.getCoolingLevelAvailable();
+ Boolean horizontalPositionAvailable = msg.getHorizontalPositionAvailable();
+ Boolean verticalPositionAvailable = msg.getVerticalPositionAvailable();
+ Boolean frontVerticalPositionAvailable = msg.getFrontVerticalPositionAvailable();
+ Boolean backVerticalPositionAvailable = msg.getBackVerticalPositionAvailable();
+ Boolean backTiltAngleAvailable = msg.getBackTiltAngleAvailable();
+ Boolean headSupportHorizontalPositionAvailable = msg.getHeadSupportHorizontalPositionAvailable();
+ Boolean headSupportVerticalPositionAvailable = msg.getHeadSupportVerticalPositionAvailable();
+ Boolean massageEnabledAvailable = msg.getMassageEnabledAvailable();
+ Boolean massageModeAvailable = msg.getMassageModeAvailable();
+ Boolean massageCushionFirmnessAvailable = msg.getMassageCushionFirmnessAvailable();
+
+ Boolean memoryAvailable = msg.getMemoryAvailable();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_STRING, moduleName);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, heatingEnabledAvailable);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, coolingEnabledAvailable);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, heatingLevelAvailable);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, coolingLevelAvailable);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, horizontalPositionAvailable);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, verticalPositionAvailable);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, frontVerticalPositionAvailable);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, backVerticalPositionAvailable);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, backTiltAngleAvailable);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, headSupportHorizontalPositionAvailable);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, headSupportVerticalPositionAvailable);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, massageEnabledAvailable);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, massageModeAvailable);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, massageCushionFirmnessAvailable);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, memoryAvailable);
+
+ // Invalid/Null Tests
+ SeatControlCapabilities msg = new SeatControlCapabilities();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getModuleName());
+ assertNull(Test.NULL, msg.getHeatingEnabledAvailable());
+ assertNull(Test.NULL, msg.getCoolingEnabledAvailable());
+ assertNull(Test.NULL, msg.getHeatingLevelAvailable());
+ assertNull(Test.NULL, msg.getCoolingLevelAvailable());
+ assertNull(Test.NULL, msg.getHorizontalPositionAvailable());
+ assertNull(Test.NULL, msg.getVerticalPositionAvailable());
+ assertNull(Test.NULL, msg.getFrontVerticalPositionAvailable());
+ assertNull(Test.NULL, msg.getBackVerticalPositionAvailable());
+ assertNull(Test.NULL, msg.getBackTiltAngleAvailable());
+ assertNull(Test.NULL, msg.getHeadSupportHorizontalPositionAvailable());
+ assertNull(Test.NULL, msg.getHeadSupportVerticalPositionAvailable());
+ assertNull(Test.NULL, msg.getMassageEnabledAvailable());
+ assertNull(Test.NULL, msg.getMassageModeAvailable());
+ assertNull(Test.NULL, msg.getMassageCushionFirmnessAvailable());
+ assertNull(Test.NULL, msg.getMemoryAvailable());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(SeatControlCapabilities.KEY_MODULE_NAME, Test.GENERAL_STRING);
+ reference.put(SeatControlCapabilities.KEY_HEATING_ENABLED_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(SeatControlCapabilities.KEY_COOLING_ENABLED_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(SeatControlCapabilities.KEY_HEATING_LEVEL_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(SeatControlCapabilities.KEY_COOLING_LEVEL_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(SeatControlCapabilities.KEY_HORIZONTAL_POSITION_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(SeatControlCapabilities.KEY_VERTICAL_POSITION_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(SeatControlCapabilities.KEY_FRONT_VERTICAL_POSITION_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(SeatControlCapabilities.KEY_BACK_VERTICAL_POSITION_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(SeatControlCapabilities.KEY_BACK_TILT_ANGLE_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(SeatControlCapabilities.KEY_HEAD_SUPPORT_HORIZONTAL_POSITION_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(SeatControlCapabilities.KEY_HEAD_SUPPORT_VERTICAL_POSITION_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(SeatControlCapabilities.KEY_MASSAGE_ENABLED_AVAILABLE, Test.GENERAL_BOOLEAN);
+
+ reference.put(SeatControlCapabilities.KEY_MASSAGE_MODE_AVAILABLE, Test.GENERAL_BOOLEAN);
+ reference.put(SeatControlCapabilities.KEY_MASSAGE_CUSHION_FIRMNESS_AVAILABLE, Test.GENERAL_BOOLEAN);
+
+ reference.put(SeatControlCapabilities.KEY_MEMORY_AVAILABLE, Test.GENERAL_BOOLEAN);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SeatControlDataTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SeatControlDataTest.java
new file mode 100644
index 000000000..535e7cf3e
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SeatControlDataTest.java
@@ -0,0 +1,173 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.proxy.rpc.MassageCushionFirmness;
+import com.smartdevicelink.proxy.rpc.MassageModeData;
+import com.smartdevicelink.proxy.rpc.SeatControlData;
+import com.smartdevicelink.proxy.rpc.SeatMemoryAction;
+import com.smartdevicelink.proxy.rpc.enums.SupportedSeat;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+import com.smartdevicelink.test.Validator;
+
+import junit.framework.TestCase;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.SeatControlData}
+ */
+public class SeatControlDataTest extends TestCase {
+
+ private SeatControlData msg;
+
+ @Override
+ public void setUp() {
+ msg = new SeatControlData();
+ msg.setId(Test.GENERAL_SUPPORTEDSEAT);
+ msg.setHeatingEnabled(Test.GENERAL_BOOLEAN);
+ msg.setCoolingEnabled(Test.GENERAL_BOOLEAN);
+ msg.setHeatingLevel(Test.GENERAL_INT);
+ msg.setCoolingLevel(Test.GENERAL_INT);
+ msg.setHorizontalPosition(Test.GENERAL_INT);
+ msg.setVerticalPosition(Test.GENERAL_INT);
+ msg.setFrontVerticalPosition(Test.GENERAL_INT);
+ msg.setBackVerticalPosition(Test.GENERAL_INT);
+ msg.setBackTiltAngle(Test.GENERAL_INT);
+ msg.setHeadSupportVerticalPosition(Test.GENERAL_INT);
+ msg.setHeadSupportHorizontalPosition(Test.GENERAL_INT);
+ msg.setMassageEnabled(Test.GENERAL_BOOLEAN);
+ msg.setMassageMode(Test.GENERAL_MASSAGEMODEDATA_LIST);
+ msg.setMassageCushionFirmness(Test.GENERAL_MASSAGECUSHIONFIRMNESS_LIST);
+ msg.setMemory(Test.GENERAL_SEATMEMORYACTION);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+ SupportedSeat id = msg.getId();
+ Boolean heatingEnabled = msg.getHeatingEnabled();
+ Boolean coolingEnabled = msg.getCoolingEnabled();
+ Integer heatingLevel = msg.getHeatingLevel();
+ Integer coolingLevel = msg.getCoolingLevel();
+ Integer horizontalPosition = msg.getHorizontalPosition();
+ Integer verticalPosition = msg.getVerticalPosition();
+ Integer frontVerticalPosition = msg.getFrontVerticalPosition();
+ Integer backVerticalPosition = msg.getBackVerticalPosition();
+ Integer backTiltAngle = msg.getBackTiltAngle();
+ Integer headSupportHorizontalPosition = msg.getHeadSupportHorizontalPosition();
+ Integer headSupportVerticalPosition = msg.getHeadSupportVerticalPosition();
+ Boolean massageEnabled = msg.getMassageEnabled();
+
+ List<MassageModeData> massageMode = msg.getMassageMode();
+ List<MassageCushionFirmness> massageCushionFirmness = msg.getMassageCushionFirmness();
+ SeatMemoryAction memory = msg.getMemory();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_SUPPORTEDSEAT, id);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, heatingEnabled);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, coolingEnabled);
+ assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, heatingLevel);
+ assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, coolingLevel);
+ assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, horizontalPosition);
+ assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, verticalPosition);
+ assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, frontVerticalPosition);
+ assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, backVerticalPosition);
+ assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, backTiltAngle);
+ assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, headSupportHorizontalPosition);
+ assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, headSupportVerticalPosition);
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, massageEnabled);
+
+ assertTrue(Test.TRUE, Validator.validateMassageModeDataList(Test.GENERAL_MASSAGEMODEDATA_LIST, massageMode));
+ assertTrue(Test.TRUE, Validator.validateMassageCushionFirmnessList(Test.GENERAL_MASSAGECUSHIONFIRMNESS_LIST, massageCushionFirmness));
+
+ assertTrue(Test.TRUE, Validator.validateSeatMemoryAction(Test.GENERAL_SEATMEMORYACTION, memory));
+
+ // Invalid/Null Tests
+ SeatControlData msg = new SeatControlData();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getId());
+ assertNull(Test.NULL, msg.getHeatingEnabled());
+ assertNull(Test.NULL, msg.getCoolingEnabled());
+ assertNull(Test.NULL, msg.getHeatingLevel());
+ assertNull(Test.NULL, msg.getCoolingLevel());
+ assertNull(Test.NULL, msg.getHorizontalPosition());
+ assertNull(Test.NULL, msg.getVerticalPosition());
+ assertNull(Test.NULL, msg.getFrontVerticalPosition());
+ assertNull(Test.NULL, msg.getBackVerticalPosition());
+ assertNull(Test.NULL, msg.getBackTiltAngle());
+ assertNull(Test.NULL, msg.getHeadSupportHorizontalPosition());
+ assertNull(Test.NULL, msg.getHeadSupportVerticalPosition());
+ assertNull(Test.NULL, msg.getMassageEnabled());
+ assertNull(Test.NULL, msg.getMassageMode());
+ assertNull(Test.NULL, msg.getMassageCushionFirmness());
+ assertNull(Test.NULL, msg.getMemory());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(SeatControlData.KEY_ID, Test.GENERAL_SUPPORTEDSEAT);
+ reference.put(SeatControlData.KEY_HEATING_ENABLED, Test.GENERAL_BOOLEAN);
+ reference.put(SeatControlData.KEY_COOLING_ENABLED, Test.GENERAL_BOOLEAN);
+ reference.put(SeatControlData.KEY_HEATING_LEVEL, Test.GENERAL_INT);
+ reference.put(SeatControlData.KEY_COOLING_LEVEL, Test.GENERAL_INT);
+ reference.put(SeatControlData.KEY_HORIZONTAL_POSITION, Test.GENERAL_INT);
+ reference.put(SeatControlData.KEY_VERTICAL_POSITION, Test.GENERAL_INT);
+ reference.put(SeatControlData.KEY_FRONT_VERTICAL_POSITION, Test.GENERAL_INT);
+ reference.put(SeatControlData.KEY_BACK_VERTICAL_POSITION, Test.GENERAL_INT);
+ reference.put(SeatControlData.KEY_BACK_TILT_ANGLE, Test.GENERAL_INT);
+ reference.put(SeatControlData.KEY_HEAD_SUPPORT_HORIZONTAL_POSITION, Test.GENERAL_INT);
+ reference.put(SeatControlData.KEY_HEAD_SUPPORT_VERTICAL_POSITION, Test.GENERAL_INT);
+ reference.put(SeatControlData.KEY_MASSAGE_ENABLED, Test.GENERAL_BOOLEAN);
+
+ reference.put(SeatControlData.KEY_MASSAGE_MODE, Test.GENERAL_MASSAGEMODEDATA_LIST);
+ reference.put(SeatControlData.KEY_MASSAGE_CUSHION_FIRMNESS, Test.GENERAL_MASSAGECUSHIONFIRMNESS_LIST);
+
+ reference.put(SeatControlData.KEY_MEMORY, Test.GENERAL_SEATMEMORYACTION);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ if (key.equals(SeatControlData.KEY_MASSAGE_MODE)) {
+ List<MassageModeData> mmdReference = (List<MassageModeData>) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONArray mmdArray = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
+ int i = 0;
+ for (MassageModeData mmd : mmdReference) {
+ assertTrue(Validator.validateMassageModeData(mmd, new MassageModeData(JsonRPCMarshaller.deserializeJSONObject(mmdArray.getJSONObject(i++)))));
+ }
+ } else if (key.equals(SeatControlData.KEY_MASSAGE_CUSHION_FIRMNESS)) {
+ List<MassageCushionFirmness> mcfReference = (List<MassageCushionFirmness>) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONArray mcfArray = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
+ int i = 0;
+ for (MassageCushionFirmness mcf : mcfReference) {
+ assertTrue(Validator.validateMassageCushionFirmness(mcf, new MassageCushionFirmness(JsonRPCMarshaller.deserializeJSONObject(mcfArray.getJSONObject(i++)))));
+ }
+ } else if (key.equals(SeatControlData.KEY_MEMORY)) {
+ SeatMemoryAction mReference = (SeatMemoryAction) JsonUtils.readObjectFromJsonObject(reference, key);
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(JsonUtils.readJsonObjectFromJsonObject(underTest, key));
+ assertTrue(Validator.validateSeatMemoryAction(mReference, new SeatMemoryAction(hashTest)));
+ } else {
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+ }
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SeatMemoryActionTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SeatMemoryActionTest.java
new file mode 100644
index 000000000..a8c17cee3
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SeatMemoryActionTest.java
@@ -0,0 +1,75 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.proxy.rpc.SeatMemoryAction;
+import com.smartdevicelink.proxy.rpc.enums.SeatMemoryActionType;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.SeatMemoryAction}
+ */
+public class SeatMemoryActionTest extends TestCase {
+
+ private SeatMemoryAction msg;
+
+ @Override
+ public void setUp() {
+ msg = new SeatMemoryAction();
+
+ msg.setId(Test.GENERAL_INT);
+ msg.setLabel(Test.GENERAL_STRING);
+ msg.setAction(Test.GENERAL_SEATMEMORYACTIONTYPE);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+ Integer id = msg.getId();
+ String label = msg.getLabel();
+ SeatMemoryActionType action = msg.getAction();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, (Integer) Test.GENERAL_INT, id);
+ assertEquals(Test.MATCH, Test.GENERAL_STRING, label);
+ assertEquals(Test.MATCH, Test.GENERAL_SEATMEMORYACTIONTYPE, action);
+
+ // Invalid/Null Tests
+ SeatMemoryAction msg = new SeatMemoryAction();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getId());
+ assertNull(Test.NULL, msg.getLabel());
+ assertNull(Test.NULL, msg.getAction());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(SeatMemoryAction.KEY_ID, Test.GENERAL_INT);
+ reference.put(SeatMemoryAction.KEY_LABEL, Test.GENERAL_STRING);
+ reference.put(SeatMemoryAction.KEY_ACTION, Test.GENERAL_SEATMEMORYACTIONTYPE);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SingleTireStatusTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SingleTireStatusTest.java
index aa6d7fadd..9f1d3342a 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SingleTireStatusTest.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SingleTireStatusTest.java
@@ -9,12 +9,13 @@ import org.json.JSONObject;
import com.smartdevicelink.proxy.rpc.SingleTireStatus;
import com.smartdevicelink.proxy.rpc.enums.ComponentVolumeStatus;
+import com.smartdevicelink.proxy.rpc.enums.TPMS;
import com.smartdevicelink.test.JsonUtils;
import com.smartdevicelink.test.Test;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.SingleTireStatus}
+ * {@link com.smartdevicelink.proxy.rpc.SingleTireStatus}
*/
public class SingleTireStatusTest extends TestCase {
@@ -25,6 +26,8 @@ public class SingleTireStatusTest extends TestCase {
msg = new SingleTireStatus();
msg.setStatus(Test.GENERAL_COMPONENTVOLUMESTATUS);
+ msg.setTPMS(Test.GENERAL_TPMS);
+ msg.setPressure(Test.GENERAL_FLOAT);
}
/**
@@ -33,15 +36,21 @@ public class SingleTireStatusTest extends TestCase {
public void testRpcValues () {
// Test Values
ComponentVolumeStatus status = msg.getStatus();
+ TPMS tpms = msg.getTPMS();
+ Float pressure = msg.getPressure();
// Valid Tests
assertEquals(Test.MATCH, Test.GENERAL_COMPONENTVOLUMESTATUS, status);
+ assertEquals(Test.MATCH, Test.GENERAL_TPMS, tpms);
+ assertEquals(Test.MATCH, Test.GENERAL_FLOAT, pressure);
// Invalid/Null Tests
SingleTireStatus msg = new SingleTireStatus();
assertNotNull(Test.NOT_NULL, msg);
assertNull(Test.NULL, msg.getStatus());
+ assertNull(Test.NULL, msg.getTPMS());
+ assertNull(Test.NULL, msg.getPressure());
}
public void testJson() {
@@ -49,6 +58,8 @@ public class SingleTireStatusTest extends TestCase {
try {
reference.put(SingleTireStatus.KEY_STATUS, Test.GENERAL_COMPONENTVOLUMESTATUS);
+ reference.put(SingleTireStatus.KEY_TPMS, Test.GENERAL_TPMS);
+ reference.put(SingleTireStatus.KEY_PRESSURE, Test.GENERAL_FLOAT);
JSONObject underTest = msg.serializeJSON();
assertEquals(Test.MATCH, reference.length(), underTest.length());
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SisDataTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SisDataTests.java
new file mode 100644
index 000000000..51e38f8d1
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/SisDataTests.java
@@ -0,0 +1,105 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.proxy.rpc.GPSData;
+import com.smartdevicelink.proxy.rpc.SisData;
+import com.smartdevicelink.proxy.rpc.StationIDNumber;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+import com.smartdevicelink.test.Validator;
+import com.smartdevicelink.test.VehicleDataHelper;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.SisData}
+ */
+public class SisDataTests extends TestCase {
+
+ private SisData msg;
+
+ @Override
+ public void setUp() {
+ msg = new SisData();
+
+ msg.setStationShortName(Test.GENERAL_STRING);
+ msg.setStationIDNumber(Test.GENERAL_STATIONIDNUMBER);
+ msg.setStationLongName(Test.GENERAL_STRING);
+ msg.setStationLocation(VehicleDataHelper.GPS);
+ msg.setStationMessage(Test.GENERAL_STRING);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+ String stationShortName = msg.getStationShortName();
+ StationIDNumber stationIDNumber = msg.getStationIDNumber();
+ String stationLongName = msg.getStationLongName();
+ GPSData stationLocation = msg.getStationLocation();
+ String stationMessage = msg.getStationMessage();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_STRING, stationShortName);
+ assertEquals(Test.MATCH, Test.GENERAL_STATIONIDNUMBER, stationIDNumber);
+ assertEquals(Test.MATCH, Test.GENERAL_STRING, stationLongName);
+ assertEquals(Test.MATCH, VehicleDataHelper.GPS, stationLocation);
+ assertEquals(Test.MATCH, Test.GENERAL_STRING, stationMessage);
+
+ // Invalid/Null Tests
+ SisData msg = new SisData();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getStationShortName());
+ assertNull(Test.NULL, msg.getStationIDNumber());
+ assertNull(Test.NULL, msg.getStationLongName());
+ assertNull(Test.NULL, msg.getStationLocation());
+ assertNull(Test.NULL, msg.getStationMessage());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(SisData.KEY_STATION_SHORT_NAME, Test.GENERAL_STRING);
+ reference.put(SisData.KEY_STATION_ID_NUMBER, JsonRPCMarshaller.serializeHashtable(Test.GENERAL_STATIONIDNUMBER.getStore()));
+ reference.put(SisData.KEY_STATION_LONG_NAME, Test.GENERAL_STRING);
+ reference.put(SisData.KEY_STATION_LOCATION, JsonRPCMarshaller.serializeHashtable(VehicleDataHelper.GPS.getStore()));
+ reference.put(SisData.KEY_STATION_MESSAGE, Test.GENERAL_STRING);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ if (key.equals(SisData.KEY_STATION_ID_NUMBER)) {
+ JSONObject objectEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
+ assertTrue(Test.TRUE, Validator.validateStationIDNumber(new StationIDNumber(hashReference), new StationIDNumber(hashTest)));
+ } else if (key.equals(SisData.KEY_STATION_LOCATION)) {
+ JSONObject objectEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(reference, key);
+ JSONObject testEquals = (JSONObject) JsonUtils.readObjectFromJsonObject(underTest, key);
+ Hashtable<String, Object> hashReference = JsonRPCMarshaller.deserializeJSONObject(objectEquals);
+ Hashtable<String, Object> hashTest = JsonRPCMarshaller.deserializeJSONObject(testEquals);
+ assertTrue(Test.TRUE, Validator.validateGpsData(new GPSData(hashReference), new GPSData(hashTest)));
+ } else {
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+ }
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/StationIDNumberTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/StationIDNumberTests.java
new file mode 100644
index 000000000..e7e61f8fd
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/StationIDNumberTests.java
@@ -0,0 +1,73 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.proxy.rpc.StationIDNumber;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.StationIDNumber}
+ */
+public class StationIDNumberTests extends TestCase {
+
+ private StationIDNumber msg;
+
+ @Override
+ public void setUp() {
+ msg = new StationIDNumber();
+
+ msg.setCountryCode(Test.GENERAL_INT);
+ msg.setFccFacilityId(Test.GENERAL_INT);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+
+ int countryCode = msg.getCountryCode();
+ int fccFacilityId = msg.getFccFacilityId();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_INT, countryCode);
+ assertEquals(Test.MATCH, Test.GENERAL_INT, fccFacilityId);
+
+ // Invalid/Null Tests
+ StationIDNumber msg = new StationIDNumber();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getCountryCode());
+ assertNull(Test.NULL, msg.getFccFacilityId());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+
+ reference.put(StationIDNumber.KEY_COUNTRY_CODE, Test.GENERAL_INT);
+ reference.put(StationIDNumber.KEY_FCC_FACILITY_ID, Test.GENERAL_INT);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ assertEquals(Test.MATCH, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
+
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/TemplateColorSchemeTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/TemplateColorSchemeTest.java
new file mode 100644
index 000000000..0ac90fc86
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/datatypes/TemplateColorSchemeTest.java
@@ -0,0 +1,81 @@
+package com.smartdevicelink.test.rpc.datatypes;
+
+import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.proxy.rpc.RGBColor;
+import com.smartdevicelink.proxy.rpc.RegisterAppInterface;
+import com.smartdevicelink.proxy.rpc.TemplateColorScheme;
+import com.smartdevicelink.test.JsonUtils;
+import com.smartdevicelink.test.Test;
+import com.smartdevicelink.test.Validator;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.proxy.rpc.TemplateColorScheme}
+ */
+public class TemplateColorSchemeTest extends TestCase {
+
+ private TemplateColorScheme msg;
+
+ @Override
+ public void setUp() {
+ msg = new TemplateColorScheme();
+ msg.setPrimaryColor(Test.GENERAL_RGBCOLOR);
+ msg.setSecondaryColor(Test.GENERAL_RGBCOLOR);
+ msg.setBackgroundColor(Test.GENERAL_RGBCOLOR);
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues () {
+ // Test Values
+ RGBColor primaryColor = msg.getPrimaryColor();
+ RGBColor secondaryColor = msg.getSecondaryColor();
+ RGBColor backgroundColor = msg.getBackgroundColor();
+
+ // Valid Tests
+ assertTrue(Test.TRUE, Validator.validateRGBColor(Test.GENERAL_RGBCOLOR, primaryColor));
+ assertTrue(Test.TRUE, Validator.validateRGBColor(Test.GENERAL_RGBCOLOR, secondaryColor));
+ assertTrue(Test.TRUE, Validator.validateRGBColor(Test.GENERAL_RGBCOLOR, backgroundColor));
+
+ // Invalid/Null Tests
+ TemplateColorScheme msg = new TemplateColorScheme();
+ assertNotNull(Test.NOT_NULL, msg);
+
+ assertNull(Test.NULL, msg.getPrimaryColor());
+ assertNull(Test.NULL, msg.getSecondaryColor());
+ assertNull(Test.NULL, msg.getBackgroundColor());
+ }
+
+ public void testJson() {
+ JSONObject reference = new JSONObject();
+
+ try {
+ reference.put(TemplateColorScheme.KEY_PRIMARY_COLOR, Test.JSON_RGBCOLOR);
+ reference.put(TemplateColorScheme.KEY_SECONDARY_COLOR, Test.JSON_RGBCOLOR);
+ reference.put(TemplateColorScheme.KEY_BACKGROUND_COLOR, Test.JSON_RGBCOLOR);
+
+ JSONObject underTest = msg.serializeJSON();
+ assertEquals(Test.MATCH, reference.length(), underTest.length());
+
+ Iterator<?> iterator = reference.keys();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+ JSONObject referenceColorObj = JsonUtils.readJsonObjectFromJsonObject(reference, key);
+ RGBColor referenceColor = new RGBColor(JsonRPCMarshaller.deserializeJSONObject(referenceColorObj));
+ JSONObject underTestColorObj = JsonUtils.readJsonObjectFromJsonObject(underTest, key);
+ RGBColor underTestColor = new RGBColor(JsonRPCMarshaller.deserializeJSONObject(underTestColorObj));
+ assertTrue(Test.TRUE, Validator.validateRGBColor(referenceColor, underTestColor));
+ }
+ } catch (JSONException e) {
+ fail(Test.JSON_FAIL);
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/AudioStreamingIndicatorTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/AudioStreamingIndicatorTests.java
new file mode 100644
index 000000000..85312ecde
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/AudioStreamingIndicatorTests.java
@@ -0,0 +1,80 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import com.smartdevicelink.proxy.rpc.enums.AudioStreamingIndicator;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.proxy.rpc.enums.AudioStreamingIndicator}
+ */
+public class AudioStreamingIndicatorTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums () {
+ String example = "PLAY_PAUSE";
+ AudioStreamingIndicator enumPlayPause = AudioStreamingIndicator.valueForString(example);
+ example = "PLAY";
+ AudioStreamingIndicator enumPlay = AudioStreamingIndicator.valueForString(example);
+ example = "PAUSE";
+ AudioStreamingIndicator enumPause = AudioStreamingIndicator.valueForString(example);
+ example = "STOP";
+ AudioStreamingIndicator enumStop = AudioStreamingIndicator.valueForString(example);
+
+
+ assertNotNull("PLAY_PAUSE returned null", enumPlayPause);
+ assertNotNull("PLAY returned null", enumPlay);
+ assertNotNull("PAUSE returned null", enumPause);
+ assertNotNull("STOP returned null", enumStop);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum () {
+ String example = "pLayPauZe";
+ try {
+ AudioStreamingIndicator temp = AudioStreamingIndicator.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum () {
+ String example = null;
+ try {
+ AudioStreamingIndicator temp = AudioStreamingIndicator.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of AudioStreamingIndicator.
+ */
+ public void testListEnum() {
+ List<AudioStreamingIndicator> enumValueList = Arrays.asList(AudioStreamingIndicator.values());
+
+ List<AudioStreamingIndicator> enumTestList = new ArrayList<>();
+ enumTestList.add(AudioStreamingIndicator.PLAY_PAUSE);
+ enumTestList.add(AudioStreamingIndicator.PLAY);
+ enumTestList.add(AudioStreamingIndicator.PAUSE);
+ enumTestList.add(AudioStreamingIndicator.STOP);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/AudioStreamingStateTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/AudioStreamingStateTests.java
index ab5972218..178613e53 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/AudioStreamingStateTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/AudioStreamingStateTests.java
@@ -10,7 +10,7 @@ import com.smartdevicelink.proxy.rpc.enums.AudioStreamingState;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.enums.AudioStreaming}
+ * {@link com.smartdevicelink.proxy.rpc.enums.AudioStreamingState}
*/
public class AudioStreamingStateTests extends TestCase {
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ButtonNameTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ButtonNameTests.java
index e37eb2fd1..e823e7593 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ButtonNameTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ButtonNameTests.java
@@ -10,7 +10,7 @@ import com.smartdevicelink.proxy.rpc.enums.ButtonName;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.enums.ButtonName}
+ * {@link com.smartdevicelink.proxy.rpc.enums.ButtonName}
*/
public class ButtonNameTests extends TestCase {
@@ -199,6 +199,7 @@ public class ButtonNameTests extends TestCase {
enumTestList.add(ButtonName.SOURCE);
enumTestList.add(ButtonName.SHUFFLE);
enumTestList.add(ButtonName.REPEAT);
+ enumTestList.add(ButtonName.PLAY_PAUSE);
assertTrue("Enum value list does not match enum class list",
enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/DisplayModeTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/DisplayModeTests.java
new file mode 100644
index 000000000..94387ef9a
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/DisplayModeTests.java
@@ -0,0 +1,74 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.DisplayMode;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.enums.DisplayMode}
+ */
+public class DisplayModeTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums() {
+ String example = "DAY";
+ DisplayMode enumDay = DisplayMode.valueForString(example);
+ example = "NIGHT";
+ DisplayMode enumNight = DisplayMode.valueForString(example);
+ example = "AUTO";
+ DisplayMode enumAuto = DisplayMode.valueForString(example);
+
+ assertNotNull("DAY returned null", enumDay);
+ assertNotNull("NIGHT returned null", enumNight);
+ assertNotNull("AUTO returned null", enumAuto);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum() {
+ String example = "dAY";
+ try {
+ DisplayMode temp = DisplayMode.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum() {
+ String example = null;
+ try {
+ DisplayMode temp = DisplayMode.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of DisplayMode.
+ */
+ public void testListEnum() {
+ List<DisplayMode> enumValueList = Arrays.asList(DisplayMode.values());
+
+ List<DisplayMode> enumTestList = new ArrayList<DisplayMode>();
+ enumTestList.add(DisplayMode.DAY);
+ enumTestList.add(DisplayMode.NIGHT);
+ enumTestList.add(DisplayMode.AUTO);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/DistanceUnitTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/DistanceUnitTests.java
new file mode 100644
index 000000000..c421d6029
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/DistanceUnitTests.java
@@ -0,0 +1,69 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.DistanceUnit;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.enums.DistanceUnit}
+ */
+public class DistanceUnitTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums() {
+ String example = "MILES";
+ DistanceUnit enumMiles = DistanceUnit.valueForString(example);
+ example = "KILOMETERS";
+ DistanceUnit enumKilometers = DistanceUnit.valueForString(example);
+
+ assertNotNull("MILES returned null", enumMiles);
+ assertNotNull("KILOMETERS returned null", enumKilometers);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum() {
+ String example = "mILES";
+ try {
+ DistanceUnit temp = DistanceUnit.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum() {
+ String example = null;
+ try {
+ DistanceUnit temp = DistanceUnit.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of DistanceUnit.
+ */
+ public void testListEnum() {
+ List<DistanceUnit> enumValueList = Arrays.asList(DistanceUnit.values());
+ List<DistanceUnit> enumTestList = new ArrayList<DistanceUnit>();
+ enumTestList.add(DistanceUnit.MILES);
+ enumTestList.add(DistanceUnit.KILOMETERS);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ElectronicParkBrakeStatusTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ElectronicParkBrakeStatusTests.java
new file mode 100644
index 000000000..bbeb1bce3
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ElectronicParkBrakeStatusTests.java
@@ -0,0 +1,82 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.ElectronicParkBrakeStatus;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.enums.ElectronicParkBrakeStatus}
+ */
+public class ElectronicParkBrakeStatusTests extends TestCase {
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums () {
+ String example = "CLOSED";
+ ElectronicParkBrakeStatus enumClosed = ElectronicParkBrakeStatus.valueForString(example);
+ example = "TRANSITION";
+ ElectronicParkBrakeStatus enumTransition = ElectronicParkBrakeStatus.valueForString(example);
+ example = "OPEN";
+ ElectronicParkBrakeStatus enumOpen = ElectronicParkBrakeStatus.valueForString(example);
+ example = "DRIVE_ACTIVE";
+ ElectronicParkBrakeStatus enumDriveActive = ElectronicParkBrakeStatus.valueForString(example);
+ example = "FAULT";
+ ElectronicParkBrakeStatus enumFault = ElectronicParkBrakeStatus.valueForString(example);
+
+ assertNotNull("CLOSED returned null", enumClosed);
+ assertNotNull("TRANSITION returned null", enumTransition);
+ assertNotNull("OPEN returned null", enumOpen);
+ assertNotNull("DRIVE_ACTIVE returned null", enumDriveActive);
+ assertNotNull("FAULT returned null", enumFault);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum () {
+ String example = "Clsoed";
+ try {
+ ElectronicParkBrakeStatus temp = ElectronicParkBrakeStatus.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum () {
+ String example = null;
+ try {
+ ElectronicParkBrakeStatus temp = ElectronicParkBrakeStatus.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of Electronic Brake Status.
+ */
+ public void testListEnum() {
+ List<ElectronicParkBrakeStatus> enumValueList = Arrays.asList(ElectronicParkBrakeStatus.values());
+
+ List<ElectronicParkBrakeStatus> enumTestList = new ArrayList<ElectronicParkBrakeStatus>();
+ enumTestList.add(ElectronicParkBrakeStatus.CLOSED);
+ enumTestList.add(ElectronicParkBrakeStatus.TRANSITION);
+ enumTestList.add(ElectronicParkBrakeStatus.OPEN);
+ enumTestList.add(ElectronicParkBrakeStatus.DRIVE_ACTIVE);
+ enumTestList.add(ElectronicParkBrakeStatus.FAULT);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/FuelTypeTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/FuelTypeTests.java
new file mode 100644
index 000000000..525cc0316
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/FuelTypeTests.java
@@ -0,0 +1,87 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.FuelType;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.enums.FuelType}
+ */
+public class FuelTypeTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums () {
+ String example = "GASOLINE";
+ FuelType enumGasoline = FuelType.valueForString(example);
+ example = "DIESEL";
+ FuelType enumDiesel = FuelType.valueForString(example);
+ example = "CNG";
+ FuelType enumCng = FuelType.valueForString(example);
+ example = "LPG";
+ FuelType enumLpg = FuelType.valueForString(example);
+ example = "HYDROGEN";
+ FuelType enumHydrogen = FuelType.valueForString(example);
+ example = "BATTERY";
+ FuelType enumBattery = FuelType.valueForString(example);
+
+ assertNotNull("GASOLINE returned null", enumGasoline);
+ assertNotNull("DIESEL returned null", enumDiesel);
+ assertNotNull("CNG returned null", enumCng);
+ assertNotNull("LPG returned null", enumLpg);
+ assertNotNull("HYDROGEN returned null", enumHydrogen);
+ assertNotNull("BATTERY returned null", enumBattery);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum () {
+ String example = "gASOLINE";
+ try {
+ FuelType temp = FuelType.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum () {
+ String example = null;
+ try {
+ FuelType temp = FuelType.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of FuelType.
+ */
+ public void testListEnum() {
+ List<FuelType> enumValueList = Arrays.asList(FuelType.values());
+
+ List<FuelType> enumTestList = new ArrayList<FuelType>();
+ enumTestList.add(FuelType.GASOLINE);
+ enumTestList.add(FuelType.DIESEL);
+ enumTestList.add(FuelType.CNG);
+ enumTestList.add(FuelType.LPG);
+ enumTestList.add(FuelType.HYDROGEN);
+ enumTestList.add(FuelType.BATTERY);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ImageFieldNameTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ImageFieldNameTests.java
index 13937cd89..aa2c1cbf1 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ImageFieldNameTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ImageFieldNameTests.java
@@ -42,6 +42,8 @@ public class ImageFieldNameTests extends TestCase {
ImageFieldName enumShowConstantTbtNextTurnIcon = ImageFieldName.valueForString(example);
example = "locationImage";
ImageFieldName enumLocationImage = ImageFieldName.valueForString(example);
+ example = "secondaryGraphic";
+ ImageFieldName enumSecondaryGraphic = ImageFieldName.valueForString(example);
assertNotNull("softButtonImage returned null", enumSoftButtonImage);
assertNotNull("choiceImage returned null", enumChoiceImage);
@@ -55,6 +57,7 @@ public class ImageFieldNameTests extends TestCase {
assertNotNull("showConstantTBTIcon returned null", enumShowConstantTbtIcon);
assertNotNull("showConstantTBTNextTurnIcon returned null", enumShowConstantTbtNextTurnIcon);
assertNotNull("location image returned null", enumLocationImage);
+ assertNotNull("secondary graphic returned null", enumSecondaryGraphic);
}
/**
@@ -104,6 +107,7 @@ public class ImageFieldNameTests extends TestCase {
enumTestList.add(ImageFieldName.showConstantTBTIcon);
enumTestList.add(ImageFieldName.showConstantTBTNextTurnIcon);
enumTestList.add(ImageFieldName.locationImage);
+ enumTestList.add(ImageFieldName.secondaryGraphic);
assertTrue("Enum value list does not match enum class list",
enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/LightNameTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/LightNameTests.java
new file mode 100644
index 000000000..10df1e762
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/LightNameTests.java
@@ -0,0 +1,261 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.LightName;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.enums.LightName}
+ */
+public class LightNameTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums() {
+ String example = "FRONT_LEFT_HIGH_BEAM";
+ LightName enumFrontLeftHighBeam = LightName.valueForString(example);
+ example = "FRONT_RIGHT_HIGH_BEAM";
+ LightName enumFrontRightHighBeam = LightName.valueForString(example);
+ example = "FRONT_LEFT_LOW_BEAM";
+ LightName enumFrontLeftLowBeam = LightName.valueForString(example);
+ example = "FRONT_RIGHT_LOW_BEAM";
+ LightName enumFrontRightLowBeam = LightName.valueForString(example);
+ example = "FRONT_LEFT_PARKING_LIGHT";
+ LightName enumFrontLeftParkingLight = LightName.valueForString(example);
+ example = "FRONT_RIGHT_PARKING_LIGHT";
+ LightName enumFrontRightParkingLight = LightName.valueForString(example);
+ example = "FRONT_LEFT_FOG_LIGHT";
+ LightName enumFrontLeftFogLight = LightName.valueForString(example);
+ example = "FRONT_RIGHT_FOG_LIGHT";
+ LightName enumFrontRightFogLight = LightName.valueForString(example);
+ example = "FRONT_LEFT_DAYTIME_RUNNING_LIGHT";
+ LightName enumFrontLeftDaytimeRunningLight = LightName.valueForString(example);
+ example = "FRONT_RIGHT_DAYTIME_RUNNING_LIGHT";
+ LightName enumFrontRightDaytimeRunningLight = LightName.valueForString(example);
+ example = "FRONT_LEFT_TURN_LIGHT";
+ LightName enumFrontLeftTurnLight = LightName.valueForString(example);
+ example = "FRONT_RIGHT_TURN_LIGHT";
+ LightName enumFrontRightTurnLight = LightName.valueForString(example);
+ example = "REAR_LEFT_FOG_LIGHT";
+ LightName enumRearLeftFogLight = LightName.valueForString(example);
+ example = "REAR_RIGHT_FOG_LIGHT";
+ LightName enumRearRightFogLight = LightName.valueForString(example);
+ example = "REAR_LEFT_TAIL_LIGHT";
+ LightName enumRearLeftTailLight = LightName.valueForString(example);
+ example = "REAR_RIGHT_TAIL_LIGHT";
+ LightName enumRearRightTailLight = LightName.valueForString(example);
+ example = "REAR_LEFT_BRAKE_LIGHT";
+ LightName enumRearLeftBrakeLight = LightName.valueForString(example);
+ example = "REAR_RIGHT_BRAKE_LIGHT";
+ LightName enumRearRightBrakeLight = LightName.valueForString(example);
+ example = "REAR_LEFT_TURN_LIGHT";
+ LightName enumRearLeftTurnLight = LightName.valueForString(example);
+ example = "REAR_RIGHT_TURN_LIGHT";
+ LightName enumRearRightTurnLight = LightName.valueForString(example);
+ example = "REAR_REGISTRATION_PLATE_LIGHT";
+ LightName enumRearRegistrationPlateLight = LightName.valueForString(example);
+ example = "HIGH_BEAMS";
+ LightName enumHighBeams = LightName.valueForString(example);
+ example = "LOW_BEAMS";
+ LightName enumLowBeams = LightName.valueForString(example);
+ example = "FOG_LIGHTS";
+ LightName enumFogLights = LightName.valueForString(example);
+ example = "RUNNING_LIGHTS";
+ LightName enumRunningLights = LightName.valueForString(example);
+ example = "PARKING_LIGHTS";
+ LightName enumParkingLights = LightName.valueForString(example);
+ example = "BRAKE_LIGHTS";
+ LightName enumBrakeLights = LightName.valueForString(example);
+ example = "REAR_REVERSING_LIGHTS";
+ LightName enumRearReversingLights = LightName.valueForString(example);
+ example = "SIDE_MARKER_LIGHTS";
+ LightName enumSideMarkerLights = LightName.valueForString(example);
+ example = "LEFT_TURN_LIGHTS";
+ LightName enumLeftTurnLights = LightName.valueForString(example);
+ example = "RIGHT_TURN_LIGHTS";
+ LightName enumRightTurnLights = LightName.valueForString(example);
+ example = "HAZARD_LIGHTS";
+ LightName enumHazardLights = LightName.valueForString(example);
+
+ example = "REAR_CARGO_LIGHTS";
+ LightName enumRearCargoLights = LightName.valueForString(example);
+ example = "REAR_TRUCK_BED_LIGHTS";
+ LightName enumRearTruckBedLights = LightName.valueForString(example);
+ example = "REAR_TRAILER_LIGHTS";
+ LightName enumRearTrailerLights = LightName.valueForString(example);
+ example = "LEFT_SPOT_LIGHTS";
+ LightName enumLeftSpotLights = LightName.valueForString(example);
+ example = "RIGHT_SPOT_LIGHTS";
+ LightName enumRightSpotLights = LightName.valueForString(example);
+ example = "LEFT_PUDDLE_LIGHTS";
+ LightName enumLeftPuddleLights = LightName.valueForString(example);
+ example = "RIGHT_PUDDLE_LIGHTS";
+ LightName enumRightPuddleLights = LightName.valueForString(example);
+ example = "AMBIENT_LIGHTS";
+ LightName enumAmbientLights = LightName.valueForString(example);
+ example = "OVERHEAD_LIGHTS";
+ LightName enumOverheadLights = LightName.valueForString(example);
+ example = "READING_LIGHTS";
+ LightName enumReadingLights = LightName.valueForString(example);
+ example = "TRUNK_LIGHTS";
+ LightName enumTrunkLights = LightName.valueForString(example);
+ example = "EXTERIOR_FRONT_LIGHTS";
+ LightName enumExteriorFrontLights = LightName.valueForString(example);
+ example = "EXTERIOR_REAR_LIGHTS";
+ LightName enumExteriorRearLights = LightName.valueForString(example);
+ example = "EXTERIOR_LEFT_LIGHTS";
+ LightName enumExteriorLeftLights = LightName.valueForString(example);
+ example = "EXTERIOR_RIGHT_LIGHTS";
+ LightName enumExteriorRightLights = LightName.valueForString(example);
+ example = "EXTERIOR_ALL_LIGHTS";
+ LightName enumExteriorAllLights = LightName.valueForString(example);
+
+ assertNotNull("FRONT_LEFT_HIGH_BEAM returned null", enumFrontLeftHighBeam);
+ assertNotNull("FRONT_RIGHT_HIGH_BEAM returned null", enumFrontRightHighBeam);
+ assertNotNull("FRONT_LEFT_LOW_BEAM returned null", enumFrontLeftLowBeam);
+ assertNotNull("FRONT_RIGHT_LOW_BEAM returned null", enumFrontRightLowBeam);
+ assertNotNull("FRONT_LEFT_PARKING_LIGHT returned null", enumFrontLeftParkingLight);
+ assertNotNull("FRONT_RIGHT_PARKING_LIGHT returned null", enumFrontRightParkingLight);
+ assertNotNull("FRONT_LEFT_FOG_LIGHT returned null", enumFrontLeftFogLight);
+ assertNotNull("FRONT_RIGHT_FOG_LIGHT returned null", enumFrontRightFogLight);
+ assertNotNull("FRONT_LEFT_DAYTIME_RUNNING_LIGHT returned null", enumFrontLeftDaytimeRunningLight);
+ assertNotNull("FRONT_RIGHT_DAYTIME_RUNNING_LIGHT returned null", enumFrontRightDaytimeRunningLight);
+
+ assertNotNull("FRONT_LEFT_TURN_LIGHT returned null", enumFrontLeftTurnLight);
+ assertNotNull("FRONT_RIGHT_TURN_LIGHT returned null", enumFrontRightTurnLight);
+ assertNotNull("REAR_LEFT_FOG_LIGHT returned null", enumRearLeftFogLight);
+ assertNotNull("REAR_RIGHT_FOG_LIGHT returned null", enumRearRightFogLight);
+ assertNotNull("REAR_LEFT_TAIL_LIGHT returned null", enumRearLeftTailLight);
+ assertNotNull("REAR_RIGHT_TAIL_LIGHT returned null", enumRearRightTailLight);
+ assertNotNull("REAR_LEFT_BRAKE_LIGHT returned null", enumRearLeftBrakeLight);
+ assertNotNull("REAR_RIGHT_BRAKE_LIGHT returned null", enumRearRightBrakeLight);
+ assertNotNull("REAR_LEFT_TURN_LIGHT returned null", enumRearLeftTurnLight);
+ assertNotNull("REAR_RIGHT_TURN_LIGHT returned null", enumRearRightTurnLight);
+ assertNotNull("REAR_REGISTRATION_PLATE_LIGHT returned null", enumRearRegistrationPlateLight);
+
+ assertNotNull("HIGH_BEAMS returned null", enumHighBeams);
+ assertNotNull("LOW_BEAMS returned null", enumLowBeams);
+ assertNotNull("FOG_LIGHTS returned null", enumFogLights);
+ assertNotNull("RUNNING_LIGHTS returned null", enumRunningLights);
+ assertNotNull("PARKING_LIGHTS returned null", enumParkingLights);
+ assertNotNull("BRAKE_LIGHTS returned null", enumBrakeLights);
+
+ assertNotNull("REAR_REVERSING_LIGHTS returned null", enumRearReversingLights);
+ assertNotNull("SIDE_MARKER_LIGHTS returned null", enumSideMarkerLights);
+ assertNotNull("LEFT_TURN_LIGHTS returned null", enumLeftTurnLights);
+ assertNotNull("RIGHT_TURN_LIGHTS returned null", enumRightTurnLights);
+ assertNotNull("HAZARD_LIGHTS returned null", enumHazardLights);
+ assertNotNull("REAR_CARGO_LIGHTS returned null", enumRearCargoLights);
+ assertNotNull("REAR_TRUCK_BED_LIGHTS returned null", enumRearTruckBedLights);
+ assertNotNull("REAR_TRAILER_LIGHTS returned null", enumRearTrailerLights);
+ assertNotNull("LEFT_SPOT_LIGHTS returned null", enumLeftSpotLights);
+ assertNotNull("RIGHT_SPOT_LIGHTS returned null", enumRightSpotLights);
+ assertNotNull("LEFT_PUDDLE_LIGHTS returned null", enumLeftPuddleLights);
+ assertNotNull("RIGHT_PUDDLE_LIGHTS returned null", enumRightPuddleLights);
+
+ assertNotNull("AMBIENT_LIGHTS returned null", enumAmbientLights);
+ assertNotNull("OVERHEAD_LIGHTS returned null", enumOverheadLights);
+ assertNotNull("READING_LIGHTS returned null", enumReadingLights);
+ assertNotNull("TRUNK_LIGHTS returned null", enumTrunkLights);
+
+ assertNotNull("EXTERIOR_FRONT_LIGHTS returned null", enumExteriorFrontLights);
+ assertNotNull("EXTERIOR_REAR_LIGHTS returned null", enumExteriorRearLights);
+ assertNotNull("EXTERIOR_LEFT_LIGHTS returned null", enumExteriorLeftLights);
+ assertNotNull("EXTERIOR_RIGHT_LIGHTS returned null", enumExteriorRightLights);
+
+ assertNotNull("EXTERIOR_ALL_LIGHTS returned null", enumExteriorAllLights);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum() {
+ String example = "fRONT_LEFT_HIGH_BEAM";
+ try {
+ LightName temp = LightName.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum() {
+ String example = null;
+ try {
+ LightName temp = LightName.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of LightName.
+ */
+ public void testListEnum() {
+ List<LightName> enumValueList = Arrays.asList(LightName.values());
+
+ List<LightName> enumTestList = new ArrayList<LightName>();
+ enumTestList.add(LightName.FRONT_LEFT_HIGH_BEAM);
+ enumTestList.add(LightName.FRONT_RIGHT_HIGH_BEAM);
+ enumTestList.add(LightName.FRONT_LEFT_LOW_BEAM);
+ enumTestList.add(LightName.FRONT_RIGHT_LOW_BEAM);
+ enumTestList.add(LightName.FRONT_LEFT_PARKING_LIGHT);
+ enumTestList.add(LightName.FRONT_RIGHT_PARKING_LIGHT);
+ enumTestList.add(LightName.FRONT_LEFT_FOG_LIGHT);
+ enumTestList.add(LightName.FRONT_RIGHT_FOG_LIGHT);
+ enumTestList.add(LightName.FRONT_LEFT_DAYTIME_RUNNING_LIGHT);
+ enumTestList.add(LightName.FRONT_RIGHT_DAYTIME_RUNNING_LIGHT);
+ enumTestList.add(LightName.FRONT_LEFT_TURN_LIGHT);
+ enumTestList.add(LightName.FRONT_RIGHT_TURN_LIGHT);
+ enumTestList.add(LightName.REAR_LEFT_FOG_LIGHT);
+ enumTestList.add(LightName.REAR_RIGHT_FOG_LIGHT);
+ enumTestList.add(LightName.REAR_LEFT_TAIL_LIGHT);
+ enumTestList.add(LightName.REAR_RIGHT_TAIL_LIGHT);
+ enumTestList.add(LightName.REAR_LEFT_BRAKE_LIGHT);
+ enumTestList.add(LightName.REAR_RIGHT_BRAKE_LIGHT);
+ enumTestList.add(LightName.REAR_LEFT_TURN_LIGHT);
+ enumTestList.add(LightName.REAR_RIGHT_TURN_LIGHT);
+ enumTestList.add(LightName.REAR_REGISTRATION_PLATE_LIGHT);
+ enumTestList.add(LightName.HIGH_BEAMS);
+ enumTestList.add(LightName.LOW_BEAMS);
+ enumTestList.add(LightName.FOG_LIGHTS);
+ enumTestList.add(LightName.RUNNING_LIGHTS);
+ enumTestList.add(LightName.PARKING_LIGHTS);
+ enumTestList.add(LightName.BRAKE_LIGHTS);
+ enumTestList.add(LightName.REAR_REVERSING_LIGHTS);
+ enumTestList.add(LightName.SIDE_MARKER_LIGHTS);
+ enumTestList.add(LightName.LEFT_TURN_LIGHTS);
+ enumTestList.add(LightName.RIGHT_TURN_LIGHTS);
+ enumTestList.add(LightName.HAZARD_LIGHTS);
+ enumTestList.add(LightName.REAR_CARGO_LIGHTS);
+ enumTestList.add(LightName.REAR_TRUCK_BED_LIGHTS);
+ enumTestList.add(LightName.REAR_TRAILER_LIGHTS);
+ enumTestList.add(LightName.LEFT_SPOT_LIGHTS);
+ enumTestList.add(LightName.RIGHT_SPOT_LIGHTS);
+ enumTestList.add(LightName.LEFT_PUDDLE_LIGHTS);
+ enumTestList.add(LightName.RIGHT_PUDDLE_LIGHTS);
+ enumTestList.add(LightName.AMBIENT_LIGHTS);
+ enumTestList.add(LightName.OVERHEAD_LIGHTS);
+ enumTestList.add(LightName.READING_LIGHTS);
+ enumTestList.add(LightName.TRUNK_LIGHTS);
+ enumTestList.add(LightName.EXTERIOR_FRONT_LIGHTS);
+ enumTestList.add(LightName.EXTERIOR_REAR_LIGHTS);
+ enumTestList.add(LightName.EXTERIOR_LEFT_LIGHTS);
+ enumTestList.add(LightName.EXTERIOR_RIGHT_LIGHTS);
+ enumTestList.add(LightName.EXTERIOR_ALL_LIGHTS);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/LightStatusTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/LightStatusTests.java
new file mode 100644
index 000000000..a97cd6eba
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/LightStatusTests.java
@@ -0,0 +1,86 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.LightStatus;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.enums.LightStatus}
+ */
+public class LightStatusTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums() {
+ String example = "ON";
+ LightStatus enumOn = LightStatus.valueForString(example);
+ example = "OFF";
+ LightStatus enumOff = LightStatus.valueForString(example);
+ example = "RAMP_UP";
+ LightStatus enumRampUp = LightStatus.valueForString(example);
+ example = "RAMP_DOWN";
+ LightStatus enumRampDown = LightStatus.valueForString(example);
+ example = "UNKNOWN";
+ LightStatus enumUnknown = LightStatus.valueForString(example);
+ example = "INVALID";
+ LightStatus enumInvalid = LightStatus.valueForString(example);
+
+ assertNotNull("ON returned null", enumOn);
+ assertNotNull("OFF returned null", enumOff);
+ assertNotNull("RAMP_UP returned null", enumRampUp);
+ assertNotNull("RAMP_DOWN returned null", enumRampDown);
+ assertNotNull("UNKNOWN returned null", enumUnknown);
+ assertNotNull("INVALID returned null", enumInvalid);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum() {
+ String example = "oN";
+ try {
+ LightStatus temp = LightStatus.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum() {
+ String example = null;
+ try {
+ LightStatus temp = LightStatus.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of LightStatus.
+ */
+ public void testListEnum() {
+ List<LightStatus> enumValueList = Arrays.asList(LightStatus.values());
+
+ List<LightStatus> enumTestList = new ArrayList<LightStatus>();
+ enumTestList.add(LightStatus.ON);
+ enumTestList.add(LightStatus.OFF);
+ enumTestList.add(LightStatus.RAMP_UP);
+ enumTestList.add(LightStatus.RAMP_DOWN);
+ enumTestList.add(LightStatus.UNKNOWN);
+ enumTestList.add(LightStatus.INVALID);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MassageCushionTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MassageCushionTests.java
new file mode 100644
index 000000000..e1f58ffef
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MassageCushionTests.java
@@ -0,0 +1,81 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.MassageCushion;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.enums.MassageCushion}
+ */
+public class MassageCushionTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums() {
+ String example = "TOP_LUMBAR";
+ MassageCushion enumTopLumbar = MassageCushion.valueForString(example);
+ example = "MIDDLE_LUMBAR";
+ MassageCushion enumMiddleLumbar = MassageCushion.valueForString(example);
+ example = "BOTTOM_LUMBAR";
+ MassageCushion enumBottomLumbar = MassageCushion.valueForString(example);
+ example = "BACK_BOLSTERS";
+ MassageCushion enumBackBolsters = MassageCushion.valueForString(example);
+ example = "SEAT_BOLSTERS";
+ MassageCushion enumSeatBolsters = MassageCushion.valueForString(example);
+
+ assertNotNull("TOP_LUMBAR returned null", enumTopLumbar);
+ assertNotNull("MIDDLE_LUMBAR returned null", enumMiddleLumbar);
+ assertNotNull("BOTTOM_LUMBAR returned null", enumBottomLumbar);
+ assertNotNull("BACK_BOLSTERS returned null", enumBackBolsters);
+ assertNotNull("SEAT_BOLSTERS returned null", enumSeatBolsters);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum() {
+ String example = "tOP_LUMBAR";
+ try {
+ MassageCushion temp = MassageCushion.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum() {
+ String example = null;
+ try {
+ MassageCushion temp = MassageCushion.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of MassageCushion.
+ */
+ public void testListEnum() {
+ List<MassageCushion> enumValueList = Arrays.asList(MassageCushion.values());
+
+ List<MassageCushion> enumTestList = new ArrayList<MassageCushion>();
+ enumTestList.add(MassageCushion.TOP_LUMBAR);
+ enumTestList.add(MassageCushion.MIDDLE_LUMBAR);
+ enumTestList.add(MassageCushion.BOTTOM_LUMBAR);
+ enumTestList.add(MassageCushion.BACK_BOLSTERS);
+ enumTestList.add(MassageCushion.SEAT_BOLSTERS);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MassageModeTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MassageModeTests.java
new file mode 100644
index 000000000..55e82ac21
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MassageModeTests.java
@@ -0,0 +1,73 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.MassageMode;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.enums.MassageMode}
+ */
+public class MassageModeTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums() {
+ String example = "OFF";
+ MassageMode enumOff = MassageMode.valueForString(example);
+ example = "LOW";
+ MassageMode enumLow = MassageMode.valueForString(example);
+ example = "HIGH";
+ MassageMode enumHigh = MassageMode.valueForString(example);
+
+ assertNotNull("OFF returned null", enumOff);
+ assertNotNull("LOW returned null", enumLow);
+ assertNotNull("HIGH returned null", enumHigh);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum() {
+ String example = "oFF";
+ try {
+ MassageMode temp = MassageMode.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum() {
+ String example = null;
+ try {
+ MassageMode temp = MassageMode.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of MassageMode.
+ */
+ public void testListEnum() {
+ List<MassageMode> enumValueList = Arrays.asList(MassageMode.values());
+
+ List<MassageMode> enumTestList = new ArrayList<MassageMode>();
+ enumTestList.add(MassageMode.OFF);
+ enumTestList.add(MassageMode.LOW);
+ enumTestList.add(MassageMode.HIGH);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MassageZoneTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MassageZoneTests.java
new file mode 100644
index 000000000..bbd543d4e
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MassageZoneTests.java
@@ -0,0 +1,69 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.MassageZone;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.enums.MassageZone}
+ */
+public class MassageZoneTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums() {
+ String example = "LUMBAR";
+ MassageZone enumLumbar = MassageZone.valueForString(example);
+ example = "SEAT_CUSHION";
+ MassageZone enumSeatCushion = MassageZone.valueForString(example);
+
+ assertNotNull("LUMBAR returned null", enumLumbar);
+ assertNotNull("SEAT_CUSHION returned null", enumSeatCushion);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum() {
+ String example = "lUMBAR";
+ try {
+ MassageZone temp = MassageZone.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum() {
+ String example = null;
+ try {
+ MassageZone temp = MassageZone.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of MassageZone.
+ */
+ public void testListEnum() {
+ List<MassageZone> enumValueList = Arrays.asList(MassageZone.values());
+
+ List<MassageZone> enumTestList = new ArrayList<MassageZone>();
+ enumTestList.add(MassageZone.LUMBAR);
+ enumTestList.add(MassageZone.SEAT_CUSHION);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MetadataTypeTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MetadataTypeTests.java
index c1aff1bdd..c381dfff3 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MetadataTypeTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/MetadataTypeTests.java
@@ -14,12 +14,12 @@ import java.util.List;
* {@link com.smartdevicelink.proxy.rpc.MetadataTags}
*/
-public class MetadataTypeTests extends TestCase{
+public class MetadataTypeTests extends TestCase {
/**
* Verifies that the enum values are not null upon valid assignment.
*/
- public void testValidEnums () {
+ public void testValidEnums() {
String example = "mediaTitle";
MetadataType enumMediaTitle = MetadataType.valueForString(example);
example = "mediaArtist";
@@ -63,13 +63,12 @@ public class MetadataTypeTests extends TestCase{
/**
* Verifies that an invalid assignment is null.
*/
- public void testInvalidEnum () {
+ public void testInvalidEnum() {
String example = "MEDIA_TITLEZ";
try {
MetadataType temp = MetadataType.valueForString(example);
assertNull("Result of valueForString should be null.", temp);
- }
- catch (IllegalArgumentException exception) {
+ } catch (IllegalArgumentException exception) {
fail("Invalid enum throws IllegalArgumentException.");
}
}
@@ -77,13 +76,12 @@ public class MetadataTypeTests extends TestCase{
/**
* Verifies that a null assignment is invalid.
*/
- public void testNullEnum () {
+ public void testNullEnum() {
String example = null;
try {
MetadataType temp = MetadataType.valueForString(example);
assertNull("Result of valueForString should be null.", temp);
- }
- catch (NullPointerException exception) {
+ } catch (NullPointerException exception) {
fail("Null string throws NullPointerException.");
}
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ModuleTypeTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ModuleTypeTests.java
index 18a47b79d..65432873e 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ModuleTypeTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ModuleTypeTests.java
@@ -9,7 +9,7 @@ import java.util.Arrays;
import java.util.List;
/**
- * This is a unit test class for the SmartDeviceLink library project class :
+ * This is a unit test class for the SmartDeviceLink library project class :
* {@link com.smartdevicelink.rpc.enums.ModuleType}
*/
public class ModuleTypeTests extends TestCase {
@@ -17,41 +17,51 @@ public class ModuleTypeTests extends TestCase {
/**
* Verifies that the enum values are not null upon valid assignment.
*/
- public void testValidEnums () {
+ public void testValidEnums() {
String example = "CLIMATE";
ModuleType enumClimate = ModuleType.valueForString(example);
example = "RADIO";
ModuleType enumRadio = ModuleType.valueForString(example);
+ example = "SEAT";
+ ModuleType enumSeat = ModuleType.valueForString(example);
+ example = "AUDIO";
+ ModuleType enumAudio = ModuleType.valueForString(example);
+ example = "LIGHT";
+ ModuleType enumLight = ModuleType.valueForString(example);
+ example = "HMI_SETTINGS";
+ ModuleType enumHmiSettings = ModuleType.valueForString(example);
assertNotNull("CLIMATE returned null", enumClimate);
assertNotNull("RADIO returned null", enumRadio);
+ assertNotNull("SEAT returned null", enumSeat);
+ assertNotNull("AUDIO returned null", enumAudio);
+ assertNotNull("LIGHT returned null", enumLight);
+ assertNotNull("HMI_SETTINGS returned null", enumHmiSettings);
}
/**
* Verifies that an invalid assignment is null.
*/
- public void testInvalidEnum () {
+ public void testInvalidEnum() {
String example = "cLIMATE";
try {
ModuleType temp = ModuleType.valueForString(example);
- assertNull("Result of valueForString should be null.", temp);
- }
- catch (IllegalArgumentException exception) {
- fail("Invalid enum throws IllegalArgumentException.");
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
}
}
/**
* Verifies that a null assignment is invalid.
*/
- public void testNullEnum () {
+ public void testNullEnum() {
String example = null;
try {
ModuleType temp = ModuleType.valueForString(example);
- assertNull("Result of valueForString should be null.", temp);
- }
- catch (NullPointerException exception) {
- fail("Null string throws NullPointerException.");
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
}
}
@@ -59,13 +69,17 @@ public class ModuleTypeTests extends TestCase {
* Verifies the possible enum values of ModuleType.
*/
public void testListEnum() {
- List<ModuleType> enumValueList = Arrays.asList(ModuleType.values());
+ List<ModuleType> enumValueList = Arrays.asList(ModuleType.values());
List<ModuleType> enumTestList = new ArrayList<ModuleType>();
enumTestList.add(ModuleType.CLIMATE);
enumTestList.add(ModuleType.RADIO);
+ enumTestList.add(ModuleType.SEAT);
+ enumTestList.add(ModuleType.AUDIO);
+ enumTestList.add(ModuleType.LIGHT);
+ enumTestList.add(ModuleType.HMI_SETTINGS);
- assertTrue("Enum value list does not match enum class list",
+ assertTrue("Enum value list does not match enum class list",
enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
- }
+ }
} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/PredefinedLayoutTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/PredefinedLayoutTests.java
new file mode 100644
index 000000000..26b32d08b
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/PredefinedLayoutTests.java
@@ -0,0 +1,144 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.PredefinedLayout;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.proxy.rpc.enums.PredefinedLayout}
+ */
+public class PredefinedLayoutTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums () {
+ String example = "DEFAULT";
+ PredefinedLayout defaultenum = PredefinedLayout.valueForString(example);
+ example = "MEDIA";
+ PredefinedLayout media = PredefinedLayout.valueForString(example);
+ example = "NON-MEDIA";
+ PredefinedLayout nonmedia = PredefinedLayout.valueForString(example);
+ example = "ONSCREEN_PRESETS";
+ PredefinedLayout onscreen_presets = PredefinedLayout.valueForString(example);
+ example = "NAV_FULLSCREEN_MAP";
+ PredefinedLayout nav_fullscreen_map = PredefinedLayout.valueForString(example);
+ example = "NAV_LIST";
+ PredefinedLayout nav_list = PredefinedLayout.valueForString(example);
+ example = "NAV_KEYBOARD";
+ PredefinedLayout nav_keyboard = PredefinedLayout.valueForString(example);
+ example = "GRAPHIC_WITH_TEXT";
+ PredefinedLayout graphic_with_text = PredefinedLayout.valueForString(example);
+ example = "TEXT_WITH_GRAPHIC";
+ PredefinedLayout text_with_graphic = PredefinedLayout.valueForString(example);
+ example = "TILES_ONLY";
+ PredefinedLayout tiles_only = PredefinedLayout.valueForString(example);
+ example = "TEXTBUTTONS_ONLY";
+ PredefinedLayout textbuttons_only = PredefinedLayout.valueForString(example);
+ example = "GRAPHIC_WITH_TILES";
+ PredefinedLayout graphic_with_tiles = PredefinedLayout.valueForString(example);
+ example = "TILES_WITH_GRAPHIC";
+ PredefinedLayout tiles_with_graphic = PredefinedLayout.valueForString(example);
+ example = "GRAPHIC_WITH_TEXT_AND_SOFTBUTTONS";
+ PredefinedLayout graphic_with_text_and_softbuttons = PredefinedLayout.valueForString(example);
+ example = "TEXT_AND_SOFTBUTTONS_WITH_GRAPHIC";
+ PredefinedLayout text_and_softbuttons_with_graphics = PredefinedLayout.valueForString(example);
+ example = "GRAPHIC_WITH_TEXTBUTTONS";
+ PredefinedLayout graphic_with_textbuttons = PredefinedLayout.valueForString(example);
+ example = "TEXTBUTTONS_WITH_GRAPHIC";
+ PredefinedLayout textbuttons_with_graphic = PredefinedLayout.valueForString(example);
+ example = "LARGE_GRAPHIC_WITH_SOFTBUTTONS";
+ PredefinedLayout large_graphic_with_softbuttons = PredefinedLayout.valueForString(example);
+ example = "DOUBLE_GRAPHIC_WITH_SOFTBUTTONS";
+ PredefinedLayout double_graphic_with_softbuttons = PredefinedLayout.valueForString(example);
+ example = "LARGE_GRAPHIC_ONLY";
+ PredefinedLayout large_graphic_only = PredefinedLayout.valueForString(example);
+
+ assertNotNull("DEFAULT returned null", defaultenum);
+ assertNotNull("MEDIA returned null", media);
+ assertNotNull("NON-MEDIA returned null", nonmedia);
+ assertNotNull("ONSCREEN_PRESETS returned null", onscreen_presets);
+ assertNotNull("NAV_FULLSCREEN_MAP returned null", nav_fullscreen_map);
+ assertNotNull("NAV_LIST returned null", nav_list);
+ assertNotNull("NAV_KEYBOARD returned null", nav_keyboard);
+ assertNotNull("GRAPHIC_WITH_TEXT returned null", graphic_with_text);
+ assertNotNull("TEXT_WITH_GRAPHIC returned null", text_with_graphic);
+ assertNotNull("TILES_ONLY returned null", tiles_only);
+ assertNotNull("TEXTBUTTONS_ONLY returned null", textbuttons_only);
+ assertNotNull("GRAPHIC_WITH_TILES returned null", graphic_with_tiles);
+ assertNotNull("TILES_WITH_GRAPHIC returned null", tiles_with_graphic);
+ assertNotNull("GRAPHIC_WITH_TEXT_AND_SOFTBUTTONS returned null", graphic_with_text_and_softbuttons);
+ assertNotNull("TEXT_AND_SOFTBUTTONS_WITH_GRAPHIC returned null", text_and_softbuttons_with_graphics);
+ assertNotNull("GRAPHIC_WITH_TEXTBUTTONS returned null", graphic_with_textbuttons);
+ assertNotNull("TEXTBUTTONS_WITH_GRAPHIC returned null", textbuttons_with_graphic);
+ assertNotNull("LARGE_GRAPHIC_WITH_SOFTBUTTONS returned null", large_graphic_with_softbuttons);
+ assertNotNull("DOUBLE_GRAPHIC_WITH_SOFTBUTTONS returned null", double_graphic_with_softbuttons);
+ assertNotNull("LARGE_GRAPHIC_ONLY returned null", large_graphic_only);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum () {
+ String example = "LARGE_GRApHIC_ONLY";
+ try {
+ PredefinedLayout temp = PredefinedLayout.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum () {
+ String example = null;
+ try {
+ PredefinedLayout temp = PredefinedLayout.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of PredefinedLayout.
+ */
+ public void testListEnum() {
+ List<PredefinedLayout> enumValueList = Arrays.asList(PredefinedLayout.values());
+
+ List<PredefinedLayout> enumTestList = new ArrayList<>();
+
+ enumTestList.add(PredefinedLayout.DEFAULT);
+ enumTestList.add(PredefinedLayout.MEDIA);
+ enumTestList.add(PredefinedLayout.NON_MEDIA);
+ enumTestList.add(PredefinedLayout.ONSCREEN_PRESETS);
+ enumTestList.add(PredefinedLayout.NAV_FULLSCREEN_MAP);
+ enumTestList.add(PredefinedLayout.NAV_LIST);
+ enumTestList.add(PredefinedLayout.NAV_KEYBOARD);
+ enumTestList.add(PredefinedLayout.GRAPHIC_WITH_TEXT);
+ enumTestList.add(PredefinedLayout.TEXT_WITH_GRAPHIC);
+ enumTestList.add(PredefinedLayout.TILES_ONLY);
+ enumTestList.add(PredefinedLayout.TEXTBUTTONS_ONLY);
+ enumTestList.add(PredefinedLayout.GRAPHIC_WITH_TILES);
+ enumTestList.add(PredefinedLayout.TILES_WITH_GRAPHIC);
+ enumTestList.add(PredefinedLayout.GRAPHIC_WITH_TEXT_AND_SOFTBUTTONS);
+ enumTestList.add(PredefinedLayout.TEXT_AND_SOFTBUTTONS_WITH_GRAPHIC);
+ enumTestList.add(PredefinedLayout.GRAPHIC_WITH_TEXTBUTTONS);
+ enumTestList.add(PredefinedLayout.TEXTBUTTONS_WITH_GRAPHIC);
+ enumTestList.add(PredefinedLayout.LARGE_GRAPHIC_WITH_SOFTBUTTONS);
+ enumTestList.add(PredefinedLayout.DOUBLE_GRAPHIC_WITH_SOFTBUTTONS);
+ enumTestList.add(PredefinedLayout.LARGE_GRAPHIC_ONLY);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/PrimaryAudioSourceTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/PrimaryAudioSourceTests.java
index 94c2e2b39..b3432985d 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/PrimaryAudioSourceTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/PrimaryAudioSourceTests.java
@@ -1,16 +1,16 @@
package com.smartdevicelink.test.rpc.enums;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+import com.smartdevicelink.proxy.rpc.enums.PrimaryAudioSource;
import junit.framework.TestCase;
-import com.smartdevicelink.proxy.rpc.enums.PrimaryAudioSource;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
/**
- * This is a unit test class for the SmartDeviceLink library project class :
+ * This is a unit test class for the SmartDeviceLink library project class :
* {@link com.smartdevicelink.rpc.enums.PrimaryAudioSource}
*/
public class PrimaryAudioSourceTests extends TestCase {
@@ -18,7 +18,7 @@ public class PrimaryAudioSourceTests extends TestCase {
/**
* Verifies that the enum values are not null upon valid assignment.
*/
- public void testValidEnums () {
+ public void testValidEnums() {
String example = "NO_SOURCE_SELECTED";
PrimaryAudioSource enumNoSourceSelected = PrimaryAudioSource.valueForString(example);
example = "USB";
@@ -33,7 +33,17 @@ public class PrimaryAudioSourceTests extends TestCase {
PrimaryAudioSource enumIpod = PrimaryAudioSource.valueForString(example);
example = "MOBILE_APP";
PrimaryAudioSource enumMobileApp = PrimaryAudioSource.valueForString(example);
-
+ example = "CD";
+ PrimaryAudioSource enumCd = PrimaryAudioSource.valueForString(example);
+ example = "AM";
+ PrimaryAudioSource enumAm = PrimaryAudioSource.valueForString(example);
+ example = "FM";
+ PrimaryAudioSource enumFm = PrimaryAudioSource.valueForString(example);
+ example = "XM";
+ PrimaryAudioSource enumXm = PrimaryAudioSource.valueForString(example);
+ example = "DAB";
+ PrimaryAudioSource enumDab = PrimaryAudioSource.valueForString(example);
+
assertNotNull("NO_SOURCE_SELECTED returned null", enumNoSourceSelected);
assertNotNull("USB returned null", enumUsb);
assertNotNull("USB2 returned null", enumUsb2);
@@ -41,42 +51,45 @@ public class PrimaryAudioSourceTests extends TestCase {
assertNotNull("LINE_IN returned null", enumLineIn);
assertNotNull("IPOD returned null", enumIpod);
assertNotNull("MOBILE_APP returned null", enumMobileApp);
+ assertNotNull("CD returned null", enumCd);
+ assertNotNull("AM returned null", enumAm);
+ assertNotNull("FM returned null", enumFm);
+ assertNotNull("XM returned null", enumXm);
+ assertNotNull("DAB returned null", enumDab);
}
/**
* Verifies that an invalid assignment is null.
*/
- public void testInvalidEnum () {
+ public void testInvalidEnum() {
String example = "no_SouRCe_SelEcteD";
try {
- PrimaryAudioSource temp = PrimaryAudioSource.valueForString(example);
- assertNull("Result of valueForString should be null.", temp);
- }
- catch (IllegalArgumentException exception) {
- fail("Invalid enum throws IllegalArgumentException.");
+ PrimaryAudioSource temp = PrimaryAudioSource.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
}
}
/**
* Verifies that a null assignment is invalid.
*/
- public void testNullEnum () {
+ public void testNullEnum() {
String example = null;
try {
- PrimaryAudioSource temp = PrimaryAudioSource.valueForString(example);
- assertNull("Result of valueForString should be null.", temp);
- }
- catch (NullPointerException exception) {
- fail("Null string throws NullPointerException.");
+ PrimaryAudioSource temp = PrimaryAudioSource.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
}
- }
-
+ }
+
/**
* Verifies the possible enum values of PrimaryAudioSource.
*/
public void testListEnum() {
- List<PrimaryAudioSource> enumValueList = Arrays.asList(PrimaryAudioSource.values());
+ List<PrimaryAudioSource> enumValueList = Arrays.asList(PrimaryAudioSource.values());
List<PrimaryAudioSource> enumTestList = new ArrayList<PrimaryAudioSource>();
enumTestList.add(PrimaryAudioSource.NO_SOURCE_SELECTED);
@@ -84,10 +97,15 @@ public class PrimaryAudioSourceTests extends TestCase {
enumTestList.add(PrimaryAudioSource.USB2);
enumTestList.add(PrimaryAudioSource.BLUETOOTH_STEREO_BTST);
enumTestList.add(PrimaryAudioSource.LINE_IN);
- enumTestList.add(PrimaryAudioSource.IPOD);
+ enumTestList.add(PrimaryAudioSource.IPOD);
enumTestList.add(PrimaryAudioSource.MOBILE_APP);
+ enumTestList.add(PrimaryAudioSource.CD);
+ enumTestList.add(PrimaryAudioSource.AM);
+ enumTestList.add(PrimaryAudioSource.FM);
+ enumTestList.add(PrimaryAudioSource.XM);
+ enumTestList.add(PrimaryAudioSource.DAB);
- assertTrue("Enum value list does not match enum class list",
+ assertTrue("Enum value list does not match enum class list",
enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
- }
+ }
} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/RequestTypeTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/RequestTypeTests.java
index ea50b11b1..4ae23815f 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/RequestTypeTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/RequestTypeTests.java
@@ -138,8 +138,9 @@ public class RequestTypeTests extends TestCase {
enumTestList.add(RequestType.SETTINGS);
enumTestList.add(RequestType.VEHICLE_DIAGNOSTICS);
enumTestList.add(RequestType.EMERGENCY);
- enumTestList.add(RequestType.MEDIA);
- enumTestList.add(RequestType.FOTA);
+ enumTestList.add(RequestType.MEDIA);
+ enumTestList.add(RequestType.FOTA);
+ enumTestList.add(RequestType.OEM_SPECIFIC);
assertTrue("Enum value list does not match enum class list",
enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ResultTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ResultTests.java
index 5156c4f44..4cea3acbe 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ResultTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/ResultTests.java
@@ -10,14 +10,14 @@ import com.smartdevicelink.proxy.rpc.enums.Result;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.enums.Result}
+ * {@link com.smartdevicelink.proxy.rpc.enums.Result}
*/
public class ResultTests extends TestCase {
/**
* Verifies that the enum values are not null upon valid assignment.
*/
- public void testValidEnums () {
+ public void testValidEnums () {
String example = "SUCCESS";
Result enumSuccess = Result.valueForString(example);
example = "INVALID_DATA";
@@ -86,6 +86,8 @@ public class ResultTests extends TestCase {
Result enumDataNotAvailable = Result.valueForString(example);
example = "READ_ONLY";
Result enumReadOnly = Result.valueForString(example);
+ example = "CORRUPTED_DATA";
+ Result enumCorruptData = Result.valueForString(example);
assertNotNull("SUCCESS returned null", enumSuccess);
assertNotNull("INVALID_DATA returned null", enumInvalidData);
@@ -121,6 +123,7 @@ public class ResultTests extends TestCase {
assertNotNull("RESUME_FAILED returned null", enumResumeFailed);
assertNotNull("DATA_NOT_AVAILABLE returned null", enumDataNotAvailable);
assertNotNull("READ_ONLY returned null", enumReadOnly);
+ assertNotNull("CORRUPTED_DATA", enumCorruptData);
}
/**
@@ -192,6 +195,7 @@ public class ResultTests extends TestCase {
enumTestList.add(Result.RESUME_FAILED);
enumTestList.add(Result.DATA_NOT_AVAILABLE);
enumTestList.add(Result.READ_ONLY);
+ enumTestList.add(Result.CORRUPTED_DATA);
assertTrue("Enum value list does not match enum class list",
enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SdlDisconnectedReasonTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SdlDisconnectedReasonTests.java
index a96988af7..1b32c9544 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SdlDisconnectedReasonTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SdlDisconnectedReasonTests.java
@@ -146,6 +146,7 @@ public class SdlDisconnectedReasonTests extends TestCase {
enumTestList.add(SdlDisconnectedReason.GENERIC_ERROR);
enumTestList.add(SdlDisconnectedReason.LEGACY_BLUETOOTH_MODE_ENABLED);
enumTestList.add(SdlDisconnectedReason.RPC_SESSION_ENDED);
+ enumTestList.add(SdlDisconnectedReason.PRIMARY_TRANSPORT_CYCLE_REQUEST);
assertTrue("Enum value list does not match enum class list",
enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
@@ -153,7 +154,7 @@ public class SdlDisconnectedReasonTests extends TestCase {
/**
* Verifies the valid returns of the conversion method,
- * {@link com.smartdevicelink.rpc.enums.SdlDisconnectedReason#convertAppInterfaceunregisteredReason(AppInterfaceUnregisteredReason)}
+ * {@link com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason#convertAppInterfaceunregisteredReason(AppInterfaceUnregisteredReason)}
*/
public void testConvertMethod () {
assertEquals(Test.MATCH, SdlDisconnectedReason.DEFAULT, SdlDisconnectedReason.convertAppInterfaceUnregisteredReason(AppInterfaceUnregisteredReason.APP_UNAUTHORIZED));
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SeatMemoryActionTypeTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SeatMemoryActionTypeTests.java
new file mode 100644
index 000000000..2642e35d3
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SeatMemoryActionTypeTests.java
@@ -0,0 +1,73 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.SeatMemoryActionType;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.enums.SeatMemoryActionType}
+ */
+public class SeatMemoryActionTypeTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums() {
+ String example = "SAVE";
+ SeatMemoryActionType enumSave = SeatMemoryActionType.valueForString(example);
+ example = "RESTORE";
+ SeatMemoryActionType enumRestore = SeatMemoryActionType.valueForString(example);
+ example = "NONE";
+ SeatMemoryActionType enumNone = SeatMemoryActionType.valueForString(example);
+
+ assertNotNull("SAVE returned null", enumSave);
+ assertNotNull("RESTORE returned null", enumRestore);
+ assertNotNull("NONE returned null", enumNone);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum() {
+ String example = "sAVE";
+ try {
+ SeatMemoryActionType temp = SeatMemoryActionType.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum() {
+ String example = null;
+ try {
+ SeatMemoryActionType temp = SeatMemoryActionType.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of SeatMemoryActionType.
+ */
+ public void testListEnum() {
+ List<SeatMemoryActionType> enumValueList = Arrays.asList(SeatMemoryActionType.values());
+
+ List<SeatMemoryActionType> enumTestList = new ArrayList<SeatMemoryActionType>();
+ enumTestList.add(SeatMemoryActionType.SAVE);
+ enumTestList.add(SeatMemoryActionType.RESTORE);
+ enumTestList.add(SeatMemoryActionType.NONE);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SpeechCapabilitiesTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SpeechCapabilitiesTests.java
index 2ed1b4a77..364f7c896 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SpeechCapabilitiesTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SpeechCapabilitiesTests.java
@@ -76,6 +76,7 @@ public class SpeechCapabilitiesTests extends TestCase {
enumTestList.add(SpeechCapabilities.LHPLUS_PHONEMES);
enumTestList.add(SpeechCapabilities.PRE_RECORDED);
enumTestList.add(SpeechCapabilities.SILENCE);
+ enumTestList.add(SpeechCapabilities.FILE);
assertTrue("Enum value list does not match enum class list",
enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/StaticIconNameTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/StaticIconNameTests.java
new file mode 100644
index 000000000..b85905039
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/StaticIconNameTests.java
@@ -0,0 +1,931 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.StaticIconName;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.proxy.rpc.enums.StaticIconName}
+ */
+public class StaticIconNameTests extends TestCase {
+
+ public void testValidEnums(){
+ String example = "0x29";
+ StaticIconName ACCEPT_CALL = StaticIconName.valueForString(example);
+ assertNotNull("ACCEPT_CALL returned null", ACCEPT_CALL);
+
+ example = "0x1B";
+ StaticIconName ADD_WAYPOINT = StaticIconName.valueForString(example);
+ assertNotNull("ADD_WAYPOINT returned null", ADD_WAYPOINT);
+
+ example = "0x21";
+ StaticIconName ALBUM = StaticIconName.valueForString(example);
+ assertNotNull("ALBUM returned null", ALBUM);
+
+ example = "0x3d";
+ StaticIconName AMBIENT_LIGHTING = StaticIconName.valueForString(example);
+ assertNotNull("AMBIENT_LIGHTING returned null", AMBIENT_LIGHTING);
+
+ example = "0x40";
+ StaticIconName ARROW_NORTH = StaticIconName.valueForString(example);
+ assertNotNull("ARROW_NORTH returned null", ARROW_NORTH);
+
+ example = "0x12";
+ StaticIconName AUDIO_MUTE = StaticIconName.valueForString(example);
+ assertNotNull("AUDIO_MUTE returned null", AUDIO_MUTE);
+
+ example = "0x83";
+ StaticIconName AUDIOBOOK_EPISODE = StaticIconName.valueForString(example);
+ assertNotNull("AUDIOBOOK_EPISODE returned null", AUDIOBOOK_EPISODE);
+
+ example = "0x82";
+ StaticIconName AUDIOBOOK_NARRATOR = StaticIconName.valueForString(example);
+ assertNotNull("AUDIOBOOK_NARRATOR returned null", AUDIOBOOK_NARRATOR);
+
+ example = "0x45";
+ StaticIconName AUXILLARY_AUDIO = StaticIconName.valueForString(example);
+ assertNotNull("AUXILLARY_AUDIO returned null", AUXILLARY_AUDIO);
+
+ example = "0x86";
+ StaticIconName BACK = StaticIconName.valueForString(example);
+ assertNotNull("BACK returned null", BACK);
+
+ example = "0xF7";
+ StaticIconName BATTERY_CAPACITY_0_OF_5 = StaticIconName.valueForString(example);
+ assertNotNull("BATTERY_CAPACITY_0_OF_5 returned null", BATTERY_CAPACITY_0_OF_5);
+
+ example = "0xF8";
+ StaticIconName BATTERY_CAPACITY_1_OF_5 = StaticIconName.valueForString(example);
+ assertNotNull("BATTERY_CAPACITY_1_OF_5 returned null", BATTERY_CAPACITY_1_OF_5);
+
+ example = "0xF9";
+ StaticIconName BATTERY_CAPACITY_2_OF_5 = StaticIconName.valueForString(example);
+ assertNotNull("BATTERY_CAPACITY_2_OF_5 returned null", BATTERY_CAPACITY_2_OF_5);
+
+ example = "0xFA";
+ StaticIconName BATTERY_CAPACITY_3_OF_5 = StaticIconName.valueForString(example);
+ assertNotNull("BATTERY_CAPACITY_3_OF_5 returned null", BATTERY_CAPACITY_3_OF_5);
+
+ example = "0xf6";
+ StaticIconName BATTERY_CAPACITY_4_OF_5 = StaticIconName.valueForString(example);
+ assertNotNull("BATTERY_CAPACITY_4_OF_5 returned null", BATTERY_CAPACITY_4_OF_5);
+
+ example = "0xFB";
+ StaticIconName BATTERY_CAPACITY_5_OF_5 = StaticIconName.valueForString(example);
+ assertNotNull("BATTERY_CAPACITY_5_OF_5 returned null", BATTERY_CAPACITY_5_OF_5);
+
+ example = "0x09";
+ StaticIconName BLUETOOTH_AUDIO_SOURCE = StaticIconName.valueForString(example);
+ assertNotNull("BLUETOOTH_AUDIO_SOURCE returned null", BLUETOOTH_AUDIO_SOURCE);
+
+ example = "0xcc";
+ StaticIconName BLUETOOTH1 = StaticIconName.valueForString(example);
+ assertNotNull("BLUETOOTH1 returned null", BLUETOOTH1);
+
+ example = "0xCD";
+ StaticIconName BLUETOOTH2 = StaticIconName.valueForString(example);
+ assertNotNull("BLUETOOTH2 returned null", BLUETOOTH2);
+
+ example = "0x77";
+ StaticIconName BROWSE = StaticIconName.valueForString(example);
+ assertNotNull("BROWSE returned null", BROWSE);
+
+ example = "0x66";
+ StaticIconName CELL_PHONE_IN_ROAMING_MODE = StaticIconName.valueForString(example);
+ assertNotNull("CELL_PHONE_IN_ROAMING_MODE returned null", CELL_PHONE_IN_ROAMING_MODE);
+
+ example = "0x67";
+ StaticIconName CELL_SERVICE_SIGNAL_STRENGTH_0_OF_5_BARS = StaticIconName.valueForString(example);
+ assertNotNull("CELL_SERVICE_SIGNAL_STRENGTH_0_OF_5_BARS returned null", CELL_SERVICE_SIGNAL_STRENGTH_0_OF_5_BARS);
+
+ example = "0x68";
+ StaticIconName CELL_SERVICE_SIGNAL_STRENGTH_1_OF_5_BARS = StaticIconName.valueForString(example);
+ assertNotNull("CELL_SERVICE_SIGNAL_STRENGTH_1_OF_5_BARS returned null", CELL_SERVICE_SIGNAL_STRENGTH_1_OF_5_BARS);
+
+ example = "0x69";
+ StaticIconName CELL_SERVICE_SIGNAL_STRENGTH_2_OF_5_BARS = StaticIconName.valueForString(example);
+ assertNotNull("CELL_SERVICE_SIGNAL_STRENGTH_2_OF_5_BARS returned null", CELL_SERVICE_SIGNAL_STRENGTH_2_OF_5_BARS);
+
+ example = "0x6A";
+ StaticIconName CELL_SERVICE_SIGNAL_STRENGTH_3_OF_5_BARS = StaticIconName.valueForString(example);
+ assertNotNull("CELL_SERVICE_SIGNAL_STRENGTH_3_OF_5_BARS returned null", CELL_SERVICE_SIGNAL_STRENGTH_3_OF_5_BARS);
+
+ example = "0x6B";
+ StaticIconName CELL_SERVICE_SIGNAL_STRENGTH_4_OF_5_BARS = StaticIconName.valueForString(example);
+ assertNotNull("CELL_SERVICE_SIGNAL_STRENGTH_4_OF_5_BARS returned null", CELL_SERVICE_SIGNAL_STRENGTH_4_OF_5_BARS);
+
+ example = "0xd3";
+ StaticIconName CELL_SERVICE_SIGNAL_STRENGTH_5_OF_5_BARS = StaticIconName.valueForString(example);
+ assertNotNull("CELL_SERVICE_SIGNAL_STRENGTH_5_OF_5_BARS returned null", CELL_SERVICE_SIGNAL_STRENGTH_5_OF_5_BARS);
+
+ example = "0xc3";
+ StaticIconName CHANGE_LANE_LEFT = StaticIconName.valueForString(example);
+ assertNotNull("CHANGE_LANE_LEFT returned null", CHANGE_LANE_LEFT);
+
+ example = "0xc1";
+ StaticIconName CHANGE_LANE_RIGHT = StaticIconName.valueForString(example);
+ assertNotNull("CHANGE_LANE_RIGHT returned null", CHANGE_LANE_RIGHT);
+
+ example = "0x27";
+ StaticIconName CHECK_BOX_CHECKED = StaticIconName.valueForString(example);
+ assertNotNull("CHECK_BOX_CHECKED returned null", CHECK_BOX_CHECKED);
+
+ example = "0x28";
+ StaticIconName CHECK_BOX_UNCHECKED = StaticIconName.valueForString(example);
+ assertNotNull("CHECK_BOX_UNCHECKED returned null", CHECK_BOX_UNCHECKED);
+
+ example = "0xd1";
+ StaticIconName CLIMATE = StaticIconName.valueForString(example);
+ assertNotNull("CLIMATE returned null", CLIMATE);
+
+ example = "0xfc";
+ StaticIconName CLOCK = StaticIconName.valueForString(example);
+ assertNotNull("CLOCK returned null", CLOCK);
+
+ example = "0x1A";
+ StaticIconName COMPOSE = StaticIconName.valueForString(example);
+ assertNotNull("COMPOSE returned null", COMPOSE);
+
+ example = "0x5C";
+ StaticIconName CONTACT = StaticIconName.valueForString(example);
+ assertNotNull("CONTACT returned null", CONTACT);
+
+ example = "0x42";
+ StaticIconName CONTINUE = StaticIconName.valueForString(example);
+ assertNotNull("CONTINUE returned null", CONTINUE);
+
+ example = "0x7F";
+ StaticIconName DASH = StaticIconName.valueForString(example);
+ assertNotNull("DASH returned null", DASH);
+
+ example = "0x87";
+ StaticIconName DATE = StaticIconName.valueForString(example);
+ assertNotNull("DATE returned null", DATE);
+
+ example = "0x0F";
+ StaticIconName DELETE = StaticIconName.valueForString(example);
+ assertNotNull("DELETE returned null", DELETE);
+
+ example = "0x94";
+ StaticIconName DESTINATION = StaticIconName.valueForString(example);
+ assertNotNull("DESTINATION returned null", DESTINATION);
+
+ example = "0x4D";
+ StaticIconName DESTINATION_FERRY_AHEAD = StaticIconName.valueForString(example);
+ assertNotNull("DESTINATION_FERRY_AHEAD returned null", DESTINATION_FERRY_AHEAD);
+
+ example = "0x2B";
+ StaticIconName EBOOKMARK = StaticIconName.valueForString(example);
+ assertNotNull("EBOOKMARK returned null", EBOOKMARK);
+
+ example = "0x2C";
+ StaticIconName END_CALL = StaticIconName.valueForString(example);
+ assertNotNull("END_CALL returned null", END_CALL);
+
+ example = "0xD6";
+ StaticIconName FAIL = StaticIconName.valueForString(example);
+ assertNotNull("FAIL returned null", FAIL);
+
+ example = "0x08";
+ StaticIconName FAST_FORWARD_30_SECS = StaticIconName.valueForString(example);
+ assertNotNull("FAST_FORWARD_30_SECS returned null", FAST_FORWARD_30_SECS);
+
+ example = "0x0E";
+ StaticIconName FAVORITE_HEART = StaticIconName.valueForString(example);
+ assertNotNull("FAVORITE_HEART returned null", FAVORITE_HEART);
+
+ example = "0x95";
+ StaticIconName FAVORITE_STAR = StaticIconName.valueForString(example);
+ assertNotNull("FAVORITE_STAR returned null", FAVORITE_STAR);
+
+ example = "0x80";
+ StaticIconName FAX_NUMBER = StaticIconName.valueForString(example);
+ assertNotNull("FAX_NUMBER returned null", FAX_NUMBER);
+
+ example = "0x50";
+ StaticIconName FILENAME = StaticIconName.valueForString(example);
+ assertNotNull("FILENAME returned null", FILENAME);
+
+ example = "0x79";
+ StaticIconName FILTER = StaticIconName.valueForString(example);
+ assertNotNull("FILTER returned null", FILTER);
+
+ example = "0x1C";
+ StaticIconName FOLDER = StaticIconName.valueForString(example);
+ assertNotNull("FOLDER returned null", FOLDER);
+
+ example = "0xe9";
+ StaticIconName FUEL_PRICES = StaticIconName.valueForString(example);
+ assertNotNull("FUEL_PRICES returned null", FUEL_PRICES);
+
+ example = "0x0c";
+ StaticIconName FULL_MAP = StaticIconName.valueForString(example);
+ assertNotNull("FULL_MAP returned null", FULL_MAP);
+
+ example = "0x53";
+ StaticIconName GENERIC_PHONE_NUMBER = StaticIconName.valueForString(example);
+ assertNotNull("GENERIC_PHONE_NUMBER returned null", GENERIC_PHONE_NUMBER);
+
+ example = "0x4E";
+ StaticIconName GENRE = StaticIconName.valueForString(example);
+ assertNotNull("GENRE returned null", GENRE);
+
+ example = "0xea";
+ StaticIconName GLOBAL_KEYBOARD = StaticIconName.valueForString(example);
+ assertNotNull("GLOBAL_KEYBOARD returned null", GLOBAL_KEYBOARD);
+
+ example = "0xf4";
+ StaticIconName HIGHWAY_EXIT_INFORMATION = StaticIconName.valueForString(example);
+ assertNotNull("HIGHWAY_EXIT_INFORMATION returned null", HIGHWAY_EXIT_INFORMATION);
+
+ example = "0x55";
+ StaticIconName HOME_PHONE_NUMBER = StaticIconName.valueForString(example);
+ assertNotNull("HOME_PHONE_NUMBER returned null", HOME_PHONE_NUMBER);
+
+ example = "0x78";
+ StaticIconName HYPERLINK = StaticIconName.valueForString(example);
+ assertNotNull("HYPERLINK returned null", HYPERLINK);
+
+ example = "0x51";
+ StaticIconName ID3_TAG_UNKNOWN = StaticIconName.valueForString(example);
+ assertNotNull("ID3_TAG_UNKNOWN returned null", ID3_TAG_UNKNOWN);
+
+ example = "0x57";
+ StaticIconName INCOMING_CALLS = StaticIconName.valueForString(example);
+ assertNotNull("INCOMING_CALLS returned null", INCOMING_CALLS);
+
+ example = "0x5d";
+ StaticIconName INFORMATION = StaticIconName.valueForString(example);
+ assertNotNull("INFORMATION returned null", INFORMATION);
+
+ example = "0x0D";
+ StaticIconName IPOD_MEDIA_SOURCE = StaticIconName.valueForString(example);
+ assertNotNull("IPOD_MEDIA_SOURCE returned null", IPOD_MEDIA_SOURCE);
+
+ example = "0x02";
+ StaticIconName JOIN_CALLS = StaticIconName.valueForString(example);
+ assertNotNull("JOIN_CALLS returned null", JOIN_CALLS);
+
+ example = "0x46";
+ StaticIconName KEEP_LEFT = StaticIconName.valueForString(example);
+ assertNotNull("KEEP_LEFT returned null", KEEP_LEFT);
+
+ example = "0x48";
+ StaticIconName KEEP_RIGHT = StaticIconName.valueForString(example);
+ assertNotNull("KEEP_RIGHT returned null", KEEP_RIGHT);
+
+ example = "0x7D";
+ StaticIconName KEY = StaticIconName.valueForString(example);
+ assertNotNull("KEY returned null", KEY);
+
+ example = "0x9f";
+ StaticIconName LEFT = StaticIconName.valueForString(example);
+ assertNotNull("LEFT returned null", LEFT);
+
+ example = "0x4B";
+ StaticIconName LEFT_ARROW = StaticIconName.valueForString(example);
+ assertNotNull("LEFT_ARROW returned null", LEFT_ARROW);
+
+ example = "0xaf";
+ StaticIconName LEFT_EXIT = StaticIconName.valueForString(example);
+ assertNotNull("LEFT_EXIT returned null", LEFT_EXIT);
+
+ example = "0x06";
+ StaticIconName LINE_IN_AUDIO_SOURCE = StaticIconName.valueForString(example);
+ assertNotNull("LINE_IN_AUDIO_SOURCE returned null", LINE_IN_AUDIO_SOURCE);
+
+ example = "0x22";
+ StaticIconName LOCKED = StaticIconName.valueForString(example);
+ assertNotNull("LOCKED returned null", LOCKED);
+
+ example = "0x17";
+ StaticIconName MEDIA_CONTROL_LEFT_ARROW = StaticIconName.valueForString(example);
+ assertNotNull("MEDIA_CONTROL_LEFT_ARROW returned null", MEDIA_CONTROL_LEFT_ARROW);
+
+ example = "0x20";
+ StaticIconName MEDIA_CONTROL_RECORDING = StaticIconName.valueForString(example);
+ assertNotNull("MEDIA_CONTROL_RECORDING returned null", MEDIA_CONTROL_RECORDING);
+
+ example = "0x15";
+ StaticIconName MEDIA_CONTROL_RIGHT_ARROW = StaticIconName.valueForString(example);
+ assertNotNull("MEDIA_CONTROL_RIGHT_ARROW returned null", MEDIA_CONTROL_RIGHT_ARROW);
+
+ example = "0x16";
+ StaticIconName MEDIA_CONTROL_STOP = StaticIconName.valueForString(example);
+ assertNotNull("MEDIA_CONTROL_STOP returned null", MEDIA_CONTROL_STOP);
+
+ example = "0xe8";
+ StaticIconName MICROPHONE = StaticIconName.valueForString(example);
+ assertNotNull("MICROPHONE returned null", MICROPHONE);
+
+ example = "0x58";
+ StaticIconName MISSED_CALLS = StaticIconName.valueForString(example);
+ assertNotNull("MISSED_CALLS returned null", MISSED_CALLS);
+
+ example = "0x54";
+ StaticIconName MOBILE_PHONE_NUMBER = StaticIconName.valueForString(example);
+ assertNotNull("MOBILE_PHONE_NUMBER returned null", MOBILE_PHONE_NUMBER);
+
+ example = "0xE5";
+ StaticIconName MOVE_DOWN = StaticIconName.valueForString(example);
+ assertNotNull("MOVE_DOWN returned null", MOVE_DOWN);
+
+ example = "0xe4";
+ StaticIconName MOVE_UP = StaticIconName.valueForString(example);
+ assertNotNull("MOVE_UP returned null", MOVE_UP);
+
+ example = "0x24";
+ StaticIconName MP3_TAG_ARTIST = StaticIconName.valueForString(example);
+ assertNotNull("MP3_TAG_ARTIST returned null", MP3_TAG_ARTIST);
+
+ example = "0x8e";
+ StaticIconName NAVIGATION = StaticIconName.valueForString(example);
+ assertNotNull("NAVIGATION returned null", NAVIGATION);
+
+ example = "0x0a";
+ StaticIconName NAVIGATION_CURRENT_DIRECTION = StaticIconName.valueForString(example);
+ assertNotNull("NAVIGATION_CURRENT_DIRECTION returned null", NAVIGATION_CURRENT_DIRECTION);
+
+ example = "0x14";
+ StaticIconName NEGATIVE_RATING_THUMBS_DOWN = StaticIconName.valueForString(example);
+ assertNotNull("NEGATIVE_RATING_THUMBS_DOWN returned null", NEGATIVE_RATING_THUMBS_DOWN);
+
+ example = "0x5E";
+ StaticIconName NEW = StaticIconName.valueForString(example);
+ assertNotNull("NEW returned null", NEW);
+
+ example = "0x56";
+ StaticIconName OFFICE_PHONE_NUMBER = StaticIconName.valueForString(example);
+ assertNotNull("OFFICE_PHONE_NUMBER returned null", OFFICE_PHONE_NUMBER);
+
+ example = "0x5F";
+ StaticIconName OPENED = StaticIconName.valueForString(example);
+ assertNotNull("OPENED returned null", OPENED);
+
+ example = "0x96";
+ StaticIconName ORIGIN = StaticIconName.valueForString(example);
+ assertNotNull("ORIGIN returned null", ORIGIN);
+
+ example = "0x59";
+ StaticIconName OUTGOING_CALLS = StaticIconName.valueForString(example);
+ assertNotNull("OUTGOING_CALLS returned null", OUTGOING_CALLS);
+
+ example = "0x1D";
+ StaticIconName PHONE_CALL_1 = StaticIconName.valueForString(example);
+ assertNotNull("PHONE_CALL_1 returned null", PHONE_CALL_1);
+
+ example = "0x1E";
+ StaticIconName PHONE_CALL_2 = StaticIconName.valueForString(example);
+ assertNotNull("PHONE_CALL_2 returned null", PHONE_CALL_2);
+
+ example = "0x03";
+ StaticIconName PHONE_DEVICE = StaticIconName.valueForString(example);
+ assertNotNull("PHONE_DEVICE returned null", PHONE_DEVICE);
+
+ example = "0x81";
+ StaticIconName PHONEBOOK = StaticIconName.valueForString(example);
+ assertNotNull("PHONEBOOK returned null", PHONEBOOK);
+
+ example = "0x88";
+ StaticIconName PHOTO = StaticIconName.valueForString(example);
+ assertNotNull("PHOTO returned null", PHOTO);
+
+ example = "0xD0";
+ StaticIconName PLAY = StaticIconName.valueForString(example);
+ assertNotNull("PLAY returned null", PLAY);
+
+ example = "0x4F";
+ StaticIconName PLAYLIST = StaticIconName.valueForString(example);
+ assertNotNull("PLAYLIST returned null", PLAYLIST);
+
+ example = "0x76";
+ StaticIconName POPUP = StaticIconName.valueForString(example);
+ assertNotNull("POPUP returned null", POPUP);
+
+ example = "0x13";
+ StaticIconName POSITIVE_RATING_THUMBS_UP = StaticIconName.valueForString(example);
+ assertNotNull("POSITIVE_RATING_THUMBS_UP returned null", POSITIVE_RATING_THUMBS_UP);
+
+ example = "0x5b";
+ StaticIconName POWER = StaticIconName.valueForString(example);
+ assertNotNull("POWER returned null", POWER);
+
+ example = "0x1F";
+ StaticIconName PRIMARY_PHONE = StaticIconName.valueForString(example);
+ assertNotNull("PRIMARY_PHONE returned null", PRIMARY_PHONE);
+
+ example = "0x25";
+ StaticIconName RADIO_BUTTON_CHECKED = StaticIconName.valueForString(example);
+ assertNotNull("RADIO_BUTTON_CHECKED returned null", RADIO_BUTTON_CHECKED);
+
+ example = "0x26";
+ StaticIconName RADIO_BUTTON_UNCHECKED = StaticIconName.valueForString(example);
+ assertNotNull("RADIO_BUTTON_UNCHECKED returned null", RADIO_BUTTON_UNCHECKED);
+
+ example = "0xe7";
+ StaticIconName RECENT_CALLS = StaticIconName.valueForString(example);
+ assertNotNull("RECENT_CALLS returned null", RECENT_CALLS);
+
+ example = "0xf2";
+ StaticIconName RECENT_DESTINATIONS = StaticIconName.valueForString(example);
+ assertNotNull("RECENT_DESTINATIONS returned null", RECENT_DESTINATIONS);
+
+ example = "0x19";
+ StaticIconName REDO = StaticIconName.valueForString(example);
+ assertNotNull("REDO returned null", REDO);
+
+ example = "0x97";
+ StaticIconName REFRESH = StaticIconName.valueForString(example);
+ assertNotNull("REFRESH returned null", REFRESH);
+
+ example = "0x7E";
+ StaticIconName REMOTE_DIAGNOSTICS_CHECK_ENGINE = StaticIconName.valueForString(example);
+ assertNotNull("REMOTE_DIAGNOSTICS_CHECK_ENGINE returned null", REMOTE_DIAGNOSTICS_CHECK_ENGINE);
+
+ example = "0xac";
+ StaticIconName RENDERED_911_ASSIST = StaticIconName.valueForString(example);
+ assertNotNull("RENDERED_911_ASSIST returned null", RENDERED_911_ASSIST);
+
+ example = "0xe6";
+ StaticIconName REPEAT = StaticIconName.valueForString(example);
+ assertNotNull("REPEAT returned null", REPEAT);
+
+ example = "0x73";
+ StaticIconName REPEAT_PLAY = StaticIconName.valueForString(example);
+ assertNotNull("REPEAT_PLAY returned null", REPEAT_PLAY);
+
+ example = "0x04";
+ StaticIconName REPLY = StaticIconName.valueForString(example);
+ assertNotNull("REPLY returned null", REPLY);
+
+ example = "0x07";
+ StaticIconName REWIND_30_SECS = StaticIconName.valueForString(example);
+ assertNotNull("REWIND_30_SECS returned null", REWIND_30_SECS);
+
+ example = "0xa3";
+ StaticIconName RIGHT = StaticIconName.valueForString(example);
+ assertNotNull("RIGHT returned null", RIGHT);
+
+ example = "0xb1";
+ StaticIconName RIGHT_EXIT = StaticIconName.valueForString(example);
+ assertNotNull("RIGHT_EXIT returned null", RIGHT_EXIT);
+
+ example = "0x5A";
+ StaticIconName RINGTONES = StaticIconName.valueForString(example);
+ assertNotNull("RINGTONES returned null", RINGTONES);
+
+ example = "0xee";
+ StaticIconName ROUNDABOUT_LEFT_HAND_1 = StaticIconName.valueForString(example);
+ assertNotNull("ROUNDABOUT_LEFT_HAND_1 returned null", ROUNDABOUT_LEFT_HAND_1);
+
+ example = "0x8c";
+ StaticIconName ROUNDABOUT_LEFT_HAND_2 = StaticIconName.valueForString(example);
+ assertNotNull("ROUNDABOUT_LEFT_HAND_2 returned null", ROUNDABOUT_LEFT_HAND_2);
+
+ example = "0x84";
+ StaticIconName ROUNDABOUT_LEFT_HAND_3 = StaticIconName.valueForString(example);
+ assertNotNull("ROUNDABOUT_LEFT_HAND_3 returned null", ROUNDABOUT_LEFT_HAND_3);
+
+ example = "0x72";
+ StaticIconName ROUNDABOUT_LEFT_HAND_4 = StaticIconName.valueForString(example);
+ assertNotNull("ROUNDABOUT_LEFT_HAND_4 returned null", ROUNDABOUT_LEFT_HAND_4);
+
+ example = "0x6e";
+ StaticIconName ROUNDABOUT_LEFT_HAND_5 = StaticIconName.valueForString(example);
+ assertNotNull("ROUNDABOUT_LEFT_HAND_5 returned null", ROUNDABOUT_LEFT_HAND_5);
+
+ example = "0x64";
+ StaticIconName ROUNDABOUT_LEFT_HAND_6 = StaticIconName.valueForString(example);
+ assertNotNull("ROUNDABOUT_LEFT_HAND_6 returned null", ROUNDABOUT_LEFT_HAND_6);
+
+ example = "0x60";
+ StaticIconName ROUNDABOUT_LEFT_HAND_7 = StaticIconName.valueForString(example);
+ assertNotNull("ROUNDABOUT_LEFT_HAND_7 returned null", ROUNDABOUT_LEFT_HAND_7);
+
+ example = "0x62";
+ StaticIconName ROUNDABOUT_RIGHT_HAND_1 = StaticIconName.valueForString(example);
+ assertNotNull("ROUNDABOUT_RIGHT_HAND_1 returned null", ROUNDABOUT_RIGHT_HAND_1);
+
+ example = "0x6c";
+ StaticIconName ROUNDABOUT_RIGHT_HAND_2 = StaticIconName.valueForString(example);
+ assertNotNull("ROUNDABOUT_RIGHT_HAND_2 returned null", ROUNDABOUT_RIGHT_HAND_2);
+
+ example = "0x70";
+ StaticIconName ROUNDABOUT_RIGHT_HAND_3 = StaticIconName.valueForString(example);
+ assertNotNull("ROUNDABOUT_RIGHT_HAND_3 returned null", ROUNDABOUT_RIGHT_HAND_3);
+
+ example = "0x7a";
+ StaticIconName ROUNDABOUT_RIGHT_HAND_4 = StaticIconName.valueForString(example);
+ assertNotNull("ROUNDABOUT_RIGHT_HAND_4 returned null", ROUNDABOUT_RIGHT_HAND_4);
+
+ example = "0x8a";
+ StaticIconName ROUNDABOUT_RIGHT_HAND_5 = StaticIconName.valueForString(example);
+ assertNotNull("ROUNDABOUT_RIGHT_HAND_5 returned null", ROUNDABOUT_RIGHT_HAND_5);
+
+ example = "0xec";
+ StaticIconName ROUNDABOUT_RIGHT_HAND_6 = StaticIconName.valueForString(example);
+ assertNotNull("ROUNDABOUT_RIGHT_HAND_6 returned null", ROUNDABOUT_RIGHT_HAND_6);
+
+ example = "0xf0";
+ StaticIconName ROUNDABOUT_RIGHT_HAND_7 = StaticIconName.valueForString(example);
+ assertNotNull("ROUNDABOUT_RIGHT_HAND_7 returned null", ROUNDABOUT_RIGHT_HAND_7);
+
+ example = "0x89";
+ StaticIconName RSS = StaticIconName.valueForString(example);
+ assertNotNull("RSS returned null", RSS);
+
+ example = "0x49";
+ StaticIconName SETTINGS = StaticIconName.valueForString(example);
+ assertNotNull("SETTINGS returned null", SETTINGS);
+
+ example = "0xa5";
+ StaticIconName SHARP_LEFT = StaticIconName.valueForString(example);
+ assertNotNull("SHARP_LEFT returned null", SHARP_LEFT);
+
+ example = "0xe1";
+ StaticIconName SHOW = StaticIconName.valueForString(example);
+ assertNotNull("SHOW returned null", SHOW);
+
+ example = "0x74";
+ StaticIconName SHUFFLE_PLAY = StaticIconName.valueForString(example);
+ assertNotNull("SHUFFLE_PLAY returned null", SHUFFLE_PLAY);
+
+ example = "0xab";
+ StaticIconName SKI_PLACES = StaticIconName.valueForString(example);
+ assertNotNull("SKI_PLACES returned null", SKI_PLACES);
+
+ example = "0x9d";
+ StaticIconName SLIGHT_LEFT = StaticIconName.valueForString(example);
+ assertNotNull("SLIGHT_LEFT returned null", SLIGHT_LEFT);
+
+ example = "0xa1";
+ StaticIconName SLIGHT_RIGHT = StaticIconName.valueForString(example);
+ assertNotNull("SLIGHT_RIGHT returned null", SLIGHT_RIGHT);
+
+ example = "0x05";
+ StaticIconName SMARTPHONE = StaticIconName.valueForString(example);
+ assertNotNull("SMARTPHONE returned null", SMARTPHONE);
+
+ example = "0x7B";
+ StaticIconName SORT_LIST = StaticIconName.valueForString(example);
+ assertNotNull("SORT_LIST returned null", SORT_LIST);
+
+ example = "0xE0";
+ StaticIconName SPEED_DIAL_NUMBERS_NUMBER_0 = StaticIconName.valueForString(example);
+ assertNotNull("SPEED_DIAL_NUMBERS_NUMBER_0 returned null", SPEED_DIAL_NUMBERS_NUMBER_0);
+
+ example = "0xD7";
+ StaticIconName SPEED_DIAL_NUMBERS_NUMBER_1 = StaticIconName.valueForString(example);
+ assertNotNull("SPEED_DIAL_NUMBERS_NUMBER_1 returned null", SPEED_DIAL_NUMBERS_NUMBER_1);
+
+ example = "0xD8";
+ StaticIconName SPEED_DIAL_NUMBERS_NUMBER_2 = StaticIconName.valueForString(example);
+ assertNotNull("SPEED_DIAL_NUMBERS_NUMBER_2 returned null", SPEED_DIAL_NUMBERS_NUMBER_2);
+
+ example = "0xD9";
+ StaticIconName SPEED_DIAL_NUMBERS_NUMBER_3 = StaticIconName.valueForString(example);
+ assertNotNull("SPEED_DIAL_NUMBERS_NUMBER_3 returned null", SPEED_DIAL_NUMBERS_NUMBER_3);
+
+ example = "0xDA";
+ StaticIconName SPEED_DIAL_NUMBERS_NUMBER_4 = StaticIconName.valueForString(example);
+ assertNotNull("SPEED_DIAL_NUMBERS_NUMBER_4 returned null", SPEED_DIAL_NUMBERS_NUMBER_4);
+
+ example = "0xDB";
+ StaticIconName SPEED_DIAL_NUMBERS_NUMBER_5 = StaticIconName.valueForString(example);
+ assertNotNull("SPEED_DIAL_NUMBERS_NUMBER_5 returned null", SPEED_DIAL_NUMBERS_NUMBER_5);
+
+ example = "0xDC";
+ StaticIconName SPEED_DIAL_NUMBERS_NUMBER_6 = StaticIconName.valueForString(example);
+ assertNotNull("SPEED_DIAL_NUMBERS_NUMBER_6 returned null", SPEED_DIAL_NUMBERS_NUMBER_6);
+
+ example = "0xDD";
+ StaticIconName SPEED_DIAL_NUMBERS_NUMBER_7 = StaticIconName.valueForString(example);
+ assertNotNull("SPEED_DIAL_NUMBERS_NUMBER_7 returned null", SPEED_DIAL_NUMBERS_NUMBER_7);
+
+ example = "0xDE";
+ StaticIconName SPEED_DIAL_NUMBERS_NUMBER_8 = StaticIconName.valueForString(example);
+ assertNotNull("SPEED_DIAL_NUMBERS_NUMBER_8 returned null", SPEED_DIAL_NUMBERS_NUMBER_8);
+
+ example = "0xDF";
+ StaticIconName SPEED_DIAL_NUMBERS_NUMBER_9 = StaticIconName.valueForString(example);
+ assertNotNull("SPEED_DIAL_NUMBERS_NUMBER_9 returned null", SPEED_DIAL_NUMBERS_NUMBER_9);
+
+ example = "0xD5";
+ StaticIconName SUCCESS = StaticIconName.valueForString(example);
+ assertNotNull("SUCCESS returned null", SUCCESS);
+
+ example = "0x4C";
+ StaticIconName TRACK_TITLE = StaticIconName.valueForString(example);
+ assertNotNull("TRACK_TITLE returned null", TRACK_TITLE);
+
+ example = "0x2A";
+ StaticIconName TRAFFIC_REPORT = StaticIconName.valueForString(example);
+ assertNotNull("TRAFFIC_REPORT returned null", TRAFFIC_REPORT);
+
+ example = "0x10";
+ StaticIconName TURN_LIST = StaticIconName.valueForString(example);
+ assertNotNull("TURN_LIST returned null", TURN_LIST);
+
+ example = "0xad";
+ StaticIconName UTURN_LEFT_TRAFFIC = StaticIconName.valueForString(example);
+ assertNotNull("UTURN_LEFT_TRAFFIC returned null", UTURN_LEFT_TRAFFIC);
+
+ example = "0xa9";
+ StaticIconName UTURN_RIGHT_TRAFFIC = StaticIconName.valueForString(example);
+ assertNotNull("UTURN_RIGHT_TRAFFIC returned null", UTURN_RIGHT_TRAFFIC);
+
+ example = "0x18";
+ StaticIconName UNDO = StaticIconName.valueForString(example);
+ assertNotNull("UNDO returned null", UNDO);
+
+ example = "0x23";
+ StaticIconName UNLOCKED = StaticIconName.valueForString(example);
+ assertNotNull("UNLOCKED returned null", UNLOCKED);
+
+ example = "0x0B";
+ StaticIconName USB_MEDIA_AUDIO_SOURCE = StaticIconName.valueForString(example);
+ assertNotNull("USB_MEDIA_AUDIO_SOURCE returned null", USB_MEDIA_AUDIO_SOURCE);
+
+ example = "0xC7";
+ StaticIconName VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_1 = StaticIconName.valueForString(example);
+ assertNotNull("VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_1 returned null", VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_1);
+
+ example = "0xC8";
+ StaticIconName VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_2 = StaticIconName.valueForString(example);
+ assertNotNull("VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_2 returned null", VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_2);
+
+ example = "0xC9";
+ StaticIconName VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_3 = StaticIconName.valueForString(example);
+ assertNotNull("VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_3 returned null", VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_3);
+
+ example = "0xCA";
+ StaticIconName VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_4 = StaticIconName.valueForString(example);
+ assertNotNull("VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_4 returned null", VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_4);
+
+ example = "0x90";
+ StaticIconName VOICE_RECOGNITION_FAILED = StaticIconName.valueForString(example);
+ assertNotNull("VOICE_RECOGNITION_FAILED returned null", VOICE_RECOGNITION_FAILED);
+
+ example = "0x92";
+ StaticIconName VOICE_RECOGNITION_PAUSE = StaticIconName.valueForString(example);
+ assertNotNull("VOICE_RECOGNITION_PAUSE returned null", VOICE_RECOGNITION_PAUSE);
+
+ example = "0x8F";
+ StaticIconName VOICE_RECOGNITION_SUCCESSFUL = StaticIconName.valueForString(example);
+ assertNotNull("VOICE_RECOGNITION_SUCCESSFUL returned null", VOICE_RECOGNITION_SUCCESSFUL);
+
+ example = "0x11";
+ StaticIconName VOICE_RECOGNITION_SYSTEM_ACTIVE = StaticIconName.valueForString(example);
+ assertNotNull("VOICE_RECOGNITION_SYSTEM_ACTIVE returned null", VOICE_RECOGNITION_SYSTEM_ACTIVE);
+
+ example = "0x91";
+ StaticIconName VOICE_RECOGNITION_SYSTEM_LISTENING = StaticIconName.valueForString(example);
+ assertNotNull("VOICE_RECOGNITION_SYSTEM_LISTENING returned null", VOICE_RECOGNITION_SYSTEM_LISTENING);
+
+ example = "0x93";
+ StaticIconName VOICE_RECOGNITION_TRY_AGAIN = StaticIconName.valueForString(example);
+ assertNotNull("VOICE_RECOGNITION_TRY_AGAIN returned null", VOICE_RECOGNITION_TRY_AGAIN);
+
+ example = "0xfe";
+ StaticIconName WARNING = StaticIconName.valueForString(example);
+ assertNotNull("WARNING returned null", WARNING);
+
+ example = "0xeb";
+ StaticIconName WEATHER = StaticIconName.valueForString(example);
+ assertNotNull("WEATHER returned null", WEATHER);
+
+ example = "0x43";
+ StaticIconName WIFI_FULL = StaticIconName.valueForString(example);
+ assertNotNull("WIFI_FULL returned null", WIFI_FULL);
+
+ example = "0x98";
+ StaticIconName ZOOM_IN = StaticIconName.valueForString(example);
+ assertNotNull("ZOOM_IN returned null", ZOOM_IN);
+
+ example = "0x9a";
+ StaticIconName ZOOM_OUT = StaticIconName.valueForString(example);
+ assertNotNull("ZOOM_OUT returned null", ZOOM_OUT);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum () {
+ String example = "SoMeThInG";
+ try {
+ StaticIconName SOMETHING = StaticIconName.valueForString(example);
+ assertNull("Result of valueForString should be null.", SOMETHING);
+ }
+ catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum () {
+ String example = null;
+ try {
+ StaticIconName temp = StaticIconName.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of StaticIconNames.
+ */
+ public void testListEnum() {
+
+ List<StaticIconName> enumValueList = Arrays.asList(StaticIconName.values());
+
+ List<StaticIconName> enumTestList = new ArrayList<>();
+ enumTestList.add(StaticIconName.ACCEPT_CALL);
+ enumTestList.add(StaticIconName.ADD_WAYPOINT);
+ enumTestList.add(StaticIconName.ALBUM);
+ enumTestList.add(StaticIconName.AMBIENT_LIGHTING);
+ enumTestList.add(StaticIconName.ARROW_NORTH);
+ enumTestList.add(StaticIconName.AUDIO_MUTE);
+ enumTestList.add(StaticIconName.AUDIOBOOK_EPISODE);
+ enumTestList.add(StaticIconName.AUDIOBOOK_NARRATOR);
+ enumTestList.add(StaticIconName.AUXILLARY_AUDIO);
+ enumTestList.add(StaticIconName.BACK);
+ enumTestList.add(StaticIconName.BATTERY_CAPACITY_0_OF_5);
+ enumTestList.add(StaticIconName.BATTERY_CAPACITY_1_OF_5);
+ enumTestList.add(StaticIconName.BATTERY_CAPACITY_2_OF_5);
+ enumTestList.add(StaticIconName.BATTERY_CAPACITY_3_OF_5);
+ enumTestList.add(StaticIconName.BATTERY_CAPACITY_4_OF_5);
+ enumTestList.add(StaticIconName.BATTERY_CAPACITY_5_OF_5);
+ enumTestList.add(StaticIconName.BLUETOOTH_AUDIO_SOURCE);
+ enumTestList.add(StaticIconName.BLUETOOTH1);
+ enumTestList.add(StaticIconName.BLUETOOTH2);
+ enumTestList.add(StaticIconName.BROWSE);
+ enumTestList.add(StaticIconName.CELL_PHONE_IN_ROAMING_MODE);
+ enumTestList.add(StaticIconName.CELL_SERVICE_SIGNAL_STRENGTH_0_OF_5_BARS);
+ enumTestList.add(StaticIconName.CELL_SERVICE_SIGNAL_STRENGTH_1_OF_5_BARS);
+ enumTestList.add(StaticIconName.CELL_SERVICE_SIGNAL_STRENGTH_2_OF_5_BARS);
+ enumTestList.add(StaticIconName.CELL_SERVICE_SIGNAL_STRENGTH_3_OF_5_BARS);
+ enumTestList.add(StaticIconName.CELL_SERVICE_SIGNAL_STRENGTH_4_OF_5_BARS);
+ enumTestList.add(StaticIconName.CELL_SERVICE_SIGNAL_STRENGTH_5_OF_5_BARS);
+ enumTestList.add(StaticIconName.CHANGE_LANE_LEFT);
+ enumTestList.add(StaticIconName.CHANGE_LANE_RIGHT);
+ enumTestList.add(StaticIconName.CHECK_BOX_CHECKED);
+ enumTestList.add(StaticIconName.CHECK_BOX_UNCHECKED);
+ enumTestList.add(StaticIconName.CLIMATE);
+ enumTestList.add(StaticIconName.CLOCK);
+ enumTestList.add(StaticIconName.COMPOSE);
+ enumTestList.add(StaticIconName.CONTACT);
+ enumTestList.add(StaticIconName.CONTINUE);
+ enumTestList.add(StaticIconName.DASH);
+ enumTestList.add(StaticIconName.DATE);
+ enumTestList.add(StaticIconName.DELETE);
+ enumTestList.add(StaticIconName.DESTINATION);
+ enumTestList.add(StaticIconName.DESTINATION_FERRY_AHEAD);
+ enumTestList.add(StaticIconName.EBOOKMARK);
+ enumTestList.add(StaticIconName.END_CALL);
+ enumTestList.add(StaticIconName.FAIL);
+ enumTestList.add(StaticIconName.FAST_FORWARD_30_SECS);
+ enumTestList.add(StaticIconName.FAVORITE_HEART);
+ enumTestList.add(StaticIconName.FAVORITE_STAR);
+ enumTestList.add(StaticIconName.FAX_NUMBER);
+ enumTestList.add(StaticIconName.FILENAME);
+ enumTestList.add(StaticIconName.FILTER);
+ enumTestList.add(StaticIconName.FOLDER);
+ enumTestList.add(StaticIconName.FUEL_PRICES);
+ enumTestList.add(StaticIconName.FULL_MAP);
+ enumTestList.add(StaticIconName.GENERIC_PHONE_NUMBER);
+ enumTestList.add(StaticIconName.GENRE);
+ enumTestList.add(StaticIconName.GLOBAL_KEYBOARD);
+ enumTestList.add(StaticIconName.HIGHWAY_EXIT_INFORMATION);
+ enumTestList.add(StaticIconName.HOME_PHONE_NUMBER);
+ enumTestList.add(StaticIconName.HYPERLINK);
+ enumTestList.add(StaticIconName.ID3_TAG_UNKNOWN);
+ enumTestList.add(StaticIconName.INCOMING_CALLS);
+ enumTestList.add(StaticIconName.INFORMATION);
+ enumTestList.add(StaticIconName.IPOD_MEDIA_SOURCE);
+ enumTestList.add(StaticIconName.JOIN_CALLS);
+ enumTestList.add(StaticIconName.KEEP_LEFT);
+ enumTestList.add(StaticIconName.KEEP_RIGHT);
+ enumTestList.add(StaticIconName.KEY);
+ enumTestList.add(StaticIconName.LEFT);
+ enumTestList.add(StaticIconName.LEFT_ARROW);
+ enumTestList.add(StaticIconName.LEFT_EXIT);
+ enumTestList.add(StaticIconName.LINE_IN_AUDIO_SOURCE);
+ enumTestList.add(StaticIconName.LOCKED);
+ enumTestList.add(StaticIconName.MEDIA_CONTROL_LEFT_ARROW);
+ enumTestList.add(StaticIconName.MEDIA_CONTROL_RECORDING);
+ enumTestList.add(StaticIconName.MEDIA_CONTROL_RIGHT_ARROW);
+ enumTestList.add(StaticIconName.MEDIA_CONTROL_STOP);
+ enumTestList.add(StaticIconName.MICROPHONE);
+ enumTestList.add(StaticIconName.MISSED_CALLS);
+ enumTestList.add(StaticIconName.MOBILE_PHONE_NUMBER);
+ enumTestList.add(StaticIconName.MOVE_DOWN);
+ enumTestList.add(StaticIconName.MOVE_UP);
+ enumTestList.add(StaticIconName.MP3_TAG_ARTIST);
+ enumTestList.add(StaticIconName.NAVIGATION);
+ enumTestList.add(StaticIconName.NAVIGATION_CURRENT_DIRECTION);
+ enumTestList.add(StaticIconName.NEGATIVE_RATING_THUMBS_DOWN);
+ enumTestList.add(StaticIconName.NEW);
+ enumTestList.add(StaticIconName.OFFICE_PHONE_NUMBER);
+ enumTestList.add(StaticIconName.OPENED);
+ enumTestList.add(StaticIconName.ORIGIN);
+ enumTestList.add(StaticIconName.OUTGOING_CALLS);
+ enumTestList.add(StaticIconName.PHONE_CALL_1);
+ enumTestList.add(StaticIconName.PHONE_CALL_2);
+ enumTestList.add(StaticIconName.PHONE_DEVICE);
+ enumTestList.add(StaticIconName.PHONEBOOK);
+ enumTestList.add(StaticIconName.PHOTO);
+ enumTestList.add(StaticIconName.PLAY);
+ enumTestList.add(StaticIconName.PLAYLIST);
+ enumTestList.add(StaticIconName.POPUP);
+ enumTestList.add(StaticIconName.POSITIVE_RATING_THUMBS_UP);
+ enumTestList.add(StaticIconName.POWER);
+ enumTestList.add(StaticIconName.PRIMARY_PHONE);
+ enumTestList.add(StaticIconName.RADIO_BUTTON_CHECKED);
+ enumTestList.add(StaticIconName.RADIO_BUTTON_UNCHECKED);
+ enumTestList.add(StaticIconName.RECENT_CALLS);
+ enumTestList.add(StaticIconName.RECENT_DESTINATIONS);
+ enumTestList.add(StaticIconName.REDO);
+ enumTestList.add(StaticIconName.REFRESH);
+ enumTestList.add(StaticIconName.REMOTE_DIAGNOSTICS_CHECK_ENGINE);
+ enumTestList.add(StaticIconName.RENDERED_911_ASSIST);
+ enumTestList.add(StaticIconName.REPEAT);
+ enumTestList.add(StaticIconName.REPEAT_PLAY);
+ enumTestList.add(StaticIconName.REPLY);
+ enumTestList.add(StaticIconName.REWIND_30_SECS);
+ enumTestList.add(StaticIconName.RIGHT);
+ enumTestList.add(StaticIconName.RIGHT_EXIT);
+ enumTestList.add(StaticIconName.RINGTONES);
+ enumTestList.add(StaticIconName.ROUNDABOUT_LEFT_HAND_1);
+ enumTestList.add(StaticIconName.ROUNDABOUT_LEFT_HAND_2);
+ enumTestList.add(StaticIconName.ROUNDABOUT_LEFT_HAND_3);
+ enumTestList.add(StaticIconName.ROUNDABOUT_LEFT_HAND_4);
+ enumTestList.add(StaticIconName.ROUNDABOUT_LEFT_HAND_5);
+ enumTestList.add(StaticIconName.ROUNDABOUT_LEFT_HAND_6);
+ enumTestList.add(StaticIconName.ROUNDABOUT_LEFT_HAND_7);
+ enumTestList.add(StaticIconName.ROUNDABOUT_RIGHT_HAND_1);
+ enumTestList.add(StaticIconName.ROUNDABOUT_RIGHT_HAND_2);
+ enumTestList.add(StaticIconName.ROUNDABOUT_RIGHT_HAND_3);
+ enumTestList.add(StaticIconName.ROUNDABOUT_RIGHT_HAND_4);
+ enumTestList.add(StaticIconName.ROUNDABOUT_RIGHT_HAND_5);
+ enumTestList.add(StaticIconName.ROUNDABOUT_RIGHT_HAND_6);
+ enumTestList.add(StaticIconName.ROUNDABOUT_RIGHT_HAND_7);
+ enumTestList.add(StaticIconName.RSS);
+ enumTestList.add(StaticIconName.SETTINGS);
+ enumTestList.add(StaticIconName.SHARP_LEFT);
+ enumTestList.add(StaticIconName.SHARP_RIGHT);
+ enumTestList.add(StaticIconName.SHOW);
+ enumTestList.add(StaticIconName.SHUFFLE_PLAY);
+ enumTestList.add(StaticIconName.SKI_PLACES);
+ enumTestList.add(StaticIconName.SLIGHT_LEFT);
+ enumTestList.add(StaticIconName.SLIGHT_RIGHT);
+ enumTestList.add(StaticIconName.SMARTPHONE);
+ enumTestList.add(StaticIconName.SORT_LIST);
+ enumTestList.add(StaticIconName.SPEED_DIAL_NUMBERS_NUMBER_0);
+ enumTestList.add(StaticIconName.SPEED_DIAL_NUMBERS_NUMBER_1);
+ enumTestList.add(StaticIconName.SPEED_DIAL_NUMBERS_NUMBER_2);
+ enumTestList.add(StaticIconName.SPEED_DIAL_NUMBERS_NUMBER_3);
+ enumTestList.add(StaticIconName.SPEED_DIAL_NUMBERS_NUMBER_4);
+ enumTestList.add(StaticIconName.SPEED_DIAL_NUMBERS_NUMBER_5);
+ enumTestList.add(StaticIconName.SPEED_DIAL_NUMBERS_NUMBER_6);
+ enumTestList.add(StaticIconName.SPEED_DIAL_NUMBERS_NUMBER_7);
+ enumTestList.add(StaticIconName.SPEED_DIAL_NUMBERS_NUMBER_8);
+ enumTestList.add(StaticIconName.SPEED_DIAL_NUMBERS_NUMBER_9);
+ enumTestList.add(StaticIconName.SUCCESS);
+ enumTestList.add(StaticIconName.TRACK_TITLE);
+ enumTestList.add(StaticIconName.TRAFFIC_REPORT);
+ enumTestList.add(StaticIconName.TURN_LIST);
+ enumTestList.add(StaticIconName.UTURN_LEFT_TRAFFIC);
+ enumTestList.add(StaticIconName.UTURN_RIGHT_TRAFFIC);
+ enumTestList.add(StaticIconName.UNDO);
+ enumTestList.add(StaticIconName.UNLOCKED);
+ enumTestList.add(StaticIconName.USB_MEDIA_AUDIO_SOURCE);
+ enumTestList.add(StaticIconName.VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_1);
+ enumTestList.add(StaticIconName.VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_2);
+ enumTestList.add(StaticIconName.VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_3);
+ enumTestList.add(StaticIconName.VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_4);
+ enumTestList.add(StaticIconName.VOICE_RECOGNITION_FAILED);
+ enumTestList.add(StaticIconName.VOICE_RECOGNITION_PAUSE);
+ enumTestList.add(StaticIconName.VOICE_RECOGNITION_SUCCESSFUL);
+ enumTestList.add(StaticIconName.VOICE_RECOGNITION_SYSTEM_ACTIVE);
+ enumTestList.add(StaticIconName.VOICE_RECOGNITION_SYSTEM_LISTENING);
+ enumTestList.add(StaticIconName.VOICE_RECOGNITION_TRY_AGAIN);
+ enumTestList.add(StaticIconName.WARNING);
+ enumTestList.add(StaticIconName.WEATHER);
+ enumTestList.add(StaticIconName.WIFI_FULL);
+ enumTestList.add(StaticIconName.ZOOM_IN);
+ enumTestList.add(StaticIconName.ZOOM_OUT);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SupportedSeatTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SupportedSeatTests.java
new file mode 100644
index 000000000..6a2dbd18f
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/SupportedSeatTests.java
@@ -0,0 +1,69 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.SupportedSeat;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.rpc.enums.SupportedSeat}
+ */
+public class SupportedSeatTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums() {
+ String example = "DRIVER";
+ SupportedSeat enumDriver = SupportedSeat.valueForString(example);
+ example = "FRONT_PASSENGER";
+ SupportedSeat enumFrontPassenger = SupportedSeat.valueForString(example);
+
+ assertNotNull("DRIVER returned null", enumDriver);
+ assertNotNull("FRONT_PASSENGER returned null", enumFrontPassenger);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum() {
+ String example = "dRIVER";
+ try {
+ SupportedSeat temp = SupportedSeat.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum() {
+ String example = null;
+ try {
+ SupportedSeat temp = SupportedSeat.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of SupportedSeat.
+ */
+ public void testListEnum() {
+ List<SupportedSeat> enumValueList = Arrays.asList(SupportedSeat.values());
+
+ List<SupportedSeat> enumTestList = new ArrayList<SupportedSeat>();
+ enumTestList.add(SupportedSeat.DRIVER);
+ enumTestList.add(SupportedSeat.FRONT_PASSENGER);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/TPMSTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/TPMSTests.java
new file mode 100644
index 000000000..c573a0d7a
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/TPMSTests.java
@@ -0,0 +1,95 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.TPMS;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.proxy.rpc.enums.TPMS}
+ */
+public class TPMSTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums () {
+ String example = "UNKNOWN";
+ TPMS unknown = TPMS.valueForString(example);
+ example = "SYSTEM_FAULT";
+ TPMS systemFault = TPMS.valueForString(example);
+ example = "SENSOR_FAULT";
+ TPMS sensorFault = TPMS.valueForString(example);
+ example = "LOW";
+ TPMS low = TPMS.valueForString(example);
+ example = "SYSTEM_ACTIVE";
+ TPMS systemActive = TPMS.valueForString(example);
+ example = "TRAIN";
+ TPMS train = TPMS.valueForString(example);
+ example = "TRAINING_COMPLETE";
+ TPMS trainingComplete = TPMS.valueForString(example);
+ example = "NOT_TRAINED";
+ TPMS notTrained = TPMS.valueForString(example);
+
+ assertNotNull("UNKNOWN returned null", unknown);
+ assertNotNull("SYSTEM_FAULT returned null", systemFault);
+ assertNotNull("SENSOR_FAULT returned null", sensorFault);
+ assertNotNull("LOW returned null", low);
+ assertNotNull("SYSTEM_ACTIVE returned null", systemActive);
+ assertNotNull("TRAIN returned null", train);
+ assertNotNull("TRAINING_COMPLETE returned null", trainingComplete);
+ assertNotNull("NOT_TRAINED returned null", notTrained);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum () {
+ String example = "IsHoUldBeNulL";
+ try {
+ TPMS temp = TPMS.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum () {
+ String example = null;
+ try {
+ TPMS temp = TPMS.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of TPMS.
+ */
+ public void testListEnum() {
+ List<TPMS> enumValueList = Arrays.asList(TPMS.values());
+
+ List<TPMS> enumTestList = new ArrayList<>();
+ enumTestList.add(TPMS.UNKNOWN);
+ enumTestList.add(TPMS.SYSTEM_FAULT);
+ enumTestList.add(TPMS.SENSOR_FAULT);
+ enumTestList.add(TPMS.LOW);
+ enumTestList.add(TPMS.SYSTEM_ACTIVE);
+ enumTestList.add(TPMS.TRAIN);
+ enumTestList.add(TPMS.TRAINING_COMPLETE);
+ enumTestList.add(TPMS.NOT_TRAINED);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/TurnSignalTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/TurnSignalTests.java
new file mode 100644
index 000000000..a758d683e
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/TurnSignalTests.java
@@ -0,0 +1,79 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.TurnSignal;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.proxy.rpc.enums.TurnSignal}
+ */
+public class TurnSignalTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums () {
+ String example = "OFF";
+ TurnSignal off = TurnSignal.valueForString(example);
+ example = "LEFT";
+ TurnSignal left = TurnSignal.valueForString(example);
+ example = "RIGHT";
+ TurnSignal right = TurnSignal.valueForString(example);
+ example = "BOTH";
+ TurnSignal both = TurnSignal.valueForString(example);
+
+ assertNotNull("OFF returned null", off);
+ assertNotNull("LEFT returned null", left);
+ assertNotNull("RIGHT returned null", right);
+ assertNotNull("BOTH returned null", both);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum () {
+ String example = "IsHoUldBeNulL";
+ try {
+ TurnSignal temp = TurnSignal.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum () {
+ String example = null;
+ try {
+ TurnSignal temp = TurnSignal.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of TurnSignal.
+ */
+ public void testListEnum() {
+ List<TurnSignal> enumValueList = Arrays.asList(TurnSignal.values());
+
+ List<TurnSignal> enumTestList = new ArrayList<>();
+ enumTestList.add(TurnSignal.OFF);
+ enumTestList.add(TurnSignal.LEFT);
+ enumTestList.add(TurnSignal.RIGHT);
+ enumTestList.add(TurnSignal.BOTH);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/VehicleDataTypeTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/VehicleDataTypeTests.java
index 7490940fa..9f9ff3449 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/VehicleDataTypeTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/VehicleDataTypeTests.java
@@ -10,7 +10,7 @@ import com.smartdevicelink.proxy.rpc.enums.VehicleDataType;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.enums.VehicleData}
+ * {@link com.smartdevicelink.proxy.rpc.enums.VehicleDataType}
*/
public class VehicleDataTypeTests extends TestCase {
@@ -56,6 +56,8 @@ public class VehicleDataTypeTests extends TestCase {
VehicleDataType enumVehicleDataBattVoltage = VehicleDataType.valueForString(example);
example = "VEHICLEDATA_ENGINETORQUE";
VehicleDataType enumVehicleDataEngineTorque = VehicleDataType.valueForString(example);
+ example = "VEHICLEDATA_ENGINEOILLIFE";
+ VehicleDataType enumVehicleDataEngineOilLife = VehicleDataType.valueForString(example);
example = "VEHICLEDATA_ACCPEDAL";
VehicleDataType enumVehicleDataAccPedal = VehicleDataType.valueForString(example);
example = "VEHICLEDATA_STEERINGWHEEL";
@@ -70,6 +72,12 @@ public class VehicleDataTypeTests extends TestCase {
VehicleDataType enumVehicleDataClusterModeStatus = VehicleDataType.valueForString(example);
example = "VEHICLEDATA_MYKEY";
VehicleDataType enumVehicleDataMyKey = VehicleDataType.valueForString(example);
+ example = "VEHICLEDATA_FUELRANGE";
+ VehicleDataType enumVehicleDataFuelRange = VehicleDataType.valueForString(example);
+ example = "VEHICLEDATA_TURNSIGNAL";
+ VehicleDataType enumVehicleDataTurnSignal = VehicleDataType.valueForString(example);
+ example = "VEHICLEDATA_ELECTRONICPARKBRAKESTATUS";
+ VehicleDataType enumVehicleDataElectronicParkBrakeStatus = VehicleDataType.valueForString(example);
assertNotNull("VEHICLEDATA_GPS returned null", enumVehicleDataGps);
assertNotNull("VEHICLEDATA_SPEED returned null", enumVehicleDataSpeed);
@@ -90,6 +98,7 @@ public class VehicleDataTypeTests extends TestCase {
assertNotNull("VEHICLEDATA_HEADLAMPSTATUS returned null", enumVehicleDataHeadlampStatus);
assertNotNull("VEHICLEDATA_BATTVOLTAGE returned null", enumVehicleDataBattVoltage);
assertNotNull("VEHICLEDATA_ENGINETORQUE returned null", enumVehicleDataEngineTorque);
+ assertNotNull("VEHICLEDATA_ENGINEOILLIFE returned null", enumVehicleDataEngineOilLife);
assertNotNull("VEHICLEDATA_ACCPEDAL returned null", enumVehicleDataAccPedal);
assertNotNull("VEHICLEDATA_STEERINGWHEEL returned null", enumVehicleDataSteeringWheel);
assertNotNull("VEHICLEDATA_ECALLINFO returned null", enumVehicleDataECallInfo);
@@ -97,6 +106,9 @@ public class VehicleDataTypeTests extends TestCase {
assertNotNull("VEHICLEDATA_EMERGENCYEVENT returned null", enumVehicleDataEmergencyEvent);
assertNotNull("VEHICLEDATA_CLUSTERMODESTATUS returned null", enumVehicleDataClusterModeStatus);
assertNotNull("VEHICLEDATA_MYKEY returned null", enumVehicleDataMyKey);
+ assertNotNull("VEHICLEDATA_FUELRANGE returned null", enumVehicleDataFuelRange);
+ assertNotNull("VEHICLEDATA_TURNSIGNAL returned null", enumVehicleDataTurnSignal);
+ assertNotNull("VEHICLEDATA_ELECTRONICPARKBRAKESTATUS returned null", enumVehicleDataElectronicParkBrakeStatus);
}
/**
@@ -153,13 +165,17 @@ public class VehicleDataTypeTests extends TestCase {
enumTestList.add(VehicleDataType.VEHICLEDATA_HEADLAMPSTATUS);
enumTestList.add(VehicleDataType.VEHICLEDATA_BATTVOLTAGE);
enumTestList.add(VehicleDataType.VEHICLEDATA_ENGINETORQUE);
+ enumTestList.add(VehicleDataType.VEHICLEDATA_ENGINEOILLIFE);
enumTestList.add(VehicleDataType.VEHICLEDATA_ACCPEDAL);
enumTestList.add(VehicleDataType.VEHICLEDATA_STEERINGWHEEL);
enumTestList.add(VehicleDataType.VEHICLEDATA_ECALLINFO);
enumTestList.add(VehicleDataType.VEHICLEDATA_AIRBAGSTATUS);
enumTestList.add(VehicleDataType.VEHICLEDATA_EMERGENCYEVENT);
enumTestList.add(VehicleDataType.VEHICLEDATA_CLUSTERMODESTATUS);
- enumTestList.add(VehicleDataType.VEHICLEDATA_MYKEY);
+ enumTestList.add(VehicleDataType.VEHICLEDATA_MYKEY);
+ enumTestList.add(VehicleDataType.VEHICLEDATA_FUELRANGE);
+ enumTestList.add(VehicleDataType.VEHICLEDATA_TURNSIGNAL);
+ enumTestList.add(VehicleDataType.VEHICLEDATA_ELECTRONICPARKBRAKESTATUS);
assertTrue("Enum value list does not match enum class list",
enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/VideoStreamingStateTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/VideoStreamingStateTests.java
new file mode 100644
index 000000000..2074efe47
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/enums/VideoStreamingStateTests.java
@@ -0,0 +1,71 @@
+package com.smartdevicelink.test.rpc.enums;
+
+import com.smartdevicelink.proxy.rpc.enums.VideoStreamingState;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This is a unit test class for the SmartDeviceLink library project class :
+ * {@link com.smartdevicelink.proxy.rpc.enums.VideoStreamingState}
+ */
+public class VideoStreamingStateTests extends TestCase {
+
+ /**
+ * Verifies that the enum values are not null upon valid assignment.
+ */
+ public void testValidEnums () {
+ String example = "STREAMABLE";
+ VideoStreamingState enumStreamable = VideoStreamingState.valueForString(example);
+ example = "NOT_STREAMABLE";
+ VideoStreamingState enumNotStreamable = VideoStreamingState.valueForString(example);
+
+ assertNotNull("STREAMABLE returned null", enumStreamable);
+ assertNotNull("NOT_STREAMABLE returned null", enumNotStreamable);
+ }
+
+ /**
+ * Verifies that an invalid assignment is null.
+ */
+ public void testInvalidEnum () {
+ String example = "StrEAmaBlE";
+ try {
+ VideoStreamingState temp = VideoStreamingState.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ /**
+ * Verifies that a null assignment is invalid.
+ */
+ public void testNullEnum () {
+ String example = null;
+ try {
+ VideoStreamingState temp = VideoStreamingState.valueForString(example);
+ assertNull("Result of valueForString should be null.", temp);
+ }
+ catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ /**
+ * Verifies the possible enum values of VideoStreamingState.
+ */
+ public void testListEnum() {
+ List<VideoStreamingState> enumValueList = Arrays.asList(VideoStreamingState.values());
+
+ List<VideoStreamingState> enumTestList = new ArrayList<VideoStreamingState>();
+ enumTestList.add(VideoStreamingState.STREAMABLE);
+ enumTestList.add(VideoStreamingState.NOT_STREAMABLE);
+
+ assertTrue("Enum value list does not match enum class list",
+ enumValueList.containsAll(enumTestList) && enumTestList.containsAll(enumValueList));
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnHMIStatusTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnHMIStatusTests.java
index 329018aa2..6f38fdfa0 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnHMIStatusTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnHMIStatusTests.java
@@ -9,12 +9,14 @@ import com.smartdevicelink.proxy.rpc.OnHMIStatus;
import com.smartdevicelink.proxy.rpc.enums.AudioStreamingState;
import com.smartdevicelink.proxy.rpc.enums.HMILevel;
import com.smartdevicelink.proxy.rpc.enums.SystemContext;
+import com.smartdevicelink.proxy.rpc.enums.VideoStreamingState;
import com.smartdevicelink.test.BaseRpcTests;
import com.smartdevicelink.test.Test;
+import com.smartdevicelink.util.Version;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.OnHMIStatus}
+ * {@link com.smartdevicelink.proxy.rpc.OnHMIStatus}
*/
public class OnHMIStatusTests extends BaseRpcTests{
@@ -23,6 +25,7 @@ public class OnHMIStatusTests extends BaseRpcTests{
OnHMIStatus msg = new OnHMIStatus();
msg.setAudioStreamingState(Test.GENERAL_AUDIOSTREAMINGSTATE);
+ msg.setVideoStreamingState(Test.GENERAL_VIDEOSTREAMINGSTATE);
msg.setFirstRun(Test.GENERAL_BOOLEAN);
msg.setHmiLevel(Test.GENERAL_HMILEVEL);
msg.setSystemContext(Test.GENERAL_SYSTEMCONTEXT);
@@ -46,6 +49,7 @@ public class OnHMIStatusTests extends BaseRpcTests{
try{
result.put(OnHMIStatus.KEY_AUDIO_STREAMING_STATE, Test.GENERAL_AUDIOSTREAMINGSTATE);
+ result.put(OnHMIStatus.KEY_VIDEO_STREAMING_STATE, Test.GENERAL_VIDEOSTREAMINGSTATE);
result.put(OnHMIStatus.KEY_HMI_LEVEL, Test.GENERAL_HMILEVEL);
result.put(OnHMIStatus.KEY_SYSTEM_CONTEXT, Test.GENERAL_SYSTEMCONTEXT);
}catch(JSONException e){
@@ -60,12 +64,14 @@ public class OnHMIStatusTests extends BaseRpcTests{
*/
public void testRpcValues () {
// Test Values
- AudioStreamingState state = ( (OnHMIStatus) msg ).getAudioStreamingState();
+ AudioStreamingState audioStreamingState = ( (OnHMIStatus) msg ).getAudioStreamingState();
+ VideoStreamingState videoStreamingState = ( (OnHMIStatus) msg ).getVideoStreamingState();
HMILevel hmiLevel = ( (OnHMIStatus) msg ).getHmiLevel();
SystemContext context = ( (OnHMIStatus) msg ).getSystemContext();
// Valid Tests
- assertEquals(Test.MATCH, Test.GENERAL_AUDIOSTREAMINGSTATE, state);
+ assertEquals(Test.MATCH, Test.GENERAL_AUDIOSTREAMINGSTATE, audioStreamingState);
+ assertEquals(Test.MATCH, Test.GENERAL_VIDEOSTREAMINGSTATE, videoStreamingState);
assertEquals(Test.MATCH, Test.GENERAL_HMILEVEL, hmiLevel);
assertEquals(Test.MATCH, Test.GENERAL_SYSTEMCONTEXT, context);
@@ -75,6 +81,10 @@ public class OnHMIStatusTests extends BaseRpcTests{
testNullBase(msg);
assertNull(Test.NULL, msg.getAudioStreamingState());
+
+ assertNull(Test.NULL, msg.getVideoStreamingState());
+ msg.format(new Version(4,5,0),true);
+ assertEquals(Test.MATCH, VideoStreamingState.STREAMABLE, msg.getVideoStreamingState());
assertNull(Test.NULL, msg.getHmiLevel());
assertNull(Test.NULL, msg.getSystemContext());
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnRCStatusTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnRCStatusTests.java
new file mode 100644
index 000000000..a6d4d63fd
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnRCStatusTests.java
@@ -0,0 +1,92 @@
+package com.smartdevicelink.test.rpc.notifications;
+
+import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCMessage;
+import com.smartdevicelink.proxy.rpc.ModuleData;
+import com.smartdevicelink.proxy.rpc.OnRCStatus;
+import com.smartdevicelink.test.BaseRpcTests;
+import com.smartdevicelink.test.Test;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class OnRCStatusTests extends BaseRpcTests {
+ @Override
+ protected RPCMessage createMessage() {
+ OnRCStatus msg = new OnRCStatus();
+
+ List<ModuleData> listAllocatedModules = Test.GENERAL_MODULEDATA_LIST;
+
+ msg.setAllocatedModules(listAllocatedModules);
+
+ List<ModuleData> listFreeModules = new ArrayList<>();
+ listFreeModules.add(Test.GENERAL_MODULEDATA);
+ msg.setFreeModules(listFreeModules);
+
+ msg.setAllowed(Test.GENERAL_BOOLEAN);
+ return msg;
+ }
+
+ @Override
+ protected String getMessageType() {
+ return RPCMessage.KEY_NOTIFICATION;
+ }
+
+ @Override
+ protected String getCommandType() {
+ return FunctionID.ON_RC_STATUS.toString();
+ }
+
+ @Override
+ protected JSONObject getExpectedParameters(int sdlVersion) {
+ JSONObject result = new JSONObject();
+
+ JSONArray jsonArrayAllocatedModules = new JSONArray();
+ JSONArray jsonArrayFreeModules = new JSONArray();
+ try {
+ jsonArrayAllocatedModules.put(JsonRPCMarshaller.serializeHashtable(Test.GENERAL_MODULEDATA.getStore()));
+ jsonArrayFreeModules.put(JsonRPCMarshaller.serializeHashtable(Test.GENERAL_MODULEDATA.getStore()));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ result.put(OnRCStatus.KEY_ALLOCATED_MODULES, jsonArrayAllocatedModules);
+ result.put(OnRCStatus.KEY_FREE_MODULES, jsonArrayFreeModules);
+ result.put(OnRCStatus.KEY_ALLOWED, Test.GENERAL_BOOLEAN);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ return result;
+ }
+
+ /**
+ * Tests the expected values of the RPC message.
+ */
+ public void testRpcValues() {
+ // Test Values
+ List<ModuleData> listAllocatedModules = ((OnRCStatus) msg).getAllocatedModules();
+ List<ModuleData> listFreeModules = ((OnRCStatus) msg).getFreeModules();
+ Boolean allowed = ((OnRCStatus) msg).getAllowed();
+
+ // Valid Tests
+ assertEquals(Test.MATCH, Test.GENERAL_MODULEDATA, listAllocatedModules.get(0));
+ assertEquals(Test.MATCH, Test.GENERAL_MODULEDATA, listFreeModules.get(0));
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, allowed);
+
+ // Invalid/Null Tests
+ OnRCStatus msg = new OnRCStatus();
+ assertNotNull(Test.NOT_NULL, msg);
+ testNullBase(msg);
+
+ assertNull(Test.NULL, msg.getAllocatedModules());
+ assertNull(Test.NULL, msg.getFreeModules());
+ assertNull(Test.NULL, msg.getAllowed());
+ }
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnSystemRequestTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnSystemRequestTests.java
index fbe073259..a4bb53e71 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnSystemRequestTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnSystemRequestTests.java
@@ -15,7 +15,7 @@ import com.smartdevicelink.test.Validator;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.OnSystemRequest}
+ * {@link com.smartdevicelink.proxy.rpc.OnSystemRequest}
*/
public class OnSystemRequestTests extends BaseRpcTests{
@@ -27,6 +27,7 @@ public class OnSystemRequestTests extends BaseRpcTests{
msg.setLength(Test.GENERAL_LONG);
msg.setOffset(Test.GENERAL_LONG);
msg.setRequestType(Test.GENERAL_REQUESTTYPE);
+ msg.setRequestSubType(Test.GENERAL_STRING);
msg.setTimeout(Test.GENERAL_INT);
msg.setUrl(Test.GENERAL_STRING);
@@ -54,6 +55,7 @@ public class OnSystemRequestTests extends BaseRpcTests{
result.put(OnSystemRequest.KEY_OFFSET, Test.GENERAL_LONG);
result.put(OnSystemRequest.KEY_URL, Test.GENERAL_STRING);
result.put(OnSystemRequest.KEY_REQUEST_TYPE, Test.GENERAL_REQUESTTYPE);
+ result.put(OnSystemRequest.KEY_REQUEST_SUB_TYPE, Test.GENERAL_STRING);
} catch(JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -72,6 +74,7 @@ public class OnSystemRequestTests extends BaseRpcTests{
Long offset = ( (OnSystemRequest) msg ).getOffset();
String url = ( (OnSystemRequest) msg ).getUrl();
RequestType requestType = ( (OnSystemRequest) msg ).getRequestType();
+ String requestSubType = ( (OnSystemRequest) msg ).getRequestSubType();
// Valid Tests
@@ -81,6 +84,7 @@ public class OnSystemRequestTests extends BaseRpcTests{
assertEquals(Test.MATCH, Test.GENERAL_LONG, offset);
assertEquals(Test.MATCH, Test.GENERAL_STRING, url);
assertEquals(Test.MATCH, Test.GENERAL_REQUESTTYPE, requestType);
+ assertEquals(Test.MATCH, Test.GENERAL_STRING, requestSubType);
// Test Body
OnSystemRequest osr = (OnSystemRequest) msg;
@@ -124,5 +128,6 @@ public class OnSystemRequestTests extends BaseRpcTests{
assertNull(Test.NULL, msg.getTimeout());
assertNull(Test.NULL, msg.getUrl());
assertNull(Test.NULL, msg.getRequestType());
+ assertNull(Test.NULL, msg.getRequestSubType());
}
} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnVehicleDataTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnVehicleDataTests.java
index 5d328813c..c530c1278 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnVehicleDataTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/notifications/OnVehicleDataTests.java
@@ -1,7 +1,10 @@
package com.smartdevicelink.test.rpc.notifications;
+import java.util.ArrayList;
import java.util.Iterator;
+import java.util.List;
+import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -15,6 +18,7 @@ import com.smartdevicelink.proxy.rpc.ClusterModeStatus;
import com.smartdevicelink.proxy.rpc.DeviceStatus;
import com.smartdevicelink.proxy.rpc.ECallInfo;
import com.smartdevicelink.proxy.rpc.EmergencyEvent;
+import com.smartdevicelink.proxy.rpc.FuelRange;
import com.smartdevicelink.proxy.rpc.GPSData;
import com.smartdevicelink.proxy.rpc.HeadLampStatus;
import com.smartdevicelink.proxy.rpc.MyKey;
@@ -22,7 +26,9 @@ import com.smartdevicelink.proxy.rpc.OnVehicleData;
import com.smartdevicelink.proxy.rpc.SingleTireStatus;
import com.smartdevicelink.proxy.rpc.TireStatus;
import com.smartdevicelink.proxy.rpc.enums.ComponentVolumeStatus;
+import com.smartdevicelink.proxy.rpc.enums.ElectronicParkBrakeStatus;
import com.smartdevicelink.proxy.rpc.enums.PRNDL;
+import com.smartdevicelink.proxy.rpc.enums.TurnSignal;
import com.smartdevicelink.proxy.rpc.enums.VehicleDataEventStatus;
import com.smartdevicelink.proxy.rpc.enums.WiperStatus;
import com.smartdevicelink.test.BaseRpcTests;
@@ -33,7 +39,7 @@ import com.smartdevicelink.test.VehicleDataHelper;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.OnVehicleData}
+ * {@link com.smartdevicelink.proxy.rpc.OnVehicleData}
*/
public class OnVehicleDataTests extends BaseRpcTests{
@@ -65,6 +71,7 @@ public class OnVehicleDataTests extends BaseRpcTests{
result.put(OnVehicleData.KEY_PRNDL, VehicleDataHelper.PRNDL_FINAL);
result.put(OnVehicleData.KEY_TIRE_PRESSURE, VehicleDataHelper.TIRE_PRESSURE.serializeJSON());
result.put(OnVehicleData.KEY_ENGINE_TORQUE, VehicleDataHelper.ENGINE_TORQUE);
+ result.put(OnVehicleData.KEY_ENGINE_OIL_LIFE, VehicleDataHelper.ENGINE_OIL_LIFE);
result.put(OnVehicleData.KEY_ODOMETER, VehicleDataHelper.ODOMETER);
result.put(OnVehicleData.KEY_GPS, VehicleDataHelper.GPS.serializeJSON());
result.put(OnVehicleData.KEY_FUEL_LEVEL_STATE, VehicleDataHelper.FUEL_LEVEL_STATE);
@@ -82,6 +89,9 @@ public class OnVehicleDataTests extends BaseRpcTests{
result.put(OnVehicleData.KEY_EMERGENCY_EVENT, VehicleDataHelper.EMERGENCY_EVENT.serializeJSON());
result.put(OnVehicleData.KEY_CLUSTER_MODE_STATUS, VehicleDataHelper.CLUSTER_MODE_STATUS.serializeJSON());
result.put(OnVehicleData.KEY_MY_KEY, VehicleDataHelper.MY_KEY.serializeJSON());
+ result.put(OnVehicleData.KEY_FUEL_RANGE, VehicleDataHelper.JSON_FUEL_RANGE);
+ result.put(OnVehicleData.KEY_TURN_SIGNAL, VehicleDataHelper.TURN_SIGNAL);
+ result.put(OnVehicleData.KEY_ELECTRONIC_PARK_BRAKE_STATUS, VehicleDataHelper.ELECTRONIC_PARK_BRAKE_STATUS);
} catch(JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -102,6 +112,7 @@ public class OnVehicleDataTests extends BaseRpcTests{
PRNDL prndl = ( (OnVehicleData) msg).getPrndl();
TireStatus pressure = ( (OnVehicleData) msg).getTirePressure();
Double torque = ( (OnVehicleData) msg).getEngineTorque();
+ Float engineOilLife = ( (OnVehicleData) msg).getEngineOilLife();
int odometer = ( (OnVehicleData) msg).getOdometer();
GPSData gps = ( (OnVehicleData) msg).getGps();
ComponentVolumeStatus state = ( (OnVehicleData) msg).getFuelLevelState();
@@ -119,6 +130,9 @@ public class OnVehicleDataTests extends BaseRpcTests{
EmergencyEvent event = ( (OnVehicleData) msg).getEmergencyEvent();
ClusterModeStatus cluster = ( (OnVehicleData) msg).getClusterModeStatus();
MyKey key = ( (OnVehicleData) msg).getMyKey();
+ List<FuelRange> fuelRangeList = ( (OnVehicleData) msg).getFuelRange();
+ TurnSignal turnSignal = ( (OnVehicleData) msg).getTurnSignal();
+ ElectronicParkBrakeStatus electronicParkBrakeStatus = ( (OnVehicleData) msg).getElectronicParkBrakeStatus();
// Valid Tests
assertEquals(Test.MATCH, VehicleDataHelper.SPEED, speed);
@@ -129,6 +143,7 @@ public class OnVehicleDataTests extends BaseRpcTests{
assertEquals(Test.MATCH, VehicleDataHelper.PRNDL_FINAL, prndl);
assertTrue(Test.MATCH, Validator.validateTireStatus(VehicleDataHelper.TIRE_PRESSURE, pressure));
assertEquals(Test.MATCH, VehicleDataHelper.ENGINE_TORQUE, torque);
+ assertEquals(Test.MATCH, VehicleDataHelper.ENGINE_OIL_LIFE, engineOilLife);
assertEquals(Test.MATCH, VehicleDataHelper.ODOMETER, odometer);
assertTrue(Test.MATCH, Validator.validateGpsData(VehicleDataHelper.GPS, gps));
assertEquals(Test.MATCH, VehicleDataHelper.FUEL_LEVEL_STATE, state);
@@ -146,6 +161,9 @@ public class OnVehicleDataTests extends BaseRpcTests{
assertTrue(Test.TRUE, Validator.validateEmergencyEvent(VehicleDataHelper.EMERGENCY_EVENT, event));
assertTrue(Test.TRUE, Validator.validateClusterModeStatus(VehicleDataHelper.CLUSTER_MODE_STATUS, cluster));
assertTrue(Test.TRUE, Validator.validateMyKey(VehicleDataHelper.MY_KEY, key));
+ assertTrue(Test.TRUE, Validator.validateFuelRange(VehicleDataHelper.FUEL_RANGE_LIST, fuelRangeList));
+ assertEquals(Test.MATCH, VehicleDataHelper.TURN_SIGNAL, turnSignal);
+ assertEquals(Test.MATCH, VehicleDataHelper.ELECTRONIC_PARK_BRAKE_STATUS, electronicParkBrakeStatus);
// Invalid/Null Tests
OnVehicleData msg = new OnVehicleData();
@@ -160,6 +178,7 @@ public class OnVehicleDataTests extends BaseRpcTests{
assertNull(Test.NULL, msg.getPrndl());
assertNull(Test.NULL, msg.getTirePressure());
assertNull(Test.NULL, msg.getEngineTorque());
+ assertNull(Test.NULL, msg.getEngineOilLife());
assertNull(Test.NULL, msg.getOdometer());
assertNull(Test.NULL, msg.getGps());
assertNull(Test.NULL, msg.getFuelLevelState());
@@ -176,8 +195,11 @@ public class OnVehicleDataTests extends BaseRpcTests{
assertNull(Test.NULL, msg.getAirbagStatus());
assertNull(Test.NULL, msg.getEmergencyEvent());
assertNull(Test.NULL, msg.getClusterModeStatus());
- assertNull(Test.NULL, msg.getMyKey());
- }
+ assertNull(Test.NULL, msg.getMyKey());
+ assertNull(Test.NULL, msg.getFuelRange());
+ assertNull(Test.NULL, msg.getTurnSignal());
+ assertNull(Test.NULL, msg.getElectronicParkBrakeStatus());
+ }
public void testJson() {
JSONObject reference = new JSONObject();
@@ -194,6 +216,8 @@ public class OnVehicleDataTests extends BaseRpcTests{
JSONObject emergencyEventObj = new JSONObject();
JSONObject clusterModeStatusObj = new JSONObject();
JSONObject myKeyObj = new JSONObject();
+ JSONObject fuelRangeObj = new JSONObject();
+ JSONArray fuelRangeArrayObj = new JSONArray();
try {
//Set up the JSONObject to represent OnVehicleData:
@@ -313,7 +337,12 @@ public class OnVehicleDataTests extends BaseRpcTests{
//MY_KEY
myKeyObj.put(MyKey.KEY_E_911_OVERRIDE, VehicleDataHelper.MY_KEY_E_911_OVERRIDE);
-
+
+ // FUEL_RANGE
+ fuelRangeObj.put(FuelRange.KEY_TYPE, VehicleDataHelper.FUEL_RANGE_TYPE);
+ fuelRangeObj.put(FuelRange.KEY_RANGE, VehicleDataHelper.FUEL_RANGE_RANGE);
+ fuelRangeArrayObj.put(fuelRangeObj);
+
reference.put(OnVehicleData.KEY_SPEED, VehicleDataHelper.SPEED);
reference.put(OnVehicleData.KEY_RPM, VehicleDataHelper.RPM);
reference.put(OnVehicleData.KEY_EXTERNAL_TEMPERATURE, VehicleDataHelper.EXTERNAL_TEMPERATURE);
@@ -322,6 +351,7 @@ public class OnVehicleDataTests extends BaseRpcTests{
reference.put(OnVehicleData.KEY_PRNDL, VehicleDataHelper.PRNDL_FINAL);
reference.put(OnVehicleData.KEY_TIRE_PRESSURE, tireStatusObj);
reference.put(OnVehicleData.KEY_ENGINE_TORQUE, VehicleDataHelper.ENGINE_TORQUE);
+ reference.put(OnVehicleData.KEY_ENGINE_OIL_LIFE, VehicleDataHelper.ENGINE_OIL_LIFE);
reference.put(OnVehicleData.KEY_ODOMETER, VehicleDataHelper.ODOMETER);
reference.put(OnVehicleData.KEY_GPS, GPSDataObj);
reference.put(OnVehicleData.KEY_FUEL_LEVEL_STATE, VehicleDataHelper.FUEL_LEVEL_STATE);
@@ -339,6 +369,9 @@ public class OnVehicleDataTests extends BaseRpcTests{
reference.put(OnVehicleData.KEY_EMERGENCY_EVENT, emergencyEventObj);
reference.put(OnVehicleData.KEY_CLUSTER_MODE_STATUS, clusterModeStatusObj);
reference.put(OnVehicleData.KEY_MY_KEY, myKeyObj);
+ reference.put(OnVehicleData.KEY_FUEL_RANGE, fuelRangeArrayObj);
+ reference.put(OnVehicleData.KEY_TURN_SIGNAL, VehicleDataHelper.TURN_SIGNAL);
+ reference.put(OnVehicleData.KEY_ELECTRONIC_PARK_BRAKE_STATUS, VehicleDataHelper.ELECTRONIC_PARK_BRAKE_STATUS);
JSONObject underTest = msg.serializeJSON();
//go inside underTest and only return the JSONObject inside the parameters key inside the notification key
@@ -433,6 +466,28 @@ public class OnVehicleDataTests extends BaseRpcTests{
new MyKey(JsonRPCMarshaller.deserializeJSONObject(myKeyObjReference)),
new MyKey(JsonRPCMarshaller.deserializeJSONObject(myKeyObjTest))));
}
+ else if (key.equals(OnVehicleData.KEY_ENGINE_OIL_LIFE)) {
+ assertEquals(JsonUtils.readDoubleFromJsonObject(reference, key), JsonUtils.readDoubleFromJsonObject(underTest, key));
+ }
+ else if (key.equals(OnVehicleData.KEY_FUEL_RANGE)) {
+ JSONArray fuelRangeArrayObjReference = JsonUtils.readJsonArrayFromJsonObject(reference, key);
+ List<FuelRange> fuelRangeRefereceList = new ArrayList<FuelRange>();
+ for (int index = 0; index < fuelRangeArrayObjReference.length(); index++) {
+ FuelRange fuelRange = new FuelRange(JsonRPCMarshaller.deserializeJSONObject( (JSONObject)fuelRangeArrayObjReference.get(index) ));
+ fuelRangeRefereceList.add(fuelRange);
+ }
+
+ JSONArray fuelRangeArrayObjTest = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
+ List<FuelRange> fuelRangeUnderTestList = new ArrayList<FuelRange>();
+ for (int index = 0; index < fuelRangeArrayObjTest.length(); index++) {
+ FuelRange fuelRange = new FuelRange(JsonRPCMarshaller.deserializeJSONObject( (JSONObject)fuelRangeArrayObjTest.get(index) ));
+ fuelRangeUnderTestList.add(fuelRange);
+ }
+
+ assertTrue(Test.TRUE, Validator.validateFuelRange(
+ fuelRangeRefereceList,
+ fuelRangeUnderTestList));
+ }
else {
assertEquals(Test.TRUE, JsonUtils.readObjectFromJsonObject(reference, key), JsonUtils.readObjectFromJsonObject(underTest, key));
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/AddSubmenuTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/AddSubmenuTests.java
index e44340216..6e73121f1 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/AddSubmenuTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/AddSubmenuTests.java
@@ -9,14 +9,16 @@ import com.smartdevicelink.marshal.JsonRPCMarshaller;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCMessage;
import com.smartdevicelink.proxy.rpc.AddSubMenu;
+import com.smartdevicelink.proxy.rpc.Image;
import com.smartdevicelink.test.BaseRpcTests;
import com.smartdevicelink.test.JsonUtils;
import com.smartdevicelink.test.Test;
+import com.smartdevicelink.test.Validator;
import com.smartdevicelink.test.json.rpc.JsonFileReader;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.AddSubmenu}
+ * {@link com.smartdevicelink.proxy.rpc.AddSubMenu}
*/
public class AddSubmenuTests extends BaseRpcTests{
@@ -27,6 +29,7 @@ public class AddSubmenuTests extends BaseRpcTests{
msg.setMenuID(Test.GENERAL_INT);
msg.setMenuName(Test.GENERAL_STRING);
msg.setPosition(Test.GENERAL_INT);
+ msg.setMenuIcon(Test.GENERAL_IMAGE);
return msg;
}
@@ -49,6 +52,7 @@ public class AddSubmenuTests extends BaseRpcTests{
result.put(AddSubMenu.KEY_MENU_ID, Test.GENERAL_INT);
result.put(AddSubMenu.KEY_MENU_NAME, Test.GENERAL_STRING);
result.put(AddSubMenu.KEY_POSITION, Test.GENERAL_INT);
+ result.put(AddSubMenu.KEY_MENU_ICON, Test.JSON_IMAGE);
}catch(JSONException e){
fail(Test.JSON_FAIL);
}
@@ -64,13 +68,16 @@ public class AddSubmenuTests extends BaseRpcTests{
int testMenuId = ( (AddSubMenu) msg ).getMenuID();
int testPosition = ( (AddSubMenu) msg ).getPosition();
String testMenuName = ( (AddSubMenu) msg ).getMenuName();
+ Image testMenuIcon = ( (AddSubMenu) msg ).getMenuIcon();
// Valid Tests
assertEquals("Menu ID didn't match input menu ID.", Test.GENERAL_INT, testMenuId);
assertEquals("Menu name didn't match input menu name.", Test.GENERAL_STRING, testMenuName);
assertEquals("Position didn't match input position.", Test.GENERAL_INT, testPosition);
-
- // Invalid/Null Tests
+ assertTrue("Menu icon didn't match input icon.", Validator.validateImage(Test.GENERAL_IMAGE, testMenuIcon));
+
+
+ // Invalid/Null Tests
AddSubMenu msg = new AddSubMenu();
assertNotNull("Null object creation failed.", msg);
testNullBase(msg);
@@ -78,6 +85,7 @@ public class AddSubmenuTests extends BaseRpcTests{
assertNull(Test.NULL, msg.getMenuID());
assertNull(Test.NULL, msg.getMenuName());
assertNull(Test.NULL, msg.getPosition());
+ assertNull(Test.NULL, msg.getMenuIcon());
}
/**
@@ -103,6 +111,10 @@ public class AddSubmenuTests extends BaseRpcTests{
assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(parameters, AddSubMenu.KEY_MENU_ID), cmd.getMenuID());
assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(parameters, AddSubMenu.KEY_POSITION), cmd.getPosition());
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, AddSubMenu.KEY_MENU_NAME), cmd.getMenuName());
+
+ JSONObject menuIcon = JsonUtils.readJsonObjectFromJsonObject(parameters, AddSubMenu.KEY_MENU_ICON);
+ Image referenceMenuIcon = new Image(JsonRPCMarshaller.deserializeJSONObject(menuIcon));
+ assertTrue(Test.TRUE, Validator.validateImage(referenceMenuIcon, cmd.getMenuIcon()));
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/GetVehicleDataTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/GetVehicleDataTests.java
index 658c28257..54f299fdf 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/GetVehicleDataTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/GetVehicleDataTests.java
@@ -16,7 +16,7 @@ import com.smartdevicelink.test.json.rpc.JsonFileReader;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.GetVehicleData}
+ * {@link com.smartdevicelink.proxy.rpc.GetVehicleData}
*/
public class GetVehicleDataTests extends BaseRpcTests {
@@ -31,6 +31,7 @@ public class GetVehicleDataTests extends BaseRpcTests {
msg.setPrndl(Test.GENERAL_BOOLEAN);
msg.setTirePressure(Test.GENERAL_BOOLEAN);
msg.setEngineTorque(Test.GENERAL_BOOLEAN);
+ msg.setEngineOilLife(Test.GENERAL_BOOLEAN);
msg.setOdometer(Test.GENERAL_BOOLEAN);
msg.setGps(Test.GENERAL_BOOLEAN);
msg.setFuelLevelState(Test.GENERAL_BOOLEAN);
@@ -49,6 +50,9 @@ public class GetVehicleDataTests extends BaseRpcTests {
msg.setEmergencyEvent(Test.GENERAL_BOOLEAN);
msg.setClusterModeStatus(Test.GENERAL_BOOLEAN);
msg.setMyKey(Test.GENERAL_BOOLEAN);
+ msg.setFuelRange(Test.GENERAL_BOOLEAN);
+ msg.setTurnSignal(Test.GENERAL_BOOLEAN);
+ msg.setElectronicParkBrakeStatus(Test.GENERAL_BOOLEAN);
return msg;
}
@@ -75,6 +79,7 @@ public class GetVehicleDataTests extends BaseRpcTests {
result.put(GetVehicleData.KEY_PRNDL, Test.GENERAL_BOOLEAN);
result.put(GetVehicleData.KEY_TIRE_PRESSURE, Test.GENERAL_BOOLEAN);
result.put(GetVehicleData.KEY_ENGINE_TORQUE, Test.GENERAL_BOOLEAN);
+ result.put(GetVehicleData.KEY_ENGINE_OIL_LIFE, Test.GENERAL_BOOLEAN);
result.put(GetVehicleData.KEY_ODOMETER, Test.GENERAL_BOOLEAN);
result.put(GetVehicleData.KEY_GPS, Test.GENERAL_BOOLEAN);
result.put(GetVehicleData.KEY_FUEL_LEVEL_STATE, Test.GENERAL_BOOLEAN);
@@ -93,6 +98,9 @@ public class GetVehicleDataTests extends BaseRpcTests {
result.put(GetVehicleData.KEY_EMERGENCY_EVENT, Test.GENERAL_BOOLEAN);
result.put(GetVehicleData.KEY_CLUSTER_MODE_STATUS, Test.GENERAL_BOOLEAN);
result.put(GetVehicleData.KEY_MY_KEY, Test.GENERAL_BOOLEAN);
+ result.put(GetVehicleData.KEY_FUEL_RANGE, Test.GENERAL_BOOLEAN);
+ result.put(GetVehicleData.KEY_TURN_SIGNAL, Test.GENERAL_BOOLEAN);
+ result.put(GetVehicleData.KEY_ELECTRONIC_PARK_BRAKE_STATUS, Test.GENERAL_BOOLEAN);
}catch(JSONException e){
fail(Test.JSON_FAIL);
}
@@ -112,6 +120,7 @@ public class GetVehicleDataTests extends BaseRpcTests {
assertTrue(Test.TRUE, ( (GetVehicleData) msg ).getPrndl());
assertTrue(Test.TRUE, ( (GetVehicleData) msg ).getTirePressure());
assertTrue(Test.TRUE, ( (GetVehicleData) msg ).getEngineTorque());
+ assertTrue(Test.TRUE, ( (GetVehicleData) msg ).getEngineOilLife());
assertTrue(Test.TRUE, ( (GetVehicleData) msg ).getOdometer());
assertTrue(Test.TRUE, ( (GetVehicleData) msg ).getGps());
assertTrue(Test.TRUE, ( (GetVehicleData) msg ).getFuelLevelState());
@@ -131,6 +140,9 @@ public class GetVehicleDataTests extends BaseRpcTests {
assertTrue(Test.TRUE, ( (GetVehicleData) msg ).getEmergencyEvent());
assertTrue(Test.TRUE, ( (GetVehicleData) msg ).getClusterModeStatus());
assertTrue(Test.TRUE, ( (GetVehicleData) msg ).getMyKey());
+ assertTrue(Test.TRUE, ( (GetVehicleData) msg ).getFuelRange());
+ assertTrue(Test.TRUE, ( (GetVehicleData) msg ).getTurnSignal());
+ assertTrue(Test.TRUE, ( (GetVehicleData) msg ).getElectronicParkBrakeStatus());
// Invalid/Null Tests
GetVehicleData msg = new GetVehicleData();
@@ -157,11 +169,15 @@ public class GetVehicleDataTests extends BaseRpcTests {
assertNull(Test.NULL, msg.getDeviceStatus());
assertNull(Test.NULL, msg.getHeadLampStatus());
assertNull(Test.NULL, msg.getEngineTorque());
+ assertNull(Test.NULL, msg.getEngineOilLife());
assertNull(Test.NULL, msg.getSteeringWheelAngle());
assertNull(Test.NULL, msg.getECallInfo());
assertNull(Test.NULL, msg.getEmergencyEvent());
assertNull(Test.NULL, msg.getClusterModeStatus());
assertNull(Test.NULL, msg.getMyKey());
+ assertNull(Test.NULL, msg.getFuelRange());
+ assertNull(Test.NULL, msg.getTurnSignal());
+ assertNull(Test.NULL, msg.getElectronicParkBrakeStatus());
}
/**
@@ -191,6 +207,7 @@ public class GetVehicleDataTests extends BaseRpcTests {
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, GetVehicleData.KEY_PRNDL), cmd.getPrndl());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, GetVehicleData.KEY_TIRE_PRESSURE), cmd.getTirePressure());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, GetVehicleData.KEY_ENGINE_TORQUE), cmd.getEngineTorque());
+ assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, GetVehicleData.KEY_ENGINE_OIL_LIFE), cmd.getEngineOilLife());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, GetVehicleData.KEY_ODOMETER), cmd.getOdometer());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, GetVehicleData.KEY_GPS), cmd.getGps());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, GetVehicleData.KEY_FUEL_LEVEL_STATE), cmd.getFuelLevelState());
@@ -208,6 +225,9 @@ public class GetVehicleDataTests extends BaseRpcTests {
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, GetVehicleData.KEY_EMERGENCY_EVENT), cmd.getEmergencyEvent());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, GetVehicleData.KEY_CLUSTER_MODE_STATUS), cmd.getClusterModeStatus());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, GetVehicleData.KEY_MY_KEY), cmd.getMyKey());
+ assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, GetVehicleData.KEY_FUEL_RANGE), cmd.getFuelRange());
+ assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, GetVehicleData.KEY_TURN_SIGNAL), cmd.getTurnSignal());
+ assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, GetVehicleData.KEY_ELECTRONIC_PARK_BRAKE_STATUS), cmd.getElectronicParkBrakeStatus());
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/PutFileTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/PutFileTests.java
index becca8eee..7b6ce75e5 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/PutFileTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/PutFileTests.java
@@ -1,6 +1,7 @@
package com.smartdevicelink.test.rpc.requests;
import java.util.Hashtable;
+import java.util.zip.CRC32;
import org.json.JSONException;
import org.json.JSONObject;
@@ -17,7 +18,7 @@ import com.smartdevicelink.test.json.rpc.JsonFileReader;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.PutFile}
+ * {@link com.smartdevicelink.proxy.rpc.PutFile}
*/
public class PutFileTests extends BaseRpcTests {
@@ -30,6 +31,8 @@ public class PutFileTests extends BaseRpcTests {
msg.setSystemFile(Test.GENERAL_BOOLEAN);
msg.setOffset(Test.GENERAL_LONG);
msg.setLength(Test.GENERAL_LONG);
+ msg.setCRC(Test.GENERAL_BYTE_ARRAY);
+ msg.setCRC(Test.GENERAL_LONG);
return msg;
}
@@ -53,7 +56,8 @@ public class PutFileTests extends BaseRpcTests {
result.put(PutFile.KEY_PERSISTENT_FILE, Test.GENERAL_BOOLEAN);
result.put(PutFile.KEY_SYSTEM_FILE, Test.GENERAL_BOOLEAN);
result.put(PutFile.KEY_OFFSET, Test.GENERAL_LONG);
- result.put(PutFile.KEY_LENGTH, Test.GENERAL_LONG);
+ result.put(PutFile.KEY_LENGTH, Test.GENERAL_LONG);
+ result.put(PutFile.KEY_CRC, Test.GENERAL_LONG);
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -71,14 +75,16 @@ public class PutFileTests extends BaseRpcTests {
boolean testSystemFile = ( (PutFile) msg ).getSystemFile();
Long testOffset = ( (PutFile) msg ).getOffset();
Long testLength = ( (PutFile) msg ).getLength();
-
+ Long testCRC = ( (PutFile) msg ).getCRC();
+
// Valid Tests
assertEquals(Test.MATCH, Test.GENERAL_FILETYPE, testFileType);
assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, testPersistentFile);
assertEquals(Test.MATCH, Test.GENERAL_BOOLEAN, testSystemFile);
assertEquals(Test.MATCH, Test.GENERAL_LONG, testOffset);
assertEquals(Test.MATCH, Test.GENERAL_LONG, testLength);
-
+ assertEquals(Test.MATCH, Test.GENERAL_LONG, testCRC);
+
// Invalid/Null Tests
PutFile msg = new PutFile();
assertNotNull("Null object creation failed.", msg);
@@ -89,8 +95,27 @@ public class PutFileTests extends BaseRpcTests {
assertNull(Test.NULL, msg.getSystemFile());
assertNull(Test.NULL, msg.getOffset());
assertNull(Test.NULL, msg.getLength());
+ assertNull(Test.NULL, msg.getCRC());
}
+ /**
+ * Tests the expected values of the CRC checksum.
+ */
+ public void testByteArrayCheckSum () {
+ // Test Values
+ PutFile msgCRC = new PutFile();
+ msgCRC.setCRC(Test.GENERAL_BYTE_ARRAY);
+ Long testCRCByteArray = msgCRC.getCRC();
+
+ CRC32 crc = new CRC32();
+ crc.update(Test.GENERAL_BYTE_ARRAY);
+ Long crcValue = crc.getValue();
+
+ assertEquals(Test.MATCH, crcValue, testCRCByteArray);
+ }
+
+
+
/**
* Tests a valid JSON construction of this RPC message.
*/
@@ -115,7 +140,8 @@ public class PutFileTests extends BaseRpcTests {
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, PutFile.KEY_FILE_TYPE), cmd.getFileType().toString());
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, PutFile.KEY_SDL_FILE_NAME), cmd.getSdlFileName());
assertEquals(Test.MATCH, (Long) JsonUtils.readIntegerFromJsonObject(parameters, PutFile.KEY_OFFSET).longValue(), cmd.getOffset());
- assertEquals(Test.MATCH, (Long) JsonUtils.readIntegerFromJsonObject(parameters, PutFile.KEY_LENGTH).longValue(), cmd.getLength());
+ assertEquals(Test.MATCH, (Long) JsonUtils.readIntegerFromJsonObject(parameters, PutFile.KEY_LENGTH).longValue(), cmd.getLength());
+ assertEquals(Test.MATCH, (Long) JsonUtils.readIntegerFromJsonObject(parameters, PutFile.KEY_CRC).longValue(), cmd.getCRC());
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/RegisterAppInterfaceTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/RegisterAppInterfaceTests.java
index 1310890b4..85b6f28ea 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/RegisterAppInterfaceTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/RegisterAppInterfaceTests.java
@@ -15,6 +15,7 @@ import com.smartdevicelink.proxy.rpc.DeviceInfo;
import com.smartdevicelink.proxy.rpc.RegisterAppInterface;
import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
import com.smartdevicelink.proxy.rpc.TTSChunk;
+import com.smartdevicelink.proxy.rpc.TemplateColorScheme;
import com.smartdevicelink.proxy.rpc.enums.AppHMIType;
import com.smartdevicelink.proxy.rpc.enums.Language;
import com.smartdevicelink.test.BaseRpcTests;
@@ -25,7 +26,7 @@ import com.smartdevicelink.test.json.rpc.JsonFileReader;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.RegisterAppInterface}
+ * {@link com.smartdevicelink.proxy.rpc.RegisterAppInterface}
*/
public class RegisterAppInterfaceTests extends BaseRpcTests {
@@ -36,7 +37,7 @@ public class RegisterAppInterfaceTests extends BaseRpcTests {
msg.setSdlMsgVersion(Test.GENERAL_SDLMSGVERSION);
msg.setAppName(Test.GENERAL_STRING);
msg.setNgnMediaScreenAppName(Test.GENERAL_STRING);
- msg.setAppID(Test.GENERAL_STRING);
+ msg.setFullAppID(Test.GENERAL_FULL_APP_ID);
msg.setLanguageDesired(Test.GENERAL_LANGUAGE);
msg.setHmiDisplayLanguageDesired(Test.GENERAL_LANGUAGE);
msg.setHashID(Test.GENERAL_STRING);
@@ -45,6 +46,8 @@ public class RegisterAppInterfaceTests extends BaseRpcTests {
msg.setAppHMIType(Test.GENERAL_APPHMITYPE_LIST);
msg.setIsMediaApplication(Test.GENERAL_BOOLEAN);
msg.setDeviceInfo(Test.GENERAL_DEVICEINFO);
+ msg.setDayColorScheme(Test.GENERAL_DAYCOLORSCHEME);
+ msg.setNightColorScheme(Test.GENERAL_NIGHTCOLORSCHEME);
return msg;
}
@@ -67,7 +70,8 @@ public class RegisterAppInterfaceTests extends BaseRpcTests {
result.put(RegisterAppInterface.KEY_SDL_MSG_VERSION, Test.JSON_SDLMSGVERSION);
result.put(RegisterAppInterface.KEY_APP_NAME, Test.GENERAL_STRING);
result.put(RegisterAppInterface.KEY_NGN_MEDIA_SCREEN_APP_NAME, Test.GENERAL_STRING);
- result.put(RegisterAppInterface.KEY_APP_ID, Test.GENERAL_STRING);
+ result.put(RegisterAppInterface.KEY_APP_ID, Test.GENERAL_APP_ID);
+ result.put(RegisterAppInterface.KEY_FULL_APP_ID, Test.GENERAL_FULL_APP_ID);
result.put(RegisterAppInterface.KEY_LANGUAGE_DESIRED, Test.GENERAL_LANGUAGE);
result.put(RegisterAppInterface.KEY_HMI_DISPLAY_LANGUAGE_DESIRED, Test.GENERAL_LANGUAGE);
result.put(RegisterAppInterface.KEY_HASH_ID, Test.GENERAL_STRING);
@@ -76,6 +80,8 @@ public class RegisterAppInterfaceTests extends BaseRpcTests {
result.put(RegisterAppInterface.KEY_APP_HMI_TYPE, JsonUtils.createJsonArrayOfJsonNames(Test.GENERAL_APPHMITYPE_LIST, SDL_VERSION_UNDER_TEST));
result.put(RegisterAppInterface.KEY_IS_MEDIA_APPLICATION, Test.GENERAL_BOOLEAN);
result.put(RegisterAppInterface.KEY_DEVICE_INFO, Test.JSON_DEVICEINFO);
+ result.put(RegisterAppInterface.KEY_DAY_COLOR_SCHEME, Test.JSON_DAYCOLORSCHEME);
+ result.put(RegisterAppInterface.KEY_NIGHT_COLOR_SCHEME, Test.JSON_NIGHTCOLORSCHEME);
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -86,26 +92,30 @@ public class RegisterAppInterfaceTests extends BaseRpcTests {
/**
* Tests the expected values of the RPC message.
*/
- public void testRpcValues () {
+ public void testRpcValues () {
// Test Values
SdlMsgVersion testVersion = ( (RegisterAppInterface) msg).getSdlMsgVersion();
String testName = ( (RegisterAppInterface) msg).getAppName();
String testNgnName = ( (RegisterAppInterface) msg).getNgnMediaScreenAppName();
String testAppId = ( (RegisterAppInterface) msg).getAppID();
+ String testFullAppId = ( (RegisterAppInterface) msg).getFullAppID();
Language testLang = ( (RegisterAppInterface) msg).getLanguageDesired();
Language testHmiLang = ( (RegisterAppInterface) msg).getHmiDisplayLanguageDesired();
String testHashId = ( (RegisterAppInterface) msg).getHashID();
List<TTSChunk> testTts = ( (RegisterAppInterface) msg).getTtsName();
- List<String> testSynonyms = ( (RegisterAppInterface) msg).getVrSynonyms();
+ List<String> testSynonyms = ( (RegisterAppInterface) msg).getVrSynonyms();
List<AppHMIType> testApps = ( (RegisterAppInterface) msg).getAppHMIType();
Boolean testMedia = ( (RegisterAppInterface) msg).getIsMediaApplication();
DeviceInfo testDeviceInfo = ( (RegisterAppInterface) msg).getDeviceInfo();
-
+ TemplateColorScheme testDayColorScheme = ( (RegisterAppInterface) msg).getDayColorScheme();
+ TemplateColorScheme testNightColorScheme = ( (RegisterAppInterface) msg).getNightColorScheme();
+
// Valid Tests
assertTrue(Test.TRUE, Validator.validateSdlMsgVersion(Test.GENERAL_SDLMSGVERSION, testVersion));
assertEquals(Test.MATCH, Test.GENERAL_STRING, testName);
assertEquals(Test.MATCH, Test.GENERAL_STRING, testNgnName);
- assertEquals(Test.MATCH, Test.GENERAL_STRING, testAppId);
+ assertEquals(Test.MATCH, Test.GENERAL_APP_ID, testAppId);
+ assertEquals(Test.MATCH, Test.GENERAL_FULL_APP_ID, testFullAppId);
assertEquals(Test.MATCH, Test.GENERAL_LANGUAGE, testLang);
assertEquals(Test.MATCH, Test.GENERAL_LANGUAGE, testHmiLang);
assertEquals(Test.MATCH, Test.GENERAL_STRING, testHashId);
@@ -114,7 +124,9 @@ public class RegisterAppInterfaceTests extends BaseRpcTests {
assertEquals(Test.MATCH, Test.GENERAL_APPHMITYPE_LIST, testApps);
assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, testMedia);
assertTrue(Test.TRUE, Validator.validateDeviceInfo(Test.GENERAL_DEVICEINFO, testDeviceInfo));
-
+ assertTrue(Test.TRUE, Validator.validateTemplateColorScheme(Test.GENERAL_DAYCOLORSCHEME, testDayColorScheme));
+ assertTrue(Test.TRUE, Validator.validateTemplateColorScheme(Test.GENERAL_NIGHTCOLORSCHEME, testNightColorScheme));
+
// Invalid/Null Tests
RegisterAppInterface msg = new RegisterAppInterface();
assertNotNull(Test.NOT_NULL, msg);
@@ -124,6 +136,7 @@ public class RegisterAppInterfaceTests extends BaseRpcTests {
assertNull(Test.NULL, msg.getAppName());
assertNull(Test.NULL, msg.getNgnMediaScreenAppName());
assertNull(Test.NULL, msg.getAppID());
+ assertNull(Test.NULL, msg.getFullAppID());
assertNull(Test.NULL, msg.getLanguageDesired());
assertNull(Test.NULL, msg.getHmiDisplayLanguageDesired());
assertNull(Test.NULL, msg.getHashID());
@@ -132,6 +145,8 @@ public class RegisterAppInterfaceTests extends BaseRpcTests {
assertNull(Test.NULL, msg.getAppHMIType());
assertNull(Test.NULL, msg.getIsMediaApplication());
assertNull(Test.NULL, msg.getDeviceInfo());
+ assertNull(Test.NULL, msg.getDayColorScheme());
+ assertNull(Test.NULL, msg.getNightColorScheme());
}
/**
@@ -140,14 +155,14 @@ public class RegisterAppInterfaceTests extends BaseRpcTests {
public void testJsonConstructor () {
JSONObject commandJson = JsonFileReader.readId(this.mContext, getCommandType(), getMessageType());
assertNotNull(Test.NOT_NULL, commandJson);
-
+
try {
Hashtable<String, Object> hash = JsonRPCMarshaller.deserializeJSONObject(commandJson);
RegisterAppInterface cmd = new RegisterAppInterface(hash);
-
+
JSONObject body = JsonUtils.readJsonObjectFromJsonObject(commandJson, getMessageType());
assertNotNull(Test.NOT_NULL, body);
-
+
// Test everything in the json body.
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(body, RPCMessage.KEY_FUNCTION_NAME), cmd.getFunctionName());
assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(body, RPCMessage.KEY_CORRELATION_ID), cmd.getCorrelationID());
@@ -161,15 +176,16 @@ public class RegisterAppInterfaceTests extends BaseRpcTests {
}
assertTrue(Test.TRUE, Validator.validateTtsChunks(ttsNameList, cmd.getTtsName()));
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, RegisterAppInterface.KEY_HMI_DISPLAY_LANGUAGE_DESIRED), cmd.getHmiDisplayLanguageDesired().toString());
-
+
JSONArray appHmiTypeArray = JsonUtils.readJsonArrayFromJsonObject(parameters, RegisterAppInterface.KEY_APP_HMI_TYPE);
for (int index = 0; index < appHmiTypeArray.length(); index++) {
AppHMIType appHmiTypeItem = AppHMIType.valueForString( appHmiTypeArray.get(index).toString() );
assertEquals(Test.MATCH, appHmiTypeItem, cmd.getAppHMIType().get(index) );
}
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, RegisterAppInterface.KEY_APP_ID), cmd.getAppID());
+ assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, RegisterAppInterface.KEY_FULL_APP_ID), cmd.getFullAppID());
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, RegisterAppInterface.KEY_LANGUAGE_DESIRED), cmd.getLanguageDesired().toString());
-
+
JSONObject deviceInfoObj = JsonUtils.readJsonObjectFromJsonObject(parameters, RegisterAppInterface.KEY_DEVICE_INFO);
DeviceInfo deviceInfo = new DeviceInfo(JsonRPCMarshaller.deserializeJSONObject(deviceInfoObj));
assertTrue(Test.TRUE, Validator.validateDeviceInfo(deviceInfo, cmd.getDeviceInfo()) );
@@ -181,13 +197,22 @@ public class RegisterAppInterfaceTests extends BaseRpcTests {
List<String> testSynonymsList = cmd.getVrSynonyms();
assertEquals(Test.MATCH, vrSynonymsList.size(), testSynonymsList.size());
assertTrue(Test.TRUE, Validator.validateStringList(vrSynonymsList, testSynonymsList));
-
+
JSONObject sdlMsgVersionObj = JsonUtils.readJsonObjectFromJsonObject(parameters, RegisterAppInterface.KEY_SDL_MSG_VERSION);
SdlMsgVersion sdlMsgVersion = new SdlMsgVersion(JsonRPCMarshaller.deserializeJSONObject(sdlMsgVersionObj));
assertTrue(Test.TRUE, Validator.validateSdlMsgVersion(sdlMsgVersion, cmd.getSdlMsgVersion()) );
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, RegisterAppInterface.KEY_HASH_ID), cmd.getHashID());
+
+ JSONObject dayColorSchemeObj = JsonUtils.readJsonObjectFromJsonObject(parameters, RegisterAppInterface.KEY_DAY_COLOR_SCHEME);
+ TemplateColorScheme dayColorScheme = new TemplateColorScheme(JsonRPCMarshaller.deserializeJSONObject(dayColorSchemeObj));
+ assertTrue(Test.TRUE, Validator.validateTemplateColorScheme(dayColorScheme, cmd.getDayColorScheme()) );
+
+ JSONObject nightColorSchemeObj = JsonUtils.readJsonObjectFromJsonObject(parameters, RegisterAppInterface.KEY_DAY_COLOR_SCHEME);
+ TemplateColorScheme nightColorScheme = new TemplateColorScheme(JsonRPCMarshaller.deserializeJSONObject(nightColorSchemeObj));
+ assertTrue(Test.TRUE, Validator.validateTemplateColorScheme(nightColorScheme, cmd.getDayColorScheme()) );
+
} catch (JSONException e) {
fail(Test.JSON_FAIL);
- }
- }
+ }
+ }
} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetDisplayLayoutTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetDisplayLayoutTests.java
index cb48e812f..d0ccc6fc7 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetDisplayLayoutTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetDisplayLayoutTests.java
@@ -9,9 +9,11 @@ import com.smartdevicelink.marshal.JsonRPCMarshaller;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCMessage;
import com.smartdevicelink.proxy.rpc.SetDisplayLayout;
+import com.smartdevicelink.proxy.rpc.TemplateColorScheme;
import com.smartdevicelink.test.BaseRpcTests;
import com.smartdevicelink.test.JsonUtils;
import com.smartdevicelink.test.Test;
+import com.smartdevicelink.test.Validator;
import com.smartdevicelink.test.json.rpc.JsonFileReader;
@@ -26,6 +28,8 @@ public class SetDisplayLayoutTests extends BaseRpcTests {
SetDisplayLayout msg = new SetDisplayLayout();
msg.setDisplayLayout(Test.GENERAL_STRING);
+ msg.setDayColorScheme(Test.GENERAL_DAYCOLORSCHEME);
+ msg.setNightColorScheme(Test.GENERAL_NIGHTCOLORSCHEME);
return msg;
}
@@ -45,7 +49,9 @@ public class SetDisplayLayoutTests extends BaseRpcTests {
JSONObject result = new JSONObject();
try {
- result.put(SetDisplayLayout.KEY_DISPLAY_LAYOUT, Test.GENERAL_STRING);
+ result.put(SetDisplayLayout.KEY_DISPLAY_LAYOUT, Test.GENERAL_STRING);
+ result.put(SetDisplayLayout.KEY_DAY_COLOR_SCHEME, Test.JSON_DAYCOLORSCHEME);
+ result.put(SetDisplayLayout.KEY_NIGHT_COLOR_SCHEME, Test.JSON_NIGHTCOLORSCHEME);
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -59,9 +65,13 @@ public class SetDisplayLayoutTests extends BaseRpcTests {
public void testRpcValues () {
// Test Values
String testDisplayLayout = ( (SetDisplayLayout) msg ).getDisplayLayout();
+ TemplateColorScheme testDayColorScheme = ( (SetDisplayLayout) msg).getDayColorScheme();
+ TemplateColorScheme testNightColorScheme = ( (SetDisplayLayout) msg).getNightColorScheme();
// Valid Tests
- assertEquals("Data didn't match input data.", Test.GENERAL_STRING, testDisplayLayout);
+ assertEquals(Test.MATCH, Test.GENERAL_STRING, testDisplayLayout);
+ assertTrue(Test.TRUE, Validator.validateTemplateColorScheme(Test.GENERAL_DAYCOLORSCHEME, testDayColorScheme));
+ assertTrue(Test.TRUE, Validator.validateTemplateColorScheme(Test.GENERAL_NIGHTCOLORSCHEME, testNightColorScheme));
// Invalid/Null Tests
SetDisplayLayout msg = new SetDisplayLayout();
@@ -69,6 +79,8 @@ public class SetDisplayLayoutTests extends BaseRpcTests {
testNullBase(msg);
assertNull(Test.NULL, msg.getDisplayLayout());
+ assertNull(Test.NULL, msg.getDayColorScheme());
+ assertNull(Test.NULL, msg.getNightColorScheme());
}
/**
@@ -91,6 +103,16 @@ public class SetDisplayLayoutTests extends BaseRpcTests {
JSONObject parameters = JsonUtils.readJsonObjectFromJsonObject(body, RPCMessage.KEY_PARAMETERS);
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, SetDisplayLayout.KEY_DISPLAY_LAYOUT), cmd.getDisplayLayout());
+
+
+ JSONObject dayColorSchemeObj = JsonUtils.readJsonObjectFromJsonObject(parameters, SetDisplayLayout.KEY_DAY_COLOR_SCHEME);
+ TemplateColorScheme dayColorScheme = new TemplateColorScheme(JsonRPCMarshaller.deserializeJSONObject(dayColorSchemeObj));
+ assertTrue(Test.TRUE, Validator.validateTemplateColorScheme(dayColorScheme, cmd.getDayColorScheme()) );
+
+ JSONObject nightColorSchemeObj = JsonUtils.readJsonObjectFromJsonObject(parameters, SetDisplayLayout.KEY_DAY_COLOR_SCHEME);
+ TemplateColorScheme nightColorScheme = new TemplateColorScheme(JsonRPCMarshaller.deserializeJSONObject(nightColorSchemeObj));
+ assertTrue(Test.TRUE, Validator.validateTemplateColorScheme(nightColorScheme, cmd.getDayColorScheme()) );
+
} catch (JSONException e) {
fail(Test.JSON_FAIL);
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetMediaClockTimerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetMediaClockTimerTests.java
index 7d52bb75c..a90bd31b9 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetMediaClockTimerTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SetMediaClockTimerTests.java
@@ -10,6 +10,7 @@ import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCMessage;
import com.smartdevicelink.proxy.rpc.SetMediaClockTimer;
import com.smartdevicelink.proxy.rpc.StartTime;
+import com.smartdevicelink.proxy.rpc.enums.AudioStreamingIndicator;
import com.smartdevicelink.proxy.rpc.enums.UpdateMode;
import com.smartdevicelink.test.BaseRpcTests;
import com.smartdevicelink.test.JsonUtils;
@@ -19,7 +20,7 @@ import com.smartdevicelink.test.json.rpc.JsonFileReader;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.SetMediaClockTimer}
+ * {@link com.smartdevicelink.proxy.rpc.SetMediaClockTimer}
*/
public class SetMediaClockTimerTests extends BaseRpcTests {
@@ -30,6 +31,7 @@ public class SetMediaClockTimerTests extends BaseRpcTests {
msg.setStartTime(Test.GENERAL_STARTTIME);
msg.setEndTime(Test.GENERAL_STARTTIME);
msg.setUpdateMode(Test.GENERAL_UPDATEMODE);
+ msg.setAudioStreamingIndicator(Test.GENERAL_AUDIO_STREAMING_INDICATOR);
return msg;
}
@@ -51,7 +53,8 @@ public class SetMediaClockTimerTests extends BaseRpcTests {
try {
result.put(SetMediaClockTimer.KEY_START_TIME, Test.JSON_STARTTIME);
result.put(SetMediaClockTimer.KEY_END_TIME, Test.JSON_STARTTIME);
- result.put(SetMediaClockTimer.KEY_UPDATE_MODE, Test.GENERAL_UPDATEMODE);
+ result.put(SetMediaClockTimer.KEY_UPDATE_MODE, Test.GENERAL_UPDATEMODE);
+ result.put(SetMediaClockTimer.KEY_AUDIO_STREAMING_INDICATOR, Test.GENERAL_AUDIO_STREAMING_INDICATOR);
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -67,9 +70,11 @@ public class SetMediaClockTimerTests extends BaseRpcTests {
StartTime testStartTime = ( (SetMediaClockTimer) msg ).getStartTime();
StartTime testEndTime = ( (SetMediaClockTimer) msg ).getEndTime();
UpdateMode testUpdateMode = ( (SetMediaClockTimer) msg ).getUpdateMode();
+ AudioStreamingIndicator testAudioStreamingIndicator = ( (SetMediaClockTimer) msg ).getAudioStreamingIndicator();
// Valid Tests
assertEquals(Test.MATCH, Test.GENERAL_UPDATEMODE, testUpdateMode);
+ assertEquals(Test.MATCH, Test.GENERAL_AUDIO_STREAMING_INDICATOR, testAudioStreamingIndicator);
assertTrue(Test.TRUE, Validator.validateStartTime(Test.GENERAL_STARTTIME, testStartTime));
assertTrue(Test.TRUE, Validator.validateStartTime(Test.GENERAL_STARTTIME, testEndTime));
@@ -81,6 +86,7 @@ public class SetMediaClockTimerTests extends BaseRpcTests {
assertNull(Test.NULL, msg.getStartTime());
assertNull(Test.NULL, msg.getEndTime());
assertNull(Test.NULL, msg.getUpdateMode());
+ assertNull(Test.NULL, msg.getAudioStreamingIndicator());
}
/**
@@ -110,6 +116,7 @@ public class SetMediaClockTimerTests extends BaseRpcTests {
StartTime referenceEndTime = new StartTime(JsonRPCMarshaller.deserializeJSONObject(endTime));
assertTrue(Test.TRUE, Validator.validateStartTime(referenceEndTime, cmd.getEndTime()));
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, SetMediaClockTimer.KEY_UPDATE_MODE), cmd.getUpdateMode().toString());
+ assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, SetMediaClockTimer.KEY_AUDIO_STREAMING_INDICATOR), cmd.getAudioStreamingIndicator().toString());
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SubscribeVehicleDataTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SubscribeVehicleDataTests.java
index 83cdf0dcf..ce93c52ea 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SubscribeVehicleDataTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SubscribeVehicleDataTests.java
@@ -16,7 +16,7 @@ import com.smartdevicelink.test.json.rpc.JsonFileReader;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.SubscribeVehicleData}
+ * {@link com.smartdevicelink.proxy.rpc.SubscribeVehicleData}
*/
public class SubscribeVehicleDataTests extends BaseRpcTests {
@@ -31,6 +31,7 @@ public class SubscribeVehicleDataTests extends BaseRpcTests {
msg.setPrndl(Test.GENERAL_BOOLEAN);
msg.setTirePressure(Test.GENERAL_BOOLEAN);
msg.setEngineTorque(Test.GENERAL_BOOLEAN);
+ msg.setEngineOilLife(Test.GENERAL_BOOLEAN);
msg.setOdometer(Test.GENERAL_BOOLEAN);
msg.setGps(Test.GENERAL_BOOLEAN);
msg.setFuelLevelState(Test.GENERAL_BOOLEAN);
@@ -48,6 +49,9 @@ public class SubscribeVehicleDataTests extends BaseRpcTests {
msg.setEmergencyEvent(Test.GENERAL_BOOLEAN);
msg.setClusterModeStatus(Test.GENERAL_BOOLEAN);
msg.setMyKey(Test.GENERAL_BOOLEAN);
+ msg.setFuelRange(Test.GENERAL_BOOLEAN);
+ msg.setTurnSignal(Test.GENERAL_BOOLEAN);
+ msg.setElectronicParkBrakeStatus(Test.GENERAL_BOOLEAN);
return msg;
}
@@ -74,6 +78,7 @@ public class SubscribeVehicleDataTests extends BaseRpcTests {
result.put(SubscribeVehicleData.KEY_PRNDL, Test.GENERAL_BOOLEAN);
result.put(SubscribeVehicleData.KEY_TIRE_PRESSURE, Test.GENERAL_BOOLEAN);
result.put(SubscribeVehicleData.KEY_ENGINE_TORQUE, Test.GENERAL_BOOLEAN);
+ result.put(SubscribeVehicleData.KEY_ENGINE_OIL_LIFE, Test.GENERAL_BOOLEAN);
result.put(SubscribeVehicleData.KEY_ODOMETER, Test.GENERAL_BOOLEAN);
result.put(SubscribeVehicleData.KEY_GPS, Test.GENERAL_BOOLEAN);
result.put(SubscribeVehicleData.KEY_FUEL_LEVEL_STATE, Test.GENERAL_BOOLEAN);
@@ -91,6 +96,9 @@ public class SubscribeVehicleDataTests extends BaseRpcTests {
result.put(SubscribeVehicleData.KEY_EMERGENCY_EVENT, Test.GENERAL_BOOLEAN);
result.put(SubscribeVehicleData.KEY_CLUSTER_MODE_STATUS, Test.GENERAL_BOOLEAN);
result.put(SubscribeVehicleData.KEY_MY_KEY, Test.GENERAL_BOOLEAN);
+ result.put(SubscribeVehicleData.KEY_FUEL_RANGE, Test.GENERAL_BOOLEAN);
+ result.put(SubscribeVehicleData.KEY_TURN_SIGNAL, Test.GENERAL_BOOLEAN);
+ result.put(SubscribeVehicleData.KEY_ELECTRONIC_PARK_BRAKE_STATUS, Test.GENERAL_BOOLEAN);
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -111,6 +119,7 @@ public class SubscribeVehicleDataTests extends BaseRpcTests {
assertTrue(Test.MATCH,( (SubscribeVehicleData) msg ).getPrndl());
assertTrue(Test.MATCH,( (SubscribeVehicleData) msg ).getTirePressure());
assertTrue(Test.MATCH,( (SubscribeVehicleData) msg ).getEngineTorque());
+ assertTrue(Test.MATCH,( (SubscribeVehicleData) msg ).getEngineOilLife());
assertTrue(Test.MATCH,( (SubscribeVehicleData) msg ).getOdometer());
assertTrue(Test.MATCH,( (SubscribeVehicleData) msg ).getGps());
assertTrue(Test.MATCH,( (SubscribeVehicleData) msg ).getFuelLevelState());
@@ -128,6 +137,9 @@ public class SubscribeVehicleDataTests extends BaseRpcTests {
assertTrue(Test.MATCH,( (SubscribeVehicleData) msg ).getEmergencyEvent());
assertTrue(Test.MATCH,( (SubscribeVehicleData) msg ).getClusterModeStatus());
assertTrue(Test.MATCH,( (SubscribeVehicleData) msg ).getMyKey());
+ assertTrue(Test.MATCH,( (SubscribeVehicleData) msg ).getFuelRange());
+ assertTrue(Test.MATCH,( (SubscribeVehicleData) msg ).getTurnSignal());
+ assertTrue(Test.MATCH,( (SubscribeVehicleData) msg ).getElectronicParkBrakeStatus());
// Invalid/Null Tests
SubscribeVehicleData msg = new SubscribeVehicleData();
@@ -153,11 +165,15 @@ public class SubscribeVehicleDataTests extends BaseRpcTests {
assertNull(Test.NULL, msg.getDeviceStatus());
assertNull(Test.NULL, msg.getHeadLampStatus());
assertNull(Test.NULL, msg.getEngineTorque());
+ assertNull(Test.NULL, msg.getEngineOilLife());
assertNull(Test.NULL, msg.getSteeringWheelAngle());
assertNull(Test.NULL, msg.getECallInfo());
assertNull(Test.NULL, msg.getEmergencyEvent());
assertNull(Test.NULL, msg.getClusterModeStatus());
assertNull(Test.NULL, msg.getMyKey());
+ assertNull(Test.NULL, msg.getFuelRange());
+ assertNull(Test.NULL, msg.getTurnSignal());
+ assertNull(Test.NULL, msg.getElectronicParkBrakeStatus());
}
/**
@@ -186,6 +202,7 @@ public class SubscribeVehicleDataTests extends BaseRpcTests {
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_PRNDL), cmd.getPrndl());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_TIRE_PRESSURE), cmd.getTirePressure());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_ENGINE_TORQUE), cmd.getEngineTorque());
+ assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_ENGINE_OIL_LIFE), cmd.getEngineOilLife());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_ODOMETER), cmd.getOdometer());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_GPS), cmd.getGps());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_FUEL_LEVEL_STATE), cmd.getFuelLevelState());
@@ -202,7 +219,10 @@ public class SubscribeVehicleDataTests extends BaseRpcTests {
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_AIRBAG_STATUS), cmd.getAirbagStatus());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_EMERGENCY_EVENT), cmd.getEmergencyEvent());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_CLUSTER_MODE_STATUS), cmd.getClusterModeStatus());
- assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_MY_KEY), cmd.getMyKey());
+ assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_MY_KEY), cmd.getMyKey());
+ assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_FUEL_RANGE), cmd.getFuelRange());
+ assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_TURN_SIGNAL), cmd.getTurnSignal());
+ assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, SubscribeVehicleData.KEY_ELECTRONIC_PARK_BRAKE_STATUS), cmd.getElectronicParkBrakeStatus());
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SystemRequestTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SystemRequestTests.java
index 11f3f42a2..9ca720198 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SystemRequestTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/SystemRequestTests.java
@@ -30,6 +30,7 @@ public class SystemRequestTests extends BaseRpcTests {
msg.setLegacyData(Test.GENERAL_STRING_LIST);
msg.setFileName(Test.GENERAL_STRING);
msg.setRequestType(Test.GENERAL_REQUESTTYPE);
+ msg.setRequestSubType(Test.GENERAL_STRING);
return msg;
}
@@ -51,7 +52,8 @@ public class SystemRequestTests extends BaseRpcTests {
try {
result.put(SystemRequest.KEY_DATA, JsonUtils.createJsonArray(Test.GENERAL_STRING_LIST));
result.put(SystemRequest.KEY_FILE_NAME, Test.GENERAL_STRING);
- result.put(SystemRequest.KEY_REQUEST_TYPE, Test.GENERAL_REQUESTTYPE);
+ result.put(SystemRequest.KEY_REQUEST_TYPE, Test.GENERAL_REQUESTTYPE);
+ result.put(SystemRequest.KEY_REQUEST_SUB_TYPE, Test.GENERAL_STRING);
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -65,11 +67,13 @@ public class SystemRequestTests extends BaseRpcTests {
public void testRpcValues () {
// Test Values
RequestType testRequestType = ( (SystemRequest) msg ).getRequestType();
+ String testRequestSubType = ( (SystemRequest) msg ).getRequestSubType();
String testFileName = ( (SystemRequest) msg ).getFileName();
List<String> testLegacyData = ( (SystemRequest) msg ).getLegacyData();
// Valid Tests
assertEquals(Test.MATCH, Test.GENERAL_REQUESTTYPE, testRequestType);
+ assertEquals(Test.MATCH, Test.GENERAL_STRING, testRequestSubType);
assertEquals(Test.MATCH, Test.GENERAL_STRING, testFileName);
assertTrue(Test.TRUE, Validator.validateStringList(Test.GENERAL_STRING_LIST, testLegacyData));
@@ -81,6 +85,7 @@ public class SystemRequestTests extends BaseRpcTests {
assertNull(Test.NULL, msg.getLegacyData());
assertNull(Test.NULL, msg.getFileName());
assertNull(Test.NULL, msg.getRequestType());
+ assertNull(Test.NULL, msg.getRequestSubType());
assertNull(Test.NULL, msg.getBulkData());
}
@@ -105,6 +110,7 @@ public class SystemRequestTests extends BaseRpcTests {
JSONObject parameters = JsonUtils.readJsonObjectFromJsonObject(body, RPCMessage.KEY_PARAMETERS);
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, SystemRequest.KEY_FILE_NAME), cmd.getFileName());
assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, SystemRequest.KEY_REQUEST_TYPE), cmd.getRequestType().toString());
+ assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, SystemRequest.KEY_REQUEST_SUB_TYPE), cmd.getRequestSubType());
List<String> dataList = JsonUtils.readStringListFromJsonObject(parameters, SystemRequest.KEY_DATA);
List<String> testDataList = cmd.getLegacyData();
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/UnsubscribeVehicleDataTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/UnsubscribeVehicleDataTests.java
index 15cd321af..af8560410 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/UnsubscribeVehicleDataTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/requests/UnsubscribeVehicleDataTests.java
@@ -17,7 +17,7 @@ import com.smartdevicelink.test.json.rpc.JsonFileReader;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.UnsubscribeVehicleData}
+ * {@link com.smartdevicelink.proxy.rpc.UnsubscribeVehicleData}
*/
public class UnsubscribeVehicleDataTests extends BaseRpcTests {
@@ -32,6 +32,7 @@ public class UnsubscribeVehicleDataTests extends BaseRpcTests {
msg.setPrndl(Test.GENERAL_BOOLEAN);
msg.setTirePressure(Test.GENERAL_BOOLEAN);
msg.setEngineTorque(Test.GENERAL_BOOLEAN);
+ msg.setEngineOilLife(Test.GENERAL_BOOLEAN);
msg.setOdometer(Test.GENERAL_BOOLEAN);
msg.setGps(Test.GENERAL_BOOLEAN);
msg.setFuelLevelState(Test.GENERAL_BOOLEAN);
@@ -49,6 +50,9 @@ public class UnsubscribeVehicleDataTests extends BaseRpcTests {
msg.setEmergencyEvent(Test.GENERAL_BOOLEAN);
msg.setClusterModeStatus(Test.GENERAL_BOOLEAN);
msg.setMyKey(Test.GENERAL_BOOLEAN);
+ msg.setFuelRange(Test.GENERAL_BOOLEAN);
+ msg.setTurnSignal(Test.GENERAL_BOOLEAN);
+ msg.setElectronicParkBrakeStatus(Test.GENERAL_BOOLEAN);
return msg;
}
@@ -75,6 +79,7 @@ public class UnsubscribeVehicleDataTests extends BaseRpcTests {
result.put(UnsubscribeVehicleData.KEY_PRNDL, Test.GENERAL_BOOLEAN);
result.put(UnsubscribeVehicleData.KEY_TIRE_PRESSURE, Test.GENERAL_BOOLEAN);
result.put(UnsubscribeVehicleData.KEY_ENGINE_TORQUE, Test.GENERAL_BOOLEAN);
+ result.put(UnsubscribeVehicleData.KEY_ENGINE_OIL_LIFE, Test.GENERAL_BOOLEAN);
result.put(UnsubscribeVehicleData.KEY_ODOMETER, Test.GENERAL_BOOLEAN);
result.put(UnsubscribeVehicleData.KEY_GPS, Test.GENERAL_BOOLEAN);
result.put(UnsubscribeVehicleData.KEY_FUEL_LEVEL_STATE, Test.GENERAL_BOOLEAN);
@@ -91,7 +96,10 @@ public class UnsubscribeVehicleDataTests extends BaseRpcTests {
result.put(UnsubscribeVehicleData.KEY_AIRBAG_STATUS, Test.GENERAL_BOOLEAN);
result.put(UnsubscribeVehicleData.KEY_EMERGENCY_EVENT, Test.GENERAL_BOOLEAN);
result.put(UnsubscribeVehicleData.KEY_CLUSTER_MODE_STATUS, Test.GENERAL_BOOLEAN);
- result.put(UnsubscribeVehicleData.KEY_MY_KEY, Test.GENERAL_BOOLEAN);
+ result.put(UnsubscribeVehicleData.KEY_MY_KEY, Test.GENERAL_BOOLEAN);
+ result.put(UnsubscribeVehicleData.KEY_FUEL_RANGE, Test.GENERAL_BOOLEAN);
+ result.put(UnsubscribeVehicleData.KEY_TURN_SIGNAL, Test.GENERAL_BOOLEAN);
+ result.put(UnsubscribeVehicleData.KEY_ELECTRONIC_PARK_BRAKE_STATUS, Test.GENERAL_BOOLEAN);
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -111,6 +119,7 @@ public class UnsubscribeVehicleDataTests extends BaseRpcTests {
assertTrue(Test.TRUE,( (UnsubscribeVehicleData) msg ).getPrndl());
assertTrue(Test.TRUE,( (UnsubscribeVehicleData) msg ).getTirePressure());
assertTrue(Test.TRUE,( (UnsubscribeVehicleData) msg ).getEngineTorque());
+ assertTrue(Test.TRUE,( (UnsubscribeVehicleData) msg ).getEngineOilLife());
assertTrue(Test.TRUE,( (UnsubscribeVehicleData) msg ).getOdometer());
assertTrue(Test.TRUE,( (UnsubscribeVehicleData) msg ).getGps());
assertTrue(Test.TRUE,( (UnsubscribeVehicleData) msg ).getFuelLevelState());
@@ -128,6 +137,9 @@ public class UnsubscribeVehicleDataTests extends BaseRpcTests {
assertTrue(Test.TRUE,( (UnsubscribeVehicleData) msg ).getEmergencyEvent());
assertTrue(Test.TRUE,( (UnsubscribeVehicleData) msg ).getClusterModeStatus());
assertTrue(Test.TRUE,( (UnsubscribeVehicleData) msg ).getMyKey());
+ assertTrue(Test.TRUE,( (UnsubscribeVehicleData) msg ).getFuelRange());
+ assertTrue(Test.TRUE,( (UnsubscribeVehicleData) msg ).getTurnSignal());
+ assertTrue(Test.TRUE,( (UnsubscribeVehicleData) msg ).getElectronicParkBrakeStatus());
// Invalid/Null Tests
UnsubscribeVehicleData msg = new UnsubscribeVehicleData();
@@ -153,12 +165,16 @@ public class UnsubscribeVehicleDataTests extends BaseRpcTests {
assertNull(Test.NULL, msg.getDeviceStatus());
assertNull(Test.NULL, msg.getHeadLampStatus());
assertNull(Test.NULL, msg.getEngineTorque());
+ assertNull(Test.NULL, msg.getEngineOilLife());
assertNull(Test.NULL, msg.getSteeringWheelAngle());
assertNull(Test.NULL, msg.getECallInfo());
assertNull(Test.NULL, msg.getEmergencyEvent());
assertNull(Test.NULL, msg.getClusterModeStatus());
- assertNull(Test.NULL, msg.getMyKey());
- }
+ assertNull(Test.NULL, msg.getMyKey());
+ assertNull(Test.NULL, msg.getFuelRange());
+ assertNull(Test.NULL, msg.getTurnSignal());
+ assertNull(Test.NULL, msg.getElectronicParkBrakeStatus());
+ }
/**
* Tests a valid JSON construction of this RPC message.
@@ -186,6 +202,7 @@ public class UnsubscribeVehicleDataTests extends BaseRpcTests {
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_PRNDL), cmd.getPrndl());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_TIRE_PRESSURE), cmd.getTirePressure());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_ENGINE_TORQUE), cmd.getEngineTorque());
+ assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_ENGINE_OIL_LIFE), cmd.getEngineOilLife());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_ODOMETER), cmd.getOdometer());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_GPS), cmd.getGps());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_FUEL_LEVEL_STATE), cmd.getFuelLevelState());
@@ -202,7 +219,10 @@ public class UnsubscribeVehicleDataTests extends BaseRpcTests {
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_AIRBAG_STATUS), cmd.getAirbagStatus());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_EMERGENCY_EVENT), cmd.getEmergencyEvent());
assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_CLUSTER_MODE_STATUS), cmd.getClusterModeStatus());
- assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_MY_KEY), cmd.getMyKey());
+ assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_MY_KEY), cmd.getMyKey());
+ assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_FUEL_RANGE), cmd.getFuelRange());
+ assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_TURN_SIGNAL), cmd.getTurnSignal());
+ assertEquals(Test.MATCH, JsonUtils.readBooleanFromJsonObject(parameters, UnsubscribeVehicleData.KEY_ELECTRONIC_PARK_BRAKE_STATUS), cmd.getElectronicParkBrakeStatus());
}
catch (JSONException e) {
fail(Test.JSON_FAIL);
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/DeleteFileResponseTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/DeleteFileResponseTests.java
index 9d6886802..2c4ecb01f 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/DeleteFileResponseTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/DeleteFileResponseTests.java
@@ -16,7 +16,7 @@ import com.smartdevicelink.test.json.rpc.JsonFileReader;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.DeleteFileResponse}
+ * {@link com.smartdevicelink.proxy.rpc.DeleteFileResponse}
*/
public class DeleteFileResponseTests extends BaseRpcTests{
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/GetVehicleDataResponseTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/GetVehicleDataResponseTests.java
index 314a2f419..2bcff82ee 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/GetVehicleDataResponseTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/GetVehicleDataResponseTests.java
@@ -1,8 +1,11 @@
package com.smartdevicelink.test.rpc.responses;
+import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
+import java.util.List;
+import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -16,12 +19,14 @@ import com.smartdevicelink.proxy.rpc.ClusterModeStatus;
import com.smartdevicelink.proxy.rpc.DeviceStatus;
import com.smartdevicelink.proxy.rpc.ECallInfo;
import com.smartdevicelink.proxy.rpc.EmergencyEvent;
+import com.smartdevicelink.proxy.rpc.FuelRange;
import com.smartdevicelink.proxy.rpc.GPSData;
import com.smartdevicelink.proxy.rpc.GetVehicleDataResponse;
import com.smartdevicelink.proxy.rpc.HeadLampStatus;
import com.smartdevicelink.proxy.rpc.MyKey;
import com.smartdevicelink.proxy.rpc.SingleTireStatus;
import com.smartdevicelink.proxy.rpc.TireStatus;
+import com.smartdevicelink.proxy.rpc.enums.TurnSignal;
import com.smartdevicelink.test.BaseRpcTests;
import com.smartdevicelink.test.JsonUtils;
import com.smartdevicelink.test.Test;
@@ -32,7 +37,7 @@ import com.smartdevicelink.test.json.rpc.JsonFileReader;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.GetVehicleDataResponse}
+ * {@link com.smartdevicelink.proxy.rpc.GetVehicleDataResponse}
*/
public class GetVehicleDataResponseTests extends BaseRpcTests{
@@ -64,6 +69,7 @@ public class GetVehicleDataResponseTests extends BaseRpcTests{
result.put(GetVehicleDataResponse.KEY_PRNDL, VehicleDataHelper.PRNDL_FINAL);
result.put(GetVehicleDataResponse.KEY_TIRE_PRESSURE, VehicleDataHelper.TIRE_PRESSURE.serializeJSON());
result.put(GetVehicleDataResponse.KEY_ENGINE_TORQUE, VehicleDataHelper.ENGINE_TORQUE);
+ result.put(GetVehicleDataResponse.KEY_ENGINE_OIL_LIFE, VehicleDataHelper.ENGINE_OIL_LIFE);
result.put(GetVehicleDataResponse.KEY_ODOMETER, VehicleDataHelper.ODOMETER);
result.put(GetVehicleDataResponse.KEY_GPS, VehicleDataHelper.GPS.serializeJSON());
result.put(GetVehicleDataResponse.KEY_FUEL_LEVEL_STATE, VehicleDataHelper.FUEL_LEVEL_STATE);
@@ -81,6 +87,9 @@ public class GetVehicleDataResponseTests extends BaseRpcTests{
result.put(GetVehicleDataResponse.KEY_EMERGENCY_EVENT, VehicleDataHelper.EMERGENCY_EVENT.serializeJSON());
result.put(GetVehicleDataResponse.KEY_CLUSTER_MODE_STATUS, VehicleDataHelper.CLUSTER_MODE_STATUS.serializeJSON());
result.put(GetVehicleDataResponse.KEY_MY_KEY, VehicleDataHelper.MY_KEY.serializeJSON());
+ result.put(GetVehicleDataResponse.KEY_FUEL_RANGE, VehicleDataHelper.JSON_FUEL_RANGE);
+ result.put(GetVehicleDataResponse.KEY_TURN_SIGNAL, VehicleDataHelper.TURN_SIGNAL);
+ result.put(GetVehicleDataResponse.KEY_ELECTRONIC_PARK_BRAKE_STATUS, VehicleDataHelper.ELECTRONIC_PARK_BRAKE_STATUS);
} catch(JSONException e){
fail(Test.JSON_FAIL);
}
@@ -103,6 +112,8 @@ public class GetVehicleDataResponseTests extends BaseRpcTests{
JSONObject emergencyEventObj = new JSONObject();
JSONObject clusterModeStatusObj = new JSONObject();
JSONObject myKeyObj = new JSONObject();
+ JSONObject fuelRangeObj = new JSONObject();
+ JSONArray fuelRangeArrayObj = new JSONArray();
try {
//set up the JSONObject to represent GetVehicleDataResponse
@@ -221,7 +232,12 @@ public class GetVehicleDataResponseTests extends BaseRpcTests{
//MY_KEY
myKeyObj.put(MyKey.KEY_E_911_OVERRIDE, VehicleDataHelper.MY_KEY_E_911_OVERRIDE);
-
+
+ // FUEL_RANGE
+ fuelRangeObj.put(FuelRange.KEY_TYPE, VehicleDataHelper.FUEL_RANGE_TYPE);
+ fuelRangeObj.put(FuelRange.KEY_RANGE, VehicleDataHelper.FUEL_RANGE_RANGE);
+ fuelRangeArrayObj.put(fuelRangeObj);
+
reference.put(GetVehicleDataResponse.KEY_SPEED, VehicleDataHelper.SPEED);
reference.put(GetVehicleDataResponse.KEY_RPM, VehicleDataHelper.RPM);
reference.put(GetVehicleDataResponse.KEY_EXTERNAL_TEMPERATURE, VehicleDataHelper.EXTERNAL_TEMPERATURE);
@@ -230,6 +246,7 @@ public class GetVehicleDataResponseTests extends BaseRpcTests{
reference.put(GetVehicleDataResponse.KEY_PRNDL, VehicleDataHelper.PRNDL_FINAL);
reference.put(GetVehicleDataResponse.KEY_TIRE_PRESSURE, tireStatusObj);
reference.put(GetVehicleDataResponse.KEY_ENGINE_TORQUE, VehicleDataHelper.ENGINE_TORQUE);
+ reference.put(GetVehicleDataResponse.KEY_ENGINE_OIL_LIFE, VehicleDataHelper.ENGINE_OIL_LIFE);
reference.put(GetVehicleDataResponse.KEY_ODOMETER, VehicleDataHelper.ODOMETER);
reference.put(GetVehicleDataResponse.KEY_GPS, GPSDataObj);
reference.put(GetVehicleDataResponse.KEY_FUEL_LEVEL_STATE, VehicleDataHelper.FUEL_LEVEL_STATE);
@@ -247,6 +264,9 @@ public class GetVehicleDataResponseTests extends BaseRpcTests{
reference.put(GetVehicleDataResponse.KEY_EMERGENCY_EVENT, emergencyEventObj);
reference.put(GetVehicleDataResponse.KEY_CLUSTER_MODE_STATUS, clusterModeStatusObj);
reference.put(GetVehicleDataResponse.KEY_MY_KEY, myKeyObj);
+ reference.put(GetVehicleDataResponse.KEY_FUEL_RANGE, fuelRangeArrayObj);
+ reference.put(GetVehicleDataResponse.KEY_TURN_SIGNAL, TurnSignal.OFF);
+ reference.put(GetVehicleDataResponse.KEY_ELECTRONIC_PARK_BRAKE_STATUS, VehicleDataHelper.ELECTRONIC_PARK_BRAKE_STATUS);
JSONObject underTest = msg.serializeJSON();
@@ -360,6 +380,30 @@ public class GetVehicleDataResponseTests extends BaseRpcTests{
new MyKey(JsonRPCMarshaller.deserializeJSONObject(myKeyObjReference)),
new MyKey(JsonRPCMarshaller.deserializeJSONObject(myKeyObjTest))));
}
+ else if (key.equals(GetVehicleDataResponse.KEY_ENGINE_OIL_LIFE)) {
+ assertEquals("JSON value didn't match expected value for key \"" + key + "\".",
+ JsonUtils.readDoubleFromJsonObject(reference, key), JsonUtils.readDoubleFromJsonObject(underTest, key));
+ }
+ else if (key.equals(GetVehicleDataResponse.KEY_FUEL_RANGE)) {
+ JSONArray fuelRangeArrayObjReference = JsonUtils.readJsonArrayFromJsonObject(reference, key);
+ List<FuelRange> fuelRangeRefereceList = new ArrayList<FuelRange>();
+ for (int index = 0; index < fuelRangeArrayObjReference.length(); index++) {
+ FuelRange fuelRange = new FuelRange(JsonRPCMarshaller.deserializeJSONObject( (JSONObject)fuelRangeArrayObjReference.get(index) ));
+ fuelRangeRefereceList.add(fuelRange);
+ }
+
+ JSONArray fuelRangeArrayObjTest = JsonUtils.readJsonArrayFromJsonObject(underTest, key);
+ List<FuelRange> fuelRangeUnderTestList = new ArrayList<FuelRange>();
+ for (int index = 0; index < fuelRangeArrayObjTest.length(); index++) {
+ FuelRange fuelRange = new FuelRange(JsonRPCMarshaller.deserializeJSONObject( (JSONObject)fuelRangeArrayObjTest.get(index) ));
+ fuelRangeUnderTestList.add(fuelRange);
+ }
+
+ assertTrue("JSON value didn't match expected value for key \"" + key + "\".",
+ Validator.validateFuelRange(
+ fuelRangeRefereceList,
+ fuelRangeUnderTestList));
+ }
else {
assertEquals("JSON value didn't match expected value for key \"" + key + "\".",
JsonUtils.readObjectFromJsonObject(reference, key),
@@ -385,6 +429,7 @@ public class GetVehicleDataResponseTests extends BaseRpcTests{
assertEquals(Test.MATCH, VehicleDataHelper.PRNDL_FINAL, ( (GetVehicleDataResponse) msg ).getPrndl());
assertEquals(Test.MATCH, VehicleDataHelper.TIRE_PRESSURE, ( (GetVehicleDataResponse) msg ).getTirePressure());
assertEquals(Test.MATCH, VehicleDataHelper.ENGINE_TORQUE, ( (GetVehicleDataResponse) msg ).getEngineTorque());
+ assertEquals(Test.MATCH, VehicleDataHelper.ENGINE_OIL_LIFE, ( (GetVehicleDataResponse) msg ).getEngineOilLife());
assertEquals(Test.MATCH, (Integer) VehicleDataHelper.ODOMETER, ( (GetVehicleDataResponse) msg ).getOdometer());
assertEquals(Test.MATCH, VehicleDataHelper.GPS, ( (GetVehicleDataResponse) msg ).getGps());
assertEquals(Test.MATCH, VehicleDataHelper.FUEL_LEVEL_STATE, ( (GetVehicleDataResponse) msg ).getFuelLevelState());
@@ -402,6 +447,8 @@ public class GetVehicleDataResponseTests extends BaseRpcTests{
assertEquals(Test.MATCH, VehicleDataHelper.EMERGENCY_EVENT, ( (GetVehicleDataResponse) msg ).getEmergencyEvent());
assertEquals(Test.MATCH, VehicleDataHelper.CLUSTER_MODE_STATUS, ( (GetVehicleDataResponse) msg ).getClusterModeStatus());
assertEquals(Test.MATCH, VehicleDataHelper.MY_KEY, ( (GetVehicleDataResponse) msg ).getMyKey());
+ assertEquals(Test.MATCH, VehicleDataHelper.TURN_SIGNAL, ( (GetVehicleDataResponse) msg ).getTurnSignal());
+ assertEquals(Test.MATCH, VehicleDataHelper.ELECTRONIC_PARK_BRAKE_STATUS, ( (GetVehicleDataResponse) msg ).getElectronicParkBrakeStatus());
// Invalid/Null Tests
GetVehicleDataResponse msg = new GetVehicleDataResponse();
@@ -427,11 +474,14 @@ public class GetVehicleDataResponseTests extends BaseRpcTests{
assertNull(Test.NULL, msg.getDeviceStatus());
assertNull(Test.NULL, msg.getHeadLampStatus());
assertNull(Test.NULL, msg.getEngineTorque());
+ assertNull(Test.NULL, msg.getEngineOilLife());
assertNull(Test.NULL, msg.getSteeringWheelAngle());
assertNull(Test.NULL, msg.getECallInfo());
assertNull(Test.NULL, msg.getEmergencyEvent());
assertNull(Test.NULL, msg.getClusterModeStatus());
- assertNull(Test.NULL, msg.getMyKey());
+ assertNull(Test.NULL, msg.getMyKey());
+ assertNull(Test.NULL, msg.getTurnSignal());
+ assertNull(Test.NULL, msg.getElectronicParkBrakeStatus());
}
@@ -464,8 +514,9 @@ public class GetVehicleDataResponseTests extends BaseRpcTests{
JSONObject tireStatusObj = JsonUtils.readJsonObjectFromJsonObject(parameters, GetVehicleDataResponse.KEY_TIRE_PRESSURE);
TireStatus tireStatus = new TireStatus(JsonRPCMarshaller.deserializeJSONObject(tireStatusObj));
assertTrue(Test.TRUE, Validator.validateTireStatus(tireStatus, cmd.getTirePressure()) );
-
+
assertEquals(Test.MATCH, JsonUtils.readDoubleFromJsonObject(parameters, GetVehicleDataResponse.KEY_ENGINE_TORQUE), cmd.getEngineTorque());
+ assertEquals(Test.MATCH, JsonUtils.readDoubleFromJsonObject(parameters, GetVehicleDataResponse.KEY_ENGINE_OIL_LIFE), cmd.getEngineOilLife(), 0.0002);
assertEquals(Test.MATCH, JsonUtils.readIntegerFromJsonObject(parameters, GetVehicleDataResponse.KEY_ODOMETER), cmd.getOdometer());
JSONObject gpsDataObj = JsonUtils.readJsonObjectFromJsonObject(parameters, GetVehicleDataResponse.KEY_GPS);
@@ -516,6 +567,9 @@ public class GetVehicleDataResponseTests extends BaseRpcTests{
JSONObject myKeyObj = JsonUtils.readJsonObjectFromJsonObject(parameters, GetVehicleDataResponse.KEY_MY_KEY);
MyKey myKey = new MyKey(JsonRPCMarshaller.deserializeJSONObject(myKeyObj));
assertTrue(Test.TRUE, Validator.validateMyKey(myKey, cmd.getMyKey()) );
+
+ assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, GetVehicleDataResponse.KEY_TURN_SIGNAL), cmd.getTurnSignal().toString());
+ assertEquals(Test.MATCH, JsonUtils.readStringFromJsonObject(parameters, GetVehicleDataResponse.KEY_ELECTRONIC_PARK_BRAKE_STATUS), cmd.getElectronicParkBrakeStatus().toString());
} catch (JSONException e) {
e.printStackTrace();
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/ListFilesResponseTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/ListFilesResponseTests.java
index 2a060c640..878a47776 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/ListFilesResponseTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/ListFilesResponseTests.java
@@ -18,7 +18,7 @@ import com.smartdevicelink.test.json.rpc.JsonFileReader;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.ListFilesResponse}
+ * {@link com.smartdevicelink.proxy.rpc.ListFilesResponse}
*/
public class ListFilesResponseTests extends BaseRpcTests{
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/PutFileResponseTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/PutFileResponseTest.java
index bb355a05a..150994180 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/PutFileResponseTest.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/PutFileResponseTest.java
@@ -16,7 +16,7 @@ import com.smartdevicelink.test.json.rpc.JsonFileReader;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.PutFileResponse}
+ * {@link com.smartdevicelink.proxy.rpc.PutFileResponse}
*/
public class PutFileResponseTest extends BaseRpcTests {
@@ -44,7 +44,7 @@ public class PutFileResponseTest extends BaseRpcTests {
JSONObject result = new JSONObject();
try {
- result.put(PutFileResponse.KEY_SPACE_AVAILABLE, Test.GENERAL_INT);
+ result.put(PutFileResponse.KEY_SPACE_AVAILABLE, Test.GENERAL_INT);
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/RegisterAppInterfaceResponseTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/RegisterAppInterfaceResponseTest.java
index a08b35d24..55450898e 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/RegisterAppInterfaceResponseTest.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/RegisterAppInterfaceResponseTest.java
@@ -15,6 +15,7 @@ import com.smartdevicelink.proxy.rpc.AudioPassThruCapabilities;
import com.smartdevicelink.proxy.rpc.ButtonCapabilities;
import com.smartdevicelink.proxy.rpc.DisplayCapabilities;
import com.smartdevicelink.proxy.rpc.PresetBankCapabilities;
+import com.smartdevicelink.proxy.rpc.RegisterAppInterface;
import com.smartdevicelink.proxy.rpc.RegisterAppInterfaceResponse;
import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
import com.smartdevicelink.proxy.rpc.SoftButtonCapabilities;
@@ -55,6 +56,7 @@ public class RegisterAppInterfaceResponseTest extends BaseRpcTests {
msg.setVrCapabilities(Test.GENERAL_VRCAPABILITIES_LIST);
msg.setPrerecordedSpeech(Test.GENERAL_PRERECORDEDSPEECH_LIST);
msg.setSupportedDiagModes(Test.GENERAL_INTEGER_LIST);
+ msg.setIconResumed(Test.GENERAL_BOOLEAN);
return msg;
}
@@ -90,6 +92,7 @@ public class RegisterAppInterfaceResponseTest extends BaseRpcTests {
result.put(RegisterAppInterfaceResponse.KEY_VR_CAPABILITIES, JsonUtils.createJsonArray(Test.GENERAL_VRCAPABILITIES_LIST));
result.put(RegisterAppInterfaceResponse.KEY_HMI_ZONE_CAPABILITIES, JsonUtils.createJsonArray(Test.GENERAL_HMIZONECAPABILITIES_LIST));
result.put(RegisterAppInterfaceResponse.KEY_PRERECORDED_SPEECH, JsonUtils.createJsonArray(Test.GENERAL_PRERECORDEDSPEECH_LIST));
+ result.put(RegisterAppInterfaceResponse.KEY_ICON_RESUMED, Test.GENERAL_BOOLEAN);
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -117,6 +120,7 @@ public class RegisterAppInterfaceResponseTest extends BaseRpcTests {
SdlMsgVersion testMsgVersion = ( (RegisterAppInterfaceResponse) msg ).getSdlMsgVersion();
List<AudioPassThruCapabilities> testAptc = ( (RegisterAppInterfaceResponse) msg ).getAudioPassThruCapabilities();
AudioPassThruCapabilities testPcmStream = ( (RegisterAppInterfaceResponse) msg ).getPcmStreamingCapabilities();
+ Boolean testIconResumed = ( (RegisterAppInterfaceResponse) msg ).getIconResumed();
// Valid Tests
assertEquals(Test.MATCH, Test.GENERAL_INTEGER_LIST, testSupportedDiagModes);
@@ -134,6 +138,7 @@ public class RegisterAppInterfaceResponseTest extends BaseRpcTests {
assertTrue(Test.TRUE, Validator.validateSdlMsgVersion(Test.GENERAL_SDLMSGVERSION, testMsgVersion));
assertTrue(Test.TRUE, Validator.validateAudioPassThruCapabilities(Test.GENERAL_AUDIOPASSTHRUCAPABILITIES_LIST, testAptc));
assertTrue(Test.TRUE, Validator.validatePcmStreamCapabilities(Test.GENERAL_AUDIOPASSTHRUCAPABILITIES, testPcmStream));
+ assertEquals(Test.MATCH, (Boolean) Test.GENERAL_BOOLEAN, testIconResumed);
// Invalid/Null Tests
RegisterAppInterfaceResponse msg = new RegisterAppInterfaceResponse();
@@ -155,6 +160,7 @@ public class RegisterAppInterfaceResponseTest extends BaseRpcTests {
assertNull(Test.NULL, msg.getVrCapabilities());
assertNull(Test.NULL, msg.getPrerecordedSpeech());
assertNull(Test.NULL, msg.getSupportedDiagModes());
+ assertNull(Test.NULL, msg.getIconResumed());
}
/**
@@ -253,6 +259,9 @@ public class RegisterAppInterfaceResponseTest extends BaseRpcTests {
JSONObject presetBankCapabilitiesObj = JsonUtils.readJsonObjectFromJsonObject(parameters, RegisterAppInterfaceResponse.KEY_PRESET_BANK_CAPABILITIES);
PresetBankCapabilities presetBankCapabilities = new PresetBankCapabilities(JsonRPCMarshaller.deserializeJSONObject(presetBankCapabilitiesObj));
assertTrue(Test.TRUE, Validator.validatePresetBankCapabilities(presetBankCapabilities, cmd.getPresetBankCapabilities()) );
+
+ Boolean iconResumed = JsonUtils.readBooleanFromJsonObject(parameters, RegisterAppInterfaceResponse.KEY_ICON_RESUMED);
+ assertEquals(Test.MATCH, iconResumed, cmd.getIconResumed());
} catch (JSONException e) {
e.printStackTrace();
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/SubscribeVehicleDataResponseTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/SubscribeVehicleDataResponseTest.java
index a73500a94..e1dfc603c 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/SubscribeVehicleDataResponseTest.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/SubscribeVehicleDataResponseTest.java
@@ -19,7 +19,7 @@ import com.smartdevicelink.test.json.rpc.JsonFileReader;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.SubscribeVehicleDataResponse}
+ * {@link com.smartdevicelink.proxy.rpc.SubscribeVehicleDataResponse}
*/
public class SubscribeVehicleDataResponseTest extends BaseRpcTests {
@@ -36,6 +36,7 @@ public class SubscribeVehicleDataResponseTest extends BaseRpcTests {
msg.setPrndl(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_PRNDL.ordinal()));
msg.setTirePressure(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_TIREPRESSURE.ordinal()));
msg.setEngineTorque(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ENGINETORQUE.ordinal()));
+ msg.setEngineOilLife(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ENGINEOILLIFE.ordinal()));
msg.setOdometer(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ODOMETER.ordinal()));
msg.setGps(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_GPS.ordinal()));
msg.setFuelLevelState(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_FUELLEVEL_STATE.ordinal()));
@@ -53,6 +54,9 @@ public class SubscribeVehicleDataResponseTest extends BaseRpcTests {
msg.setEmergencyEvent(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_EMERGENCYEVENT.ordinal()));
msg.setClusterModeStatus(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_CLUSTERMODESTATUS.ordinal()));
msg.setMyKey(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_MYKEY.ordinal()));
+ msg.setFuelRange(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_FUELRANGE.ordinal()));
+ msg.setTurnSignal(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_TURNSIGNAL.ordinal()));
+ msg.setElectronicParkBrakeStatus(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ELECTRONICPARKBRAKESTATUS.ordinal()));
return msg;
}
@@ -84,6 +88,7 @@ public class SubscribeVehicleDataResponseTest extends BaseRpcTests {
result.put(SubscribeVehicleDataResponse.KEY_PRNDL, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_PRNDL.ordinal()).serializeJSON());
result.put(SubscribeVehicleDataResponse.KEY_TIRE_PRESSURE, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_TIREPRESSURE.ordinal()).serializeJSON());
result.put(SubscribeVehicleDataResponse.KEY_ENGINE_TORQUE, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ENGINETORQUE.ordinal()).serializeJSON());
+ result.put(SubscribeVehicleDataResponse.KEY_ENGINE_OIL_LIFE, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ENGINEOILLIFE.ordinal()).serializeJSON());
result.put(SubscribeVehicleDataResponse.KEY_ODOMETER, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ODOMETER.ordinal()).serializeJSON());
result.put(SubscribeVehicleDataResponse.KEY_GPS, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_GPS.ordinal()).serializeJSON());
result.put(SubscribeVehicleDataResponse.KEY_FUEL_LEVEL_STATE, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_FUELLEVEL_STATE.ordinal()).serializeJSON());
@@ -101,6 +106,9 @@ public class SubscribeVehicleDataResponseTest extends BaseRpcTests {
result.put(SubscribeVehicleDataResponse.KEY_EMERGENCY_EVENT, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_EMERGENCYEVENT.ordinal()).serializeJSON());
result.put(SubscribeVehicleDataResponse.KEY_CLUSTER_MODE_STATUS, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_CLUSTERMODESTATUS.ordinal()).serializeJSON());
result.put(SubscribeVehicleDataResponse.KEY_MY_KEY, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_MYKEY.ordinal()).serializeJSON());
+ result.put(SubscribeVehicleDataResponse.KEY_FUEL_RANGE, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_FUELRANGE.ordinal()).serializeJSON());
+ result.put(SubscribeVehicleDataResponse.KEY_TURN_SIGNAL, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_TURNSIGNAL.ordinal()).serializeJSON());
+ result.put(SubscribeVehicleDataResponse.KEY_ELECTRONIC_PARK_BRAKE_STATUS, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ELECTRONICPARKBRAKESTATUS.ordinal()).serializeJSON());
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -131,12 +139,16 @@ public class SubscribeVehicleDataResponseTest extends BaseRpcTests {
VehicleDataResult testConsumption = ( (SubscribeVehicleDataResponse) msg ).getInstantFuelConsumption();
VehicleDataResult testExternalTemp = ( (SubscribeVehicleDataResponse) msg ).getExternalTemperature();
VehicleDataResult testEngineTorque = ( (SubscribeVehicleDataResponse) msg ).getEngineTorque();
+ VehicleDataResult testEngineOilLife = ( (SubscribeVehicleDataResponse) msg ).getEngineOilLife();
VehicleDataResult testAccPedal = ( (SubscribeVehicleDataResponse) msg ).getAccPedalPosition();
VehicleDataResult testSteeringWheel = ( (SubscribeVehicleDataResponse) msg ).getSteeringWheelAngle();
VehicleDataResult testFuelLevelState = ( (SubscribeVehicleDataResponse) msg ).getFuelLevelState();
VehicleDataResult testPrndl = ( (SubscribeVehicleDataResponse) msg ).getPrndl();
VehicleDataResult testBraking = ( (SubscribeVehicleDataResponse) msg ).getDriverBraking();
VehicleDataResult testWiperStatus = ( (SubscribeVehicleDataResponse) msg ).getWiperStatus();
+ VehicleDataResult testFuelRange = ( (SubscribeVehicleDataResponse) msg ).getFuelRange();
+ VehicleDataResult testTurnSignal = ( (SubscribeVehicleDataResponse) msg ).getTurnSignal();
+ VehicleDataResult testEBrakeStatus = ( (SubscribeVehicleDataResponse) msg ).getElectronicParkBrakeStatus();
// Valid Tests
assertTrue(Test.TRUE, testGps.getDataType().equals(VehicleDataType.VEHICLEDATA_GPS));
@@ -157,12 +169,16 @@ public class SubscribeVehicleDataResponseTest extends BaseRpcTests {
assertTrue(Test.TRUE, testConsumption.getDataType().equals(VehicleDataType.VEHICLEDATA_FUELCONSUMPTION));
assertTrue(Test.TRUE, testExternalTemp.getDataType().equals(VehicleDataType.VEHICLEDATA_EXTERNTEMP));
assertTrue(Test.TRUE, testEngineTorque.getDataType().equals(VehicleDataType.VEHICLEDATA_ENGINETORQUE));
+ assertTrue(Test.TRUE, testEngineOilLife.getDataType().equals(VehicleDataType.VEHICLEDATA_ENGINEOILLIFE));
assertTrue(Test.TRUE, testAccPedal.getDataType().equals(VehicleDataType.VEHICLEDATA_ACCPEDAL));
assertTrue(Test.TRUE, testSteeringWheel.getDataType().equals(VehicleDataType.VEHICLEDATA_STEERINGWHEEL));
assertTrue(Test.TRUE, testFuelLevelState.getDataType().equals(VehicleDataType.VEHICLEDATA_FUELLEVEL_STATE));
assertTrue(Test.TRUE, testPrndl.getDataType().equals(VehicleDataType.VEHICLEDATA_PRNDL));
assertTrue(Test.TRUE, testBraking.getDataType().equals(VehicleDataType.VEHICLEDATA_BRAKING));
assertTrue(Test.TRUE, testWiperStatus.getDataType().equals(VehicleDataType.VEHICLEDATA_WIPERSTATUS));
+ assertTrue(Test.TRUE, testFuelRange.getDataType().equals(VehicleDataType.VEHICLEDATA_FUELRANGE));
+ assertTrue(Test.TRUE, testTurnSignal.getDataType().equals(VehicleDataType.VEHICLEDATA_TURNSIGNAL));
+ assertTrue(Test.TRUE, testEBrakeStatus.getDataType().equals(VehicleDataType.VEHICLEDATA_ELECTRONICPARKBRAKESTATUS));
// Invalid/Null Tests
SubscribeVehicleDataResponse msg = new SubscribeVehicleDataResponse();
@@ -188,11 +204,15 @@ public class SubscribeVehicleDataResponseTest extends BaseRpcTests {
assertNull(Test.NULL, msg.getDeviceStatus());
assertNull(Test.NULL, msg.getHeadLampStatus());
assertNull(Test.NULL, msg.getEngineTorque());
+ assertNull(Test.NULL, msg.getEngineOilLife());
assertNull(Test.NULL, msg.getSteeringWheelAngle());
assertNull(Test.NULL, msg.getECallInfo());
assertNull(Test.NULL, msg.getEmergencyEvent());
assertNull(Test.NULL, msg.getClusterModeStatus());
assertNull(Test.NULL, msg.getMyKey());
+ assertNull(Test.NULL, msg.getFuelRange());
+ assertNull(Test.NULL, msg.getTurnSignal());
+ assertNull(Test.NULL, msg.getElectronicParkBrakeStatus());
}
/**
@@ -238,11 +258,15 @@ public class SubscribeVehicleDataResponseTest extends BaseRpcTests {
JSONObject tirePressure = JsonUtils.readJsonObjectFromJsonObject(parameters, SubscribeVehicleDataResponse.KEY_TIRE_PRESSURE);
VehicleDataResult referenceTirePressure = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(tirePressure));
assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceTirePressure, cmd.getTirePressure()));
-
+
JSONObject engineTorque = JsonUtils.readJsonObjectFromJsonObject(parameters, SubscribeVehicleDataResponse.KEY_ENGINE_TORQUE);
VehicleDataResult referenceEngineTorque = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(engineTorque));
assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceEngineTorque, cmd.getEngineTorque()));
-
+
+ JSONObject engineOilLife = JsonUtils.readJsonObjectFromJsonObject(parameters, SubscribeVehicleDataResponse.KEY_ENGINE_OIL_LIFE);
+ VehicleDataResult referenceEngineOilLife = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(engineOilLife));
+ assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceEngineOilLife, cmd.getEngineOilLife()));
+
JSONObject odometer = JsonUtils.readJsonObjectFromJsonObject(parameters, SubscribeVehicleDataResponse.KEY_ODOMETER);
VehicleDataResult referenceOdometer = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(odometer));
assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceOdometer, cmd.getOdometer()));
@@ -310,6 +334,18 @@ public class SubscribeVehicleDataResponseTest extends BaseRpcTests {
JSONObject myKey = JsonUtils.readJsonObjectFromJsonObject(parameters, SubscribeVehicleDataResponse.KEY_MY_KEY);
VehicleDataResult referenceMyKey = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(myKey));
assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceMyKey, cmd.getMyKey()));
+
+ JSONObject fuelRange = JsonUtils.readJsonObjectFromJsonObject(parameters, SubscribeVehicleDataResponse.KEY_FUEL_RANGE);
+ VehicleDataResult referenceFuelRange = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(fuelRange));
+ assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceFuelRange, cmd.getFuelRange()));
+
+ JSONObject turnSignal = JsonUtils.readJsonObjectFromJsonObject(parameters, SubscribeVehicleDataResponse.KEY_TURN_SIGNAL);
+ VehicleDataResult referenceTurnSignal = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(turnSignal));
+ assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceTurnSignal, cmd.getTurnSignal()));
+
+ JSONObject electronicParkBrakeStatus = JsonUtils.readJsonObjectFromJsonObject(parameters, SubscribeVehicleDataResponse.KEY_ELECTRONIC_PARK_BRAKE_STATUS);
+ VehicleDataResult referenceEBrakeStatus = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(electronicParkBrakeStatus));
+ assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceEBrakeStatus, cmd.getElectronicParkBrakeStatus()));
} catch (JSONException e) {
e.printStackTrace();
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/UnsubscribeVehicleDataResponseTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/UnsubscribeVehicleDataResponseTest.java
index 489f6bc1c..cba7fcf0d 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/UnsubscribeVehicleDataResponseTest.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/responses/UnsubscribeVehicleDataResponseTest.java
@@ -21,7 +21,7 @@ import com.smartdevicelink.test.json.rpc.JsonFileReader;
/**
* This is a unit test class for the SmartDeviceLink library project class :
- * {@link com.smartdevicelink.rpc.UnsubscribeVehicleDataResponse}
+ * {@link com.smartdevicelink.proxy.rpc.UnsubscribeVehicleDataResponse}
*/
public class UnsubscribeVehicleDataResponseTest extends BaseRpcTests {
@@ -38,6 +38,7 @@ public class UnsubscribeVehicleDataResponseTest extends BaseRpcTests {
msg.setPrndl(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_PRNDL.ordinal()));
msg.setTirePressure(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_TIREPRESSURE.ordinal()));
msg.setEngineTorque(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ENGINETORQUE.ordinal()));
+ msg.setEngineOilLife(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ENGINEOILLIFE.ordinal()));
msg.setOdometer(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ODOMETER.ordinal()));
msg.setGps(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_GPS.ordinal()));
msg.setFuelLevelState(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_FUELLEVEL_STATE.ordinal()));
@@ -55,6 +56,9 @@ public class UnsubscribeVehicleDataResponseTest extends BaseRpcTests {
msg.setEmergencyEvent(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_EMERGENCYEVENT.ordinal()));
msg.setClusterModeStatus(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_CLUSTERMODESTATUS.ordinal()));
msg.setMyKey(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_MYKEY.ordinal()));
+ msg.setFuelRange(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_FUELRANGE.ordinal()));
+ msg.setTurnSignal(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_TURNSIGNAL.ordinal()));
+ msg.setElectronicParkBrakeStatus(Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ELECTRONICPARKBRAKESTATUS.ordinal()));
return msg;
}
@@ -86,6 +90,7 @@ public class UnsubscribeVehicleDataResponseTest extends BaseRpcTests {
result.put(SubscribeVehicleDataResponse.KEY_PRNDL, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_PRNDL.ordinal()).serializeJSON());
result.put(SubscribeVehicleDataResponse.KEY_TIRE_PRESSURE, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_TIREPRESSURE.ordinal()).serializeJSON());
result.put(SubscribeVehicleDataResponse.KEY_ENGINE_TORQUE, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ENGINETORQUE.ordinal()).serializeJSON());
+ result.put(SubscribeVehicleDataResponse.KEY_ENGINE_OIL_LIFE, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ENGINEOILLIFE.ordinal()).serializeJSON());
result.put(SubscribeVehicleDataResponse.KEY_ODOMETER, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ODOMETER.ordinal()).serializeJSON());
result.put(SubscribeVehicleDataResponse.KEY_GPS, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_GPS.ordinal()).serializeJSON());
result.put(SubscribeVehicleDataResponse.KEY_FUEL_LEVEL_STATE, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_FUELLEVEL_STATE.ordinal()).serializeJSON());
@@ -103,6 +108,9 @@ public class UnsubscribeVehicleDataResponseTest extends BaseRpcTests {
result.put(SubscribeVehicleDataResponse.KEY_EMERGENCY_EVENT, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_EMERGENCYEVENT.ordinal()).serializeJSON());
result.put(SubscribeVehicleDataResponse.KEY_CLUSTER_MODE_STATUS, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_CLUSTERMODESTATUS.ordinal()).serializeJSON());
result.put(SubscribeVehicleDataResponse.KEY_MY_KEY, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_MYKEY.ordinal()).serializeJSON());
+ result.put(SubscribeVehicleDataResponse.KEY_FUEL_RANGE, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_FUELRANGE.ordinal()).serializeJSON());
+ result.put(SubscribeVehicleDataResponse.KEY_TURN_SIGNAL, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_TURNSIGNAL.ordinal()).serializeJSON());
+ result.put(SubscribeVehicleDataResponse.KEY_ELECTRONIC_PARK_BRAKE_STATUS, Test.GENERAL_VEHICLEDATARESULT_LIST.get(VehicleDataType.VEHICLEDATA_ELECTRONICPARKBRAKESTATUS.ordinal()).serializeJSON());
} catch (JSONException e) {
fail(Test.JSON_FAIL);
}
@@ -133,12 +141,16 @@ public class UnsubscribeVehicleDataResponseTest extends BaseRpcTests {
VehicleDataResult testConsumption = ( (UnsubscribeVehicleDataResponse) msg ).getInstantFuelConsumption();
VehicleDataResult testExternalTemp = ( (UnsubscribeVehicleDataResponse) msg ).getExternalTemperature();
VehicleDataResult testEngineTorque = ( (UnsubscribeVehicleDataResponse) msg ).getEngineTorque();
+ VehicleDataResult testEngineOilLife = ( (UnsubscribeVehicleDataResponse) msg ).getEngineOilLife();
VehicleDataResult testAccPedal = ( (UnsubscribeVehicleDataResponse) msg ).getAccPedalPosition();
VehicleDataResult testSteeringWheel = ( (UnsubscribeVehicleDataResponse) msg ).getSteeringWheelAngle();
VehicleDataResult testFuelLevelState = ( (UnsubscribeVehicleDataResponse) msg ).getFuelLevelState();
VehicleDataResult testPrndl = ( (UnsubscribeVehicleDataResponse) msg ).getPrndl();
VehicleDataResult testBraking = ( (UnsubscribeVehicleDataResponse) msg ).getDriverBraking();
VehicleDataResult testWiperStatus = ( (UnsubscribeVehicleDataResponse) msg ).getWiperStatus();
+ VehicleDataResult testFuelRange = ( (UnsubscribeVehicleDataResponse) msg ).getFuelRange();
+ VehicleDataResult testTurnSignal = ( (UnsubscribeVehicleDataResponse) msg ).getTurnSignal();
+ VehicleDataResult testEBrakeStatus = ( (UnsubscribeVehicleDataResponse) msg ).getElectronicParkBrakeStatus();
// Valid Tests
assertTrue(Test.TRUE, testGps.getDataType().equals(VehicleDataType.VEHICLEDATA_GPS));
@@ -159,12 +171,16 @@ public class UnsubscribeVehicleDataResponseTest extends BaseRpcTests {
assertTrue(Test.TRUE, testConsumption.getDataType().equals(VehicleDataType.VEHICLEDATA_FUELCONSUMPTION));
assertTrue(Test.TRUE, testExternalTemp.getDataType().equals(VehicleDataType.VEHICLEDATA_EXTERNTEMP));
assertTrue(Test.TRUE, testEngineTorque.getDataType().equals(VehicleDataType.VEHICLEDATA_ENGINETORQUE));
+ assertTrue(Test.TRUE, testEngineOilLife.getDataType().equals(VehicleDataType.VEHICLEDATA_ENGINEOILLIFE));
assertTrue(Test.TRUE, testAccPedal.getDataType().equals(VehicleDataType.VEHICLEDATA_ACCPEDAL));
assertTrue(Test.TRUE, testSteeringWheel.getDataType().equals(VehicleDataType.VEHICLEDATA_STEERINGWHEEL));
assertTrue(Test.TRUE, testFuelLevelState.getDataType().equals(VehicleDataType.VEHICLEDATA_FUELLEVEL_STATE));
assertTrue(Test.TRUE, testPrndl.getDataType().equals(VehicleDataType.VEHICLEDATA_PRNDL));
assertTrue(Test.TRUE, testBraking.getDataType().equals(VehicleDataType.VEHICLEDATA_BRAKING));
assertTrue(Test.TRUE, testWiperStatus.getDataType().equals(VehicleDataType.VEHICLEDATA_WIPERSTATUS));
+ assertTrue(Test.TRUE, testFuelRange.getDataType().equals(VehicleDataType.VEHICLEDATA_FUELRANGE));
+ assertTrue(Test.TRUE, testTurnSignal.getDataType().equals(VehicleDataType.VEHICLEDATA_TURNSIGNAL));
+ assertTrue(Test.TRUE, testEBrakeStatus.getDataType().equals(VehicleDataType.VEHICLEDATA_ELECTRONICPARKBRAKESTATUS));
// Invalid/Null Tests
UnsubscribeVehicleDataResponse msg = new UnsubscribeVehicleDataResponse();
@@ -190,11 +206,15 @@ public class UnsubscribeVehicleDataResponseTest extends BaseRpcTests {
assertNull(Test.NULL, msg.getDeviceStatus());
assertNull(Test.NULL, msg.getHeadLampStatus());
assertNull(Test.NULL, msg.getEngineTorque());
+ assertNull(Test.NULL, msg.getEngineOilLife());
assertNull(Test.NULL, msg.getSteeringWheelAngle());
assertNull(Test.NULL, msg.getECallInfo());
assertNull(Test.NULL, msg.getEmergencyEvent());
assertNull(Test.NULL, msg.getClusterModeStatus());
assertNull(Test.NULL, msg.getMyKey());
+ assertNull(Test.NULL, msg.getFuelRange());
+ assertNull(Test.NULL, msg.getTurnSignal());
+ assertNull(Test.NULL, msg.getElectronicParkBrakeStatus());
}
/**
@@ -240,11 +260,15 @@ public class UnsubscribeVehicleDataResponseTest extends BaseRpcTests {
JSONObject tirePressure = JsonUtils.readJsonObjectFromJsonObject(parameters, UnsubscribeVehicleDataResponse.KEY_TIRE_PRESSURE);
VehicleDataResult referenceTirePressure = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(tirePressure));
assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceTirePressure, cmd.getTirePressure()));
-
+
JSONObject engineTorque = JsonUtils.readJsonObjectFromJsonObject(parameters, UnsubscribeVehicleDataResponse.KEY_ENGINE_TORQUE);
VehicleDataResult referenceEngineTorque = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(engineTorque));
assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceEngineTorque, cmd.getEngineTorque()));
-
+
+ JSONObject engineOilLife = JsonUtils.readJsonObjectFromJsonObject(parameters, UnsubscribeVehicleDataResponse.KEY_ENGINE_OIL_LIFE);
+ VehicleDataResult referenceEngineOilLife = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(engineOilLife));
+ assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceEngineOilLife, cmd.getEngineOilLife()));
+
JSONObject odometer = JsonUtils.readJsonObjectFromJsonObject(parameters, UnsubscribeVehicleDataResponse.KEY_ODOMETER);
VehicleDataResult referenceOdometer = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(odometer));
assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceOdometer, cmd.getOdometer()));
@@ -312,8 +336,20 @@ public class UnsubscribeVehicleDataResponseTest extends BaseRpcTests {
JSONObject myKey = JsonUtils.readJsonObjectFromJsonObject(parameters, UnsubscribeVehicleDataResponse.KEY_MY_KEY);
VehicleDataResult referenceMyKey = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(myKey));
assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceMyKey, cmd.getMyKey()));
+
+ JSONObject fuelRange = JsonUtils.readJsonObjectFromJsonObject(parameters, UnsubscribeVehicleDataResponse.KEY_FUEL_RANGE);
+ VehicleDataResult referenceFuelRange = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(fuelRange));
+ assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceFuelRange, cmd.getFuelRange()));
+
+ JSONObject turnSignal = JsonUtils.readJsonObjectFromJsonObject(parameters, UnsubscribeVehicleDataResponse.KEY_TURN_SIGNAL);
+ VehicleDataResult referenceTurnSignal = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(turnSignal));
+ assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceTurnSignal, cmd.getTurnSignal()));
+
+ JSONObject eBrakeStatus = JsonUtils.readJsonObjectFromJsonObject(parameters, UnsubscribeVehicleDataResponse.KEY_ELECTRONIC_PARK_BRAKE_STATUS);
+ VehicleDataResult referenceEBrakeStatus = new VehicleDataResult(JsonRPCMarshaller.deserializeJSONObject(eBrakeStatus));
+ assertTrue(Test.TRUE, Validator.validateVehicleDataResult(referenceEBrakeStatus, cmd.getElectronicParkBrakeStatus()));
} catch (JSONException e) {
e.printStackTrace();
- }
+ }
}
} \ No newline at end of file
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/security/SdlSecurityBaseTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/security/SdlSecurityBaseTest.java
index 2bf6136fa..e91903e21 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/security/SdlSecurityBaseTest.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/security/SdlSecurityBaseTest.java
@@ -2,9 +2,9 @@ package com.smartdevicelink.test.security;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
-import android.test.AndroidTestCase;
-
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.SdlConnection.ISdlConnectionListener;
import com.smartdevicelink.SdlConnection.SdlSession;
import com.smartdevicelink.protocol.ProtocolMessage;
@@ -13,8 +13,10 @@ import com.smartdevicelink.security.SdlSecurityBase;
import com.smartdevicelink.test.Test;
import com.smartdevicelink.transport.BTTransportConfig;
import com.smartdevicelink.transport.BaseTransportConfig;
+import com.smartdevicelink.transport.MultiplexTransportConfig;
+import com.smartdevicelink.transport.enums.TransportType;
-public class SdlSecurityBaseTest extends AndroidTestCase {
+public class SdlSecurityBaseTest extends AndroidTestCase2 {
@Override
protected void setUp() throws Exception {
@@ -64,6 +66,12 @@ public class SdlSecurityBaseTest extends AndroidTestCase {
public void onTransportDisconnected(String info) {
}
+
+ @Override
+ public void onTransportDisconnected(String info, boolean availablePrimary, MultiplexTransportConfig transportConfig) {
+
+ }
+
@Override
public void onTransportError(String info, Exception e) {
@@ -104,9 +112,9 @@ public class SdlSecurityBaseTest extends AndroidTestCase {
@Override
public void onProtocolServiceDataACK(SessionType sessionType, int dataSize,
byte sessionID) {
-
+
}
-
+
}
public void testMakeListSetAndGet(){
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/MockInterfaceBroker.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/MockInterfaceBroker.java
index 86dbd7b81..79fad2abb 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/MockInterfaceBroker.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/MockInterfaceBroker.java
@@ -3,8 +3,12 @@ package com.smartdevicelink.test.streaming;
import com.smartdevicelink.SdlConnection.ISdlConnectionListener;
import com.smartdevicelink.protocol.ProtocolMessage;
import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.transport.MultiplexTransportConfig;
+import com.smartdevicelink.transport.enums.TransportType;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* This is a mock class for testing the following :
@@ -16,6 +20,12 @@ public class MockInterfaceBroker implements ISdlConnectionListener {
public void onTransportDisconnected(String info) {
}
+
+ @Override
+ public void onTransportDisconnected(String info, boolean availablePrimary, MultiplexTransportConfig transportConfig) {
+
+ }
+
@Override
public void onTransportError(String info, Exception e) {
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/MockPacketizer.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/MockPacketizer.java
index d32a204a6..2c6618f62 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/MockPacketizer.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/MockPacketizer.java
@@ -5,6 +5,7 @@ import com.smartdevicelink.protocol.enums.SessionType;
import com.smartdevicelink.proxy.RPCRequest;
import com.smartdevicelink.streaming.AbstractPacketizer;
import com.smartdevicelink.streaming.IStreamListener;
+import com.smartdevicelink.util.Version;
import java.io.IOException;
import java.io.InputStream;
@@ -15,6 +16,7 @@ import java.io.InputStream;
*/
public class MockPacketizer extends AbstractPacketizer {
public MockPacketizer (IStreamListener l, InputStream i, SessionType s, byte sid, SdlSession sdlsession) throws IOException { super (l, i, s, sid, sdlsession); }
+ public MockPacketizer (IStreamListener l, InputStream i, RPCRequest r, SessionType s, byte sid, Version protocolVersion,SdlSession sdlsession) throws IOException { super (l, i, r, s, sid, protocolVersion, sdlsession); }
public MockPacketizer (IStreamListener l, InputStream i, RPCRequest r, SessionType s, byte sid, byte w, SdlSession sdlsession) throws IOException { super (l, i, r, s, sid, w, sdlsession); }
@Override public void start() throws IOException { }
@@ -26,7 +28,9 @@ public class MockPacketizer extends AbstractPacketizer {
public SdlSession getSdlSession () { return _session; }
public byte getSessionId () { return _rpcSessionID; }
public RPCRequest getRPCRequest () { return _request; }
- public byte getWiproVersion () { return _wiproVersion; }
+ @Deprecated
+ public byte getWiproVersion () { if(_wiproVersion != null){return (byte)_wiproVersion.getMajor(); }else{return 5;}}
+ public Version getProtocolVersion () { return _wiproVersion; }
@Override public void pause() { }
@Override public void resume() { }
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/video/SdlRemoteDisplayTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/video/SdlRemoteDisplayTest.java
index 96e6e29cb..453239bca 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/video/SdlRemoteDisplayTest.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/streaming/video/SdlRemoteDisplayTest.java
@@ -4,12 +4,11 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.os.Bundle;
import android.os.Looper;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
import android.view.Display;
import android.view.MotionEvent;
import android.widget.RelativeLayout;
-import com.smartdevicelink.R;
import com.smartdevicelink.encoder.VirtualDisplayEncoder;
import com.smartdevicelink.proxy.interfaces.IVideoStreamListener;
import com.smartdevicelink.streaming.video.SdlRemoteDisplay;
@@ -21,7 +20,7 @@ import java.nio.ByteBuffer;
import java.util.concurrent.FutureTask;
-public class SdlRemoteDisplayTest extends AndroidTestCase {
+public class SdlRemoteDisplayTest extends TestCase {
MockRemoteDisplayCallback rdCallback = new MockRemoteDisplayCallback();
@@ -38,7 +37,7 @@ public class SdlRemoteDisplayTest extends AndroidTestCase {
assertNotNull(encoder);
- SdlRemoteDisplay.Creator creator = new SdlRemoteDisplay.Creator(this.getContext(), encoder.getVirtualDisplay(), null, MockRemoteDisplay.class, rdCallback);
+ SdlRemoteDisplay.Creator creator = new SdlRemoteDisplay.Creator(InstrumentationRegistry.getContext(), encoder.getVirtualDisplay(), null, MockRemoteDisplay.class, rdCallback);
assertNotNull(creator);
FutureTask<Boolean> fTask = new FutureTask<Boolean>(creator);
Thread showPresentation = new Thread(fTask);
@@ -49,7 +48,7 @@ public class SdlRemoteDisplayTest extends AndroidTestCase {
public void testConstructor(){
VirtualDisplayEncoder encoder = createVDE();
assertNotNull(encoder);
- MockRemoteDisplay remoteDisplay = new MockRemoteDisplay(getContext(), encoder.getVirtualDisplay());
+ MockRemoteDisplay remoteDisplay = new MockRemoteDisplay(InstrumentationRegistry.getContext(), encoder.getVirtualDisplay());
assertNotNull(remoteDisplay);
encoder.shutDown();
@@ -60,7 +59,7 @@ public class SdlRemoteDisplayTest extends AndroidTestCase {
public void testTouchEvents(){
VirtualDisplayEncoder encoder = createVDE();
assertNotNull(encoder);
- MockRemoteDisplay remoteDisplay = new MockRemoteDisplay(getContext(), encoder.getVirtualDisplay());
+ MockRemoteDisplay remoteDisplay = new MockRemoteDisplay(InstrumentationRegistry.getContext(), encoder.getVirtualDisplay());
assertNotNull(remoteDisplay);
remoteDisplay.show();
@@ -80,7 +79,7 @@ public class SdlRemoteDisplayTest extends AndroidTestCase {
public VirtualDisplayEncoder createVDE(){
try{
VirtualDisplayEncoder displayEncoder = new VirtualDisplayEncoder();
- displayEncoder.init(getContext(), new MockVideoStreamListener(), new VideoStreamingParameters());
+ displayEncoder.init(InstrumentationRegistry.getContext(), new MockVideoStreamListener(), new VideoStreamingParameters());
displayEncoder.start();
return displayEncoder;
}catch (Exception e ){
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/transport/MultiplexTransportConfigTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/transport/MultiplexTransportConfigTests.java
index c4bfad6cc..cb3de5670 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/transport/MultiplexTransportConfigTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/transport/MultiplexTransportConfigTests.java
@@ -1,10 +1,10 @@
package com.smartdevicelink.test.transport;
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.transport.MultiplexTransportConfig;
-import android.test.AndroidTestCase;
-public class MultiplexTransportConfigTests extends AndroidTestCase {
+public class MultiplexTransportConfigTests extends AndroidTestCase2 {
public void testDefaultSecurity(){
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/transport/WiFiSocketFactoryTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/transport/WiFiSocketFactoryTest.java
new file mode 100644
index 000000000..ab2b7b52d
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/transport/WiFiSocketFactoryTest.java
@@ -0,0 +1,354 @@
+package com.smartdevicelink.test.transport;
+
+import android.Manifest;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.os.Build;
+import android.util.Log;
+
+import com.smartdevicelink.transport.utl.WiFiSocketFactory;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.net.SocketFactory;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * This is a unit test class for the WiFiSocketFactory class:
+ * {@link com.smartdevicelink.transport.utl.WiFiSocketFactory}
+ *
+ * Requires LOLLIPOP or later since the tests use android.net.NetworkCapabilities class
+ */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class WiFiSocketFactoryTest extends TestCase {
+
+ private static final String TAG = WiFiSocketFactoryTest.class.getSimpleName();
+
+ private Context mMockContext;
+ private PackageManager mMockPackageManager;
+ private ConnectivityManager mMockConnMan;
+ private SocketFactory mMockSocketFactory; // this is the SocketFactory that creates mWiFiBoundSocket
+ private Socket mWiFiBoundSocket;
+
+ private enum FactoryRet {
+ RETURNS_NULL,
+ RETURNS_CORRECT_FACTORY,
+ RETURNS_ANOTHER_FACTORY,
+ }
+
+ private class MockNetworkConfig {
+ // true to make a null Network
+ boolean isNull;
+ // specify the transport type of the Network
+ int transportType;
+ // spcify the type of SocketFactory returned from this Network
+ FactoryRet factoryReturnValue;
+
+ MockNetworkConfig(boolean isNull, int transportType, FactoryRet factoryReturnValue) {
+ this.isNull = isNull;
+ this.transportType = transportType;
+ this.factoryReturnValue = factoryReturnValue;
+ }
+ }
+
+ private void setupMockNetworks(MockNetworkConfig[] configs) {
+ if (configs == null) {
+ when(mMockConnMan.getAllNetworks()).thenReturn(null);
+ return;
+ }
+
+ List<Network> networkList = new ArrayList<Network>(configs.length);
+
+ for (MockNetworkConfig config : configs) {
+ if (config.isNull) {
+ networkList.add(null);
+ continue;
+ }
+
+ Network network = mock(Network.class);
+
+ NetworkCapabilities networkCapabilities = createNetworkCapabilitiesWithTransport(config.transportType);
+ when(mMockConnMan.getNetworkCapabilities(network)).thenReturn(networkCapabilities);
+
+ SocketFactory factory = null;
+ switch (config.factoryReturnValue) {
+ case RETURNS_NULL:
+ break;
+ case RETURNS_CORRECT_FACTORY:
+ factory = mMockSocketFactory;
+ break;
+ case RETURNS_ANOTHER_FACTORY:
+ // create another mock SocketFactory instance
+ factory = mock(SocketFactory.class);
+ break;
+ }
+ when(network.getSocketFactory()).thenReturn(factory);
+
+ networkList.add(network);
+ }
+
+ when(mMockConnMan.getAllNetworks()).thenReturn(networkList.toArray(new Network[networkList.size()]));
+ }
+
+ private static NetworkCapabilities createNetworkCapabilitiesWithTransport(int transport) {
+ // Creates a dummy NetworkCapabilities instance.
+ // Since NetworkCapabilities class is 'final', we cannot create its mock. To create a dummy
+ // instance, here we use reflection to call its constructor and a method that are marked
+ // with "@hide".
+ // It is possible that these methods will not be available in a future version of Android.
+ // In that case we need to update our code accordingly.
+ Class<NetworkCapabilities> c = NetworkCapabilities.class;
+ try {
+ Method addTransportTypeMethod = c.getMethod("addTransportType", int.class);
+ addTransportTypeMethod.setAccessible(true);
+
+ NetworkCapabilities instance = c.getDeclaredConstructor().newInstance();
+ addTransportTypeMethod.invoke(instance, transport);
+ Log.e(TAG, "Yes successful");
+ return instance;
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to create NetworkCapabilities instance using reflection: ", e);
+ return null;
+ }
+ }
+
+ // from https://stackoverflow.com/questions/40300469/mock-build-version-with-mockito
+ // and https://stackoverflow.com/questions/13755117/android-changing-private-static-final-field-using-java-reflection
+ private static void setFinalStatic(Field field, Object newValue) throws Exception {
+ field.setAccessible(true);
+// Field modifiersField = Field.class.getDeclaredField("modifiers");
+ // This call might fail on some devices (for example, Nexus 6 with Android 5.0.1).
+ // If that's the issue, we might want to introduce PowerMock.
+ Field modifiersField = Field.class.getDeclaredField("accessFlags");
+ modifiersField.setAccessible(true);
+ modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
+ field.set(null, newValue);
+ }
+
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mMockContext = mock(Context.class);
+ mMockPackageManager = mock(PackageManager.class);
+ mMockConnMan = mock(ConnectivityManager.class);
+
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ when(mMockContext.getPackageName()).thenReturn("dummyPackageName");
+ when(mMockContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE))).thenReturn(mMockConnMan);
+
+ when(mMockPackageManager.checkPermission(eq(Manifest.permission.ACCESS_NETWORK_STATE), anyString())).thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ mMockSocketFactory = mock(SocketFactory.class);
+ mWiFiBoundSocket = new Socket();
+ when(mMockSocketFactory.createSocket()).thenReturn(mWiFiBoundSocket);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ // test the happy path
+ public void testWithWiFiNetwork() {
+ setupMockNetworks(new MockNetworkConfig[] {
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_CELLULAR, FactoryRet.RETURNS_ANOTHER_FACTORY),
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_WIFI, FactoryRet.RETURNS_CORRECT_FACTORY),
+ });
+
+ Socket ret = WiFiSocketFactory.createSocket(mMockContext);
+
+ assertNotNull("createSocket() should always return a Socket instance", ret);
+ assertEquals("Returned Socket should be created through SocketFactory", mWiFiBoundSocket, ret);
+ }
+
+ // test the case where SDK_INT is less than 21
+ /* This is disabled since Travis CI uses an AVD with 5.1.1 and setFinalStatic() doesn't work on it.
+ public void testPriorToLollipop() throws Exception {
+ setupMockNetworks(new MockNetworkConfig[] {
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_CELLULAR, FactoryRet.RETURNS_ANOTHER_FACTORY),
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_WIFI, FactoryRet.RETURNS_CORRECT_FACTORY),
+ });
+
+ // simulate SDK_INT to less than LOLLIPOP
+ int previousSDKInt = Build.VERSION.SDK_INT;
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), Build.VERSION_CODES.KITKAT_WATCH);
+
+ Socket ret = WiFiSocketFactory.createSocket(mMockContext);
+
+ // make sure we revert our change
+ setFinalStatic(Build.VERSION.class.getField("SDK_INT"), previousSDKInt);
+
+ assertNotNull("createSocket() should always return a Socket instance", ret);
+ assertNotSame("Returned Socket shouldn't be created through SocketFactory since it is not available prior to LOLLIPOP",
+ mWiFiBoundSocket, ret);
+ }
+ */
+
+ // test the case where we do not have ACCESS_NETWORK_STATE permission
+ public void testWithoutPermission() {
+ setupMockNetworks(new MockNetworkConfig[] {
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_WIFI, FactoryRet.RETURNS_CORRECT_FACTORY),
+ });
+
+ // simulate the case where required permission isn't available
+ when(mMockPackageManager.checkPermission(eq(Manifest.permission.ACCESS_NETWORK_STATE), anyString())).thenReturn(PackageManager.PERMISSION_DENIED);
+
+ Socket ret = WiFiSocketFactory.createSocket(mMockContext);
+
+ assertNotNull("createSocket() should always return a Socket instance", ret);
+ assertNotSame("Returned Socket shouldn't be created through SocketFactory since we don't have required permission",
+ mWiFiBoundSocket, ret);
+ }
+
+ // test the case where context.getPackageManager() returns null
+ public void testPackageManagerNull() {
+ setupMockNetworks(new MockNetworkConfig[] {
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_WIFI, FactoryRet.RETURNS_CORRECT_FACTORY),
+ });
+
+ // simulate the case where ConnectivityManager isn't available
+ when(mMockContext.getPackageManager()).thenReturn(null);
+
+ Socket ret = WiFiSocketFactory.createSocket(mMockContext);
+
+ assertNotNull("createSocket() should always return a Socket instance", ret);
+ assertNotSame("Returned Socket shouldn't be created through SocketFactory since PackageManager isn't available",
+ mWiFiBoundSocket, ret);
+ }
+
+ // test the case where getSystemService() returns null
+ public void testConnectivityManagerNull() {
+ setupMockNetworks(new MockNetworkConfig[] {
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_WIFI, FactoryRet.RETURNS_CORRECT_FACTORY),
+ });
+
+ // simulate the case where ConnectivityManager isn't available
+ when(mMockContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE))).thenReturn(null);
+
+ Socket ret = WiFiSocketFactory.createSocket(mMockContext);
+
+ assertNotNull("createSocket() should always return a Socket instance", ret);
+ assertNotSame("Returned Socket shouldn't be created through SocketFactory since ConnectivityManager isn't working",
+ mWiFiBoundSocket, ret);
+ }
+
+ // test the case where ConnectivityManager returns null for the network list
+ public void testNetworkListNull() {
+ setupMockNetworks(null);
+
+ Socket ret = WiFiSocketFactory.createSocket(mMockContext);
+
+ assertNotNull("createSocket() should always return a Socket instance", ret);
+ assertNotSame("Returned Socket shouldn't be created through SocketFactory since Network list isn't available",
+ mWiFiBoundSocket, ret);
+ }
+
+ // test the case where the network list contains a null for Network instance
+ public void testNetworkListHasNull() {
+ setupMockNetworks(new MockNetworkConfig[] {
+ // multiple Network instances in the list, the first one being NULL
+ new MockNetworkConfig(true, 0, FactoryRet.RETURNS_ANOTHER_FACTORY),
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_WIFI, FactoryRet.RETURNS_CORRECT_FACTORY),
+ });
+
+ Socket ret = WiFiSocketFactory.createSocket(mMockContext);
+
+ assertNotNull("createSocket() should always return a Socket instance", ret);
+ assertEquals("Returned Socket should be created through SocketFactory", mWiFiBoundSocket, ret);
+ }
+
+ // test the case where the phone isn't connected to Wi-Fi network
+ public void testNoWiFiNetwork() {
+ setupMockNetworks(new MockNetworkConfig[] {
+ // none of the instances has TRANSPORT_WIFI in their capabilities
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_CELLULAR, FactoryRet.RETURNS_ANOTHER_FACTORY),
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_BLUETOOTH, FactoryRet.RETURNS_ANOTHER_FACTORY),
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_VPN, FactoryRet.RETURNS_ANOTHER_FACTORY),
+ });
+
+ Socket ret = WiFiSocketFactory.createSocket(mMockContext);
+
+ assertNotNull("createSocket() should always return a Socket instance", ret);
+ assertNotSame("Returned Socket shouldn't be created through SocketFactory since Wi-Fi network isn't available",
+ mWiFiBoundSocket, ret);
+ }
+
+ // test the case where we get null for SocketFactory
+ public void testSocketFactoryNull() {
+ setupMockNetworks(new MockNetworkConfig[] {
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_CELLULAR, FactoryRet.RETURNS_ANOTHER_FACTORY),
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_WIFI, FactoryRet.RETURNS_NULL),
+ });
+
+ Socket ret = WiFiSocketFactory.createSocket(mMockContext);
+
+ assertNotNull("createSocket() should always return a Socket instance", ret);
+ assertNotSame("Returned Socket shouldn't be created through SocketFactory since SocketFactory isn't available",
+ mWiFiBoundSocket, ret);
+ }
+
+ // test the case where we get a null for SocketFactory, then a valid one for another
+ public void testSocketFactoryNull2() {
+ setupMockNetworks(new MockNetworkConfig[] {
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_CELLULAR, FactoryRet.RETURNS_ANOTHER_FACTORY),
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_WIFI, FactoryRet.RETURNS_NULL),
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_WIFI, FactoryRet.RETURNS_CORRECT_FACTORY),
+ });
+
+ Socket ret = WiFiSocketFactory.createSocket(mMockContext);
+
+ assertNotNull("createSocket() should always return a Socket instance", ret);
+ assertEquals("Returned Socket should be created through SocketFactory", mWiFiBoundSocket, ret);
+ }
+
+ // test the case where we get an exception with SocketFactory.createSocket()
+ public void testFactoryReturnsException() throws IOException {
+ setupMockNetworks(new MockNetworkConfig[] {
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_WIFI, FactoryRet.RETURNS_CORRECT_FACTORY),
+ });
+
+ when(mMockSocketFactory.createSocket()).thenThrow(new IOException("Dummy IOException for testing!"));
+
+ Socket ret = WiFiSocketFactory.createSocket(mMockContext);
+
+ assertNotNull("createSocket() should always return a Socket instance", ret);
+ assertNotSame("Returned Socket shouldn't be created through SocketFactory since it throws an IOException",
+ mWiFiBoundSocket, ret);
+ }
+
+ // Test the case we get multiple Network instances with Wi-Fi transport, and the SocketFactory of
+ // the first one throws Exception and the other one succeeds.
+ // This is to simulate Samsung Galaxy S9.
+ public void testFactoryReturnsException2() throws IOException {
+ setupMockNetworks(new MockNetworkConfig[] {
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_WIFI, FactoryRet.RETURNS_CORRECT_FACTORY),
+ new MockNetworkConfig(false, NetworkCapabilities.TRANSPORT_WIFI, FactoryRet.RETURNS_CORRECT_FACTORY),
+ });
+
+ when(mMockSocketFactory.createSocket()).thenThrow(new IOException("Dummy IOException for testing!"))
+ .thenReturn(mWiFiBoundSocket);
+
+ Socket ret = WiFiSocketFactory.createSocket(mMockContext);
+
+ assertNotNull("createSocket() should always return a Socket instance", ret);
+ assertEquals("Returned Socket should be created through SocketFactory", mWiFiBoundSocket, ret);
+ }
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/DeviceUtil.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/DeviceUtil.java
index 08b5c0840..389403eaf 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/DeviceUtil.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/DeviceUtil.java
@@ -8,10 +8,11 @@ public class DeviceUtil {
|| Build.FINGERPRINT.startsWith("unknown")
|| Build.MODEL.contains("google_sdk")
|| Build.MODEL.contains("Emulator")
- || Build.MODEL.contains("Android SDL built for")
+ || Build.MODEL.contains("Android SDK built for")
+ || Build.MANUFACTURER.contains("Genymotion")
|| (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
|| (Build.BRAND.startsWith("Android") && Build.DEVICE.startsWith("generic"))
|| (Build.PRODUCT != null && Build.PRODUCT.startsWith("sdk_google_phone"))
|| "google_sdk".equals(Build.PRODUCT);
}
-} \ No newline at end of file
+}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java
index 116e846d7..027de8b2c 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/SdlAppInfoTests.java
@@ -38,8 +38,8 @@ import android.content.pm.PackageInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Bundle;
-import android.test.AndroidTestCase;
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.R;
import com.smartdevicelink.util.SdlAppInfo;
@@ -51,7 +51,7 @@ import java.util.List;
* Created by Joey Grover on 2/20/18.
*/
-public class SdlAppInfoTests extends AndroidTestCase {
+public class SdlAppInfoTests extends AndroidTestCase2 {
Context context;
ResolveInfo defaultResolveInfo;
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/VersionTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/VersionTest.java
index 44d25ffe0..4798de56b 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/VersionTest.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/util/VersionTest.java
@@ -1,10 +1,9 @@
package com.smartdevicelink.test.util;
-import android.test.AndroidTestCase;
-
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.util.Version;
-public class VersionTest extends AndroidTestCase {
+public class VersionTest extends AndroidTestCase2 {
private static final String TEST_VERSION = "1.2.3";
@@ -28,4 +27,22 @@ public class VersionTest extends AndroidTestCase {
Version version = new Version(TEST_VERSION);
assertEquals(version.toString(), TEST_VERSION);
}
+
+ public void testisNewerThan(){
+ Version version1 = new Version(5,0,0);
+
+ //Supplied version is newer
+ assertEquals(-1,version1.isNewerThan(new Version(6,0,0)));
+ assertEquals(-1,version1.isNewerThan( new Version(5,1,0)));
+ assertEquals(-1,version1.isNewerThan( new Version(5,0,1)));
+
+ //Supplied version is older
+ assertEquals(1,version1.isNewerThan( new Version(4,0,0)));
+ assertEquals(1,version1.isNewerThan( new Version(4,1,0)));
+ assertEquals(1,version1.isNewerThan( new Version(4,0,1)));
+
+ //Supplied version is equal
+ assertEquals(0,version1.isNewerThan( new Version(5,0,0)));
+
+ }
}
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java
index e15c95098..c715bb62c 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/test/utl/AndroidToolsTests.java
@@ -2,11 +2,11 @@ package com.smartdevicelink.test.utl;
import junit.framework.Assert;
import android.content.ComponentName;
-import android.test.AndroidTestCase;
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.util.AndroidTools;
-public class AndroidToolsTests extends AndroidTestCase{
+public class AndroidToolsTests extends AndroidTestCase2 {
public void testIsServiceExportedNormal(){
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/transport/LocalRouterServiceTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/transport/LocalRouterServiceTests.java
index c918ffa12..10aa25d75 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/transport/LocalRouterServiceTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/transport/LocalRouterServiceTests.java
@@ -3,9 +3,10 @@ package com.smartdevicelink.transport;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Parcel;
-import android.test.AndroidTestCase;
-public class LocalRouterServiceTests extends AndroidTestCase {
+import com.smartdevicelink.AndroidTestCase2;
+
+public class LocalRouterServiceTests extends AndroidTestCase2 {
private static final int TEST_WITH_CONSTRUCTOR = 0;
private static final int TEST_WITH_CREATOR = 1;
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/transport/MultiplexTransportTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/transport/MultiplexTransportTest.java
index 901a756a3..9551a5a6f 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/transport/MultiplexTransportTest.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/transport/MultiplexTransportTest.java
@@ -1,14 +1,13 @@
package com.smartdevicelink.transport;
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.protocol.SdlPacket;
import com.smartdevicelink.test.SdlUnitTestContants;
import com.smartdevicelink.transport.enums.TransportType;
-import android.test.AndroidTestCase;
-
import junit.framework.Assert;
-public class MultiplexTransportTest extends AndroidTestCase {
+public class MultiplexTransportTest extends AndroidTestCase2 {
private static final int TIMEOUT = 2000;
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/transport/RSVTestCase.java b/sdl_android/src/androidTest/java/com/smartdevicelink/transport/RSVTestCase.java
index e40049afd..b19a0c6ce 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/transport/RSVTestCase.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/transport/RSVTestCase.java
@@ -5,9 +5,9 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.test.AndroidTestCase;
import android.util.Log;
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.transport.RouterServiceValidator.TrustedAppStore;
import com.smartdevicelink.util.HttpRequestTask.HttpRequestTaskCallback;
@@ -21,7 +21,7 @@ import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.Semaphore;
-public class RSVTestCase extends AndroidTestCase {
+public class RSVTestCase extends AndroidTestCase2 {
private static final String TAG = "RSVTestCase";
private static final long REFRESH_TRUSTED_APP_LIST_TIME_DAY = 3600000 * 24; // A day in ms
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/transport/RegisteredAppTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/transport/RegisteredAppTests.java
index 4208c1479..89dbae3ab 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/transport/RegisteredAppTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/transport/RegisteredAppTests.java
@@ -1,16 +1,16 @@
package com.smartdevicelink.transport;
-import android.os.Handler;
import android.os.Looper;
import android.os.Messenger;
-import android.test.AndroidTestCase;
+
+import com.smartdevicelink.AndroidTestCase2;
/**
* Created by brettywhite on 4/4/17.
*/
-public class RegisteredAppTests extends AndroidTestCase {
+public class RegisteredAppTests extends AndroidTestCase2 {
private static final String APP_ID = "123451123";
private static final Messenger messenger = null;
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/transport/SdlRouterServiceTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/transport/SdlRouterServiceTests.java
index c23b3b624..1a0bc2458 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/transport/SdlRouterServiceTests.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/transport/SdlRouterServiceTests.java
@@ -5,11 +5,11 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.test.AndroidTestCase;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.marshal.JsonRPCMarshaller;
import com.smartdevicelink.protocol.BinaryFrameHeader;
import com.smartdevicelink.protocol.ProtocolMessage;
@@ -19,6 +19,8 @@ import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.protocol.enums.MessageType;
import com.smartdevicelink.protocol.enums.SessionType;
import com.smartdevicelink.proxy.rpc.UnregisterAppInterface;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
import junit.framework.Assert;
@@ -27,7 +29,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
-public class SdlRouterServiceTests extends AndroidTestCase {
+public class SdlRouterServiceTests extends AndroidTestCase2 {
public static final String TAG = "SdlRouterServiceTests";
private final int SAMPLE_RPC_CORRELATION_ID = 630;
@@ -126,7 +128,7 @@ public class SdlRouterServiceTests extends AndroidTestCase {
//First, set mSerialService to the correct state so we get to test packet being null
MultiplexBluetoothTransport transport = new MultiplexBluetoothTransport(null);
transport.setStateManually(MultiplexBluetoothTransport.STATE_CONNECTED);
- field = SdlRouterService.class.getDeclaredField("mSerialService");
+ field = SdlRouterService.class.getDeclaredField("bluetoothTransport");
field.setAccessible(true);
field.set(sdlRouterService, transport);
bundle = new Bundle();
@@ -177,7 +179,7 @@ public class SdlRouterServiceTests extends AndroidTestCase {
// need a session map too
SparseArray<String> sessionMap = new SparseArray<String>();
sessionMap.put(1, "12345");
- Field sessionMapField = sdlRouterService.getClass().getDeclaredField("sessionMap");
+ Field sessionMapField = sdlRouterService.getClass().getDeclaredField("bluetoothSessionMap");
sessionMapField.setAccessible(true);
sessionMapField.set(sdlRouterService, sessionMap);
@@ -227,6 +229,7 @@ public class SdlRouterServiceTests extends AndroidTestCase {
// create packet and invoke sendPacketToRegisteredApp
SdlPacket packet = new SdlPacket(4, false, SdlPacket.FRAME_TYPE_SINGLE, SdlPacket.SERVICE_TYPE_RPC, 0, sessionId, data.length, 123, data);
+ packet.setTransportRecord(new TransportRecord(TransportType.BLUETOOTH,null));
method = sdlRouterService.getClass().getDeclaredMethod("sendPacketToRegisteredApp", SdlPacket.class);
Boolean success = (Boolean) method.invoke(sdlRouterService, packet);
@@ -268,7 +271,7 @@ public class SdlRouterServiceTests extends AndroidTestCase {
// need a session map too
SparseArray<String> sessionMap = new SparseArray<String>();
sessionMap.put(1, "12345");
- Field sessionMapField = sdlRouterService.getClass().getDeclaredField("sessionMap");
+ Field sessionMapField = sdlRouterService.getClass().getDeclaredField("bluetoothSessionMap");
sessionMapField.setAccessible(true);
sessionMapField.set(sdlRouterService, sessionMap);
@@ -318,6 +321,7 @@ public class SdlRouterServiceTests extends AndroidTestCase {
// create packet and invoke sendPacketToRegisteredApp
SdlPacket packet = new SdlPacket(4, false, SdlPacket.FRAME_TYPE_SINGLE, SdlPacket.SERVICE_TYPE_RPC, 0, sessionId, data.length, 123, data);
+ packet.setTransportRecord(new TransportRecord(TransportType.BLUETOOTH,null));
method = sdlRouterService.getClass().getDeclaredMethod("sendPacketToRegisteredApp", SdlPacket.class);
Boolean success = (Boolean) method.invoke(sdlRouterService, packet);
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/transport/TransportBrokerTest.java b/sdl_android/src/androidTest/java/com/smartdevicelink/transport/TransportBrokerTest.java
index 5725b6974..ac97857ad 100644
--- a/sdl_android/src/androidTest/java/com/smartdevicelink/transport/TransportBrokerTest.java
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/transport/TransportBrokerTest.java
@@ -5,12 +5,12 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
-import android.test.AndroidTestCase;
+import com.smartdevicelink.AndroidTestCase2;
import com.smartdevicelink.test.SdlUnitTestContants;
import com.smartdevicelink.test.util.DeviceUtil;
-public class TransportBrokerTest extends AndroidTestCase {
+public class TransportBrokerTest extends AndroidTestCase2 {
RouterServiceValidator rsvp;
// public TransportBrokerThread(Context context, String appId, ComponentName service){
diff --git a/sdl_android/src/androidTest/java/com/smartdevicelink/transport/TransportManagerTests.java b/sdl_android/src/androidTest/java/com/smartdevicelink/transport/TransportManagerTests.java
new file mode 100644
index 000000000..bdb628e05
--- /dev/null
+++ b/sdl_android/src/androidTest/java/com/smartdevicelink/transport/TransportManagerTests.java
@@ -0,0 +1,129 @@
+package com.smartdevicelink.transport;
+
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcelable;
+
+import com.smartdevicelink.AndroidTestCase2;
+import com.smartdevicelink.protocol.SdlPacket;
+import com.smartdevicelink.protocol.SdlPacketFactory;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.test.SdlUnitTestContants;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class TransportManagerTests extends AndroidTestCase2 {
+
+ MultiplexTransportConfig config;
+ final TransportRecord defaultBtRecord = new TransportRecord(TransportType.BLUETOOTH, "12:34:56:78:90");
+ final ComponentName routerServiceComponentName = new ComponentName("com.smartdevicelink.test","com.smartdevicelink.test.SdlRouterService");
+ final SdlPacket defaultPacket = SdlPacketFactory.createStartSessionACK(SessionType.RPC,(byte)1,100,(byte)5);
+
+
+ TransportManager.TransportEventListener defaultListener = new TransportManager.TransportEventListener() {
+ @Override
+ public void onPacketReceived(SdlPacket packet) { assertEquals(defaultPacket,packet);}
+ @Override
+ public void onTransportConnected(List<TransportRecord> transports) {}
+ @Override
+ public void onTransportDisconnected(String info, TransportRecord type, List<TransportRecord> connectedTransports) {}
+ @Override
+ public void onError(String info) {}
+ @Override
+ public boolean onLegacyModeEnabled(String info) {return false; }
+ };
+
+
+ @Override
+ protected void setUp() throws Exception {
+ config = new MultiplexTransportConfig(this.mContext, SdlUnitTestContants.TEST_APP_ID);
+ config.setService(routerServiceComponentName);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+
+ }
+
+ public TransportManager createTransportManager(){
+ TransportManager manager = new TransportManager(config,defaultListener);
+
+ //The default listener returns false as legacy is unacceptable
+ assertNull(manager.legacyBluetoothHandler);
+
+ manager.exitLegacyMode("Test");
+ manager.transport = manager.new TransportBrokerImpl(mContext, config.appId, routerServiceComponentName);
+
+ manager.start();
+ assert true;
+ return manager;
+ }
+
+ public void testBase(){
+ TransportManager manager = new TransportManager(config,defaultListener);
+ assertNotNull(manager);
+ }
+
+ public void testConnectionStatus(){
+ TransportManager manager = new TransportManager(config,defaultListener);
+
+ manager.transportStatus.clear();
+ manager.transportStatus.add(defaultBtRecord);
+
+ assertTrue(manager.isConnected(null, null));
+ assertTrue(manager.isConnected(TransportType.BLUETOOTH, null));
+ assertTrue(manager.isConnected(TransportType.BLUETOOTH, defaultBtRecord.getAddress()));
+
+ assertNull(manager.getTransportRecord(null, null));
+ assertNull(manager.getTransportRecord(null, defaultBtRecord.getAddress()));
+ assertNull(manager.getTransportRecord(TransportType.USB, null));
+
+ assertEquals(defaultBtRecord, manager.getTransportRecord(defaultBtRecord.getType(), null));
+ assertEquals(defaultBtRecord, manager.getTransportRecord(defaultBtRecord.getType(), defaultBtRecord.getAddress()));
+
+ assertFalse(manager.isHighBandwidthAvailable());
+
+ manager.transportStatus.add(new TransportRecord(TransportType.USB,"test"));
+ assertTrue(manager.isHighBandwidthAvailable());
+ assertNotNull(manager.getTransportRecord(TransportType.USB, null));
+
+ }
+
+ public void testOnTransportConnections(){
+
+ TransportManager manager = createTransportManager();
+
+ manager.transport.onHardwareConnected(Collections.singletonList(defaultBtRecord));
+
+ assertTrue(manager.isConnected(null, null));
+ assertTrue(manager.isConnected(TransportType.BLUETOOTH, null));
+ assertTrue(manager.isConnected(TransportType.BLUETOOTH, defaultBtRecord.getAddress()));
+
+ assertNull(manager.getTransportRecord(null, null));
+ assertNull(manager.getTransportRecord(null, defaultBtRecord.getAddress()));
+ assertNull(manager.getTransportRecord(TransportType.USB, null));
+
+ assertEquals(defaultBtRecord, manager.getTransportRecord(defaultBtRecord.getType(), null));
+ assertEquals(defaultBtRecord, manager.getTransportRecord(defaultBtRecord.getType(), defaultBtRecord.getAddress()));
+
+ assertFalse(manager.isHighBandwidthAvailable());
+
+ }
+
+ public void testOnPacket(){
+ TransportManager manager = createTransportManager();
+ assertNotNull(manager.transportListener);
+
+ manager.transport.onPacketReceived(defaultPacket);
+
+ }
+
+
+
+}
diff --git a/sdl_android/src/androidTest/res/raw/test_audio_square_250hz_80amp_1s.mp3 b/sdl_android/src/androidTest/res/raw/test_audio_square_250hz_80amp_1s.mp3
new file mode 100644
index 000000000..6108d27ec
--- /dev/null
+++ b/sdl_android/src/androidTest/res/raw/test_audio_square_250hz_80amp_1s.mp3
Binary files differ
diff --git a/sdl_android/src/main/AndroidManifest.xml b/sdl_android/src/main/AndroidManifest.xml
index a958fb2fc..32a1590e5 100644
--- a/sdl_android/src/main/AndroidManifest.xml
+++ b/sdl_android/src/main/AndroidManifest.xml
@@ -1,3 +1,4 @@
-<manifest package="com.smartdevicelink" xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-sdk android:minSdkVersion="8"/>
+<manifest package="com.smartdevicelink"
+ xmlns:tools="http://schemas.android.com/tools">
+ <uses-sdk tools:overrideLibrary="android.arch.lifecycle, android.arch.lifecycle.extensions, android.arch.lifecycle.livedata, android.arch.lifecycle.livedata.core, android.arch.core, android.arch.lifecycle.viewmodel, android.support.fragment, android.support.coreui, android.support.coreutils, android.support.compat" />
</manifest>
diff --git a/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/ISdlConnectionListener.java b/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/ISdlConnectionListener.java
index 16350da4b..5035f5547 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/ISdlConnectionListener.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/ISdlConnectionListener.java
@@ -2,13 +2,21 @@ package com.smartdevicelink.SdlConnection;
import com.smartdevicelink.protocol.ProtocolMessage;
import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.transport.MultiplexTransportConfig;
+import com.smartdevicelink.transport.enums.TransportType;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
public interface ISdlConnectionListener {
+ @Deprecated
public void onTransportDisconnected(String info);
-
+
+ public void onTransportDisconnected(String info, boolean availablePrimary, MultiplexTransportConfig transportConfig);
+
+
public void onTransportError(String info, Exception e);
public void onProtocolMessageReceived(ProtocolMessage msg);
diff --git a/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlConnection.java b/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlConnection.java
index b346884aa..19b60abe2 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlConnection.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlConnection.java
@@ -2,9 +2,11 @@ package com.smartdevicelink.SdlConnection;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import android.content.ComponentName;
+import android.os.Bundle;
import android.util.Log;
import com.smartdevicelink.exception.SdlException;
@@ -29,6 +31,7 @@ import com.smartdevicelink.transport.USBTransport;
import com.smartdevicelink.transport.USBTransportConfig;
import com.smartdevicelink.transport.enums.TransportType;
+@Deprecated
public class SdlConnection implements IProtocolListener, ITransportListener {
private static final String TAG = "SdlConnection";
@@ -279,7 +282,8 @@ public class SdlConnection implements IProtocolListener, ITransportListener {
public void onProtocolError(String info, Exception e) {
_connectionListener.onProtocolError(info, e);
}
-
+
+
/**
* Gets type of transport currently used by this connection.
*
@@ -374,6 +378,11 @@ public class SdlConnection implements IProtocolListener, ITransportListener {
}
@Override
+ public void onTransportDisconnected(String info, boolean availablePrimary, MultiplexTransportConfig transportConfig) {
+ onTransportDisconnected(info);
+ }
+
+ @Override
public void onTransportError(String info, Exception e) {
//If there's an error with the transport we want to make sure we clear out any reference to it held by the static list in sessions
SdlSession.removeConnection(SdlConnection.this);
@@ -465,7 +474,7 @@ public class SdlConnection implements IProtocolListener, ITransportListener {
if (session != null) {
session.onProtocolServiceDataACK(serviceType, dataSize, sessionID);
}
- }
+ }
}
public int getRegisterCount() {
diff --git a/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession.java b/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession.java
index 20bcc0cc8..c3e66fb06 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession.java
@@ -1,15 +1,5 @@
package com.smartdevicelink.SdlConnection;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
-import java.util.HashMap;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.concurrent.CopyOnWriteArrayList;
-
import android.annotation.SuppressLint;
import android.os.Build;
import android.util.Log;
@@ -33,66 +23,84 @@ import com.smartdevicelink.security.ISecurityInitializedListener;
import com.smartdevicelink.security.SdlSecurityBase;
import com.smartdevicelink.streaming.AbstractPacketizer;
import com.smartdevicelink.streaming.IStreamListener;
-import com.smartdevicelink.streaming.video.RTPH264Packetizer;
import com.smartdevicelink.streaming.StreamPacketizer;
import com.smartdevicelink.streaming.StreamRPCPacketizer;
+import com.smartdevicelink.streaming.video.RTPH264Packetizer;
import com.smartdevicelink.streaming.video.VideoStreamingParameters;
import com.smartdevicelink.transport.BaseTransportConfig;
import com.smartdevicelink.transport.MultiplexTransport;
+import com.smartdevicelink.transport.MultiplexTransportConfig;
import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.util.Version;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+@Deprecated
public class SdlSession implements ISdlConnectionListener, IHeartbeatMonitorListener, IStreamListener, ISecurityInitializedListener {
+
+ private static final String TAG = "SdlSession";
+
+ protected final static int BUFF_READ_SIZE = 1024;
+
private static CopyOnWriteArrayList<SdlConnection> shareConnections = new CopyOnWriteArrayList<SdlConnection>();
- private CopyOnWriteArrayList<SessionType> encryptedServices = new CopyOnWriteArrayList<SessionType>();
-
+
+ private byte wiproProcolVer;
+
+ protected BaseTransportConfig transportConfig;
+ protected ISdlConnectionListener sessionListener;
+ protected LockScreenManager lockScreenMan = new LockScreenManager();
+ protected SdlSecurityBase sdlSecurity = null;
+ protected VideoStreamingParameters desiredVideoParams = null;
+ protected VideoStreamingParameters acceptedVideoParams = null;
+
+ protected byte sessionId;
+ protected int sessionHashId = 0;
+ protected HashMap<SessionType, CopyOnWriteArrayList<ISdlServiceListener>> serviceListeners;
+ protected CopyOnWriteArrayList<SessionType> encryptedServices = new CopyOnWriteArrayList<SessionType>();
+
+
SdlConnection _sdlConnection = null;
- private byte sessionId;
- private byte wiproProcolVer;
- private ISdlConnectionListener sessionListener;
- private BaseTransportConfig transportConfig;
- IHeartbeatMonitor _outgoingHeartbeatMonitor = null;
- IHeartbeatMonitor _incomingHeartbeatMonitor = null;
- private static final String TAG = "SdlSession";
- private LockScreenManager lockScreenMan = new LockScreenManager();
- private SdlSecurityBase sdlSecurity = null;
- StreamRPCPacketizer mRPCPacketizer = null;
- AbstractPacketizer mVideoPacketizer = null;
- StreamPacketizer mAudioPacketizer = null;
- SdlEncoder mSdlEncoder = null;
- VirtualDisplayEncoder virtualDisplayEncoder = null;
- private final static int BUFF_READ_SIZE = 1024;
- private int sessionHashId = 0;
- private HashMap<SessionType, CopyOnWriteArrayList<ISdlServiceListener>> serviceListeners;
- private VideoStreamingParameters desiredVideoParams = null;
- private VideoStreamingParameters acceptedVideoParams = null;
-
-
- public static SdlSession createSession(byte wiproVersion, ISdlConnectionListener listener, BaseTransportConfig btConfig) {
-
- SdlSession session = new SdlSession();
- session.wiproProcolVer = wiproVersion;
- session.sessionListener = listener;
- session.transportConfig = btConfig;
-
- return session;
- }
-
- public BaseTransportConfig getTransportConfig() {
- return this.transportConfig;
- }
-
- public LockScreenManager getLockScreenMan() {
- return lockScreenMan;
- }
-
-
- private SdlSession() {
- }
-
+
+ IHeartbeatMonitor _outgoingHeartbeatMonitor = null;
+ IHeartbeatMonitor _incomingHeartbeatMonitor = null;
+
+ StreamRPCPacketizer mRPCPacketizer = null;
+ AbstractPacketizer mVideoPacketizer = null;
+ StreamPacketizer mAudioPacketizer = null;
+ SdlEncoder mSdlEncoder = null;
+ VirtualDisplayEncoder virtualDisplayEncoder = null;
+
+ public static SdlSession createSession(byte wiproVersion, ISdlConnectionListener listener, BaseTransportConfig btConfig) {
+
+ SdlSession session = new SdlSession();
+ session.wiproProcolVer = wiproVersion;
+ session.sessionListener = listener;
+ session.transportConfig = btConfig;
+
+ return session;
+ }
+
+ public BaseTransportConfig getTransportConfig() {
+ return this.transportConfig;
+ }
+
+ public LockScreenManager getLockScreenMan() {
+ return lockScreenMan;
+ }
+
+
public IHeartbeatMonitor getOutgoingHeartbeatMonitor() {
return _outgoingHeartbeatMonitor;
}
-
+
public IHeartbeatMonitor getIncomingHeartbeatMonitor() {
return _incomingHeartbeatMonitor;
}
@@ -100,85 +108,85 @@ public class SdlSession implements ISdlConnectionListener, IHeartbeatMonitorList
public void setOutgoingHeartbeatMonitor(IHeartbeatMonitor outgoingHeartbeatMonitor) {
this._outgoingHeartbeatMonitor = outgoingHeartbeatMonitor;
_outgoingHeartbeatMonitor.setListener(this);
- }
+ }
public void setIncomingHeartbeatMonitor(IHeartbeatMonitor incomingHeartbeatMonitor) {
this._incomingHeartbeatMonitor = incomingHeartbeatMonitor;
_incomingHeartbeatMonitor.setListener(this);
- }
-
+ }
+
public int getSessionHashId() {
- return this.sessionHashId;
- }
-
- public byte getSessionId() {
- return this.sessionId;
- }
-
- public SdlConnection getSdlConnection() {
- return this._sdlConnection;
- }
-
- public int getMtu(){
- if(this._sdlConnection!=null){
- return this._sdlConnection.getWiProProtocol().getMtu();
- }else{
- return 0;
- }
- }
-
- public long getMtu(SessionType type) {
- if (this._sdlConnection != null) {
- return this._sdlConnection.getWiProProtocol().getMtu(type);
- } else {
- return 0;
- }
- }
-
- public void close() {
- if (sdlSecurity != null)
- {
- sdlSecurity.resetParams();
- sdlSecurity.shutDown();
- }
-
- if (_sdlConnection != null) { //sessionId == 0 means session is not started.
- _sdlConnection.unregisterSession(this);
-
- if (_sdlConnection.getRegisterCount() == 0) {
- shareConnections.remove(_sdlConnection);
- }
-
- _sdlConnection = null;
- }
- }
-
- public void startStream(InputStream is, SessionType sType, byte rpcSessionID) throws IOException {
+ return this.sessionHashId;
+ }
+
+ public byte getSessionId() {
+ return this.sessionId;
+ }
+
+ public SdlConnection getSdlConnection() {
+ return this._sdlConnection;
+ }
+
+ public int getMtu(){
+ if(this._sdlConnection!=null){
+ return this._sdlConnection.getWiProProtocol().getMtu();
+ }else{
+ return 0;
+ }
+ }
+
+ public long getMtu(SessionType type) {
+ if (this._sdlConnection != null) {
+ return this._sdlConnection.getWiProProtocol().getMtu(type);
+ } else {
+ return 0;
+ }
+ }
+
+ public void close() {
+ if (sdlSecurity != null)
+ {
+ sdlSecurity.resetParams();
+ sdlSecurity.shutDown();
+ }
+
+ if (_sdlConnection != null) { //sessionId == 0 means session is not started.
+ //_sdlConnection.unregisterSession(this);
+
+ if (_sdlConnection.getRegisterCount() == 0) {
+ shareConnections.remove(_sdlConnection);
+ }
+
+ _sdlConnection = null;
+ }
+ }
+
+ public void startStream(InputStream is, SessionType sType, byte rpcSessionID) throws IOException {
if (sType.equals(SessionType.NAV))
{
- // protocol is fixed to RAW
- StreamPacketizer packetizer = new StreamPacketizer(this, is, sType, rpcSessionID, this);
- packetizer.sdlConnection = this.getSdlConnection();
- mVideoPacketizer = packetizer;
- mVideoPacketizer.start();
+ // protocol is fixed to RAW
+ StreamPacketizer packetizer = new StreamPacketizer(this, is, sType, rpcSessionID, this);
+ packetizer.sdlConnection = this.getSdlConnection();
+ mVideoPacketizer = packetizer;
+ mVideoPacketizer.start();
}
else if (sType.equals(SessionType.PCM))
{
- mAudioPacketizer = new StreamPacketizer(this, is, sType, rpcSessionID, this);
- mAudioPacketizer.sdlConnection = this.getSdlConnection();
- mAudioPacketizer.start();
- }
- }
-
- @SuppressLint("NewApi")
- public OutputStream startStream(SessionType sType, byte rpcSessionID) throws IOException {
- OutputStream os = new PipedOutputStream();
- InputStream is = null;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
- is = new PipedInputStream((PipedOutputStream) os, BUFF_READ_SIZE);
- } else {
- is = new PipedInputStream((PipedOutputStream) os);
- }
+ mAudioPacketizer = new StreamPacketizer(this, is, sType, rpcSessionID, this);
+ mAudioPacketizer.sdlConnection = this.getSdlConnection();
+ mAudioPacketizer.start();
+ }
+ }
+
+ @SuppressLint("NewApi")
+ public OutputStream startStream(SessionType sType, byte rpcSessionID) throws IOException {
+ OutputStream os = new PipedOutputStream();
+ InputStream is = null;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
+ is = new PipedInputStream((PipedOutputStream) os, BUFF_READ_SIZE);
+ } else {
+ is = new PipedInputStream((PipedOutputStream) os);
+ }
if (sType.equals(SessionType.NAV))
{
// protocol is fixed to RAW
@@ -186,565 +194,597 @@ public class SdlSession implements ISdlConnectionListener, IHeartbeatMonitorList
packetizer.sdlConnection = this.getSdlConnection();
mVideoPacketizer = packetizer;
mVideoPacketizer.start();
- }
+ }
else if (sType.equals(SessionType.PCM))
{
- mAudioPacketizer = new StreamPacketizer(this, is, sType, rpcSessionID, this);
- mAudioPacketizer.sdlConnection = this.getSdlConnection();
- mAudioPacketizer.start();
+ mAudioPacketizer = new StreamPacketizer(this, is, sType, rpcSessionID, this);
+ mAudioPacketizer.sdlConnection = this.getSdlConnection();
+ mAudioPacketizer.start();
}
else
{
- os.close();
- is.close();
- return null;
- }
- return os;
- }
-
- public IVideoStreamListener startVideoStream() {
- byte rpcSessionID = getSessionId();
- VideoStreamingProtocol protocol = getAcceptedProtocol();
- try {
- switch (protocol) {
- case RAW: {
- StreamPacketizer packetizer = new StreamPacketizer(this, null, SessionType.NAV, rpcSessionID, this);
- packetizer.sdlConnection = this.getSdlConnection();
- mVideoPacketizer = packetizer;
- mVideoPacketizer.start();
- return packetizer;
- }
- case RTP: {
- RTPH264Packetizer packetizer = new RTPH264Packetizer(this, SessionType.NAV, rpcSessionID, this);
- mVideoPacketizer = packetizer;
- mVideoPacketizer.start();
- return packetizer;
- }
- default:
- Log.e(TAG, "Protocol " + protocol + " is not supported.");
- return null;
- }
- } catch (IOException e) {
- return null;
- }
- }
-
- public IAudioStreamListener startAudioStream() {
- byte rpcSessionID = getSessionId();
- try {
- StreamPacketizer packetizer = new StreamPacketizer(this, null, SessionType.PCM, rpcSessionID, this);
- packetizer.sdlConnection = this.getSdlConnection();
- mAudioPacketizer = packetizer;
- mAudioPacketizer.start();
- return packetizer;
- } catch (IOException e) {
- return null;
- }
- }
-
- public void startRPCStream(InputStream is, RPCRequest request, SessionType sType, byte rpcSessionID, byte wiproVersion) {
- try {
- mRPCPacketizer = new StreamRPCPacketizer(null, this, is, request, sType, rpcSessionID, wiproVersion, 0, this);
- mRPCPacketizer.start();
- } catch (Exception e) {
- Log.e("SdlConnection", "Unable to start streaming:" + e.toString());
- }
- }
-
- public OutputStream startRPCStream(RPCRequest request, SessionType sType, byte rpcSessionID, byte wiproVersion) {
- try {
- OutputStream os = new PipedOutputStream();
- InputStream is = new PipedInputStream((PipedOutputStream) os);
- mRPCPacketizer = new StreamRPCPacketizer(null, this, is, request, sType, rpcSessionID, wiproVersion, 0, this);
- mRPCPacketizer.start();
- return os;
- } catch (Exception e) {
- Log.e("SdlConnection", "Unable to start streaming:" + e.toString());
- }
- return null;
- }
-
- public void pauseRPCStream()
- {
- if (mRPCPacketizer != null)
- {
- mRPCPacketizer.pause();
- }
- }
-
- public void resumeRPCStream()
- {
- if (mRPCPacketizer != null)
- {
- mRPCPacketizer.resume();
- }
- }
-
- public void stopRPCStream()
- {
- if (mRPCPacketizer != null)
- {
- mRPCPacketizer.stop();
- }
- }
-
- public boolean stopAudioStream()
- {
- if (mAudioPacketizer != null)
- {
- mAudioPacketizer.stop();
- return true;
- }
- return false;
- }
-
- public boolean stopVideoStream()
- {
- if (mVideoPacketizer != null)
- {
- mVideoPacketizer.stop();
- return true;
- }
- return false;
- }
-
- public boolean pauseAudioStream()
- {
- if (mAudioPacketizer != null)
- {
- mAudioPacketizer.pause();
- return true;
- }
- return false;
- }
-
- public boolean pauseVideoStream()
- {
- if (mVideoPacketizer != null)
- {
- mVideoPacketizer.pause();
- return true;
- }
- return false;
- }
-
- public boolean resumeAudioStream()
- {
- if (mAudioPacketizer != null)
- {
- mAudioPacketizer.resume();
- return true;
- }
- return false;
- }
-
- public boolean resumeVideoStream()
- {
- if (mVideoPacketizer != null)
- {
- mVideoPacketizer.resume();
- return true;
- }
- return false;
- }
-
- public Surface createOpenGLInputSurface(int frameRate, int iFrameInterval, int width,
- int height, int bitrate, SessionType sType, byte rpcSessionID) {
- IVideoStreamListener encoderListener = startVideoStream();
- if (encoderListener == null) {
- return null;
- }
-
- mSdlEncoder = new SdlEncoder();
- mSdlEncoder.setFrameRate(frameRate);
- mSdlEncoder.setFrameInterval(iFrameInterval);
- mSdlEncoder.setFrameWidth(width);
- mSdlEncoder.setFrameHeight(height);
- mSdlEncoder.setBitrate(bitrate);
- mSdlEncoder.setOutputListener(encoderListener);
- return mSdlEncoder.prepareEncoder();
- }
-
- public void startEncoder () {
- if(mSdlEncoder != null) {
- mSdlEncoder.startEncoder();
- }
- }
-
- public void releaseEncoder() {
- if(mSdlEncoder != null) {
- mSdlEncoder.releaseEncoder();
- }
- }
-
- public void drainEncoder(boolean endOfStream) {
- if(mSdlEncoder != null) {
- mSdlEncoder.drainEncoder(endOfStream);
- }
- }
-
- @Override
- public void sendStreamPacket(ProtocolMessage pm) {
- sendMessage(pm);
- }
-
- public void setSdlSecurity(SdlSecurityBase sec) {
- sdlSecurity = sec;
- }
-
- public SdlSecurityBase getSdlSecurity() {
- return sdlSecurity;
- }
-
- public void startService (SessionType serviceType, byte sessionID, boolean isEncrypted) {
- if (_sdlConnection == null)
- return;
-
- if (isEncrypted)
- {
- if (sdlSecurity != null)
- {
- List<SessionType> serviceList = sdlSecurity.getServiceList();
- if (!serviceList.contains(serviceType))
- serviceList.add(serviceType);
-
- sdlSecurity.initialize();
- }
- return;
- }
- _sdlConnection.startService(serviceType, sessionID, isEncrypted);
- }
-
- public void endService (SessionType serviceType, byte sessionID) {
- if (_sdlConnection == null)
- return;
- _sdlConnection.endService(serviceType, sessionID);
- }
-
- private void processControlService(ProtocolMessage msg) {
- if (sdlSecurity == null)
- return;
- int ilen = msg.getData().length - 12;
- byte[] data = new byte[ilen];
- System.arraycopy(msg.getData(), 12, data, 0, ilen);
-
- byte[] dataToRead = new byte[4096];
-
- Integer iNumBytes = sdlSecurity.runHandshake(data, dataToRead);
-
- if (iNumBytes == null || iNumBytes <= 0)
- return;
-
- byte[] returnBytes = new byte[iNumBytes];
- System.arraycopy(dataToRead, 0, returnBytes, 0, iNumBytes);
- ProtocolMessage protocolMessage = new ProtocolMessage();
- protocolMessage.setSessionType(SessionType.CONTROL);
- protocolMessage.setData(returnBytes);
- protocolMessage.setFunctionID(0x01);
- protocolMessage.setVersion(wiproProcolVer);
- protocolMessage.setSessionID(getSessionId());
-
- //sdlSecurity.hs();
-
- sendMessage(protocolMessage);
- }
-
- public String getBroadcastComment(BaseTransportConfig myTransport) {
- SdlConnection connection = null;
- if (myTransport.shareConnection()) {
- connection = findTheProperConnection(myTransport);
- } else {
- connection = this._sdlConnection;
- }
-
- if (connection != null)
- return connection.getBroadcastComment();
-
- return "";
- }
-
-
- public void startSession() throws SdlException {
- SdlConnection connection = null;
- if (this.transportConfig.shareConnection()) {
- connection = findTheProperConnection(this.transportConfig);
-
- if (connection == null) {
- connection = new SdlConnection(this.transportConfig);
- shareConnections.add(connection);
- }
- } else {
- connection = new SdlConnection(this.transportConfig);
- }
-
- this._sdlConnection = connection;
- connection.registerSession(this); //Handshake will start when register.
- }
-
- private void initialiseSession() {
+ os.close();
+ is.close();
+ return null;
+ }
+ return os;
+ }
+
+ public IVideoStreamListener startVideoStream() {
+ byte rpcSessionID = getSessionId();
+ VideoStreamingProtocol protocol = getAcceptedProtocol();
+ try {
+ switch (protocol) {
+ case RAW: {
+ StreamPacketizer packetizer = new StreamPacketizer(this, null, SessionType.NAV, rpcSessionID, this);
+ packetizer.sdlConnection = this.getSdlConnection();
+ mVideoPacketizer = packetizer;
+ mVideoPacketizer.start();
+ return packetizer;
+ }
+ case RTP: {
+ RTPH264Packetizer packetizer = new RTPH264Packetizer(this, SessionType.NAV, rpcSessionID, this);
+ mVideoPacketizer = packetizer;
+ mVideoPacketizer.start();
+ return packetizer;
+ }
+ default:
+ Log.e(TAG, "Protocol " + protocol + " is not supported.");
+ return null;
+ }
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ public IAudioStreamListener startAudioStream() {
+ byte rpcSessionID = getSessionId();
+ try {
+ StreamPacketizer packetizer = new StreamPacketizer(this, null, SessionType.PCM, rpcSessionID, this);
+ packetizer.sdlConnection = this.getSdlConnection();
+ mAudioPacketizer = packetizer;
+ mAudioPacketizer.start();
+ return packetizer;
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ public void startRPCStream(InputStream is, RPCRequest request, SessionType sType, byte rpcSessionID, byte wiproVersion) {
+ try {
+ mRPCPacketizer = new StreamRPCPacketizer(null, this, is, request, sType, rpcSessionID, wiproVersion, 0, this);
+ mRPCPacketizer.start();
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to start streaming:" + e.toString());
+ }
+ }
+
+ public OutputStream startRPCStream(RPCRequest request, SessionType sType, byte rpcSessionID, byte wiproVersion) {
+ try {
+ OutputStream os = new PipedOutputStream();
+ InputStream is = new PipedInputStream((PipedOutputStream) os);
+ mRPCPacketizer = new StreamRPCPacketizer(null, this, is, request, sType, rpcSessionID, wiproVersion, 0, this);
+ mRPCPacketizer.start();
+ return os;
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to start streaming:" + e.toString());
+ }
+ return null;
+ }
+
+ public void pauseRPCStream()
+ {
+ if (mRPCPacketizer != null)
+ {
+ mRPCPacketizer.pause();
+ }
+ }
+
+ public void resumeRPCStream()
+ {
+ if (mRPCPacketizer != null)
+ {
+ mRPCPacketizer.resume();
+ }
+ }
+
+ public void stopRPCStream()
+ {
+ if (mRPCPacketizer != null)
+ {
+ mRPCPacketizer.stop();
+ }
+ }
+
+ public boolean stopAudioStream()
+ {
+ if (mAudioPacketizer != null)
+ {
+ mAudioPacketizer.stop();
+ return true;
+ }
+ return false;
+ }
+
+ public boolean stopVideoStream()
+ {
+ if (mVideoPacketizer != null)
+ {
+ mVideoPacketizer.stop();
+ return true;
+ }
+ return false;
+ }
+
+ public boolean pauseAudioStream()
+ {
+ if (mAudioPacketizer != null)
+ {
+ mAudioPacketizer.pause();
+ return true;
+ }
+ return false;
+ }
+
+ public boolean pauseVideoStream()
+ {
+ if (mVideoPacketizer != null)
+ {
+ mVideoPacketizer.pause();
+ return true;
+ }
+ return false;
+ }
+
+ public boolean resumeAudioStream()
+ {
+ if (mAudioPacketizer != null)
+ {
+ mAudioPacketizer.resume();
+ return true;
+ }
+ return false;
+ }
+
+ public boolean resumeVideoStream()
+ {
+ if (mVideoPacketizer != null)
+ {
+ mVideoPacketizer.resume();
+ return true;
+ }
+ return false;
+ }
+
+ public Surface createOpenGLInputSurface(int frameRate, int iFrameInterval, int width,
+ int height, int bitrate, SessionType sType, byte rpcSessionID) {
+ IVideoStreamListener encoderListener = startVideoStream();
+ if (encoderListener == null) {
+ return null;
+ }
+
+ mSdlEncoder = new SdlEncoder();
+ mSdlEncoder.setFrameRate(frameRate);
+ mSdlEncoder.setFrameInterval(iFrameInterval);
+ mSdlEncoder.setFrameWidth(width);
+ mSdlEncoder.setFrameHeight(height);
+ mSdlEncoder.setBitrate(bitrate);
+ mSdlEncoder.setOutputListener(encoderListener);
+ return mSdlEncoder.prepareEncoder();
+ }
+
+ public void startEncoder () {
+ if(mSdlEncoder != null) {
+ mSdlEncoder.startEncoder();
+ }
+ }
+
+ public void releaseEncoder() {
+ if(mSdlEncoder != null) {
+ mSdlEncoder.releaseEncoder();
+ }
+ }
+
+ public void drainEncoder(boolean endOfStream) {
+ if(mSdlEncoder != null) {
+ mSdlEncoder.drainEncoder(endOfStream);
+ }
+ }
+
+ @Override
+ public void sendStreamPacket(ProtocolMessage pm) {
+ sendMessage(pm);
+ }
+
+ public void setSdlSecurity(SdlSecurityBase sec) {
+ sdlSecurity = sec;
+ }
+
+ public SdlSecurityBase getSdlSecurity() {
+ return sdlSecurity;
+ }
+
+ public void startService (SessionType serviceType, byte sessionID, boolean isEncrypted) {
+ if (_sdlConnection == null)
+ return;
+
+ if (isEncrypted)
+ {
+ if (sdlSecurity != null)
+ {
+ List<SessionType> serviceList = sdlSecurity.getServiceList();
+ if (!serviceList.contains(serviceType))
+ serviceList.add(serviceType);
+
+ sdlSecurity.initialize();
+ }
+ return;
+ }
+ _sdlConnection.startService(serviceType, sessionID, isEncrypted);
+ }
+
+ public void endService (SessionType serviceType, byte sessionID) {
+ if (_sdlConnection == null)
+ return;
+ _sdlConnection.endService(serviceType, sessionID);
+ }
+
+ protected void processControlService(ProtocolMessage msg) {
+ if (sdlSecurity == null)
+ return;
+ int ilen = msg.getData().length - 12;
+ byte[] data = new byte[ilen];
+ System.arraycopy(msg.getData(), 12, data, 0, ilen);
+
+ byte[] dataToRead = new byte[4096];
+
+ Integer iNumBytes = sdlSecurity.runHandshake(data, dataToRead);
+
+ if (iNumBytes == null || iNumBytes <= 0)
+ return;
+
+ byte[] returnBytes = new byte[iNumBytes];
+ System.arraycopy(dataToRead, 0, returnBytes, 0, iNumBytes);
+ ProtocolMessage protocolMessage = new ProtocolMessage();
+ protocolMessage.setSessionType(SessionType.CONTROL);
+ protocolMessage.setData(returnBytes);
+ protocolMessage.setFunctionID(0x01);
+ protocolMessage.setVersion(wiproProcolVer);
+ protocolMessage.setSessionID(getSessionId());
+
+ //sdlSecurity.hs();
+
+ sendMessage(protocolMessage);
+ }
+
+ public String getBroadcastComment(BaseTransportConfig myTransport) {
+ SdlConnection connection = null;
+ if (myTransport.shareConnection()) {
+ connection = findTheProperConnection(myTransport);
+ } else {
+ connection = this._sdlConnection;
+ }
+
+ if (connection != null)
+ return connection.getBroadcastComment();
+
+ return "";
+ }
+
+
+ public void startSession() throws SdlException {
+ SdlConnection connection = null;
+ if (this.transportConfig.shareConnection()) {
+ connection = findTheProperConnection(this.transportConfig);
+
+ if (connection == null) {
+ connection = new SdlConnection(this.transportConfig);
+ shareConnections.add(connection);
+ }
+ } else {
+ connection = new SdlConnection(this.transportConfig);
+ }
+
+ this._sdlConnection = connection;
+ connection.registerSession(this); //Handshake will start when register.
+ }
+
+ protected void initialiseSession() {
if (_outgoingHeartbeatMonitor != null) {
- _outgoingHeartbeatMonitor.start();
+ _outgoingHeartbeatMonitor.start();
}
if (_incomingHeartbeatMonitor != null) {
- _incomingHeartbeatMonitor.start();
- }
- }
-
- public void sendMessage(ProtocolMessage msg) {
- if (_sdlConnection == null)
- return;
- _sdlConnection.sendMessage(msg);
- }
-
- public TransportType getCurrentTransportType() {
- if (_sdlConnection == null)
- return null;
- return _sdlConnection.getCurrentTransportType();
- }
-
- public boolean getIsConnected() {
- if (_sdlConnection == null)
- return false;
- return _sdlConnection != null && _sdlConnection.getIsConnected();
- }
-
- public boolean isServiceProtected(SessionType sType) {
- return encryptedServices.contains(sType);
- }
-
- @Override
- public void onTransportDisconnected(String info) {
- this.sessionListener.onTransportDisconnected(info);
- }
-
- @Override
- public void onTransportError(String info, Exception e) {
- this.sessionListener.onTransportError(info, e);
- }
-
- @Override
- public void onProtocolMessageReceived(ProtocolMessage msg) {
- if (msg.getSessionType().equals(SessionType.CONTROL)) {
- processControlService(msg);
- return;
- }
-
- this.sessionListener.onProtocolMessageReceived(msg);
- }
-
- @Override
- public void onHeartbeatTimedOut(byte sessionID) {
- this.sessionListener.onHeartbeatTimedOut(sessionID);
-
- }
-
-
- @Override
- public void onProtocolSessionStarted(SessionType sessionType,
- byte sessionID, byte version, String correlationID, int hashID, boolean isEncrypted) {
- this.sessionId = sessionID;
- lockScreenMan.setSessionID(sessionID);
- if (isEncrypted)
- encryptedServices.addIfAbsent(sessionType);
- this.sessionListener.onProtocolSessionStarted(sessionType, sessionID, version, correlationID, hashID, isEncrypted);
- if(serviceListeners != null && serviceListeners.containsKey(sessionType)){
- CopyOnWriteArrayList<ISdlServiceListener> listeners = serviceListeners.get(sessionType);
- for(ISdlServiceListener listener:listeners){
- listener.onServiceStarted(this, sessionType, isEncrypted);
- }
- }
- //if (version == 3)
- initialiseSession();
- if (sessionType.eq(SessionType.RPC)){
- sessionHashId = hashID;
- }
- }
-
- @Override
- public void onProtocolSessionEnded(SessionType sessionType, byte sessionID,
- String correlationID) {
- this.sessionListener.onProtocolSessionEnded(sessionType, sessionID, correlationID);
- if(serviceListeners != null && serviceListeners.containsKey(sessionType)){
- CopyOnWriteArrayList<ISdlServiceListener> listeners = serviceListeners.get(sessionType);
- for(ISdlServiceListener listener:listeners){
- listener.onServiceEnded(this, sessionType);
- }
- }
- encryptedServices.remove(sessionType);
- }
-
- @Override
- public void onProtocolError(String info, Exception e) {
- this.sessionListener.onProtocolError(info, e);
- }
-
+ _incomingHeartbeatMonitor.start();
+ }
+ }
+
+ public void sendMessage(ProtocolMessage msg) {
+ if (_sdlConnection == null)
+ return;
+ _sdlConnection.sendMessage(msg);
+ }
+
+ public TransportType getCurrentTransportType() {
+ if (_sdlConnection == null)
+ return null;
+ return _sdlConnection.getCurrentTransportType();
+ }
+
+ public boolean getIsConnected() {
+ if (_sdlConnection == null)
+ return false;
+ return _sdlConnection != null && _sdlConnection.getIsConnected();
+ }
+
+ public boolean isServiceProtected(SessionType sType) {
+ return encryptedServices.contains(sType);
+ }
+
+ @Override
+ public void onTransportDisconnected(String info) {
+ this.sessionListener.onTransportDisconnected(info);
+ }
+
+ @Override
+ public void onTransportDisconnected(String info, boolean availablePrimary, MultiplexTransportConfig transportConfig) {
+ this.sessionListener.onTransportDisconnected(info);
+ }
+
+ @Override
+ public void onTransportError(String info, Exception e) {
+ this.sessionListener.onTransportError(info, e);
+ }
+
+ @Override
+ public void onProtocolMessageReceived(ProtocolMessage msg) {
+ if (msg.getSessionType().equals(SessionType.CONTROL)) {
+ processControlService(msg);
+ return;
+ }
+
+ this.sessionListener.onProtocolMessageReceived(msg);
+ }
+
+ @Override
+ public void onHeartbeatTimedOut(byte sessionID) {
+ this.sessionListener.onHeartbeatTimedOut(sessionID);
+
+ }
+
+
+ @Override
+ public void onProtocolSessionStarted(SessionType sessionType,
+ byte sessionID, byte version, String correlationID, int hashID, boolean isEncrypted) {
+ this.sessionId = sessionID;
+ lockScreenMan.setSessionID(sessionID);
+ if (sessionType.eq(SessionType.RPC)){
+ sessionHashId = hashID;
+ wiproProcolVer = version;
+ }
+ if (isEncrypted)
+ encryptedServices.addIfAbsent(sessionType);
+ this.sessionListener.onProtocolSessionStarted(sessionType, sessionID, version, correlationID, hashID, isEncrypted);
+ if(serviceListeners != null && serviceListeners.containsKey(sessionType)){
+ CopyOnWriteArrayList<ISdlServiceListener> listeners = serviceListeners.get(sessionType);
+ for(ISdlServiceListener listener:listeners){
+ listener.onServiceStarted(this, sessionType, isEncrypted);
+ }
+ }
+ //if (version == 3)
+ initialiseSession();
+
+ }
+
+ @Override
+ public void onProtocolSessionEnded(SessionType sessionType, byte sessionID,
+ String correlationID) {
+ this.sessionListener.onProtocolSessionEnded(sessionType, sessionID, correlationID);
+ if(serviceListeners != null && serviceListeners.containsKey(sessionType)){
+ CopyOnWriteArrayList<ISdlServiceListener> listeners = serviceListeners.get(sessionType);
+ for(ISdlServiceListener listener:listeners){
+ listener.onServiceEnded(this, sessionType);
+ }
+ }
+ encryptedServices.remove(sessionType);
+ }
+
+ @Override
+ public void onProtocolError(String info, Exception e) {
+ this.sessionListener.onProtocolError(info, e);
+ }
+
@Override
public void sendHeartbeat(IHeartbeatMonitor monitor) {
Log.d(TAG, "Asked to send heartbeat");
if (_sdlConnection != null)
- _sdlConnection.sendHeartbeat(this);
+ _sdlConnection.sendHeartbeat(this);
}
@Override
- public void heartbeatTimedOut(IHeartbeatMonitor monitor) {
+ public void heartbeatTimedOut(IHeartbeatMonitor monitor) {
if (_sdlConnection != null)
- _sdlConnection._connectionListener.onHeartbeatTimedOut(this.sessionId);
+ _sdlConnection._connectionListener.onHeartbeatTimedOut(this.sessionId);
close();
}
- private static SdlConnection findTheProperConnection(BaseTransportConfig config) {
- SdlConnection connection = null;
-
- int minCount = 0;
- for (SdlConnection c : shareConnections) {
- if (c.getCurrentTransportType() == config.getTransportType()) {
- if (minCount == 0 || minCount >= c.getRegisterCount()) {
- connection = c;
- minCount = c.getRegisterCount();
- }
- }
- }
-
- return connection;
- }
-
- @Override
- public void onProtocolSessionStartedNACKed(SessionType sessionType,
- byte sessionID, byte version, String correlationID, List<String> rejectedParams) {
- this.sessionListener.onProtocolSessionStartedNACKed(sessionType,
- sessionID, version, correlationID, rejectedParams);
- if(serviceListeners != null && serviceListeners.containsKey(sessionType)){
- CopyOnWriteArrayList<ISdlServiceListener> listeners = serviceListeners.get(sessionType);
- for(ISdlServiceListener listener:listeners){
- listener.onServiceError(this, sessionType, "Start "+ sessionType.toString() +" Service NACK'ed");
- }
- }
- }
-
- @Override
- public void onProtocolSessionEndedNACKed(SessionType sessionType,
- byte sessionID, String correlationID) {
- this.sessionListener.onProtocolSessionEndedNACKed(sessionType, sessionID, correlationID);
- 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");
- }
- }
- }
-
- @Override
- public void onProtocolServiceDataACK(SessionType sessionType, int dataSize, byte sessionID) {
- this.sessionListener.onProtocolServiceDataACK(sessionType, dataSize, sessionID);
- }
-
- @Override
- public void onSecurityInitialized() {
-
- if (_sdlConnection != null && sdlSecurity != null)
- {
- List<SessionType> list = sdlSecurity.getServiceList();
-
- SessionType service;
- ListIterator<SessionType> iter = list.listIterator();
-
- while (iter.hasNext()) {
- service = iter.next();
-
- if (service != null)
- _sdlConnection.startService(service, getSessionId(), true);
-
- iter.remove();
- }
- }
- }
-
- public void clearConnection(){
- _sdlConnection = null;
- }
-
- public void checkForOpenMultiplexConnection(SdlConnection connection){
- removeConnection(connection);
- connection.unregisterSession(this);
- _sdlConnection = null;
- for (SdlConnection c : shareConnections) {
- if (c.getCurrentTransportType() == TransportType.MULTIPLEX) {
- if(c.getIsConnected() || ((MultiplexTransport)c._transport).isPendingConnected()){
- _sdlConnection = c;
- try {
- _sdlConnection.registerSession(this);//Handshake will start when register.
- } catch (SdlException e) {
- e.printStackTrace();
- }
- return;
- }
-
- }
- }
- }
- public static boolean removeConnection(SdlConnection connection){
- return shareConnections.remove(connection);
- }
-
- public void addServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener){
- if(serviceListeners == null){
- serviceListeners = new HashMap<>();
- }
- if(serviceType != null && sdlServiceListener != null){
- if(!serviceListeners.containsKey(serviceType)){
- serviceListeners.put(serviceType,new CopyOnWriteArrayList<ISdlServiceListener>());
- }
- serviceListeners.get(serviceType).add(sdlServiceListener);
- }
- }
-
- public boolean removeServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener){
- if(serviceListeners!= null && serviceType != null && sdlServiceListener != null && serviceListeners.containsKey(serviceType)){
- return serviceListeners.get(serviceType).remove(sdlServiceListener);
- }
- return false;
- }
-
-
- public HashMap<SessionType, CopyOnWriteArrayList<ISdlServiceListener>> getServiceListeners(){
- return serviceListeners;
- }
-
- public void setDesiredVideoParams(VideoStreamingParameters params){
- this.desiredVideoParams = params;
- }
-
- /**
- * Returns the currently set desired video streaming parameters. If there haven't been any set,
- * the default options will be returned and set for this instance.
- * @return
- */
- public VideoStreamingParameters getDesiredVideoParams(){
- if(desiredVideoParams == null){
- desiredVideoParams = new VideoStreamingParameters();
- }
- return desiredVideoParams;
- }
-
- public void setAcceptedVideoParams(VideoStreamingParameters params){
- this.acceptedVideoParams = params;
- }
-
- public VideoStreamingParameters getAcceptedVideoParams(){
- return acceptedVideoParams;
- }
-
- private VideoStreamingProtocol getAcceptedProtocol() {
- // acquire default protocol (RAW)
- VideoStreamingProtocol protocol = new VideoStreamingParameters().getFormat().getProtocol();
-
- if (acceptedVideoParams != null) {
- VideoStreamingFormat format = acceptedVideoParams.getFormat();
- if (format != null && format.getProtocol() != null) {
- protocol = format.getProtocol();
- }
- }
-
- return protocol;
- }
-}
+ private static SdlConnection findTheProperConnection(BaseTransportConfig config) {
+ SdlConnection connection = null;
+
+ int minCount = 0;
+ for (SdlConnection c : shareConnections) {
+ if (c.getCurrentTransportType() == config.getTransportType()) {
+ if (minCount == 0 || minCount >= c.getRegisterCount()) {
+ connection = c;
+ minCount = c.getRegisterCount();
+ }
+ }
+ }
+
+ return connection;
+ }
+
+ @Override
+ public void onProtocolSessionStartedNACKed(SessionType sessionType,
+ byte sessionID, byte version, String correlationID, List<String> rejectedParams) {
+ this.sessionListener.onProtocolSessionStartedNACKed(sessionType,
+ sessionID, version, correlationID, rejectedParams);
+ if(serviceListeners != null && serviceListeners.containsKey(sessionType)){
+ CopyOnWriteArrayList<ISdlServiceListener> listeners = serviceListeners.get(sessionType);
+ for(ISdlServiceListener listener:listeners){
+ listener.onServiceError(this, sessionType, "Start "+ sessionType.toString() +" Service NACK'ed");
+ }
+ }
+ }
+
+ @Override
+ public void onProtocolSessionEndedNACKed(SessionType sessionType,
+ byte sessionID, String correlationID) {
+ this.sessionListener.onProtocolSessionEndedNACKed(sessionType, sessionID, correlationID);
+ 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");
+ }
+ }
+ }
+
+ @Override
+ public void onProtocolServiceDataACK(SessionType sessionType, int dataSize, byte sessionID) {
+ this.sessionListener.onProtocolServiceDataACK(sessionType, dataSize, sessionID);
+ }
+
+ @Override
+ public void onSecurityInitialized() {
+
+ if (_sdlConnection != null && sdlSecurity != null)
+ {
+ List<SessionType> list = sdlSecurity.getServiceList();
+
+ SessionType service;
+ ListIterator<SessionType> iter = list.listIterator();
+
+ while (iter.hasNext()) {
+ service = iter.next();
+
+ if (service != null)
+ _sdlConnection.startService(service, getSessionId(), true);
+
+ iter.remove();
+ }
+ }
+ }
+
+ public void clearConnection(){
+ _sdlConnection = null;
+ }
+
+ public void checkForOpenMultiplexConnection(SdlConnection connection){
+ removeConnection(connection);
+ connection.unregisterSession(this);
+ _sdlConnection = null;
+ for (SdlConnection c : shareConnections) {
+ if (c.getCurrentTransportType() == TransportType.MULTIPLEX) {
+ if(c.getIsConnected() || ((MultiplexTransport)c._transport).isPendingConnected()){
+ _sdlConnection = c;
+ try {
+ _sdlConnection.registerSession(this);//Handshake will start when register.
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+ return;
+ }
+
+ }
+ }
+ }
+ public static boolean removeConnection(SdlConnection connection){
+ return shareConnections.remove(connection);
+ }
+
+ public void addServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener){
+ if(serviceListeners == null){
+ serviceListeners = new HashMap<>();
+ }
+ if(serviceType != null && sdlServiceListener != null){
+ if(!serviceListeners.containsKey(serviceType)){
+ serviceListeners.put(serviceType,new CopyOnWriteArrayList<ISdlServiceListener>());
+ }
+ serviceListeners.get(serviceType).add(sdlServiceListener);
+ }
+ }
+
+ public boolean removeServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener){
+ if(serviceListeners!= null && serviceType != null && sdlServiceListener != null && serviceListeners.containsKey(serviceType)){
+ return serviceListeners.get(serviceType).remove(sdlServiceListener);
+ }
+ return false;
+ }
+
+
+ public HashMap<SessionType, CopyOnWriteArrayList<ISdlServiceListener>> getServiceListeners(){
+ return serviceListeners;
+ }
+
+ public void setDesiredVideoParams(VideoStreamingParameters params){
+ this.desiredVideoParams = params;
+ }
+
+ /**
+ * Returns the currently set desired video streaming parameters. If there haven't been any set,
+ * the default options will be returned and set for this instance.
+ * @return
+ */
+ public VideoStreamingParameters getDesiredVideoParams(){
+ if(desiredVideoParams == null){
+ desiredVideoParams = new VideoStreamingParameters();
+ }
+ return desiredVideoParams;
+ }
+
+ public void setAcceptedVideoParams(VideoStreamingParameters params){
+ this.acceptedVideoParams = params;
+ }
+
+ public VideoStreamingParameters getAcceptedVideoParams(){
+ return acceptedVideoParams;
+ }
+
+ private VideoStreamingProtocol getAcceptedProtocol() {
+ // acquire default protocol (RAW)
+ VideoStreamingProtocol protocol = new VideoStreamingParameters().getFormat().getProtocol();
+
+ if (acceptedVideoParams != null) {
+ VideoStreamingFormat format = acceptedVideoParams.getFormat();
+ if (format != null && format.getProtocol() != null) {
+ protocol = format.getProtocol();
+ }
+ }
+
+ return protocol;
+ }
+
+ public Version getProtocolVersion(){
+ //Since this session version never supported a minor protocol version this should be fine
+ return new Version(wiproProcolVer,0,0);
+ }
+
+ /**
+ * Check to see if a transport is available to start/use the supplied service.
+ * @param sessionType the session that should be checked for transport availability
+ * @return true if there is either a supported
+ * transport currently connected or a transport is
+ * available to connect with for the supplied service type.
+ * <br>false if there is no
+ * transport connected to support the service type in question and
+ * no possibility in the foreseeable future.
+ */
+ public boolean isTransportForServiceAvailable(SessionType sessionType){
+ return _sdlConnection!= null
+ && _sdlConnection._transport!= null
+ && _sdlConnection._transport.getIsConnected()
+ && ((sessionType == SessionType.RPC || sessionType == SessionType.CONTROL || sessionType == SessionType.BULK_DATA ) //If this is a service that can run on any transport just return true
+ || (_sdlConnection._transport.getTransportType() == TransportType.USB || _sdlConnection._transport.getTransportType() == TransportType.TCP));
+ }
+
+
+} \ No newline at end of file
diff --git a/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession2.java b/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession2.java
new file mode 100644
index 000000000..497e3da95
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession2.java
@@ -0,0 +1,298 @@
+/*
+ * 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.SdlConnection;
+
+import android.util.Log;
+
+import com.smartdevicelink.exception.SdlException;
+import com.smartdevicelink.protocol.ISdlProtocol;
+import com.smartdevicelink.protocol.ProtocolMessage;
+import com.smartdevicelink.protocol.SdlPacket;
+import com.smartdevicelink.protocol.SdlProtocol;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.protocol.heartbeat.IHeartbeatMonitor;
+import com.smartdevicelink.proxy.interfaces.ISdlServiceListener;
+import com.smartdevicelink.transport.BaseTransportConfig;
+import com.smartdevicelink.transport.MultiplexTransportConfig;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.util.Version;
+
+import java.util.List;
+import java.util.ListIterator;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+@SuppressWarnings({"WeakerAccess", "deprecation"})
+public class SdlSession2 extends SdlSession implements ISdlProtocol{
+ private static final String TAG = "SdlSession2";
+
+
+ final protected SdlProtocol sdlProtocol;
+
+ @SuppressWarnings("SameReturnValue")
+ @Deprecated
+ public static SdlSession2 createSession(byte protocolVersion, ISdlConnectionListener listener, BaseTransportConfig btConfig) {
+ return null;
+ }
+
+ public SdlSession2(ISdlConnectionListener listener, MultiplexTransportConfig config){
+ this.transportConfig = config;
+ this.sessionListener = listener;
+ this.sdlProtocol = new SdlProtocol(this,config);
+
+ }
+
+ @Deprecated
+ @Override
+ public SdlConnection getSdlConnection() {
+ return null;
+ }
+
+ @Override
+ public int getMtu(){
+ if(this.sdlProtocol!=null){
+ return this.sdlProtocol.getMtu();
+ }else{
+ return 0;
+ }
+ }
+
+ @Override
+ public long getMtu(SessionType type) {
+ if (this.sdlProtocol != null) {
+ return this.sdlProtocol.getMtu(type);
+ } else {
+ return 0;
+ }
+ }
+
+ public void close() {
+ if (sdlSecurity != null)
+ {
+ sdlSecurity.resetParams();
+ sdlSecurity.shutDown();
+ }
+ if(sdlProtocol != null){
+ sdlProtocol.endSession(sessionId, sessionHashId);
+ }
+ }
+
+
+ @SuppressWarnings("ConstantConditions")
+ @Override
+ public void startService (SessionType serviceType, byte sessionID, boolean isEncrypted) {
+ if (isEncrypted){
+ if (sdlSecurity != null){
+ List<SessionType> serviceList = sdlSecurity.getServiceList();
+ if (!serviceList.contains(serviceType))
+ serviceList.add(serviceType);
+
+ sdlSecurity.initialize();
+ }
+ return;
+ }
+ sdlProtocol.startService(serviceType, sessionID, isEncrypted);
+ }
+
+ @Override
+ public void endService (SessionType serviceType, byte sessionID) {
+ if (sdlProtocol == null) {
+ return;
+ }
+ sdlProtocol.endService(serviceType,sessionID);
+ }
+
+
+ public String getBroadcastComment(BaseTransportConfig myTransport) {
+ return "Multiplexing";
+ }
+
+
+ @SuppressWarnings("RedundantThrows")
+ @Override
+ public void startSession() throws SdlException {
+ sdlProtocol.start();
+ }
+
+
+ @Override
+ public void sendMessage(ProtocolMessage msg) {
+ if (sdlProtocol == null){
+ return;
+ }
+ sdlProtocol.sendMessage(msg);
+ }
+
+ @Override
+ public TransportType getCurrentTransportType() {
+ return TransportType.MULTIPLEX;
+ }
+
+ @Override
+ public boolean getIsConnected() {
+ return sdlProtocol != null && sdlProtocol.isConnected();
+ }
+
+
+ public void shutdown(String info){
+ Log.d(TAG, "Shutdown - " + info);
+ this.sessionListener.onTransportDisconnected(info);
+
+ }
+
+ @Override
+ public void onTransportDisconnected(String info, boolean altTransportAvailable, MultiplexTransportConfig transportConfig) {
+ this.sessionListener.onTransportDisconnected(info, altTransportAvailable, (MultiplexTransportConfig)this.transportConfig);
+ }
+
+ /**
+ * Get the current protocol version used by this session
+ * @return Version that represents the Protocol version being used
+ */
+ @Override
+ public Version getProtocolVersion(){
+ if(sdlProtocol!=null){
+ return sdlProtocol.getProtocolVersion();
+ }
+ return new Version(1,0,0);
+ }
+
+
+ /* ***********************************************************************************************************************************************************************
+ * ***************************************************************** IProtocol Listener ********************************************************************************
+ *************************************************************************************************************************************************************************/
+
+ @Override
+ public void onProtocolMessageBytesToSend(SdlPacket packet) {
+ //Log.d(TAG, "onProtocolMessageBytesToSend - " + packet.getTransportType());
+ sdlProtocol.sendPacket(packet);
+ }
+
+
+ public void onProtocolSessionStartedNACKed(SessionType sessionType, byte sessionID, byte version, String correlationID, List<String> rejectedParams){
+ onProtocolSessionNACKed(sessionType,sessionID,version,correlationID,rejectedParams);
+ }
+
+ @Override
+ public void onProtocolSessionNACKed(SessionType sessionType, byte sessionID, byte version, String correlationID, List<String> rejectedParams) {
+ this.sessionListener.onProtocolSessionStartedNACKed(sessionType,
+ sessionID, version, correlationID, rejectedParams);
+ if(serviceListeners != null && serviceListeners.containsKey(sessionType)){
+ CopyOnWriteArrayList<ISdlServiceListener> listeners = serviceListeners.get(sessionType);
+ for(ISdlServiceListener listener:listeners){
+ listener.onServiceError(this, sessionType, "Start "+ sessionType.toString() +" Service NAKed");
+ }
+ }
+ }
+
+ /* Not supported methods from IProtocolListener */
+ @Override
+ public void sendHeartbeat(IHeartbeatMonitor monitor) {/* Not supported */ }
+ @Override
+ public void heartbeatTimedOut(IHeartbeatMonitor monitor) {/* Not supported */}
+ @Override
+ public void onHeartbeatTimedOut(byte sessionId){ /* Not supported */}
+ @Override
+ public void onProtocolHeartbeat(SessionType sessionType, byte sessionID) { /* Not supported */}
+ @Override
+ public void onProtocolHeartbeatACK(SessionType sessionType, byte sessionID) {/* Not supported */}
+ @Override
+ public void onResetOutgoingHeartbeat(SessionType sessionType, byte sessionID) {/* Not supported */}
+ @Override
+ public void onResetIncomingHeartbeat(SessionType sessionType, byte sessionID) {/* Not supported */}
+
+ /* ***********************************************************************************************************************************************************************
+ * ***************************************************************** Security Listener *********************************************************************************
+ *************************************************************************************************************************************************************************/
+
+
+ @Override
+ public void onSecurityInitialized() {
+
+ if (sdlProtocol != null && sdlSecurity != null)
+ {
+ List<SessionType> list = sdlSecurity.getServiceList();
+
+ SessionType service;
+ ListIterator<SessionType> iter = list.listIterator();
+
+ while (iter.hasNext()) {
+ service = iter.next();
+
+ if (service != null)
+ sdlProtocol.startService(service, getSessionId(), true);
+
+ iter.remove();
+ }
+ }
+ }
+
+ @Override
+ public void stopStream(SessionType serviceType) {
+ if(SessionType.NAV.equals(serviceType)){
+ stopVideoStream();
+ }else if(SessionType.PCM.equals(serviceType)){
+ stopAudioStream();
+ }
+
+ }
+
+ /**
+ * Check to see if a transport is available to start/use the supplied service.
+ * @param sessionType the session that should be checked for transport availability
+ * @return true if there is either a supported
+ * transport currently connected or a transport is
+ * available to connect with for the supplied service type.
+ * <br>false if there is no
+ * transport connected to support the service type in question and
+ * no possibility in the foreseeable future.
+ */
+ @Override
+ public boolean isTransportForServiceAvailable(SessionType sessionType){
+ return sdlProtocol!=null && sdlProtocol.isTransportForServiceAvailable(sessionType);
+ }
+
+
+ @Override
+ @Deprecated
+ public void clearConnection(){/* Not supported */}
+
+ @SuppressWarnings("SameReturnValue")
+ @Deprecated
+ public static boolean removeConnection(SdlConnection connection){/* Not supported */ return false;}
+
+ @Deprecated
+ @Override
+ public void checkForOpenMultiplexConnection(SdlConnection connection){/* Not supported */}
+
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/encoder/SdlEncoder.java b/sdl_android/src/main/java/com/smartdevicelink/encoder/SdlEncoder.java
index bd1e0c364..6c9198cb4 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/encoder/SdlEncoder.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/encoder/SdlEncoder.java
@@ -21,6 +21,8 @@ public class SdlEncoder {
// parameters for the encoder
private static final String _MIME_TYPE = "video/avc"; // H.264/AVC video
+ private static final long KEEPALIVE_INTERVAL_MSEC = 100;
+
// private static final String MIME_TYPE = "video/mp4v-es"; //MPEG4 video
private int frameRate = 30;
private int frameInterval = 5;
@@ -32,7 +34,8 @@ public class SdlEncoder {
private MediaCodec mEncoder;
private PipedOutputStream mOutputStream;
private IVideoStreamListener mOutputListener;
-
+ private long mLastEmittedFrameTimestamp;
+
// allocate one of these up front so we don't need to do it every time
private MediaCodec.BufferInfo mBufferInfo;
@@ -48,13 +51,13 @@ public class SdlEncoder {
frameInterval = iVal;
}
public void setFrameWidth(int iVal){
- frameWidth = iVal;
+ frameWidth = iVal;
}
public void setFrameHeight(int iVal){
frameHeight = iVal;
}
public void setBitrate(int iVal){
- bitrate = iVal;
+ bitrate = iVal;
}
public void setOutputStream(PipedOutputStream mStream){
mOutputStream = mStream;
@@ -101,13 +104,13 @@ public class SdlEncoder {
return null;
}
}
-
+
public void startEncoder () {
if(mEncoder != null) {
mEncoder.start();
}
}
-
+
/**
* Releases encoder resources.
*/
@@ -140,7 +143,7 @@ public class SdlEncoder {
final int TIMEOUT_USEC = 10000;
if(mEncoder == null || (mOutputStream == null && mOutputListener == null)) {
- return;
+ return;
}
if (endOfStream) {
mEncoder.signalEndOfInputStream();
@@ -153,6 +156,7 @@ public class SdlEncoder {
if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
// no output available yet
if (!endOfStream) {
+ trySendVideoKeepalive();
break; // out of while
}
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
@@ -199,13 +203,8 @@ public class SdlEncoder {
encoderOutputBuffer.get(dataToWrite, dataOffset, mBufferInfo.size);
- if (mOutputStream != null) {
- mOutputStream.write(dataToWrite, 0, mBufferInfo.size);
- } else if (mOutputListener != null) {
- mOutputListener.sendFrame(
- dataToWrite, 0, dataToWrite.length, mBufferInfo.presentationTimeUs);
- }
- } catch (Exception e) {}
+ emitFrame(dataToWrite);
+ } catch (Exception e) {}
}
mEncoder.releaseOutputBuffer(encoderStatus, false);
@@ -216,4 +215,27 @@ public class SdlEncoder {
}
}
}
+
+ private void trySendVideoKeepalive() {
+ if (mH264CodecSpecificData == null) {
+ return;
+ }
+
+ try {
+ long timeSinceLastEmitted = System.currentTimeMillis() - mLastEmittedFrameTimestamp;
+ if (timeSinceLastEmitted >= KEEPALIVE_INTERVAL_MSEC) {
+ emitFrame(mH264CodecSpecificData);
+ }
+ } catch (IOException e) {}
+ }
+
+ private void emitFrame(final byte[] dataToWrite) throws IOException {
+ if (mOutputStream != null) {
+ mOutputStream.write(dataToWrite, 0, mBufferInfo.size);
+ } else if (mOutputListener != null) {
+ mOutputListener.sendFrame(
+ dataToWrite, 0, dataToWrite.length, mBufferInfo.presentationTimeUs);
+ }
+ mLastEmittedFrameTimestamp = System.currentTimeMillis();
+ }
} \ No newline at end of file
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/BaseSubManager.java b/sdl_android/src/main/java/com/smartdevicelink/managers/BaseSubManager.java
new file mode 100644
index 000000000..6475b481e
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/BaseSubManager.java
@@ -0,0 +1,83 @@
+package com.smartdevicelink.managers;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.transport.utl.TransportRecord;
+
+import java.util.List;
+
+/**
+ * <strong>BaseSubManager</strong> <br>
+ *
+ * Note: This class is extended by SubManagers <br>
+ *
+ * It is broken down to these areas: <br>
+ *
+ * 1. <br>
+ */
+public abstract class BaseSubManager {
+
+ // states - if this gets more complicated we can move elsewhere
+ private int state;
+ private final Object STATE_LOCK = new Object();
+ public static final int SETTING_UP = 0x00, READY = 0x30, LIMITED = 0x50, SHUTDOWN = 0x80, ERROR = 0xC0;
+ protected final ISdl internalInterface;
+ private CompletionListener completionListener;
+
+ public BaseSubManager(@NonNull ISdl internalInterface){
+ this.internalInterface = internalInterface;
+ transitionToState(SETTING_UP);
+ }
+
+ /**
+ * Starts up a BaseSubManager, and calls provided callback once BaseSubManager is done setting up or failed setup.
+ * @param listener CompletionListener that is called once the BaseSubManager's state is READY, LIMITED, or ERROR
+ */
+ public void start(CompletionListener listener){
+ this.completionListener = listener;
+ int state = getState();
+ if((state == READY || state == LIMITED || state == ERROR) && completionListener != null){
+ completionListener.onComplete(state == READY || state == LIMITED);
+ completionListener = null;
+ }
+ }
+
+ /**
+ * <p>Called when manager is being torn down</p>
+ */
+ public void dispose(){
+ transitionToState(SHUTDOWN);
+ }
+
+ protected void transitionToState(int state) {
+ synchronized (STATE_LOCK) {
+ this.state = state;
+ }
+ if((state == READY || state == LIMITED || state == ERROR) && completionListener != null ){
+ completionListener.onComplete(state == READY || state == LIMITED);
+ completionListener = null;
+ }
+ }
+
+ public int getState() {
+ synchronized (STATE_LOCK) {
+ return state;
+ }
+ }
+
+ //This allows the method to not be exposed to developers
+ protected void handleTransportUpdated(List<TransportRecord> connectedTransports, boolean audioStreamTransportAvail, boolean videoStreamTransportAvail){
+ this.onTransportUpdate(connectedTransports,audioStreamTransportAvail,videoStreamTransportAvail);
+ }
+
+ /**
+ * Transport status has been updated
+ * @param connectedTransports currently connected transports
+ * @param audioStreamTransportAvail if there is a transport that could be used to carry the
+ * audio service
+ * @param videoStreamTransportAvail if there is a transport that could be used to carry the
+ * video service
+ */
+ protected void onTransportUpdate(List<TransportRecord> connectedTransports, boolean audioStreamTransportAvail, boolean videoStreamTransportAvail){}
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/CompletionListener.java b/sdl_android/src/main/java/com/smartdevicelink/managers/CompletionListener.java
new file mode 100644
index 000000000..93e618dae
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/CompletionListener.java
@@ -0,0 +1,10 @@
+package com.smartdevicelink.managers;
+
+public interface CompletionListener {
+
+ /**
+ * Returns whether a specific operation was successful or not
+ * @param success - success or fail
+ */
+ void onComplete(boolean success);
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/ProxyBridge.java b/sdl_android/src/main/java/com/smartdevicelink/managers/ProxyBridge.java
new file mode 100644
index 000000000..b8d97f39c
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/ProxyBridge.java
@@ -0,0 +1,560 @@
+package com.smartdevicelink.managers;
+
+import android.util.SparseArray;
+
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.IProxyListener;
+import com.smartdevicelink.proxy.RPCMessage;
+import com.smartdevicelink.proxy.callbacks.OnServiceEnded;
+import com.smartdevicelink.proxy.callbacks.OnServiceNACKed;
+import com.smartdevicelink.proxy.rpc.AddCommandResponse;
+import com.smartdevicelink.proxy.rpc.AddSubMenuResponse;
+import com.smartdevicelink.proxy.rpc.AlertManeuverResponse;
+import com.smartdevicelink.proxy.rpc.AlertResponse;
+import com.smartdevicelink.proxy.rpc.ButtonPressResponse;
+import com.smartdevicelink.proxy.rpc.ChangeRegistrationResponse;
+import com.smartdevicelink.proxy.rpc.CreateInteractionChoiceSetResponse;
+import com.smartdevicelink.proxy.rpc.DeleteCommandResponse;
+import com.smartdevicelink.proxy.rpc.DeleteFileResponse;
+import com.smartdevicelink.proxy.rpc.DeleteInteractionChoiceSetResponse;
+import com.smartdevicelink.proxy.rpc.DeleteSubMenuResponse;
+import com.smartdevicelink.proxy.rpc.DiagnosticMessageResponse;
+import com.smartdevicelink.proxy.rpc.DialNumberResponse;
+import com.smartdevicelink.proxy.rpc.EndAudioPassThruResponse;
+import com.smartdevicelink.proxy.rpc.GenericResponse;
+import com.smartdevicelink.proxy.rpc.GetDTCsResponse;
+import com.smartdevicelink.proxy.rpc.GetInteriorVehicleDataResponse;
+import com.smartdevicelink.proxy.rpc.GetSystemCapabilityResponse;
+import com.smartdevicelink.proxy.rpc.GetVehicleDataResponse;
+import com.smartdevicelink.proxy.rpc.GetWayPointsResponse;
+import com.smartdevicelink.proxy.rpc.ListFilesResponse;
+import com.smartdevicelink.proxy.rpc.OnAppInterfaceUnregistered;
+import com.smartdevicelink.proxy.rpc.OnAudioPassThru;
+import com.smartdevicelink.proxy.rpc.OnButtonEvent;
+import com.smartdevicelink.proxy.rpc.OnButtonPress;
+import com.smartdevicelink.proxy.rpc.OnCommand;
+import com.smartdevicelink.proxy.rpc.OnDriverDistraction;
+import com.smartdevicelink.proxy.rpc.OnHMIStatus;
+import com.smartdevicelink.proxy.rpc.OnHashChange;
+import com.smartdevicelink.proxy.rpc.OnInteriorVehicleData;
+import com.smartdevicelink.proxy.rpc.OnKeyboardInput;
+import com.smartdevicelink.proxy.rpc.OnLanguageChange;
+import com.smartdevicelink.proxy.rpc.OnLockScreenStatus;
+import com.smartdevicelink.proxy.rpc.OnPermissionsChange;
+import com.smartdevicelink.proxy.rpc.OnRCStatus;
+import com.smartdevicelink.proxy.rpc.OnStreamRPC;
+import com.smartdevicelink.proxy.rpc.OnSystemRequest;
+import com.smartdevicelink.proxy.rpc.OnTBTClientState;
+import com.smartdevicelink.proxy.rpc.OnTouchEvent;
+import com.smartdevicelink.proxy.rpc.OnVehicleData;
+import com.smartdevicelink.proxy.rpc.OnWayPointChange;
+import com.smartdevicelink.proxy.rpc.PerformAudioPassThruResponse;
+import com.smartdevicelink.proxy.rpc.PerformInteractionResponse;
+import com.smartdevicelink.proxy.rpc.PutFileResponse;
+import com.smartdevicelink.proxy.rpc.ReadDIDResponse;
+import com.smartdevicelink.proxy.rpc.RegisterAppInterfaceResponse;
+import com.smartdevicelink.proxy.rpc.ResetGlobalPropertiesResponse;
+import com.smartdevicelink.proxy.rpc.ScrollableMessageResponse;
+import com.smartdevicelink.proxy.rpc.SendHapticDataResponse;
+import com.smartdevicelink.proxy.rpc.SendLocationResponse;
+import com.smartdevicelink.proxy.rpc.SetAppIconResponse;
+import com.smartdevicelink.proxy.rpc.SetDisplayLayoutResponse;
+import com.smartdevicelink.proxy.rpc.SetGlobalPropertiesResponse;
+import com.smartdevicelink.proxy.rpc.SetInteriorVehicleDataResponse;
+import com.smartdevicelink.proxy.rpc.SetMediaClockTimerResponse;
+import com.smartdevicelink.proxy.rpc.ShowConstantTbtResponse;
+import com.smartdevicelink.proxy.rpc.ShowResponse;
+import com.smartdevicelink.proxy.rpc.SliderResponse;
+import com.smartdevicelink.proxy.rpc.SpeakResponse;
+import com.smartdevicelink.proxy.rpc.StreamRPCResponse;
+import com.smartdevicelink.proxy.rpc.SubscribeButtonResponse;
+import com.smartdevicelink.proxy.rpc.SubscribeVehicleDataResponse;
+import com.smartdevicelink.proxy.rpc.SubscribeWayPointsResponse;
+import com.smartdevicelink.proxy.rpc.SystemRequestResponse;
+import com.smartdevicelink.proxy.rpc.UnregisterAppInterfaceResponse;
+import com.smartdevicelink.proxy.rpc.UnsubscribeButtonResponse;
+import com.smartdevicelink.proxy.rpc.UnsubscribeVehicleDataResponse;
+import com.smartdevicelink.proxy.rpc.UnsubscribeWayPointsResponse;
+import com.smartdevicelink.proxy.rpc.UpdateTurnListResponse;
+import com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCListener;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public class ProxyBridge implements IProxyListener{
+ private final Object RPC_LISTENER_LOCK = new Object();
+ private SparseArray<CopyOnWriteArrayList<OnRPCListener>> rpcListeners = null;
+ private final LifecycleListener lifecycleListener;
+
+ @Override
+ public void onProxyOpened() {}
+
+ @Override
+ public void onRegisterAppInterfaceResponse(RegisterAppInterfaceResponse response) {
+ onRPCReceived(response);
+ if(response.getSuccess()){
+ lifecycleListener.onProxyConnected();
+ }
+ }
+
+ @Override
+ public void onOnAppInterfaceUnregistered(OnAppInterfaceUnregistered notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onUnregisterAppInterfaceResponse(UnregisterAppInterfaceResponse response) {
+ onRPCReceived(response);
+ }
+
+ protected interface LifecycleListener{
+ void onProxyConnected();
+ void onProxyClosed(String info, Exception e, SdlDisconnectedReason reason);
+ void onServiceEnded(OnServiceEnded serviceEnded);
+ void onServiceNACKed(OnServiceNACKed serviceNACKed);
+ void onError(String info, Exception e);
+ }
+
+ public ProxyBridge( LifecycleListener lifecycleListener){
+ this.lifecycleListener = lifecycleListener;
+ rpcListeners = new SparseArray<>();
+ }
+
+ public boolean onRPCReceived(final RPCMessage message){
+ synchronized(RPC_LISTENER_LOCK){
+ final int id = FunctionID.getFunctionId(message.getFunctionName());
+ CopyOnWriteArrayList<OnRPCListener> listeners = rpcListeners.get(id);
+ if(listeners!=null && listeners.size()>0) {
+ for (OnRPCListener listener : listeners) {
+ listener.onReceived(message);
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+
+ protected void addRpcListener(FunctionID id, OnRPCListener listener){
+ synchronized(RPC_LISTENER_LOCK){
+ if (id != null && listener != null) {
+ if (rpcListeners.indexOfKey(id.getId()) < 0) {
+ rpcListeners.put(id.getId(), new CopyOnWriteArrayList<OnRPCListener>());
+ }
+ rpcListeners.get(id.getId()).add(listener);
+ }
+ }
+ }
+
+ public boolean removeOnRPCListener(FunctionID id, OnRPCListener listener){
+ synchronized(RPC_LISTENER_LOCK){
+ if(rpcListeners!= null
+ && id != null
+ && listener != null
+ && rpcListeners.indexOfKey(id.getId()) >= 0){
+ return rpcListeners.get(id.getId()).remove(listener);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void onProxyClosed(String info, Exception e, SdlDisconnectedReason reason) {
+ lifecycleListener.onProxyClosed(info,e,reason);
+ }
+
+ @Override
+ public void onServiceEnded(OnServiceEnded serviceEnded) {
+ lifecycleListener.onServiceEnded(serviceEnded);
+
+ }
+
+ @Override
+ public void onServiceNACKed(OnServiceNACKed serviceNACKed) {
+ lifecycleListener.onServiceNACKed(serviceNACKed);
+
+ }
+ @Override
+ public void onError(String info, Exception e) {
+ lifecycleListener.onError(info, e);
+ }
+
+ @Override
+ public void onOnStreamRPC(OnStreamRPC notification) {
+ onRPCReceived(notification);
+
+ }
+
+ @Override
+ public void onStreamRPCResponse(StreamRPCResponse response) {
+ onRPCReceived(response);
+ }
+
+ @Override
+ public void onOnHMIStatus(OnHMIStatus notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onGenericResponse(GenericResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onOnCommand(OnCommand notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onAddCommandResponse(AddCommandResponse response) {
+ onRPCReceived(response);
+ }
+
+ @Override
+ public void onAddSubMenuResponse(AddSubMenuResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onCreateInteractionChoiceSetResponse(CreateInteractionChoiceSetResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onAlertResponse(AlertResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onDeleteCommandResponse(DeleteCommandResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onDeleteInteractionChoiceSetResponse(DeleteInteractionChoiceSetResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onDeleteSubMenuResponse(DeleteSubMenuResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onPerformInteractionResponse(PerformInteractionResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onResetGlobalPropertiesResponse(ResetGlobalPropertiesResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onSetGlobalPropertiesResponse(SetGlobalPropertiesResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onSetMediaClockTimerResponse(SetMediaClockTimerResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onShowResponse(ShowResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onSpeakResponse(SpeakResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onOnButtonEvent(OnButtonEvent notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onOnButtonPress(OnButtonPress notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onSubscribeButtonResponse(SubscribeButtonResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onUnsubscribeButtonResponse(UnsubscribeButtonResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onOnPermissionsChange(OnPermissionsChange notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onSubscribeVehicleDataResponse(SubscribeVehicleDataResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onUnsubscribeVehicleDataResponse(UnsubscribeVehicleDataResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onGetVehicleDataResponse(GetVehicleDataResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onOnVehicleData(OnVehicleData notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onPerformAudioPassThruResponse(PerformAudioPassThruResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onEndAudioPassThruResponse(EndAudioPassThruResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onOnAudioPassThru(OnAudioPassThru notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onPutFileResponse(PutFileResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onDeleteFileResponse(DeleteFileResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onListFilesResponse(ListFilesResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onSetAppIconResponse(SetAppIconResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onScrollableMessageResponse(ScrollableMessageResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onChangeRegistrationResponse(ChangeRegistrationResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onSetDisplayLayoutResponse(SetDisplayLayoutResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onOnLanguageChange(OnLanguageChange notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onOnHashChange(OnHashChange notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onSliderResponse(SliderResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onOnDriverDistraction(OnDriverDistraction notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onOnTBTClientState(OnTBTClientState notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onOnSystemRequest(OnSystemRequest notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onSystemRequestResponse(SystemRequestResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onOnKeyboardInput(OnKeyboardInput notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onOnTouchEvent(OnTouchEvent notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onDiagnosticMessageResponse(DiagnosticMessageResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onReadDIDResponse(ReadDIDResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onGetDTCsResponse(GetDTCsResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onOnLockScreenNotification(OnLockScreenStatus notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onDialNumberResponse(DialNumberResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onSendLocationResponse(SendLocationResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onShowConstantTbtResponse(ShowConstantTbtResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onAlertManeuverResponse(AlertManeuverResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onUpdateTurnListResponse(UpdateTurnListResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onServiceDataACK(int dataSize) {
+
+ }
+
+ @Override
+ public void onGetWayPointsResponse(GetWayPointsResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onSubscribeWayPointsResponse(SubscribeWayPointsResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onUnsubscribeWayPointsResponse(UnsubscribeWayPointsResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onOnWayPointChange(OnWayPointChange notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onGetSystemCapabilityResponse(GetSystemCapabilityResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onGetInteriorVehicleDataResponse(GetInteriorVehicleDataResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onButtonPressResponse(ButtonPressResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onSetInteriorVehicleDataResponse(SetInteriorVehicleDataResponse response) {
+ onRPCReceived(response);
+
+ }
+
+ @Override
+ public void onOnInteriorVehicleData(OnInteriorVehicleData notification) {
+ onRPCReceived(notification);
+ }
+
+ @Override
+ public void onSendHapticDataResponse(SendHapticDataResponse response) {
+ onRPCReceived(response);
+ }
+
+ @Override
+ public void onOnRCStatus(OnRCStatus notification) {
+ onRPCReceived(notification);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java b/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java
new file mode 100644
index 000000000..2717123b5
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java
@@ -0,0 +1,909 @@
+package com.smartdevicelink.managers;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+import com.smartdevicelink.exception.SdlException;
+import com.smartdevicelink.managers.audio.AudioStreamManager;
+import com.smartdevicelink.managers.file.FileManager;
+import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
+import com.smartdevicelink.managers.lockscreen.LockScreenConfig;
+import com.smartdevicelink.managers.lockscreen.LockScreenManager;
+import com.smartdevicelink.managers.permission.PermissionManager;
+import com.smartdevicelink.managers.screen.ScreenManager;
+import com.smartdevicelink.managers.video.VideoStreamManager;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.proxy.RPCMessage;
+import com.smartdevicelink.proxy.RPCRequest;
+import com.smartdevicelink.proxy.SdlProxyBase;
+import com.smartdevicelink.proxy.SystemCapabilityManager;
+import com.smartdevicelink.proxy.callbacks.OnServiceEnded;
+import com.smartdevicelink.proxy.callbacks.OnServiceNACKed;
+import com.smartdevicelink.proxy.interfaces.IAudioStreamListener;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.interfaces.ISdlServiceListener;
+import com.smartdevicelink.proxy.interfaces.IVideoStreamListener;
+import com.smartdevicelink.proxy.interfaces.OnSystemCapabilityListener;
+import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
+import com.smartdevicelink.proxy.rpc.SetAppIcon;
+import com.smartdevicelink.proxy.rpc.TTSChunk;
+import com.smartdevicelink.proxy.rpc.TemplateColorScheme;
+import com.smartdevicelink.proxy.rpc.enums.AppHMIType;
+import com.smartdevicelink.proxy.rpc.enums.Language;
+import com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason;
+import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
+import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCListener;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
+import com.smartdevicelink.security.SdlSecurityBase;
+import com.smartdevicelink.streaming.audio.AudioStreamingCodec;
+import com.smartdevicelink.streaming.audio.AudioStreamingParams;
+import com.smartdevicelink.streaming.video.VideoStreamingParameters;
+import com.smartdevicelink.transport.BaseTransportConfig;
+import com.smartdevicelink.transport.MultiplexTransportConfig;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
+import com.smartdevicelink.util.DebugTool;
+import com.smartdevicelink.util.Version;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * <strong>SDLManager</strong> <br>
+ *
+ * This is the main point of contact between an application and SDL <br>
+ *
+ * It is broken down to these areas: <br>
+ *
+ * 1. SDLManagerBuilder <br>
+ * 2. ISdl Interface along with its overridden methods - This can be passed into attached managers <br>
+ * 3. Sending Requests <br>
+ * 4. Helper methods
+ */
+public class SdlManager{
+ private static final String TAG = "SdlManager";
+ private SdlProxyBase proxy;
+ private String appId, appName, shortAppName;
+ private boolean isMediaApp;
+ private Language hmiLanguage;
+ private SdlArtwork appIcon;
+ private Vector<AppHMIType> hmiTypes;
+ private BaseTransportConfig transport;
+ private Context context;
+ private Vector<String> vrSynonyms;
+ private Vector<TTSChunk> ttsChunks;
+ private TemplateColorScheme dayColorScheme, nightColorScheme;
+ private SdlManagerListener managerListener;
+ private int state = -1;
+ private List<Class<? extends SdlSecurityBase>> sdlSecList;
+ private LockScreenConfig lockScreenConfig;
+ private final Object STATE_LOCK = new Object();
+
+
+ // Managers
+ private PermissionManager permissionManager;
+ private FileManager fileManager;
+ private LockScreenManager lockScreenManager;
+ private ScreenManager screenManager;
+ private VideoStreamManager videoStreamManager;
+ private AudioStreamManager audioStreamManager;
+
+
+ // Initialize proxyBridge with anonymous lifecycleListener
+ private final ProxyBridge proxyBridge= new ProxyBridge(new ProxyBridge.LifecycleListener() {
+ @Override
+ public void onProxyConnected() {
+ DebugTool.logInfo("Proxy is connected. Now initializing.");
+ initialize();
+ }
+
+ @Override
+ public void onProxyClosed(String info, Exception e, SdlDisconnectedReason reason){
+ dispose();
+ }
+
+ @Override
+ public void onServiceEnded(OnServiceEnded serviceEnded){
+
+ }
+
+ @Override
+ public void onServiceNACKed(OnServiceNACKed serviceNACKed){
+
+ }
+
+ @Override
+ public void onError(String info, Exception e){
+
+ }
+ });
+
+ // Sub manager listener
+ private final CompletionListener subManagerListener = new CompletionListener() {
+ @Override
+ public synchronized void onComplete(boolean success) {
+ if(!success){
+ Log.e(TAG, "Sub manager failed to initialize");
+ }
+ checkState();
+ }
+ };
+
+ void checkState() {
+ if (permissionManager != null && fileManager != null && screenManager != null && (!lockScreenConfig.isEnabled() || lockScreenManager != null)) {
+ if (permissionManager.getState() == BaseSubManager.READY && fileManager.getState() == BaseSubManager.READY && screenManager.getState() == BaseSubManager.READY && (!lockScreenConfig.isEnabled() || lockScreenManager.getState() == BaseSubManager.READY)) {
+ DebugTool.logInfo("Starting sdl manager, all sub managers are in ready state");
+ transitionToState(BaseSubManager.READY);
+ notifyDevListener(null);
+ onReady();
+ } else if (permissionManager.getState() == BaseSubManager.ERROR && fileManager.getState() == BaseSubManager.ERROR && screenManager.getState() == BaseSubManager.ERROR && (!lockScreenConfig.isEnabled() || lockScreenManager.getState() == BaseSubManager.ERROR)) {
+ String info = "ERROR starting sdl manager, all sub managers are in error state";
+ Log.e(TAG, info);
+ transitionToState(BaseSubManager.ERROR);
+ notifyDevListener(info);
+ } else if (permissionManager.getState() == BaseSubManager.SETTING_UP || fileManager.getState() == BaseSubManager.SETTING_UP || screenManager.getState() == BaseSubManager.SETTING_UP || (lockScreenConfig.isEnabled() && lockScreenManager != null && lockScreenManager.getState() == BaseSubManager.SETTING_UP)) {
+ DebugTool.logInfo("SETTING UP sdl manager, some sub managers are still setting up");
+ transitionToState(BaseSubManager.SETTING_UP);
+ // No need to notify developer here!
+ } else {
+ Log.w(TAG, "LIMITED starting sdl manager, some sub managers are in error or limited state and the others finished setting up");
+ transitionToState(BaseSubManager.LIMITED);
+ notifyDevListener(null);
+ onReady();
+ }
+ } else {
+ // We should never be here, but somehow one of the sub-sub managers is null
+ String info = "ERROR one of the sdl sub managers is null";
+ Log.e(TAG, info);
+ transitionToState(BaseSubManager.ERROR);
+ notifyDevListener(info);
+ }
+ }
+
+ private void notifyDevListener(String info) {
+ if (managerListener != null) {
+ if (getState() == BaseSubManager.ERROR){
+ managerListener.onError(info, null);
+ } else {
+ managerListener.onStart();
+ }
+ }
+ }
+
+ private void onReady(){
+ // Set the app icon
+ if (SdlManager.this.appIcon != null && SdlManager.this.appIcon.getName() != null) {
+ if (fileManager != null && fileManager.getState() == BaseSubManager.READY && !fileManager.hasUploadedFile(SdlManager.this.appIcon)) {
+ fileManager.uploadArtwork(SdlManager.this.appIcon, new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ if (success) {
+ SetAppIcon msg = new SetAppIcon(SdlManager.this.appIcon.getName());
+ _internalInterface.sendRPCRequest(msg);
+ }
+ }
+ });
+ } else {
+ SetAppIcon msg = new SetAppIcon(SdlManager.this.appIcon.getName());
+ _internalInterface.sendRPCRequest(msg);
+ }
+ }
+ }
+
+ protected void initialize(){
+ // Instantiate sub managers
+ this.permissionManager = new PermissionManager(_internalInterface);
+ this.fileManager = new FileManager(_internalInterface, context);
+ if (lockScreenConfig.isEnabled()) {
+ this.lockScreenManager = new LockScreenManager(lockScreenConfig, context, _internalInterface);
+ }
+ this.screenManager = new ScreenManager(_internalInterface, this.fileManager);
+ if(getAppTypes().contains(AppHMIType.NAVIGATION) || getAppTypes().contains(AppHMIType.PROJECTION)){
+ this.videoStreamManager = new VideoStreamManager(_internalInterface);
+ } else {
+ this.videoStreamManager = null;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
+ && (getAppTypes().contains(AppHMIType.NAVIGATION) || getAppTypes().contains(AppHMIType.PROJECTION)) ) {
+ this.audioStreamManager = new AudioStreamManager(_internalInterface, context);
+ } else {
+ this.audioStreamManager = null;
+ }
+
+ // Start sub managers
+ this.permissionManager.start(subManagerListener);
+ this.fileManager.start(subManagerListener);
+ if (lockScreenConfig.isEnabled()){
+ this.lockScreenManager.start(subManagerListener);
+ }
+ this.screenManager.start(subManagerListener);
+ }
+
+ /**
+ * Get the current state for the SdlManager
+ * @return int value that represents the current state
+ * @see BaseSubManager
+ */
+ public int getState() {
+ synchronized (STATE_LOCK) {
+ return state;
+ }
+ }
+
+ protected void transitionToState(int state) {
+ synchronized (STATE_LOCK) {
+ this.state = state;
+ }
+ }
+
+ @SuppressLint("NewApi")
+ public void dispose() {
+ if (this.permissionManager != null) {
+ this.permissionManager.dispose();
+ }
+
+ if (this.fileManager != null) {
+ this.fileManager.dispose();
+ }
+
+ if (this.lockScreenManager != null) {
+ this.lockScreenManager.dispose();
+ }
+
+ if (this.screenManager != null) {
+ this.screenManager.dispose();
+ }
+
+ if(this.videoStreamManager != null) {
+ this.videoStreamManager.dispose();
+ }
+
+ // SuppressLint("NewApi") is used because audioStreamManager is only available on android >= jelly bean
+ if (this.audioStreamManager != null) {
+ this.audioStreamManager.dispose();
+ }
+
+ if(managerListener != null){
+ managerListener.onDestroy();
+ managerListener = null;
+ }
+ }
+
+ // BUILDER
+ public static class Builder {
+ SdlManager sdlManager;
+
+ /**
+ * Builder for the SdlManager. Parameters in the constructor are required.
+ * @param context the current context
+ * @param appId the app's ID
+ * @param appName the app's name
+ * @param listener a SdlManagerListener object
+ */
+ public Builder(@NonNull Context context, @NonNull final String appId, @NonNull final String appName, @NonNull final SdlManagerListener listener){
+ sdlManager = new SdlManager();
+ setContext(context);
+ setAppId(appId);
+ setAppName(appName);
+ setManagerListener(listener);
+ }
+
+ /**
+ * Sets the App ID
+ * @param appId
+ */
+ public Builder setAppId(@NonNull final String appId){
+ sdlManager.appId = appId;
+ return this;
+ }
+
+ /**
+ * Sets the Application Name
+ * @param appName
+ */
+ public Builder setAppName(@NonNull final String appName){
+ sdlManager.appName = appName;
+ return this;
+ }
+
+ /**
+ * Sets the Short Application Name
+ * @param shortAppName
+ */
+ public Builder setShortAppName(final String shortAppName) {
+ sdlManager.shortAppName = shortAppName;
+ return this;
+ }
+
+ /**
+ * Sets the Language of the App
+ * @param hmiLanguage
+ */
+ public Builder setLanguage(final Language hmiLanguage){
+ sdlManager.hmiLanguage = hmiLanguage;
+ return this;
+ }
+
+ /**
+ * Sets the TemplateColorScheme for daytime
+ * @param dayColorScheme
+ */
+ public Builder setDayColorScheme(final TemplateColorScheme dayColorScheme){
+ sdlManager.dayColorScheme = dayColorScheme;
+ return this;
+ }
+
+ /**
+ * Sets the TemplateColorScheme for nighttime
+ * @param nightColorScheme
+ */
+ public Builder setNightColorScheme(final TemplateColorScheme nightColorScheme){
+ sdlManager.nightColorScheme = nightColorScheme;
+ return this;
+ }
+
+ /**
+ * Sets the LockScreenConfig for the session. <br>
+ * <strong>Note: If not set, the default configuration will be used.</strong>
+ * @param lockScreenConfig - configuration options
+ */
+ public Builder setLockScreenConfig (final LockScreenConfig lockScreenConfig){
+ sdlManager.lockScreenConfig = lockScreenConfig;
+ return this;
+ }
+
+ /**
+ * Sets the icon for the app on HU <br>
+ * @param sdlArtwork
+ */
+ public Builder setAppIcon(final SdlArtwork sdlArtwork){
+ sdlManager.appIcon = sdlArtwork;
+ return this;
+ }
+
+ /**
+ * Sets the vector of AppHMIType <br>
+ * <strong>Note: This should be an ordered list from most -> least relevant</strong>
+ * @param hmiTypes
+ */
+ public Builder setAppTypes(final Vector<AppHMIType> hmiTypes){
+
+ sdlManager.hmiTypes = hmiTypes;
+
+ if (hmiTypes != null) {
+ sdlManager.isMediaApp = hmiTypes.contains(AppHMIType.MEDIA);
+ }
+
+ return this;
+ }
+
+ /**
+ * Sets the vector of vrSynonyms
+ * @param vrSynonyms
+ */
+ public Builder setVrSynonyms(final Vector<String> vrSynonyms) {
+ sdlManager.vrSynonyms = vrSynonyms;
+ return this;
+ }
+
+ /**
+ * Sets the TTS Name
+ * @param ttsChunks
+ */
+ public Builder setTtsName(final Vector<TTSChunk> ttsChunks) {
+ sdlManager.ttsChunks = ttsChunks;
+ return this;
+ }
+
+ /**
+ * This Object type may change with the transport refactor
+ * Sets the BaseTransportConfig
+ * @param transport
+ */
+ public Builder setTransportType(BaseTransportConfig transport){
+ sdlManager.transport = transport;
+ return this;
+ }
+
+ /**
+ * Sets the Context
+ * @param context
+ */
+ public Builder setContext(Context context){
+ sdlManager.context = context;
+ return this;
+ }
+
+ /**
+ * Sets the Security library
+ * @param secList The list of security class(es)
+ */
+ public Builder setSdlSecurity(List<Class<? extends SdlSecurityBase>> secList) {
+ sdlManager.sdlSecList = secList;
+ return this;
+ }
+
+ /**
+ * Set the SdlManager Listener
+ * @param listener the listener
+ */
+ public Builder setManagerListener(@NonNull final SdlManagerListener listener){
+ sdlManager.managerListener = listener;
+ return this;
+ }
+
+ public SdlManager build() {
+
+ if (sdlManager.appName == null) {
+ throw new IllegalArgumentException("You must specify an app name by calling setAppName");
+ }
+
+ if (sdlManager.appId == null) {
+ throw new IllegalArgumentException("You must specify an app ID by calling setAppId");
+ }
+
+ if (sdlManager.managerListener == null) {
+ throw new IllegalArgumentException("You must set a SdlManagerListener object");
+ }
+
+ if (sdlManager.hmiTypes == null) {
+ Vector<AppHMIType> hmiTypesDefault = new Vector<>();
+ hmiTypesDefault.add(AppHMIType.DEFAULT);
+ sdlManager.hmiTypes = hmiTypesDefault;
+ sdlManager.isMediaApp = false;
+ }
+
+ if (sdlManager.lockScreenConfig == null){
+ // if lock screen params are not set, use default
+ sdlManager.lockScreenConfig = new LockScreenConfig();
+ }
+
+ if (sdlManager.hmiLanguage == null){
+ sdlManager.hmiLanguage = Language.EN_US;
+ }
+
+ sdlManager.transitionToState(BaseSubManager.SETTING_UP);
+
+ return sdlManager;
+ }
+ }
+
+ private void checkSdlManagerState(){
+ if (getState() != BaseSubManager.READY && getState() != BaseSubManager.LIMITED){
+ Log.e(TAG, "SdlManager is not ready for use, be sure to initialize with start() method, implement callback, and use SubManagers in the SdlManager's callback");
+ }
+ }
+
+ // MANAGER GETTERS
+
+ /**
+ * Gets the PermissionManager. <br>
+ * <strong>Note: PermissionManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
+ * @return a PermissionManager object
+ */
+ public PermissionManager getPermissionManager() {
+ if (permissionManager.getState() != BaseSubManager.READY && permissionManager.getState() != BaseSubManager.LIMITED){
+ Log.e(TAG,"PermissionManager should not be accessed because it is not in READY/LIMITED state");
+ }
+ checkSdlManagerState();
+ return permissionManager;
+ }
+
+ /**
+ * Gets the FileManager. <br>
+ * <strong>Note: FileManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
+ * @return a FileManager object
+ */
+ public FileManager getFileManager() {
+ if (fileManager.getState() != BaseSubManager.READY && fileManager.getState() != BaseSubManager.LIMITED){
+ Log.e(TAG, "FileManager should not be accessed because it is not in READY/LIMITED state");
+ }
+ checkSdlManagerState();
+ return fileManager;
+ }
+
+ /**
+ * Gets the VideoStreamManager. <br>
+ * The VideoStreamManager returned will only be not null if the registered app type is
+ * either NAVIGATION or PROJECTION. Once the VideoStreamManager is retrieved, its start()
+ * method will need to be called before use.
+ * <br><br><strong>Note: VideoStreamManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
+ * @return a VideoStreamManager object attached to shit SdlManager instance
+ */
+
+ public @Nullable
+ VideoStreamManager getVideoStreamManager() {
+ checkSdlManagerState();
+ return videoStreamManager;
+ }
+
+ /**
+ * Gets the AudioStreamManager. <br>
+ * The AudioStreamManager returned will only be not null if the registered app type is
+ * either NAVIGATION or PROJECTION. Once the AudioStreamManager is retrieved, its start()
+ * method will need to be called before use.
+ * <br><strong>Note: AudioStreamManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
+ * @return a AudioStreamManager object
+ */
+ public @Nullable AudioStreamManager getAudioStreamManager() {
+ checkSdlManagerState();
+ return audioStreamManager;
+ }
+
+ /**
+ * Gets the ScreenManager. <br>
+ * <strong>Note: ScreenManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
+ * @return a ScreenManager object
+ */
+ public ScreenManager getScreenManager() {
+ if (screenManager.getState() != BaseSubManager.READY && screenManager.getState() != BaseSubManager.LIMITED){
+ Log.e(TAG, "ScreenManager should not be accessed because it is not in READY/LIMITED state");
+ }
+ checkSdlManagerState();
+ return screenManager;
+ }
+
+ /**
+ * Gets the LockScreenManager. <br>
+ * <strong>Note: LockScreenManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
+ * @return a LockScreenManager object
+ */
+ public LockScreenManager getLockScreenManager() {
+ if (lockScreenManager.getState() != BaseSubManager.READY && lockScreenManager.getState() != BaseSubManager.LIMITED){
+ Log.e(TAG, "LockScreenManager should not be accessed because it is not in READY/LIMITED state");
+ }
+ checkSdlManagerState();
+ return lockScreenManager;
+ }
+
+ /**
+ * Gets the SystemCapabilityManager. <br>
+ * <strong>Note: SystemCapabilityManager should be used only after SdlManager.start() CompletionListener callback is completed successfully.</strong>
+ * @return a SystemCapabilityManager object
+ */
+ public SystemCapabilityManager getSystemCapabilityManager(){
+ return proxy.getSystemCapabilityManager();
+ }
+
+ // PROTECTED GETTERS
+ protected String getAppName() { return appName; }
+
+ protected String getAppId() { return appId; }
+
+ protected String getShortAppName() { return shortAppName; }
+
+ protected Language getHmiLanguage() { return hmiLanguage; }
+
+ protected TemplateColorScheme getDayColorScheme() { return dayColorScheme; }
+
+ protected TemplateColorScheme getNightColorScheme() { return nightColorScheme; }
+
+ protected Vector<AppHMIType> getAppTypes() { return hmiTypes; }
+
+ protected Vector<String> getVrSynonyms() { return vrSynonyms; }
+
+ protected Vector<TTSChunk> getTtsChunks() { return ttsChunks; }
+
+ protected BaseTransportConfig getTransport() { return transport; }
+
+ protected LockScreenConfig getLockScreenConfig() { return lockScreenConfig; }
+
+ // SENDING REQUESTS
+
+ /**
+ * Send RPC Message <br>
+ * <strong>Note: Only takes type of RPCRequest for now, notifications and responses will be thrown out</strong>
+ * @param message RPCMessage
+ * @throws SdlException
+ */
+ public void sendRPC(RPCMessage message) throws SdlException {
+
+ if (message instanceof RPCRequest){
+ proxy.sendRPCRequest((RPCRequest)message);
+ }
+ }
+
+ /**
+ * Takes a list of RPCMessages and sends it to SDL in a synchronous fashion. Responses are captured through callback on OnMultipleRequestListener.
+ * For sending requests asynchronously, use sendRequests <br>
+ *
+ * <strong>NOTE: This will override any listeners on individual RPCs</strong><br>
+ *
+ * <strong>ADDITIONAL NOTE: This only takes the type of RPCRequest for now, notifications and responses will be thrown out</strong>
+ *
+ * @param rpcs is the list of RPCMessages being sent
+ * @param listener listener for updates and completions
+ * @throws SdlException if an unrecoverable error is encountered
+ */
+ public void sendSequentialRPCs(final List<? extends RPCMessage> rpcs, final OnMultipleRequestListener listener) throws SdlException {
+
+ List<RPCRequest> rpcRequestList = new ArrayList<>();
+ for (int i = 0; i < rpcs.size(); i++) {
+ if (rpcs.get(i) instanceof RPCRequest){
+ rpcRequestList.add((RPCRequest)rpcs.get(i));
+ }
+ }
+
+ if (rpcRequestList.size() > 0) {
+ proxy.sendSequentialRequests(rpcRequestList, listener);
+ }
+ }
+
+ /**
+ * Takes a list of RPCMessages and sends it to SDL. Responses are captured through callback on OnMultipleRequestListener.
+ * For sending requests synchronously, use sendSequentialRPCs <br>
+ *
+ * <strong>NOTE: This will override any listeners on individual RPCs</strong> <br>
+ *
+ * <strong>ADDITIONAL NOTE: This only takes the type of RPCRequest for now, notifications and responses will be thrown out</strong>
+ *
+ * @param rpcs is the list of RPCMessages being sent
+ * @param listener listener for updates and completions
+ * @throws SdlException if an unrecoverable error is encountered
+ */
+ public void sendRPCs(List<? extends RPCMessage> rpcs, final OnMultipleRequestListener listener) throws SdlException {
+
+ List<RPCRequest> rpcRequestList = new ArrayList<>();
+ for (int i = 0; i < rpcs.size(); i++) {
+ if (rpcs.get(i) instanceof RPCRequest){
+ rpcRequestList.add((RPCRequest)rpcs.get(i));
+ }
+ }
+
+ if (rpcRequestList.size() > 0) {
+ proxy.sendRequests(rpcRequestList, listener);
+ }
+ }
+
+ /**
+ * Add an OnRPCNotificationListener
+ * @param listener listener that will be called when a notification is received
+ */
+ public void addOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener){
+ proxy.addOnRPCNotificationListener(notificationId,listener);
+ }
+
+ /**
+ * Remove an OnRPCNotificationListener
+ * @param listener listener that was previously added
+ */
+ public void removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener){
+ proxy.removeOnRPCNotificationListener(notificationId, listener);
+ }
+
+ // LIFECYCLE / OTHER
+
+ // STARTUP
+
+ /**
+ * Starts up a SdlManager, and calls provided callback called once all BaseSubManagers are done setting up
+ */
+ @SuppressWarnings("unchecked")
+ public void start(){
+ if (proxy == null) {
+ try {
+ if(transport!= null && transport.getTransportType() == TransportType.MULTIPLEX){
+ //Do the thing
+ MultiplexTransportConfig multiplexTransportConfig = (MultiplexTransportConfig)(transport);
+ final MultiplexTransportConfig.TransportListener devListener = multiplexTransportConfig.getTransportListener();
+ multiplexTransportConfig.setTransportListener(new MultiplexTransportConfig.TransportListener() {
+ @Override
+ public void onTransportEvent(List<TransportRecord> connectedTransports, boolean audioStreamTransportAvail, boolean videoStreamTransportAvail) {
+
+ //Pass to submanagers that need it
+ if(videoStreamManager != null){
+ videoStreamManager.handleTransportUpdated(connectedTransports, audioStreamTransportAvail, videoStreamTransportAvail);
+ }
+
+ if(audioStreamManager != null){
+ audioStreamManager.handleTransportUpdated(connectedTransports, audioStreamTransportAvail, videoStreamTransportAvail);
+ }
+ //If the developer supplied a listener to start, it is time to call that
+ if(devListener != null){
+ devListener.onTransportEvent(connectedTransports,audioStreamTransportAvail,videoStreamTransportAvail);
+ }
+ }
+ });
+ }
+
+ proxy = new SdlProxyBase(proxyBridge, context, appName, shortAppName, isMediaApp, hmiLanguage,
+ hmiLanguage, hmiTypes, appId, transport, vrSynonyms, ttsChunks, dayColorScheme,
+ nightColorScheme) {};
+ if (sdlSecList != null && !sdlSecList.isEmpty()) {
+ proxy.setSdlSecurityClassList(sdlSecList);
+ }
+ } catch (SdlException e) {
+ if (managerListener != null) {
+ managerListener.onError("Unable to start manager", e);
+ }
+ }
+ }
+ }
+
+ protected void setProxy(SdlProxyBase proxy){
+ this.proxy = proxy;
+ }
+
+ // INTERNAL INTERFACE
+ private ISdl _internalInterface = new ISdl() {
+ @Override
+ public void start() {
+ try{
+ proxy.initializeProxy();
+ }catch (SdlException e){
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void stop() {
+ try{
+ proxy.dispose();
+ }catch (SdlException e){
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public boolean isConnected() {
+ return proxy.getIsConnected();
+ }
+
+ @Override
+ public void addServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener) {
+ proxy.addServiceListener(serviceType,sdlServiceListener);
+ }
+
+ @Override
+ public void removeServiceListener(SessionType serviceType, ISdlServiceListener sdlServiceListener) {
+ proxy.removeServiceListener(serviceType,sdlServiceListener);
+ }
+
+ @Override
+ public void startVideoService(VideoStreamingParameters parameters, boolean encrypted) {
+ if(proxy.getIsConnected()){
+ proxy.startVideoStream(encrypted,parameters);
+ }
+ }
+
+ @Override
+ public IVideoStreamListener startVideoStream(boolean isEncrypted, VideoStreamingParameters parameters){
+ return proxy.startVideoStream(isEncrypted, parameters);
+ }
+
+ @Override
+ public void stopVideoService() {
+ if(proxy.getIsConnected()){
+ proxy.endVideoStream();
+ }
+ }
+
+ @Override
+ public void startAudioService(boolean isEncrypted, AudioStreamingCodec codec,
+ AudioStreamingParams params) {
+ if(proxy.getIsConnected()){
+ proxy.startAudioStream(isEncrypted, codec, params);
+ }
+ }
+
+ @Override
+ public void startAudioService(boolean encrypted) {
+ if(isConnected()){
+ proxy.startService(SessionType.PCM, encrypted);
+ }
+ }
+
+ @Override
+ public IAudioStreamListener startAudioStream(boolean isEncrypted, AudioStreamingCodec codec,
+ AudioStreamingParams params) {
+ return proxy.startAudioStream(isEncrypted, codec, params);
+ }
+
+ @Override
+ public void stopAudioService() {
+ if(proxy.getIsConnected()){
+ proxy.endAudioStream();
+ }
+ }
+
+ @Override
+ public void sendRPCRequest(RPCRequest message){
+ try {
+ proxy.sendRPCRequest(message);
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void sendRequests(List<? extends RPCRequest> rpcs, OnMultipleRequestListener listener) {
+ try {
+ proxy.sendRequests(rpcs, listener);
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void addOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {
+ proxy.addOnRPCNotificationListener(notificationId,listener);
+ }
+
+ @Override
+ public boolean removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {
+ return proxy.removeOnRPCNotificationListener(notificationId,listener);
+ }
+
+ @Override
+ public void addOnRPCListener(final FunctionID responseId, final OnRPCListener listener) {
+ proxyBridge.addRpcListener(responseId, listener);
+ }
+
+ @Override
+ public boolean removeOnRPCListener(final FunctionID responseId, final OnRPCListener listener) {
+ return proxyBridge.removeOnRPCListener(responseId, listener);
+ }
+
+ @Override
+ public Object getCapability(SystemCapabilityType systemCapabilityType){
+ return proxy.getCapability(systemCapabilityType);
+ }
+
+ @Override
+ public void getCapability(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener scListener) {
+ proxy.getCapability(systemCapabilityType, scListener);
+ }
+
+ @Override
+ public boolean isCapabilitySupported(SystemCapabilityType systemCapabilityType){
+ return proxy.isCapabilitySupported(systemCapabilityType);
+ }
+
+ @Override
+ public void addOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) {
+ proxy.addOnSystemCapabilityListener(systemCapabilityType, listener);
+ }
+
+ @Override
+ public boolean removeOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) {
+ return proxy.removeOnSystemCapabilityListener(systemCapabilityType, listener);
+ }
+
+ @Override
+ public boolean isTransportForServiceAvailable(SessionType serviceType) {
+ if(SessionType.NAV.equals(serviceType)){
+ return proxy.isVideoStreamTransportAvailable();
+ }else if(SessionType.PCM.equals(serviceType)){
+ return proxy.isAudioStreamTransportAvailable();
+ }
+ return false;
+ }
+
+ @Override
+ public SdlMsgVersion getSdlMsgVersion(){
+ try {
+ return proxy.getSdlMsgVersion();
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public @NonNull Version getProtocolVersion() {
+ if(proxy.getProtocolVersion() != null){
+ return proxy.getProtocolVersion();
+ }else{
+ return new Version(1,0,0);
+ }
+ }
+
+ };
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java b/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java
new file mode 100644
index 000000000..22a3fcd58
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java
@@ -0,0 +1,21 @@
+package com.smartdevicelink.managers;
+
+public interface SdlManagerListener {
+
+ /**
+ * Called when a manager is ready for use
+ */
+ void onStart();
+
+ /**
+ * Called when the manager is destroyed
+ */
+ void onDestroy();
+
+ /**
+ * Called when the manager encounters an error
+ * @param info info regarding the error
+ * @param e the exception
+ */
+ void onError(String info, Exception e);
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/StreamingStateMachine.java b/sdl_android/src/main/java/com/smartdevicelink/managers/StreamingStateMachine.java
new file mode 100644
index 000000000..caabf67a2
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/StreamingStateMachine.java
@@ -0,0 +1,72 @@
+package com.smartdevicelink.managers;
+
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+public class StreamingStateMachine {
+ @IntDef({NONE, READY, STARTED, STOPPED, ERROR})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StreamingState {}
+ public static final int NONE = 0x00, READY = 0x30, STARTED = 0x60, STOPPED = 0x90, ERROR = 0xC0;
+
+ private @StreamingState int state = NONE;
+ private final Object STATE_LOCK = new Object();
+
+ public StreamingStateMachine(){}
+
+ public void transitionToState(int state) {
+ if(state != NONE && state != READY && state != STARTED
+ && state != STOPPED && state != ERROR) {
+ return;
+ }
+ synchronized (STATE_LOCK) {
+ if(isValidTransition(this.state, state)){
+ this.state = state;
+ }
+ }
+ }
+
+ public @StreamingState int getState() {
+ synchronized (STATE_LOCK) {
+ return state;
+ }
+ }
+
+ private boolean isValidTransition(int prev_state, int next_state){
+ if(prev_state == next_state){
+ return false;
+ }
+ switch (prev_state){
+ case NONE:
+ if((next_state == READY) || (next_state == ERROR)){
+ return true;
+ }
+ break;
+ case READY:
+ if((next_state == STARTED) || (next_state == ERROR)){
+ return true;
+ }
+ break;
+ case STARTED:
+ if((next_state == STOPPED) || (next_state == ERROR)){
+ return true;
+ }
+ break;
+ case STOPPED:
+ if((next_state == STARTED) || (next_state == NONE)){
+ return true;
+ }
+ break;
+ case ERROR:
+ if(next_state == NONE){
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioDecoder.java b/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioDecoder.java
new file mode 100644
index 000000000..c80ebba39
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioDecoder.java
@@ -0,0 +1,90 @@
+package com.smartdevicelink.managers.audio;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.util.Log;
+import com.smartdevicelink.managers.audio.AudioStreamManager.SampleType;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The audio decoder to decode a single audio file to PCM.
+ */
+@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+public class AudioDecoder extends BaseAudioDecoder {
+ private static final String TAG = AudioDecoder.class.getSimpleName();
+
+ /**
+ * Creates a new object of AudioDecoder.
+ * @param audioSource The audio source to decode.
+ * @param context The context object to use to open the audio source.
+ * @param sampleRate The desired sample rate for decoded audio data.
+ * @param sampleType The desired sample type (8bit, 16bit, float).
+ * @param listener A listener who receives the decoded audio.
+ */
+ AudioDecoder(Uri audioSource, Context context, int sampleRate, @SampleType int sampleType, AudioDecoderListener listener) {
+ super(audioSource, context, sampleRate, sampleType, listener);
+ }
+
+ /**
+ * Starts the audio decoding asynchronously.
+ */
+ public void start() {
+ try {
+ initMediaComponents();
+
+ decoder.setCallback(new MediaCodec.Callback() {
+ @Override
+ public void onInputBufferAvailable(@NonNull MediaCodec mediaCodec, int i) {
+ ByteBuffer inputBuffer = mediaCodec.getInputBuffer(i);
+ if (inputBuffer == null) return;
+
+ MediaCodec.BufferInfo info = AudioDecoder.super.onInputBufferAvailable(extractor, inputBuffer);
+ mediaCodec.queueInputBuffer(i, info.offset, info.size, info.presentationTimeUs, info.flags);
+ }
+
+ @Override
+ public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec, int i, @NonNull MediaCodec.BufferInfo bufferInfo) {
+ ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(i);
+ if (outputBuffer == null) return;
+
+ if (outputBuffer.limit() > 0) {
+ SampleBuffer targetSampleBuffer = AudioDecoder.super.onOutputBufferAvailable(outputBuffer);
+ AudioDecoder.this.listener.onAudioDataAvailable(targetSampleBuffer);
+ } else {
+ Log.w(TAG, "output buffer empty. Chance that silence was detected");
+ }
+
+ mediaCodec.releaseOutputBuffer(i, false);
+
+ if (bufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
+ listener.onDecoderFinish(true);
+ stop();
+ }
+ }
+
+ @Override
+ public void onOutputFormatChanged(@NonNull MediaCodec mediaCodec, @NonNull MediaFormat mediaFormat) {
+ AudioDecoder.super.onOutputFormatChanged(mediaFormat);
+ }
+
+ @Override
+ public void onError(@NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
+ AudioDecoder.super.onMediaCodecError(e);
+ }
+ });
+
+ decoder.start();
+ } catch (Exception e) {
+ e.printStackTrace();
+ listener.onDecoderError(e);
+ listener.onDecoderFinish(false);
+ stop();
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioDecoderCompat.java b/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioDecoderCompat.java
new file mode 100644
index 000000000..43daef4b3
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioDecoderCompat.java
@@ -0,0 +1,137 @@
+package com.smartdevicelink.managers.audio;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.util.Log;
+
+import com.smartdevicelink.managers.audio.AudioStreamManager.SampleType;
+
+import java.lang.ref.WeakReference;
+import java.nio.ByteBuffer;
+
+/**
+ * The audio decoder to decode a single audio file to PCM.
+ * This decoder supports phones with api < 21 but uses methods deprecated with api 21.
+ */
+@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
+public class AudioDecoderCompat extends BaseAudioDecoder {
+ private static final String TAG = AudioDecoderCompat.class.getSimpleName();
+ private static final int DEQUEUE_TIMEOUT = 3000;
+ private static Runnable sRunnable;
+ private Thread mThread;
+
+ /**
+ * Creates a new object of AudioDecoder.
+ * @param audioSource The audio source to decode.
+ * @param context The context object to use to open the audio source.
+ * @param sampleRate The desired sample rate for decoded audio data.
+ * @param sampleType The desired sample type (8bit, 16bit, float).
+ * @param listener A listener who receives the decoded audio.
+ */
+ AudioDecoderCompat(@NonNull Uri audioSource, @NonNull Context context, int sampleRate, @SampleType int sampleType, AudioDecoderListener listener) {
+ super(audioSource, context, sampleRate, sampleType, listener);
+ }
+
+ /**
+ * Starts the audio decoding asynchronously.
+ */
+ public void start() {
+ try {
+ initMediaComponents();
+ decoder.start();
+ mThread = new Thread(new DecoderRunnable(AudioDecoderCompat.this));
+ mThread.start();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ if(this.listener != null) {
+ this.listener.onDecoderError(e);
+ this.listener.onDecoderFinish(false);
+ }
+ stop();
+ }
+ }
+
+
+ /**
+ * Runnable to decode audio data
+ */
+ private static class DecoderRunnable implements Runnable {
+ WeakReference<AudioDecoderCompat> weakReference;
+
+ /**
+ * Decodes all audio data from source
+ * @param audioDecoderCompat instance of this class
+ */
+ DecoderRunnable(@NonNull AudioDecoderCompat audioDecoderCompat){
+ weakReference = new WeakReference<>(audioDecoderCompat);
+
+ }
+ @Override
+ public void run() {
+ final AudioDecoderCompat reference = weakReference.get();
+ if (reference == null) {
+ Log.w(TAG, "AudioDecoderCompat reference was null");
+ return;
+ }
+ final ByteBuffer[] inputBuffersArray = reference.decoder.getInputBuffers();
+ final ByteBuffer[] outputBuffersArray = reference.decoder.getOutputBuffers();
+ MediaCodec.BufferInfo outputBufferInfo = new MediaCodec.BufferInfo();
+ MediaCodec.BufferInfo inputBufferInfo;
+ ByteBuffer inputBuffer, outputBuffer;
+ SampleBuffer sampleBuffer;
+
+ while (reference!= null && !reference.mThread.isInterrupted()) {
+ int inputBuffersArrayIndex = 0;
+ while (inputBuffersArrayIndex != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ inputBuffersArrayIndex = reference.decoder.dequeueInputBuffer(DEQUEUE_TIMEOUT);
+ if (inputBuffersArrayIndex >= 0) {
+ inputBuffer = inputBuffersArray[inputBuffersArrayIndex];
+ inputBufferInfo = reference.onInputBufferAvailable(reference.extractor, inputBuffer);
+ reference.decoder.queueInputBuffer(inputBuffersArrayIndex, inputBufferInfo.offset, inputBufferInfo.size, inputBufferInfo.presentationTimeUs, inputBufferInfo.flags);
+ }
+ }
+
+ int outputBuffersArrayIndex = 0;
+ while (outputBuffersArrayIndex != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ outputBuffersArrayIndex = reference.decoder.dequeueOutputBuffer(outputBufferInfo, DEQUEUE_TIMEOUT);
+ if (outputBuffersArrayIndex >= 0) {
+ outputBuffer = outputBuffersArray[outputBuffersArrayIndex];
+ if ((outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0 && outputBufferInfo.size != 0) {
+ reference.decoder.releaseOutputBuffer(outputBuffersArrayIndex, false);
+ } else if (outputBuffer.limit() > 0) {
+ sampleBuffer = reference.onOutputBufferAvailable(outputBuffer);
+ if(reference.listener!=null){
+ reference.listener.onAudioDataAvailable(sampleBuffer);
+ }
+ reference.decoder.releaseOutputBuffer(outputBuffersArrayIndex, false);
+ }
+ } else if (outputBuffersArrayIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ MediaFormat newFormat = reference.decoder.getOutputFormat();
+ reference.onOutputFormatChanged(newFormat);
+ }
+ }
+
+ if (outputBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
+ if (reference.listener != null) {
+ reference.listener.onDecoderFinish(true);
+ }
+ reference.stop();
+ try {
+ reference.mThread.interrupt();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ reference.mThread = null;
+ break;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioDecoderListener.java b/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioDecoderListener.java
new file mode 100644
index 000000000..d8dcc1238
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioDecoderListener.java
@@ -0,0 +1,27 @@
+package com.smartdevicelink.managers.audio;
+
+/**
+ * An interface for the audio decoder classes.
+ * The caller using the audio decoder will be
+ * notified when the decoding is finished or if an error occurred.
+ * During decoding the caller receives sample buffers with decoded audio data.
+ */
+public interface AudioDecoderListener {
+ /**
+ * Notifies that decoded audio data is available.
+ * @param sampleBuffer The sample buffer holding the decoded audio data.
+ */
+ void onAudioDataAvailable(SampleBuffer sampleBuffer);
+
+ /**
+ * Notifies that the audio decoding is finished.
+ * @param success Indicates whether audio decoding was successful or if an error occurred.
+ */
+ void onDecoderFinish(boolean success);
+
+ /**
+ * Notifies the caller that an error/exception occurred during audio decoding.
+ * @param e The exception storing information about the error.
+ */
+ void onDecoderError(Exception e);
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioStreamManager.java b/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioStreamManager.java
new file mode 100644
index 000000000..da58692af
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioStreamManager.java
@@ -0,0 +1,447 @@
+package com.smartdevicelink.managers.audio;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.util.Log;
+
+import com.smartdevicelink.SdlConnection.SdlSession;
+import com.smartdevicelink.managers.BaseSubManager;
+import com.smartdevicelink.managers.CompletionListener;
+import com.smartdevicelink.managers.StreamingStateMachine;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.proxy.RPCNotification;
+import com.smartdevicelink.proxy.interfaces.IAudioStreamListener;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.interfaces.ISdlServiceListener;
+import com.smartdevicelink.proxy.interfaces.OnSystemCapabilityListener;
+import com.smartdevicelink.proxy.rpc.AudioPassThruCapabilities;
+import com.smartdevicelink.proxy.rpc.OnHMIStatus;
+import com.smartdevicelink.proxy.rpc.enums.HMILevel;
+import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
+import com.smartdevicelink.transport.utl.TransportRecord;
+import com.smartdevicelink.util.Version;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+
+/**
+ * The AudioStreamManager class provides methods to start and stop an audio stream
+ * to the connected device. Audio files can be pushed to the manager in order to
+ * play them on the connected device. The manager uses the Android built-in MediaCodec.
+ */
+@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
+public class AudioStreamManager extends BaseSubManager {
+ private static final String TAG = AudioStreamManager.class.getSimpleName();
+ private static final int COMPLETION_TIMEOUT = 2000;
+
+ private IAudioStreamListener sdlAudioStream;
+ private int sdlSampleRate;
+ private @SampleType int sdlSampleType;
+ private final Queue<BaseAudioDecoder> queue;
+ private final WeakReference<Context> context;
+ private final StreamingStateMachine streamingStateMachine;
+ private AudioPassThruCapabilities audioStreamingCapabilities;
+ private HMILevel hmiLevel;
+ private boolean isTransportAvailable = false;
+ // This completion listener is used as a callback to the app developer when starting/stopping audio service
+ private CompletionListener serviceCompletionListener;
+ // As the internal interface does not provide timeout we need to use a future task
+ private final Handler serviceCompletionHandler;
+
+ private final Runnable serviceCompletionTimeoutCallback = new Runnable() {
+ @Override
+ public void run() {
+ serviceListener.onServiceError(null, SessionType.PCM, "Service operation timeout reached");
+ }
+ };
+
+
+
+ // INTERNAL INTERFACE
+
+ private final ISdlServiceListener serviceListener = new ISdlServiceListener() {
+ @Override
+ public void onServiceStarted(SdlSession session, SessionType type, boolean isEncrypted) {
+ if (SessionType.PCM.equals(type)) {
+ serviceCompletionHandler.removeCallbacks(serviceCompletionTimeoutCallback);
+
+ sdlAudioStream = session.startAudioStream();
+ streamingStateMachine.transitionToState(StreamingStateMachine.STARTED);
+
+ if (serviceCompletionListener != null) {
+ CompletionListener completionListener = serviceCompletionListener;
+ serviceCompletionListener = null;
+ completionListener.onComplete(true);
+ }
+ }
+ }
+
+ @Override
+ public void onServiceEnded(SdlSession session, SessionType type) {
+ if (SessionType.PCM.equals(type)) {
+ serviceCompletionHandler.removeCallbacks(serviceCompletionTimeoutCallback);
+
+ session.stopAudioStream();
+ sdlAudioStream = null;
+ streamingStateMachine.transitionToState(StreamingStateMachine.NONE);
+
+ if (serviceCompletionListener != null) {
+ CompletionListener completionListener = serviceCompletionListener;
+ serviceCompletionListener = null;
+ completionListener.onComplete(true);
+ }
+ }
+ }
+
+ @Override
+ public void onServiceError(SdlSession session, SessionType type, String reason) {
+ if (SessionType.PCM.equals(type)) {
+ serviceCompletionHandler.removeCallbacks(serviceCompletionTimeoutCallback);
+
+ streamingStateMachine.transitionToState(StreamingStateMachine.ERROR);
+ Log.e(TAG, "OnServiceError: " + reason);
+ streamingStateMachine.transitionToState(StreamingStateMachine.NONE);
+
+ if (serviceCompletionListener != null) {
+ CompletionListener completionListener = serviceCompletionListener;
+ serviceCompletionListener = null;
+ completionListener.onComplete(false);
+ }
+ }
+ }
+ };
+
+ private final OnRPCNotificationListener hmiListener = new OnRPCNotificationListener() {
+ @Override
+ public void onNotified(RPCNotification notification) {
+ if(notification != null){
+ hmiLevel = ((OnHMIStatus)notification).getHmiLevel();
+ if(hmiLevel.equals(HMILevel.HMI_FULL) || hmiLevel.equals(HMILevel.HMI_LIMITED)){
+ checkState();
+ }
+ }
+ }
+ };
+
+ /**
+ * Creates a new object of AudioStreamManager
+ * @param internalInterface The internal interface to the connected device.
+ */
+ public AudioStreamManager(@NonNull ISdl internalInterface, @NonNull Context context) {
+ super(internalInterface);
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN){
+ this.queue = null;
+ this.context = null;
+ this.serviceCompletionHandler = null;
+ this.streamingStateMachine = null;
+ transitionToState(ERROR);
+ return;
+ }
+ this.queue = new LinkedList<>();
+ this.context = new WeakReference<>(context);
+ this.serviceCompletionHandler = new Handler(Looper.getMainLooper());
+
+ internalInterface.addServiceListener(SessionType.PCM, serviceListener);
+
+ // Listen for HMILevel changes
+ internalInterface.addOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, hmiListener);
+
+ streamingStateMachine = new StreamingStateMachine();
+
+ }
+
+ @Override
+ public void start(CompletionListener listener) {
+ isTransportAvailable = internalInterface.isTransportForServiceAvailable(SessionType.PCM);
+ getAudioStreamingCapabilities();
+ checkState();
+ super.start(listener);
+ }
+
+ private void checkState(){
+ if(audioStreamingCapabilities != null
+ && isTransportAvailable
+ && hmiLevel != null
+ && (hmiLevel.equals(HMILevel.HMI_LIMITED) || hmiLevel.equals(HMILevel.HMI_FULL))){
+ transitionToState(READY);
+ }
+ }
+
+ private void getAudioStreamingCapabilities(){
+ internalInterface.getCapability(SystemCapabilityType.PCM_STREAMING, new OnSystemCapabilityListener() {
+ @Override
+ public void onCapabilityRetrieved(Object capability) {
+ if(capability != null && capability instanceof AudioPassThruCapabilities){
+ audioStreamingCapabilities = (AudioPassThruCapabilities) capability;
+ checkState();
+ }
+ }
+
+ @Override
+ public void onError(String info) {
+ Log.e(TAG, "Error retrieving audio streaming capability: " + info);
+ streamingStateMachine.transitionToState(StreamingStateMachine.ERROR);
+ transitionToState(ERROR);
+ }
+ });
+ }
+
+ @Override
+ public void dispose() {
+ stopAudioStream(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ internalInterface.removeServiceListener(SessionType.PCM, serviceListener);
+ }
+ });
+
+ super.dispose();
+ }
+
+ /**
+ * Starts the audio service and audio stream to the connected device.
+ * The method is non-blocking.
+ * @param encrypted Specify whether or not the audio stream should be encrypted.
+ */
+ public void startAudioStream(boolean encrypted, final CompletionListener completionListener) {
+ // audio stream cannot be started without a connected internal interface
+ if (!internalInterface.isConnected()) {
+ Log.w(TAG, "startAudioStream called without being connected.");
+ finish(completionListener, false);
+ return;
+ }
+
+ // streaming state must be NONE (starting the service is ready. starting stream is started)
+ if (streamingStateMachine.getState() != StreamingStateMachine.NONE) {
+ Log.w(TAG, "startAudioStream called but streamingStateMachine is not in state NONE (current: " + streamingStateMachine.getState() + ")");
+ finish(completionListener, false);
+ return;
+ }
+
+ AudioPassThruCapabilities capabilities = (AudioPassThruCapabilities) internalInterface.getCapability(SystemCapabilityType.PCM_STREAMING);
+
+ if (capabilities != null) {
+ switch (capabilities.getSamplingRate()) {
+ case _8KHZ:
+ sdlSampleRate = 8000;
+ break;
+ case _16KHZ:
+ sdlSampleRate = 16000;
+ break;
+ case _22KHZ:
+ // common sample rate is 22050, not 22000
+ // see https://en.wikipedia.org/wiki/Sampling_(signal_processing)#Audio_sampling
+ sdlSampleRate = 22050;
+ break;
+ case _44KHZ:
+ // 2x 22050 is 44100
+ // see https://en.wikipedia.org/wiki/Sampling_(signal_processing)#Audio_sampling
+ sdlSampleRate = 44100;
+ break;
+ default:
+ finish(completionListener, false);
+ return;
+ }
+
+ switch (capabilities.getBitsPerSample()) {
+ case _8_BIT:
+ sdlSampleType = SampleType.UNSIGNED_8_BIT;
+ break;
+ case _16_BIT:
+ sdlSampleType = SampleType.SIGNED_16_BIT;
+ break;
+ default:
+ finish(completionListener, false);
+ return;
+
+ }
+ } else {
+ finish(completionListener, false);
+ return;
+ }
+
+ streamingStateMachine.transitionToState(StreamingStateMachine.READY);
+ serviceCompletionListener = completionListener;
+ serviceCompletionHandler.postDelayed(serviceCompletionTimeoutCallback, COMPLETION_TIMEOUT);
+ internalInterface.startAudioService(encrypted);
+ }
+
+ /**
+ * Makes the callback to the listener
+ * @param listener the listener to notify
+ * @param isSuccess flag to notify
+ */
+ private void finish(CompletionListener listener, boolean isSuccess) {
+ if (listener != null) {
+ listener.onComplete(isSuccess);
+ }
+ }
+
+ /**
+ * Stops the audio service and audio stream to the connected device.
+ * The method is non-blocking.
+ */
+ public void stopAudioStream(final CompletionListener completionListener) {
+ if (!internalInterface.isConnected()) {
+ Log.w(TAG, "stopAudioStream called without being connected");
+ finish(completionListener, false);
+ return;
+ }
+
+ // streaming state must be STARTED (starting the service is ready. starting stream is started)
+ if (streamingStateMachine.getState() != StreamingStateMachine.STARTED) {
+ Log.w(TAG, "stopAudioStream called but streamingStateMachine is not STARTED (current: " + streamingStateMachine.getState() + ")");
+ finish(completionListener, false);
+ return;
+ }
+
+ streamingStateMachine.transitionToState(StreamingStateMachine.STOPPED);
+ serviceCompletionListener = completionListener;
+ serviceCompletionHandler.postDelayed(serviceCompletionTimeoutCallback, COMPLETION_TIMEOUT);
+ internalInterface.stopAudioService();
+ }
+
+ /**
+ * Pushes the specified resource file to the playback queue.
+ * The audio file will be played immediately. If another audio file is currently playing
+ * the specified file will stay queued and automatically played when ready.
+ * @param resourceId The specified resource file to be played.
+ * @param completionListener A completion listener that informs when the audio file is played.
+ */
+ public void pushResource(int resourceId, final CompletionListener completionListener) {
+ Context c = context.get();
+ Resources r = c.getResources();
+ Uri uri = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
+ .authority(r.getResourcePackageName(resourceId))
+ .appendPath(r.getResourceTypeName(resourceId))
+ .appendPath(r.getResourceEntryName(resourceId))
+ .build();
+
+ this.pushAudioSource(uri, completionListener);
+ }
+
+ /**
+ * Pushes the specified audio file to the playback queue.
+ * The audio file will be played immediately. If another audio file is currently playing
+ * the specified file will stay queued and automatically played when ready.
+ * @param audioSource The specified audio file to be played.
+ * @param completionListener A completion listener that informs when the audio file is played.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public void pushAudioSource(Uri audioSource, final CompletionListener completionListener) {
+ // streaming state must be STARTED (starting the service is ready. starting stream is started)
+ if (streamingStateMachine.getState() != StreamingStateMachine.STARTED) {
+ return;
+ }
+
+ BaseAudioDecoder decoder;
+ AudioDecoderListener decoderListener = new AudioDecoderListener() {
+ @Override
+ public void onAudioDataAvailable(SampleBuffer buffer) {
+ sdlAudioStream.sendAudio(buffer.getByteBuffer(), buffer.getPresentationTimeUs());
+ }
+
+ @Override
+ public void onDecoderFinish(boolean success) {
+ finish(completionListener, true);
+
+ synchronized (queue) {
+ // remove throws an exception if the queue is empty. The decoder of this listener
+ // should still be in this queue so we should be fine by just removing it
+ // if the queue is empty than we have a bug somewhere in the code
+ // and we deserve the crash...
+ queue.remove();
+
+ // if the queue contains more items then start the first one (without removing it)
+ if (queue.size() > 0) {
+ queue.element().start();
+ }
+ }
+ }
+
+ @Override
+ public void onDecoderError(Exception e) {
+ Log.e(TAG, "decoder error", e);
+ }
+ };
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ decoder = new AudioDecoder(audioSource, context.get(), sdlSampleRate, sdlSampleType, decoderListener);
+ } else {
+ // this BaseAudioDecoder subclass uses methods deprecated with api 21
+ decoder = new AudioDecoderCompat(audioSource, context.get(), sdlSampleRate, sdlSampleType, decoderListener);
+ }
+
+ synchronized (queue) {
+ queue.add(decoder);
+
+ if (queue.size() == 1) {
+ decoder.start();
+ }
+ }
+ }
+
+
+ @Override
+ protected void onTransportUpdate(List<TransportRecord> connectedTransports, boolean audioStreamTransportAvail, boolean videoStreamTransportAvail){
+
+ isTransportAvailable = audioStreamTransportAvail;
+
+ if(internalInterface.getProtocolVersion().isNewerThan(new Version(5,1,0)) >= 0){
+ if(audioStreamTransportAvail){
+ checkState();
+ }
+ }else{
+ //The protocol version doesn't support simultaneous transports.
+ if(!audioStreamTransportAvail){
+ //If video streaming isn't available on primary transport then it is not possible to
+ //use the video streaming manager until a complete register on a transport that
+ //supports video
+ transitionToState(ERROR);
+ }
+ }
+ }
+
+ @IntDef({SampleType.UNSIGNED_8_BIT, SampleType.SIGNED_16_BIT, SampleType.FLOAT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SampleType {
+ // ref https://developer.android.com/reference/android/media/AudioFormat "Encoding" section
+ // The audio sample is a 8 bit unsigned integer in the range [0, 255], with a 128 offset for zero.
+ // This is typically stored as a Java byte in a byte array or ByteBuffer. Since the Java byte is
+ // signed, be careful with math operations and conversions as the most significant bit is inverted.
+ //
+ // The unsigned byte range is [0, 255] and should be converted to double [-1.0, 1.0]
+ // The 8 bits of the byte are easily converted to int by using bitwise operator
+ int UNSIGNED_8_BIT = Byte.SIZE >> 3;
+
+ // ref https://developer.android.com/reference/android/media/AudioFormat "Encoding" section
+ // The audio sample is a 16 bit signed integer typically stored as a Java short in a short array,
+ // but when the short is stored in a ByteBuffer, it is native endian (as compared to the default Java big endian).
+ // The short has full range from [-32768, 32767], and is sometimes interpreted as fixed point Q.15 data.
+ //
+ // the conversion is slightly easier from [-32768, 32767] to [-1.0, 1.0]
+ int SIGNED_16_BIT = Short.SIZE >> 3;
+
+ // ref https://developer.android.com/reference/android/media/AudioFormat "Encoding" section
+ // Introduced in API Build.VERSION_CODES.LOLLIPOP, this encoding specifies that the audio sample
+ // is a 32 bit IEEE single precision float. The sample can be manipulated as a Java float in a
+ // float array, though within a ByteBuffer it is stored in native endian byte order. The nominal
+ // range of ENCODING_PCM_FLOAT audio data is [-1.0, 1.0].
+ int FLOAT = Float.SIZE >> 3;
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/audio/BaseAudioDecoder.java b/sdl_android/src/main/java/com/smartdevicelink/managers/audio/BaseAudioDecoder.java
new file mode 100644
index 000000000..22a54a172
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/audio/BaseAudioDecoder.java
@@ -0,0 +1,246 @@
+package com.smartdevicelink.managers.audio;
+
+import android.content.Context;
+import android.media.AudioFormat;
+import android.media.MediaCodec;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.util.Log;
+import com.smartdevicelink.managers.audio.AudioStreamManager.SampleType;
+import com.smartdevicelink.proxy.rpc.AudioPassThruCapabilities;
+
+import java.lang.ref.WeakReference;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+@SuppressWarnings("WeakerAccess")
+@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
+public abstract class BaseAudioDecoder {
+ private static final String TAG = AudioDecoder.class.getSimpleName();
+
+ protected final int targetSampleRate;
+ protected @SampleType final int targetSampleType;
+
+ private int outputChannelCount;
+ private int outputSampleRate;
+ private @SampleType int outputSampleType;
+
+ private double lastOutputSample = 0;
+
+ private double lastOutputPresentationTimeUs = 0;
+ private double lastTargetPresentationTimeUs = 0;
+
+ protected MediaExtractor extractor;
+ protected MediaCodec decoder;
+
+ protected final Uri audioSource;
+ protected final WeakReference<Context> contextWeakReference;
+ protected final AudioDecoderListener listener;
+
+ /**
+ *
+ * @param audioSource Uri of the audio source to be converted
+ * @param context the context
+ * @param sampleRate can be either 8000, 16000, 22050 or 44100
+ * @see AudioPassThruCapabilities#getSamplingRate()
+ * @param sampleType can be either UNSIGNED_8_BIT, SIGNED_16_BIT, FLOAT
+ * @see SampleType
+ * @param listener listener for event callbacks
+ */
+ public BaseAudioDecoder(@NonNull Uri audioSource, @NonNull Context context, int sampleRate, @SampleType int sampleType, AudioDecoderListener listener) {
+ this.audioSource = audioSource;
+ this.contextWeakReference = new WeakReference<>(context);
+ this.listener = listener;
+
+ targetSampleRate = sampleRate;
+ targetSampleType = sampleType;
+ }
+
+ protected void initMediaComponents() throws Exception {
+ if(targetSampleRate <= 0){
+ throw new InstantiationException("Target sample rate of " + targetSampleRate + " is unsupported");
+ }
+
+ extractor = new MediaExtractor();
+ Context contextRef = contextWeakReference.get();
+ if(contextRef == null){
+ throw new InstantiationException("Context reference was null");
+ }
+ extractor.setDataSource(contextRef, audioSource, null);
+ MediaFormat format = null;
+ String mime = null;
+
+ // Select the first audio track we find.
+ int numTracks = extractor.getTrackCount();
+ for (int i = 0; i < numTracks; ++i) {
+ MediaFormat f = extractor.getTrackFormat(i);
+ String m = f.getString(MediaFormat.KEY_MIME);
+ if (m.startsWith("audio/")) {
+ format = f;
+ mime = m;
+ extractor.selectTrack(i);
+ break;
+ }
+ }
+
+ if (mime == null) {
+ throw new Exception("The audio file " + audioSource.getPath() + " doesn't contain an audio track.");
+ }
+
+ decoder = MediaCodec.createDecoderByType(mime);
+ decoder.configure(format, null, null, 0);
+ }
+
+ private Double sampleAtTargetTime(double lastOutputSample, SampleBuffer outputSampleBuffer, double outputPresentationTimeUs, double outputDurationPerSampleUs, double targetPresentationTimeUs) {
+ double timeDiff = targetPresentationTimeUs - outputPresentationTimeUs;
+ double index = timeDiff / outputDurationPerSampleUs;
+
+ // the "last known sample" allows an index from -1.0 to 0
+ // the index cannot exceed the last sample. it must be stored to become the "last known sample" in the next iteration
+ if (index < -1.0 || Math.ceil(index) >= outputSampleBuffer.limit()) {
+ return null;
+ }
+
+ if (index == -1.0) {
+ // the index points exactly to the last known sample
+ return lastOutputSample;
+ } else if (index % 1 == 0) {
+ // index has no digits. therefore current index points to a known sample
+ return outputSampleBuffer.get((int) index);
+ } else {
+ // the first sample can be the last known one
+ double first = index < 0.0 ? lastOutputSample : outputSampleBuffer.get((int) index);
+ double second = outputSampleBuffer.get((int) Math.ceil(index));
+ double rel = index % 1;
+
+ // if the relative is between -1 and 0
+ if (rel < 0.0) {
+ rel = 1 + rel;
+ }
+
+ return first + (second - first) * rel;
+ }
+ }
+
+ protected MediaCodec.BufferInfo onInputBufferAvailable(@NonNull MediaExtractor extractor, @NonNull ByteBuffer inputBuffer) {
+ long sampleTime = extractor.getSampleTime();
+ int counter = 0;
+ int maxresult = 0;
+ int result;
+ boolean advanced = false;
+
+ do {
+ result = extractor.readSampleData(inputBuffer, counter);
+ if (result >= 0) {
+ advanced = extractor.advance();
+ maxresult = Math.max(maxresult, result);
+ counter += result;
+ }
+ } while (result >= 0 && advanced && inputBuffer.capacity() - inputBuffer.limit() > maxresult);
+ // the remaining capacity should be more than enough for another sample data block
+
+ // queue the input buffer. At end of file counter will be 0 and flags marks end of stream
+ // offset MUST be 0. The output buffer code cannot handle offsets
+ // result < 0 means the end of the file input is reached
+ int flags = advanced ? 0 : MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+
+ MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
+ bufferInfo.set(0, counter, sampleTime, flags);
+
+ return bufferInfo;
+ }
+
+ protected SampleBuffer onOutputBufferAvailable(@NonNull ByteBuffer outputBuffer) {
+ double outputPresentationTimeUs = lastOutputPresentationTimeUs;
+ double outputDurationPerSampleUs = 1000000.0 / (double)outputSampleRate;
+
+ double targetPresentationTimeUs = lastTargetPresentationTimeUs;
+ double targetDurationPerSampleUs = 1000000.0 / (double)targetSampleRate;
+
+ // wrap the output buffer to make it provide audio samples
+ SampleBuffer outputSampleBuffer = SampleBuffer.wrap(outputBuffer, outputSampleType, outputChannelCount, (long)outputPresentationTimeUs);
+ outputSampleBuffer.position(0);
+
+ // the buffer size is related to the output and target sample rate
+ // add 2 samples to round up and add an extra sample
+ int sampleSize = outputSampleBuffer.limit() * targetSampleRate / outputSampleRate + 2;
+
+ SampleBuffer targetSampleBuffer = SampleBuffer.allocate(sampleSize, targetSampleType, ByteOrder.LITTLE_ENDIAN, (long)targetPresentationTimeUs);
+ Double sample;
+
+ do {
+ sample = sampleAtTargetTime(lastOutputSample, outputSampleBuffer, outputPresentationTimeUs, outputDurationPerSampleUs, targetPresentationTimeUs);
+ if (sample != null) {
+ targetSampleBuffer.put(sample);
+ targetPresentationTimeUs += targetDurationPerSampleUs;
+ }
+ } while (sample != null);
+
+ lastTargetPresentationTimeUs = targetPresentationTimeUs;
+ lastOutputPresentationTimeUs += outputSampleBuffer.limit() * outputDurationPerSampleUs;
+ lastOutputSample = outputSampleBuffer.get(outputSampleBuffer.limit() - 1);
+
+ targetSampleBuffer.limit(targetSampleBuffer.position());
+ targetSampleBuffer.position(0);
+
+ return targetSampleBuffer;
+ }
+
+ protected void onOutputFormatChanged(@NonNull MediaFormat mediaFormat) {
+ if (mediaFormat.containsKey(MediaFormat.KEY_CHANNEL_COUNT)) {
+ outputChannelCount = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+ }
+
+ if (mediaFormat.containsKey(MediaFormat.KEY_SAMPLE_RATE)) {
+ outputSampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
+ }
+
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N && mediaFormat.containsKey(MediaFormat.KEY_PCM_ENCODING)) {
+ int key = mediaFormat.getInteger(MediaFormat.KEY_PCM_ENCODING);
+ switch (key) {
+ case AudioFormat.ENCODING_PCM_8BIT:
+ outputSampleType = SampleType.UNSIGNED_8_BIT;
+ break;
+ case AudioFormat.ENCODING_PCM_FLOAT:
+ outputSampleType = SampleType.FLOAT;
+ break;
+ case AudioFormat.ENCODING_PCM_16BIT:
+ default:
+ // by default we fallback to signed 16 bit samples
+ outputSampleType = SampleType.SIGNED_16_BIT;
+ break;
+ }
+ } else {
+ outputSampleType = SampleType.SIGNED_16_BIT;
+ }
+ }
+
+ protected void onMediaCodecError(@NonNull MediaCodec.CodecException e) {
+ Log.e(TAG, "MediaCodec.onError: " + e.getLocalizedMessage());
+ if (listener != null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ listener.onDecoderError(e);
+ } else {
+ listener.onDecoderError(new Exception("Error decoding audio file"));
+ }
+ }
+ }
+
+ public abstract void start();
+
+ public void stop() {
+ if (decoder != null) {
+ decoder.stop();
+ decoder.release();
+ decoder = null;
+ }
+
+ if (extractor != null) {
+ extractor = null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/audio/SampleBuffer.java b/sdl_android/src/main/java/com/smartdevicelink/managers/audio/SampleBuffer.java
new file mode 100644
index 000000000..6ae5c6266
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/audio/SampleBuffer.java
@@ -0,0 +1,280 @@
+package com.smartdevicelink.managers.audio;
+
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import com.smartdevicelink.managers.audio.AudioStreamManager.SampleType;
+
+/**
+ * Wraps a buffer of raw audio samples depending on the sample type (8 bit, 16 bit)
+ * Unifies samples into double.
+ */
+public class SampleBuffer {
+ private static final String TAG = SampleBuffer.class.getSimpleName();
+
+ @SuppressWarnings({"unused", "FieldCanBeLocal"})
+ private @SampleType final int sampleType;
+ private final ByteBuffer byteBuffer;
+ private final int channelCount;
+ private final long presentationTimeUs;
+
+ /**
+ * Wraps a raw (mono) byte buffer to a new sample buffer.
+ * @param buffer The raw buffer to be wrapped.
+ * @param sampleType The sample type of the samples in the raw buffer.
+ * @param presentationTimeUs The presentation time of the buffer.
+ * @return A new sample buffer wrapping the specified raw buffer.
+ */
+ public static SampleBuffer wrap(ByteBuffer buffer, @SampleType int sampleType, long presentationTimeUs) {
+ return new SampleBuffer(buffer, sampleType, 1, presentationTimeUs);
+ }
+
+ /**
+ * Wraps a raw byte buffer to a new sample buffer.
+ * @param buffer The raw buffer to be wrapped.
+ * @param sampleType The sample type of the samples in the raw buffer.
+ * @param channelCount The number of channels (1 = mono, 2 = stereo).
+ * @param presentationTimeUs The presentation time of the buffer.
+ * @return A new sample buffer wrapping the specified raw buffer.
+ */
+ public static SampleBuffer wrap(ByteBuffer buffer, @SampleType int sampleType, int channelCount, long presentationTimeUs) {
+ return new SampleBuffer(buffer, sampleType, channelCount, presentationTimeUs);
+ }
+
+ /**
+ * Allocates a new sample buffer.
+ * @param capacity The specified sample capacity of the sample buffer.
+ * @param sampleType The sample type of the samples the buffer should store.
+ * @param byteOrder The byte order for the samples (little or big endian).
+ * @param presentationTimeUs The presentation time for the buffer.
+ * @return A new and empty sample buffer.
+ */
+ public static SampleBuffer allocate(int capacity, @SampleType int sampleType, ByteOrder byteOrder, long presentationTimeUs) {
+ return new SampleBuffer(capacity, sampleType, 1, byteOrder, presentationTimeUs);
+ }
+
+ /**
+ * Allocates a new sample buffer.
+ * @param capacity The specified sample capacity of the sample buffer.
+ * @param sampleType The sample type of the samples the buffer should store.
+ * @param channelCount The number of channels (1 = mono, 2 = stereo).
+ * @param byteOrder The byte order for the samples (little or big endian).
+ * @param presentationTimeUs The presentation time for the buffer.
+ * @return A new and empty sample buffer.
+ */
+ @SuppressWarnings("unused")
+ public static SampleBuffer allocate(int capacity, @SampleType int sampleType, int channelCount, ByteOrder byteOrder, long presentationTimeUs) {
+ return new SampleBuffer(capacity, sampleType, channelCount, byteOrder, presentationTimeUs);
+ }
+
+ private SampleBuffer(int capacity, @SampleType int sampleType, int channelCount, ByteOrder byteOrder, long presentationTimeUs) {
+ this.byteBuffer = ByteBuffer.allocate(sampleType * capacity);
+ this.byteBuffer.order(byteOrder);
+ this.sampleType = sampleType;
+ this.channelCount = channelCount;
+ this.presentationTimeUs = presentationTimeUs;
+ }
+
+ private SampleBuffer(ByteBuffer buffer, @SampleType int sampleType, int channelCount, long presentationTimeUs) {
+ this.byteBuffer = buffer;
+ this.sampleType = sampleType;
+ this.channelCount = channelCount;
+ this.presentationTimeUs = presentationTimeUs;
+ }
+
+ /**
+ * Returns the capacity of the buffer per channel.
+ */
+ @SuppressWarnings("unused")
+ public int capacity() {
+ return byteBuffer.capacity() / sampleType / channelCount;
+ }
+
+ /**
+ * Returns the number of samples in the buffer per channel.
+ */
+ public int limit() {
+ return byteBuffer.limit() / sampleType / channelCount;
+ }
+
+ /**
+ * Sets the number of samples in the buffer to the new limit.
+ * @param newLimit The new limit of the sample buffer.
+ */
+ public void limit(int newLimit) {
+ byteBuffer.limit(newLimit * sampleType * channelCount);
+ }
+
+ /**
+ * Returns the current position in the buffer per channel.
+ * @return The position of the sample buffer.
+ */
+ public int position() {
+ return byteBuffer.position() / sampleType / channelCount;
+ }
+
+ /**
+ *Sets the position of the sample buffer to the new index.
+ * @param newPosition The new position of the sample buffer.
+ */
+ public void position(int newPosition) {
+ byteBuffer.position(newPosition * sampleType * channelCount);
+ }
+
+ /**
+ * Returns the sample of the current position and then increments the position.
+ * The sample returned is a mixed sample getting all samples from each channel.
+ * @return The mixed sample.
+ */
+ public double get() {
+ // convenient method to avoid duplicate code: we use -1 index to call get()
+ return get(-1);
+ }
+
+ /**
+ * Returns the sample from the given index in the buffer.
+ * If the buffer's channel count is > 1 the sample returned
+ * is a mixed sample getting all samples from each channel.
+ * @param index The index of the sample requested.
+ * @return The sample requested.
+ */
+ public double get(int index) {
+ int internalIndex = index * channelCount * sampleType;
+
+ switch (sampleType) {
+ case SampleType.UNSIGNED_8_BIT: {
+ double avg = 0;
+
+ // get a sample mix to mono from the index
+ for (int i = 0; i < channelCount; i++) {
+ byte b = index == -1 ? byteBuffer.get() : byteBuffer.get(internalIndex + i * sampleType);
+ int a = b & 0xff; // convert the 8 bits into int so we can calc > 127
+ avg += a / (double)channelCount;
+ }
+
+ return avg * 2.0 / 255.0 - 1.0; //magic? check out SampleType
+ }
+ case SampleType.SIGNED_16_BIT: {
+ double avg = 0;
+
+ // get a sample mix to mono from the index
+ for (int i = 0; i < channelCount; i++) {
+ short a = index == -1 ? byteBuffer.getShort() : byteBuffer.getShort(internalIndex + i * sampleType);
+ avg += a / (double)channelCount;
+ }
+
+ return (avg + 32768.0) * 2.0 / 65535.0 - 1.0; //magic? check out SampleType
+ }
+ case SampleType.FLOAT: {
+ double avg = 0;
+
+ // get a sample mix to mono from the index
+ for (int i = 0; i < channelCount; i++) {
+ double a = index == -1 ? byteBuffer.getFloat() : byteBuffer.getFloat(internalIndex + i * sampleType);
+ avg += a / (double)channelCount;
+ }
+
+ return avg;
+ }
+ default: {
+ Log.e(TAG, "SampleBuffer.get(int): The sample type is not known: " + sampleType);
+ return 0.0;
+ }
+ }
+ }
+
+ /**
+ * Puts a sample to the current position and increments the position.
+ * @param sample The sample to put into the buffer.
+ */
+ public void put(double sample) {
+ put(-1, sample);
+ }
+
+ /**
+ * Puts a sample to the given index in the buffer.
+ * If the buffer's channel count is > 1 the sample
+ * will be stored in each channel at the given index.
+ * @param index The index to put the sample.
+ * @param sample The sample to store in the buffer.
+ */
+ public void put(int index, double sample) {
+ int internalIndex = index * channelCount * sampleType;
+ switch (sampleType) {
+ case SampleType.UNSIGNED_8_BIT: {
+ int a = (int)Math.round((sample + 1.0) * 255.0 / 2.0); //magic? check out SampleType
+ byte b = (byte)a;
+ if (index == -1) {
+ for (int i = 0; i < channelCount; i++) {
+ byteBuffer.put(b);
+ }
+ } else {
+ for (int i = 0; i < channelCount; i++) {
+ byteBuffer.put(internalIndex + i * sampleType, b);
+ }
+ }
+ break;
+ }
+ case SampleType.SIGNED_16_BIT: {
+ short a = (short)Math.round((sample + 1.0) * 65535 / 2.0 - 32767.0); //magic? check out SampleType
+ if (index == -1) {
+ for (int i = 0; i < channelCount; i++) {
+ byteBuffer.putShort(a);
+ }
+ } else {
+ for (int i = 0; i < channelCount; i++) {
+ byteBuffer.putShort(internalIndex + i * sampleType, a);
+ }
+ }
+ break;
+ }
+ case SampleType.FLOAT: {
+ if (index == -1) {
+ for (int i = 0; i < channelCount; i++) {
+ byteBuffer.putFloat((float) sample);
+ }
+ } else {
+ for (int i = 0; i < channelCount; i++) {
+ byteBuffer.putFloat(internalIndex + i * sampleType, (float) sample);
+ }
+ }
+ break;
+ }
+ default: {
+ Log.e(TAG, "SampleBuffer.set(int): The sample type is not known: " + sampleType);
+ }
+ }
+ }
+
+ /**
+ * Returns the raw byte buffer managed by this sample buffer.
+ * @return The raw byte buffer managed by this sample buffer.
+ */
+ public ByteBuffer getByteBuffer() {
+ return byteBuffer;
+ }
+
+ /**
+ * Returns a copy of the bytes from position 0 to the current limit.
+ * @return A copy of the bytes.
+ */
+ public byte[] getBytes() {
+ int limit = byteBuffer.limit();
+ byte[] bytes = new byte[limit];
+
+ for (int i = 0; i < limit; ++i) {
+ bytes[i] = byteBuffer.get(i);
+ }
+
+ return bytes;
+ }
+
+ /**
+ * The presentation time of this sample buffer.
+ * @return The presentation time of this sample buffer.
+ */
+ public long getPresentationTimeUs() {
+ return presentationTimeUs;
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/file/FileManager.java b/sdl_android/src/main/java/com/smartdevicelink/managers/file/FileManager.java
new file mode 100644
index 000000000..559b74514
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/file/FileManager.java
@@ -0,0 +1,434 @@
+package com.smartdevicelink.managers.file;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.smartdevicelink.managers.BaseSubManager;
+import com.smartdevicelink.managers.CompletionListener;
+import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
+import com.smartdevicelink.managers.file.filetypes.SdlFile;
+import com.smartdevicelink.proxy.RPCRequest;
+import com.smartdevicelink.proxy.RPCResponse;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.rpc.DeleteFile;
+import com.smartdevicelink.proxy.rpc.ListFiles;
+import com.smartdevicelink.proxy.rpc.ListFilesResponse;
+import com.smartdevicelink.proxy.rpc.PutFile;
+import com.smartdevicelink.proxy.rpc.enums.Result;
+import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <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 BaseSubManager {
+
+ private final static String TAG = "FileManager";
+ private List<String> remoteFiles, uploadedEphemeralFileNames;
+ private final WeakReference<Context> context;
+
+ public FileManager(ISdl internalInterface, Context context) {
+
+ // setup
+ super(internalInterface);
+ this.context = new WeakReference<>(context);
+
+ uploadedEphemeralFileNames = new ArrayList<>();
+ }
+
+ @Override
+ public void start(CompletionListener listener) {
+ // prepare manager - don't set state to ready until we have list of files
+ retrieveRemoteFiles();
+ super.start(listener);
+ }
+
+ // GETTERS
+
+ /**
+ * Returns a list of file names currently residing on core
+ * @return List<String> of remote file names
+ */
+ public List<String> getRemoteFileNames() {
+ if (getState() != BaseSubManager.READY){
+ // error and dont return list
+ throw new IllegalArgumentException("FileManager is not READY");
+ }
+ // return list (this is synchronous at this point)
+ return remoteFiles;
+ }
+
+ private void retrieveRemoteFiles(){
+ remoteFiles = new ArrayList<>();
+ // hold list in remoteFiles class var
+ ListFiles listFiles = new ListFiles();
+ listFiles.setOnRPCResponseListener(new OnRPCResponseListener() {
+ @Override
+ public void onResponse(int correlationId, RPCResponse response) {
+ if(response.getSuccess()){
+ if(((ListFilesResponse) response).getFilenames() != null){
+ remoteFiles.addAll(((ListFilesResponse) response).getFilenames());
+ }
+ // on callback set manager to ready state
+ transitionToState(BaseSubManager.READY);
+ }
+ }
+
+ @Override
+ public void onError(int correlationId, Result resultCode, String info) {
+ // file list could not be received
+ transitionToState(BaseSubManager.ERROR);
+ }
+ });
+ internalInterface.sendRPCRequest(listFiles);
+ }
+
+ // DELETION
+
+ /**
+ * Attempts to delete the desired file from core, calls listener with indication of success/failure
+ * @param fileName name of file to be deleted
+ * @param listener callback that is called on response from core
+ */
+ public void deleteRemoteFileWithName(@NonNull final String fileName, final CompletionListener listener){
+ DeleteFile deleteFile = new DeleteFile();
+ deleteFile.setSdlFileName(fileName);
+ deleteFile.setOnRPCResponseListener(new OnRPCResponseListener() {
+ @Override
+ public void onResponse(int correlationId, RPCResponse response) {
+ if(response.getSuccess()){
+ remoteFiles.remove(fileName);
+ uploadedEphemeralFileNames.remove(fileName);
+ }
+ if(listener != null){
+ listener.onComplete(response.getSuccess());
+ }
+ }
+ });
+ internalInterface.sendRPCRequest(deleteFile);
+ }
+
+ /**
+ * Attempts to delete a list of files from core, calls listener with indication of success/failure
+ * @param fileNames list of file names to be deleted
+ * @param listener callback that is called once core responds to all deletion requests
+ */
+ public void deleteRemoteFilesWithNames(@NonNull List<String> fileNames, final MultipleFileCompletionListener listener){
+ if(fileNames.isEmpty()){
+ return;
+ }
+ final List<DeleteFile> deleteFileRequests = new ArrayList<>();
+ for(String fileName : fileNames){
+ DeleteFile deleteFile = new DeleteFile();
+ deleteFile.setSdlFileName(fileName);
+ deleteFileRequests.add(deleteFile);
+ }
+ sendMultipleFileOperations(deleteFileRequests, listener);
+ }
+
+ // UPLOAD FILES / ARTWORK
+
+ /**
+ * 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
+ */
+ private 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.getResourceId() > 0){
+ // Use resource id to upload file
+ byte[] contents = contentsOfResource(file.getResourceId());
+ if(contents != null){
+ putFile.setFileData(contents);
+ }else{
+ throw new IllegalArgumentException("Resource file id was empty");
+ }
+ }else if(file.getUri() != null){
+ // Use URI to upload file
+ byte[] contents = contentsOfUri(file.getUri());
+ if(contents != null){
+ putFile.setFileData(contents);
+ }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;
+ }
+
+ /**
+ * Sends list of provided requests (strictly PutFile or DeleteFile) asynchronously through internalInterface,
+ * calls listener on conclusion of sending requests.
+ * @param requests Non-empty list of PutFile or DeleteFile requests
+ * @param listener MultipleFileCompletionListener that is called upon conclusion of sending requests
+ */
+ private void sendMultipleFileOperations(final List<? extends RPCRequest> requests, final MultipleFileCompletionListener listener){
+ final Map<String, String> errors = new HashMap<>();
+ final SparseArray<String> fileNameMap = new SparseArray<>();
+ final boolean deletionOperation;
+ if(requests.get(0) instanceof PutFile){
+ deletionOperation = false;
+ }else if(requests.get(0) instanceof DeleteFile){
+ deletionOperation = true;
+ }else{
+ return; // requests are not DeleteFile or PutFile
+ }
+ internalInterface.sendRequests(requests, new OnMultipleRequestListener() {
+ int fileNum = 0;
+
+ @Override
+ public void addCorrelationId(int correlationid) {
+ super.addCorrelationId(correlationid);
+ if(deletionOperation){
+ fileNameMap.put(correlationid, ((DeleteFile) requests.get(fileNum++)).getSdlFileName());
+ }else{
+ fileNameMap.put(correlationid, ((PutFile) requests.get(fileNum++)).getSdlFileName());
+ }
+ }
+
+ @Override
+ public void onUpdate(int remainingRequests) {}
+
+ @Override
+ public void onFinished() {
+ if(listener != null) {
+ if (errors.isEmpty()) {
+ listener.onComplete(null);
+ } else {
+ listener.onComplete(errors);
+ }
+ }
+ }
+
+ @Override
+ public void onError(int correlationId, Result resultCode, String info) {
+ if(fileNameMap.get(correlationId) != null){
+ errors.put(fileNameMap.get(correlationId), buildErrorString(resultCode, info));
+ }// else no fileName for given correlation ID
+ }
+
+ @Override
+ public void onResponse(int correlationId, RPCResponse response) {
+ if(response.getSuccess()){
+ if(fileNameMap.get(correlationId) != null){
+ if(deletionOperation){
+ remoteFiles.remove(fileNameMap.get(correlationId));
+ uploadedEphemeralFileNames.remove(fileNameMap.get(correlationId));
+ }else{
+ remoteFiles.add(fileNameMap.get(correlationId));
+ uploadedEphemeralFileNames.add(fileNameMap.get(correlationId));
+ }
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Attempts to upload a SdlFile to core
+ * @param file SdlFile with file name and one of A) fileData, B) Uri, or C) resourceID set
+ * @param listener called when core responds to the attempt to upload the file
+ */
+ public void uploadFile(@NonNull final SdlFile file, final CompletionListener listener){
+ PutFile putFile = createPutFile(file);
+
+ putFile.setOnRPCResponseListener(new OnRPCResponseListener() {
+ @Override
+ public void onResponse(int correlationId, RPCResponse response) {
+ if(response.getSuccess()){
+ remoteFiles.add(file.getName());
+ uploadedEphemeralFileNames.add(file.getName());
+ }
+ if(listener != null){
+ listener.onComplete(response.getSuccess());
+ }
+ }
+
+ @Override
+ public void onError(int correlationId, Result resultCode, String info) {
+ super.onError(correlationId, resultCode, info);
+ if(listener != null){
+ listener.onComplete(false);
+ }
+ }
+ });
+
+ internalInterface.sendRPCRequest(putFile);
+ }
+
+ /**
+ * Attempts to upload a list of SdlFiles to core
+ * @param files list of SdlFiles with file name and one of A) fileData, B) Uri, or C) resourceID set
+ * @param listener callback that is called once core responds to all upload requests
+ */
+ public void uploadFiles(@NonNull List<? extends SdlFile> files, final MultipleFileCompletionListener listener){
+ if(files.isEmpty()){
+ return;
+ }
+ final List<PutFile> putFileRequests = new ArrayList<>();
+ for(SdlFile file : files){
+ putFileRequests.add(createPutFile(file));
+ }
+ sendMultipleFileOperations(putFileRequests, listener);
+ }
+
+ /**
+ * Attempts to upload a SdlArtwork to core
+ * @param file SdlArtwork with file name and one of A) fileData, B) Uri, or C) resourceID set
+ * @param listener called when core responds to the attempt to upload the file
+ */
+ public void uploadArtwork(final SdlArtwork file, final CompletionListener listener){
+ uploadFile(file, listener);
+ }
+
+ /**
+ * Attempts to upload a list of SdlArtworks to core
+ * @param files list of SdlArtworks with file name and one of A) fileData, B) Uri, or C) resourceID set
+ * @param listener callback that is called once core responds to all upload requests
+ */
+ public void uploadArtworks(List<SdlArtwork> files, final MultipleFileCompletionListener listener){
+ uploadFiles(files, listener);
+ }
+
+ /**
+ * Check if an SdlFile has been uploaded to core
+ * @param file SdlFile
+ * @return boolean that tells whether file has been uploaded to core (true) or not (false)
+ */
+ public boolean hasUploadedFile(@NonNull SdlFile file){
+ if(file.isPersistent() && remoteFiles != null && remoteFiles.contains(file.getName())){
+ return true;
+ }else if(!file.isPersistent() && remoteFiles != null && remoteFiles.contains(file.getName())
+ && uploadedEphemeralFileNames.contains(file.getName())){
+ return true;
+ }
+ return false;
+ }
+
+ // HELPERS
+
+ /**
+ * Builds an error string for a given Result and info string
+ * @param resultCode Result
+ * @param info String returned from OnRPCRequestListener.onError()
+ * @return Error string
+ */
+ static public String buildErrorString(Result resultCode, String info){
+ return resultCode.toString() + " : " + info;
+ }
+
+ /**
+ * Helper method to take resource files and turn them into byte arrays
+ * @param resource Resource file id
+ * @return Resulting byte array
+ */
+ private byte[] contentsOfResource(int resource) {
+ InputStream is = null;
+ try {
+ is = context.get().getResources().openRawResource(resource);
+ return contentsOfInputStream(is);
+ } catch (Resources.NotFoundException e) {
+ Log.w(TAG, "Can't read from resource", e);
+ return null;
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * 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 = context.get().getContentResolver().openInputStream(uri);
+ return contentsOfInputStream(is);
+ } catch (IOException e){
+ Log.w(TAG, "Can't read from Uri", e);
+ return null;
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper method to take InputStream and turn it into byte array
+ * @param is valid InputStream
+ * @return Resulting byte array
+ */
+ private byte[] contentsOfInputStream(InputStream is){
+ if(is == null){
+ return null;
+ }
+ try{
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ final int bufferSize = 4096;
+ final byte[] buffer = new byte[bufferSize];
+ int available;
+ while ((available = is.read(buffer)) >= 0) {
+ os.write(buffer, 0, available);
+ }
+ return os.toByteArray();
+ } catch (IOException e){
+ Log.w(TAG, "Can't read from InputStream", e);
+ return null;
+ }
+ }
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/file/MultipleFileCompletionListener.java b/sdl_android/src/main/java/com/smartdevicelink/managers/file/MultipleFileCompletionListener.java
new file mode 100644
index 000000000..803c54f64
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/file/MultipleFileCompletionListener.java
@@ -0,0 +1,14 @@
+package com.smartdevicelink.managers.file;
+
+import java.util.Map;
+
+public interface MultipleFileCompletionListener {
+
+ /**
+ * @param errors - a dictionary (map) property, of type <String: String>, and contains information
+ * on all failed uploads. The key is the name of the file that did not upload properly,
+ * the value is an error String describing what went wrong on that particular upload attempt.
+ * If all files are uploaded successfully, errors is null
+ */
+ void onComplete(Map<String, String> errors);
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java b/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java
new file mode 100644
index 000000000..d888f56ed
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java
@@ -0,0 +1,35 @@
+package com.smartdevicelink.managers.file.filetypes;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.rpc.enums.FileType;
+
+/**
+ * A class that extends SdlFile, representing artwork (JPEG, PNG, or BMP) to be uploaded to core
+ */
+public class SdlArtwork extends SdlFile {
+ public SdlArtwork(){}
+
+ public SdlArtwork(@NonNull String fileName, @NonNull FileType fileType, int id, boolean persistentFile) {
+ super(fileName, fileType, id, persistentFile);
+ }
+
+ public SdlArtwork(@NonNull String fileName, @NonNull FileType fileType, Uri uri, boolean persistentFile) {
+ super(fileName, fileType, uri, persistentFile);
+ }
+
+ public SdlArtwork(@NonNull String fileName, @NonNull FileType fileType, byte[] data, boolean persistentFile) {
+ super(fileName, fileType, data, persistentFile);
+ }
+
+ @Override
+ public void setType(@NonNull FileType fileType) {
+ if(fileType.equals(FileType.GRAPHIC_JPEG) || fileType.equals(FileType.GRAPHIC_PNG)
+ || fileType.equals(FileType.GRAPHIC_BMP)){
+ super.setType(fileType);
+ }else{
+ throw new IllegalArgumentException("Only JPEG, PNG, and BMP image types are supported.");
+ }
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java b/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java
new file mode 100644
index 000000000..ce4cf8285
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java
@@ -0,0 +1,83 @@
+package com.smartdevicelink.managers.file.filetypes;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.rpc.enums.FileType;
+
+/**
+ * A class representing data to be uploaded to core
+ */
+public class SdlFile{
+ private String fileName;
+ private int id = -1;
+ private Uri uri;
+ private byte[] fileData;
+ private FileType fileType;
+ private boolean persistentFile;
+
+ public SdlFile(){}
+
+ public SdlFile(@NonNull String fileName, @NonNull FileType fileType, int id, boolean persistentFile){
+ this.fileName = fileName;
+ this.fileType = fileType;
+ this.id = id;
+ this.persistentFile = persistentFile;
+ }
+
+ public SdlFile(@NonNull String fileName, @NonNull FileType fileType, Uri uri, boolean persistentFile){
+ this.fileName = fileName;
+ this.fileType = fileType;
+ this.uri = uri;
+ this.persistentFile = persistentFile;
+ }
+
+ public SdlFile(@NonNull String fileName, @NonNull FileType fileType, byte[] data, boolean persistentFile){
+ this.fileName = fileName;
+ this.fileType = fileType;
+ this.fileData = data;
+ this.persistentFile = persistentFile;
+ }
+
+ public void setName(@NonNull String fileName){
+ this.fileName = fileName;
+ }
+ public String getName(){
+ return fileName;
+ }
+
+ public void setResourceId(int id){
+ this.id = id;
+ }
+ public int getResourceId(){
+ return id;
+ }
+
+ public void setUri(Uri uri){
+ this.uri = uri;
+ }
+ public Uri getUri(){
+ return uri;
+ }
+
+ public void setFileData(byte[] data){
+ this.fileData = data;
+ }
+ public byte[] getFileData(){
+ return fileData;
+ }
+
+ public void setType(@NonNull FileType fileType){
+ this.fileType = fileType;
+ }
+ public FileType getType(){
+ return fileType;
+ }
+
+ public void setPersistent(boolean persistentFile){
+ this.persistentFile = persistentFile;
+ }
+ public boolean isPersistent(){
+ return this.persistentFile;
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenConfig.java b/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenConfig.java
new file mode 100644
index 000000000..ce571daeb
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenConfig.java
@@ -0,0 +1,114 @@
+package com.smartdevicelink.managers.lockscreen;
+
+/**
+ * <strong>LockScreenConfig</strong> <br>
+ *
+ * This is set during SdlManager instantiation. <br>
+ *
+ * <li> enable - if false, don't worry about the other parameters. You are responsible for creating and managing a lockscreen.
+ * If true, also set the backgroundColor and appIcon if you want. If you don't set the backgroundColor or appIcon, it will use the defaults.</li>
+ *
+ * <li> backgroundColor - if using the default lockscreen, you can set this to a color of your choosing </li>
+ *
+ * <li> appIcon - if using the default lockscreen, you can set your own app icon</li>
+ *
+ * <li> customView - If you would like to provide your own view, you can pass it in here.</li>
+ */
+public class LockScreenConfig {
+
+ private boolean enable, deviceLogo;
+ private int backgroundColor, appIconInt, customViewInt;
+
+ public LockScreenConfig(){
+ // set default values
+ this.enable = true;
+ this.deviceLogo = false;
+ }
+
+ /**
+ * If set to true, SDL will manage the showing and dismissing of the lock screen for you. <br>
+ *
+ * If false, you must manage the lock screen
+ * @param enable boolean
+ */
+ public void setEnabled(boolean enable){
+ this.enable = enable;
+ }
+
+ /**
+ * Gets whether the lock screen is being managed for you
+ * @return boolean
+ */
+ public boolean isEnabled() {
+ return enable;
+ }
+
+ /**
+ * Set the resource int of the background color. Colors should define colors in your Colors.xml file
+ * @param resourceColor resource int of the color
+ */
+ public void setBackgroundColor(int resourceColor){
+ this.backgroundColor = resourceColor;
+ }
+
+ /**
+ * Gets the int reference to the custom lock screen background color
+ * @return the color reference
+ */
+ public int getBackgroundColor() {
+ return backgroundColor;
+ }
+
+ /**
+ * int of the drawable icon.
+ * @param appIconInt the drawable of the icon to be displayed on the lock screen
+ */
+ public void setAppIcon(int appIconInt) {
+ this.appIconInt = appIconInt;
+ }
+
+ /**
+ * Gets the resource reference of the icon to be displayed on the lock screen
+ * @return the icon reference
+ */
+ public int getAppIcon() {
+ return appIconInt;
+ }
+
+ /**
+ * Sets the reference to the custom layout to be used for the lock screen <br>
+ * <strong>If set, the color and icon setters will be ignored</strong>
+ * @param customViewInt the layout
+ */
+ public void setCustomView(int customViewInt) {
+ this.customViewInt = customViewInt;
+ }
+
+ /**
+ * Gets the reference to the custom lockscreen layout to be used
+ * @return the layout reference
+ */
+ public int getCustomView() {
+ return customViewInt;
+ }
+
+ /**
+ * Whether or not to show the device's logo on the default lock screen <br>
+ * The logo will come from the connected hardware, if set by the manufacturer <br>
+ * If using a Custom View, this will be ignored.
+ * @param deviceLogo - boolean
+ */
+ public void showDeviceLogo(boolean deviceLogo) {
+ this.deviceLogo = deviceLogo;
+ }
+
+ /**
+ * Get whether or not the device's Logo is shown on the default lock screen <br>
+ * The logo will come from the connected hardware, if set by the manufacturer <br>
+ * @return deviceLogo - boolean
+ */
+ public boolean isDeviceLogoEnabled() {
+ return deviceLogo;
+ }
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java b/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java
new file mode 100644
index 000000000..4bd2f229f
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java
@@ -0,0 +1,289 @@
+package com.smartdevicelink.managers.lockscreen;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.Build;
+import android.util.Log;
+
+import com.smartdevicelink.managers.BaseSubManager;
+import com.smartdevicelink.managers.CompletionListener;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCNotification;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.rpc.OnDriverDistraction;
+import com.smartdevicelink.proxy.rpc.OnHMIStatus;
+import com.smartdevicelink.proxy.rpc.OnSystemRequest;
+import com.smartdevicelink.proxy.rpc.enums.DriverDistractionState;
+import com.smartdevicelink.proxy.rpc.enums.HMILevel;
+import com.smartdevicelink.proxy.rpc.enums.LockScreenStatus;
+import com.smartdevicelink.proxy.rpc.enums.RequestType;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
+import com.smartdevicelink.util.HttpUtils;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+
+/**
+ * <strong>LockscreenManager</strong> <br>
+ *
+ * Note: This class must be accessed through the SdlManager. Do not instantiate it by itself. <br>
+ *
+ * The LockscreenManager handles the logic of showing and hiding the lock screen. <br>
+ *
+ */
+public class LockScreenManager extends BaseSubManager {
+
+ private static final String TAG = "LockScreenManager";
+ private WeakReference<Context> context;
+ private HMILevel hmiLevel;
+ private OnRPCNotificationListener systemRequestListener, ddListener, hmiListener;
+ private String deviceIconUrl;
+ private boolean driverDistStatus;
+ private volatile boolean isApplicationForegrounded;
+ private android.arch.lifecycle.LifecycleObserver lifecycleObserver;
+ protected boolean lockScreenEnabled, deviceLogoEnabled;
+ protected int lockScreenIcon, lockScreenColor, customView;
+ protected Bitmap deviceLogo;
+
+ public LockScreenManager(LockScreenConfig lockScreenConfig, Context context, ISdl internalInterface){
+
+ super(internalInterface);
+ this.context = new WeakReference<>(context);
+
+ // set initial class variables
+ hmiLevel = HMILevel.HMI_NONE;
+ driverDistStatus = false;
+
+ // setup the manager
+ lockScreenIcon = lockScreenConfig.getAppIcon();
+ lockScreenColor = lockScreenConfig.getBackgroundColor();
+ customView = lockScreenConfig.getCustomView();
+ lockScreenEnabled = lockScreenConfig.isEnabled();
+ deviceLogoEnabled = lockScreenConfig.isDeviceLogoEnabled();
+
+ setupListeners();
+ }
+
+ @Override
+ public void start(CompletionListener listener) {
+ transitionToState(READY);
+ super.start(listener);
+ }
+
+ @Override
+ public void dispose(){
+ // send broadcast to close lock screen if open
+ if (context.get() != null) {
+ context.get().sendBroadcast(new Intent(SDLLockScreenActivity.CLOSE_LOCK_SCREEN_ACTION));
+ }
+ // remove listeners
+ internalInterface.removeOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, hmiListener);
+ internalInterface.removeOnRPCNotificationListener(FunctionID.ON_DRIVER_DISTRACTION, ddListener);
+ if (deviceLogoEnabled) {
+ internalInterface.removeOnRPCNotificationListener(FunctionID.ON_SYSTEM_REQUEST, systemRequestListener);
+ }
+ deviceLogo = null;
+ deviceIconUrl = null;
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ try {
+ if (android.arch.lifecycle.ProcessLifecycleOwner.get() != null && lifecycleObserver != null) {
+ android.arch.lifecycle.ProcessLifecycleOwner.get().getLifecycle().removeObserver(lifecycleObserver);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ lifecycleObserver = null;
+ }
+
+ isApplicationForegrounded = false;
+
+ super.dispose();
+ }
+
+ ////
+ // SETUP
+ ////
+
+ /**
+ * Adds 3 listeners that help determine whether or not a lockscreen should be shown.
+ * This will change the variables that we hold in the manager to the newest values and then
+ * usually call launchLockScreenActivity
+ *
+ * 1. ON_HMI_STATUS
+ * 2. ON_DRIVER_DISTRACTION
+ * 3. ON_SYSTEM_REQUEST (used for device Icon Downloading)
+ */
+ private void setupListeners(){
+ // add hmi listener
+ hmiListener = new OnRPCNotificationListener() {
+ @Override
+ public void onNotified(RPCNotification notification) {
+ hmiLevel = ((OnHMIStatus)notification).getHmiLevel();
+ launchLockScreenActivity();
+ }
+ };
+ internalInterface.addOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, hmiListener);
+
+ // set up driver distraction listener
+ ddListener = new OnRPCNotificationListener() {
+ @Override
+ public void onNotified(RPCNotification notification) {
+ // do something with the status
+ if (notification != null) {
+ OnDriverDistraction ddState = (OnDriverDistraction) notification;
+
+ if (ddState.getState() == DriverDistractionState.DD_ON){
+ // launch lock screen
+ driverDistStatus = true;
+ launchLockScreenActivity();
+ }else{
+ // close lock screen
+ driverDistStatus = false;
+ if (context.get() != null) {
+ context.get().sendBroadcast(new Intent(SDLLockScreenActivity.CLOSE_LOCK_SCREEN_ACTION));
+ }
+ }
+ }
+ }
+ };
+ internalInterface.addOnRPCNotificationListener(FunctionID.ON_DRIVER_DISTRACTION, ddListener);
+
+ // set up system request listener
+ if (deviceLogoEnabled) {
+ systemRequestListener = new OnRPCNotificationListener() {
+ @Override
+ public void onNotified(RPCNotification notification) {
+ // do something with the status
+ final OnSystemRequest msg = (OnSystemRequest) notification;
+ if (msg.getRequestType() == RequestType.LOCK_SCREEN_ICON_URL &&
+ msg.getUrl() != null) {
+ // send intent to activity to download icon from core
+ deviceIconUrl = msg.getUrl();
+ downloadDeviceIcon(deviceIconUrl);
+ }
+ }
+ };
+ internalInterface.addOnRPCNotificationListener(FunctionID.ON_SYSTEM_REQUEST, systemRequestListener);
+ }
+
+ // Set up listener for Application Foreground / Background events
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ try {
+ lifecycleObserver = new android.arch.lifecycle.LifecycleObserver() {
+ @android.arch.lifecycle.OnLifecycleEvent(android.arch.lifecycle.Lifecycle.Event.ON_START)
+ public void onMoveToForeground() {
+ isApplicationForegrounded = true;
+ launchLockScreenActivity();
+ }
+
+ @android.arch.lifecycle.OnLifecycleEvent(android.arch.lifecycle.Lifecycle.Event.ON_STOP)
+ public void onMoveToBackground() {
+ isApplicationForegrounded = false;
+ }
+ };
+
+ if (android.arch.lifecycle.ProcessLifecycleOwner.get() != null) {
+ android.arch.lifecycle.ProcessLifecycleOwner.get().getLifecycle().addObserver(lifecycleObserver);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else{
+ isApplicationForegrounded = true;
+ }
+ }
+
+ ////
+ // LAUNCH LOCK SCREEN LOGIC
+ ////
+
+ /**
+ * 1. Check if user wants us to manage lock screen
+ * 2. If so, get the HMI level and LockScreenStatus from the method below
+ * 3. Build intent and start the SDLLockScreenActivity
+ *
+ * X. If the status is set to OFF, Send broadcast to close lock screen if it is open
+ */
+ private void launchLockScreenActivity(){
+ // intent to open SDLLockScreenActivity
+ // pass in icon, background color, and custom view
+ if (lockScreenEnabled && isApplicationForegrounded && context.get() != null) {
+ LockScreenStatus status = getLockScreenStatus();
+ if (status == LockScreenStatus.REQUIRED) {
+ Intent showLockScreenIntent = new Intent(context.get(), SDLLockScreenActivity.class);
+ showLockScreenIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // Extra parameters for customization of the lock screen view
+ showLockScreenIntent.putExtra(SDLLockScreenActivity.LOCKSCREEN_ICON_EXTRA, lockScreenIcon);
+ showLockScreenIntent.putExtra(SDLLockScreenActivity.LOCKSCREEN_COLOR_EXTRA, lockScreenColor);
+ showLockScreenIntent.putExtra(SDLLockScreenActivity.LOCKSCREEN_CUSTOM_VIEW_EXTRA, customView);
+ showLockScreenIntent.putExtra(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_EXTRA, deviceLogoEnabled);
+ showLockScreenIntent.putExtra(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_BITMAP, deviceLogo);
+ context.get().startActivity(showLockScreenIntent);
+ } else if (status == LockScreenStatus.OFF) {
+ context.get().sendBroadcast(new Intent(SDLLockScreenActivity.CLOSE_LOCK_SCREEN_ACTION));
+ }
+ }
+ }
+
+ ////
+ // HELPERS
+ ////
+
+ /**
+ * Step through some logic to determine if we need to show the lock screen or not
+ * This function is usually triggered on some sort of notification.
+ *
+ * @return Whether or not the Lock Screen is required
+ */
+ protected synchronized LockScreenStatus getLockScreenStatus() {
+
+ if ( (hmiLevel == null) || (hmiLevel.equals(HMILevel.HMI_NONE))) {
+ return LockScreenStatus.OFF;
+ }
+ else if ( hmiLevel.equals(HMILevel.HMI_BACKGROUND)) {
+ if (!driverDistStatus) {
+ //we don't have driver distraction, lock screen is entirely based on if user is using the app on the head unit
+ return LockScreenStatus.OFF;
+ } else {
+ return LockScreenStatus.REQUIRED;
+ }
+ }
+ else if ( (hmiLevel.equals(HMILevel.HMI_FULL)) || (hmiLevel.equals(HMILevel.HMI_LIMITED))) {
+ if (!driverDistStatus) {
+ return LockScreenStatus.OPTIONAL;
+ } else {
+ return LockScreenStatus.REQUIRED;
+ }
+ }
+ return LockScreenStatus.OFF;
+ }
+
+ private void downloadDeviceIcon(final String url){
+
+ if (deviceLogo != null || context.get() == null){
+ return;
+ }
+
+ new Thread(new Runnable(){
+ @Override
+ public void run(){
+ try{
+ deviceLogo = HttpUtils.downloadImage(url);
+ Intent intent = new Intent(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_DOWNLOADED);
+ intent.putExtra(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_EXTRA, deviceLogoEnabled);
+ intent.putExtra(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_BITMAP, deviceLogo);
+ if (context.get() != null) {
+ context.get().sendBroadcast(intent);
+ }
+ }catch(IOException e){
+ Log.e(TAG, "device Icon Error Downloading");
+ }
+ }
+ }).start();
+ }
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/SDLLockScreenActivity.java b/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/SDLLockScreenActivity.java
new file mode 100644
index 000000000..b99cc0d05
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/SDLLockScreenActivity.java
@@ -0,0 +1,130 @@
+package com.smartdevicelink.managers.lockscreen;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Bitmap;
+
+import android.os.Bundle;
+import android.view.Window;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+
+import com.smartdevicelink.R;
+
+public class SDLLockScreenActivity extends Activity {
+
+ private static final String TAG = "SDLLockScreenActivity";
+ public static final String LOCKSCREEN_COLOR_EXTRA = "LOCKSCREEN_COLOR_EXTRA";
+ public static final String LOCKSCREEN_ICON_EXTRA = "LOCKSCREEN_ICON_EXTRA";
+ public static final String LOCKSCREEN_DEVICE_LOGO_EXTRA = "LOCKSCREEN_DEVICE_LOGO_EXTRA";
+ public static final String LOCKSCREEN_DEVICE_LOGO_BITMAP = "LOCKSCREEN_DEVICE_LOGO_BITMAP";
+ public static final String LOCKSCREEN_CUSTOM_VIEW_EXTRA = "LOCKSCREEN_CUSTOM_VIEW_EXTRA";
+ public static final String LOCKSCREEN_DEVICE_LOGO_DOWNLOADED = "LOCKSCREEN_DEVICE_LOGO_DOWNLOADED";
+ public static final String CLOSE_LOCK_SCREEN_ACTION = "CLOSE_LOCK_SCREEN";
+
+ private final BroadcastReceiver lockScreenBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent != null){
+ String action = intent.getAction();
+ if (action != null){
+ if (action.equalsIgnoreCase(CLOSE_LOCK_SCREEN_ACTION)){
+ finish();
+ } else if (action.equalsIgnoreCase(LOCKSCREEN_DEVICE_LOGO_DOWNLOADED)){
+ boolean deviceLogoEnabled = intent.getBooleanExtra(LOCKSCREEN_DEVICE_LOGO_EXTRA, true);
+ Bitmap deviceLogo = intent.getParcelableExtra(LOCKSCREEN_DEVICE_LOGO_BITMAP);
+ if (deviceLogoEnabled && deviceLogo != null){
+ setDeviceLogo(deviceLogo);
+ }
+ }
+ }
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ this.requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ // set any parameters that came from the lock screen manager
+ initializeActivity(getIntent());
+
+ // create intent filter
+ IntentFilter lockscreenFilter = new IntentFilter();
+ lockscreenFilter.addAction(CLOSE_LOCK_SCREEN_ACTION);
+ lockscreenFilter.addAction(LOCKSCREEN_DEVICE_LOGO_DOWNLOADED);
+
+ // register broadcast receivers
+ registerReceiver(lockScreenBroadcastReceiver, lockscreenFilter);
+ }
+
+ @Override
+ protected void onDestroy() {
+ unregisterReceiver(lockScreenBroadcastReceiver);
+ super.onDestroy();
+ }
+
+ @Override
+ public void onBackPressed() {
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
+ }
+
+ public void initializeActivity(Intent intent){
+ if (intent != null){
+ boolean deviceLogoEnabled = intent.getBooleanExtra(LOCKSCREEN_DEVICE_LOGO_EXTRA, true);
+ int customColor = intent.getIntExtra(LOCKSCREEN_COLOR_EXTRA, 0);
+ int customIcon = intent.getIntExtra(LOCKSCREEN_ICON_EXTRA, 0);
+ int customView = intent.getIntExtra(LOCKSCREEN_CUSTOM_VIEW_EXTRA, 0);
+ Bitmap deviceIcon = intent.getParcelableExtra(LOCKSCREEN_DEVICE_LOGO_BITMAP);
+
+ if (customView != 0){
+ setCustomView(customView);
+ } else {
+ setContentView(R.layout.activity_sdllock_screen);
+
+ if (customColor != 0){
+ changeBackgroundColor(customColor);
+ }
+
+ if (customIcon != 0){
+ changeIcon(customIcon);
+ }
+
+ if (deviceLogoEnabled && deviceIcon != null){
+ setDeviceLogo(deviceIcon);
+ }
+ }
+ }
+ }
+
+ private void changeBackgroundColor(int customColor) {
+ RelativeLayout layout = findViewById(R.id.lockscreen_relative_layout);
+ layout.setBackgroundColor(getResources().getColor(customColor));
+ }
+
+ private void changeIcon(int customIcon) {
+ ImageView lockscreen_iv = findViewById(R.id.lockscreen_image);
+ lockscreen_iv.setBackgroundResource(customIcon);
+ }
+
+ private void setDeviceLogo(Bitmap deviceLogo) {
+ ImageView device_iv = findViewById(R.id.device_image);
+ if (deviceLogo != null) {
+ device_iv.setImageBitmap(deviceLogo);
+ }
+ }
+
+ private void setCustomView(int customView) {
+ setContentView(customView);
+ }
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/permission/OnPermissionChangeListener.java b/sdl_android/src/main/java/com/smartdevicelink/managers/permission/OnPermissionChangeListener.java
new file mode 100644
index 000000000..45035b91a
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/permission/OnPermissionChangeListener.java
@@ -0,0 +1,20 @@
+package com.smartdevicelink.managers.permission;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.protocol.enums.FunctionID;
+
+import java.util.Map;
+
+/**
+ * OnPermissionChangeListener is a listener which includes a callback method that can be called when there are permission changes
+ */
+public interface OnPermissionChangeListener {
+ /**
+ * Call back method that PermissionManager will call to inform the developer about permission changes
+ * @param allowedPermissions an overall view about the status of the permissions
+ * @param permissionGroupStatus a detailed view about which permissions are allowed and which ones are not
+ * @see com.smartdevicelink.managers.permission.PermissionManager.PermissionGroupStatus
+ */
+ void onPermissionsChange(@NonNull Map<FunctionID, PermissionStatus> allowedPermissions, @NonNull @PermissionManager.PermissionGroupStatus int permissionGroupStatus);
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionElement.java b/sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionElement.java
new file mode 100644
index 000000000..edb3788b6
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionElement.java
@@ -0,0 +1,42 @@
+package com.smartdevicelink.managers.permission;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.protocol.enums.FunctionID;
+
+import java.util.List;
+
+/**
+ * PermissionElement holds the RPC name that the developer wants to add a listener for.
+ * It also holds any permission parameters for that RPC that the developer wants to track as well.
+ */
+public class PermissionElement {
+ private final FunctionID rpcName;
+ private final List<String> parameters;
+
+ /**
+ * Create a new instance of PermissionElement
+ * @param rpcName
+ * @param parameters
+ */
+ public PermissionElement(@NonNull FunctionID rpcName, List<String> parameters){
+ this.rpcName = rpcName;
+ this.parameters = parameters;
+ }
+
+ /**
+ * Get the RPC name
+ * @return FunctionID value represents the RPC name
+ */
+ public FunctionID getRPCName() {
+ return rpcName;
+ }
+
+ /**
+ * Get the permission parameters for the RPC
+ * @return List<String> represents the permission parameters for the RPC
+ */
+ public List<String> getParameters() {
+ return parameters;
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionFilter.java b/sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionFilter.java
new file mode 100644
index 000000000..de7aab01a
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionFilter.java
@@ -0,0 +1,70 @@
+package com.smartdevicelink.managers.permission;
+
+import android.support.annotation.NonNull;
+
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * PermissionFilter holds all the required information for a specific OnPermissionChangeListener
+ */
+class PermissionFilter {
+ private final UUID identifier;
+ private final List<PermissionElement> permissionElements;
+ private final int groupType;
+ private final OnPermissionChangeListener listener;
+
+ /**
+ * Creates a new instance of PermissionFilter
+ * @param identifier
+ * @param permissionElements
+ * @param groupType
+ * @param listener
+ * @see com.smartdevicelink.managers.permission.PermissionManager.PermissionGroupType
+ */
+ PermissionFilter(UUID identifier, @NonNull List<PermissionElement> permissionElements, @NonNull @PermissionManager.PermissionGroupType int groupType, @NonNull OnPermissionChangeListener listener) {
+ if (identifier == null) {
+ this.identifier = UUID.randomUUID();
+ } else {
+ this.identifier = identifier;
+ }
+ this.permissionElements = permissionElements;
+ this.groupType = groupType;
+ this.listener = listener;
+ }
+
+ /**
+ * Get the unique id for the listener
+ * @return UUID object represents the id for the listener
+ */
+ protected UUID getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ * Get the permission elements that the developer wants to add a listener for
+ * @return List<PermissionElement> represents the RPCs and their parameters that the developer wants to add a listener for
+ */
+ protected List<PermissionElement> getPermissionElements() {
+ return permissionElements;
+ }
+
+ /**
+ * Get how we want the listener to be called: when any change happens? or when all permissions become allowed?
+ * @return PermissionGroupType int value represents whether the developer needs the listener to be called when there is any permissions change or only when all permission become allowed
+ * @see com.smartdevicelink.managers.permission.PermissionManager.PermissionGroupType
+ */
+ protected @PermissionManager.PermissionGroupType int getGroupType() {
+ return groupType;
+ }
+
+ /**
+ * Get the listener object
+ * @return OnPermissionChangeListener object represents the listener for that filter
+ */
+ protected OnPermissionChangeListener getListener() {
+ return listener;
+ }
+
+
+} \ No newline at end of file
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionManager.java b/sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionManager.java
new file mode 100644
index 000000000..0c0ea2b6e
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionManager.java
@@ -0,0 +1,350 @@
+package com.smartdevicelink.managers.permission;
+
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.managers.BaseSubManager;
+import com.smartdevicelink.managers.CompletionListener;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCNotification;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.rpc.OnHMIStatus;
+import com.smartdevicelink.proxy.rpc.OnPermissionsChange;
+import com.smartdevicelink.proxy.rpc.PermissionItem;
+import com.smartdevicelink.proxy.rpc.enums.HMILevel;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ 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 BaseSubManager{
+
+ private HMILevel currentHMILevel;
+ private Map<FunctionID, PermissionItem> currentPermissionItems;
+ private OnRPCNotificationListener onHMIStatusListener, onPermissionsChangeListener;
+ private List<PermissionFilter> filters;
+
+ // Permission groups status constants
+ @IntDef({PERMISSION_GROUP_STATUS_ALLOWED, PERMISSION_GROUP_STATUS_DISALLOWED,
+ PERMISSION_GROUP_STATUS_MIXED, PERMISSION_GROUP_STATUS_UNKNOWN})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PermissionGroupStatus {}
+ public static final int PERMISSION_GROUP_STATUS_ALLOWED = 0; // Every permission in the group is currently allowed
+ public static final int PERMISSION_GROUP_STATUS_DISALLOWED = 1; // Every permission in the group is currently disallowed
+ public static final int PERMISSION_GROUP_STATUS_MIXED = 2; // Some permissions in the group are allowed and some disallowed
+ public static final int PERMISSION_GROUP_STATUS_UNKNOWN = 3; // The current status of the group is unknown
+
+ // Permission groups type constants
+ @IntDef({PERMISSION_GROUP_TYPE_ALL_ALLOWED, PERMISSION_GROUP_TYPE_ANY})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PermissionGroupType {}
+ public static final int PERMISSION_GROUP_TYPE_ALL_ALLOWED = 0; // Be notified when all of the permission in the group are allowed, or, when they all stop being allowed in some sense, that is, when they were all allowed, and now they are not.
+ public static final int PERMISSION_GROUP_TYPE_ANY = 1; // Be notified when any change in availability occurs among the group
+
+ /**
+ * Creates a new instance of the PermissionManager
+ * @param internalInterface
+ */
+ public PermissionManager(@NonNull ISdl internalInterface){
+ super(internalInterface);
+ this.currentPermissionItems = new HashMap<>();
+ this.filters = new ArrayList<>();
+
+ // Set PermissionManager's OnHMIStatusListener to keep currentHMILevel updated and call developer's listeners if needed
+ onHMIStatusListener = new OnRPCNotificationListener() {
+ @Override
+ public void onNotified(RPCNotification notification) {
+ HMILevel previousHMILevel = currentHMILevel;
+ currentHMILevel = ((OnHMIStatus)notification).getHmiLevel();
+ checkState();
+ notifyListeners(currentPermissionItems, previousHMILevel, currentPermissionItems, currentHMILevel);
+ }
+ };
+ internalInterface.addOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, onHMIStatusListener);
+
+ // Set PermissionManager's PermissionsChangeListener to keep currentPermissionItems updated and call developer's listeners if needed
+ onPermissionsChangeListener = new OnRPCNotificationListener() {
+ @Override
+ public void onNotified(RPCNotification notification) {
+ List<PermissionItem> permissionItems = ((OnPermissionsChange)notification).getPermissionItem();
+ Map<FunctionID, PermissionItem> previousPermissionItems = currentPermissionItems;
+ currentPermissionItems = new HashMap<>();
+ for (PermissionItem permissionItem : permissionItems) {
+ currentPermissionItems.put(FunctionID.getEnumForString(permissionItem.getRpcName()), permissionItem);
+ }
+ notifyListeners(previousPermissionItems, currentHMILevel, currentPermissionItems, currentHMILevel);
+ previousPermissionItems.clear();
+ }
+ };
+ internalInterface.addOnRPCNotificationListener(FunctionID.ON_PERMISSIONS_CHANGE, onPermissionsChangeListener);
+ }
+
+ @Override
+ public void start(CompletionListener listener) {
+ checkState();
+ super.start(listener);
+ }
+
+ private synchronized void checkState(){
+ if(this.getState() == SETTING_UP && currentHMILevel != null){
+ transitionToState(READY);
+ }
+ }
+
+ /**
+ * Go over all developer's listeners and call them if needed because of HMI level change or permission items change
+ * @param previousPermissionItems
+ * @param previousHmiLevel
+ * @param currentPermissionItems
+ * @param currentHMILevel
+ */
+ private void notifyListeners(Map<FunctionID, PermissionItem> previousPermissionItems, HMILevel previousHmiLevel, Map<FunctionID, PermissionItem> currentPermissionItems, HMILevel currentHMILevel){
+ for (PermissionFilter filter : filters) {
+ boolean anyChange = false;
+ boolean allWereAllowed = true;
+ boolean allNowAllowed = true;
+ for (PermissionElement permissionElement : filter.getPermissionElements()) {
+ // If at any point this condition is satisfied, then we don't need to continue
+ if (anyChange && !allWereAllowed && !allNowAllowed){
+ break;
+ }
+ boolean rpcWasAllowed = isRPCAllowed(permissionElement.getRPCName(), previousPermissionItems, previousHmiLevel);
+ boolean rpcNowAllowed = isRPCAllowed(permissionElement.getRPCName(), currentPermissionItems, currentHMILevel);
+ if (rpcWasAllowed != rpcNowAllowed){
+ anyChange = true;
+ }
+ if (!rpcWasAllowed){
+ allWereAllowed = false;
+ }
+ if (!rpcNowAllowed){
+ allNowAllowed = false;
+ }
+ if (permissionElement.getParameters() != null && permissionElement.getParameters().size() > 0) {
+ for (String parameter : permissionElement.getParameters()) {
+ boolean parameterWasAllowed = isPermissionParameterAllowed(permissionElement.getRPCName(), parameter, previousPermissionItems, previousHmiLevel);
+ boolean parameterNowAllowed = isPermissionParameterAllowed(permissionElement.getRPCName(), parameter, currentPermissionItems, currentHMILevel);
+ if (parameterWasAllowed != parameterNowAllowed){
+ anyChange = true;
+ }
+ if (!parameterWasAllowed){
+ allWereAllowed = false;
+ }
+ if (!parameterNowAllowed){
+ allNowAllowed = false;
+ }
+ }
+ }
+ }
+ if (filter.getGroupType() == PERMISSION_GROUP_TYPE_ALL_ALLOWED && anyChange && (allWereAllowed || allNowAllowed)){
+ notifyListener(filter);
+ } else if (filter.getGroupType() == PERMISSION_GROUP_TYPE_ANY && anyChange){
+ notifyListener(filter);
+ }
+ }
+ }
+
+ /**
+ * Determine if an individual RPC is allowed
+ * @param rpcName FunctionID value that represents the name of the RPC
+ * @param permissionItems Map containing HMI and parameter permissions for a specific RPC
+ * @param hmiLevel If the RPC is allowed at that HMI Level. Ex: None or Full
+ * @return boolean represents whether the RPC is allowed or not
+ */
+ private boolean isRPCAllowed(@NonNull FunctionID rpcName, Map<FunctionID, PermissionItem> permissionItems, HMILevel hmiLevel){
+ PermissionItem permissionItem = permissionItems.get(rpcName);
+ if (hmiLevel == null || permissionItem == null || permissionItem.getHMIPermissions() == null || permissionItem.getHMIPermissions().getAllowed() == null){
+ return false;
+ } else if (permissionItem.getHMIPermissions().getUserDisallowed() != null){
+ return permissionItem.getHMIPermissions().getAllowed().contains(hmiLevel) && !permissionItem.getHMIPermissions().getUserDisallowed().contains(hmiLevel);
+ } else {
+ return permissionItem.getHMIPermissions().getAllowed().contains(hmiLevel);
+ }
+ }
+
+ /**
+ * Determine if an individual RPC is allowed for the current permission items and HMI level
+ * @param rpcName rpcName FunctionID value that represents the name of the RPC
+ * @return boolean represents whether the RPC is allowed or not
+ */
+ @SuppressWarnings("WeakerAccess")
+ public boolean isRPCAllowed(@NonNull FunctionID rpcName){
+ return isRPCAllowed(rpcName, currentPermissionItems, currentHMILevel);
+ }
+
+ /**
+ * Determine if an individual permission parameter is allowed
+ * @param rpcName FunctionID value that represents the name of the RPC
+ * @param parameter String value that represents a parameter for the RPC. Ex: "rpm" or "speed" for GetVehicleData
+ * @param permissionItems Map containing HMI and parameter permissions for a specific RPC
+ * @param hmiLevel If the RPC is allowed at that HMI Level. Ex: None or Full
+ * @return boolean represents whether the permission parameter is allowed or not
+ */
+ private boolean isPermissionParameterAllowed(@NonNull FunctionID rpcName, @NonNull String parameter, Map<FunctionID, PermissionItem> permissionItems, HMILevel hmiLevel){
+ PermissionItem permissionItem = permissionItems.get(rpcName);
+ if (!isRPCAllowed(rpcName, permissionItems, hmiLevel) || permissionItem.getParameterPermissions() == null || permissionItem.getParameterPermissions().getAllowed() == null){
+ return false;
+ } else if (permissionItem.getParameterPermissions().getUserDisallowed() != null){
+ return permissionItem.getParameterPermissions().getAllowed().contains(parameter) && !permissionItem.getParameterPermissions().getUserDisallowed().contains(parameter);
+ } else {
+ return permissionItem.getParameterPermissions().getAllowed().contains(parameter);
+ }
+ }
+
+ /**
+ * Determine if an individual permission parameter is allowed for current permission items and current HMI level
+ * @param rpcName FunctionID value that represents the name of the RPC
+ * @param parameter String value that represents a parameter for the RPC
+ * @return boolean represents whether the permission parameter is allowed or not
+ */
+ @SuppressWarnings("WeakerAccess")
+ public boolean isPermissionParameterAllowed(@NonNull FunctionID rpcName, @NonNull String parameter){
+ return isPermissionParameterAllowed(rpcName, parameter, currentPermissionItems, currentHMILevel);
+ }
+
+ /**
+ * Clean up everything after the manager is no longer needed
+ */
+ @Override
+ public void dispose(){
+ super.dispose();
+
+ // Remove onHMIStatusListener
+ internalInterface.removeOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, onHMIStatusListener);
+ onHMIStatusListener = null;
+
+ // Remove onPermissionsChangeListener
+ internalInterface.removeOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, onPermissionsChangeListener);
+ onPermissionsChangeListener = null;
+
+ // Remove developer's listeners
+ filters.clear();
+ }
+
+ /**
+ * Determine if a group of permissions is allowed for the current HMI level
+ * @param permissionElements list of PermissionElement that represents the RPC names and their parameters
+ * @return PermissionGroupStatus int value that gives an overall view whether the permissions are allowed or not
+ * @see PermissionGroupStatus
+ */
+ @SuppressWarnings("WeakerAccess")
+ public @PermissionGroupStatus int getGroupStatusOfPermissions(@NonNull List<PermissionElement> permissionElements){
+ if (currentHMILevel == null){
+ return PERMISSION_GROUP_STATUS_UNKNOWN;
+ }
+
+ boolean hasAllowed = false;
+ boolean hasDisallowed = false;
+
+ for (PermissionElement permissionElement : permissionElements) {
+ // If at any point, we have both allowed and disallowed permissions, return the mixed result
+ if (hasAllowed && hasDisallowed) {
+ return PERMISSION_GROUP_STATUS_MIXED;
+ }
+
+ if (permissionElement == null){
+ continue;
+ } else if (!isRPCAllowed(permissionElement.getRPCName())){
+ hasDisallowed = true;
+ } else {
+ if (permissionElement.getParameters() == null || permissionElement.getParameters().size() == 0){
+ hasAllowed = true;
+ } else {
+ for (String permissionParameter : permissionElement.getParameters()) {
+ if (isPermissionParameterAllowed(permissionElement.getRPCName(), permissionParameter)) {
+ hasAllowed = true;
+ } else {
+ hasDisallowed = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (!hasAllowed && !hasDisallowed){
+ return PERMISSION_GROUP_STATUS_ALLOWED;
+ } else if (hasAllowed && hasDisallowed) {
+ return PERMISSION_GROUP_STATUS_MIXED;
+ } else if (hasAllowed) {
+ return PERMISSION_GROUP_STATUS_ALLOWED;
+ } else{
+ return PERMISSION_GROUP_STATUS_DISALLOWED;
+ }
+ }
+
+ /**
+ * Determine if a group of permissions is allowed for the current HMI level
+ * This method is similar to getGroupStatusOfPermissions() but returns more detailed result about each individual permission
+ * @param permissionElements list of PermissionElement that represents the RPC names and their parameters
+ * @return a map with keys that are the passed in RPC names specifying if that RPC and its parameter permissions are currently allowed for the current HMI level
+ */
+ @SuppressWarnings("WeakerAccess")
+ public Map <FunctionID, PermissionStatus> getStatusOfPermissions(@NonNull List<PermissionElement> permissionElements){
+ Map<FunctionID, PermissionStatus> statusOfPermissions = new HashMap<>();
+ for (PermissionElement permissionElement : permissionElements) {
+ if (permissionElement == null){
+ continue;
+ }
+ Map<String, Boolean> allowedParameters = null;
+ if (permissionElement.getParameters() != null && permissionElement.getParameters().size() > 0) {
+ allowedParameters = new HashMap<>();
+ for (String permissionParameter : permissionElement.getParameters()) {
+ allowedParameters.put(permissionParameter, isPermissionParameterAllowed(permissionElement.getRPCName(), permissionParameter));
+ }
+ }
+ PermissionStatus permissionStatus = new PermissionStatus(permissionElement.getRPCName(), isRPCAllowed(permissionElement.getRPCName()), allowedParameters);
+ statusOfPermissions.put(permissionElement.getRPCName(), permissionStatus);
+ }
+ return statusOfPermissions;
+ }
+
+ /**
+ * Call the listener for a specific filter
+ * @param filter the permission filter to cal
+ */
+ private void notifyListener(@NonNull PermissionFilter filter){
+ int permissionGroupStatus = getGroupStatusOfPermissions(filter.getPermissionElements());
+ Map <FunctionID, PermissionStatus> allowedPermissions = getStatusOfPermissions(filter.getPermissionElements());
+ filter.getListener().onPermissionsChange(allowedPermissions, permissionGroupStatus);
+ }
+
+ /**
+ * Add a listener to be called when there is permissions change
+ * @param permissionElements list of PermissionElement that represents the RPC names and their parameters
+ * @param groupType PermissionGroupType int value represents whether we need the listener to be called when there is any permissions change or only when all permission become allowed
+ * @param listener OnPermissionChangeListener interface
+ * @return unique uuid number for the listener. It can be used to remove the listener later.
+ */
+ @SuppressWarnings({"WeakerAccess", "UnusedReturnValue"})
+ public UUID addListener(@NonNull List<PermissionElement> permissionElements, @PermissionGroupType int groupType, @NonNull OnPermissionChangeListener listener){
+ PermissionFilter filter = new PermissionFilter(null, permissionElements, groupType, listener);
+ filters.add(filter);
+ return filter.getIdentifier();
+ }
+
+ /**
+ * Removes specific listener
+ * @param listenerId the id of the listener
+ */
+ @SuppressWarnings("WeakerAccess")
+ public void removeListener(@NonNull UUID listenerId){
+ for (PermissionFilter filter : filters) {
+ if (filter.getIdentifier().equals(listenerId)) {
+ filters.remove(filter);
+ break;
+ }
+ }
+ }
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionStatus.java b/sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionStatus.java
new file mode 100644
index 000000000..11f464552
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/permission/PermissionStatus.java
@@ -0,0 +1,68 @@
+package com.smartdevicelink.managers.permission;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.protocol.enums.FunctionID;
+
+import java.util.Map;
+
+/**
+ * PermissionStatus gives a detailed view about whether an RPC and its permission parameters are allowed or not
+ */
+public class PermissionStatus {
+ private final FunctionID rpcName;
+ private boolean isRPCAllowed;
+ private Map<String, Boolean> allowedParameters;
+
+ /**
+ * Creates a new PermissionStatus instance
+ * @param rpcName
+ * @param isRPCAllowed
+ * @param allowedParameters
+ */
+ public PermissionStatus(@NonNull FunctionID rpcName, @NonNull boolean isRPCAllowed, Map<String, Boolean> allowedParameters) {
+ this.rpcName = rpcName;
+ this.isRPCAllowed = isRPCAllowed;
+ this.allowedParameters = allowedParameters;
+ }
+
+ /**
+ * Get the name of the RPC
+ * @return FunctionID value represents the name of the RPC
+ */
+ public FunctionID getRPCName() {
+ return rpcName;
+ }
+
+ /**
+ * Get whether the RCP is allowed or not
+ * @return boolean represents whether the RCP is allowed or not
+ */
+ public boolean getIsRPCAllowed() {
+ return isRPCAllowed;
+ }
+
+ /**
+ * Set whether the RPC is allowed or not
+ * @param isRPCAllowed
+ */
+ protected void setIsRPCAllowed(@NonNull boolean isRPCAllowed) {
+ this.isRPCAllowed = isRPCAllowed;
+ }
+
+ /**
+ * Get the status of the permission parameter for the RPC
+ * @return Map<String, Boolean> object with keys that represent the permission parameter names and values that represent whether the parameters are allowed or not
+ */
+ public Map<String, Boolean> getAllowedParameters() {
+ return allowedParameters;
+ }
+
+ /**
+ * Set the status of the permission parameter for the RPC
+ * @param allowedParameters
+ */
+ protected void setAllowedParameters(Map<String, Boolean> allowedParameters) {
+ this.allowedParameters = allowedParameters;
+ }
+} \ No newline at end of file
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/screen/ScreenManager.java b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/ScreenManager.java
new file mode 100644
index 000000000..5372cc72c
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/ScreenManager.java
@@ -0,0 +1,361 @@
+package com.smartdevicelink.managers.screen;
+
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import com.smartdevicelink.managers.BaseSubManager;
+import com.smartdevicelink.managers.CompletionListener;
+import com.smartdevicelink.managers.file.FileManager;
+import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.rpc.SetDisplayLayout;
+import com.smartdevicelink.proxy.rpc.enums.MetadataType;
+import com.smartdevicelink.proxy.rpc.enums.PredefinedLayout;
+import com.smartdevicelink.proxy.rpc.enums.TextAlignment;
+import com.smartdevicelink.util.DebugTool;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+
+/**
+ * <strong>ScreenManager</strong> <br>
+ *
+ * Note: This class must be accessed through the SdlManager. Do not instantiate it by itself. <br>
+*/
+public class ScreenManager extends BaseSubManager {
+
+ private static String TAG = "ScreenManager";
+ private final WeakReference<FileManager> fileManager;
+ private SoftButtonManager softButtonManager;
+ private TextAndGraphicManager textAndGraphicManager;
+
+ // Sub manager listener
+ private final CompletionListener subManagerListener = new CompletionListener() {
+ @Override
+ public synchronized void onComplete(boolean success) {
+ if (softButtonManager != null && textAndGraphicManager != null) {
+ if (softButtonManager.getState() == BaseSubManager.READY && textAndGraphicManager.getState() == BaseSubManager.READY) {
+ DebugTool.logInfo("Starting screen manager, all sub managers are in ready state");
+ transitionToState(READY);
+ } else if (softButtonManager.getState() == BaseSubManager.ERROR && textAndGraphicManager.getState() == BaseSubManager.ERROR) {
+ Log.e(TAG, "ERROR starting screen manager, both sub managers in error state");
+ transitionToState(ERROR);
+ } else if (textAndGraphicManager.getState() == BaseSubManager.SETTING_UP || softButtonManager.getState() == BaseSubManager.SETTING_UP) {
+ DebugTool.logInfo("SETTING UP screen manager, one sub manager is still setting up");
+ transitionToState(SETTING_UP);
+ } else {
+ Log.w(TAG, "LIMITED starting screen manager, one sub manager in error state and the other is ready");
+ transitionToState(LIMITED);
+ }
+ } else {
+ // We should never be here, but somehow one of the sub-sub managers is null
+ Log.e(TAG, "ERROR one of the screen sub managers is null");
+ transitionToState(ERROR);
+ }
+ }
+ };
+
+ public ScreenManager(@NonNull ISdl internalInterface, @NonNull FileManager fileManager) {
+ super(internalInterface);
+ this.fileManager = new WeakReference<>(fileManager);
+ initialize();
+ }
+
+ @Override
+ public void start(CompletionListener listener) {
+ super.start(listener);
+ }
+
+ private void initialize(){
+ if (fileManager.get() != null) {
+ this.softButtonManager = new SoftButtonManager(internalInterface, fileManager.get());
+ this.textAndGraphicManager = new TextAndGraphicManager(internalInterface, fileManager.get(), softButtonManager);
+ this.softButtonManager.start(subManagerListener);
+ this.textAndGraphicManager.start(subManagerListener);
+ }
+ }
+
+ /**
+ * <p>Called when manager is being torn down</p>
+ */
+ @Override
+ public void dispose() {
+ softButtonManager.dispose();
+ textAndGraphicManager.dispose();
+ super.dispose();
+ }
+
+ /**
+ * Set the textField1 on the head unit screen
+ * Sending an empty String "" will clear the field
+ * @param textField1 String value represents the textField1
+ */
+ public void setTextField1(String textField1) {
+ this.softButtonManager.setCurrentMainField1(textField1);
+ this.textAndGraphicManager.setTextField1(textField1);
+ }
+
+ /**
+ * Get the current textField1 value
+ * @return a String value represents the current textField1 value
+ */
+ public String getTextField1() {
+ return this.textAndGraphicManager.getTextField1();
+ }
+
+ /**
+ * Set the textField2 on the head unit screen
+ * Sending an empty String "" will clear the field
+ * @param textField2 String value represents the textField1
+ */
+ public void setTextField2(String textField2) {
+ this.textAndGraphicManager.setTextField2(textField2);
+ }
+
+ /**
+ * Get the current textField2 value
+ * @return a String value represents the current textField2 value
+ */
+ public String getTextField2() {
+ return this.textAndGraphicManager.getTextField2();
+ }
+
+ /**
+ * Set the textField3 on the head unit screen
+ * Sending an empty String "" will clear the field
+ * @param textField3 String value represents the textField1
+ */
+ public void setTextField3(String textField3) {
+ this.textAndGraphicManager.setTextField3(textField3);
+ }
+
+ /**
+ * Get the current textField3 value
+ * @return a String value represents the current textField3 value
+ */
+ public String getTextField3() {
+ return this.textAndGraphicManager.getTextField3();
+ }
+
+ /**
+ * Set the textField4 on the head unit screen
+ * Sending an empty String "" will clear the field
+ * @param textField4 String value represents the textField1
+ */
+ public void setTextField4(String textField4) {
+ this.textAndGraphicManager.setTextField4(textField4);
+ }
+
+ /**
+ * Get the current textField4 value
+ * @return a String value represents the current textField4 value
+ */
+ public String getTextField4() {
+ return this.textAndGraphicManager.getTextField4();
+ }
+
+ /**
+ * Set the mediaTrackTextField on the head unit screen
+ * @param mediaTrackTextField String value represents the mediaTrackTextField
+ */
+ public void setMediaTrackTextField(String mediaTrackTextField) {
+ this.textAndGraphicManager.setMediaTrackTextField(mediaTrackTextField);
+ }
+
+ /**
+ * Get the current mediaTrackTextField value
+ * @return a String value represents the current mediaTrackTextField
+ */
+ public String getMediaTrackTextField() {
+ return this.textAndGraphicManager.getMediaTrackTextField();
+ }
+
+ /**
+ * Set the primaryGraphic on the head unit screen
+ * @param primaryGraphic an SdlArtwork object represents the primaryGraphic
+ */
+ public void setPrimaryGraphic(SdlArtwork primaryGraphic) {
+ if (primaryGraphic == null){
+ primaryGraphic = textAndGraphicManager.getBlankArtwork();
+ }
+ this.textAndGraphicManager.setPrimaryGraphic(primaryGraphic);
+ }
+
+ /**
+ * Get the current primaryGraphic value
+ * @return an SdlArtwork object represents the current primaryGraphic
+ */
+ public SdlArtwork getPrimaryGraphic() {
+ return this.textAndGraphicManager.getPrimaryGraphic();
+ }
+
+ /**
+ * Set the secondaryGraphic on the head unit screen
+ * @param secondaryGraphic an SdlArtwork object represents the secondaryGraphic
+ */
+ public void setSecondaryGraphic(SdlArtwork secondaryGraphic) {
+ if (secondaryGraphic == null){
+ secondaryGraphic = textAndGraphicManager.getBlankArtwork();
+ }
+ this.textAndGraphicManager.setSecondaryGraphic(secondaryGraphic);
+ }
+
+ /**
+ * Get the current secondaryGraphic value
+ * @return an SdlArtwork object represents the current secondaryGraphic
+ */
+ public SdlArtwork getSecondaryGraphic() {
+ return this.textAndGraphicManager.getSecondaryGraphic();
+ }
+
+ /**
+ * Set the alignment for the text fields
+ * @param textAlignment TextAlignment value represents the alignment for the text fields
+ */
+ public void setTextAlignment(TextAlignment textAlignment) {
+ this.textAndGraphicManager.setTextAlignment(textAlignment);
+ }
+
+ /**
+ * Get the alignment for the text fields
+ * @return a TextAlignment value represents the alignment for the text fields
+ */
+ public TextAlignment getTextAlignment() {
+ return this.textAndGraphicManager.getTextAlignment();
+ }
+
+ /**
+ * Set the metadata type for the textField1
+ * @param textField1Type a MetadataType value represents the metadata for textField1
+ */
+ public void setTextField1Type(MetadataType textField1Type) {
+ this.textAndGraphicManager.setTextField1Type(textField1Type);
+ }
+
+ /**
+ * Get the metadata type for textField1
+ * @return a MetadataType value represents the metadata for textField1
+ */
+ public MetadataType getTextField1Type() {
+ return this.textAndGraphicManager.getTextField1Type();
+ }
+
+ /**
+ * Set the metadata type for the textField2
+ * @param textField2Type a MetadataType value represents the metadata for textField2
+ */
+ public void setTextField2Type(MetadataType textField2Type) {
+ this.textAndGraphicManager.setTextField2Type(textField2Type);
+ }
+
+ /**
+ * Get the metadata type for textField2
+ * @return a MetadataType value represents the metadata for textField2
+ */
+ public MetadataType getTextField2Type() {
+ return this.textAndGraphicManager.getTextField2Type();
+ }
+
+ /**
+ * Set the metadata type for the textField3
+ * @param textField3Type a MetadataType value represents the metadata for textField3
+ */
+ public void setTextField3Type(MetadataType textField3Type) {
+ this.textAndGraphicManager.setTextField3Type(textField3Type);
+ }
+
+ /**
+ * Get the metadata type for textField3
+ * @return a MetadataType value represents the metadata for textField3
+ */
+ public MetadataType getTextField3Type() {
+ return this.textAndGraphicManager.getTextField3Type();
+ }
+
+ /**
+ * Set the metadata type for the textField4
+ * @param textField4Type a MetadataType value represents the metadata for textField4
+ */
+ public void setTextField4Type(MetadataType textField4Type) {
+ this.textAndGraphicManager.setTextField4Type(textField4Type);
+ }
+
+ /**
+ * Get the metadata type for textField4
+ * @return a MetadataType value represents the metadata for textField4
+ */
+ public MetadataType getTextField4Type() {
+ return this.textAndGraphicManager.getTextField4Type();
+ }
+
+ /**
+ * Set softButtonObjects list and upload the images to the head unit
+ * @param softButtonObjects the list of the SoftButtonObject values that should be displayed on the head unit
+ */
+ public void setSoftButtonObjects(@NonNull List<SoftButtonObject> softButtonObjects) {
+ softButtonManager.setSoftButtonObjects(softButtonObjects);
+ }
+
+ /**
+ * Get the soft button objects list
+ * @return a List<SoftButtonObject>
+ */
+ public List<SoftButtonObject> getSoftButtonObjects() {
+ return softButtonManager.getSoftButtonObjects();
+ }
+
+ /**
+ * Get the SoftButtonObject that has the provided name
+ * @param name a String value that represents the name
+ * @return a SoftButtonObject
+ */
+ public SoftButtonObject getSoftButtonObjectByName(@NonNull String name){
+ return softButtonManager.getSoftButtonObjectByName(name);
+ }
+
+ /**
+ * Get the SoftButtonObject that has the provided buttonId
+ * @param buttonId a int value that represents the id of the button
+ * @return a SoftButtonObject
+ */
+ public SoftButtonObject getSoftButtonObjectById(int buttonId){
+ return softButtonManager.getSoftButtonObjectById(buttonId);
+ }
+
+ /**
+ * Begin a multiple updates transaction. The updates will be applied when commit() is called<br>
+ * Note: if we don't use beginTransaction & commit, every update will be sent individually.
+ */
+ public void beginTransaction(){
+ softButtonManager.setBatchUpdates(true);
+ textAndGraphicManager.setBatchUpdates(true);
+ }
+
+ /**
+ * Send the updates that were started after beginning the transaction
+ * @param listener a CompletionListener that has a callback that will be called when the updates are finished
+ */
+ public void commit(final CompletionListener listener){
+ softButtonManager.setBatchUpdates(false);
+ softButtonManager.update(new CompletionListener() {
+ boolean updateSuccessful = true;
+ @Override
+ public void onComplete(boolean success) {
+ if (!success){
+ updateSuccessful = false;
+ }
+ textAndGraphicManager.setBatchUpdates(false);
+ textAndGraphicManager.update(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ if (!success){
+ updateSuccessful = false;
+ }
+ listener.onComplete(updateSuccessful);
+ }
+ });
+ }
+ });
+ }
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java
new file mode 100644
index 000000000..f995231eb
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonManager.java
@@ -0,0 +1,568 @@
+package com.smartdevicelink.managers.screen;
+
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import com.smartdevicelink.managers.BaseSubManager;
+import com.smartdevicelink.managers.CompletionListener;
+import com.smartdevicelink.managers.file.FileManager;
+import com.smartdevicelink.managers.file.MultipleFileCompletionListener;
+import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCNotification;
+import com.smartdevicelink.proxy.RPCResponse;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.interfaces.OnSystemCapabilityListener;
+import com.smartdevicelink.proxy.rpc.DisplayCapabilities;
+import com.smartdevicelink.proxy.rpc.OnButtonEvent;
+import com.smartdevicelink.proxy.rpc.OnButtonPress;
+import com.smartdevicelink.proxy.rpc.OnHMIStatus;
+import com.smartdevicelink.proxy.rpc.Show;
+import com.smartdevicelink.proxy.rpc.SoftButton;
+import com.smartdevicelink.proxy.rpc.SoftButtonCapabilities;
+import com.smartdevicelink.proxy.rpc.enums.ButtonName;
+import com.smartdevicelink.proxy.rpc.enums.HMILevel;
+import com.smartdevicelink.proxy.rpc.enums.Result;
+import com.smartdevicelink.proxy.rpc.enums.SoftButtonType;
+import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener;
+import com.smartdevicelink.util.DebugTool;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * <strong>SoftButtonManager</strong> <br>
+ * SoftButtonManager gives the developer the ability to control how soft buttons are displayed on the head unit.<br>
+ * Note: This class must be accessed through the SdlManager->ScreenManager. Do not instantiate it by itself.<br>
+ */
+class SoftButtonManager extends BaseSubManager {
+
+ private static final String TAG = "SoftButtonManager";
+ private WeakReference<FileManager> fileManager;
+ private DisplayCapabilities displayCapabilities;
+ private SoftButtonCapabilities softButtonCapabilities;
+ private CopyOnWriteArrayList<SoftButtonObject> softButtonObjects;
+ private HMILevel currentHMILevel;
+ private Show inProgressShowRPC;
+ private CompletionListener inProgressListener, queuedUpdateListener, cachedListener;
+ private boolean hasQueuedUpdate, batchUpdates, waitingOnHMILevelUpdateToSetButtons;
+ private final OnSystemCapabilityListener onSoftButtonCapabilitiesListener, onDisplayCapabilitiesListener;
+ private final OnRPCNotificationListener onHMIStatusListener, onButtonPressListener, onButtonEventListener;
+ private final SoftButtonObject.UpdateListener updateListener;
+
+ /**
+ * HAX: This is necessary due to a Ford Sync 3 bug that doesn't like Show requests without a main field being set (it will accept them, but with a GENERIC_ERROR, and 10-15 seconds late...)
+ */
+ private String currentMainField1;
+
+
+ /**
+ * Creates a new instance of the SoftButtonManager
+ * @param internalInterface
+ * @param fileManager
+ */
+ SoftButtonManager(@NonNull ISdl internalInterface, @NonNull FileManager fileManager) {
+ super(internalInterface);
+ this.fileManager = new WeakReference<>(fileManager);
+ this.softButtonObjects = new CopyOnWriteArrayList<>();
+ this.currentHMILevel = HMILevel.HMI_NONE; // Assume NONE until we get something else
+ this.waitingOnHMILevelUpdateToSetButtons = false;
+ this.updateListener = new SoftButtonObject.UpdateListener() {
+ @Override
+ public void onUpdate() {
+ update(null);
+ }
+ };
+
+
+ // Add OnSoftButtonCapabilitiesListener to keep softButtonCapabilities updated
+ onSoftButtonCapabilitiesListener = new OnSystemCapabilityListener() {
+ @Override
+ public void onCapabilityRetrieved(Object capability) {
+ List<SoftButtonCapabilities> softButtonCapabilitiesList = (List<SoftButtonCapabilities>) capability;
+ if (softButtonCapabilitiesList != null && !softButtonCapabilitiesList.isEmpty()) {
+ softButtonCapabilities = softButtonCapabilitiesList.get(0);
+ } else {
+ softButtonCapabilities = null;
+ }
+ }
+
+ @Override
+ public void onError(String info) {
+ Log.w(TAG, "SoftButton Capability cannot be retrieved:");
+ softButtonCapabilities = null;
+ }
+ };
+ this.internalInterface.addOnSystemCapabilityListener(SystemCapabilityType.SOFTBUTTON, onSoftButtonCapabilitiesListener);
+
+
+ // Add OnDisplayCapabilitiesListener to keep displayCapabilities updated
+ onDisplayCapabilitiesListener = new OnSystemCapabilityListener() {
+ @Override
+ public void onCapabilityRetrieved(Object capability) {
+ displayCapabilities = (DisplayCapabilities) capability;
+ }
+
+ @Override
+ public void onError(String info) {
+ Log.w(TAG, "Display Capability cannot be retrieved:");
+ displayCapabilities = null;
+ }
+ };
+ this.internalInterface.addOnSystemCapabilityListener(SystemCapabilityType.DISPLAY, onDisplayCapabilitiesListener);
+
+
+ // Add OnHMIStatusListener to keep currentHMILevel updated
+ this.onHMIStatusListener = new OnRPCNotificationListener() {
+ @Override
+ public void onNotified(RPCNotification notification) {
+
+ OnHMIStatus onHMIStatus = (OnHMIStatus) notification;
+ HMILevel oldHmiLevel = currentHMILevel;
+ currentHMILevel = onHMIStatus.getHmiLevel();
+
+
+ // Auto-send an updated show if we were in NONE and now we are not
+ if (oldHmiLevel == HMILevel.HMI_NONE && currentHMILevel != HMILevel.HMI_NONE) {
+ if (waitingOnHMILevelUpdateToSetButtons) {
+ setSoftButtonObjects(softButtonObjects);
+ } else {
+ update(cachedListener);
+ }
+ }
+ }
+ };
+ this.internalInterface.addOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, onHMIStatusListener);
+
+
+ // Add OnButtonPressListener to notify SoftButtonObjects when there is a button press
+ this.onButtonPressListener = new OnRPCNotificationListener() {
+ @Override
+ public void onNotified(RPCNotification notification) {
+ OnButtonPress onButtonPress = (OnButtonPress) notification;
+ if (onButtonPress!= null && onButtonPress.getButtonName() == ButtonName.CUSTOM_BUTTON) {
+ Integer buttonId = onButtonPress.getCustomButtonName();
+ if (getSoftButtonObjects() != null) {
+ for (SoftButtonObject softButtonObject : getSoftButtonObjects()) {
+ if (softButtonObject.getButtonId() == buttonId && softButtonObject.getOnEventListener() != null) {
+ softButtonObject.getOnEventListener().onPress(getSoftButtonObjectById(buttonId), onButtonPress);
+ break;
+ }
+ }
+ }
+ }
+ }
+ };
+ this.internalInterface.addOnRPCNotificationListener(FunctionID.ON_BUTTON_PRESS, onButtonPressListener);
+
+
+ // Add OnButtonEventListener to notify SoftButtonObjects when there is a button event
+ this.onButtonEventListener = new OnRPCNotificationListener() {
+ @Override
+ public void onNotified(RPCNotification notification) {
+ OnButtonEvent onButtonEvent = (OnButtonEvent) notification;
+ if (onButtonEvent!= null && onButtonEvent.getButtonName() == ButtonName.CUSTOM_BUTTON) {
+ Integer buttonId = onButtonEvent.getCustomButtonID();
+ if (getSoftButtonObjects() != null) {
+ for (SoftButtonObject softButtonObject : getSoftButtonObjects()) {
+ if (softButtonObject.getButtonId() == buttonId && softButtonObject.getOnEventListener() != null) {
+ softButtonObject.getOnEventListener().onEvent(getSoftButtonObjectById(buttonId), onButtonEvent);
+ break;
+ }
+ }
+ }
+ }
+ }
+ };
+ this.internalInterface.addOnRPCNotificationListener(FunctionID.ON_BUTTON_EVENT, onButtonEventListener);
+ }
+
+ @Override
+ public void start(CompletionListener listener) {
+ transitionToState(READY);
+ super.start(listener);
+ }
+
+ /**
+ * Get the SoftButtonObject that has the provided name
+ * @param name a String value that represents the name
+ * @return a SoftButtonObject
+ */
+ protected SoftButtonObject getSoftButtonObjectByName(String name) {
+ for (SoftButtonObject softButtonObject : softButtonObjects) {
+ if (softButtonObject.getName().equals(name)) {
+ return softButtonObject;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the SoftButtonObject that has the provided buttonId
+ * @param buttonId a int value that represents the id of the button
+ * @return a SoftButtonObject
+ */
+ protected SoftButtonObject getSoftButtonObjectById(int buttonId) {
+ for (SoftButtonObject softButtonObject : softButtonObjects) {
+ if (softButtonObject.getButtonId() == buttonId) {
+ return softButtonObject;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the soft button objects list
+ * @return a List<SoftButtonObject>
+ */
+ protected List<SoftButtonObject> getSoftButtonObjects() {
+ return softButtonObjects;
+ }
+
+ /**
+ * Set softButtonObjects list and upload the images to the head unit
+ * @param list the list of the SoftButtonObject values that should be displayed on the head unit
+ */
+ protected void setSoftButtonObjects(@NonNull List<SoftButtonObject> list) {
+ // Convert the List to CopyOnWriteArrayList
+ CopyOnWriteArrayList<SoftButtonObject> softButtonObjects;
+ if(list instanceof CopyOnWriteArrayList){
+ softButtonObjects = (CopyOnWriteArrayList<SoftButtonObject>) list;
+ }else{
+ softButtonObjects = new CopyOnWriteArrayList<>(list);
+ }
+
+
+ if (hasTwoSoftButtonObjectsOfSameName(softButtonObjects)) {
+ this.softButtonObjects = new CopyOnWriteArrayList<>();
+ Log.e(TAG, "Attempted to set soft button objects, but two buttons had the same name");
+ return;
+ }
+
+ // Set ids and updateListeners for soft button objects
+ for (int i = 0; i < softButtonObjects.size(); i++) {
+ softButtonObjects.get(i).setButtonId(i * 100);
+ softButtonObjects.get(i).setUpdateListener(updateListener);
+ }
+ this.softButtonObjects = softButtonObjects;
+
+
+ if (currentHMILevel == null || currentHMILevel == HMILevel.HMI_NONE) {
+ waitingOnHMILevelUpdateToSetButtons = true;
+ return;
+ }
+
+
+ // End any in-progress update
+ inProgressShowRPC = null;
+ if (inProgressListener != null) {
+ inProgressListener.onComplete(false);
+ inProgressListener = null;
+ }
+
+
+ // End any queued update
+ hasQueuedUpdate = false;
+ if (queuedUpdateListener != null) {
+ queuedUpdateListener.onComplete(false);
+ queuedUpdateListener = null;
+ }
+
+
+ // Prepare soft button images to be uploaded to the head unit.
+ // we will prepare a list for initial state images and another list for other state images
+ // so we can upload the initial state images first, then the other states images.
+ List<SdlArtwork> initialStatesToBeUploaded = new ArrayList<>();
+ List<SdlArtwork> otherStatesToBeUploaded = new ArrayList<>();
+ if (softButtonImagesSupported() && fileManager.get() != null) {
+ for (SoftButtonObject softButtonObject : softButtonObjects) {
+ SoftButtonState initialState = null;
+ if (softButtonObject != null) {
+ initialState = softButtonObject.getCurrentState();
+ }
+ if (initialState != null && softButtonObject.getStates() != null) {
+ for (SoftButtonState softButtonState : softButtonObject.getStates()) {
+ if (softButtonState != null && softButtonState.getName() != null && softButtonState.getArtwork() != null && !fileManager.get().hasUploadedFile(softButtonState.getArtwork())) {
+ if (softButtonState.getName().equals(initialState.getName())) {
+ initialStatesToBeUploaded.add(softButtonObject.getCurrentState().getArtwork());
+ } else{
+ otherStatesToBeUploaded.add(softButtonState.getArtwork());
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ // Upload initial state images
+ if (initialStatesToBeUploaded.size() > 0 && fileManager.get() != null) {
+ DebugTool.logInfo( "Uploading soft button initial state artworks");
+ fileManager.get().uploadArtworks(initialStatesToBeUploaded, new MultipleFileCompletionListener() {
+ @Override
+ public void onComplete(Map<String, String> errors) {
+ if (errors != null && errors.size() > 0) {
+ Log.e(TAG, "Error uploading soft button artworks");
+ }
+ DebugTool.logInfo( "Soft button initial artworks uploaded");
+ update(cachedListener);
+ }
+ });
+ }
+
+
+ // Upload other state images
+ if (otherStatesToBeUploaded.size() > 0 && fileManager.get() != null) {
+ DebugTool.logInfo("Uploading soft button other state artworks");
+ fileManager.get().uploadArtworks(otherStatesToBeUploaded, new MultipleFileCompletionListener() {
+ @Override
+ public void onComplete(Map<String, String> errors) {
+ if (errors != null && errors.size() > 0) {
+ Log.e(TAG, "Error uploading soft button artworks");
+ }
+ DebugTool.logInfo("Soft button other state artworks uploaded");
+ // In case our soft button states have changed in the meantime
+ update(cachedListener);
+ }
+ });
+ }
+
+ // This is necessary because there may be no images needed to be uploaded
+ update(cachedListener);
+ }
+
+ /**
+ * Update the SoftButtonManger by sending a new Show RPC to reflect the changes
+ * @param listener a CompletionListener
+ */
+ protected void update(CompletionListener listener) {
+ cachedListener = listener;
+
+ if (batchUpdates) {
+ return;
+ }
+
+ // Don't send if we're in HMI NONE
+ if (currentHMILevel == null || currentHMILevel == HMILevel.HMI_NONE) {
+ return;
+ }
+
+ DebugTool.logInfo("Updating soft buttons");
+
+ cachedListener = null;
+
+
+ // Check if we have update already in progress
+ if (inProgressShowRPC != null) {
+ DebugTool.logInfo("In progress update exists, queueing update");
+ // If we already have a pending update, we're going to tell the old listener that it was superseded by a new update and then return
+ if (queuedUpdateListener != null) {
+ DebugTool.logInfo("Queued update already exists, superseding previous queued update");
+ queuedUpdateListener.onComplete(false);
+ queuedUpdateListener = null;
+ }
+
+ // Note: the queued update will be started after the in-progress one finishes
+ if (listener != null) {
+ queuedUpdateListener = listener;
+ }
+ hasQueuedUpdate = true;
+ return;
+ }
+
+
+ // Send Show RPC with soft buttons representing the current state for the soft button objects
+ inProgressListener = listener;
+ inProgressShowRPC = new Show();
+ inProgressShowRPC.setMainField1(getCurrentMainField1());
+ if (softButtonObjects == null) {
+ DebugTool.logInfo("Soft button objects are null, sending an empty array");
+ inProgressShowRPC.setSoftButtons(new ArrayList<SoftButton>());
+ } else if ((currentStateHasImages() && !allCurrentStateImagesAreUploaded()) || !softButtonImagesSupported()) {
+ // The images don't yet exist on the head unit, or we cannot use images, send a text update if possible, otherwise, don't send anything yet
+ List<SoftButton> textOnlySoftButtons = createTextSoftButtonsForCurrentState();
+ if (textOnlySoftButtons != null) {
+ DebugTool.logInfo( "Soft button images unavailable, sending text buttons");
+ inProgressShowRPC.setSoftButtons(textOnlySoftButtons);
+
+ } else {
+ DebugTool.logInfo( "Soft button images unavailable, text buttons unavailable");
+ inProgressShowRPC = null;
+ return;
+ }
+
+ } else {
+ DebugTool.logInfo( "Sending soft buttons with images");
+ inProgressShowRPC.setSoftButtons(createSoftButtonsForCurrentState());
+ }
+
+
+ inProgressShowRPC.setOnRPCResponseListener(new OnRPCResponseListener() {
+ @Override
+ public void onResponse(int correlationId, RPCResponse response) {
+ DebugTool.logInfo("Soft button update completed");
+ handleResponse(true);
+ }
+
+ @Override
+ public void onError(int correlationId, Result resultCode, String info) {
+ super.onError(correlationId, resultCode, info);
+
+ Log.e(TAG, "Soft button update error");
+ handleResponse(false);
+
+ }
+
+ private void handleResponse(boolean success){
+
+ inProgressShowRPC = null;
+ CompletionListener currentListener;
+ if (inProgressListener != null) {
+ currentListener = inProgressListener;
+ inProgressListener = null;
+ currentListener.onComplete(success);
+ }
+
+
+ if (hasQueuedUpdate) {
+ DebugTool.logInfo("Queued update exists, sending another update");
+ currentListener = queuedUpdateListener;
+ queuedUpdateListener = null;
+ hasQueuedUpdate = false;
+ update(currentListener);
+ }
+ }
+ });
+
+
+ internalInterface.sendRPCRequest(inProgressShowRPC);
+ }
+
+ private boolean softButtonImagesSupported(){
+ return (displayCapabilities == null || displayCapabilities.getGraphicSupported()) && (softButtonCapabilities == null || softButtonCapabilities.getImageSupported());
+ }
+
+ /**
+ * Check if two SoftButtonObject have the same name
+ * @param softButtonObjects
+ * @return a boolean value
+ */
+ private boolean hasTwoSoftButtonObjectsOfSameName(List<SoftButtonObject> softButtonObjects) {
+ for (int i = 0; i < softButtonObjects.size(); i++) {
+ String buttonName = softButtonObjects.get(i).getName();
+ for (int j = (i + 1); j < softButtonObjects.size(); j++) {
+ if (softButtonObjects.get(j).getName().equals(buttonName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get the TextField1
+ * @return currentMainField1
+ */
+ protected String getCurrentMainField1() {
+ if (currentMainField1 == null){
+ return "";
+ }
+ return currentMainField1;
+ }
+
+ /**
+ * Set the TextField1
+ * @param currentMainField1
+ */
+ protected void setCurrentMainField1(String currentMainField1) {
+ this.currentMainField1 = currentMainField1;
+ }
+
+ /**
+ * Set the batchUpdates flag that represents whether the manager should wait until commit() is called to send the updated show RPC
+ * @param batchUpdates
+ */
+ protected void setBatchUpdates(boolean batchUpdates) {
+ this.batchUpdates = batchUpdates;
+ }
+
+ /**
+ * Clean up everything after the manager is no longer needed
+ */
+ @Override
+ public void dispose() {
+ super.dispose();
+
+ // Remove listeners
+ internalInterface.removeOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, onHMIStatusListener);
+ internalInterface.removeOnRPCNotificationListener(FunctionID.ON_BUTTON_PRESS, onButtonPressListener);
+ internalInterface.removeOnRPCNotificationListener(FunctionID.ON_BUTTON_EVENT, onButtonEventListener);
+ internalInterface.removeOnSystemCapabilityListener(SystemCapabilityType.SOFTBUTTON, onSoftButtonCapabilitiesListener);
+ internalInterface.removeOnSystemCapabilityListener(SystemCapabilityType.DISPLAY, onDisplayCapabilitiesListener);
+ }
+
+ /**
+ * Check if the current state for any SoftButtonObject has images
+ * @return a boolean value
+ */
+ private boolean currentStateHasImages() {
+ for (SoftButtonObject softButtonObject : this.softButtonObjects) {
+ if (softButtonObject.getCurrentState() != null && softButtonObject.getCurrentState().getArtwork() != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if the current state for any SoftButtonObject has images that are not uploaded yet
+ * @return a boolean value
+ */
+ private boolean allCurrentStateImagesAreUploaded() {
+ if (fileManager.get() != null) {
+ for (SoftButtonObject softButtonObject : softButtonObjects) {
+ SoftButtonState currentState = softButtonObject.getCurrentState();
+ if (currentState != null && currentState.getArtwork() != null && !fileManager.get().hasUploadedFile(currentState.getArtwork())) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns text soft buttons representing the initial states of the button objects, or null if _any_ of the buttons' current states are image only buttons.
+ * @return The text soft buttons
+ */
+ private List<SoftButton> createTextSoftButtonsForCurrentState() {
+ List<SoftButton> textButtons = new ArrayList<>();
+ for (SoftButtonObject softButtonObject : softButtonObjects) {
+ SoftButton softButton = softButtonObject.getCurrentStateSoftButton();
+ if (softButton.getText() == null) {
+ return null;
+ }
+ // We should create a new softButtonObject rather than modifying the original one
+ SoftButton textOnlySoftButton = new SoftButton(SoftButtonType.SBT_TEXT, softButton.getSoftButtonID());
+ textOnlySoftButton.setText(softButton.getText());
+ textButtons.add(textOnlySoftButton);
+ }
+ return textButtons;
+ }
+
+ /**
+ * Returns a list of the SoftButton for the SoftButtonObjects' current state
+ * @return a List<SoftButton>
+ */
+ protected List<SoftButton> createSoftButtonsForCurrentState() {
+ List<SoftButton> softButtons = new ArrayList<>();
+ for (SoftButtonObject softButtonObject : softButtonObjects) {
+ softButtons.add(softButtonObject.getCurrentStateSoftButton());
+ }
+ return softButtons;
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonObject.java b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonObject.java
new file mode 100644
index 000000000..01c760d09
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonObject.java
@@ -0,0 +1,272 @@
+package com.smartdevicelink.managers.screen;
+
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import com.smartdevicelink.proxy.rpc.OnButtonEvent;
+import com.smartdevicelink.proxy.rpc.OnButtonPress;
+import com.smartdevicelink.proxy.rpc.SoftButton;
+import com.smartdevicelink.util.DebugTool;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * <strong>SoftButtonObject</strong> <br>
+ * SoftButtonObject define a button that can have multiple SoftButtonState values.<br>
+ * The states of SoftButtonObject allow the developer to not have to manage multiple SoftButtons that have very similar functionality.<br>
+ * For example, a repeat button in a music app can be thought of as one SoftButtonObject with three typical states: repeat off, repeat 1, and repeat on.<br>
+ * @see SoftButtonState
+ */
+public class SoftButtonObject {
+
+ private static final String TAG = "SoftButtonObject";
+ private String name;
+ private List<SoftButtonState> states;
+ private String currentStateName;
+ private int buttonId;
+ private OnEventListener onEventListener;
+ private UpdateListener updateListener;
+
+ /**
+ * Create a new instance of the SoftButtonObject with multiple states
+ * @param name a String value represents name of the object
+ * @param states a list of SoftButtonState represents the SoftButtonState values for the object
+ * @param initialStateName a String value represents the name for the initial state
+ * @param onEventListener a listener that has a callback that will be triggered when a button event happens
+ * Note: the initialStateName should match exactly the name of one of the states for the object. Otherwise an exception will be thrown.
+ */
+ public SoftButtonObject(@NonNull String name, @NonNull List<SoftButtonState> states, @NonNull String initialStateName, OnEventListener onEventListener) {
+
+ // Make sure there aren't two states with the same name
+ if (hasTwoStatesOfSameName(states)) {
+ Log.e(TAG, "Two states have the same name in states list for soft button object");
+ return;
+ }
+
+ this.name = name;
+ this.states = states;
+ currentStateName = initialStateName;
+ this.buttonId = 0;
+ this.onEventListener = onEventListener;
+ }
+
+ /**
+ * Create a new instance of the SoftButtonObject with one state
+ * @param name a String value represents name of the object
+ * @param state a SoftButtonState represents state for the object
+ * @param onEventListener a listener that has a callback that will be triggered when a button event happens
+ */
+ public SoftButtonObject(@NonNull String name, @NonNull SoftButtonState state, OnEventListener onEventListener) {
+ this(name, Collections.singletonList(state), state.getName(), onEventListener);
+ }
+
+ /**
+ * Transition the SoftButtonObject to a specific state
+ * @param newStateName a String value represents the name fo the state that we want to transition the SoftButtonObject to
+ * @return a boolean value that represents whether the transition succeeded or failed
+ */
+ public boolean transitionToStateByName(@NonNull String newStateName) {
+ SoftButtonState newState = getStateByName(newStateName);
+ if (newState == null) {
+ Log.e(TAG, String.format("Attempted to transition to state: %s on soft button object: %s but no state with that name was found", newStateName, this.name));
+ return false;
+ }
+ DebugTool.logInfo(String.format("Transitioning soft button object %s to state %s", this.name, newStateName));
+ currentStateName = newStateName;
+
+ // Send a new Show RPC because the state has changed which means the actual SoftButton has changed
+ if (updateListener != null) {
+ updateListener.onUpdate();
+ } else {
+ Log.e(TAG, String.format("SoftButtonManager is not set for soft button object: %s. Update cannot be triggered", this.name));
+ }
+
+ return true;
+ }
+
+ /**
+ * Transition the SoftButtonObject to the next state
+ */
+ public void transitionToNextState() {
+ String nextStateName = null;
+ for (int i = 0; i < states.size(); i++) {
+ if (states.get(i).getName().equals(currentStateName)) {
+ if (i == (states.size() - 1)) {
+ nextStateName = states.get(0).getName();
+ } else {
+ nextStateName = states.get(i + 1).getName();
+ }
+ break;
+ }
+ }
+ if (nextStateName == null) {
+ Log.e(TAG, String.format("Current state name : %s cannot be found for soft button object %s", currentStateName, this.name));
+ return;
+ }
+ transitionToStateByName(nextStateName);
+ }
+
+ /**
+ * Get the current state for the SoftButtonObject
+ * @return a SoftButtonState represents the current state
+ */
+ public SoftButtonState getCurrentState() {
+ SoftButtonState state = getStateByName(currentStateName);
+ if (state == null) {
+ Log.e(TAG, String.format("Current state name : %s cannot be found for soft button object %s", currentStateName, this.name));
+ }
+ return state;
+ }
+
+ /**
+ * Get the SoftButton object for the current state
+ * @return a SoftButton object that is associated with the current state
+ */
+ public SoftButton getCurrentStateSoftButton() {
+ SoftButtonState currentState = getCurrentState();
+ if (currentState == null || currentState.getSoftButton() == null) {
+ return null;
+ }
+
+ SoftButton softButton = currentState.getSoftButton();
+ softButton.setSoftButtonID(this.buttonId);
+ return softButton;
+ }
+
+ /**
+ * Find and get the SoftButtonState that has the provided name
+ * @param stateName a String value that represents the name of the state
+ * @return a SoftButtonState object that represents the state that has the provided name
+ */
+ private SoftButtonState getStateByName(String stateName) {
+ if (stateName != null && states != null) {
+ for (SoftButtonState state : states) {
+ if (state.getName().equals(stateName)) {
+ return state;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Check if two SoftButtonState have the same name
+ * @param states a list of SoftButtonState
+ * @return a boolean value that represents whether we have two states with the same name
+ */
+ private boolean hasTwoStatesOfSameName(List<SoftButtonState> states) {
+ for (int i = 0; i < states.size(); i++) {
+ String stateName = states.get(i).getName();
+ for (int j = (i + 1); j < states.size(); j++) {
+ if (states.get(j).getName().equals(stateName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Set the SoftButtonManager's update listener
+ * @param updateListener the SoftButtonManager.UpdateListener object
+ */
+ protected void setUpdateListener(UpdateListener updateListener) {
+ this.updateListener = updateListener;
+ }
+
+ /**
+ * Get the name of the SoftButtonObject
+ * @return a String that represents the name of the SoftButtonObject
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Set the name of the SoftButtonObject
+ * @param name a String that represents the name of the SoftButtonObject
+ */
+ public void setName(@NonNull String name) {
+ this.name = name;
+ }
+
+ /**
+ * Get the SoftButtonState list
+ * @return a list of the object's soft button states
+ */
+ public List<SoftButtonState> getStates() {
+ return states;
+ }
+
+ /**
+ * Set the the SoftButtonState list
+ * @param states a list of the object's soft button states
+ */
+ public void setStates(@NonNull List<SoftButtonState> states) {
+ this.states = states;
+ }
+
+ /**
+ * Get the name of the current state
+ * @return a String that represents the name of the current state
+ */
+ public String getCurrentStateName() {
+ return currentStateName;
+ }
+
+ /**
+ * Set the name of the current state
+ * @param currentStateName a String that represents the name of the current state
+ */
+ public void setCurrentStateName(@NonNull String currentStateName) {
+ this.currentStateName = currentStateName;
+ }
+
+ /**
+ * Get the dd of the SoftButtonObject
+ * @return an int value that represents the id of the SoftButtonObject
+ */
+ public int getButtonId() {
+ return buttonId;
+ }
+
+ /**
+ * Set the id of the SoftButtonObject
+ * @param buttonId an int value that represents the id of the SoftButtonObject
+ */
+ public void setButtonId(int buttonId) {
+ this.buttonId = buttonId;
+ }
+
+ /**
+ * Get the event listener for the SoftButtonObject
+ * @return OnEventListener
+ */
+ public OnEventListener getOnEventListener() {
+ return onEventListener;
+ }
+
+ /**
+ * Set the event listener for the SoftButtonObject
+ * @param onEventListener a listener that has a callback that will be triggered when a button event happens
+ */
+ public void setOnEventListener(OnEventListener onEventListener) {
+ this.onEventListener = onEventListener;
+ }
+
+ public interface OnEventListener{
+ void onPress(SoftButtonObject softButtonObject, OnButtonPress onButtonPress);
+ void onEvent(SoftButtonObject softButtonObject, OnButtonEvent onButtonEvent);
+ }
+
+ /**
+ * A listener interface that is used by SoftButtonObject to request an update from SoftButtonManager
+ */
+ interface UpdateListener{
+ /**
+ * Requests an update from SoftButtonManager
+ */
+ void onUpdate();
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonState.java b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonState.java
new file mode 100644
index 000000000..67458ce2c
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/SoftButtonState.java
@@ -0,0 +1,97 @@
+package com.smartdevicelink.managers.screen;
+
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
+import com.smartdevicelink.proxy.rpc.Image;
+import com.smartdevicelink.proxy.rpc.SoftButton;
+import com.smartdevicelink.proxy.rpc.enums.ImageType;
+import com.smartdevicelink.proxy.rpc.enums.SoftButtonType;
+
+/**
+ * <strong>SoftButtonState</strong> <br>
+ * Defines an individual state for SoftButtonObject.<br>
+ * The states of SoftButtonObject allow the developer to not have to manage multiple SoftButtons that have very similar functionality.<br>
+ * For example, a repeat button in a music app can be thought of as one SoftButtonObject with three typical states: repeat off, repeat 1, and repeat on.<br>
+ * @see SoftButtonObject
+ */
+public class SoftButtonState {
+
+ private static final String TAG = "SoftButtonState";
+ private String name;
+ private SdlArtwork artwork;
+ private final SoftButton softButton;
+
+ /**
+ * Creates a new instance of SoftButtonState
+ * Note: state names should be different for each SoftButtonObject
+ * @param name a String value represents name of the state
+ * @param text a String represents the text for the state
+ * @param artwork an SdlArtwork represents the artwork for the state
+ */
+ public SoftButtonState(@NonNull String name, String text, SdlArtwork artwork) {
+ if (text == null && artwork == null) {
+ Log.e(TAG, "Attempted to create an invalid soft button state: text and artwork are both null");
+ softButton = null;
+ return;
+ }
+ this.name = name;
+ this.artwork = artwork;
+
+
+ // Create a SoftButton and set its Type
+ SoftButtonType type;
+ if (artwork != null && text != null) {
+ type = SoftButtonType.SBT_BOTH;
+ } else if (artwork != null) {
+ type = SoftButtonType.SBT_IMAGE;
+ } else {
+ type = SoftButtonType.SBT_TEXT;
+ }
+ this.softButton = new SoftButton(type, 0);
+
+
+ // Set the SoftButton's image
+ if (artwork != null) {
+ softButton.setImage(new Image(artwork.getName(), ImageType.DYNAMIC));
+ }
+
+ // Set the SoftButton's text
+ if (text != null) {
+ softButton.setText(text);
+ }
+ }
+
+ /**
+ * Get the state name
+ * @return a String value represents the name of the state
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Set the state name
+ * @param name a String value represents the name of the state
+ */
+ public void setName(@NonNull String name) {
+ this.name = name;
+ }
+
+ /**
+ * Get the SoftButton for the state
+ * @return a SoftButton object represents the SoftButton for the state
+ */
+ public SoftButton getSoftButton() {
+ return softButton;
+ }
+
+ /**
+ * Get the Artwork for the state
+ * @return an SdlArtwork object represents the artwork for the state
+ */
+ public SdlArtwork getArtwork() {
+ return artwork;
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java
new file mode 100644
index 000000000..4497062ef
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/screen/TextAndGraphicManager.java
@@ -0,0 +1,895 @@
+package com.smartdevicelink.managers.screen;
+
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import com.smartdevicelink.R;
+import com.smartdevicelink.managers.BaseSubManager;
+import com.smartdevicelink.managers.CompletionListener;
+import com.smartdevicelink.managers.file.FileManager;
+import com.smartdevicelink.managers.file.MultipleFileCompletionListener;
+import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCNotification;
+import com.smartdevicelink.proxy.RPCResponse;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.interfaces.OnSystemCapabilityListener;
+import com.smartdevicelink.proxy.rpc.DisplayCapabilities;
+import com.smartdevicelink.proxy.rpc.Image;
+import com.smartdevicelink.proxy.rpc.MetadataTags;
+import com.smartdevicelink.proxy.rpc.OnHMIStatus;
+import com.smartdevicelink.proxy.rpc.Show;
+import com.smartdevicelink.proxy.rpc.TextField;
+import com.smartdevicelink.proxy.rpc.enums.FileType;
+import com.smartdevicelink.proxy.rpc.enums.HMILevel;
+import com.smartdevicelink.proxy.rpc.enums.ImageType;
+import com.smartdevicelink.proxy.rpc.enums.MetadataType;
+import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
+import com.smartdevicelink.proxy.rpc.enums.TextFieldName;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
+import com.smartdevicelink.proxy.rpc.enums.TextAlignment;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener;
+import com.smartdevicelink.util.DebugTool;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static com.smartdevicelink.proxy.rpc.enums.TextAlignment.CENTERED;
+
+/**
+ * <strong>TextAndGraphicManager</strong> <br>
+ *
+ * Note: This class must be accessed through the SdlManager. Do not instantiate it by itself. <br>
+ *
+ */
+class TextAndGraphicManager extends BaseSubManager {
+
+ private static final String TAG = "TextAndGraphicManager";
+
+ boolean isDirty, hasQueuedUpdate;
+ volatile Show inProgressUpdate;
+ Show currentScreenData, queuedImageUpdate;
+ HMILevel currentHMILevel;
+ protected DisplayCapabilities displayCapabilities;
+ private boolean pendingHMIFull, batchingUpdates;
+ private final WeakReference<FileManager> fileManager;
+ private final WeakReference<SoftButtonManager> softButtonManager;
+ private CompletionListener queuedUpdateListener, inProgressListener, pendingHMIListener;
+ private SdlArtwork blankArtwork;
+ private OnRPCNotificationListener hmiListener;
+ private OnSystemCapabilityListener onDisplayCapabilitiesListener;
+ private SdlArtwork primaryGraphic, secondaryGraphic;
+ private TextAlignment textAlignment;
+ private String textField1, textField2, textField3, textField4, mediaTrackTextField;
+ private MetadataType textField1Type, textField2Type, textField3Type, textField4Type;
+
+ //Constructors
+
+ TextAndGraphicManager(@NonNull ISdl internalInterface, @NonNull FileManager fileManager, @NonNull SoftButtonManager softButtonManager) {
+ // set class vars
+ super(internalInterface);
+ this.fileManager = new WeakReference<>(fileManager);
+ this.softButtonManager = new WeakReference<>(softButtonManager);
+ batchingUpdates = false;
+ isDirty = false;
+ pendingHMIFull = false;
+ textAlignment = CENTERED;
+ currentHMILevel = HMILevel.HMI_NONE;
+ currentScreenData = new Show();
+ addListeners();
+ getBlankArtwork();
+ }
+
+ @Override
+ public void start(CompletionListener listener) {
+ transitionToState(READY);
+ super.start(listener);
+ }
+
+ @Override
+ public void dispose(){
+
+ textField1 = null;
+ textField1Type = null;
+ textField2 = null;
+ textField2Type = null;
+ textField3 = null;
+ textField3Type = null;
+ textField4 = null;
+ textField4Type = null;
+ mediaTrackTextField = null;
+ textAlignment = null;
+ primaryGraphic = null;
+ secondaryGraphic = null;
+ blankArtwork = null;
+ displayCapabilities = null;
+ inProgressUpdate = null;
+ queuedImageUpdate = null;
+ currentScreenData = null;
+ queuedUpdateListener = null;
+ pendingHMIListener = null;
+ inProgressListener = null;
+ hasQueuedUpdate = false;
+ isDirty = false;
+ pendingHMIFull = false;
+
+ // remove listeners
+ internalInterface.removeOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, hmiListener);
+ internalInterface.removeOnSystemCapabilityListener(SystemCapabilityType.DISPLAY, onDisplayCapabilitiesListener);
+
+ super.dispose();
+ }
+
+ private void addListeners() {
+ // add listener
+ hmiListener = new OnRPCNotificationListener() {
+ @Override
+ public void onNotified(RPCNotification notification) {
+ currentHMILevel = ((OnHMIStatus)notification).getHmiLevel();
+ if (currentHMILevel == HMILevel.HMI_FULL){
+ if (pendingHMIFull){
+ DebugTool.logInfo( "Acquired HMI_FULL with pending update. Sending now");
+ pendingHMIFull = false;
+ sdlUpdate(pendingHMIListener);
+ pendingHMIListener = null;
+ }
+ }
+ }
+ };
+ internalInterface.addOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, hmiListener);
+
+ // Add OnDisplayCapabilitiesListener to keep displayCapabilities updated
+ onDisplayCapabilitiesListener = new OnSystemCapabilityListener() {
+ @Override
+ public void onCapabilityRetrieved(Object capability) {
+ displayCapabilities = (DisplayCapabilities)capability;
+ }
+
+ @Override
+ public void onError(String info) {
+ Log.e(TAG, "DISPLAY Capability cannot be retrieved:");
+ displayCapabilities = null;
+ }
+ };
+ this.internalInterface.addOnSystemCapabilityListener(SystemCapabilityType.DISPLAY, onDisplayCapabilitiesListener);
+ }
+
+ // Upload / Send
+
+ protected void update(CompletionListener listener) {
+
+ // check if is batch update
+ if (batchingUpdates) {
+ return;
+ }
+
+ if (isDirty){
+ isDirty = false;
+ sdlUpdate(listener);
+ }
+ }
+
+ private synchronized void sdlUpdate(CompletionListener listener){
+
+ // make sure hmi is not none
+ if (currentHMILevel == null || currentHMILevel == HMILevel.HMI_NONE){
+ //Trying to send show on HMI_NONE, waiting for full
+ pendingHMIFull = true;
+ if (listener != null){
+ pendingHMIListener = listener;
+ }
+ return;
+ }
+
+ //Updating Text and Graphics
+ if (inProgressUpdate != null){
+
+ //In progress update exists, queueing update
+ if (queuedUpdateListener != null){
+
+ //Queued update already exists, superseding previous queued update
+ queuedUpdateListener.onComplete(false);
+ queuedUpdateListener = null;
+ }
+
+ if (listener != null){
+ queuedUpdateListener = listener;
+ }else{
+ hasQueuedUpdate = true;
+ }
+ return;
+ }
+
+ Show fullShow = new Show();
+ fullShow.setAlignment(textAlignment);
+ fullShow = assembleShowText(fullShow);
+ fullShow = assembleShowImages(fullShow);
+
+ inProgressListener = listener;
+
+ if (!shouldUpdatePrimaryImage() && !shouldUpdateSecondaryImage()){
+
+ //No Images to send, only sending text
+ inProgressUpdate = extractTextFromShow(fullShow);
+ sendShow();
+
+ }else if (isArtworkUploadedOrDoesntExist(primaryGraphic) && ( secondaryGraphic == blankArtwork || isArtworkUploadedOrDoesntExist(secondaryGraphic))){
+
+ //Images already uploaded, sending full update
+ // The files to be updated are already uploaded, send the full show immediately
+ inProgressUpdate = fullShow;
+ sendShow();
+ } else{
+
+ // Images need to be uploaded, sending text and uploading images
+ inProgressUpdate = fullShow;
+ final Show thisUpdate = fullShow;
+
+ uploadImages(new CompletionListener() {
+ @Override
+ public void onComplete(boolean success) {
+ if (!success){
+ Log.e(TAG, "Error uploading image");
+ inProgressUpdate = extractTextFromShow(inProgressUpdate);
+ sendShow();
+ }
+ // Check if queued image update still matches our images (there could have been a new Show in the meantime)
+ // and send a new update if it does. Since the images will already be on the head unit, the whole show will be sent
+ if (thisUpdate.getGraphic() != null && thisUpdate.getGraphic().equals(queuedImageUpdate.getGraphic()) ||
+ (thisUpdate.getSecondaryGraphic() != null && queuedImageUpdate.getSecondaryGraphic() != null) && thisUpdate.getSecondaryGraphic().equals(queuedImageUpdate.getSecondaryGraphic())){
+ // Queued image update matches the images we need, sending update
+ sendShow();
+ }
+ // Else, Queued image update does not match the images we need, skipping update
+ }
+ });
+ queuedImageUpdate = fullShow;
+ }
+ }
+
+ private void sendShow(){
+ inProgressUpdate.setOnRPCResponseListener(new OnRPCResponseListener() {
+ @Override
+ public void onResponse(int correlationId, RPCResponse response) {
+ if (response.getSuccess()){
+ updateCurrentScreenDataState(inProgressUpdate);
+ }
+
+ inProgressUpdate = null;
+ if (inProgressListener != null){
+ inProgressListener.onComplete(true);
+ inProgressListener = null;
+ }
+
+ if (hasQueuedUpdate){
+ //Queued update exists, sending another update
+ hasQueuedUpdate = false;
+ CompletionListener temp = queuedUpdateListener;
+ queuedUpdateListener = null;
+ sdlUpdate(temp);
+ }
+ }
+ });
+
+ if (this.softButtonManager.get() != null) {
+ this.softButtonManager.get().setCurrentMainField1(inProgressUpdate.getMainField1());
+ }
+ internalInterface.sendRPCRequest(inProgressUpdate);
+ }
+
+ // Images
+
+ private void uploadImages(final CompletionListener listener) {
+
+ List<SdlArtwork> artworksToUpload = new ArrayList<>();
+
+ // add primary image
+ if (shouldUpdatePrimaryImage()){
+ artworksToUpload.add(primaryGraphic);
+ }
+
+ // add secondary image
+ if (shouldUpdateSecondaryImage()){
+ artworksToUpload.add(secondaryGraphic);
+ }
+
+ // use file manager to upload art
+ if (fileManager.get() != null) {
+ fileManager.get().uploadArtworks(artworksToUpload, new MultipleFileCompletionListener() {
+ @Override
+ public void onComplete(Map<String, String> errors) {
+ if (errors != null) {
+ Log.e(TAG, "Error Uploading Artworks. Error: " + errors.toString());
+ listener.onComplete(false);
+ } else {
+ listener.onComplete(true);
+ }
+ }
+ });
+ }
+ }
+
+ private Show assembleShowImages(Show show){
+
+ if (shouldUpdatePrimaryImage()){
+ Image primaryImage = new Image();
+ primaryImage.setImageType(ImageType.DYNAMIC);
+ primaryImage.setValue(primaryGraphic.getName());
+ show.setGraphic(primaryImage);
+ }
+
+ if (shouldUpdateSecondaryImage()){
+ Image secondaryImage = new Image();
+ secondaryImage.setImageType(ImageType.DYNAMIC);
+ secondaryImage.setValue(secondaryGraphic.getName());
+ show.setSecondaryGraphic(secondaryImage);
+ }
+
+ return show;
+ }
+
+ // Text
+
+ Show assembleShowText(Show show){
+
+ show = setBlankTextFields(show);
+
+ if (mediaTrackTextField != null){
+ show.setMediaTrack(mediaTrackTextField);
+ }
+
+ List<String> nonNullFields = findValidMainTextFields();
+ if (nonNullFields.isEmpty()){
+ return show;
+ }
+
+ int numberOfLines = getNumberOfLines();
+
+ switch (numberOfLines) {
+ case 1: show = assembleOneLineShowText(show, nonNullFields);
+ break;
+ case 2: show = assembleTwoLineShowText(show);
+ break;
+ case 3: show = assembleThreeLineShowText(show);
+ break;
+ case 4: show = assembleFourLineShowText(show);
+ break;
+ }
+
+ return show;
+ }
+
+ private Show assembleOneLineShowText(Show show, List<String> showFields){
+
+ StringBuilder showString1 = new StringBuilder();
+ for (int i = 0; i < showFields.size(); i++) {
+ if (i > 0) {
+ showString1.append(" - ").append(showFields.get(i));
+ }else{
+ showString1.append(showFields.get(i));
+ }
+ }
+ show.setMainField1(showString1.toString());
+
+ MetadataTags tags = new MetadataTags();
+ tags.setMainField1(findNonNullMetadataFields());
+
+ show.setMetadataTags(tags);
+
+ return show;
+ }
+
+ private Show assembleTwoLineShowText(Show show){
+
+ StringBuilder tempString = new StringBuilder();
+ MetadataTags tags = new MetadataTags();
+
+ if (textField1 != null && textField1.length() > 0) {
+ tempString.append(textField1);
+ if (textField1Type != null){
+ tags.setMainField1(textField1Type);
+ }
+ }
+
+ if (textField2 != null && textField2.length() > 0) {
+ if (( textField3 == null || !(textField3.length() > 0)) && (textField4 == null || !(textField4.length() > 0))){
+ // text does not exist in slots 3 or 4, put text2 in slot 2
+ show.setMainField2(textField2);
+ if (textField2Type != null){
+ tags.setMainField2(textField2Type);
+ }
+ } else if (textField1 != null && textField1.length() > 0) {
+ // If text 1 exists, put it in slot 1 formatted
+ tempString.append(" - ").append(textField2);
+ if (textField2Type != null){
+ List<MetadataType> typeList = new ArrayList<>();
+ typeList.add(textField2Type);
+ if (textField1Type != null){
+ typeList.add(textField1Type);
+ }
+ tags.setMainField1(typeList);
+ }
+ }else {
+ // If text 1 does not exist, put it in slot 1 unformatted
+ tempString.append(textField2);
+ if (textField2Type != null){
+ tags.setMainField1(textField2Type);
+ }
+ }
+ }
+
+ // set mainfield 1
+ show.setMainField1(tempString.toString());
+
+ // new stringbuilder object
+ tempString = new StringBuilder();
+
+ if (textField3 != null && textField3.length() > 0){
+ // If text 3 exists, put it in slot 2
+ tempString.append(textField3);
+ if (textField3Type != null){
+ List<MetadataType> typeList = new ArrayList<>();
+ typeList.add(textField3Type);
+ tags.setMainField2(typeList);
+ }
+ }
+
+ if (textField4 != null && textField4.length() > 0){
+ if (textField3 != null && textField3.length() > 0){
+ // If text 3 exists, put it in slot 2 formatted
+ tempString.append(" - ").append(textField4);
+ if (textField4Type != null){
+ List<MetadataType> typeList = new ArrayList<>();
+ typeList.add(textField4Type);
+ if (textField3Type != null){
+ typeList.add(textField3Type);
+ }
+ tags.setMainField2(typeList);
+ }
+ } else {
+ // If text 3 does not exist, put it in slot 3 unformatted
+ tempString.append(textField4);
+ if (textField4Type != null){
+ tags.setMainField2(textField4Type);
+ }
+ }
+ }
+
+ if (tempString.toString().length() > 0){
+ show.setMainField2(tempString.toString());
+ }
+
+ show.setMetadataTags(tags);
+ return show;
+ }
+
+ private Show assembleThreeLineShowText(Show show){
+
+ MetadataTags tags = new MetadataTags();
+
+ if (textField1 != null && textField1.length() > 0) {
+ show.setMainField1(textField1);
+ if (textField1Type != null){
+ tags.setMainField1(textField1Type);
+ }
+ }
+
+ if (textField2 != null && textField2.length() > 0) {
+ show.setMainField2(textField2);
+ if (textField2Type != null){
+ tags.setMainField2(textField2Type);
+ }
+ }
+
+ StringBuilder tempString = new StringBuilder();
+
+ if (textField3 != null && textField3.length() > 0){
+ tempString.append(textField3);
+ if (textField3Type != null){
+ tags.setMainField3(textField3Type);
+ }
+ }
+
+ if (textField4 != null && textField4.length() > 0) {
+ if (textField3 != null && textField3.length() > 0) {
+ // If text 3 exists, put it in slot 3 formatted
+ tempString.append(" - ").append(textField4);
+ if (textField4Type != null){
+ List<MetadataType> tags4 = new ArrayList<>();
+ if (textField3Type != null){
+ tags4.add(textField3Type);
+ }
+ tags4.add(textField4Type);
+ tags.setMainField3(tags4);
+ }
+ } else {
+ // If text 3 does not exist, put it in slot 3 formatted
+ tempString.append(textField4);
+ if (textField4Type != null){
+ tags.setMainField3(textField4Type);
+ }
+ }
+ }
+
+ show.setMainField3(tempString.toString());
+ show.setMetadataTags(tags);
+ return show;
+ }
+
+ private Show assembleFourLineShowText(Show show){
+
+ MetadataTags tags = new MetadataTags();
+
+ if (textField1 != null && textField1.length() > 0) {
+ show.setMainField1(textField1);
+ if (textField1Type != null){
+ tags.setMainField1(textField1Type);
+ }
+ }
+
+ if (textField2 != null && textField2.length() > 0) {
+ show.setMainField2(textField2);
+ if (textField2Type != null){
+ tags.setMainField2(textField2Type);
+ }
+ }
+
+ if (textField3 != null && textField3.length() > 0) {
+ show.setMainField3(textField3);
+ if (textField3Type != null){
+ tags.setMainField3(textField3Type);
+ }
+ }
+
+ if (textField4 != null && textField4.length() > 0) {
+ show.setMainField4(textField4);
+ if (textField4Type != null){
+ tags.setMainField4(textField4Type);
+ }
+ }
+
+ show.setMetadataTags(tags);
+ return show;
+ }
+
+ // Extraction
+
+ Show extractTextFromShow(Show show){
+
+ Show newShow = new Show();
+ newShow.setMainField1(show.getMainField1());
+ newShow.setMainField2(show.getMainField2());
+ newShow.setMainField3(show.getMainField3());
+ newShow.setMainField4(show.getMainField4());
+
+ return newShow;
+ }
+
+ private Show setBlankTextFields(Show newShow){
+
+ newShow.setMainField1("");
+ newShow.setMainField2("");
+ newShow.setMainField3("");
+ newShow.setMainField4("");
+ newShow.setMediaTrack("");
+
+ return newShow;
+ }
+
+ private void updateCurrentScreenDataState(Show show){
+
+ if (show == null){
+ Log.e(TAG, "can not updateCurrentScreenDataFromShow from null show");
+ return;
+ }
+
+ // If the items are null, they were not updated, so we can't just set it directly
+ if (show.getMainField1() != null){
+ currentScreenData.setMainField1(show.getMainField1());
+ }
+ if (show.getMainField2() != null){
+ currentScreenData.setMainField2(show.getMainField2());
+ }
+ if (show.getMainField3() != null){
+ currentScreenData.setMainField3(show.getMainField3());
+ }
+ if (show.getMainField4() != null){
+ currentScreenData.setMainField4(show.getMainField4());
+ }
+ if (show.getMediaTrack() != null){
+ currentScreenData.setMediaTrack(show.getMediaTrack());
+ }
+ if (show.getMetadataTags() != null){
+ currentScreenData.setMetadataTags(show.getMetadataTags());
+ }
+ if (show.getAlignment() != null){
+ currentScreenData.setAlignment(show.getAlignment());
+ }
+ if (show.getGraphic() != null){
+ currentScreenData.setGraphic(show.getGraphic());
+ }
+ if (show.getSecondaryGraphic() != null){
+ currentScreenData.setSecondaryGraphic(show.getSecondaryGraphic());
+ }
+ }
+
+ // Helpers
+
+ private List<String> findValidMainTextFields(){
+ List<String> array = new ArrayList<>();
+
+ if (textField1 != null && textField1.length() > 0) {
+ array.add(textField1);
+ }
+
+ if (textField2 != null && textField2.length() > 0) {
+ array.add(textField2);
+ }
+
+ if (textField3 != null && textField3.length() > 0) {
+ array.add(textField3);
+ }
+
+ if (textField4 != null && textField4.length() > 0) {
+ array.add(textField4);
+ }
+
+ return array;
+ }
+
+
+ private List<MetadataType> findNonNullMetadataFields(){
+ List<MetadataType> array = new ArrayList<>();
+
+ if (textField1Type != null) {
+ array.add(textField1Type);
+ }
+
+ if (textField2Type != null) {
+ array.add(textField2Type);
+ }
+
+ if (textField3Type != null) {
+ array.add(textField3Type);
+ }
+
+ if (textField4Type != null) {
+ array.add(textField4Type);
+ }
+
+ return array;
+ }
+
+ SdlArtwork getBlankArtwork(){
+
+ if (blankArtwork != null){
+ blankArtwork = new SdlArtwork();
+ blankArtwork.setType(FileType.GRAPHIC_PNG);
+ blankArtwork.setName("blankArtwork");
+ blankArtwork.setResourceId(R.drawable.transparent);
+ }
+ return blankArtwork;
+ }
+
+ private boolean isArtworkUploadedOrDoesntExist(SdlArtwork artwork){
+
+ if (fileManager.get() != null){
+ return artwork != null && fileManager.get().hasUploadedFile(artwork);
+ }
+
+ return false;
+ }
+
+ private boolean shouldUpdatePrimaryImage() {
+ if (displayCapabilities == null || displayCapabilities.getGraphicSupported()) {
+ if (currentScreenData.getGraphic() == null && primaryGraphic != null) {
+ return true;
+ } else if (currentScreenData.getGraphic() == null && primaryGraphic == null) {
+ return false;
+ }
+ return currentScreenData != null && (primaryGraphic != null && !currentScreenData.getGraphic().getValue().equalsIgnoreCase(primaryGraphic.getName()));
+ }
+ return false;
+ }
+
+ private boolean shouldUpdateSecondaryImage() {
+ // Cannot detect if there is a secondary image, so we'll just try to detect if there's a primary image and allow it if there is.
+ if (displayCapabilities == null || displayCapabilities.getGraphicSupported()) {
+ if (currentScreenData.getGraphic() == null && secondaryGraphic != null) {
+ return true;
+ } else if (currentScreenData.getGraphic() == null && secondaryGraphic == null) {
+ return false;
+ }
+ return currentScreenData != null && (secondaryGraphic != null && !currentScreenData.getGraphic().getValue().equalsIgnoreCase(secondaryGraphic.getName()));
+ }
+ return false;
+ }
+
+ int getNumberOfLines() {
+
+ if (displayCapabilities == null){
+ return 4;
+ }
+
+ int linesFound = 0;
+
+ List<TextField> textFields = displayCapabilities.getTextFields();
+ TextFieldName name;
+ for (TextField field : textFields) {
+ if (field.getName() != null) {
+ name = field.getName();
+ if (name == TextFieldName.mainField1 || name == TextFieldName.mainField2 || name == TextFieldName.mainField3 || name == TextFieldName.mainField4) {
+ linesFound += 1;
+ }
+ }
+ }
+
+ return linesFound;
+ }
+
+ // SCREEN ITEM SETTERS AND GETTERS
+
+ void setTextAlignment(TextAlignment textAlignment){
+ this.textAlignment = textAlignment;
+ // If we aren't batching, send the update immediately, if we are, set ourselves as dirty (so we know we should send an update after the batch ends)
+ if (!batchingUpdates){
+ sdlUpdate(null);
+ }else{
+ isDirty = true;
+ }
+ }
+
+ TextAlignment getTextAlignment(){
+ return textAlignment;
+ }
+
+ void setMediaTrackTextField(String mediaTrackTextField){
+ this.mediaTrackTextField = mediaTrackTextField;
+ if (!batchingUpdates){
+ sdlUpdate(null);
+ }else{
+ isDirty = true;
+ }
+ }
+
+ String getMediaTrackTextField(){
+ return mediaTrackTextField;
+ }
+
+ void setTextField1(String textField1){
+ this.textField1 = textField1;
+ if (!batchingUpdates){
+ sdlUpdate(null);
+ }else{
+ isDirty = true;
+ }
+ }
+
+ String getTextField1(){
+ return textField1;
+ }
+
+ void setTextField2(String textField2){
+ this.textField2 = textField2;
+ if (!batchingUpdates){
+ sdlUpdate(null);
+ }else{
+ isDirty = true;
+ }
+ }
+
+ String getTextField2(){
+ return textField2;
+ }
+
+ void setTextField3(String textField3){
+ this.textField3 = textField3;
+ if (!batchingUpdates){
+ sdlUpdate(null);
+ }else{
+ isDirty = true;
+ }
+ }
+
+ String getTextField3(){
+ return textField3;
+ }
+
+ void setTextField4(String textField4){
+ this.textField4 = textField4;
+ if (!batchingUpdates){
+ sdlUpdate(null);
+ }else{
+ isDirty = true;
+ }
+ }
+
+ String getTextField4(){
+ return textField4;
+ }
+
+ void setTextField1Type(MetadataType textField1Type){
+ this.textField1Type = textField1Type;
+ if (!batchingUpdates){
+ sdlUpdate(null);
+ }else{
+ isDirty = true;
+ }
+ }
+
+ MetadataType getTextField1Type(){
+ return textField1Type;
+ }
+
+ void setTextField2Type(MetadataType textField2Type){
+ this.textField2Type = textField2Type;
+ if (!batchingUpdates){
+ sdlUpdate(null);
+ }else{
+ isDirty = true;
+ }
+ }
+
+ MetadataType getTextField2Type(){
+ return textField2Type;
+ }
+
+ void setTextField3Type(MetadataType textField3Type){
+ this.textField3Type = textField3Type;
+ if (!batchingUpdates){
+ sdlUpdate(null);
+ }else{
+ isDirty = true;
+ }
+ }
+
+ MetadataType getTextField3Type(){
+ return textField3Type;
+ }
+
+ void setTextField4Type(MetadataType textField4Type){
+ this.textField4Type = textField4Type;
+ if (!batchingUpdates){
+ sdlUpdate(null);
+ }else{
+ isDirty = true;
+ }
+ }
+
+ MetadataType getTextField4Type(){
+ return textField4Type;
+ }
+
+ void setPrimaryGraphic(SdlArtwork primaryGraphic){
+ this.primaryGraphic = primaryGraphic;
+ if (!batchingUpdates){
+ sdlUpdate(null);
+ }else{
+ isDirty = true;
+ }
+ }
+
+ SdlArtwork getPrimaryGraphic(){
+ return primaryGraphic;
+ }
+
+ void setSecondaryGraphic(SdlArtwork secondaryGraphic){
+ this.secondaryGraphic = secondaryGraphic;
+ if (!batchingUpdates){
+ sdlUpdate(null);
+ }else{
+ isDirty = true;
+ }
+ }
+
+ SdlArtwork getSecondaryGraphic(){
+ return secondaryGraphic;
+ }
+
+ void setBatchUpdates(boolean batching){
+ this.batchingUpdates = batching;
+ }
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/managers/video/VideoStreamManager.java b/sdl_android/src/main/java/com/smartdevicelink/managers/video/VideoStreamManager.java
new file mode 100644
index 000000000..1e84531bd
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/managers/video/VideoStreamManager.java
@@ -0,0 +1,621 @@
+package com.smartdevicelink.managers.video;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.SystemClock;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.SparseIntArray;
+import android.view.Display;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+
+import com.smartdevicelink.SdlConnection.SdlSession;
+import com.smartdevicelink.encoder.VirtualDisplayEncoder;
+import com.smartdevicelink.haptic.HapticInterfaceManager;
+import com.smartdevicelink.managers.BaseSubManager;
+import com.smartdevicelink.managers.CompletionListener;
+import com.smartdevicelink.managers.StreamingStateMachine;
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.proxy.RPCNotification;
+import com.smartdevicelink.proxy.interfaces.ISdl;
+import com.smartdevicelink.proxy.interfaces.ISdlServiceListener;
+import com.smartdevicelink.proxy.interfaces.IVideoStreamListener;
+import com.smartdevicelink.proxy.interfaces.OnSystemCapabilityListener;
+import com.smartdevicelink.proxy.rpc.DisplayCapabilities;
+import com.smartdevicelink.proxy.rpc.ImageResolution;
+import com.smartdevicelink.proxy.rpc.OnHMIStatus;
+import com.smartdevicelink.proxy.rpc.OnTouchEvent;
+import com.smartdevicelink.proxy.rpc.TouchCoord;
+import com.smartdevicelink.proxy.rpc.TouchEvent;
+import com.smartdevicelink.proxy.rpc.VideoStreamingCapability;
+import com.smartdevicelink.proxy.rpc.enums.HMILevel;
+import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
+import com.smartdevicelink.proxy.rpc.enums.TouchType;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
+import com.smartdevicelink.streaming.video.SdlRemoteDisplay;
+import com.smartdevicelink.streaming.video.VideoStreamingParameters;
+import com.smartdevicelink.transport.utl.TransportRecord;
+import com.smartdevicelink.util.Version;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.concurrent.FutureTask;
+
+@TargetApi(19)
+public class VideoStreamManager extends BaseSubManager {
+ private static String TAG = "VideoStreamManager";
+
+ private WeakReference<Context> context;
+ private volatile VirtualDisplayEncoder virtualDisplayEncoder;
+ private Class<? extends SdlRemoteDisplay> remoteDisplayClass = null;
+ private SdlRemoteDisplay remoteDisplay;
+ private float[] touchScalar = {1.0f,1.0f}; //x, y
+ private HapticInterfaceManager hapticManager;
+ private SdlMotionEvent sdlMotionEvent = null;
+ private HMILevel hmiLevel;
+ private StreamingStateMachine stateMachine;
+ private VideoStreamingParameters parameters;
+ private IVideoStreamListener streamListener;
+ private boolean isTransportAvailable = false;
+
+ // INTERNAL INTERFACES
+
+ private final ISdlServiceListener serviceListener = new ISdlServiceListener() {
+ @Override
+ public void onServiceStarted(SdlSession session, SessionType type, boolean isEncrypted) {
+ if(SessionType.NAV.equals(type)){
+ stateMachine.transitionToState(StreamingStateMachine.READY);
+ }
+ }
+
+ @Override
+ public void onServiceEnded(SdlSession session, SessionType type) {
+ if(SessionType.NAV.equals(type)){
+ stateMachine.transitionToState(StreamingStateMachine.NONE);
+ if(remoteDisplay!=null){
+ stopStreaming();
+ }
+ }
+ }
+
+ @Override
+ public void onServiceError(SdlSession session, SessionType type, String reason) {
+ stateMachine.transitionToState(StreamingStateMachine.ERROR);
+ transitionToState(BaseSubManager.ERROR);
+ }
+ };
+
+ private final OnRPCNotificationListener hmiListener = new OnRPCNotificationListener() {
+ @Override
+ public void onNotified(RPCNotification notification) {
+ if(notification != null){
+ hmiLevel = ((OnHMIStatus)notification).getHmiLevel();
+ if(hmiLevel.equals(HMILevel.HMI_FULL)){
+ checkState();
+ }
+ }
+ }
+ };
+
+ private final OnRPCNotificationListener touchListener = new OnRPCNotificationListener() {
+ @Override
+ public void onNotified(RPCNotification notification) {
+ if(notification != null && remoteDisplay != null){
+ MotionEvent event = convertTouchEvent((OnTouchEvent)notification);
+ if(event!=null){
+ remoteDisplay.handleMotionEvent(event);
+ }
+ }
+ }
+ };
+
+ // MANAGER APIs
+
+ public VideoStreamManager(ISdl internalInterface){
+ super(internalInterface);
+
+ virtualDisplayEncoder = new VirtualDisplayEncoder();
+ hmiLevel = HMILevel.HMI_NONE;
+
+ // Listen for video service events
+ internalInterface.addServiceListener(SessionType.NAV, serviceListener);
+ // Take care of the touch events
+ internalInterface.addOnRPCNotificationListener(FunctionID.ON_TOUCH_EVENT, touchListener);
+ // Listen for HMILevel changes
+ internalInterface.addOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, hmiListener);
+
+ stateMachine = new StreamingStateMachine();
+ }
+
+ @Override
+ public void start(CompletionListener listener) {
+ isTransportAvailable = internalInterface.isTransportForServiceAvailable(SessionType.NAV);
+ getVideoStreamingParams();
+ checkState();
+ super.start(listener);
+ }
+
+ private synchronized void checkState(){
+ if(this.getState() == SETTING_UP
+ && isTransportAvailable
+ && hmiLevel != null
+ && hmiLevel.equals(HMILevel.HMI_FULL)
+ && parameters != null){
+ transitionToState(READY);
+ }
+ }
+
+ private void getVideoStreamingParams(){
+ if(internalInterface.getProtocolVersion().getMajor() >= 5) {
+ internalInterface.getCapability(SystemCapabilityType.VIDEO_STREAMING, new OnSystemCapabilityListener() {
+ @Override
+ public void onCapabilityRetrieved(Object capability) {
+ VideoStreamingParameters params = new VideoStreamingParameters();
+ params.update((VideoStreamingCapability)capability); //Streaming parameters are ready time to stream
+ VideoStreamManager.this.parameters = params;
+
+ checkState();
+
+ }
+
+ @Override
+ public void onError(String info) {
+ Log.e(TAG, "Error retrieving video streaming capability: " + info);
+ stateMachine.transitionToState(StreamingStateMachine.ERROR);
+ transitionToState(ERROR);
+ }
+ });
+ }else{
+ //We just use default video streaming params
+ VideoStreamingParameters params = new VideoStreamingParameters();
+ DisplayCapabilities dispCap = (DisplayCapabilities)internalInterface.getCapability(SystemCapabilityType.DISPLAY);
+ if(dispCap !=null){
+ params.setResolution(dispCap.getScreenParams().getImageResolution());
+ }
+
+ this.parameters = params;
+ checkState();
+ }
+ }
+
+ /**
+ * Starts streaming a remote display to the module if there is a connected session. This method of streaming requires the device to be on API level 19 or higher
+ * @param context a context that can be used to create the remote display
+ * @param remoteDisplayClass class object of the remote display. This class will be used to create an instance of the remote display and will be projected to the module
+ * @param parameters streaming parameters to be used when streaming. If null is sent in, the default/optimized options will be used.
+ * If you are unsure about what parameters to be used it is best to just send null and let the system determine what
+ * works best for the currently connected module.
+ *
+ * @param encrypted a flag of if the stream should be encrypted. Only set if you have a supplied encryption library that the module can understand.
+ */
+ public void startRemoteDisplayStream(Context context, Class<? extends SdlRemoteDisplay> remoteDisplayClass, VideoStreamingParameters parameters, final boolean encrypted){
+ this.context = new WeakReference<>(context);
+ this.remoteDisplayClass = remoteDisplayClass;
+ int majorProtocolVersion = internalInterface.getProtocolVersion().getMajor();
+ if(majorProtocolVersion >= 5 && !internalInterface.isCapabilitySupported(SystemCapabilityType.VIDEO_STREAMING)){
+ Log.e(TAG, "Video streaming not supported on this module");
+ stateMachine.transitionToState(StreamingStateMachine.ERROR);
+ return;
+ }
+ if(parameters == null){
+ if(majorProtocolVersion >= 5) {
+ internalInterface.getCapability(SystemCapabilityType.VIDEO_STREAMING, new OnSystemCapabilityListener() {
+ @Override
+ public void onCapabilityRetrieved(Object capability) {
+ VideoStreamingParameters params = new VideoStreamingParameters();
+ params.update((VideoStreamingCapability)capability); //Streaming parameters are ready time to stream
+ startStreaming(params, encrypted);
+ }
+
+ @Override
+ public void onError(String info) {
+ stateMachine.transitionToState(StreamingStateMachine.ERROR);
+ Log.e(TAG, "Error retrieving video streaming capability: " + info);
+ }
+ });
+ }else{
+ //We just use default video streaming params
+ VideoStreamingParameters params = new VideoStreamingParameters();
+ DisplayCapabilities dispCap = (DisplayCapabilities)internalInterface.getCapability(SystemCapabilityType.DISPLAY);
+ if(dispCap !=null){
+ params.setResolution(dispCap.getScreenParams().getImageResolution());
+ }
+ startStreaming(params, encrypted);
+ }
+ }else{
+ startStreaming(parameters, encrypted);
+ }
+ }
+
+ /**
+ * Opens a video service (service type 11) and subsequently provides an IVideoStreamListener
+ * to the app to send video data. The supplied VideoStreamingParameters will be set as desired paramaters
+ * that will be used to negotiate
+ *
+ * @param parameters Video streaming parameters including: codec which will be used for streaming (currently, only
+ * VideoStreamingCodec.H264 is accepted), height and width of the video in pixels.
+ * @param encrypted Specify true if packets on this service have to be encrypted
+ *
+ * @return IVideoStreamListener interface if service is opened successfully and streaming is
+ * started, null otherwise
+ */
+ protected IVideoStreamListener startVideoService(VideoStreamingParameters parameters, boolean encrypted){
+ if(hmiLevel != HMILevel.HMI_FULL){
+ Log.e(TAG, "Cannot start video service if HMILevel is not FULL.");
+ return null;
+ }
+ IVideoStreamListener listener = internalInterface.startVideoStream(encrypted, parameters);
+ if(listener != null){
+ stateMachine.transitionToState(StreamingStateMachine.STARTED);
+ }else{
+ stateMachine.transitionToState(StreamingStateMachine.ERROR);
+ }
+ return listener;
+ }
+
+ /**
+ * Starts video service, sets up encoder, haptic manager, and remote display. Begins streaming the remote display.
+ * @param parameters Video streaming parameters including: codec which will be used for streaming (currently, only
+ * VideoStreamingCodec.H264 is accepted), height and width of the video in pixels.
+ * @param encrypted Specify true if packets on this service have to be encrypted
+ */
+ private void startStreaming(VideoStreamingParameters parameters, boolean encrypted){
+ this.parameters = parameters;
+ this.streamListener = startVideoService(parameters, encrypted);
+ if(streamListener == null){
+ Log.e(TAG, "Error starting video service");
+ stateMachine.transitionToState(StreamingStateMachine.ERROR);
+ return;
+ }
+ VideoStreamingCapability capability = (VideoStreamingCapability) internalInterface.getCapability(SystemCapabilityType.VIDEO_STREAMING);
+ if(capability != null && capability.getIsHapticSpatialDataSupported()){
+ hapticManager = new HapticInterfaceManager(internalInterface);
+ }
+ startEncoder();
+ }
+
+ /**
+ * Initializes and starts the virtual display encoder and creates the remote display
+ */
+ private void startEncoder(){
+ try {
+ virtualDisplayEncoder.init(this.context.get(), streamListener, parameters);
+ //We are all set so we can start streaming at at this point
+ virtualDisplayEncoder.start();
+ //Encoder should be up and running
+ createRemoteDisplay(virtualDisplayEncoder.getVirtualDisplay());
+ stateMachine.transitionToState(StreamingStateMachine.STARTED);
+ } catch (Exception e) {
+ stateMachine.transitionToState(StreamingStateMachine.ERROR);
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Stops streaming from the remote display. To restart, call
+ * @see #resumeStreaming()
+ */
+ public void stopStreaming(){
+ if(remoteDisplay!=null){
+ remoteDisplay.stop();
+ }
+ if(virtualDisplayEncoder!=null){
+ virtualDisplayEncoder.shutDown();
+ }
+ stateMachine.transitionToState(StreamingStateMachine.STOPPED);
+ }
+
+ /**
+ * Resumes streaming after calling
+ * @see #startRemoteDisplayStream(android.content.Context, Class, com.smartdevicelink.streaming.video.VideoStreamingParameters, boolean)
+ * followed by a call to
+ * @see #stopStreaming()
+ */
+ public void resumeStreaming(){
+ if(stateMachine.getState() != StreamingStateMachine.STOPPED){
+ return;
+ }
+ startEncoder();
+ }
+
+ /**
+ * Stops streaming, ends video streaming service and removes service listeners.
+ */
+ @Override
+ public void dispose(){
+ stopStreaming();
+
+ hapticManager = null;
+ remoteDisplay = null;
+ parameters = null;
+ virtualDisplayEncoder = null;
+ if(internalInterface!=null){
+ internalInterface.stopVideoService();
+ }
+
+ // Remove listeners
+ internalInterface.removeServiceListener(SessionType.NAV, serviceListener);
+ internalInterface.removeOnRPCNotificationListener(FunctionID.ON_TOUCH_EVENT, touchListener);
+ internalInterface.removeOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, hmiListener);
+
+ stateMachine.transitionToState(StreamingStateMachine.NONE);
+ super.dispose();
+ }
+
+ // PUBLIC METHODS FOR CHECKING STATE
+
+ /**
+ * Check if a video service is currently active
+ * @return boolean (true = active, false = inactive)
+ */
+ public boolean isServiceActive(){
+ return (stateMachine.getState() == StreamingStateMachine.READY) ||
+ (stateMachine.getState() == StreamingStateMachine.STARTED) ||
+ (stateMachine.getState() == StreamingStateMachine.STOPPED);
+ }
+
+ /**
+ * Check if video is currently streaming and visible
+ * @return boolean (true = yes, false = no)
+ */
+ public boolean isStreaming(){
+ return (stateMachine.getState() == StreamingStateMachine.STARTED) ||
+ (hmiLevel == HMILevel.HMI_FULL);
+ }
+
+ /**
+ * Check if video streaming has been paused due to app moving to background or manually stopped
+ * @return boolean (true = not paused, false = paused)
+ */
+ public boolean isPaused(){
+ return (stateMachine.getState() == StreamingStateMachine.STARTED) ||
+ (hmiLevel != HMILevel.HMI_FULL);
+ }
+
+ /**
+ * Gets the current video streaming state as defined in @StreamingStateMachine
+ * @return int representing StreamingStateMachine.StreamingState
+ */
+ public @StreamingStateMachine.StreamingState int currentVideoStreamState(){
+ return stateMachine.getState();
+ }
+
+ // HELPER METHODS
+
+ private void createRemoteDisplay(final Display disp){
+ try{
+ if (disp == null){
+ return;
+ }
+
+ // Dismiss the current presentation if the display has changed.
+ if (remoteDisplay != null && remoteDisplay.getDisplay() != disp) {
+ remoteDisplay.dismissPresentation();
+ }
+
+ FutureTask<Boolean> fTask = new FutureTask<Boolean>( new SdlRemoteDisplay.Creator(context.get(), disp, remoteDisplay, remoteDisplayClass, new SdlRemoteDisplay.Callback(){
+ @Override
+ public void onCreated(final SdlRemoteDisplay remoteDisplay) {
+ //Remote display has been created.
+ //Now is a good time to do parsing for spatial data
+ VideoStreamManager.this.remoteDisplay = remoteDisplay;
+ if(hapticManager != null) {
+ remoteDisplay.getMainView().post(new Runnable() {
+ @Override
+ public void run() {
+ hapticManager.refreshHapticData(remoteDisplay.getMainView());
+ }
+ });
+ }
+ //Get touch scalars
+ ImageResolution resolution = null;
+ if(internalInterface.getProtocolVersion().getMajor() >= 5){ //At this point we should already have the capability
+ VideoStreamingCapability capability = (VideoStreamingCapability) internalInterface.getCapability(SystemCapabilityType.VIDEO_STREAMING);
+ if(capability != null){
+ resolution = capability.getPreferredResolution();
+ }
+ }
+
+ if(resolution == null){ //Either the protocol version is too low to access video streaming caps, or they were null
+ DisplayCapabilities dispCap = (DisplayCapabilities) internalInterface.getCapability(SystemCapabilityType.DISPLAY);
+ if (dispCap != null) {
+ resolution = (dispCap.getScreenParams().getImageResolution());
+ }
+ }
+
+ if(resolution != null){
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ disp.getMetrics(displayMetrics);
+ touchScalar[0] = ((float)displayMetrics.widthPixels) / resolution.getResolutionWidth();
+ touchScalar[1] = ((float)displayMetrics.heightPixels) / resolution.getResolutionHeight();
+ }
+
+ }
+
+ @Override
+ public void onInvalidated(final SdlRemoteDisplay remoteDisplay) {
+ //Our view has been invalidated
+ //A good time to refresh spatial data
+ if(hapticManager != null) {
+ remoteDisplay.getMainView().post(new Runnable() {
+ @Override
+ public void run() {
+ hapticManager.refreshHapticData(remoteDisplay.getMainView());
+ }
+ });
+ }
+ }
+ } ));
+ Thread showPresentation = new Thread(fTask);
+
+ showPresentation.start();
+ } catch (Exception ex) {
+ Log.e(TAG, "Unable to create Virtual Display.");
+ }
+ }
+
+ protected MotionEvent convertTouchEvent(OnTouchEvent touchEvent){
+ List<TouchEvent> eventList = touchEvent.getEvent();
+ if (eventList == null || eventList.size() == 0) return null;
+
+ TouchType touchType = touchEvent.getType();
+ if (touchType == null){ return null;}
+
+ int eventListSize = eventList.size();
+
+ MotionEvent.PointerProperties[] pointerProperties = new MotionEvent.PointerProperties[eventListSize];
+ MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[eventListSize];
+
+ TouchEvent event;
+ MotionEvent.PointerProperties properties;
+ MotionEvent.PointerCoords coords;
+ TouchCoord touchCoord;
+
+ for(int i = 0; i < eventListSize; i++){
+ event = eventList.get(i);
+ if(event == null || event.getId() == null || event.getTouchCoordinates() == null){
+ continue;
+ }
+
+ properties = new MotionEvent.PointerProperties();
+ properties.id = event.getId();
+ properties.toolType = MotionEvent.TOOL_TYPE_FINGER;
+
+
+ List<TouchCoord> coordList = event.getTouchCoordinates();
+ if (coordList == null || coordList.size() == 0){ continue; }
+
+ touchCoord = coordList.get(coordList.size() -1);
+ if(touchCoord == null){ continue; }
+
+ coords = new MotionEvent.PointerCoords();
+ coords.x = touchCoord.getX() * touchScalar[0];
+ coords.y = touchCoord.getY() * touchScalar[1];
+ coords.orientation = 0;
+ coords.pressure = 1.0f;
+ coords.size = 1;
+
+ //Add the info to lists only after we are sure we have all available info
+ pointerProperties[i] = properties;
+ pointerCoords[i] = coords;
+
+ }
+
+
+ if(sdlMotionEvent == null) {
+ if (touchType == TouchType.BEGIN) {
+ sdlMotionEvent = new SdlMotionEvent();
+ }else{
+ return null;
+ }
+ }
+
+ int eventAction = sdlMotionEvent.getMotionEvent(touchType, pointerProperties);
+ long startTime = sdlMotionEvent.startOfEvent;
+
+ //If the motion event should be finished we should clear our reference
+ if(eventAction == MotionEvent.ACTION_UP || eventAction == MotionEvent.ACTION_CANCEL){
+ sdlMotionEvent = null;
+ }
+
+ return MotionEvent.obtain(startTime, SystemClock.uptimeMillis(), eventAction, eventListSize, pointerProperties, pointerCoords, 0, 0,1,1,0,0, InputDevice.SOURCE_TOUCHSCREEN,0);
+ }
+
+ /**
+ * Keeps track of the current motion event for VPM
+ */
+ private static class SdlMotionEvent{
+ long startOfEvent;
+ SparseIntArray pointerStatuses = new SparseIntArray();
+
+ SdlMotionEvent(){
+ startOfEvent = SystemClock.uptimeMillis();
+ }
+
+ /**
+ * Handles the SDL Touch Event to keep track of pointer status and returns the appropirate
+ * Android MotionEvent according to this events status
+ * @param touchType The SDL TouchType that was received from the module
+ * @param pointerProperties the parsed pointer properties built from the OnTouchEvent RPC
+ * @return the correct native Andorid MotionEvent action to dispatch
+ */
+ synchronized int getMotionEvent(TouchType touchType, MotionEvent.PointerProperties[] pointerProperties){
+ int motionEvent = MotionEvent.ACTION_DOWN;
+ switch (touchType){
+ case BEGIN:
+ if(pointerStatuses.size() == 0){
+ //The motion event has just begun
+ motionEvent = MotionEvent.ACTION_DOWN;
+ }else{
+ motionEvent = MotionEvent.ACTION_POINTER_DOWN;
+ }
+ setPointerStatuses(motionEvent, pointerProperties);
+ break;
+ case MOVE:
+ motionEvent = MotionEvent.ACTION_MOVE;
+ setPointerStatuses(motionEvent, pointerProperties);
+
+ break;
+ case END:
+ //Clears out pointers that have ended
+ setPointerStatuses(MotionEvent.ACTION_UP, pointerProperties);
+
+ if(pointerStatuses.size() == 0){
+ //The motion event has just ended
+ motionEvent = MotionEvent.ACTION_UP;
+ }else{
+ motionEvent = MotionEvent.ACTION_POINTER_UP;
+ }
+ break;
+ case CANCEL:
+ //Assuming this cancels the entire event
+ motionEvent = MotionEvent.ACTION_CANCEL;
+ pointerStatuses.clear();
+ break;
+ default:
+ break;
+ }
+ return motionEvent;
+ }
+
+ private void setPointerStatuses(int motionEvent, MotionEvent.PointerProperties[] pointerProperties){
+
+ for(int i = 0; i < pointerProperties.length; i ++){
+ MotionEvent.PointerProperties properties = pointerProperties[i];
+ if(properties != null){
+ if(motionEvent == MotionEvent.ACTION_UP || motionEvent == MotionEvent.ACTION_POINTER_UP){
+ pointerStatuses.delete(properties.id);
+ }else if(motionEvent == MotionEvent.ACTION_DOWN && properties.id == 0){
+ pointerStatuses.put(properties.id, MotionEvent.ACTION_DOWN);
+ }else{
+ pointerStatuses.put(properties.id, motionEvent);
+ }
+
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onTransportUpdate(List<TransportRecord> connectedTransports, boolean audioStreamTransportAvail, boolean videoStreamTransportAvail){
+
+ isTransportAvailable = videoStreamTransportAvail;
+
+ if(internalInterface.getProtocolVersion().isNewerThan(new Version(5,1,0)) >= 0){
+ if(videoStreamTransportAvail){
+ checkState();
+ }
+ }else{
+ //The protocol version doesn't support simultaneous transports.
+ if(!videoStreamTransportAvail){
+ //If video streaming isn't available on primary transport then it is not possible to
+ //use the video streaming manager until a complete register on a transport that
+ //supports video
+ transitionToState(ERROR);
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/sdl_android/src/main/java/com/smartdevicelink/marshal/JsonRPCMarshaller.java b/sdl_android/src/main/java/com/smartdevicelink/marshal/JsonRPCMarshaller.java
index 414538a19..89f4d1ef7 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/marshal/JsonRPCMarshaller.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/marshal/JsonRPCMarshaller.java
@@ -23,7 +23,12 @@ import com.smartdevicelink.util.DebugTool;
public class JsonRPCMarshaller {
private static final String SDL_LIB_PRIVATE_KEY = "42baba60-eb57-11df-98cf-0800200c9a66";
-
+
+ /**
+ * @param msg RPC message to be marshaled
+ * @param version protocol version
+ * @return byte array of the marshalled message
+ */
public static byte[] marshall(RPCMessage msg, byte version) {
byte[] jsonBytes = null;
try {
@@ -81,7 +86,7 @@ public class JsonRPCMarshaller {
return ret;
}
- @SuppressWarnings("unchecked")
+ @SuppressWarnings("unchecked" )
private static JSONArray serializeList(List<?> list) throws JSONException{
JSONArray toPut = new JSONArray();
Iterator<Object> valueIterator = (Iterator<Object>) list.iterator();
diff --git a/sdl_android/src/main/java/com/smartdevicelink/protocol/AbstractProtocol.java b/sdl_android/src/main/java/com/smartdevicelink/protocol/AbstractProtocol.java
index bb8c7fb6c..043f7e994 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/protocol/AbstractProtocol.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/protocol/AbstractProtocol.java
@@ -1,10 +1,15 @@
package com.smartdevicelink.protocol;
+
import com.smartdevicelink.protocol.WiProProtocol.MessageFrameAssembler;
import com.smartdevicelink.protocol.enums.SessionType;
import java.util.List;
+/**
+ * @see SdlProtocol
+ */
+@Deprecated
public abstract class AbstractProtocol {
private static final String SDL_LIB_TRACE_KEY = "42baba60-eb57-11df-98cf-0800200c9a66";
@@ -92,7 +97,7 @@ public abstract class AbstractProtocol {
//FIXME SdlTrace.logProtocolEvent(InterfaceActivityDirection.Transmit, header, data,
// offset, length, SDL_LIB_TRACE_KEY);
resetOutgoingHeartbeat(SessionType.valueOf((byte)header.getServiceType()), (byte)header.getSessionId());
-
+
synchronized(_frameLock) {
//byte[] frameHeader = header.constructPacket();
@@ -153,4 +158,5 @@ public abstract class AbstractProtocol {
protected void onResetIncomingHeartbeat(SessionType sessionType, byte sessionID) {
resetIncomingHeartbeat(sessionType, sessionID);
}
+
} // end-class
diff --git a/sdl_android/src/main/java/com/smartdevicelink/protocol/IProtocolListener.java b/sdl_android/src/main/java/com/smartdevicelink/protocol/IProtocolListener.java
index 04397b935..e0c6808e1 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/protocol/IProtocolListener.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/protocol/IProtocolListener.java
@@ -1,5 +1,6 @@
package com.smartdevicelink.protocol;
+
import com.smartdevicelink.protocol.enums.*;
import java.util.List;
@@ -39,4 +40,5 @@ public interface IProtocolListener {
// Called to indicate that a protocol error was detected in received data.
void onProtocolError(String info, Exception e);
+
} // end-interfCe
diff --git a/sdl_android/src/main/java/com/smartdevicelink/protocol/ISdlProtocol.java b/sdl_android/src/main/java/com/smartdevicelink/protocol/ISdlProtocol.java
new file mode 100644
index 000000000..beb78a90a
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/protocol/ISdlProtocol.java
@@ -0,0 +1,56 @@
+/*
+ * 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 com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.security.SdlSecurityBase;
+import com.smartdevicelink.streaming.video.VideoStreamingParameters;
+import com.smartdevicelink.transport.MultiplexTransportConfig;
+
+public interface ISdlProtocol extends IProtocolListener {
+
+ byte getSessionId();
+
+ void shutdown(String info);
+
+ void onTransportDisconnected(String info, boolean altTransportAvailable, MultiplexTransportConfig transportConfig);
+
+ SdlSecurityBase getSdlSecurity();
+
+ VideoStreamingParameters getDesiredVideoParams();
+
+ void setAcceptedVideoParams(VideoStreamingParameters acceptedVideoParams);
+
+ void stopStream(SessionType serviceType);
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/protocol/ISecondaryTransportListener.java b/sdl_android/src/main/java/com/smartdevicelink/protocol/ISecondaryTransportListener.java
new file mode 100644
index 000000000..17db7ad11
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/protocol/ISecondaryTransportListener.java
@@ -0,0 +1,8 @@
+package com.smartdevicelink.protocol;
+
+import com.smartdevicelink.transport.utl.TransportRecord;
+
+public interface ISecondaryTransportListener {
+ void onConnectionSuccess(TransportRecord transportRecord);
+ void onConnectionFailure();
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlPacket.java b/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlPacket.java
index cc14cdac7..627463603 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlPacket.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlPacket.java
@@ -5,6 +5,8 @@ import java.util.HashMap;
import com.livio.BSON.BsonEncoder;
import com.smartdevicelink.protocol.enums.FrameType;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
import android.os.Parcel;
import android.os.Parcelable;
@@ -47,7 +49,11 @@ public class SdlPacket implements Parcelable{
public static final int FRAME_INFO_END_SERVICE = 0x04;
public static final int FRAME_INFO_END_SERVICE_ACK = 0x05;
public static final int FRAME_INFO_END_SERVICE_NAK = 0x06;
- //0x07-0xFD are reserved
+ public static final int FRAME_INFO_REGISTER_SECONDARY_TRANSPORT = 0x07;
+ public static final int FRAME_INFO_REGISTER_SECONDARY_TRANSPORT_ACK = 0x08;
+ public static final int FRAME_INFO_REGISTER_SECONDARY_TRANSPORT_NAK = 0x09;
+ //0x0A-0xFC are reserved
+ public static final int FRAME_INFO_TRANSPORT_EVENT_UPDATE = 0xFD;
public static final int FRAME_INFO_SERVICE_DATA_ACK = 0xFE;
public static final int FRAME_INFO_HEART_BEAT_ACK = 0xFF;
@@ -69,6 +75,9 @@ public class SdlPacket implements Parcelable{
byte[] payload = null;
HashMap<String, Object> bsonPayload;
+ int messagingVersion = 1;
+ TransportRecord transportRecord;
+
public SdlPacket(int version, boolean encryption, int frameType,
int serviceType, int frameInfo, int sessionId,
int dataSize, int messageId, byte[] payload) {
@@ -211,6 +220,15 @@ public class SdlPacket implements Parcelable{
public int getPrioirtyCoefficient(){
return this.priorityCoefficient;
}
+
+ public void setTransportRecord(TransportRecord transportRecord){
+ this.transportRecord = transportRecord;
+ }
+
+ public TransportRecord getTransportRecord() {
+ return this.transportRecord;
+ }
+
/**
* This method takes in the various components to the SDL packet structure and creates a new byte array that can be sent via the transport
* @param version
@@ -292,6 +310,10 @@ public class SdlPacket implements Parcelable{
return builder.toString();
}
+
+ public void setMessagingVersion(int version){
+ this.messagingVersion = version;
+ }
@@ -300,6 +322,7 @@ public class SdlPacket implements Parcelable{
*****************************************************************************************************************************************************/
+
//I think this is FIFO...right?
public SdlPacket(Parcel p) {
this.version = p.readInt();
@@ -314,7 +337,17 @@ public class SdlPacket implements Parcelable{
payload = new byte[dataSize];
p.readByteArray(payload);
}
+
this.priorityCoefficient = p.readInt();
+
+ if(p.dataAvail() > 0) {
+ messagingVersion = p.readInt();
+ if(messagingVersion >= 2) {
+ if (p.readInt() == 1) { //We should have a transport type attached
+ this.transportRecord = p.readParcelable(TransportRecord.class.getClassLoader());
+ }
+ }
+ }
}
@@ -340,6 +373,16 @@ public class SdlPacket implements Parcelable{
}
dest.writeInt(priorityCoefficient);
+ ///Additions after initial creation
+ if(messagingVersion > 1){
+ dest.writeInt(messagingVersion);
+
+ dest.writeInt(transportRecord!=null? 1 : 0);
+ if(transportRecord != null){
+ dest.writeParcelable(transportRecord,0);
+ }
+ }
+
}
public static final Parcelable.Creator<SdlPacket> CREATOR = new Parcelable.Creator<SdlPacket>() {
diff --git a/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlPacketFactory.java b/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlPacketFactory.java
index 5cc2807e8..31898175c 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlPacketFactory.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlPacketFactory.java
@@ -77,7 +77,12 @@ public class SdlPacketFactory {
serviceType.getValue(),frameSequenceNumber,sessionID,
length,messageID,payload,offset,length);
}
-
+
+ public static SdlPacket createRegisterSecondaryTransport(byte sessionID, byte version) {
+ return new SdlPacket(version, false, SdlPacket.FRAME_TYPE_CONTROL,
+ SessionType.CONTROL.getValue(), SdlPacket.FRAME_INFO_REGISTER_SECONDARY_TRANSPORT,
+ sessionID, 0, 0x01, null);
+ }
public static BinaryFrameHeader createBinaryFrameHeader(byte rpcType, int functionID, int corrID, int jsonSize) {
BinaryFrameHeader msg = new BinaryFrameHeader();
diff --git a/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java b/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java
new file mode 100644
index 000000000..4ca01ac5b
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java
@@ -0,0 +1,1437 @@
+/*
+ * 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 android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import com.smartdevicelink.exception.SdlException;
+import com.smartdevicelink.exception.SdlExceptionCause;
+import com.smartdevicelink.protocol.enums.ControlFrameTags;
+import com.smartdevicelink.protocol.enums.FrameDataControlFrameType;
+import com.smartdevicelink.protocol.enums.FrameType;
+import com.smartdevicelink.protocol.enums.MessageType;
+import com.smartdevicelink.protocol.enums.SessionType;
+import com.smartdevicelink.proxy.rpc.ImageResolution;
+import com.smartdevicelink.proxy.rpc.VideoStreamingFormat;
+import com.smartdevicelink.proxy.rpc.enums.VideoStreamingCodec;
+import com.smartdevicelink.proxy.rpc.enums.VideoStreamingProtocol;
+import com.smartdevicelink.security.SdlSecurityBase;
+import com.smartdevicelink.streaming.video.VideoStreamingParameters;
+import com.smartdevicelink.transport.MultiplexTransportConfig;
+import com.smartdevicelink.transport.TransportConstants;
+import com.smartdevicelink.transport.TransportManager;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
+import com.smartdevicelink.util.BitConverter;
+import com.smartdevicelink.util.DebugTool;
+import com.smartdevicelink.util.Version;
+
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+@SuppressWarnings("WeakerAccess")
+public class SdlProtocol {
+ private static final String TAG ="SdlProtocol";
+ private final static String FailurePropagating_Msg = "Failure propagating ";
+
+ private static final int TLS_MAX_RECORD_SIZE = 16384;
+
+ private static final int PRIMARY_TRANSPORT_ID = 1;
+ private static final int SECONDARY_TRANSPORT_ID = 2;
+
+ /**
+ * Original header size based on version 1.0.0 only
+ */
+ public static final int V1_HEADER_SIZE = 8;
+ /**
+ * Larger header size that is used by versions 2.0.0 and up
+ */
+ public static final int V2_HEADER_SIZE = 12;
+
+ //If increasing MAX PROTOCOL VERSION major version, make sure to alter it in SdlPsm
+ private static final Version MAX_PROTOCOL_VERSION = new Version("5.1.0");
+
+ public static final int V1_V2_MTU_SIZE = 1500;
+ public static final int V3_V4_MTU_SIZE = 131072;
+
+ private static final List<SessionType> HIGH_BANDWIDTH_SERVICES
+ = Arrays.asList(SessionType.NAV, SessionType.PCM);
+
+ // Lock to ensure all frames are sent uninterrupted
+ private final Object FRAME_LOCK = new Object();
+
+ private final ISdlProtocol iSdlProtocol;
+ private final MultiplexTransportConfig transportConfig;
+ private final Hashtable<Integer, MessageFrameAssembler> _assemblerForMessageID = new Hashtable<>();
+ private final Hashtable<Byte, Object> _messageLocks = new Hashtable<>();
+ private final HashMap<SessionType, Long> mtus = new HashMap<>();
+ private final HashMap<SessionType, TransportRecord> activeTransports = new HashMap<>();
+ private final Map<TransportType, List<ISecondaryTransportListener>> secondaryTransportListeners = new HashMap<>();
+
+
+ private TransportManager transportManager;
+ private Version protocolVersion = new Version("1.0.0");
+ private int hashID = 0;
+ private int messageID = 0;
+ private int headerSize = V1_HEADER_SIZE;
+
+ /**
+ * Requested transports for primary and secondary
+ */
+ List<TransportType> requestedPrimaryTransports, requestedSecondaryTransports;
+
+ /**
+ * List of secondary transports supported by the module
+ */
+ List<TransportType> supportedSecondaryTransports;
+
+ /**
+ * Holds the priority of transports for a specific service when that service can be started
+ * on a primary or secondary transport.
+ */
+ Map<SessionType, List<Integer>> transportPriorityForServiceMap;
+ boolean requiresHighBandwidth;
+ Map<TransportType, Bundle> secondaryTransportParams;
+ TransportRecord connectedPrimaryTransport;
+
+
+ @SuppressWarnings("ConstantConditions")
+ public SdlProtocol(@NonNull ISdlProtocol iSdlProtocol, @NonNull MultiplexTransportConfig config) {
+ if (iSdlProtocol == null ) {
+ throw new IllegalArgumentException("Provided protocol listener interface reference is null");
+ } // end-if
+
+ this.iSdlProtocol = iSdlProtocol;
+ this.transportConfig = config;
+ this.requestedPrimaryTransports = this.transportConfig.getPrimaryTransports();
+ this.requestedSecondaryTransports = this.transportConfig.getSecondaryTransports();
+ this.requiresHighBandwidth = this.transportConfig.requiresHighBandwidth();
+ this.transportManager = new TransportManager(transportConfig, transportEventListener);
+
+
+ mtus.put(SessionType.RPC, (long) (V1_V2_MTU_SIZE - headerSize));
+ } // end-ctor
+
+
+ public void start(){
+ transportManager.start();
+
+ }
+ /**
+ * Retrieves the max payload size for a packet to be sent to the module
+ * @return the max transfer unit
+ */
+ public int getMtu(){
+ return mtus.get(SessionType.RPC).intValue();
+ }
+
+ public long getMtu(SessionType type){
+ Long mtu = mtus.get(type);
+ if(mtu == null){
+ mtu = mtus.get(SessionType.RPC);
+ }
+ return mtu;
+ }
+
+ public boolean isConnected(){
+ return transportManager != null && transportManager.isConnected(null,null);
+ }
+
+ /**
+ * Resets the protocol to init status
+ */
+ protected void reset(){
+ protocolVersion = new Version("1.0.0");
+ hashID = 0;
+ messageID = 0;
+ headerSize = V1_HEADER_SIZE;
+ this.activeTransports.clear();
+ this.mtus.clear();
+ mtus.put(SessionType.RPC, (long) (V1_V2_MTU_SIZE - headerSize));
+ this.secondaryTransportParams = null;
+ this._assemblerForMessageID.clear();
+ this._messageLocks.clear();
+ }
+
+ /**
+ * For logging purposes, prints active services on each connected transport
+ */
+ protected void printActiveTransports(){
+ StringBuilder activeTransportString = new StringBuilder();
+ activeTransportString.append("Active transports --- \n");
+
+ for(Map.Entry entry : activeTransports.entrySet()){
+ String sessionString = null;
+ if(entry.getKey().equals(SessionType.NAV)) {
+ sessionString = "NAV";
+ }else if(entry.getKey().equals(SessionType.PCM)) {
+ sessionString = "PCM";
+ }else if(entry.getKey().equals(SessionType.RPC)) {
+ sessionString = "RPC";
+ }
+ if(sessionString != null){
+ activeTransportString.append("Session: ");
+
+ activeTransportString.append(sessionString);
+ activeTransportString.append(" Transport: ");
+ activeTransportString.append(entry.getValue().toString());
+ activeTransportString.append("\n");
+ }
+ }
+ Log.d(TAG, activeTransportString.toString());
+ }
+
+ protected void printSecondaryTransportDetails(List<String> secondary, List<Integer> audio, List<Integer> video){
+ StringBuilder secondaryDetailsBldr = new StringBuilder();
+ secondaryDetailsBldr.append("Checking secondary transport details \n");
+
+ if(secondary != null){
+ secondaryDetailsBldr.append("Supported secondary transports: ");
+ for(String s : secondary){
+ secondaryDetailsBldr.append(" ").append(s);
+ }
+ secondaryDetailsBldr.append("\n");
+ }else{
+ Log.d(TAG, "Supported secondary transports list is empty!");
+ }
+ if(audio != null){
+ secondaryDetailsBldr.append("Supported audio transports: ");
+ for(int a : audio){
+ secondaryDetailsBldr.append(" ").append(a);
+ }
+ secondaryDetailsBldr.append("\n");
+ }
+ if(video != null){
+ secondaryDetailsBldr.append("Supported video transports: ");
+ for(int v : video){
+ secondaryDetailsBldr.append(" ").append(v);
+ }
+ secondaryDetailsBldr.append("\n");
+ }
+
+ Log.d(TAG, secondaryDetailsBldr.toString());
+ }
+
+
+ private TransportRecord getTransportForSession(SessionType type){
+ return activeTransports.get(type);
+ }
+
+ private void setTransportPriorityForService(SessionType serviceType, List<Integer> order){
+ if(transportPriorityForServiceMap == null){
+ transportPriorityForServiceMap = new HashMap<>();
+ }
+ this.transportPriorityForServiceMap.put(serviceType, order);
+ for(SessionType service : HIGH_BANDWIDTH_SERVICES){
+ if (transportPriorityForServiceMap.get(service) != null
+ && transportPriorityForServiceMap.get(service).contains(PRIMARY_TRANSPORT_ID)) {
+ if(connectedPrimaryTransport != null) {
+ activeTransports.put(service, connectedPrimaryTransport);
+ }
+ }
+ }
+ }
+
+ /**
+ * Handles when a secondary transport can be used to start services on or when the request as failed.
+ * @param transportRecord the transport type that the event has taken place on
+ * @param registered if the transport was successfully registered on
+ */
+ private void handleSecondaryTransportRegistration(TransportRecord transportRecord, boolean registered){
+ if(registered) {
+ //Session has been registered on secondary transport
+ Log.d(TAG, transportRecord.getType().toString() + " transport was registered!");
+ if (supportedSecondaryTransports.contains(transportRecord.getType())) {
+ // If the transport type that is now available to be used it should be checked
+ // against the list of services that might be able to be started on it
+
+ for(SessionType secondaryService : HIGH_BANDWIDTH_SERVICES){
+ if (transportPriorityForServiceMap.containsKey(secondaryService)) {
+ // If this service type has extra information from the RPC StartServiceACK
+ // parse through it to find which transport should be used to start this
+ // specific service type
+ for(int transportNum : transportPriorityForServiceMap.get(secondaryService)){
+ if(transportNum == PRIMARY_TRANSPORT_ID){
+ break; // Primary is favored for this service type, break out...
+ }else if(transportNum == SECONDARY_TRANSPORT_ID){
+ // The secondary transport can be used to start this service
+ activeTransports.put(secondaryService, transportRecord);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }else{
+ Log.d(TAG, transportRecord.toString() + " transport was NOT registered!");
+ }
+ //Notify any listeners for this secondary transport
+ List<ISecondaryTransportListener> listenerList = secondaryTransportListeners.remove(transportRecord.getType());
+ if(listenerList != null){
+ for(ISecondaryTransportListener listener : listenerList){
+ if(registered) {
+ listener.onConnectionSuccess(transportRecord);
+ }else{
+ listener.onConnectionFailure();
+ }
+ }
+ }
+
+ if(DebugTool.isDebugEnabled()){
+ printActiveTransports();
+ }
+ }
+
+ private void onTransportsConnectedUpdate(List<TransportRecord> transports){
+ //Log.d(TAG, "Connected transport update");
+
+ //Temporary: this logic should all be changed to handle multiple transports of the same type
+ ArrayList<TransportType> connectedTransports = new ArrayList<>();
+ if(transports != null) {
+ for (TransportRecord record : transports) {
+ connectedTransports.add(record.getType());
+ }
+ }
+
+ if(connectedPrimaryTransport != null && !connectedTransports.contains(connectedPrimaryTransport.getType())){
+ //The primary transport being used is no longer part of the connected transports
+ //The transport manager callbacks should handle the disconnect code
+ connectedPrimaryTransport = null;
+ notifyDevTransportListener();
+ return;
+ }
+
+ if(activeTransports.get(SessionType.RPC) == null){
+ //There is no currently active transport for the RPC service meaning no primary transport
+ TransportRecord preferredPrimaryTransport = getPreferredTransport(requestedPrimaryTransports,transports);
+ if(preferredPrimaryTransport != null) {
+ connectedPrimaryTransport = preferredPrimaryTransport;
+ startService(SessionType.RPC, (byte) 0x00, false);
+ }else{
+ onTransportNotAccepted("No transports match requested primary transport");
+ }
+ //Return to that the developer does not receive the transport callback at this time
+ // as it is better to wait until the RPC service is registered and secondary transport
+ //information is available
+ return;
+ }else if(secondaryTransportListeners != null
+ && transports != null
+ && iSdlProtocol!= null){
+ // Check to see if there is a listener for a given transport.
+ // If a listener exists, it can be assumed that the transport should be registered on
+ for(TransportRecord record: transports){
+ if(secondaryTransportListeners.get(record.getType()) != null
+ && !secondaryTransportListeners.get(record.getType()).isEmpty()){
+ registerSecondaryTransport(iSdlProtocol.getSessionId(), record);
+ }
+ }
+ }
+ //Update the developer that a new transport has become available
+ notifyDevTransportListener();
+ }
+
+
+ /**
+ * Check to see if a transport is available to start/use the supplied service.
+ * @param serviceType the session that should be checked for transport availability
+ * @return true if there is either a supported
+ * transport currently connected or a transport is
+ * available to connect with for the supplied service type.
+ * <br>false if there is no
+ * transport connected to support the service type in question and
+ * no possibility in the foreseeable future.
+ */
+ public boolean isTransportForServiceAvailable(@NonNull SessionType serviceType){
+ if(connectedPrimaryTransport == null){
+ //If there is no connected primary then there is no transport available for any service
+ return false;
+ }else if(activeTransports!= null && activeTransports.containsKey(serviceType)){
+ //There is an active transport that this service can be used on
+ //This should catch RPC, Bulk, and Control service types
+ return true;
+ }
+
+ if(transportPriorityForServiceMap != null) {
+ List<Integer> transportPriority = transportPriorityForServiceMap.get(serviceType);
+
+ if (transportPriority != null && !transportPriority.isEmpty()) {
+ if (transportPriority.contains(PRIMARY_TRANSPORT_ID)) {
+ //If the transport priority for this service type contains primary then
+ // the service can be used/started
+ return true;
+ } else if (transportPriority.contains(SECONDARY_TRANSPORT_ID)) {
+ //This would mean only secondary transport is supported for this service
+ return isSecondaryTransportAvailable(false);
+ }
+ }
+ }
+
+ //No transport priority for this service type
+ if(connectedPrimaryTransport.getType() == TransportType.USB || connectedPrimaryTransport.getType() == TransportType.TCP){
+ //Since the only service type that should reach this point are ones that require a high
+ //bandwidth, true can be returned if the primary transport is a high bandwidth transport
+ return true;
+ }else{
+ //Since the only service type that should reach this point are ones that require a high
+ //bandwidth, true can be returned if a secondary transport is a high bandwidth transport
+ return isSecondaryTransportAvailable(true);
+ }
+ }
+
+ /**
+ * Checks to see if a secondary transport is available for this session
+ * @param onlyHighBandwidth if only high bandwidth transports should be included in this check
+ * @return true if any connected or potential transport meets the criteria to be a secondary
+ * transport
+ */
+ private boolean isSecondaryTransportAvailable(boolean onlyHighBandwidth){
+ if (supportedSecondaryTransports != null) {
+ for (TransportType supportedSecondary : supportedSecondaryTransports) {
+ if(!onlyHighBandwidth || supportedSecondary == TransportType.USB || supportedSecondary == TransportType.TCP) {
+ if (transportManager.isConnected(supportedSecondary, null)) {
+ //A supported secondary transport is already connected
+ return true;
+ } else if (secondaryTransportParams != null && secondaryTransportParams.containsKey(supportedSecondary)) {
+ //A secondary transport is available to connect to
+ return true;
+ }
+ }
+ }
+ }
+ // No supported secondary transports
+ return false;
+ }
+
+
+ /**
+ * If there was a TransportListener attached to the supplied multiplex config, this method will
+ * call the onTransportEvent method.
+ */
+ private void notifyDevTransportListener (){
+ if(transportConfig.getTransportListener() != null && transportManager != null) {
+ transportConfig.getTransportListener().onTransportEvent(transportManager.getConnectedTransports(), isTransportForServiceAvailable(SessionType.PCM),isTransportForServiceAvailable(SessionType.NAV));
+ }
+ }
+
+ /**
+ * Retrieves the preferred transport for the given connected transport
+ * @param preferredList the list of preferred transports (primary or secondary)
+ * @param connectedTransports the current list of connected transports
+ * @return the preferred connected transport
+ */
+ private TransportRecord getPreferredTransport(List<TransportType> preferredList, List<TransportRecord> connectedTransports) {
+ for (TransportType transportType : preferredList) {
+ for(TransportRecord record: connectedTransports) {
+ if (record.getType().equals(transportType)) {
+ return record;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void onTransportNotAccepted(String info){
+ if(iSdlProtocol != null) {
+ iSdlProtocol.shutdown(info);
+ }
+ }
+
+
+ public Version getProtocolVersion(){
+ return this.protocolVersion;
+ }
+
+ /**
+ * This method will set the major protocol version that we should use. It will also set the default MTU based on version.
+ * @param version major version to use
+ */
+ protected void setVersion(byte version) {
+ if (version > 5) {
+ this.protocolVersion = new Version("5.0.0"); //protect for future, proxy only supports v5 or lower
+ headerSize = V2_HEADER_SIZE;
+ mtus.put(SessionType.RPC, (long) V3_V4_MTU_SIZE);
+ } else if (version == 5) {
+ this.protocolVersion = new Version("5.0.0");
+ headerSize = V2_HEADER_SIZE;
+ mtus.put(SessionType.RPC, (long) V3_V4_MTU_SIZE);
+ }else if (version == 4) {
+ this.protocolVersion = new Version("4.0.0");
+ headerSize = V2_HEADER_SIZE;
+ mtus.put(SessionType.RPC, (long) V3_V4_MTU_SIZE); //versions 4 supports 128k MTU
+ } else if (version == 3) {
+ this.protocolVersion = new Version("3.0.0");
+ headerSize = V2_HEADER_SIZE;
+ mtus.put(SessionType.RPC, (long) V3_V4_MTU_SIZE); //versions 3 supports 128k MTU
+ } else if (version == 2) {
+ this.protocolVersion = new Version("2.0.0");
+ headerSize = V2_HEADER_SIZE;
+ mtus.put(SessionType.RPC, (long) (V1_V2_MTU_SIZE - headerSize));
+ } else if (version == 1){
+ this.protocolVersion = new Version("1.0.0");
+ headerSize = V1_HEADER_SIZE;
+ mtus.put(SessionType.RPC, (long) (V1_V2_MTU_SIZE - headerSize));
+ }
+ }
+
+ public void endSession(byte sessionID, int hashId) {
+ SdlPacket header;
+ if(protocolVersion.getMajor() < 5){
+ header = SdlPacketFactory.createEndSession(SessionType.RPC, sessionID, hashId, (byte)protocolVersion.getMajor(), BitConverter.intToByteArray(hashId));
+ }else{
+ header = SdlPacketFactory.createEndSession(SessionType.RPC, sessionID, hashId, (byte)protocolVersion.getMajor(), new byte[0]);
+ header.putTag(ControlFrameTags.RPC.EndService.HASH_ID, hashId);
+ }
+
+ handlePacketToSend(header);
+
+ } // end-method
+
+ public void sendPacket(SdlPacket packet){
+ if(transportManager != null){
+ transportManager.sendPacket(packet);
+ }
+ }
+
+ public void sendMessage(ProtocolMessage protocolMsg) {
+ protocolMsg.setRPCType((byte) 0x00); //always sending a request
+ SessionType sessionType = protocolMsg.getSessionType();
+ byte sessionID = protocolMsg.getSessionID();
+
+ byte[] data;
+ if (protocolVersion.getMajor() > 1 && sessionType != SessionType.NAV && sessionType != SessionType.PCM) {
+ if (sessionType.eq(SessionType.CONTROL)) {
+ final byte[] secureData = protocolMsg.getData().clone();
+ data = new byte[headerSize + secureData.length];
+
+ final BinaryFrameHeader binFrameHeader =
+ SdlPacketFactory.createBinaryFrameHeader(protocolMsg.getRPCType(),protocolMsg.getFunctionID(), protocolMsg.getCorrID(), 0);
+ System.arraycopy(binFrameHeader.assembleHeaderBytes(), 0, data, 0, headerSize);
+ System.arraycopy(secureData, 0, data, headerSize, secureData.length);
+ }
+ else if (protocolMsg.getBulkData() != null) {
+ data = new byte[12 + protocolMsg.getJsonSize() + protocolMsg.getBulkData().length];
+ sessionType = SessionType.BULK_DATA;
+ } else {
+ data = new byte[12 + protocolMsg.getJsonSize()];
+ }
+ if (!sessionType.eq(SessionType.CONTROL)) {
+ BinaryFrameHeader binFrameHeader = SdlPacketFactory.createBinaryFrameHeader(protocolMsg.getRPCType(), protocolMsg.getFunctionID(), protocolMsg.getCorrID(), protocolMsg.getJsonSize());
+ System.arraycopy(binFrameHeader.assembleHeaderBytes(), 0, data, 0, 12);
+ System.arraycopy(protocolMsg.getData(), 0, data, 12, protocolMsg.getJsonSize());
+ if (protocolMsg.getBulkData() != null) {
+ System.arraycopy(protocolMsg.getBulkData(), 0, data, 12 + protocolMsg.getJsonSize(), protocolMsg.getBulkData().length);
+ }
+ }
+ } else {
+ data = protocolMsg.getData();
+ }
+
+ if (iSdlProtocol != null && protocolMsg.getPayloadProtected()){
+
+ if (data != null && data.length > 0) {
+ byte[] dataToRead = new byte[TLS_MAX_RECORD_SIZE];
+ SdlSecurityBase sdlSec = iSdlProtocol.getSdlSecurity();
+ if (sdlSec == null)
+ return;
+
+ Integer iNumBytes = sdlSec.encryptData(data, dataToRead);
+ if ((iNumBytes == null) || (iNumBytes <= 0))
+ return;
+
+ byte[] encryptedData = new byte[iNumBytes];
+ System.arraycopy(dataToRead, 0, encryptedData, 0, iNumBytes);
+ data = encryptedData;
+ }
+ }
+
+ // Get the message lock for this protocol session
+ Object messageLock = _messageLocks.get(sessionID);
+ if (messageLock == null) {
+ handleProtocolError("Error sending protocol message to SDL.",
+ new SdlException("Attempt to send protocol message prior to startSession ACK.", SdlExceptionCause.SDL_UNAVAILABLE));
+ return;
+ }
+
+ synchronized(messageLock) {
+ if (data.length > getMtu(sessionType)) {
+
+ messageID++;
+
+ // Assemble first frame.
+ Long mtu = getMtu(sessionType);
+ int frameCount = Long.valueOf(data.length / mtu).intValue();
+ if (data.length % mtu > 0) {
+ frameCount++;
+ }
+ byte[] firstFrameData = new byte[8];
+ // First four bytes are data size.
+ System.arraycopy(BitConverter.intToByteArray(data.length), 0, firstFrameData, 0, 4);
+ // Second four bytes are frame count.
+ System.arraycopy(BitConverter.intToByteArray(frameCount), 0, firstFrameData, 4, 4);
+
+ SdlPacket firstHeader = SdlPacketFactory.createMultiSendDataFirst(sessionType, sessionID, messageID, (byte)protocolVersion.getMajor(),firstFrameData,protocolMsg.getPayloadProtected());
+ firstHeader.setPriorityCoefficient(1+protocolMsg.priorityCoefficient);
+ firstHeader.setTransportRecord(activeTransports.get(sessionType));
+ //Send the first frame
+ handlePacketToSend(firstHeader);
+
+ int currentOffset = 0;
+ byte frameSequenceNumber = 0;
+
+ for (int i = 0; i < frameCount; i++) {
+ if (i < (frameCount - 1)) {
+ ++frameSequenceNumber;
+ if (frameSequenceNumber ==
+ SdlPacket.FRAME_INFO_FINAL_CONNESCUTIVE_FRAME) {
+ // we can't use 0x00 as frameSequenceNumber, because
+ // it's reserved for the last frame
+ ++frameSequenceNumber;
+ }
+ } else {
+ frameSequenceNumber = SdlPacket.FRAME_INFO_FINAL_CONNESCUTIVE_FRAME;
+ } // end-if
+
+ int bytesToWrite = data.length - currentOffset;
+ if (bytesToWrite > mtu) {
+ bytesToWrite = mtu.intValue();
+ }
+ SdlPacket consecHeader = SdlPacketFactory.createMultiSendDataRest(sessionType, sessionID, bytesToWrite, frameSequenceNumber , messageID, (byte)protocolVersion.getMajor(),data, currentOffset, bytesToWrite, protocolMsg.getPayloadProtected());
+ consecHeader.setTransportRecord(activeTransports.get(sessionType));
+ consecHeader.setPriorityCoefficient(i+2+protocolMsg.priorityCoefficient);
+ handlePacketToSend(consecHeader);
+ currentOffset += bytesToWrite;
+ }
+ } else {
+ messageID++;
+ SdlPacket header = SdlPacketFactory.createSingleSendData(sessionType, sessionID, data.length, messageID, (byte)protocolVersion.getMajor(),data, protocolMsg.getPayloadProtected());
+ header.setPriorityCoefficient(protocolMsg.priorityCoefficient);
+ header.setTransportRecord(activeTransports.get(sessionType));
+ handlePacketToSend(header);
+ }
+ }
+ }
+
+ protected void handlePacketReceived(SdlPacket packet){
+ //Check for a version difference
+ if (protocolVersion == null || protocolVersion.getMajor() == 1) {
+ setVersion((byte)packet.version);
+ }
+
+ MessageFrameAssembler assembler = getFrameAssemblerForFrame(packet);
+ assembler.handleFrame(packet);
+
+ }
+
+
+ protected MessageFrameAssembler getFrameAssemblerForFrame(SdlPacket packet) {
+ Integer iSessionId = packet.getSessionId();
+ Byte bySessionId = iSessionId.byteValue();
+
+ MessageFrameAssembler ret = _assemblerForMessageID.get(packet.getMessageId());
+ if (ret == null) {
+ ret = new MessageFrameAssembler();
+ _assemblerForMessageID.put(packet.getMessageId(), ret);
+ } // end-if
+
+ return ret;
+ } // end-method
+
+
+
+ private void registerSecondaryTransport(byte sessionId, TransportRecord transportRecord) {
+ SdlPacket header = SdlPacketFactory.createRegisterSecondaryTransport(sessionId, (byte)protocolVersion.getMajor());
+ header.setTransportRecord(transportRecord);
+ handlePacketToSend(header);
+ }
+
+ public void startService(SessionType serviceType, byte sessionID, boolean isEncrypted) {
+ final SdlPacket header = SdlPacketFactory.createStartSession(serviceType, 0x00, (byte)protocolVersion.getMajor(), sessionID, isEncrypted);
+ if(SessionType.RPC.equals(serviceType)){
+ if(connectedPrimaryTransport != null) {
+ header.setTransportRecord(connectedPrimaryTransport);
+ }
+ //This is going to be our primary transport
+ header.putTag(ControlFrameTags.RPC.StartService.PROTOCOL_VERSION, MAX_PROTOCOL_VERSION.toString());
+ handlePacketToSend(header);
+ return; // We don't need to go any further
+ }else if(serviceType.equals(SessionType.NAV)){
+ if(iSdlProtocol != null){
+ VideoStreamingParameters videoStreamingParameters = iSdlProtocol.getDesiredVideoParams();
+ if(videoStreamingParameters != null) {
+ ImageResolution desiredResolution = videoStreamingParameters.getResolution();
+ VideoStreamingFormat desiredFormat = videoStreamingParameters.getFormat();
+ if (desiredResolution != null) {
+ header.putTag(ControlFrameTags.Video.StartService.WIDTH, desiredResolution.getResolutionWidth());
+ header.putTag(ControlFrameTags.Video.StartService.HEIGHT, desiredResolution.getResolutionHeight());
+ }
+ if (desiredFormat != null) {
+ header.putTag(ControlFrameTags.Video.StartService.VIDEO_CODEC, desiredFormat.getCodec().toString());
+ header.putTag(ControlFrameTags.Video.StartService.VIDEO_PROTOCOL, desiredFormat.getProtocol().toString());
+ }
+ }
+ }
+ }
+ if(transportPriorityForServiceMap == null
+ || transportPriorityForServiceMap.get(serviceType) == null
+ || transportPriorityForServiceMap.get(serviceType).isEmpty()){
+ //If there is no transport priority for this service it can be assumed it's primary
+ header.setTransportRecord(connectedPrimaryTransport);
+ handlePacketToSend(header);
+ return;
+ }
+ int transportPriority = transportPriorityForServiceMap.get(serviceType).get(0);
+ if(transportPriority == PRIMARY_TRANSPORT_ID){
+ // Primary is favored, and we're already connected...
+ header.setTransportRecord(connectedPrimaryTransport);
+ handlePacketToSend(header);
+ }else if(transportPriority == SECONDARY_TRANSPORT_ID) {
+ // Secondary is favored
+ for(TransportType secondaryTransportType : supportedSecondaryTransports) {
+
+ if(!requestedSecondaryTransports.contains(secondaryTransportType)){
+ // Secondary transport is not accepted by the client
+ continue;
+ }
+
+ if(activeTransports.get(serviceType) != null
+ && activeTransports.get(serviceType).getType() !=null
+ && activeTransports.get(serviceType).getType().equals(secondaryTransportType)){
+ // Transport is already active and accepted
+ header.setTransportRecord(activeTransports.get(serviceType));
+ handlePacketToSend(header);
+ return;
+ }
+
+
+
+ //If the secondary transport isn't connected yet that will have to be performed first
+
+ List<ISecondaryTransportListener> listenerList = secondaryTransportListeners.get(secondaryTransportType);
+ if(listenerList == null){
+ listenerList = new ArrayList<>();
+ secondaryTransportListeners.put(secondaryTransportType, listenerList);
+ }
+
+ //Check to see if the primary transport can also be used as a backup
+ final boolean primaryTransportBackup = transportPriorityForServiceMap.get(serviceType).contains(PRIMARY_TRANSPORT_ID);
+
+ ISecondaryTransportListener secondaryListener = new ISecondaryTransportListener() {
+ @Override
+ public void onConnectionSuccess(TransportRecord transportRecord) {
+ header.setTransportRecord(transportRecord);
+ handlePacketToSend(header);
+ }
+
+ @Override
+ public void onConnectionFailure() {
+ if(primaryTransportBackup) {
+ // Primary is also supported as backup
+ header.setTransportRecord(connectedPrimaryTransport);
+ handlePacketToSend(header);
+ }else{
+ Log.d(TAG, "Failed to connect secondary transport, threw away StartService");
+ }
+ }
+ };
+
+ if(transportManager.isConnected(secondaryTransportType,null)){
+ //The transport is actually connected, however no service has been registered
+ listenerList.add(secondaryListener);
+ registerSecondaryTransport(sessionID,transportManager.getTransportRecord(secondaryTransportType,null));
+ }else if(secondaryTransportParams != null && secondaryTransportParams.containsKey(secondaryTransportType)) {
+ //No acceptable secondary transport is connected, so first one must be connected
+ header.setTransportRecord(new TransportRecord(secondaryTransportType,""));
+ listenerList.add(secondaryListener);
+ transportManager.requestSecondaryTransportConnection(sessionID,secondaryTransportParams.get(secondaryTransportType));
+ }else{
+ Log.w(TAG, "No params to connect to secondary transport");
+ //Unable to register or start a secondary connection. Use the callback in case
+ //there is a chance to use the primary transport for this service.
+ secondaryListener.onConnectionFailure();
+ }
+
+ }
+ }
+ }
+
+ private void sendHeartBeatACK(SessionType sessionType, byte sessionID) {
+ final SdlPacket heartbeat = SdlPacketFactory.createHeartbeatACK(SessionType.CONTROL, sessionID, (byte)protocolVersion.getMajor());
+ heartbeat.setTransportRecord(activeTransports.get(sessionType));
+ handlePacketToSend(heartbeat);
+ }
+
+ public void endService(SessionType serviceType, byte sessionID) {
+ if(serviceType.equals(SessionType.RPC)){ //RPC session will close all other sessions so we want to make sure we use the correct EndProtocolSession method
+ endSession(sessionID,hashID);
+ }else {
+ SdlPacket header = SdlPacketFactory.createEndSession(serviceType, sessionID, hashID, (byte)protocolVersion.getMajor(), new byte[0]);
+ TransportRecord transportRecord = activeTransports.get(serviceType);
+ if(transportRecord != null){
+ header.setTransportRecord(transportRecord);
+ handlePacketToSend(header);
+ }
+ }
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ ----------------------------------- OLD ABSTRACT PROTOCOL ---------------------------------
+ -------------------------------------------------------------------------------------------*/
+
+
+ // This method is called whenever a protocol has an entire frame to send
+ /**
+ * SdlPacket should have included payload at this point.
+ * @param packet packet that will be sent to the router service
+ */
+ protected void handlePacketToSend(SdlPacket packet) {
+ synchronized(FRAME_LOCK) {
+
+ if(packet!=null){
+ iSdlProtocol.onProtocolMessageBytesToSend(packet);
+ }
+
+ }
+ }
+
+ /** This method handles the end of a protocol session. A callback is
+ * sent to the protocol listener.
+ **/
+ protected void handleServiceEndedNAK(SdlPacket packet, SessionType serviceType) {
+ if(packet.version >= 5){
+ if(DebugTool.isDebugEnabled()) {
+ //Currently this is only during a debugging session. Might pass back in the future
+ String rejectedTag = null;
+ if (serviceType.equals(SessionType.RPC)) {
+ rejectedTag = ControlFrameTags.RPC.EndServiceNAK.REJECTED_PARAMS;
+ } else if (serviceType.equals(SessionType.PCM)) {
+ rejectedTag = ControlFrameTags.Audio.EndServiceNAK.REJECTED_PARAMS;
+ } else if (serviceType.equals(SessionType.NAV)) {
+ rejectedTag = ControlFrameTags.Video.EndServiceNAK.REJECTED_PARAMS;
+ }
+
+ List<String> rejectedParams = (List<String>) packet.getTag(rejectedTag);
+ if(rejectedParams != null && rejectedParams.size() > 0){
+ StringBuilder builder = new StringBuilder();
+ builder.append("Rejected params for service type ");
+ builder.append(serviceType.getName());
+ builder.append(" :");
+ for(String rejectedParam : rejectedParams){
+ builder.append(rejectedParam);
+ builder.append(" ");
+ }
+ DebugTool.logWarning(builder.toString());
+ }
+
+ }
+ }
+
+ iSdlProtocol.onProtocolSessionEndedNACKed(serviceType, (byte)packet.getSessionId(), "");
+ }
+
+ // This method handles the end of a protocol session. A callback is
+ // sent to the protocol listener.
+ protected void handleServiceEnded(SdlPacket packet, SessionType sessionType) {
+
+ iSdlProtocol.onProtocolSessionEnded(sessionType, (byte)packet.getSessionId(), "");
+
+ }
+
+ /**
+ * This method handles the startup of a protocol session. A callback is sent
+ * to the protocol listener.
+ * @param packet StarServiceACK packet
+ * @param serviceType the service type that has just been started
+ */
+ protected void handleProtocolSessionStarted(SdlPacket packet, SessionType serviceType) {
+ // Use this sessionID to create a message lock
+ Object messageLock = _messageLocks.get((byte)packet.getSessionId());
+ if (messageLock == null) {
+ messageLock = new Object();
+ _messageLocks.put((byte)packet.getSessionId(), messageLock);
+ }
+ if(packet.version >= 5){
+ String mtuTag = null;
+ if(serviceType.equals(SessionType.RPC)){
+ mtuTag = ControlFrameTags.RPC.StartServiceACK.MTU;
+ }else if(serviceType.equals(SessionType.PCM)){
+ mtuTag = ControlFrameTags.Audio.StartServiceACK.MTU;
+ }else if(serviceType.equals(SessionType.NAV)){
+ mtuTag = ControlFrameTags.Video.StartServiceACK.MTU;
+ }
+ Object mtu = packet.getTag(mtuTag);
+ if(mtu!=null){
+ mtus.put(serviceType,(Long) packet.getTag(mtuTag));
+ }
+ if(serviceType.equals(SessionType.RPC)){
+ hashID = (Integer) packet.getTag(ControlFrameTags.RPC.StartServiceACK.HASH_ID);
+ Object version = packet.getTag(ControlFrameTags.RPC.StartServiceACK.PROTOCOL_VERSION);
+
+ if(version!=null) {
+ //At this point we have confirmed the negotiated version between the module and the proxy
+ protocolVersion = new Version((String) version);
+ }else{
+ protocolVersion = new Version("5.0.0");
+ }
+
+ //Check to make sure this is a transport we are willing to accept
+ TransportRecord transportRecord = packet.getTransportRecord();
+
+ if(transportRecord == null || !requestedPrimaryTransports.contains(transportRecord.getType())){
+ onTransportNotAccepted("Transport is not in requested primary transports");
+ return;
+ }
+
+
+ // This enables custom behavior based on protocol version specifics
+ if (protocolVersion.isNewerThan(new Version("5.1.0")) >= 0) {
+
+ if (activeTransports.get(SessionType.RPC) == null) { //Might be a better way to handle this
+
+ ArrayList<String> secondary = (ArrayList<String>) packet.getTag(ControlFrameTags.RPC.StartServiceACK.SECONDARY_TRANSPORTS);
+ ArrayList<Integer> audio = (ArrayList<Integer>) packet.getTag(ControlFrameTags.RPC.StartServiceACK.AUDIO_SERVICE_TRANSPORTS);
+ ArrayList<Integer> video = (ArrayList<Integer>) packet.getTag(ControlFrameTags.RPC.StartServiceACK.VIDEO_SERVICE_TRANSPORTS);
+
+ activeTransports.put(SessionType.RPC, transportRecord);
+ activeTransports.put(SessionType.BULK_DATA, transportRecord);
+ activeTransports.put(SessionType.CONTROL, transportRecord);
+
+ //Build out the supported secondary transports received from the
+ // RPC start service ACK.
+ supportedSecondaryTransports = new ArrayList<>();
+ if (secondary == null) {
+ // If no secondary transports were attached we should assume
+ // the Video and Audio services can be used on primary
+ if (requiresHighBandwidth
+ && TransportType.BLUETOOTH.equals(transportRecord.getType())) {
+ //transport can't support high bandwidth
+ onTransportNotAccepted(transportRecord.getType() + " can't support high bandwidth requirement, and secondary transport not supported.");
+ return;
+ }
+
+ if (video == null || video.contains(PRIMARY_TRANSPORT_ID)) {
+ activeTransports.put(SessionType.NAV, transportRecord);
+ }
+ if (audio == null || audio.contains(PRIMARY_TRANSPORT_ID)) {
+ activeTransports.put(SessionType.PCM, transportRecord);
+ }
+ }else{
+
+ if(DebugTool.isDebugEnabled()){
+ printSecondaryTransportDetails(secondary,audio,video);
+ }
+ for (String s : secondary) {
+ switch (s) {
+ case TransportConstants.TCP_WIFI:
+ supportedSecondaryTransports.add(TransportType.TCP);
+ break;
+ case TransportConstants.AOA_USB:
+ supportedSecondaryTransports.add(TransportType.USB);
+ break;
+ case TransportConstants.SPP_BLUETOOTH:
+ supportedSecondaryTransports.add(TransportType.BLUETOOTH);
+ break;
+ }
+ }
+ }
+
+ setTransportPriorityForService(SessionType.PCM, audio);
+ setTransportPriorityForService(SessionType.NAV, video);
+
+ //Update the developer on the transport status
+ notifyDevTransportListener();
+
+ } else {
+ Log.w(TAG, "Received a start service ack for RPC service while already active on a different transport.");
+ return;
+ }
+ }else {
+
+ //Version is either not included or lower than 5.1.0
+ if (requiresHighBandwidth
+ && TransportType.BLUETOOTH.equals(transportRecord.getType())) {
+ //transport can't support high bandwidth
+ onTransportNotAccepted(transportRecord.getType() + " can't support high bandwidth requirement, and secondary transport not supported in this protocol version: " + version);
+ return;
+ }
+
+ activeTransports.put(SessionType.RPC, transportRecord);
+ activeTransports.put(SessionType.BULK_DATA, transportRecord);
+ activeTransports.put(SessionType.CONTROL, transportRecord);
+ activeTransports.put(SessionType.NAV, transportRecord);
+ activeTransports.put(SessionType.PCM, transportRecord);
+
+ //Inform the developer of the initial transport connection
+ notifyDevTransportListener();
+ }
+
+
+ }else if(serviceType.equals(SessionType.NAV)){
+ if(iSdlProtocol != null) {
+ ImageResolution acceptedResolution = new ImageResolution();
+ VideoStreamingFormat acceptedFormat = new VideoStreamingFormat();
+ acceptedResolution.setResolutionHeight((Integer) packet.getTag(ControlFrameTags.Video.StartServiceACK.HEIGHT));
+ acceptedResolution.setResolutionWidth((Integer) packet.getTag(ControlFrameTags.Video.StartServiceACK.WIDTH));
+ acceptedFormat.setCodec(VideoStreamingCodec.valueForString((String) packet.getTag(ControlFrameTags.Video.StartServiceACK.VIDEO_CODEC)));
+ acceptedFormat.setProtocol(VideoStreamingProtocol.valueForString((String) packet.getTag(ControlFrameTags.Video.StartServiceACK.VIDEO_PROTOCOL)));
+ VideoStreamingParameters agreedVideoParams = iSdlProtocol.getDesiredVideoParams();
+ agreedVideoParams.setResolution(acceptedResolution);
+ agreedVideoParams.setFormat(acceptedFormat);
+ iSdlProtocol.setAcceptedVideoParams(agreedVideoParams);
+ }
+ }
+ } else {
+ TransportRecord transportRecord = packet.getTransportRecord();
+ if(transportRecord == null || (requiresHighBandwidth
+ && TransportType.BLUETOOTH.equals(transportRecord.getType()))){
+ //transport can't support high bandwidth
+ onTransportNotAccepted((transportRecord != null ? transportRecord.getType().toString() : "Transport") + "can't support high bandwidth requirement, and secondary transport not supported in this protocol version");
+ return;
+ }
+ //If version < 5 and transport is acceptable we need to just add these
+ activeTransports.put(SessionType.RPC, transportRecord);
+ activeTransports.put(SessionType.BULK_DATA, transportRecord);
+ activeTransports.put(SessionType.CONTROL, transportRecord);
+ activeTransports.put(SessionType.NAV, transportRecord);
+ activeTransports.put(SessionType.PCM, transportRecord);
+
+ if (protocolVersion.getMajor() > 1){
+ if (packet.payload!= null && packet.dataSize == 4){ //hashid will be 4 bytes in length
+ hashID = BitConverter.intFromByteArray(packet.payload, 0);
+ }
+ }
+ }
+
+ iSdlProtocol.onProtocolSessionStarted(serviceType, (byte) packet.getSessionId(), (byte)protocolVersion.getMajor(), "", hashID, packet.isEncrypted());
+ }
+
+ protected void handleProtocolSessionNAKed(SdlPacket packet, SessionType serviceType) {
+ List<String> rejectedParams = null;
+ if(packet.version >= 5){
+ if(DebugTool.isDebugEnabled()) {
+ //Currently this is only during a debugging session. Might pass back in the future
+ String rejectedTag = null;
+ if (serviceType.equals(SessionType.RPC)) {
+ rejectedTag = ControlFrameTags.RPC.StartServiceNAK.REJECTED_PARAMS;
+ } else if (serviceType.equals(SessionType.PCM)) {
+ rejectedTag = ControlFrameTags.Audio.StartServiceNAK.REJECTED_PARAMS;
+ } else if (serviceType.equals(SessionType.NAV)) {
+ rejectedTag = ControlFrameTags.Video.StartServiceNAK.REJECTED_PARAMS;
+ }
+
+ rejectedParams = (List<String>) packet.getTag(rejectedTag);
+ if(rejectedParams != null && rejectedParams.size() > 0){
+ StringBuilder builder = new StringBuilder();
+ builder.append("Rejected params for service type ");
+ builder.append(serviceType.getName());
+ builder.append(" :");
+ for(String rejectedParam : rejectedParams){
+ builder.append(rejectedParam);
+ builder.append(" ");
+ }
+ DebugTool.logWarning(builder.toString());
+ }
+
+ }
+ }
+ if (serviceType.eq(SessionType.NAV) || serviceType.eq(SessionType.PCM)) {
+ iSdlProtocol.onProtocolSessionNACKed(serviceType, (byte)packet.sessionId, (byte)protocolVersion.getMajor(), "", rejectedParams);
+
+ } else {
+ handleProtocolError("Got StartSessionNACK for protocol sessionID = " + packet.getSessionId(), null);
+ }
+ }
+
+ // This method handles protocol errors. A callback is sent to the protocol
+ // listener.
+ protected void handleProtocolError(String string, Exception ex) {
+ iSdlProtocol.onProtocolError(string, ex);
+ }
+
+ protected void handleProtocolHeartbeat(SessionType sessionType, byte sessionID) {
+ sendHeartBeatACK(sessionType,sessionID);
+ }
+
+ protected void handleServiceDataACK(SdlPacket packet, SessionType sessionType) {
+
+ if (packet.getPayload() != null && packet.getDataSize() == 4){ //service data ack will be 4 bytes in length
+ int serviceDataAckSize = BitConverter.intFromByteArray(packet.getPayload(), 0);
+ iSdlProtocol.onProtocolServiceDataACK(sessionType, serviceDataAckSize, (byte)packet.getSessionId ());
+
+ }
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ ----------------------------------- TRANSPORT_TYPE LISTENER ---------------------------------
+ -------------------------------------------------------------------------------------------*/
+
+ @SuppressWarnings("FieldCanBeLocal")
+ private final TransportManager.TransportEventListener transportEventListener = new TransportManager.TransportEventListener() {
+ private boolean requestedSession = false;
+
+ @Override
+ public void onPacketReceived(SdlPacket packet) {
+ handlePacketReceived(packet);
+ }
+
+ @Override
+ public void onTransportConnected(List<TransportRecord> connectedTransports) {
+ Log.d(TAG, "onTransportConnected");
+ //In the future we should move this logic into the Protocol Layer
+ TransportRecord transportRecord = getTransportForSession(SessionType.RPC);
+ if(transportRecord == null && !requestedSession){ //There is currently no transport registered
+ requestedSession = true;
+ transportManager.requestNewSession(getPreferredTransport(requestedPrimaryTransports,connectedTransports));
+ }
+ onTransportsConnectedUpdate(connectedTransports);
+ if(DebugTool.isDebugEnabled()){
+ printActiveTransports();
+ }
+ }
+
+ @Override
+ public void onTransportDisconnected(String info, TransportRecord disconnectedTransport, List<TransportRecord> connectedTransports) {
+ if (disconnectedTransport == null) {
+ Log.d(TAG, "onTransportDisconnected");
+ transportManager.close(iSdlProtocol.getSessionId());
+ iSdlProtocol.shutdown("No transports left connected");
+ return;
+ } else {
+ Log.d(TAG, "onTransportDisconnected - " + disconnectedTransport.getType().name());
+ }
+
+ //In the future we will actually compare the record but at this point we can assume only
+ //a single transport record per transport.
+ //TransportType type = disconnectedTransport.getType();
+ if(disconnectedTransport.equals(getTransportForSession(SessionType.NAV))){
+ //stopVideoStream();
+ iSdlProtocol.stopStream(SessionType.NAV);
+ activeTransports.remove(SessionType.NAV);
+ }
+ if(disconnectedTransport.equals(getTransportForSession(SessionType.PCM))){
+ //stopAudioStream();
+ iSdlProtocol.stopStream(SessionType.PCM);
+ activeTransports.remove(SessionType.PCM);
+ }
+
+ if(disconnectedTransport.equals(getTransportForSession(SessionType.RPC))){
+ //transportTypes.remove(type);
+ boolean primaryTransportAvailable = false;
+ if(requestedPrimaryTransports != null && requestedPrimaryTransports.size() > 1){
+ for (TransportType transportType: requestedPrimaryTransports){ Log.d(TAG, "Checking " + transportType.name());
+ if(!disconnectedTransport.getType().equals(transportType)
+ && transportManager != null
+ && transportManager.isConnected(transportType,null)){
+ primaryTransportAvailable = true;
+ ( transportConfig).setService(transportManager.getRouterService());
+ break;
+ }
+ }
+ }
+ transportManager.close(iSdlProtocol.getSessionId());
+ transportManager = null;
+ requestedSession = false;
+
+ activeTransports.clear();
+
+ iSdlProtocol.onTransportDisconnected(info, primaryTransportAvailable, transportConfig);
+
+ } //else Transport was not primary, continuing to stay connected
+
+ //Update the developer since a transport just disconnected
+ notifyDevTransportListener();
+
+ }
+
+ @Override
+ public void onError(String info) {
+ iSdlProtocol.shutdown(info);
+
+ }
+
+ @Override
+ public boolean onLegacyModeEnabled(String info) {
+ //Await a connection from the legacy transport
+ if(requestedPrimaryTransports!= null && requestedPrimaryTransports.contains(TransportType.BLUETOOTH)
+ && !transportConfig.requiresHighBandwidth()){
+ Log.d(TAG, "Entering legacy mode; creating new protocol instance");
+ reset();
+ return true;
+ }else{
+ Log.d(TAG, "Bluetooth is not an acceptable transport; not moving to legacy mode");
+ return false;
+ }
+ }
+ };
+
+/* -------------------------------------------------------------------------------------------------
+----------------------------------- Internal Classes ------------------------------------------
+--------------------------------------------------------------------------------------------------*/
+
+
+ protected class MessageFrameAssembler {
+ protected ByteArrayOutputStream accumulator = null;
+ protected int totalSize = 0;
+
+ protected void handleFirstDataFrame(SdlPacket packet) {
+ //The message is new, so let's figure out how big it is.
+ totalSize = BitConverter.intFromByteArray(packet.payload, 0) - headerSize;
+ try {
+ accumulator = new ByteArrayOutputStream(totalSize);
+ }catch(OutOfMemoryError e){
+ DebugTool.logError("OutOfMemory error", e); //Garbled bits were received
+ accumulator = null;
+ }
+ }
+
+ protected void handleRemainingFrame(SdlPacket packet) {
+ accumulator.write(packet.payload, 0, (int)packet.getDataSize());
+ notifyIfFinished(packet);
+ }
+
+ protected void notifyIfFinished(SdlPacket packet) {
+ if (packet.getFrameType() == FrameType.Consecutive && packet.getFrameInfo() == 0x0) {
+ ProtocolMessage message = new ProtocolMessage();
+ message.setPayloadProtected(packet.isEncrypted());
+ message.setSessionType(SessionType.valueOf((byte)packet.getServiceType()));
+ message.setSessionID((byte)packet.getSessionId());
+ //If it is WiPro 2.0 it must have binary header
+ if (protocolVersion.getMajor() > 1) {
+ BinaryFrameHeader binFrameHeader = BinaryFrameHeader.
+ parseBinaryHeader(accumulator.toByteArray());
+ if(binFrameHeader == null) {
+ return;
+ }
+ message.setVersion((byte)protocolVersion.getMajor());
+ message.setRPCType(binFrameHeader.getRPCType());
+ message.setFunctionID(binFrameHeader.getFunctionID());
+ message.setCorrID(binFrameHeader.getCorrID());
+ if (binFrameHeader.getJsonSize() > 0) message.setData(binFrameHeader.getJsonData());
+ if (binFrameHeader.getBulkData() != null) message.setBulkData(binFrameHeader.getBulkData());
+ } else{
+ message.setData(accumulator.toByteArray());
+ }
+
+ _assemblerForMessageID.remove(packet.getMessageId());
+
+ try {
+ iSdlProtocol.onProtocolMessageReceived(message);
+ } catch (Exception excp) {
+ DebugTool.logError(FailurePropagating_Msg + "onProtocolMessageReceived: " + excp.toString(), excp);
+ } // end-catch
+
+ accumulator = null;
+ } // end-if
+ } // end-method
+
+ protected void handleMultiFrameMessageFrame(SdlPacket packet) {
+ if (packet.getFrameType() == FrameType.First) {
+ handleFirstDataFrame(packet);
+ }
+ else{
+ if(accumulator != null){
+ handleRemainingFrame(packet);
+ }
+ }
+
+ } // end-method
+
+ protected void handleFrame(SdlPacket packet) {
+
+ if (packet.getPayload() != null && packet.getDataSize() > 0 && packet.isEncrypted() ) {
+
+ SdlSecurityBase sdlSec = iSdlProtocol.getSdlSecurity();
+ byte[] dataToRead = new byte[4096];
+
+ Integer iNumBytes = sdlSec.decryptData(packet.getPayload(), dataToRead);
+ if ((iNumBytes == null) || (iNumBytes <= 0)){
+ return;
+ }
+
+ byte[] decryptedData = new byte[iNumBytes];
+ System.arraycopy(dataToRead, 0, decryptedData, 0, iNumBytes);
+ packet.payload = decryptedData;
+ }
+
+ if (packet.getFrameType().equals(FrameType.Control)) {
+ handleControlFrame(packet);
+ } else {
+ // Must be a form of data frame (single, first, consecutive, etc.)
+ if ( packet.getFrameType() == FrameType.First
+ || packet.getFrameType() == FrameType.Consecutive
+ ) {
+ handleMultiFrameMessageFrame(packet);
+ } else {
+ handleSingleFrameMessageFrame(packet);
+ }
+ }
+ }
+
+ private void handleProtocolHeartbeatACK(SdlPacket packet) {
+ //Heartbeat is not supported in the SdlProtocol class beyond responding with ACKs to
+ //heartbeat messages. Receiving this ACK is suspicious and should be logged
+ DebugTool.logInfo("Received HeartbeatACK - " + packet.toString());
+ }
+
+ private void handleProtocolHeartbeat(SdlPacket packet) {
+ SdlProtocol.this.handleProtocolHeartbeat(SessionType.valueOf((byte)packet.getServiceType()),(byte)packet.getSessionId());
+ }
+
+ /**
+ * Directing method that will push the packet to the method that can handle it best
+ * @param packet a control frame packet
+ */
+ private void handleControlFrame(SdlPacket packet) {
+ Integer frameTemp = packet.getFrameInfo();
+ Byte frameInfo = frameTemp.byteValue();
+
+ SessionType serviceType = SessionType.valueOf((byte)packet.getServiceType());
+
+ if (frameInfo == FrameDataControlFrameType.Heartbeat.getValue()) {
+
+ handleProtocolHeartbeat(packet);
+
+ }else if (frameInfo == FrameDataControlFrameType.HeartbeatACK.getValue()) {
+
+ handleProtocolHeartbeatACK(packet);
+
+ }else if (frameInfo == FrameDataControlFrameType.StartSessionACK.getValue()) {
+
+ handleProtocolSessionStarted(packet, serviceType);
+
+ } else if (frameInfo == FrameDataControlFrameType.StartSessionNACK.getValue()) {
+
+ handleProtocolSessionNAKed(packet, serviceType);
+
+ } else if (frameInfo == FrameDataControlFrameType.EndSession.getValue()
+ || frameInfo == FrameDataControlFrameType.EndSessionACK.getValue()) {
+
+ handleServiceEnded(packet,serviceType);
+
+ } else if (frameInfo == FrameDataControlFrameType.EndSessionNACK.getValue()) {
+
+ handleServiceEndedNAK(packet, serviceType);
+
+ } else if (frameInfo == FrameDataControlFrameType.ServiceDataACK.getValue()) {
+
+ handleServiceDataACK(packet, serviceType);
+
+ } else if (frameInfo == FrameDataControlFrameType.RegisterSecondaryTransportACK.getValue()) {
+
+ handleSecondaryTransportRegistration(packet.getTransportRecord(),true);
+
+ } else if (frameInfo == FrameDataControlFrameType.RegisterSecondaryTransportNACK.getValue()) {
+
+ String reason = (String) packet.getTag(ControlFrameTags.RPC.RegisterSecondaryTransportNAK.REASON);
+ DebugTool.logWarning(reason);
+ handleSecondaryTransportRegistration(packet.getTransportRecord(),false);
+
+ } else if (frameInfo == FrameDataControlFrameType.TransportEventUpdate.getValue()) {
+
+ // Get TCP params
+ String ipAddr = (String) packet.getTag(ControlFrameTags.RPC.TransportEventUpdate.TCP_IP_ADDRESS);
+ Integer port = (Integer) packet.getTag(ControlFrameTags.RPC.TransportEventUpdate.TCP_PORT);
+
+ if(secondaryTransportParams == null){
+ secondaryTransportParams = new HashMap<>();
+ }
+
+ if(ipAddr != null && port != null) {
+ Bundle bundle = new Bundle();
+ bundle.putString(ControlFrameTags.RPC.TransportEventUpdate.TCP_IP_ADDRESS, ipAddr);
+ bundle.putInt(ControlFrameTags.RPC.TransportEventUpdate.TCP_PORT, port);
+ bundle.putString(TransportConstants.TRANSPORT_TYPE, TransportType.TCP.name());
+ secondaryTransportParams.put(TransportType.TCP, bundle);
+
+ //A new secondary transport just became available. Notify the developer.
+ notifyDevTransportListener();
+ }
+
+ }
+
+ _assemblerForMessageID.remove(packet.getMessageId());
+
+ } // end-method
+
+ private void handleSingleFrameMessageFrame(SdlPacket packet) {
+ ProtocolMessage message = new ProtocolMessage();
+ message.setPayloadProtected(packet.isEncrypted());
+ SessionType serviceType = SessionType.valueOf((byte)packet.getServiceType());
+ if (serviceType == SessionType.RPC) {
+ message.setMessageType(MessageType.RPC);
+ } else if (serviceType == SessionType.BULK_DATA) {
+ message.setMessageType(MessageType.BULK);
+ } // end-if
+ message.setSessionType(serviceType);
+ message.setSessionID((byte)packet.getSessionId());
+ //If it is WiPro 2.0 it must have binary header
+ boolean isControlService = message.getSessionType().equals(SessionType.CONTROL);
+ if (protocolVersion.getMajor() > 1 && !isControlService) {
+ BinaryFrameHeader binFrameHeader = BinaryFrameHeader.
+ parseBinaryHeader(packet.payload);
+ if(binFrameHeader == null) {
+ return;
+ }
+ message.setVersion((byte)protocolVersion.getMajor());
+ message.setRPCType(binFrameHeader.getRPCType());
+ message.setFunctionID(binFrameHeader.getFunctionID());
+ message.setCorrID(binFrameHeader.getCorrID());
+ if (binFrameHeader.getJsonSize() > 0){
+ message.setData(binFrameHeader.getJsonData());
+ }
+ if (binFrameHeader.getBulkData() != null){
+ message.setBulkData(binFrameHeader.getBulkData());
+ }
+ } else {
+ message.setData(packet.payload);
+ }
+
+ _assemblerForMessageID.remove(packet.getMessageId());
+
+ try {
+ iSdlProtocol.onProtocolMessageReceived(message);
+ } catch (Exception ex) {
+ DebugTool.logError(FailurePropagating_Msg + "onProtocolMessageReceived: " + ex.toString(), ex);
+ handleProtocolError(FailurePropagating_Msg + "onProtocolMessageReceived: ", ex);
+ } // end-catch
+ } // end-method
+ } // end-class
+
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/protocol/WiProProtocol.java b/sdl_android/src/main/java/com/smartdevicelink/protocol/WiProProtocol.java
index 72482d47e..73fbcffba 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/protocol/WiProProtocol.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/protocol/WiProProtocol.java
@@ -24,6 +24,10 @@ import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
+/**
+ * @see SdlProtocol
+ */
+@Deprecated
public class WiProProtocol extends AbstractProtocol {
private final static String FailurePropagating_Msg = "Failure propagating ";
//If increasing MAX PROTOCOL VERSION major version, make sure to alter it in SdlPsm
@@ -41,12 +45,12 @@ public class WiProProtocol extends AbstractProtocol {
int hashID = 0;
int messageID = 0;
SdlConnection sdlconn = null;
-
- @SuppressWarnings("unused")
- private int _heartbeatSendInterval_ms = 0;
- @SuppressWarnings("unused")
- private int _heartbeatReceiveInterval_ms = 0;
-
+
+ @SuppressWarnings("unused")
+ private int _heartbeatSendInterval_ms = 0;
+ @SuppressWarnings("unused")
+ private int _heartbeatReceiveInterval_ms = 0;
+
Hashtable<Integer, MessageFrameAssembler> _assemblerForMessageID = new Hashtable<Integer, MessageFrameAssembler>();
Hashtable<Byte, Hashtable<Integer, MessageFrameAssembler>> _assemblerForSessionID = new Hashtable<Byte, Hashtable<Integer, MessageFrameAssembler>>();
Hashtable<Byte, Object> _messageLocks = new Hashtable<Byte, Object>();
@@ -57,19 +61,20 @@ public class WiProProtocol extends AbstractProtocol {
super(null);
} // end-ctor
+
public WiProProtocol(IProtocolListener protocolListener) {
super(protocolListener);
-
+
if (protocolListener instanceof SdlConnection)
{
sdlconn = (SdlConnection) protocolListener;
}
mtus.put(SessionType.RPC, new Long(V1_V2_MTU_SIZE - HEADER_SIZE));
} // end-ctor
-
+
/**
* Retrieves the max payload size for a packet to be sent to the module
- * @return the max transfer unit
+ * @return the max transfer unit
*/
public int getMtu(){
return mtus.get(SessionType.RPC).intValue();
@@ -109,32 +114,32 @@ public class WiProProtocol extends AbstractProtocol {
* @param version
*/
public void setVersion(byte version) {
- if (version > 5) {
- this.protocolVersion = new Version("5.0.0"); //protect for future, proxy only supports v5 or lower
- HEADER_SIZE = 12;
- mtus.put(SessionType.RPC,new Long(V3_V4_MTU_SIZE) );
- } else if (version == 5) {
- this.protocolVersion = new Version("5.0.0");
- HEADER_SIZE = 12;
- mtus.put(SessionType.RPC,new Long(V3_V4_MTU_SIZE) );
- }else if (version == 4) {
- this.protocolVersion = new Version("4.0.0");
- HEADER_SIZE = 12;
- mtus.put(SessionType.RPC,new Long(V3_V4_MTU_SIZE) ); //versions 4 supports 128k MTU
- } else if (version == 3) {
- this.protocolVersion = new Version("3.0.0");
- HEADER_SIZE = 12;
- mtus.put(SessionType.RPC,new Long(V3_V4_MTU_SIZE) ); //versions 3 supports 128k MTU
- } else if (version == 2) {
- this.protocolVersion = new Version("2.0.0");
- HEADER_SIZE = 12;
- mtus.put(SessionType.RPC,new Long(V1_V2_MTU_SIZE - HEADER_SIZE) );
- } else if (version == 1){
- this.protocolVersion = new Version("1.0.0");
- HEADER_SIZE = 8;
- mtus.put(SessionType.RPC,new Long(V1_V2_MTU_SIZE - HEADER_SIZE) );
- }
- }
+ if (version > 5) {
+ this.protocolVersion = new Version("5.0.0"); //protect for future, proxy only supports v5 or lower
+ HEADER_SIZE = 12;
+ mtus.put(SessionType.RPC,new Long(V3_V4_MTU_SIZE) );
+ } else if (version == 5) {
+ this.protocolVersion = new Version("5.0.0");
+ HEADER_SIZE = 12;
+ mtus.put(SessionType.RPC,new Long(V3_V4_MTU_SIZE) );
+ }else if (version == 4) {
+ this.protocolVersion = new Version("4.0.0");
+ HEADER_SIZE = 12;
+ mtus.put(SessionType.RPC,new Long(V3_V4_MTU_SIZE) ); //versions 4 supports 128k MTU
+ } else if (version == 3) {
+ this.protocolVersion = new Version("3.0.0");
+ HEADER_SIZE = 12;
+ mtus.put(SessionType.RPC,new Long(V3_V4_MTU_SIZE) ); //versions 3 supports 128k MTU
+ } else if (version == 2) {
+ this.protocolVersion = new Version("2.0.0");
+ HEADER_SIZE = 12;
+ mtus.put(SessionType.RPC,new Long(V1_V2_MTU_SIZE - HEADER_SIZE) );
+ } else if (version == 1){
+ this.protocolVersion = new Version("1.0.0");
+ HEADER_SIZE = 8;
+ mtus.put(SessionType.RPC,new Long(V1_V2_MTU_SIZE - HEADER_SIZE) );
+ }
+ }
public void StartProtocolSession(SessionType sessionType) {
SdlPacket header = SdlPacketFactory.createStartSession(sessionType, 0x00, getMajorVersionByte(), (byte) 0x00, false);
@@ -148,93 +153,93 @@ public class WiProProtocol extends AbstractProtocol {
SdlPacket header = SdlPacketFactory.createStartSessionACK(sessionType, sessionID, 0x00, getMajorVersionByte());
handlePacketToSend(header);
} // end-method
-
+
public void EndProtocolSession(SessionType sessionType, byte sessionID, int hashId) {
SdlPacket header;
- if (sessionType.equals(SessionType.RPC)) { // check for RPC session
- if(_version < 5){
- header = SdlPacketFactory.createEndSession(sessionType, sessionID, hashID, getMajorVersionByte(), BitConverter.intToByteArray(hashID));
- }else{
- header = SdlPacketFactory.createEndSession(sessionType, sessionID, hashID, getMajorVersionByte(), new byte[0]);
- header.putTag(ControlFrameTags.RPC.EndService.HASH_ID, hashID);
- }
- }else{ //Any other service type we don't include the hash id
+ if (sessionType.equals(SessionType.RPC)) { // check for RPC session
+ if(_version < 5){
+ header = SdlPacketFactory.createEndSession(sessionType, sessionID, hashID, getMajorVersionByte(), BitConverter.intToByteArray(hashID));
+ }else{
header = SdlPacketFactory.createEndSession(sessionType, sessionID, hashID, getMajorVersionByte(), new byte[0]);
+ header.putTag(ControlFrameTags.RPC.EndService.HASH_ID, hashID);
}
+ }else{ //Any other service type we don't include the hash id
+ header = SdlPacketFactory.createEndSession(sessionType, sessionID, hashID, getMajorVersionByte(), new byte[0]);
+ }
handlePacketToSend(header);
} // end-method
- public void SendMessage(ProtocolMessage protocolMsg) {
+ public void SendMessage(ProtocolMessage protocolMsg) {
protocolMsg.setRPCType((byte) 0x00); //always sending a request
SessionType sessionType = protocolMsg.getSessionType();
byte sessionID = protocolMsg.getSessionID();
-
+
byte[] data = null;
if (protocolVersion.getMajor() > 1 && sessionType != SessionType.NAV && sessionType != SessionType.PCM) {
- if (sessionType.eq(SessionType.CONTROL)) {
- final byte[] secureData = protocolMsg.getData().clone();
- data = new byte[HEADER_SIZE + secureData.length];
-
- final BinaryFrameHeader binFrameHeader =
- SdlPacketFactory.createBinaryFrameHeader(protocolMsg.getRPCType(),protocolMsg.getFunctionID(), protocolMsg.getCorrID(), 0);
- System.arraycopy(binFrameHeader.assembleHeaderBytes(), 0, data, 0, HEADER_SIZE);
- System.arraycopy(secureData, 0, data,HEADER_SIZE, secureData.length);
- }
- else if (protocolMsg.getBulkData() != null) {
+ if (sessionType.eq(SessionType.CONTROL)) {
+ final byte[] secureData = protocolMsg.getData().clone();
+ data = new byte[HEADER_SIZE + secureData.length];
+
+ final BinaryFrameHeader binFrameHeader =
+ SdlPacketFactory.createBinaryFrameHeader(protocolMsg.getRPCType(),protocolMsg.getFunctionID(), protocolMsg.getCorrID(), 0);
+ System.arraycopy(binFrameHeader.assembleHeaderBytes(), 0, data, 0, HEADER_SIZE);
+ System.arraycopy(secureData, 0, data,HEADER_SIZE, secureData.length);
+ }
+ else if (protocolMsg.getBulkData() != null) {
data = new byte[12 + protocolMsg.getJsonSize() + protocolMsg.getBulkData().length];
sessionType = SessionType.BULK_DATA;
- } else {
+ } else {
data = new byte[12 + protocolMsg.getJsonSize()];
}
- if (!sessionType.eq(SessionType.CONTROL)) {
- BinaryFrameHeader binFrameHeader = SdlPacketFactory.createBinaryFrameHeader(protocolMsg.getRPCType(), protocolMsg.getFunctionID(), protocolMsg.getCorrID(), protocolMsg.getJsonSize());
- System.arraycopy(binFrameHeader.assembleHeaderBytes(), 0, data, 0, 12);
- System.arraycopy(protocolMsg.getData(), 0, data, 12, protocolMsg.getJsonSize());
- if (protocolMsg.getBulkData() != null) {
- System.arraycopy(protocolMsg.getBulkData(), 0, data, 12 + protocolMsg.getJsonSize(), protocolMsg.getBulkData().length);
- }
- }
+ if (!sessionType.eq(SessionType.CONTROL)) {
+ BinaryFrameHeader binFrameHeader = SdlPacketFactory.createBinaryFrameHeader(protocolMsg.getRPCType(), protocolMsg.getFunctionID(), protocolMsg.getCorrID(), protocolMsg.getJsonSize());
+ System.arraycopy(binFrameHeader.assembleHeaderBytes(), 0, data, 0, 12);
+ System.arraycopy(protocolMsg.getData(), 0, data, 12, protocolMsg.getJsonSize());
+ if (protocolMsg.getBulkData() != null) {
+ System.arraycopy(protocolMsg.getBulkData(), 0, data, 12 + protocolMsg.getJsonSize(), protocolMsg.getBulkData().length);
+ }
+ }
} else {
data = protocolMsg.getData();
}
-
+
if (sdlconn != null && protocolMsg.getPayloadProtected())
- {
+ {
if (data != null && data.length > 0) {
SdlSession session = sdlconn.findSessionById(sessionID);
-
+
if (session == null)
return;
-
+
byte[] dataToRead = new byte[TLS_MAX_RECORD_SIZE];
SdlSecurityBase sdlSec = session.getSdlSecurity();
- if (sdlSec == null)
+ if (sdlSec == null)
return;
-
+
Integer iNumBytes = sdlSec.encryptData(data, dataToRead);
if ((iNumBytes == null) || (iNumBytes <= 0))
return;
-
- byte[] encryptedData = new byte[iNumBytes];
- System.arraycopy(dataToRead, 0, encryptedData, 0, iNumBytes);
+
+ byte[] encryptedData = new byte[iNumBytes];
+ System.arraycopy(dataToRead, 0, encryptedData, 0, iNumBytes);
data = encryptedData;
}
}
-
+
// Get the message lock for this protocol session
Object messageLock = _messageLocks.get(sessionID);
if (messageLock == null) {
- handleProtocolError("Error sending protocol message to SDL.",
+ handleProtocolError("Error sending protocol message to SDL.",
new SdlException("Attempt to send protocol message prior to startSession ACK.", SdlExceptionCause.SDL_UNAVAILABLE));
return;
}
-
+
synchronized(messageLock) {
if (data.length > getMtu(sessionType)) {
messageID++;
-
+
// Assemble first frame.
Long mtu = getMtu(sessionType);
int frameCount = new Long(data.length / mtu).intValue();
@@ -252,23 +257,23 @@ public class WiProProtocol extends AbstractProtocol {
firstHeader.setPriorityCoefficient(1+protocolMsg.priorityCoefficient);
//Send the first frame
handlePacketToSend(firstHeader);
-
+
int currentOffset = 0;
byte frameSequenceNumber = 0;
for (int i = 0; i < frameCount; i++) {
if (i < (frameCount - 1)) {
- ++frameSequenceNumber;
- if (frameSequenceNumber ==
- SdlPacket.FRAME_INFO_FINAL_CONNESCUTIVE_FRAME) {
- // we can't use 0x00 as frameSequenceNumber, because
- // it's reserved for the last frame
- ++frameSequenceNumber;
- }
+ ++frameSequenceNumber;
+ if (frameSequenceNumber ==
+ SdlPacket.FRAME_INFO_FINAL_CONNESCUTIVE_FRAME) {
+ // we can't use 0x00 as frameSequenceNumber, because
+ // it's reserved for the last frame
+ ++frameSequenceNumber;
+ }
} else {
frameSequenceNumber = SdlPacket.FRAME_INFO_FINAL_CONNESCUTIVE_FRAME;
} // end-if
-
+
int bytesToWrite = data.length - currentOffset;
if (bytesToWrite > mtu) {
bytesToWrite = mtu.intValue();
@@ -290,9 +295,9 @@ public class WiProProtocol extends AbstractProtocol {
public void handlePacketReceived(SdlPacket packet){
//Check for a version difference
if (getMajorVersionByte() == 1) {
- setVersion((byte)packet.version);
+ setVersion((byte)packet.version);
}
-
+
MessageFrameAssembler assembler = getFrameAssemblerForFrame(packet);
assembler.handleFrame(packet);
@@ -300,8 +305,8 @@ public class WiProProtocol extends AbstractProtocol {
}
-
-
+
+
protected MessageFrameAssembler getFrameAssemblerForFrame(SdlPacket packet) {
Integer iSessionId = Integer.valueOf(packet.getSessionId());
Byte bySessionId = iSessionId.byteValue();
@@ -311,13 +316,13 @@ public class WiProProtocol extends AbstractProtocol {
hashSessionID = new Hashtable<Integer, MessageFrameAssembler>();
_assemblerForSessionID.put(bySessionId, hashSessionID);
} // end-if
-
+
MessageFrameAssembler ret = (MessageFrameAssembler) _assemblerForMessageID.get(Integer.valueOf(packet.getMessageId()));
if (ret == null) {
ret = new MessageFrameAssembler();
_assemblerForMessageID.put(Integer.valueOf(packet.getMessageId()), ret);
} // end-if
-
+
return ret;
} // end-method
@@ -339,15 +344,15 @@ public class WiProProtocol extends AbstractProtocol {
accumulator = null;
}
}
-
+
protected void handleRemainingFrame(SdlPacket packet) {
accumulator.write(packet.payload, 0, (int)packet.getDataSize());
notifyIfFinished(packet);
}
-
+
protected void notifyIfFinished(SdlPacket packet) {
//if (framesRemaining == 0) {
- if (packet.getFrameType() == FrameType.Consecutive && packet.getFrameInfo() == 0x0)
+ if (packet.getFrameType() == FrameType.Consecutive && packet.getFrameInfo() == 0x0)
{
ProtocolMessage message = new ProtocolMessage();
message.setPayloadProtected(packet.isEncrypted());
@@ -369,20 +374,20 @@ public class WiProProtocol extends AbstractProtocol {
} else{
message.setData(accumulator.toByteArray());
}
-
+
_assemblerForMessageID.remove(packet.getMessageId());
-
+
try {
handleProtocolMessageReceived(message);
} catch (Exception excp) {
DebugTool.logError(FailurePropagating_Msg + "onProtocolMessageReceived: " + excp.toString(), excp);
} // end-catch
-
+
hasFirstFrame = false;
accumulator = null;
} // end-if
} // end-method
-
+
protected void handleMultiFrameMessageFrame(SdlPacket packet) {
if (packet.getFrameType() == FrameType.First){
handleFirstDataFrame(packet);
@@ -391,67 +396,67 @@ public class WiProProtocol extends AbstractProtocol {
if(accumulator != null)
handleRemainingFrame(packet);
}
-
+
} // end-method
-
+
protected void handleFrame(SdlPacket packet) {
-
+
if (packet.getPayload() != null && packet.getDataSize() > 0 && packet.isEncrypted() )
{
if (sdlconn != null)
{
SdlSession session = sdlconn.findSessionById((byte)packet.getSessionId());
-
+
if (session == null)
return;
-
+
SdlSecurityBase sdlSec = session.getSdlSecurity();
- byte[] dataToRead = new byte[4096];
+ byte[] dataToRead = new byte[4096];
Integer iNumBytes = sdlSec.decryptData(packet.getPayload(), dataToRead);
- if ((iNumBytes == null) || (iNumBytes <= 0))
- return;
-
+ if ((iNumBytes == null) || (iNumBytes <= 0))
+ return;
+
byte[] decryptedData = new byte[iNumBytes];
System.arraycopy(dataToRead, 0, decryptedData, 0, iNumBytes);
packet.payload = decryptedData;
}
}
-
+
if (packet.getFrameType().equals(FrameType.Control)) {
handleControlFrame(packet);
} else {
// Must be a form of data frame (single, first, consecutive, etc.)
if ( packet.getFrameType() == FrameType.First
- || packet.getFrameType() == FrameType.Consecutive
- ) {
+ || packet.getFrameType() == FrameType.Consecutive
+ ) {
handleMultiFrameMessageFrame(packet);
} else {
handleSingleFrameMessageFrame(packet);
}
} // end-if
} // end-method
-
- private void handleProtocolHeartbeatACK(SdlPacket packet) {
- WiProProtocol.this.handleProtocolHeartbeatACK(SessionType.valueOf((byte)packet.getServiceType()),(byte)packet.getSessionId());
- } // end-method
- private void handleProtocolHeartbeat(SdlPacket packet) {
- WiProProtocol.this.handleProtocolHeartbeat(SessionType.valueOf((byte)packet.getServiceType()),(byte)packet.getSessionId());
- } // end-method
-
+
+ private void handleProtocolHeartbeatACK(SdlPacket packet) {
+ WiProProtocol.this.handleProtocolHeartbeatACK(SessionType.valueOf((byte)packet.getServiceType()),(byte)packet.getSessionId());
+ } // end-method
+ private void handleProtocolHeartbeat(SdlPacket packet) {
+ WiProProtocol.this.handleProtocolHeartbeat(SessionType.valueOf((byte)packet.getServiceType()),(byte)packet.getSessionId());
+ } // end-method
+
private void handleControlFrame(SdlPacket packet) {
Integer frameTemp = Integer.valueOf(packet.getFrameInfo());
Byte frameInfo = frameTemp.byteValue();
-
- SessionType serviceType = SessionType.valueOf((byte)packet.getServiceType());
- if (frameInfo == FrameDataControlFrameType.Heartbeat.getValue()) {
- handleProtocolHeartbeat(packet);
- }
+ SessionType serviceType = SessionType.valueOf((byte)packet.getServiceType());
+
+ if (frameInfo == FrameDataControlFrameType.Heartbeat.getValue()) {
+ handleProtocolHeartbeat(packet);
+ }
if (frameInfo == FrameDataControlFrameType.HeartbeatACK.getValue()) {
- handleProtocolHeartbeatACK(packet);
- }
- else if (frameInfo == FrameDataControlFrameType.StartSession.getValue()) {
+ handleProtocolHeartbeatACK(packet);
+ }
+ else if (frameInfo == FrameDataControlFrameType.StartSession.getValue()) {
sendStartProtocolSessionACK(serviceType, (byte)packet.getSessionId());
} else if (frameInfo == FrameDataControlFrameType.StartSessionACK.getValue()) {
// Use this sessionID to create a message lock
@@ -550,13 +555,13 @@ public class WiProProtocol extends AbstractProtocol {
handleProtocolServiceDataACK(serviceType, serviceDataAckSize,(byte)packet.getSessionId ());
}
}
- _assemblerForMessageID.remove(packet.getMessageId());
+ _assemblerForMessageID.remove(packet.getMessageId());
} // end-method
-
+
private void handleSingleFrameMessageFrame(SdlPacket packet) {
ProtocolMessage message = new ProtocolMessage();
message.setPayloadProtected(packet.isEncrypted());
- SessionType serviceType = SessionType.valueOf((byte)packet.getServiceType());
+ SessionType serviceType = SessionType.valueOf((byte)packet.getServiceType());
if (serviceType == SessionType.RPC) {
message.setMessageType(MessageType.RPC);
} else if (serviceType == SessionType.BULK_DATA) {
@@ -585,9 +590,9 @@ public class WiProProtocol extends AbstractProtocol {
} else {
message.setData(packet.payload);
}
-
+
_assemblerForMessageID.remove(packet.getMessageId());
-
+
try {
handleProtocolMessageReceived(message);
} catch (Exception ex) {
@@ -621,25 +626,25 @@ public class WiProProtocol extends AbstractProtocol {
@Override
public void SetHeartbeatSendInterval(int heartbeatSendInterval_ms) {
_heartbeatSendInterval_ms = heartbeatSendInterval_ms;
-
+
}
@Override
public void SetHeartbeatReceiveInterval(int heartbeatReceiveInterval_ms) {
_heartbeatReceiveInterval_ms = heartbeatReceiveInterval_ms;
-
+
}
@Override
public void SendHeartBeat(byte sessionID) {
- final SdlPacket heartbeat = SdlPacketFactory.createHeartbeat(SessionType.CONTROL, sessionID, getMajorVersionByte());
- handlePacketToSend(heartbeat);
+ final SdlPacket heartbeat = SdlPacketFactory.createHeartbeat(SessionType.CONTROL, sessionID, getMajorVersionByte());
+ handlePacketToSend(heartbeat);
}
@Override
public void SendHeartBeatACK(byte sessionID) {
- final SdlPacket heartbeat = SdlPacketFactory.createHeartbeatACK(SessionType.CONTROL, sessionID, getMajorVersionByte());
- handlePacketToSend(heartbeat);
+ final SdlPacket heartbeat = SdlPacketFactory.createHeartbeatACK(SessionType.CONTROL, sessionID, getMajorVersionByte());
+ handlePacketToSend(heartbeat);
}
@Override
@@ -652,4 +657,4 @@ public class WiProProtocol extends AbstractProtocol {
}
}
-} // end-class
+} // end-class \ No newline at end of file
diff --git a/sdl_android/src/main/java/com/smartdevicelink/protocol/enums/ControlFrameTags.java b/sdl_android/src/main/java/com/smartdevicelink/protocol/enums/ControlFrameTags.java
index 74a001edc..bc926f714 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/protocol/enums/ControlFrameTags.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/protocol/enums/ControlFrameTags.java
@@ -30,6 +30,11 @@ public class ControlFrameTags {
public static final String PROTOCOL_VERSION = StartService.PROTOCOL_VERSION;
/** Hash ID to identify this service and used when sending an EndService control frame*/
public static final String HASH_ID = "hashId";
+ /** HU allowed transport for secondary connection */
+ public static final String SECONDARY_TRANSPORTS = "secondaryTransports";
+ /** HU allowed transports for audio and video services (1 == Primary, 2 == Secondary) */
+ public static final String AUDIO_SERVICE_TRANSPORTS = "audioServiceTransports";
+ public static final String VIDEO_SERVICE_TRANSPORTS = "videoServiceTransports";
}
public static class StartServiceNAK extends NAKBase{}
public static class EndService {
@@ -38,6 +43,22 @@ public class ControlFrameTags {
}
public static class EndServiceACK {}
public static class EndServiceNAK extends NAKBase{}
+ /** This frame is sent from Core to application to indicate that status or configuration of
+ * transport(s) is/are updated. This frame should not be sent prior to Version Negotiation.
+ **/
+ public static class TransportEventUpdate {
+ /** The HU reported IP address and port of TCP connection */
+ public static final String TCP_IP_ADDRESS = "tcpIpAddress";
+ public static final String TCP_PORT = "tcpPort";
+ }
+ /**This frame is sent from application to Core to notify that Secondary Transport has been
+ * established. This frame should be only sent on Secondary Transport.
+ **/
+ public static class RegisterSecondaryTransport {}
+ public static class RegisterSecondaryTransportACK {}
+ public static class RegisterSecondaryTransportNAK extends NAKBase {
+ public static final String REASON = "reason";
+ }
}
/**
diff --git a/sdl_android/src/main/java/com/smartdevicelink/protocol/enums/FrameDataControlFrameType.java b/sdl_android/src/main/java/com/smartdevicelink/protocol/enums/FrameDataControlFrameType.java
index fbcde6294..bef31fe5c 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/protocol/enums/FrameDataControlFrameType.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/protocol/enums/FrameDataControlFrameType.java
@@ -22,6 +22,10 @@ public class FrameDataControlFrameType extends ByteEnumer {
public final static FrameDataControlFrameType EndSession = new FrameDataControlFrameType((byte)0x04, "EndSession");
public final static FrameDataControlFrameType EndSessionACK = new FrameDataControlFrameType((byte)0x05, "EndSessionACK");
public final static FrameDataControlFrameType EndSessionNACK = new FrameDataControlFrameType((byte)0x06, "EndSessionNACK");
+ public final static FrameDataControlFrameType RegisterSecondaryTransport = new FrameDataControlFrameType((byte)0x07, "RegisterSecondaryTransport");
+ public final static FrameDataControlFrameType RegisterSecondaryTransportACK = new FrameDataControlFrameType((byte)0x08, "RegisterSecondaryTransportACK");
+ public final static FrameDataControlFrameType RegisterSecondaryTransportNACK = new FrameDataControlFrameType((byte)0x09, "RegisterSecondaryTransportNACK");
+ public final static FrameDataControlFrameType TransportEventUpdate = new FrameDataControlFrameType((byte)0xFD, "TransportEventUpdate");
public final static FrameDataControlFrameType ServiceDataACK = new FrameDataControlFrameType((byte)0xFE, "ServiceDataACK");
public final static FrameDataControlFrameType HeartbeatACK = new FrameDataControlFrameType((byte)0xFF, "HeartbeatACK");
@@ -33,6 +37,10 @@ public class FrameDataControlFrameType extends ByteEnumer {
theList.addElement(EndSession);
theList.addElement(EndSessionACK);
theList.addElement(EndSessionNACK);
+ theList.addElement(RegisterSecondaryTransport);
+ theList.addElement(RegisterSecondaryTransportACK);
+ theList.addElement(RegisterSecondaryTransportNACK);
+ theList.addElement(TransportEventUpdate);
theList.addElement(ServiceDataACK);
theList.addElement(HeartbeatACK);
}
@@ -45,4 +53,4 @@ public class FrameDataControlFrameType extends ByteEnumer {
return theList.toArray(new FrameDataControlFrameType[theList.size()]);
}
-}
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/protocol/enums/FunctionID.java b/sdl_android/src/main/java/com/smartdevicelink/protocol/enums/FunctionID.java
index 412d3f857..4f1ad71b5 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/protocol/enums/FunctionID.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/protocol/enums/FunctionID.java
@@ -82,6 +82,7 @@ public enum FunctionID{
ON_HASH_CHANGE(32782, "OnHashChange"),
ON_INTERIOR_VEHICLE_DATA(32783, "OnInteriorVehicleData"),
ON_WAY_POINT_CHANGE(32784, "OnWayPointChange"),
+ ON_RC_STATUS(32785, "OnRCStatus"),
// MOCKED FUNCTIONS (NOT SENT FROM HEAD-UNIT)
ON_LOCK_SCREEN_STATUS(-1, "OnLockScreenStatus"),
@@ -144,4 +145,18 @@ public enum FunctionID{
Integer result = functionMap.get(functionName);
return ( result == null ) ? INVALID_ID : result;
}
+
+ /**
+ * This method gives the corresponding FunctionID enum value for a string RPC
+ * @param name String value represents the name of the RPC
+ * @return FunctionID represents the equivalent enum value for the provided string
+ */
+ public static FunctionID getEnumForString(String name){
+ for(FunctionID value : EnumSet.allOf(FunctionID.class)) {
+ if(value.JSON_NAME.equals(name)){
+ return value;
+ }
+ }
+ return null;
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/RPCRequest.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/RPCRequest.java
index 370ffe1ec..db493fecf 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/RPCRequest.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/RPCRequest.java
@@ -21,6 +21,10 @@ public class RPCRequest extends RPCMessage {
super(hash);
}
+ public RPCRequest(RPCRequest request){
+ super(request);
+ setCorrelationID(CorrelationIdGenerator.generateId());
+ }
public Integer getCorrelationID() {
//First we check to see if a correlation ID is set. If not, create one.
if(!function.containsKey(RPCMessage.KEY_CORRELATION_ID)){
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/RPCRequestFactory.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/RPCRequestFactory.java
index 983c496a7..7f9986822 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/RPCRequestFactory.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/RPCRequestFactory.java
@@ -502,6 +502,7 @@ public class RPCRequestFactory {
putFile.setFileType(fileType);
putFile.setPersistentFile(persistentFile);
putFile.setBulkData(fileData);
+ putFile.setCRC(fileData);
return putFile;
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/RPCStruct.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/RPCStruct.java
index 116c491df..f23fac781 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/RPCStruct.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/RPCStruct.java
@@ -1,6 +1,9 @@
package com.smartdevicelink.proxy;
+import android.util.Log;
+
import com.smartdevicelink.marshal.JsonRPCMarshaller;
+import com.smartdevicelink.util.Version;
import org.json.JSONException;
import org.json.JSONObject;
@@ -20,6 +23,10 @@ public class RPCStruct {
private byte[] _bulkData = null;
private Boolean protectedPayload = false;
+ private boolean formatRequested = false;
+ private Version rpcSpecVersion = null;
+
+
protected Hashtable<String, Object> store = null;
public boolean getStoreValue(String key) { // for unit testing
@@ -45,6 +52,7 @@ public class RPCStruct {
public void deserializeJSON(JSONObject jsonObject) throws JSONException {
store = JsonRPCMarshaller.deserializeJSONObject(jsonObject);
+
}
// deserializeJSONObject method moved to JsonRPCMarshaller for consistency
@@ -54,14 +62,14 @@ public class RPCStruct {
throws JSONException {
return JsonRPCMarshaller.deserializeJSONObject(jsonObject);
}
-
+
public JSONObject serializeJSON() throws JSONException {
return JsonRPCMarshaller.serializeHashtable(store);
}
@SuppressWarnings("unchecked")
- public JSONObject serializeJSON(byte version) throws JSONException {
- if (version > 1) {
+ public JSONObject serializeJSON(byte protocolVersion) throws JSONException {
+ if (protocolVersion > 1) {
String messageType = getMessageTypeName(store.keySet());
Hashtable<String, Object> function = (Hashtable<String, Object>) store.get(messageType);
Hashtable<String, Object> parameters = (Hashtable<String, Object>) function.get(RPCMessage.KEY_PARAMETERS);
@@ -69,6 +77,59 @@ public class RPCStruct {
} else return JsonRPCMarshaller.serializeHashtable(store);
}
+ /**
+ * This method should clean the the RPC to make sure it is compliant with the spec.
+ * <br><br><b> NOTE:</b> Super needs to be called at the END of the method
+ *
+ * @param rpcVersion the rpc spec version that has been negotiated. If value is null the
+ * the max value of RPC spec version this library supports should be used.
+ * @param formatParams if true, the format method will be called on subsequent params
+ */
+ public void format(Version rpcVersion, boolean formatParams){
+ formatRequested = true;
+ rpcSpecVersion = rpcVersion;
+ //Should override this method when breaking changes are made to the RPC spec
+ if(formatParams && store != null){
+ Hashtable<String, Object> parameters;
+
+ if(this instanceof RPCMessage) {
+ //If this is a message (request, response, notification) the parameters have to be
+ //retrieved from the store object.
+ String messageType = getMessageTypeName(store.keySet());
+ Hashtable<String, Object> function = (Hashtable<String, Object>) store.get(messageType);
+ parameters = (Hashtable<String, Object>) function.get(RPCMessage.KEY_PARAMETERS);
+ } else {
+ //If this is just an RPC struct the store itself should be used
+ parameters = store;
+ }
+
+ if (parameters != null) {
+ for(Object value:parameters.values()){
+ internalFormat(rpcVersion, value);
+ }
+ }
+ }
+ }
+
+ /**
+ * Cycles through parameters in this RPC to ensure they all get formated
+ * @param rpcVersion version of the rpc spec that should be used to format this rpc
+ * @param value the object to investigate if it needs to be formated
+ */
+ private void internalFormat(Version rpcVersion, Object value) {
+ if(value instanceof RPCStruct) {
+ ((RPCStruct)value).format(rpcVersion,true);
+ } else if(value instanceof List<?>) {
+ List<?> list = (List<?>)value;
+ if(list != null && list.size() > 0) {
+ for(Object listItem: list){
+ internalFormat(rpcVersion, listItem);
+ }
+ }
+ }
+ }
+
+
public byte[] getBulkData() {
return this._bulkData;
}
@@ -156,7 +217,12 @@ public class RPCStruct {
} else if (obj instanceof Hashtable) {
try {
Constructor constructor = tClass.getConstructor(Hashtable.class);
- return constructor.newInstance((Hashtable<String, Object>) obj);
+ Object customObject = constructor.newInstance((Hashtable<String, Object>) obj);
+ if(formatRequested && customObject instanceof RPCStruct){
+ ((RPCStruct)customObject).format(rpcSpecVersion,true);
+ }
+
+ return customObject;
} catch (Exception e) {
e.printStackTrace();
}
@@ -168,10 +234,17 @@ public class RPCStruct {
return list;
} else if (item instanceof Hashtable) {
List<Object> newList = new ArrayList<Object>();
+ Object customObject;
for (Object hashObj : list) {
try {
Constructor constructor = tClass.getConstructor(Hashtable.class);
- newList.add(constructor.newInstance((Hashtable<String, Object>)hashObj));
+ customObject = constructor.newInstance((Hashtable<String, Object>) hashObj);
+ if(formatRequested
+ && customObject != null
+ && customObject instanceof RPCStruct){
+ ((RPCStruct)customObject).format(rpcSpecVersion,true);
+ }
+ newList.add(customObject);
} catch (Exception e) {
e.printStackTrace();
return null;
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyALM.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyALM.java
index a9cec4f10..d3690146c 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyALM.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyALM.java
@@ -6,6 +6,7 @@ import java.util.Vector;
import android.app.Service;
import android.content.Context;
+import com.smartdevicelink.proxy.rpc.TemplateColorScheme;
import com.smartdevicelink.exception.SdlException;
import com.smartdevicelink.exception.SdlExceptionCause;
import com.smartdevicelink.proxy.interfaces.IProxyListenerALM;
@@ -16,7 +17,6 @@ import com.smartdevicelink.proxy.rpc.HMICapabilities;
import com.smartdevicelink.proxy.rpc.PresetBankCapabilities;
import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
import com.smartdevicelink.proxy.rpc.SoftButtonCapabilities;
-import com.smartdevicelink.proxy.rpc.SystemCapability;
import com.smartdevicelink.proxy.rpc.TTSChunk;
import com.smartdevicelink.proxy.rpc.VehicleType;
import com.smartdevicelink.proxy.rpc.enums.AppHMIType;
@@ -1022,6 +1022,32 @@ public class SdlProxyALM extends SdlProxyBase<IProxyListenerALM> {
"appName, isMediaApp, appID", SDL_LIB_TRACE_KEY);
}
+ public SdlProxyALM(IProxyListenerALM listener, String appName, Boolean isMediaApp, String appID,
+ TemplateColorScheme dayColorScheme, TemplateColorScheme nightColorScheme, BaseTransportConfig transportConfig) throws SdlException {
+ super( listener,
+ /*sdlProxyConfigurationResources*/null,
+ /*enable advanced lifecycle management*/true,
+ appName,
+ /*ttsName*/null,
+ /*ngnMediaScreenAppName*/null,
+ /*vrSynonyms*/null,
+ isMediaApp,
+ /*sdlMsgVersion*/null,
+ /*languageDesired*/null,
+ /*hmiDisplayLanguageDesired*/null,
+ /*App Type*/null,
+ /*App ID*/appID,
+ /*autoActivateID*/null,
+ dayColorScheme,
+ nightColorScheme,
+ false,
+ false,
+ transportConfig);
+
+ SdlTrace.logProxyEvent("Application constructed SdlProxyALM (using legacy constructor for BT transport) instance passing in: IProxyListener, " +
+ "appName, isMediaApp, appID, dayColorScheme, nightColorScheme", SDL_LIB_TRACE_KEY);
+ }
+
/**
* @deprecated
* Constructor for the SdlProxy object, the proxy for communicating between the App and SDL via specified transport.
@@ -1568,6 +1594,8 @@ public class SdlProxyALM extends SdlProxyBase<IProxyListenerALM> {
/*App Type*/appType,
/*App ID*/appID,
autoActivateID,
+ null,
+ null,
callbackToUIThread,
preRegister,
/*sHashID*/sHashID,
@@ -1597,6 +1625,8 @@ public class SdlProxyALM extends SdlProxyBase<IProxyListenerALM> {
/*App Type*/appType,
/*App ID*/appID,
autoActivateID,
+ null,
+ null,
callbackToUIThread,
preRegister,
/*sHashID*/sHashID,
@@ -1610,6 +1640,40 @@ public class SdlProxyALM extends SdlProxyBase<IProxyListenerALM> {
"appName, ngnMediaScreenAppName, vrSynonyms, isMediaApp, sdlMsgVersion, languageDesired, appType, appID, autoActivateID, " +
"callbackToUIThread and version", SDL_LIB_TRACE_KEY);
}
+ public SdlProxyALM(Service appService, IProxyListenerALM listener, SdlProxyConfigurationResources sdlProxyConfigurationResources,
+ String appName, Vector<TTSChunk> ttsName, String ngnMediaScreenAppName, Vector<String> vrSynonyms, Boolean isMediaApp,
+ SdlMsgVersion sdlMsgVersion, Language languageDesired, Language hmiDisplayLanguageDesired, Vector<AppHMIType> appType,
+ String appID, String autoActivateID, TemplateColorScheme dayColorScheme, TemplateColorScheme nightColorScheme, boolean callbackToUIThread, boolean preRegister, String sHashID,
+ BaseTransportConfig transportConfig) throws SdlException {
+ super( listener,
+ sdlProxyConfigurationResources,
+ /*enable advanced lifecycle management*/true,
+ appName,
+ ttsName,
+ ngnMediaScreenAppName,
+ vrSynonyms,
+ isMediaApp,
+ sdlMsgVersion,
+ languageDesired,
+ /*HMI Display Language Desired*/hmiDisplayLanguageDesired,
+ /*App Type*/appType,
+ /*App ID*/appID,
+ autoActivateID,
+ dayColorScheme,
+ nightColorScheme,
+ callbackToUIThread,
+ preRegister,
+ /*sHashID*/sHashID,
+ /*bEnableResume*/true,
+ transportConfig);
+
+ this.setAppService(appService);
+ this.sendTransportBroadcast();
+
+ SdlTrace.logProxyEvent("Application constructed SdlProxyALM (using new constructor with specified transport) instance passing in: IProxyListener, sdlProxyConfigurationResources, " +
+ "appName, ngnMediaScreenAppName, vrSynonyms, isMediaApp, sdlMsgVersion, languageDesired, appType, appID, autoActivateID, dayColorScheme, nightColorScheme" +
+ "callbackToUIThread and version", SDL_LIB_TRACE_KEY);
+ }
/***************************************** END OF TRANSPORT SWITCHING SUPPORT ***************************************/
// Allow applications using ALM to reset the proxy (dispose and reinstantiate)
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java
index ea55702bd..2bdf94762 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java
@@ -1,30 +1,5 @@
package com.smartdevicelink.proxy;
-import java.io.BufferedReader;
-import java.io.DataOutputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.ProtocolException;
-import java.net.URL;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Vector;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.Executors;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.ScheduledExecutorService;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
import android.annotation.TargetApi;
import android.app.Service;
import android.content.Context;
@@ -50,6 +25,7 @@ import com.smartdevicelink.Dispatcher.ProxyMessageDispatcher;
import com.smartdevicelink.SdlConnection.ISdlConnectionListener;
import com.smartdevicelink.SdlConnection.SdlConnection;
import com.smartdevicelink.SdlConnection.SdlSession;
+import com.smartdevicelink.SdlConnection.SdlSession2;
import com.smartdevicelink.encoder.VirtualDisplayEncoder;
import com.smartdevicelink.exception.SdlException;
import com.smartdevicelink.exception.SdlExceptionCause;
@@ -99,22 +75,54 @@ import com.smartdevicelink.proxy.rpc.enums.TouchType;
import com.smartdevicelink.proxy.rpc.enums.UpdateMode;
import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
import com.smartdevicelink.proxy.rpc.listeners.OnPutFileUpdateListener;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCListener;
import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener;
import com.smartdevicelink.security.SdlSecurityBase;
+import com.smartdevicelink.streaming.StreamRPCPacketizer;
import com.smartdevicelink.streaming.audio.AudioStreamingCodec;
import com.smartdevicelink.streaming.audio.AudioStreamingParams;
-import com.smartdevicelink.streaming.StreamRPCPacketizer;
import com.smartdevicelink.streaming.video.SdlRemoteDisplay;
import com.smartdevicelink.streaming.video.VideoStreamingParameters;
import com.smartdevicelink.trace.SdlTrace;
import com.smartdevicelink.trace.TraceDeviceInfo;
import com.smartdevicelink.trace.enums.InterfaceActivityDirection;
import com.smartdevicelink.transport.BaseTransportConfig;
+import com.smartdevicelink.transport.MultiplexTransportConfig;
import com.smartdevicelink.transport.SiphonServer;
+import com.smartdevicelink.transport.USBTransportConfig;
import com.smartdevicelink.transport.enums.TransportType;
import com.smartdevicelink.util.CorrelationIdGenerator;
import com.smartdevicelink.util.DebugTool;
+import com.smartdevicelink.util.Version;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.ProtocolException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.ScheduledExecutorService;
+
@SuppressWarnings({"WeakerAccess", "Convert2Diamond"})
@@ -125,12 +133,13 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
private static final int PROX_PROT_VER_ONE = 1;
private static final int RESPONSE_WAIT_TIME = 2000;
- private static final com.smartdevicelink.util.Version MAX_SUPPORTED_RPC_VERSION = new com.smartdevicelink.util.Version("4.5.0");
+ public static final com.smartdevicelink.util.Version MAX_SUPPORTED_RPC_VERSION = new com.smartdevicelink.util.Version("5.0.0");
private SdlSession sdlSession = null;
private proxyListenerType _proxyListener = null;
protected Service _appService = null;
+ private Context _appContext;
private String sPoliciesURL = ""; //for testing only
// Protected Correlation IDs
@@ -191,6 +200,8 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
private Language _hmiDisplayLanguageDesired = null;
private Vector<AppHMIType> _appType = null;
private String _appID = null;
+ private TemplateColorScheme _dayColorScheme = null;
+ private TemplateColorScheme _nightColorScheme = null;
@SuppressWarnings({"FieldCanBeLocal", "unused"}) //Need to understand what this is used for
private String _autoActivateIdDesired = null;
private String _lastHashID = null;
@@ -232,16 +243,19 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
protected Boolean _bResumeSuccess = false;
protected List<Class<? extends SdlSecurityBase>> _secList = null;
protected SystemCapabilityManager _systemCapabilityManager;
+ protected Boolean _iconResumed = false;
private final CopyOnWriteArrayList<IPutFileResponseListener> _putFileListenerList = new CopyOnWriteArrayList<IPutFileResponseListener>();
- protected byte _wiproVersion = 1;
+ protected com.smartdevicelink.util.Version protocolVersion = new com.smartdevicelink.util.Version(1,0,0);
+ protected com.smartdevicelink.util.Version rpcSpecVersion;
protected SparseArray<OnRPCResponseListener> rpcResponseListeners = null;
protected SparseArray<CopyOnWriteArrayList<OnRPCNotificationListener>> rpcNotificationListeners = null;
protected VideoStreamingManager manager; //Will move to SdlSession once the class becomes public
+
// Interface broker
private SdlInterfaceBroker _interfaceBroker = null;
//We create an easily passable anonymous class of the interface so that we don't expose the internal interface to developers
@@ -294,24 +308,25 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
}
- @Override
- public void startAudioService(boolean encrypted) {
+ @Override public void stopAudioService() {
if(isConnected()){
- sdlSession.startService(SessionType.PCM,sdlSession.getSessionId(),encrypted);
+ sdlSession.endService(SessionType.PCM,sdlSession.getSessionId());
}
}
@Override
- public void stopAudioService() {
- if(isConnected()){
- sdlSession.endService(SessionType.PCM,sdlSession.getSessionId());
+ public void sendRPCRequest(RPCRequest message){
+ try {
+ SdlProxyBase.this.sendRPCRequest(message);
+ } catch (SdlException e) {
+ e.printStackTrace();
}
}
@Override
- public void sendRPCRequest(RPCRequest message){
+ public void sendRequests(List<? extends RPCRequest> rpcs, OnMultipleRequestListener listener) {
try {
- SdlProxyBase.this.sendRPCRequest(message);
+ SdlProxyBase.this.sendRequests(rpcs, listener);
} catch (SdlException e) {
e.printStackTrace();
}
@@ -326,6 +341,90 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
public boolean removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener) {
return SdlProxyBase.this.removeOnRPCNotificationListener(notificationId,listener);
}
+
+ @Override
+ public void addOnRPCListener(FunctionID responseId, OnRPCListener listener) {
+ DebugTool.logError("Proxy.addOnRPCResponseListener() is not implemented yet");
+
+ }
+
+ @Override
+ public boolean removeOnRPCListener(FunctionID responseId, OnRPCListener listener) {
+ DebugTool.logError("Proxy.removeOnRPCResponseListener() is not implemented yet");
+ return false;
+ }
+
+ @Override
+ public Object getCapability(SystemCapabilityType systemCapabilityType){
+ return SdlProxyBase.this.getCapability(systemCapabilityType);
+ }
+
+ @Override
+ public void getCapability(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener scListener) {
+ SdlProxyBase.this.getCapability(systemCapabilityType, scListener);
+ }
+
+ @Override
+ public SdlMsgVersion getSdlMsgVersion(){
+ try {
+ return SdlProxyBase.this.getSdlMsgVersion();
+ } catch (SdlException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public com.smartdevicelink.util.Version getProtocolVersion() {
+ return SdlProxyBase.this.protocolVersion;
+ }
+
+ @Override
+ public boolean isCapabilitySupported(SystemCapabilityType systemCapabilityType){
+ return SdlProxyBase.this.isCapabilitySupported(systemCapabilityType);
+ }
+
+ @Override
+ public void addOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) {
+ SdlProxyBase.this.removeOnSystemCapabilityListener(systemCapabilityType, listener);
+ }
+
+ @Override
+ public boolean removeOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener) {
+ return SdlProxyBase.this.removeOnSystemCapabilityListener(systemCapabilityType, listener);
+ }
+
+ @Override
+ public boolean isTransportForServiceAvailable(SessionType serviceType) {
+ return SdlProxyBase.this.sdlSession != null
+ && SdlProxyBase.this.sdlSession.isTransportForServiceAvailable(serviceType);
+ }
+
+ @Override
+ public void startAudioService(boolean isEncrypted, AudioStreamingCodec codec,
+ AudioStreamingParams params) {
+ if(getIsConnected()){
+ SdlProxyBase.this.startAudioStream(isEncrypted, codec, params);
+ }
+ }
+
+ @Override
+ public void startAudioService(boolean encrypted) {
+ if(isConnected()){
+ sdlSession.startService(SessionType.PCM,sdlSession.getSessionId(),encrypted);
+ }
+ }
+
+ @Override
+ public IVideoStreamListener startVideoStream(boolean isEncrypted, VideoStreamingParameters parameters){
+ return SdlProxyBase.this.startVideoStream(isEncrypted, parameters);
+ }
+
+ @Override
+ public IAudioStreamListener startAudioStream(boolean isEncrypted, AudioStreamingCodec codec,
+ AudioStreamingParams params) {
+ return SdlProxyBase.this.startAudioStream(isEncrypted, codec, params);
+ }
};
private void notifyPutFileStreamError(Exception e, String info)
@@ -361,14 +460,29 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// disconnect has completed
notifyPutFileStreamError(null, info);
- if (!_advancedLifecycleManagementEnabled) {
+ //if (!_advancedLifecycleManagementEnabled) {
// If original model, notify app the proxy is closed so it will delete and reinstanciate
- notifyProxyClosed(info, new SdlException("Transport disconnected.", SdlExceptionCause.SDL_UNAVAILABLE), SdlDisconnectedReason.TRANSPORT_DISCONNECT);
- }// else If ALM, nothing is required to be done here
+ Log.d(TAG, "notifying proxy of closed");
+ notifyProxyClosed(info, new SdlException("Transport disconnected.", SdlExceptionCause.SDL_UNAVAILABLE), SdlDisconnectedReason.TRANSPORT_DISCONNECT);
+ //}// else If ALM, nothing is required to be done here
}
@Override
+ public void onTransportDisconnected(String info, boolean altTransportAvailable, MultiplexTransportConfig transportConfig) {
+ notifyPutFileStreamError(null, info);
+
+ if( altTransportAvailable){
+ SdlProxyBase.this._transportConfig = transportConfig;
+ Log.d(TAG, "notifying RPC session ended, but potential primary transport available");
+ cycleProxy(SdlDisconnectedReason.PRIMARY_TRANSPORT_CYCLE_REQUEST);
+
+ }else{
+ notifyProxyClosed(info, new SdlException("Transport disconnected.", SdlExceptionCause.SDL_UNAVAILABLE), SdlDisconnectedReason.TRANSPORT_DISCONNECT);
+ }
+ }
+
+ @Override
public void onTransportError(String info, Exception e) {
DebugTool.logError("Transport failure: " + info, e);
@@ -376,7 +490,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
if (_advancedLifecycleManagementEnabled) {
// Cycle the proxy
- if(SdlConnection.isLegacyModeEnabled()){
+ if(SdlConnection.isLegacyModeEnabled()){ //FIXME
cycleProxy(SdlDisconnectedReason.LEGACY_BLUETOOTH_MODE_ENABLED);
}else{
@@ -408,8 +522,12 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
updateBroadcastIntent(sendIntent, "COMMENT2", " ServiceType: " + sessionType.getName());
updateBroadcastIntent(sendIntent, "COMMENT3", " Encrypted: " + isEncrypted);
sendBroadcastIntent(sendIntent);
-
- setWiProVersion(version);
+
+ if(sdlSession!= null){
+ setProtocolVersion(sdlSession.getProtocolVersion());
+ }else{
+ setProtocolVersion(new com.smartdevicelink.util.Version(version,0,0));
+ }
if (sessionType.eq(SessionType.RPC)) {
@@ -439,7 +557,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (sessionType.eq(SessionType.RPC)){
cycleProxy(SdlDisconnectedReason.RPC_SESSION_ENDED);
}
- else if (_wiproVersion > 1) {
+ else if (protocolVersion!= null && protocolVersion.getMajor() > 1) {
//If version is 2 or above then don't need to specify a Session Type
startRPCProtocolSession();
} //else{} Handle other protocol session types here
@@ -559,6 +677,32 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
}
}
+
+ /**
+ * Used by the SdlManager
+ *
+ * @param listener Type of listener for this proxy base.
+ * @param context Application context.
+ * @param appName Client application name.
+ * @param shortAppName Client short application name.
+ * @param isMediaApp Flag that indicates that client application if media application or not.
+ * @param languageDesired Desired language.
+ * @param hmiDisplayLanguageDesired Desired language for HMI.
+ * @param appType Type of application.
+ * @param appID Application identifier.
+ * @param dayColorScheme TemplateColorScheme for the day
+ * @param nightColorScheme TemplateColorScheme for the night
+ * @param transportConfig Configuration of transport to be used by underlying connection.
+ * @param vrSynonyms List of synonyms.
+ * @param ttsName TTS name.
+ * @throws SdlException
+ */
+ public SdlProxyBase(proxyListenerType listener, Context context, String appName,String shortAppName, Boolean isMediaApp, Language languageDesired, Language hmiDisplayLanguageDesired, Vector<AppHMIType> appType, String appID,
+ BaseTransportConfig transportConfig, Vector<String> vrSynonyms, Vector<TTSChunk> ttsName, TemplateColorScheme dayColorScheme, TemplateColorScheme nightColorScheme) throws SdlException {
+ performBaseCommon(listener, null, true, appName, ttsName, shortAppName, vrSynonyms, isMediaApp,
+ null, languageDesired, hmiDisplayLanguageDesired, appType, appID, null, dayColorScheme,nightColorScheme, false, false, null, null, transportConfig);
+ _appContext = context;
+ }
/**
* Constructor.
@@ -589,7 +733,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
throws SdlException {
performBaseCommon(listener, sdlProxyConfigurationResources, enableAdvancedLifecycleManagement, appName, ttsName, ngnMediaScreenAppName, vrSynonyms, isMediaApp,
- sdlMsgVersion, languageDesired, hmiDisplayLanguageDesired, appType, appID, autoActivateID, callbackToUIThread, null, null, null, transportConfig);
+ sdlMsgVersion, languageDesired, hmiDisplayLanguageDesired, appType, appID, autoActivateID, null, null, callbackToUIThread, null, null, null, transportConfig);
}
@SuppressWarnings("ConstantConditions")
@@ -597,11 +741,12 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
boolean enableAdvancedLifecycleManagement, String appName, Vector<TTSChunk> ttsName,
String ngnMediaScreenAppName, Vector<String> vrSynonyms, Boolean isMediaApp, SdlMsgVersion sdlMsgVersion,
Language languageDesired, Language hmiDisplayLanguageDesired, Vector<AppHMIType> appType, String appID,
- String autoActivateID, boolean callbackToUIThread, Boolean preRegister, String sHashID, Boolean bAppResumeEnab,
+ String autoActivateID, TemplateColorScheme dayColorScheme, TemplateColorScheme nightColorScheme,
+ boolean callbackToUIThread, Boolean preRegister, String sHashID, Boolean bAppResumeEnab,
BaseTransportConfig transportConfig) throws SdlException
{
- Log.i(TAG, "SDL_LIB_VERSION: " + Version.VERSION);
- setWiProVersion((byte)PROX_PROT_VER_ONE);
+ Log.i(TAG, "SDL_LIB_VERSION: " + com.smartdevicelink.proxy.Version.VERSION);
+ setProtocolVersion(new Version(PROX_PROT_VER_ONE,0,0));
if (preRegister != null && preRegister)
{
@@ -635,6 +780,8 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
_appType = appType;
_appID = appID;
_autoActivateIdDesired = autoActivateID;
+ _dayColorScheme = dayColorScheme;
+ _nightColorScheme = nightColorScheme;
_transportConfig = transportConfig;
// Test conditions to invalidate the proxy
@@ -783,15 +930,14 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
boolean enableAdvancedLifecycleManagement, String appName, Vector<TTSChunk> ttsName,
String ngnMediaScreenAppName, Vector<String> vrSynonyms, Boolean isMediaApp, SdlMsgVersion sdlMsgVersion,
Language languageDesired, Language hmiDisplayLanguageDesired, Vector<AppHMIType> appType, String appID,
- String autoActivateID, boolean callbackToUIThread, boolean preRegister, String sHashID, Boolean bEnableResume, BaseTransportConfig transportConfig)
+ String autoActivateID, TemplateColorScheme dayColorScheme, TemplateColorScheme nightColorScheme,
+ boolean callbackToUIThread, boolean preRegister, String sHashID, Boolean bEnableResume, BaseTransportConfig transportConfig)
throws SdlException
{
performBaseCommon(listener, sdlProxyConfigurationResources, enableAdvancedLifecycleManagement, appName, ttsName, ngnMediaScreenAppName, vrSynonyms, isMediaApp,
- sdlMsgVersion, languageDesired, hmiDisplayLanguageDesired, appType, appID, autoActivateID, callbackToUIThread, preRegister, sHashID, bEnableResume, transportConfig);
+ sdlMsgVersion, languageDesired, hmiDisplayLanguageDesired, appType, appID, autoActivateID, dayColorScheme, nightColorScheme, callbackToUIThread, preRegister, sHashID, bEnableResume, transportConfig);
}
-
-
/**
* Constructor.
*
@@ -814,15 +960,51 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
* @param transportConfig Configuration of transport to be used by underlying connection.
* @throws SdlException if there is an unrecoverable error class might throw an exception.
*/
- protected SdlProxyBase(proxyListenerType listener, SdlProxyConfigurationResources sdlProxyConfigurationResources,
- boolean enableAdvancedLifecycleManagement, String appName, Vector<TTSChunk> ttsName,
- String ngnMediaScreenAppName, Vector<String> vrSynonyms, Boolean isMediaApp, SdlMsgVersion sdlMsgVersion,
- Language languageDesired, Language hmiDisplayLanguageDesired, Vector<AppHMIType> appType, String appID,
- String autoActivateID, boolean callbackToUIThread, boolean preRegister, BaseTransportConfig transportConfig)
+ protected SdlProxyBase(proxyListenerType listener, SdlProxyConfigurationResources sdlProxyConfigurationResources,
+ boolean enableAdvancedLifecycleManagement, String appName, Vector<TTSChunk> ttsName,
+ String ngnMediaScreenAppName, Vector<String> vrSynonyms, Boolean isMediaApp, SdlMsgVersion sdlMsgVersion,
+ Language languageDesired, Language hmiDisplayLanguageDesired, Vector<AppHMIType> appType, String appID,
+ String autoActivateID, boolean callbackToUIThread, boolean preRegister, BaseTransportConfig transportConfig)
throws SdlException
{
performBaseCommon(listener, sdlProxyConfigurationResources, enableAdvancedLifecycleManagement, appName, ttsName, ngnMediaScreenAppName, vrSynonyms, isMediaApp,
- sdlMsgVersion, languageDesired, hmiDisplayLanguageDesired, appType, appID, autoActivateID, callbackToUIThread, preRegister, null, null, transportConfig);
+ sdlMsgVersion, languageDesired, hmiDisplayLanguageDesired, appType, appID, autoActivateID, null, null, callbackToUIThread, preRegister, null, null, transportConfig);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param listener Type of listener for this proxy base.
+ * @param sdlProxyConfigurationResources Configuration resources for this proxy.
+ * @param enableAdvancedLifecycleManagement Flag that ALM should be enabled or not.
+ * @param appName Client application name.
+ * @param ttsName TTS name.
+ * @param ngnMediaScreenAppName Media Screen Application name.
+ * @param vrSynonyms List of synonyms.
+ * @param isMediaApp Flag that indicates that client application if media application or not.
+ * @param sdlMsgVersion Version of Sdl Message.
+ * @param languageDesired Desired language.
+ * @param hmiDisplayLanguageDesired Desired language for HMI.
+ * @param appType Type of application.
+ * @param appID Application identifier.
+ * @param autoActivateID Auto activation identifier.
+ * @param dayColorScheme Day color scheme.
+ * @param dayColorScheme Night color scheme.
+ * @param callbackToUIThread Flag that indicates that this proxy should send callback to UI thread or not.
+ * @param preRegister Flag that indicates that this proxy should be pre-registerd or not.
+ * @param transportConfig Configuration of transport to be used by underlying connection.
+ * @throws SdlException if there is an unrecoverable error class might throw an exception.
+ */
+ protected SdlProxyBase(proxyListenerType listener, SdlProxyConfigurationResources sdlProxyConfigurationResources,
+ boolean enableAdvancedLifecycleManagement, String appName, Vector<TTSChunk> ttsName,
+ String ngnMediaScreenAppName, Vector<String> vrSynonyms, Boolean isMediaApp, SdlMsgVersion sdlMsgVersion,
+ Language languageDesired, Language hmiDisplayLanguageDesired, Vector<AppHMIType> appType, String appID,
+ String autoActivateID, TemplateColorScheme dayColorScheme, TemplateColorScheme nightColorScheme,
+ boolean callbackToUIThread, boolean preRegister, BaseTransportConfig transportConfig)
+ throws SdlException
+ {
+ performBaseCommon(listener, sdlProxyConfigurationResources, enableAdvancedLifecycleManagement, appName, ttsName, ngnMediaScreenAppName, vrSynonyms, isMediaApp,
+ sdlMsgVersion, languageDesired, hmiDisplayLanguageDesired, appType, appID, autoActivateID, dayColorScheme, nightColorScheme, callbackToUIThread, preRegister, null, null, transportConfig);
}
private Intent createBroadcastIntent()
@@ -892,7 +1074,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
private void sendBroadcastIntent(Intent sendIntent)
{
- Service myService;
+ Service myService = null;
if (_proxyListener != null && _proxyListener instanceof Service)
{
myService = (Service) _proxyListener;
@@ -901,13 +1083,18 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
{
myService = _appService;
}
+ Context myContext;
+ if (myService != null){
+ myContext = myService.getApplicationContext();
+ } else if (_appContext != null){
+ myContext = _appContext;
+ }
else
{
return;
}
try
{
- Context myContext = myService.getApplicationContext();
if (myContext != null) myContext.sendBroadcast(sendIntent);
}
catch(Exception ex)
@@ -1102,6 +1289,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
putFile.setCorrelationID(POLICIES_CORRELATION_ID);
putFile.setSdlFileName("response_data");
putFile.setFileData(response.toString().getBytes("UTF-8"));
+ putFile.setCRC(response.toString().getBytes());
updateBroadcastIntent(sendIntent, "DATA", "Data from cloud response: " + response.toString());
sendRPCRequestPrivate(putFile);
@@ -1271,7 +1459,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
// Function to initialize new proxy connection
- private void initializeProxy() throws SdlException {
+ public void initializeProxy() throws SdlException {
// Reset all of the flags and state variables
_haveReceivedFirstNonNoneHMILevel = false;
_haveReceivedFirstFocusLevel = false;
@@ -1282,11 +1470,33 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
_sdlIntefaceAvailablity = SdlInterfaceAvailability.SDL_INTERFACE_UNAVAILABLE;
- //Initialize _systemCapabilityManager here.
+ //Initialize _systemCapabilityManager here.
_systemCapabilityManager = new SystemCapabilityManager(_internalInterface);
// Setup SdlConnection
synchronized(CONNECTION_REFERENCE_LOCK) {
- this.sdlSession = SdlSession.createSession(_wiproVersion,_interfaceBroker, _transportConfig);
+
+ //Handle legacy USB connections
+ if(_transportConfig != null
+ && TransportType.USB.equals(_transportConfig.getTransportType())){
+ //A USB transport config was provided
+ USBTransportConfig usbTransportConfig = (USBTransportConfig)_transportConfig;
+ if(usbTransportConfig.getUsbAccessory() == null){
+ DebugTool.logInfo("Legacy USB transport config was used, but received null for accessory. Attempting to connect with router service");
+ //The accessory was null which means it came from a router service
+ MultiplexTransportConfig multiplexTransportConfig = new MultiplexTransportConfig(usbTransportConfig.getUSBContext(),_appID);
+ multiplexTransportConfig.setRequiresHighBandwidth(true);
+ multiplexTransportConfig.setSecurityLevel(MultiplexTransportConfig.FLAG_MULTI_SECURITY_OFF);
+ multiplexTransportConfig.setPrimaryTransports(Collections.singletonList(TransportType.USB));
+ multiplexTransportConfig.setSecondaryTransports(new ArrayList<TransportType>());
+ _transportConfig = multiplexTransportConfig;
+ }
+ }
+
+ if(_transportConfig.getTransportType().equals(TransportType.MULTIPLEX)){
+ this.sdlSession = new SdlSession2(_interfaceBroker,(MultiplexTransportConfig)_transportConfig);
+ }else{
+ this.sdlSession = SdlSession.createSession((byte)getProtocolVersion().getMajor(),_interfaceBroker, _transportConfig);
+ }
}
synchronized(CONNECTION_REFERENCE_LOCK) {
@@ -1301,7 +1511,8 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
public void forceOnConnected(){
synchronized(CONNECTION_REFERENCE_LOCK) {
if (sdlSession != null) {
- if(sdlSession.getSdlConnection()==null){ //There is an issue when switching from v1 to v2+ where the connection is closed. So we restart the session during this call.
+ Log.d(TAG, "Forcing on connected.... might actually need this"); //FIXME
+ /*if(sdlSession.getSdlConnection()==null){ //There is an issue when switching from v1 to v2+ where the connection is closed. So we restart the session during this call.
try {
sdlSession.startSession();
} catch (SdlException e) {
@@ -1309,7 +1520,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
}
sdlSession.getSdlConnection().forceHardwareConnectEvent(TransportType.BLUETOOTH);
-
+ */
}
}
}
@@ -1383,9 +1594,37 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public static boolean isDebugEnabled() {
return DebugTool.isDebugEnabled();
- }
-
-
+ }
+
+
+ /**
+ * Check to see if it a transport is available to perform audio streaming.
+ * <br><strong>NOTE:</strong> This is only for the audio streaming service, not regular
+ * streaming of media playback.
+ * @return true if there is either an audio streaming supported
+ * transport currently connected or a transport is
+ * available to connect with. false if there is no
+ * transport connected to support audio streaming and
+ * no possibility in the foreseeable future.
+ */
+ public boolean isAudioStreamTransportAvailable(){
+ return sdlSession!= null && sdlSession.isTransportForServiceAvailable(SessionType.PCM);
+ }
+
+ /**
+ * Check to see if it a transport is available to perform video streaming.
+
+ * @return true if there is either an video streaming supported
+ * transport currently connected or a transport is
+ * available to connect with. false if there is no
+ * transport connected to support video streaming and
+ * no possibility in the foreseeable future.
+ */
+ public boolean isVideoStreamTransportAvailable(){
+ return sdlSession!= null && sdlSession.isTransportForServiceAvailable(SessionType.NAV);
+ }
+
+
@SuppressWarnings("unused")
@Deprecated
public void close() throws SdlException {
@@ -1505,7 +1744,8 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
_cycling = true;
cleanProxy(disconnectedReason);
initializeProxy();
- if(!SdlDisconnectedReason.LEGACY_BLUETOOTH_MODE_ENABLED.equals(disconnectedReason)){//We don't want to alert higher if we are just cycling for legacy bluetooth
+ if(!SdlDisconnectedReason.LEGACY_BLUETOOTH_MODE_ENABLED.equals(disconnectedReason)
+ && !SdlDisconnectedReason.PRIMARY_TRANSPORT_CYCLE_REQUEST.equals(disconnectedReason)){//We don't want to alert higher if we are just cycling for legacy bluetooth
notifyProxyClosed("Sdl Proxy Cycled", new SdlException("Sdl Proxy Cycled", SdlExceptionCause.SDL_PROXY_CYCLED), disconnectedReason);
}
}
@@ -1544,12 +1784,18 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
if (message.getSessionType().equals(SessionType.RPC)
||message.getSessionType().equals(SessionType.BULK_DATA) ) {
try {
- if (_wiproVersion == 1) {
- if (message.getVersion() > 1) setWiProVersion(message.getVersion());
+ if (protocolVersion!= null && protocolVersion.getMajor() == 1 && message.getVersion() > 1) {
+ if(sdlSession != null
+ && sdlSession.getProtocolVersion()!= null
+ && sdlSession.getProtocolVersion().getMajor() > 1){
+ setProtocolVersion(sdlSession.getProtocolVersion());
+ }else{
+ setProtocolVersion(new Version(message.getVersion(),0,0));
+ }
}
Hashtable<String, Object> hash = new Hashtable<String, Object>();
- if (_wiproVersion > 1) {
+ if (protocolVersion!= null && protocolVersion.getMajor() > 1) {
Hashtable<String, Object> hashTemp = new Hashtable<String, Object>();
hashTemp.put(RPCMessage.KEY_CORRELATION_ID, message.getCorrID());
if (message.getJsonSize() > 0) {
@@ -1591,21 +1837,27 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
passErrorToProxyListener("Error handing incoming protocol message.", e);
}
}
-
- private byte getWiProVersion() {
- return this._wiproVersion;
+
+ /**
+ * Get the SDL protocol spec version being used
+ * @return Version of the protocol spec
+ */
+ public @NonNull Version getProtocolVersion(){
+ if(this.protocolVersion == null){
+ this.protocolVersion = new Version(1,0,0);
+ }
+ return this.protocolVersion;
}
-
- private void setWiProVersion(byte version) {
- this._wiproVersion = version;
+
+ private void setProtocolVersion(@NonNull Version version) {
+ this.protocolVersion = version;
}
-
+
public String serializeJSON(RPCMessage msg)
{
- String sReturn;
try
{
- sReturn = msg.serializeJSON(getWiProVersion()).toString(2);
+ return msg.serializeJSON((byte)this.getProtocolVersion().getMajor()).toString(2);
}
catch (final Exception e)
{
@@ -1613,7 +1865,6 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
passErrorToProxyListener("Error serializing message.", e);
return null;
}
- return sReturn;
}
private void handleErrorsFromIncomingMessageDispatcher(String info, Exception e) {
@@ -1758,7 +2009,8 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
try {
SdlTrace.logRPCEvent(InterfaceActivityDirection.Transmit, request, SDL_LIB_TRACE_KEY);
- byte[] msgBytes = JsonRPCMarshaller.marshall(request, _wiproVersion);
+ request.format(rpcSpecVersion,true);
+ byte[] msgBytes = JsonRPCMarshaller.marshall(request, (byte)getProtocolVersion().getMajor());
ProtocolMessage pm = new ProtocolMessage();
pm.setData(msgBytes);
@@ -1938,7 +2190,12 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
SdlSecurityBase sec;
Service svc = getService();
SdlSecurityBase.setAppService(svc);
-
+ if (svc != null && svc.getApplicationContext() != null){
+ SdlSecurityBase.setContext(svc.getApplicationContext());
+ } else {
+ SdlSecurityBase.setContext(_appContext);
+ }
+
for (Class<? extends SdlSecurityBase> cls : _secList)
{
try
@@ -1966,6 +2223,8 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
private void handleRPCMessage(Hashtable<String, Object> hash) {
RPCMessage rpcMsg = new RPCMessage(hash);
+ //Call format to ensure the RPC is ready to be handled regardless of RPC spec version
+
String functionName = rpcMsg.getFunctionName();
String messageType = rpcMsg.getMessageType();
@@ -1980,6 +2239,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
&& _advancedLifecycleManagementEnabled
&& functionName.equals(FunctionID.REGISTER_APP_INTERFACE.toString())) {
final RegisterAppInterfaceResponse msg = new RegisterAppInterfaceResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (msg.getSuccess()) {
_appInterfaceRegisterd = true;
}
@@ -2004,11 +2264,19 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
_sdlLanguage = msg.getLanguage();
_hmiDisplayLanguage = msg.getHmiDisplayLanguage();
_sdlMsgVersion = msg.getSdlMsgVersion();
+ if(_sdlMsgVersion != null){
+ rpcSpecVersion = new com.smartdevicelink.util.Version(_sdlMsgVersion.getMajorVersion(),_sdlMsgVersion.getMinorVersion(), _sdlMsgVersion.getPatchVersion());
+ }else{
+ rpcSpecVersion = MAX_SUPPORTED_RPC_VERSION;
+ }
_vehicleType = msg.getVehicleType();
_systemSoftwareVersion = msg.getSystemSoftwareVersion();
_proxyVersionInfo = msg.getProxyVersionInfo();
+ _iconResumed = msg.getIconResumed();
-
+ if (_iconResumed == null){
+ _iconResumed = false;
+ }
if (_bAppResumeEnabled)
{
@@ -2121,6 +2389,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
APP_INTERFACE_REGISTERED_LOCK.notify();
}
final UnregisterAppInterfaceResponse msg = new UnregisterAppInterfaceResponse(hash);
+ msg.format(rpcSpecVersion, true);
Intent sendIntent = createBroadcastIntent();
updateBroadcastIntent(sendIntent, "RPC_NAME", FunctionID.UNREGISTER_APP_INTERFACE.toString());
updateBroadcastIntent(sendIntent, "TYPE", RPCMessage.KEY_RESPONSE);
@@ -2136,6 +2405,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
if (functionName.equals(FunctionID.REGISTER_APP_INTERFACE.toString())) {
final RegisterAppInterfaceResponse msg = new RegisterAppInterfaceResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (msg.getSuccess()) {
_appInterfaceRegisterd = true;
}
@@ -2149,6 +2419,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
_sdlLanguage = msg.getLanguage();
_hmiDisplayLanguage = msg.getHmiDisplayLanguage();
_sdlMsgVersion = msg.getSdlMsgVersion();
+ rpcSpecVersion = new com.smartdevicelink.util.Version(_sdlMsgVersion.getMajorVersion(),_sdlMsgVersion.getMinorVersion(), _sdlMsgVersion.getPatchVersion());
_vehicleType = msg.getVehicleType();
_systemSoftwareVersion = msg.getSystemSoftwareVersion();
_proxyVersionInfo = msg.getProxyVersionInfo();
@@ -2209,6 +2480,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// SpeakResponse
final SpeakResponse msg = new SpeakResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2226,6 +2498,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// AlertResponse
final AlertResponse msg = new AlertResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2243,6 +2516,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// ShowResponse
final ShowResponse msg = new ShowResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2260,6 +2534,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// AddCommand
final AddCommandResponse msg = new AddCommandResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2277,6 +2552,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// DeleteCommandResponse
final DeleteCommandResponse msg = new DeleteCommandResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2294,6 +2570,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// AddSubMenu
final AddSubMenuResponse msg = new AddSubMenuResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2311,6 +2588,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// DeleteSubMenu
final DeleteSubMenuResponse msg = new DeleteSubMenuResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2328,6 +2606,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// SubscribeButton
final SubscribeButtonResponse msg = new SubscribeButtonResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2345,6 +2624,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// UnsubscribeButton
final UnsubscribeButtonResponse msg = new UnsubscribeButtonResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2362,6 +2642,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// SetMediaClockTimer
final SetMediaClockTimerResponse msg = new SetMediaClockTimerResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2378,7 +2659,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.ENCODED_SYNC_P_DATA.toString())) {
final SystemRequestResponse msg = new SystemRequestResponse(hash);
-
+ msg.format(rpcSpecVersion,true);
Intent sendIntent = createBroadcastIntent();
updateBroadcastIntent(sendIntent, "RPC_NAME", FunctionID.SYSTEM_REQUEST.toString());
updateBroadcastIntent(sendIntent, "TYPE", RPCMessage.KEY_RESPONSE);
@@ -2405,6 +2686,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// CreateInteractionChoiceSet
final CreateInteractionChoiceSetResponse msg = new CreateInteractionChoiceSetResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2422,6 +2704,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// DeleteInteractionChoiceSet
final DeleteInteractionChoiceSetResponse msg = new DeleteInteractionChoiceSetResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2439,6 +2722,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// PerformInteraction
final PerformInteractionResponse msg = new PerformInteractionResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2456,6 +2740,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// SetGlobalPropertiesResponse
final SetGlobalPropertiesResponse msg = new SetGlobalPropertiesResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2473,6 +2758,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// ResetGlobalProperties
final ResetGlobalPropertiesResponse msg = new ResetGlobalPropertiesResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2495,7 +2781,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
final UnregisterAppInterfaceResponse msg = new UnregisterAppInterfaceResponse(hash);
-
+ msg.format(rpcSpecVersion,true);
Intent sendIntent = createBroadcastIntent();
updateBroadcastIntent(sendIntent, "RPC_NAME", FunctionID.UNREGISTER_APP_INTERFACE.toString());
updateBroadcastIntent(sendIntent, "TYPE", RPCMessage.KEY_RESPONSE);
@@ -2528,6 +2814,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.GENERIC_RESPONSE.toString())) {
// GenericResponse (Usually and error)
final GenericResponse msg = new GenericResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2544,6 +2831,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.SLIDER.toString())) {
// Slider
final SliderResponse msg = new SliderResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2560,6 +2848,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.PUT_FILE.toString())) {
// PutFile
final PutFileResponse msg = new PutFileResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2578,6 +2867,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.DELETE_FILE.toString())) {
// DeleteFile
final DeleteFileResponse msg = new DeleteFileResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2594,6 +2884,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.LIST_FILES.toString())) {
// ListFiles
final ListFilesResponse msg = new ListFilesResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2610,6 +2901,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.SET_APP_ICON.toString())) {
// SetAppIcon
final SetAppIconResponse msg = new SetAppIconResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2626,6 +2918,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.SCROLLABLE_MESSAGE.toString())) {
// ScrollableMessage
final ScrollableMessageResponse msg = new ScrollableMessageResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2642,6 +2935,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.CHANGE_REGISTRATION.toString())) {
// ChangeLanguageRegistration
final ChangeRegistrationResponse msg = new ChangeRegistrationResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2658,7 +2952,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.SET_DISPLAY_LAYOUT.toString())) {
// SetDisplayLayout
final SetDisplayLayoutResponse msg = new SetDisplayLayoutResponse(hash);
-
+ msg.format(rpcSpecVersion,true);
// successfully changed display layout - update layout capabilities
if(msg.getSuccess() && _systemCapabilityManager!=null){
_systemCapabilityManager.setCapability(SystemCapabilityType.DISPLAY, msg.getDisplayCapabilities());
@@ -2683,6 +2977,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.PERFORM_AUDIO_PASS_THRU.toString())) {
// PerformAudioPassThru
final PerformAudioPassThruResponse msg = new PerformAudioPassThruResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2699,6 +2994,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.END_AUDIO_PASS_THRU.toString())) {
// EndAudioPassThru
final EndAudioPassThruResponse msg = new EndAudioPassThruResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2715,6 +3011,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.SUBSCRIBE_VEHICLE_DATA.toString())) {
// SubscribeVehicleData
final SubscribeVehicleDataResponse msg = new SubscribeVehicleDataResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2731,6 +3028,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.UNSUBSCRIBE_VEHICLE_DATA.toString())) {
// UnsubscribeVehicleData
final UnsubscribeVehicleDataResponse msg = new UnsubscribeVehicleDataResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2747,6 +3045,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.GET_VEHICLE_DATA.toString())) {
// GetVehicleData
final GetVehicleDataResponse msg = new GetVehicleDataResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2763,6 +3062,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.SUBSCRIBE_WAY_POINTS.toString())) {
// SubscribeWayPoints
final SubscribeWayPointsResponse msg = new SubscribeWayPointsResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2779,6 +3079,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.UNSUBSCRIBE_WAY_POINTS.toString())) {
// UnsubscribeWayPoints
final UnsubscribeWayPointsResponse msg = new UnsubscribeWayPointsResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2795,6 +3096,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.GET_WAY_POINTS.toString())) {
// GetWayPoints
final GetWayPointsResponse msg = new GetWayPointsResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2810,6 +3112,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
} else if (functionName.equals(FunctionID.READ_DID.toString())) {
final ReadDIDResponse msg = new ReadDIDResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2825,6 +3128,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
} else if (functionName.equals(FunctionID.GET_DTCS.toString())) {
final GetDTCsResponse msg = new GetDTCsResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2840,6 +3144,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
} else if (functionName.equals(FunctionID.DIAGNOSTIC_MESSAGE.toString())) {
final DiagnosticMessageResponse msg = new DiagnosticMessageResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2857,6 +3162,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
else if (functionName.equals(FunctionID.SYSTEM_REQUEST.toString())) {
final SystemRequestResponse msg = new SystemRequestResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2874,6 +3180,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
else if (functionName.equals(FunctionID.SEND_LOCATION.toString())) {
final SendLocationResponse msg = new SendLocationResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2891,6 +3198,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
else if (functionName.equals(FunctionID.DIAL_NUMBER.toString())) {
final DialNumberResponse msg = new DialNumberResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -2907,6 +3215,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
else if (functionName.equals(FunctionID.SHOW_CONSTANT_TBT.toString())) {
final ShowConstantTbtResponse msg = new ShowConstantTbtResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
_mainUIHandler.post(new Runnable() {
@Override
@@ -2922,6 +3231,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
else if (functionName.equals(FunctionID.ALERT_MANEUVER.toString())) {
final AlertManeuverResponse msg = new AlertManeuverResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
_mainUIHandler.post(new Runnable() {
@Override
@@ -2936,6 +3246,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
} else if (functionName.equals(FunctionID.UPDATE_TURN_LIST.toString())) {
final UpdateTurnListResponse msg = new UpdateTurnListResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
_mainUIHandler.post(new Runnable() {
@Override
@@ -2950,6 +3261,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
} else if (functionName.equals(FunctionID.SET_INTERIOR_VEHICLE_DATA.toString())) {
final SetInteriorVehicleDataResponse msg = new SetInteriorVehicleDataResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
_mainUIHandler.post(new Runnable() {
@Override
@@ -2964,6 +3276,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
} else if (functionName.equals(FunctionID.GET_INTERIOR_VEHICLE_DATA.toString())) {
final GetInteriorVehicleDataResponse msg = new GetInteriorVehicleDataResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
_mainUIHandler.post(new Runnable() {
@Override
@@ -2979,6 +3292,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.GET_SYSTEM_CAPABILITY.toString())) {
// GetSystemCapabilityResponse
final GetSystemCapabilityResponse msg = new GetSystemCapabilityResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
_mainUIHandler.post(new Runnable() {
@Override
@@ -2993,6 +3307,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
} else if (functionName.equals(FunctionID.BUTTON_PRESS.toString())) {
final ButtonPressResponse msg = new ButtonPressResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
_mainUIHandler.post(new Runnable() {
@Override
@@ -3007,6 +3322,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
} else if (functionName.equals(FunctionID.SEND_HAPTIC_DATA.toString())) {
final SendHapticDataResponse msg = new SendHapticDataResponse(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3049,6 +3365,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
_hmiLevel = msg.getHmiLevel();
_audioStreamingState = msg.getAudioStreamingState();
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3068,6 +3385,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// OnCommand
final OnCommand msg = new OnCommand(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3093,6 +3411,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
sdlSession.getLockScreenMan().setDriverDistStatus(drDist == DriverDistractionState.DD_ON);
}
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3119,7 +3438,8 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// If url is null, then send notification to the app, otherwise, send to URL
if (msg.getUrl() == null) {
updateBroadcastIntent(sendIntent, "COMMENT1", "URL is a null value (received)");
- sendBroadcastIntent(sendIntent);
+ sendBroadcastIntent(sendIntent);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3155,6 +3475,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
//OnPermissionsChange
final OnPermissionsChange msg = new OnPermissionsChange(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3172,6 +3493,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// OnTBTClientState
final OnTBTClientState msg = new OnTBTClientState(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3189,6 +3511,8 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// OnButtonPress
final OnButtonPress msg = new OnButtonPress(hash);
+ msg.format(rpcSpecVersion, true);
+ final OnButtonPress onButtonPressCompat = (OnButtonPress)handleButtonNotificationFormatting(msg);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3196,16 +3520,25 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
public void run() {
_proxyListener.onOnButtonPress(msg);
onRPCNotificationReceived(msg);
+ if(onButtonPressCompat != null){
+ _proxyListener.onOnButtonPress(onButtonPressCompat);
+ }
}
});
} else {
_proxyListener.onOnButtonPress(msg);
onRPCNotificationReceived(msg);
+ if(onButtonPressCompat != null){
+ _proxyListener.onOnButtonPress(onButtonPressCompat);
+ }
}
} else if (functionName.equals(FunctionID.ON_BUTTON_EVENT.toString())) {
// OnButtonEvent
final OnButtonEvent msg = new OnButtonEvent(hash);
+ msg.format(rpcSpecVersion, true);
+ final OnButtonEvent onButtonEventCompat = (OnButtonEvent)handleButtonNotificationFormatting(msg);
+
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3213,16 +3546,23 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
public void run() {
_proxyListener.onOnButtonEvent(msg);
onRPCNotificationReceived(msg);
+ if(onButtonEventCompat != null){
+ _proxyListener.onOnButtonEvent(onButtonEventCompat);
+ }
}
});
} else {
_proxyListener.onOnButtonEvent(msg);
onRPCNotificationReceived(msg);
+ if(onButtonEventCompat != null){
+ _proxyListener.onOnButtonEvent(onButtonEventCompat);
+ }
}
} else if (functionName.equals(FunctionID.ON_LANGUAGE_CHANGE.toString())) {
// OnLanguageChange
final OnLanguageChange msg = new OnLanguageChange(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3240,6 +3580,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// OnLanguageChange
final OnHashChange msg = new OnHashChange(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3265,7 +3606,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
// OnSystemRequest
final OnSystemRequest msg = new OnSystemRequest(hash);
-
+ msg.format(rpcSpecVersion,true);
if ((msg.getUrl() != null) &&
(((msg.getRequestType() == RequestType.PROPRIETARY) && (msg.getFileType() == FileType.JSON))
|| ((msg.getRequestType() == RequestType.HTTP) && (msg.getFileType() == FileType.BINARY)))){
@@ -3285,6 +3626,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
lockScreenIconRequest = msg;
}
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3301,6 +3643,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.ON_AUDIO_PASS_THRU.toString())) {
// OnAudioPassThru
final OnAudioPassThru msg = new OnAudioPassThru(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3317,6 +3660,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
} else if (functionName.equals(FunctionID.ON_VEHICLE_DATA.toString())) {
// OnVehicleData
final OnVehicleData msg = new OnVehicleData(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3340,6 +3684,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
final OnAppInterfaceUnregistered msg = new OnAppInterfaceUnregistered(hash);
+ msg.format(rpcSpecVersion,true);
Intent sendIntent = createBroadcastIntent();
updateBroadcastIntent(sendIntent, "RPC_NAME", FunctionID.ON_APP_INTERFACE_UNREGISTERED.toString());
@@ -3369,6 +3714,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
else if (functionName.equals(FunctionID.ON_KEYBOARD_INPUT.toString())) {
final OnKeyboardInput msg = new OnKeyboardInput(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3385,6 +3731,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
else if (functionName.equals(FunctionID.ON_TOUCH_EVENT.toString())) {
final OnTouchEvent msg = new OnTouchEvent(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3401,6 +3748,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
else if (functionName.equals(FunctionID.ON_WAY_POINT_CHANGE.toString())) {
final OnWayPointChange msg = new OnWayPointChange(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3417,6 +3765,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
else if (functionName.equals(FunctionID.ON_INTERIOR_VEHICLE_DATA.toString())) {
final OnInteriorVehicleData msg = new OnInteriorVehicleData(hash);
+ msg.format(rpcSpecVersion, true);
if (_callbackToUIThread) {
// Run in UI thread
_mainUIHandler.post(new Runnable() {
@@ -3431,6 +3780,23 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
onRPCNotificationReceived(msg);
}
}
+ else if (functionName.equals(FunctionID.ON_RC_STATUS.toString())) {
+ final OnRCStatus msg = new OnRCStatus(hash);
+ msg.format(rpcSpecVersion, true);
+ if (_callbackToUIThread) {
+ // Run in UI thread
+ _mainUIHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ _proxyListener.onOnRCStatus(msg);
+ onRPCNotificationReceived(msg);
+ }
+ });
+ } else {
+ _proxyListener.onOnRCStatus(msg);
+ onRPCNotificationReceived(msg);
+ }
+ }
else {
if (_sdlMsgVersion != null) {
DebugTool.logInfo("Unrecognized notification Message: " + functionName +
@@ -3444,6 +3810,67 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
SdlTrace.logProxyEvent("Proxy received RPC Message: " + functionName, SDL_LIB_TRACE_KEY);
}
+ //FIXME
+ /**
+ * Temporary method to bridge the new PLAY_PAUSE and OKAY button functionality with the old
+ * OK button name. This should be removed during the next major release
+ * @param notification
+ */
+ private RPCNotification handleButtonNotificationFormatting(RPCNotification notification){
+ if(FunctionID.ON_BUTTON_EVENT.toString().equals(notification.getFunctionName())
+ || FunctionID.ON_BUTTON_PRESS.toString().equals(notification.getFunctionName())){
+
+ ButtonName buttonName = (ButtonName)notification.getObject(ButtonName.class, OnButtonEvent.KEY_BUTTON_NAME);
+ ButtonName compatBtnName = null;
+
+ if(rpcSpecVersion != null && rpcSpecVersion.getMajor() >= 5){
+ if(ButtonName.PLAY_PAUSE.equals(buttonName)){
+ compatBtnName = ButtonName.OK;
+ }
+ }else{ // rpc spec version is either null or less than 5
+ if(ButtonName.OK.equals(buttonName)){
+ compatBtnName = ButtonName.PLAY_PAUSE;
+ }
+ }
+
+ try {
+ if (compatBtnName != null) { //There is a button name that needs to be swapped out
+ RPCNotification notification2;
+ //The following is done because there is currently no way to make a deep copy
+ //of an RPC. Since this code will be removed, it's ugliness is borderline acceptable.
+ if (notification instanceof OnButtonEvent) {
+ OnButtonEvent onButtonEvent = new OnButtonEvent();
+ onButtonEvent.setButtonEventMode(((OnButtonEvent) notification).getButtonEventMode());
+ onButtonEvent.setCustomButtonID(((OnButtonEvent) notification).getCustomButtonID());
+ notification2 = onButtonEvent;
+ } else if (notification instanceof OnButtonPress) {
+ OnButtonPress onButtonPress = new OnButtonPress();
+ onButtonPress.setButtonPressMode(((OnButtonPress) notification).getButtonPressMode());
+ onButtonPress.setCustomButtonName(((OnButtonPress) notification).getCustomButtonName());
+ notification2 = onButtonPress;
+ } else {
+ return null;
+ }
+
+ notification2.setParameters(OnButtonEvent.KEY_BUTTON_NAME, compatBtnName);
+ return notification2;
+ }
+ }catch (Exception e){
+ //Should never get here
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get SDL Message Version
+ * @return SdlMsgVersion
+ * @throws SdlException
+ */
+ public SdlMsgVersion getSdlMsgVersion() throws SdlException{
+ return _sdlMsgVersion;
+ }
+
/**
* Takes a list of RPCRequests and sends it to SDL in a synchronous fashion. Responses are captured through callback on OnMultipleRequestListener.
* For sending requests asynchronously, use sendRequests <br>
@@ -3600,8 +4027,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
throw new SdlException("Invalid correlation ID. The correlation ID, " + request.getCorrelationID()
+ " , is a reserved correlation ID.", SdlExceptionCause.RESERVED_CORRELATION_ID);
}
-
- // Throw exception if RPCRequest is sent when SDL is unavailable
+ // Throw exception if RPCRequest is sent when SDL is unavailable
if (!_appInterfaceRegisterd && !request.getFunctionName().equals(FunctionID.REGISTER_APP_INTERFACE.toString())) {
SdlTrace.logProxyEvent("Application attempted to send an RPCRequest (non-registerAppInterface), before the interface was registerd.", SDL_LIB_TRACE_KEY);
@@ -3617,12 +4043,35 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
", is un-allowed using the Advanced Lifecycle Management Model.", SdlExceptionCause.INCORRECT_LIFECYCLE_MODEL);
}
}
+
+ //FIXME this is temporary until the next major release of the library where OK is removed
+
+ if(FunctionID.SUBSCRIBE_BUTTON.toString().equals(request.getFunctionName())
+ || FunctionID.UNSUBSCRIBE_BUTTON.toString().equals(request.getFunctionName())
+ || FunctionID.BUTTON_PRESS.toString().equals(request.getFunctionName())){
+
+ ButtonName buttonName = (ButtonName)request.getObject(ButtonName.class, SubscribeButton.KEY_BUTTON_NAME);
+
+ if(rpcSpecVersion != null && rpcSpecVersion.getMajor() < 5) {
+
+ if (ButtonName.PLAY_PAUSE.equals(buttonName)) {
+ request.setParameters(SubscribeButton.KEY_BUTTON_NAME, ButtonName.OK);
+ }
+ } else { //Newer than version 5.0.0
+ if(ButtonName.OK.equals(buttonName)){
+ RPCRequest request2 = new RPCRequest(request);
+ request2.setParameters(SubscribeButton.KEY_BUTTON_NAME, ButtonName.PLAY_PAUSE);
+ sendRPCRequestPrivate(request2);
+ }
+ }
+ }
sendRPCRequestPrivate(request);
} // end-method
protected void notifyProxyClosed(final String info, final Exception e, final SdlDisconnectedReason reason) {
SdlTrace.logProxyEvent("NotifyProxyClose", SDL_LIB_TRACE_KEY);
+ Log.d(TAG, "notifyProxyClosed: " + info);
OnProxyClosed message = new OnProxyClosed(info, e, reason);
queueInternalMessage(message);
}
@@ -3650,6 +4099,8 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
_hmiDisplayLanguageDesired,
_appType,
_appID,
+ _dayColorScheme,
+ _nightColorScheme,
REGISTER_APP_INTERFACE_CORRELATION_ID);
} catch (Exception e) {
@@ -3721,7 +4172,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
@SuppressWarnings("unchecked")
- private RPCStreamController startRPCStream(String sLocalFile, PutFile request, SessionType sType, byte rpcSessionID, byte wiproVersion)
+ private RPCStreamController startRPCStream(String sLocalFile, PutFile request, SessionType sType, byte rpcSessionID, Version protocolVersion)
{
if (sdlSession == null) return null;
@@ -3736,7 +4187,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
try {
- StreamRPCPacketizer rpcPacketizer = new StreamRPCPacketizer((SdlProxyBase<IProxyListenerBase>) this, sdlSession, is, request, sType, rpcSessionID, wiproVersion, lSize, sdlSession);
+ StreamRPCPacketizer rpcPacketizer = new StreamRPCPacketizer((SdlProxyBase<IProxyListenerBase>) this, sdlSession, is, request, sType, rpcSessionID, protocolVersion, rpcSpecVersion, lSize, sdlSession);
rpcPacketizer.start();
return new RPCStreamController(rpcPacketizer, request.getCorrelationID());
} catch (Exception e) {
@@ -3746,7 +4197,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
@SuppressWarnings({"unchecked", "UnusedReturnValue"})
- private RPCStreamController startRPCStream(InputStream is, PutFile request, SessionType sType, byte rpcSessionID, byte wiproVersion)
+ private RPCStreamController startRPCStream(InputStream is, PutFile request, SessionType sType, byte rpcSessionID, Version protocolVersion)
{
if (sdlSession == null) return null;
Long lSize = request.getLength();
@@ -3757,7 +4208,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
try {
- StreamRPCPacketizer rpcPacketizer = new StreamRPCPacketizer((SdlProxyBase<IProxyListenerBase>) this, sdlSession, is, request, sType, rpcSessionID, wiproVersion, lSize, sdlSession);
+ StreamRPCPacketizer rpcPacketizer = new StreamRPCPacketizer((SdlProxyBase<IProxyListenerBase>) this, sdlSession, is, request, sType, rpcSessionID, protocolVersion, rpcSpecVersion, lSize, sdlSession);
rpcPacketizer.start();
return new RPCStreamController(rpcPacketizer, request.getCorrelationID());
} catch (Exception e) {
@@ -3768,25 +4219,25 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
private RPCStreamController startPutFileStream(String sPath, PutFile msg) {
if (sdlSession == null) return null;
- return startRPCStream(sPath, msg, SessionType.RPC, sdlSession.getSessionId(), _wiproVersion);
+ return startRPCStream(sPath, msg, SessionType.RPC, sdlSession.getSessionId(), protocolVersion);
}
private RPCStreamController startPutFileStream(InputStream is, PutFile msg) {
if (sdlSession == null) return null;
if (is == null) return null;
- return startRPCStream(is, msg, SessionType.RPC, sdlSession.getSessionId(), _wiproVersion);
+ return startRPCStream(is, msg, SessionType.RPC, sdlSession.getSessionId(), protocolVersion);
}
@SuppressWarnings("UnusedReturnValue")
public boolean startRPCStream(InputStream is, RPCRequest msg) {
- if (sdlSession == null) return false;
- sdlSession.startRPCStream(is, msg, SessionType.RPC, sdlSession.getSessionId(), _wiproVersion);
+ if (sdlSession == null) return false;
+ sdlSession.startRPCStream(is, msg, SessionType.RPC, sdlSession.getSessionId(), (byte)getProtocolVersion().getMajor());
return true;
}
public OutputStream startRPCStream(RPCRequest msg) {
if (sdlSession == null) return null;
- return sdlSession.startRPCStream(msg, SessionType.RPC, sdlSession.getSessionId(), _wiproVersion);
+ return sdlSession.startRPCStream(msg, SessionType.RPC, sdlSession.getSessionId(), (byte)getProtocolVersion().getMajor());
}
public void endRPCStream() {
@@ -4083,8 +4534,8 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
DebugTool.logWarning("SdlSession is not created yet.");
return null;
}
- if (sdlSession.getSdlConnection() == null) {
- DebugTool.logWarning("SdlConnection is not available.");
+ if (!sdlSession.getIsConnected()) {
+ DebugTool.logWarning("Connection is not available.");
return null;
}
@@ -4152,7 +4603,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
public Surface createOpenGLInputSurface(int frameRate, int iFrameInterval, int width,
int height, int bitrate, boolean isEncrypted) {
- if (sdlSession == null || sdlSession.getSdlConnection() == null){
+ if (sdlSession == null || !sdlSession.getIsConnected()){
return null;
}
@@ -4186,7 +4637,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
*/
@TargetApi(19)
public void startRemoteDisplayStream(Context context, final Class<? extends SdlRemoteDisplay> remoteDisplay, final VideoStreamingParameters parameters, final boolean encrypted){
- if(getWiProVersion() >= 5 && !_systemCapabilityManager.isCapabilitySupported(SystemCapabilityType.VIDEO_STREAMING)){
+ if(protocolVersion!= null && protocolVersion.getMajor() >= 5 && !_systemCapabilityManager.isCapabilitySupported(SystemCapabilityType.VIDEO_STREAMING)){
Log.e(TAG, "Video streaming not supported on this module");
return;
}
@@ -4196,7 +4647,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
if(parameters == null){
- if(getWiProVersion() >= 5) {
+ if(protocolVersion!= null && protocolVersion.getMajor() >= 5) {
_systemCapabilityManager.getCapability(SystemCapabilityType.VIDEO_STREAMING, new OnSystemCapabilityListener() {
@Override
public void onCapabilityRetrieved(Object capability) {
@@ -4257,7 +4708,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
DebugTool.logWarning("SdlSession is not created yet.");
return null;
}
- if(getWiProVersion() >= 5 && !_systemCapabilityManager.isCapabilitySupported(SystemCapabilityType.VIDEO_STREAMING)){
+ if(protocolVersion!= null && protocolVersion.getMajor() >= 5 && !_systemCapabilityManager.isCapabilitySupported(SystemCapabilityType.VIDEO_STREAMING)){
DebugTool.logWarning("Module doesn't support video streaming.");
return null;
}
@@ -4283,7 +4734,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
scheduler.shutdown();
if (navServiceStartResponse) {
- if(getWiProVersion() < 5){ //Versions 1-4 do not support streaming parameter negotiations
+ if(protocolVersion!= null && protocolVersion.getMajor() < 5){ //Versions 1-4 do not support streaming parameter negotiations
sdlSession.setAcceptedVideoParams(parameters);
}
return sdlSession.getAcceptedVideoParams();
@@ -4312,10 +4763,8 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
*/
@SuppressWarnings("unused")
public void startEncoder () {
- if (sdlSession == null) return;
- SdlConnection sdlConn = sdlSession.getSdlConnection();
- if (sdlConn == null) return;
-
+ if (sdlSession == null || !sdlSession.getIsConnected()) return;
+
sdlSession.startEncoder();
}
@@ -4324,10 +4773,8 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
*/
@SuppressWarnings("unused")
public void releaseEncoder() {
- if (sdlSession == null) return;
- SdlConnection sdlConn = sdlSession.getSdlConnection();
- if (sdlConn == null) return;
-
+ if (sdlSession == null || !sdlSession.getIsConnected()) return;
+
sdlSession.releaseEncoder();
}
@@ -4336,10 +4783,8 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
*/
@SuppressWarnings("unused")
public void drainEncoder(boolean endOfStream) {
- if (sdlSession == null) return;
- SdlConnection sdlConn = sdlSession.getSdlConnection();
- if (sdlConn == null) return;
-
+ if (sdlSession == null || !sdlSession.getIsConnected()) return;
+
sdlSession.drainEncoder(endOfStream);
}
@@ -4369,8 +4814,8 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
DebugTool.logWarning("SdlSession is not created yet.");
return null;
}
- if (sdlSession.getSdlConnection() == null) {
- DebugTool.logWarning("SdlConnection is not available.");
+ if (!sdlSession.getIsConnected()) {
+ DebugTool.logWarning("Connection is not available.");
return null;
}
if (codec != AudioStreamingCodec.LPCM) {
@@ -4416,9 +4861,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
*/
@SuppressWarnings("unused")
public boolean endAudioStream() {
- if (sdlSession == null) return false;
- SdlConnection sdlConn = sdlSession.getSdlConnection();
- if (sdlConn == null) return false;
+ if (sdlSession == null || !sdlSession.getIsConnected()) return false;
pcmServiceEndResponseReceived = false;
pcmServiceEndResponse = false;
@@ -4806,28 +5249,47 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
addCommand(commandID, null, null, null, vrCommands, correlationID);
}
-
-
+
/**
* Sends an AddSubMenu RPCRequest to SDL. Responses are captured through callback on IProxyListener.
- *
+ *
* @param menuID -Unique ID of the sub menu to add.
* @param menuName -Text to show in the menu for this sub menu.
* @param position -Position within the items that are are at top level of the in application menu.
+ * @param menuIcon -Image to be be shown along with the submenu item
* @param correlationID -A unique ID that correlates each RPCRequest and RPCResponse
* @throws SdlException if an unrecoverable error is encountered
*/
@SuppressWarnings("SameParameterValue")
public void addSubMenu(@NonNull Integer menuID, @NonNull String menuName,
- Integer position, Integer correlationID)
+ Integer position, Image menuIcon, Integer correlationID)
throws SdlException {
AddSubMenu msg = new AddSubMenu(menuID, menuName);
msg.setCorrelationID(correlationID);
msg.setPosition(position);
-
+ msg.setMenuIcon(menuIcon);
+
sendRPCRequest(msg);
}
+
+ /**
+ * Sends an AddSubMenu RPCRequest to SDL. Responses are captured through callback on IProxyListener.
+ *
+ * @param menuID -Unique ID of the sub menu to add.
+ * @param menuName -Text to show in the menu for this sub menu.
+ * @param position -Position within the items that are are at top level of the in application menu.
+ * @param correlationID -A unique ID that correlates each RPCRequest and RPCResponse
+ * @throws SdlException if an unrecoverable error is encountered
+ */
+ @Deprecated
+ @SuppressWarnings("SameParameterValue")
+ public void addSubMenu(@NonNull Integer menuID, @NonNull String menuName,
+ Integer position, Integer correlationID)
+ throws SdlException {
+
+ addSubMenu(menuID, menuName, position, null, correlationID);
+ }
/**
* Sends an AddSubMenu RPCRequest to SDL. Responses are captured through callback on IProxyListener.
@@ -4837,11 +5299,12 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
* @param correlationID -A unique ID that correlates each RPCRequest and RPCResponse
* @throws SdlException if an unrecoverable error is encountered
*/
+ @Deprecated
@SuppressWarnings("unused")
public void addSubMenu(Integer menuID, String menuName,
Integer correlationID) throws SdlException {
- addSubMenu(menuID, menuName, null, correlationID);
+ addSubMenu(menuID, menuName, null, null, correlationID);
}
/*Begin V1 Enhanced helper*/
@@ -5393,14 +5856,14 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
sendRPCRequest(msg);
}
-
+
// Protected registerAppInterface used to ensure only non-ALM applications call
// reqisterAppInterface
protected void registerAppInterfacePrivate(
@NonNull SdlMsgVersion sdlMsgVersion, @NonNull String appName, Vector<TTSChunk> ttsName,
String ngnMediaScreenAppName, Vector<String> vrSynonyms, @NonNull Boolean isMediaApp,
@NonNull Language languageDesired, @NonNull Language hmiDisplayLanguageDesired, Vector<AppHMIType> appType,
- @NonNull String appID, Integer correlationID)
+ @NonNull String appID, TemplateColorScheme dayColorScheme, TemplateColorScheme nightColorScheme, Integer correlationID)
throws SdlException {
String carrierName = null;
if(telephonyManager != null){
@@ -5449,6 +5912,9 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
msg.setAppHMIType(appType);
+ msg.setDayColorScheme(dayColorScheme);
+ msg.setNightColorScheme(nightColorScheme);
+
if (_bAppResumeEnabled)
{
if (_lastHashID != null)
@@ -5939,6 +6405,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
* @throws SdlException if an unrecoverable error is encountered
*/
@SuppressWarnings("unused")
+ @Deprecated
public void subscribevehicledata(boolean gps, boolean speed, boolean rpm, boolean fuelLevel, boolean fuelLevel_State,
boolean instantFuelConsumption, boolean externalTemperature, boolean prndl, boolean tirePressure,
boolean odometer, boolean beltStatus, boolean bodyInformation, boolean deviceStatus,
@@ -5963,7 +6430,58 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
sendRPCRequest(msg);
}
-
+
+
+ /**
+ * Subscribes for specific published data items. The data will be only sent if it has changed.
+ * Responses are captured through callback on IProxyListener.
+ *
+ * @param gps -Subscribes to GPS data.
+ * @param speed -Subscribes to vehicle speed data in kilometers per hour.
+ * @param rpm -Subscribes to number of revolutions per minute of the engine.
+ * @param fuelLevel -Subscribes to fuel level in the tank (percentage).
+ * @param fuelLevel_State -Subscribes to fuel level state.
+ * @param instantFuelConsumption -Subscribes to instantaneous fuel consumption in microlitres.
+ * @param externalTemperature -Subscribes to the external temperature in degrees celsius.
+ * @param prndl -Subscribes to PRNDL data that houses the selected gear.
+ * @param tirePressure -Subscribes to the TireStatus data containing status and pressure of tires.
+ * @param engineOilLife -Subscribes to Engine Oil Life data.
+ * @param odometer -Subscribes to Odometer data in km.
+ * @param beltStatus -Subscribes to status of the seat belts.
+ * @param bodyInformation -Subscribes to body information including power modes.
+ * @param deviceStatus -Subscribes to device status including signal and battery strength.
+ * @param driverBraking -Subscribes to the status of the brake pedal.
+ * @param correlationID -A unique ID that correlates each RPCRequest and RPCResponse.
+ * @throws SdlException if an unrecoverable error is encountered
+ */
+ @SuppressWarnings("unused")
+ public void subscribevehicledata(boolean gps, boolean speed, boolean rpm, boolean fuelLevel, boolean fuelLevel_State,
+ boolean instantFuelConsumption, boolean externalTemperature, boolean prndl, boolean tirePressure,
+ boolean engineOilLife, boolean odometer, boolean beltStatus, boolean bodyInformation, boolean deviceStatus,
+ boolean driverBraking, Integer correlationID) throws SdlException
+ {
+ SubscribeVehicleData msg = new SubscribeVehicleData();
+ msg.setGps(gps);
+ msg.setSpeed(speed);
+ msg.setRpm(rpm);
+ msg.setFuelLevel(fuelLevel);
+ msg.setFuelLevel_State(fuelLevel_State);
+ msg.setInstantFuelConsumption(instantFuelConsumption);
+ msg.setExternalTemperature(externalTemperature);
+ msg.setPrndl(prndl);
+ msg.setTirePressure(tirePressure);
+ msg.setEngineOilLife(engineOilLife);
+ msg.setOdometer(odometer);
+ msg.setBeltStatus(beltStatus);
+ msg.setBodyInformation(bodyInformation);
+ msg.setDeviceStatus(deviceStatus);
+ msg.setDriverBraking(driverBraking);
+ msg.setCorrelationID(correlationID);
+
+ sendRPCRequest(msg);
+ }
+
+
/**
* Unsubscribes for specific published data items.
* Responses are captured through callback on IProxyListener.
@@ -5987,6 +6505,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
*/
@SuppressWarnings("unused")
+ @Deprecated
public void unsubscribevehicledata(boolean gps, boolean speed, boolean rpm, boolean fuelLevel, boolean fuelLevel_State,
boolean instantFuelConsumption, boolean externalTemperature, boolean prndl, boolean tirePressure,
boolean odometer, boolean beltStatus, boolean bodyInformation, boolean deviceStatus,
@@ -6014,6 +6533,57 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
/**
+ * Unsubscribes for specific published data items.
+ * Responses are captured through callback on IProxyListener.
+ *
+ * @param gps -Unsubscribes to GPS data.
+ * @param speed -Unsubscribes to vehicle speed data in kilometers per hour.
+ * @param rpm -Unsubscribes to number of revolutions per minute of the engine.
+ * @param fuelLevel -Unsubscribes to fuel level in the tank (percentage).
+ * @param fuelLevel_State -Unsubscribes to fuel level state.
+ * @param instantFuelConsumption -Unsubscribes to instantaneous fuel consumption in microlitres.
+ * @param externalTemperature -Unsubscribes to the external temperature in degrees celsius.
+ * @param prndl -Unsubscribes to PRNDL data that houses the selected gear.
+ * @param tirePressure -Unsubscribes to the TireStatus data containing status and pressure of tires.
+ * @param engineOilLife -Unsubscribes to Engine Oil Life data.
+ * @param odometer -Unsubscribes to Odometer data in km.
+ * @param beltStatus -Unsubscribes to status of the seat belts.
+ * @param bodyInformation -Unsubscribes to body information including power modes.
+ * @param deviceStatus -Unsubscribes to device status including signal and battery strength.
+ * @param driverBraking -Unsubscribes to the status of the brake pedal.
+ * @param correlationID -A unique ID that correlates each RPCRequest and RPCResponse.
+ * @throws SdlException if an unrecoverable error is encountered
+ */
+
+ @SuppressWarnings("unused")
+ public void unsubscribevehicledata(boolean gps, boolean speed, boolean rpm, boolean fuelLevel, boolean fuelLevel_State,
+ boolean instantFuelConsumption, boolean externalTemperature, boolean prndl, boolean tirePressure,
+ boolean engineOilLife, boolean odometer, boolean beltStatus, boolean bodyInformation, boolean deviceStatus,
+ boolean driverBraking, Integer correlationID) throws SdlException
+ {
+ UnsubscribeVehicleData msg = new UnsubscribeVehicleData();
+ msg.setGps(gps);
+ msg.setSpeed(speed);
+ msg.setRpm(rpm);
+ msg.setFuelLevel(fuelLevel);
+ msg.setFuelLevel_State(fuelLevel_State);
+ msg.setInstantFuelConsumption(instantFuelConsumption);
+ msg.setExternalTemperature(externalTemperature);
+ msg.setPrndl(prndl);
+ msg.setTirePressure(tirePressure);
+ msg.setEngineOilLife(engineOilLife);
+ msg.setOdometer(odometer);
+ msg.setBeltStatus(beltStatus);
+ msg.setBodyInformation(bodyInformation);
+ msg.setDeviceStatus(deviceStatus);
+ msg.setDriverBraking(driverBraking);
+ msg.setCorrelationID(correlationID);
+
+ sendRPCRequest(msg);
+ }
+
+
+ /**
* Performs a Non periodic vehicle data read request.
* Responses are captured through callback on IProxyListener.
*
@@ -6036,6 +6606,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
* @throws SdlException if an unrecoverable error is encountered
*/
@SuppressWarnings("unused")
+ @Deprecated
public void getvehicledata(boolean gps, boolean speed, boolean rpm, boolean fuelLevel, boolean fuelLevel_State,
boolean instantFuelConsumption, boolean externalTemperature, boolean vin, boolean prndl, boolean tirePressure,
boolean odometer, boolean beltStatus, boolean bodyInformation, boolean deviceStatus,
@@ -6064,6 +6635,58 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
/**
+ * Performs a Non periodic vehicle data read request.
+ * Responses are captured through callback on IProxyListener.
+ *
+ * @param gps -Performs an ad-hoc request for GPS data.
+ * @param speed -Performs an ad-hoc request for vehicle speed data in kilometers per hour.
+ * @param rpm -Performs an ad-hoc request for number of revolutions per minute of the engine.
+ * @param fuelLevel -Performs an ad-hoc request for fuel level in the tank (percentage).
+ * @param fuelLevel_State -Performs an ad-hoc request for fuel level state.
+ * @param instantFuelConsumption -Performs an ad-hoc request for instantaneous fuel consumption in microlitres.
+ * @param externalTemperature -Performs an ad-hoc request for the external temperature in degrees celsius.
+ * @param vin -Performs an ad-hoc request for the Vehicle identification number
+ * @param prndl -Performs an ad-hoc request for PRNDL data that houses the selected gear.
+ * @param tirePressure -Performs an ad-hoc request for the TireStatus data containing status and pressure of tires.
+ * @param engineOilLife -Performs an ad-hoc request for Engine Oil Life data.
+ * @param odometer -Performs an ad-hoc request for Odometer data in km.
+ * @param beltStatus -Performs an ad-hoc request for status of the seat belts.
+ * @param bodyInformation -Performs an ad-hoc request for body information including power modes.
+ * @param deviceStatus -Performs an ad-hoc request for device status including signal and battery strength.
+ * @param driverBraking -Performs an ad-hoc request for the status of the brake pedal.
+ * @param correlationID -A unique ID that correlates each RPCRequest and RPCResponse.
+ * @throws SdlException if an unrecoverable error is encountered
+ */
+ @SuppressWarnings("unused")
+ public void getvehicledata(boolean gps, boolean speed, boolean rpm, boolean fuelLevel, boolean fuelLevel_State,
+ boolean instantFuelConsumption, boolean externalTemperature, boolean vin, boolean prndl, boolean tirePressure,
+ boolean engineOilLife, boolean odometer, boolean beltStatus, boolean bodyInformation, boolean deviceStatus,
+ boolean driverBraking, Integer correlationID) throws SdlException
+ {
+ GetVehicleData msg = new GetVehicleData();
+ msg.setGps(gps);
+ msg.setSpeed(speed);
+ msg.setRpm(rpm);
+ msg.setFuelLevel(fuelLevel);
+ msg.setFuelLevel_State(fuelLevel_State);
+ msg.setInstantFuelConsumption(instantFuelConsumption);
+ msg.setExternalTemperature(externalTemperature);
+ msg.setVin(vin);
+ msg.setPrndl(prndl);
+ msg.setTirePressure(tirePressure);
+ msg.setEngineOilLife(engineOilLife);
+ msg.setOdometer(odometer);
+ msg.setBeltStatus(beltStatus);
+ msg.setBodyInformation(bodyInformation);
+ msg.setDeviceStatus(deviceStatus);
+ msg.setDriverBraking(driverBraking);
+ msg.setCorrelationID(correlationID);
+
+ sendRPCRequest(msg);
+ }
+
+
+ /**
* Creates a full screen overlay containing a large block of formatted text that can be scrolled with up to 8 SoftButtons defined.
* Responses are captured through callback on IProxyListener.
*
@@ -6549,15 +7172,15 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
sendRPCRequest(msg);
}
-
+
/**
* Set an alternate display layout. If not sent, default screen for given platform will be shown.
* Responses are captured through callback on IProxyListener.
- *
+ *
* @param displayLayout -Predefined or dynamically created screen layout.
* @param correlationID -A unique ID that correlates each RPCRequest and RPCResponse.
* @throws SdlException if an unrecoverable error is encountered
- */
+ */
@SuppressWarnings("unused")
public void setdisplaylayout(@NonNull String displayLayout, Integer correlationID) throws SdlException
{
@@ -6567,6 +7190,34 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
sendRPCRequest(msg);
}
+ /**
+ * Set an alternate display layout. If not sent, default screen for given platform will be shown.
+ * Responses are captured through callback on IProxyListener.
+ *
+ * @param displayLayout -Predefined or dynamically created screen layout.
+ * @param dayColorScheme a TemplateColorScheme object representing the colors that will be used for day color scheme
+ * @param nightColorScheme a TemplateColorScheme object representing the colors that will be used for night color scheme
+ * @param correlationID -A unique ID that correlates each RPCRequest and RPCResponse.
+ * @throws SdlException if an unrecoverable error is encountered
+ */
+ @SuppressWarnings("unused")
+ public void setdisplaylayout(String displayLayout, TemplateColorScheme dayColorScheme, TemplateColorScheme nightColorScheme, Integer correlationID) throws SdlException
+ {
+ SetDisplayLayout msg = new SetDisplayLayout(displayLayout);
+ msg.setCorrelationID(correlationID);
+ msg.setDayColorScheme(dayColorScheme);
+ msg.setNightColorScheme(nightColorScheme);
+ sendRPCRequest(msg);
+ }
+
+ /**
+ * Gets the SystemCapabilityManager. <br>
+ * @return a SystemCapabilityManager object
+ */
+ public SystemCapabilityManager getSystemCapabilityManager() {
+ return _systemCapabilityManager;
+ }
+
@SuppressWarnings("unused")
public boolean isCapabilitySupported(SystemCapabilityType systemCapabilityType) {
return _systemCapabilityManager != null && _systemCapabilityManager.isCapabilitySupported(systemCapabilityType);
@@ -6588,6 +7239,29 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
}
+ /**
+ * Add a listener to be called whenever a new capability is retrieved
+ * @param systemCapabilityType Type of capability desired
+ * @param listener callback to execute upon retrieving capability
+ */
+ public void addOnSystemCapabilityListener(final SystemCapabilityType systemCapabilityType, final OnSystemCapabilityListener listener) {
+ if(_systemCapabilityManager != null){
+ _systemCapabilityManager.addOnSystemCapabilityListener(systemCapabilityType, listener);
+ }
+ }
+
+ /**
+ * Remove an OnSystemCapabilityListener that was previously added
+ * @param systemCapabilityType Type of capability
+ * @param listener the listener that should be removed
+ */
+ public boolean removeOnSystemCapabilityListener(final SystemCapabilityType systemCapabilityType, final OnSystemCapabilityListener listener){
+ if(_systemCapabilityManager != null){
+ return _systemCapabilityManager.removeOnSystemCapabilityListener(systemCapabilityType, listener);
+ }
+ return false;
+ }
+
/* ******************* END Public Helper Methods *************************/
/**
@@ -6695,6 +7369,23 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
return sPoliciesURL;
}
+ /**
+ * Tells developer whether or not their app icon has been resumed on core.
+ * @return boolean - true if icon was resumed, false if not
+ * @throws SdlException if proxy is disposed or app is not registered
+ */
+ public boolean getIconResumed() throws SdlException {
+ // Test if proxy has been disposed
+ if (_proxyDisposed) {
+ throw new SdlException("This object has been disposed, it is no long capable of executing methods.", SdlExceptionCause.SDL_PROXY_DISPOSED);
+ }
+
+ // Test SDL availability
+ if (!_appInterfaceRegisterd) {
+ throw new SdlException("SDL is not connected. Unable to determine if app icon was resumed.", SdlExceptionCause.SDL_UNAVAILABLE);
+ }
+ return _iconResumed;
+ }
/**
@@ -6789,7 +7480,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
public void onCreated(final SdlRemoteDisplay remoteDisplay) {
//Remote display has been created.
//Now is a good time to do parsing for spatial data
- VideoStreamingManager.this.remoteDisplay = remoteDisplay;
+ SdlProxyBase.VideoStreamingManager.this.remoteDisplay = remoteDisplay;
if(hapticManager != null) {
remoteDisplay.getMainView().post(new Runnable() {
@Override
@@ -6800,15 +7491,20 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase>
}
//Get touch scalars
ImageResolution resolution = null;
- if(getWiProVersion()>=5){ //At this point we should already have the capability
+ if(protocolVersion!= null && protocolVersion.getMajor()>=5){ //At this point we should already have the capability
VideoStreamingCapability capability = (VideoStreamingCapability)_systemCapabilityManager.getCapability(SystemCapabilityType.VIDEO_STREAMING);
- resolution = capability.getPreferredResolution();
- }else {
- DisplayCapabilities dispCap = (DisplayCapabilities) _systemCapabilityManager.getCapability(SystemCapabilityType.DISPLAY);
+ if (capability != null) {
+ resolution = capability.getPreferredResolution();
+ }
+ }
+
+ if(resolution == null){ //Either the protocol version is too low to access video streaming caps, or they were null
+ DisplayCapabilities dispCap = (DisplayCapabilities) internalInterface.getCapability(SystemCapabilityType.DISPLAY);
if (dispCap != null) {
- resolution = (dispCap.getScreenParams().getImageResolution());
+ resolution = (dispCap.getScreenParams().getImageResolution());
}
}
+
if(resolution != null){
DisplayMetrics displayMetrics = new DisplayMetrics();
disp.getMetrics(displayMetrics);
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBuilder.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBuilder.java
index cbc392f67..42e2fbbc2 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBuilder.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBuilder.java
@@ -7,6 +7,7 @@ import com.smartdevicelink.exception.SdlException;
import com.smartdevicelink.proxy.interfaces.IProxyListenerALM;
import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
import com.smartdevicelink.proxy.rpc.TTSChunk;
+import com.smartdevicelink.proxy.rpc.TemplateColorScheme;
import com.smartdevicelink.proxy.rpc.enums.AppHMIType;
import com.smartdevicelink.proxy.rpc.enums.Language;
import com.smartdevicelink.security.SdlSecurityBase;
@@ -41,6 +42,7 @@ public class SdlProxyBuilder {
private boolean preRegister;
private String sAppResumeHash;
private List<Class<? extends SdlSecurityBase>> sdlSecList;
+ private TemplateColorScheme dayColorScheme, nightColorScheme;
private SdlProxyBuilder() {
service = null;
@@ -57,7 +59,9 @@ public class SdlProxyBuilder {
preRegister = false;
sAppResumeHash = null;
sdlSecList = null;
- }
+ dayColorScheme = null;
+ nightColorScheme = null;
+}
public static class Builder {
SdlProxyBuilder sdlProxyBuilder;
@@ -159,6 +163,15 @@ public class SdlProxyBuilder {
sdlProxyBuilder.sdlSecList = val;
return this;
}
+ public Builder setDayColorScheme(TemplateColorScheme val) {
+ sdlProxyBuilder.dayColorScheme = val;
+ return this;
+ }
+
+ public Builder setNightColorScheme(TemplateColorScheme val) {
+ sdlProxyBuilder.nightColorScheme = val;
+ return this;
+ }
public SdlProxyALM build() throws SdlException {
SdlProxyALM proxy = new SdlProxyALM(sdlProxyBuilder.service, sdlProxyBuilder.listener,
@@ -166,7 +179,8 @@ public class SdlProxyBuilder {
sdlProxyBuilder.ttsChunks, sdlProxyBuilder.sShortAppName, sdlProxyBuilder.vrSynonyms,
sdlProxyBuilder.isMediaApp, sdlProxyBuilder.sdlMessageVersion, sdlProxyBuilder.lang,
sdlProxyBuilder.hmiLang, sdlProxyBuilder.vrAppHMITypes, sdlProxyBuilder.appId,
- sdlProxyBuilder.autoActivateID, sdlProxyBuilder.callbackToUIThread, sdlProxyBuilder.preRegister,
+ sdlProxyBuilder.autoActivateID, sdlProxyBuilder.dayColorScheme, sdlProxyBuilder.nightColorScheme,
+ sdlProxyBuilder.callbackToUIThread, sdlProxyBuilder.preRegister,
sdlProxyBuilder.sAppResumeHash, sdlProxyBuilder.mTransport);
proxy.setSdlSecurityClassList(sdlProxyBuilder.sdlSecList);
return proxy;
@@ -174,3 +188,5 @@ public class SdlProxyBuilder {
}
}
+
+
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/SystemCapabilityManager.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/SystemCapabilityManager.java
index 710355c49..291d02a8f 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/SystemCapabilityManager.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/SystemCapabilityManager.java
@@ -1,6 +1,5 @@
package com.smartdevicelink.proxy;
-import com.smartdevicelink.exception.SdlException;
import com.smartdevicelink.proxy.interfaces.ISdl;
import com.smartdevicelink.proxy.interfaces.OnSystemCapabilityListener;
import com.smartdevicelink.proxy.rpc.GetSystemCapability;
@@ -12,31 +11,36 @@ import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener;
import com.smartdevicelink.util.CorrelationIdGenerator;
-import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
public class SystemCapabilityManager {
- HashMap<SystemCapabilityType, Object> cachedSystemCapabilities = new HashMap<>();
- ISdl callback;
+ private final HashMap<SystemCapabilityType, Object> cachedSystemCapabilities;
+ private final HashMap<SystemCapabilityType, CopyOnWriteArrayList<OnSystemCapabilityListener>> onSystemCapabilityListeners;
+ private final Object LISTENER_LOCK;
+ private final ISdl callback;
public SystemCapabilityManager(ISdl callback){
this.callback = callback;
+ this.LISTENER_LOCK = new Object();
+ this.onSystemCapabilityListeners = new HashMap<>();
+ this.cachedSystemCapabilities = new HashMap<>();
}
public void parseRAIResponse(RegisterAppInterfaceResponse response){
if(response!=null && response.getSuccess()) {
- cachedSystemCapabilities.put(SystemCapabilityType.HMI, response.getHmiCapabilities());
- cachedSystemCapabilities.put(SystemCapabilityType.DISPLAY, response.getDisplayCapabilities());
- cachedSystemCapabilities.put(SystemCapabilityType.AUDIO_PASSTHROUGH, response.getAudioPassThruCapabilities());
- cachedSystemCapabilities.put(SystemCapabilityType.PCM_STREAMING, response.getPcmStreamingCapabilities());
- cachedSystemCapabilities.put(SystemCapabilityType.BUTTON, response.getButtonCapabilities());
- cachedSystemCapabilities.put(SystemCapabilityType.HMI_ZONE, response.getHmiZoneCapabilities());
- cachedSystemCapabilities.put(SystemCapabilityType.PRESET_BANK, response.getPresetBankCapabilities());
- cachedSystemCapabilities.put(SystemCapabilityType.SOFTBUTTON, response.getSoftButtonCapabilities());
- cachedSystemCapabilities.put(SystemCapabilityType.SPEECH, response.getSpeechCapabilities());
- cachedSystemCapabilities.put(SystemCapabilityType.VOICE_RECOGNITION, response.getVrCapabilities());
+ setCapability(SystemCapabilityType.HMI, response.getHmiCapabilities());
+ setCapability(SystemCapabilityType.DISPLAY, response.getDisplayCapabilities());
+ setCapability(SystemCapabilityType.AUDIO_PASSTHROUGH, response.getAudioPassThruCapabilities());
+ setCapability(SystemCapabilityType.PCM_STREAMING, response.getPcmStreamingCapabilities());
+ setCapability(SystemCapabilityType.BUTTON, response.getButtonCapabilities());
+ setCapability(SystemCapabilityType.HMI_ZONE, response.getHmiZoneCapabilities());
+ setCapability(SystemCapabilityType.PRESET_BANK, response.getPresetBankCapabilities());
+ setCapability(SystemCapabilityType.SOFTBUTTON, response.getSoftButtonCapabilities());
+ setCapability(SystemCapabilityType.SPEECH, response.getSpeechCapabilities());
+ setCapability(SystemCapabilityType.VOICE_RECOGNITION, response.getVrCapabilities());
}
}
@@ -46,8 +50,25 @@ public class SystemCapabilityManager {
* @param systemCapabilityType
* @param capability
*/
- public void setCapability(SystemCapabilityType systemCapabilityType, Object capability){
- cachedSystemCapabilities.put(systemCapabilityType,capability);
+ public synchronized void setCapability(SystemCapabilityType systemCapabilityType, Object capability){
+ cachedSystemCapabilities.put(systemCapabilityType, capability);
+ notifyListeners(systemCapabilityType, capability);
+ }
+
+ /**
+ * Notify listners in the list about the new retrieved capability
+ * @param systemCapabilityType
+ * @param capability
+ */
+ private void notifyListeners(SystemCapabilityType systemCapabilityType, Object capability) {
+ synchronized(LISTENER_LOCK){
+ CopyOnWriteArrayList<OnSystemCapabilityListener> listeners = onSystemCapabilityListeners.get(systemCapabilityType);
+ if(listeners != null && listeners.size() > 0) {
+ for (OnSystemCapabilityListener listener : listeners) {
+ listener.onCapabilityRetrieved(capability);
+ }
+ }
+ }
}
/**
@@ -57,7 +78,8 @@ public class SystemCapabilityManager {
* @return if that capability is supported with the current, connected module
*/
public boolean isCapabilitySupported(SystemCapabilityType type){
- if(cachedSystemCapabilities.containsKey(type)){
+ if(cachedSystemCapabilities.get(type) != null){
+ //The capability exists in the map and is not null
return true;
}else if(cachedSystemCapabilities.containsKey(SystemCapabilityType.HMI)){
HMICapabilities hmiCapabilities = ((HMICapabilities)cachedSystemCapabilities.get(SystemCapabilityType.HMI));
@@ -109,6 +131,40 @@ public class SystemCapabilityManager {
}
/**
+ * Add a listener to be called whenever a new capability is retrieved
+ * @param systemCapabilityType Type of capability desired
+ * @param listener callback to execute upon retrieving capability
+ */
+ public void addOnSystemCapabilityListener(final SystemCapabilityType systemCapabilityType, final OnSystemCapabilityListener listener){
+ getCapability(systemCapabilityType, listener);
+ synchronized(LISTENER_LOCK){
+ if (systemCapabilityType != null && listener != null) {
+ if (onSystemCapabilityListeners.get(systemCapabilityType) == null) {
+ onSystemCapabilityListeners.put(systemCapabilityType, new CopyOnWriteArrayList<OnSystemCapabilityListener>());
+ }
+ onSystemCapabilityListeners.get(systemCapabilityType).add(listener);
+ }
+ }
+ }
+
+ /**
+ * Remove an OnSystemCapabilityListener that was previously added
+ * @param systemCapabilityType Type of capability
+ * @param listener the listener that should be removed
+ */
+ public boolean removeOnSystemCapabilityListener(final SystemCapabilityType systemCapabilityType, final OnSystemCapabilityListener listener){
+ synchronized(LISTENER_LOCK){
+ if(onSystemCapabilityListeners!= null
+ && systemCapabilityType != null
+ && listener != null
+ && onSystemCapabilityListeners.get(systemCapabilityType) != null){
+ return onSystemCapabilityListeners.get(systemCapabilityType).remove(listener);
+ }
+ }
+ return false;
+ }
+
+ /**
* @param systemCapabilityType Type of capability desired
* passes GetSystemCapabilityType request to `callback` to be sent by proxy
*/
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/interfaces/IProxyListenerBase.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/interfaces/IProxyListenerBase.java
index 618819f20..b7486785f 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/interfaces/IProxyListenerBase.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/interfaces/IProxyListenerBase.java
@@ -35,6 +35,7 @@ import com.smartdevicelink.proxy.rpc.OnKeyboardInput;
import com.smartdevicelink.proxy.rpc.OnLanguageChange;
import com.smartdevicelink.proxy.rpc.OnLockScreenStatus;
import com.smartdevicelink.proxy.rpc.OnPermissionsChange;
+import com.smartdevicelink.proxy.rpc.OnRCStatus;
import com.smartdevicelink.proxy.rpc.OnStreamRPC;
import com.smartdevicelink.proxy.rpc.OnSystemRequest;
import com.smartdevicelink.proxy.rpc.OnTBTClientState;
@@ -353,4 +354,6 @@ public interface IProxyListenerBase {
public void onOnInteriorVehicleData(OnInteriorVehicleData notification);
public void onSendHapticDataResponse(SendHapticDataResponse response);
+
+ public void onOnRCStatus(OnRCStatus notification);
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/interfaces/ISdl.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/interfaces/ISdl.java
index 9177a146b..5eb8ff36a 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/interfaces/ISdl.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/interfaces/ISdl.java
@@ -1,11 +1,22 @@
package com.smartdevicelink.proxy.interfaces;
+import android.support.annotation.NonNull;
+
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.protocol.enums.SessionType;
import com.smartdevicelink.proxy.RPCRequest;
+import com.smartdevicelink.util.Version;
+import com.smartdevicelink.proxy.rpc.SdlMsgVersion;
+import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
+import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener;
+import com.smartdevicelink.proxy.rpc.listeners.OnRPCListener;
import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
+import com.smartdevicelink.streaming.audio.AudioStreamingCodec;
+import com.smartdevicelink.streaming.audio.AudioStreamingParams;
import com.smartdevicelink.streaming.video.VideoStreamingParameters;
+import java.util.List;
+
/*
* Copyright (c) 2017 Livio, Inc.
* All rights reserved.
@@ -83,6 +94,19 @@ public interface ISdl {
void stopVideoService();
/**
+ * Starts the video streaming service
+ * @param isEncrypted flag to start this service with encryption or not
+ * @param parameters desired video streaming params for this sevice to be started with
+ */
+ IVideoStreamListener startVideoStream(boolean isEncrypted, VideoStreamingParameters parameters);
+
+ /**
+ * Starts the Audio streaming service
+ * @param encrypted flag to start this service with encryption or not
+ */
+ void startAudioService(boolean encrypted, AudioStreamingCodec codec, AudioStreamingParams params);
+
+ /**
* Starts the Audio streaming service
* @param encrypted flag to start this service with encryption or not
*/
@@ -94,12 +118,28 @@ public interface ISdl {
void stopAudioService();
/**
+ * Start Audio Stream and return IAudioStreamListener
+ * @param isEncrypted
+ * @param codec
+ * @param params
+ * @return IAudioStreamListener
+ */
+ IAudioStreamListener startAudioStream(boolean isEncrypted, AudioStreamingCodec codec, AudioStreamingParams params);
+
+ /**
* Pass an RPC message through the proxy to be sent to the connected module
* @param message RPCRequest that should be sent to the module
*/
void sendRPCRequest(RPCRequest message);
/**
+ * Pass a list of RPC requests through the proxy to be sent to core
+ * @param rpcs List of RPC requests
+ * @param listener OnMultipleRequestListener that is called between requests and after all are processed
+ */
+ void sendRequests(List<? extends RPCRequest> rpcs, final OnMultipleRequestListener listener);
+
+ /**
* Add an OnRPCNotificationListener for specified notification
* @param notificationId FunctionID of the notification that is to be listened for
* @param listener listener that should be added for the notification ID
@@ -113,4 +153,77 @@ public interface ISdl {
*/
boolean removeOnRPCNotificationListener(FunctionID notificationId, OnRPCNotificationListener listener);
+ /**
+ * Add an OnRPCResponseListener for specified response
+ * @param responseId FunctionID of the response that is to be listened for
+ * @param listener listener that should be added for the response ID
+ */
+ void addOnRPCListener(FunctionID responseId, OnRPCListener listener);
+
+ /**
+ * Removes an OnRPCResponseListener for specified response
+ * @param responseId FunctionID of the response that was to be listened for
+ * @param listener listener that was previously added for the response ID
+ */
+ boolean removeOnRPCListener(FunctionID responseId, OnRPCListener listener);
+
+ /**
+ * Get SystemCapability Object
+ * @param systemCapabilityType
+ * @return Object
+ */
+ Object getCapability(SystemCapabilityType systemCapabilityType);
+
+ /**
+ * Get Capability
+ * @param systemCapabilityType
+ * @param scListener
+ */
+ void getCapability(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener scListener);
+
+ /**
+ * Check if capability is supported
+ * @param systemCapabilityType
+ * @return Boolean
+ */
+ boolean isCapabilitySupported(SystemCapabilityType systemCapabilityType);
+
+ /**
+ * Add a listener to be called whenever a new capability is retrieved
+ * @param systemCapabilityType Type of capability desired
+ * @param listener callback to execute upon retrieving capability
+ */
+ void addOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener);
+
+ /**
+ * Remove an OnSystemCapabilityListener that was previously added
+ * @param systemCapabilityType Type of capability
+ * @param listener the listener that should be removed
+ */
+ boolean removeOnSystemCapabilityListener(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener listener);
+
+ /**
+ * Check to see if a transport is available to start/use the supplied service.
+ * @param serviceType the session that should be checked for transport availability
+ * @return true if there is either a supported
+ * transport currently connected or a transport is
+ * available to connect with for the supplied service type.
+ * <br>false if there is no
+ * transport connected to support the service type in question and
+ * no possibility in the foreseeable future.
+ */
+ boolean isTransportForServiceAvailable(SessionType serviceType);
+
+ /**
+ * Get the RPC specification version currently being used for the SDL messages
+ * @return SdlMsgVersion the current RPC specification version
+ */
+ @NonNull SdlMsgVersion getSdlMsgVersion();
+
+ /**
+ * Get the protocol version of this session
+ * @return byte value representing WiPro version
+ */
+ @NonNull Version getProtocolVersion();
+
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/AddSubMenu.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/AddSubMenu.java
index b61a28772..a272e5455 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/AddSubMenu.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/AddSubMenu.java
@@ -50,6 +50,14 @@ import java.util.Hashtable;
* <td>maxlength:500</td>
* <td>SmartDeviceLink 1.0</td>
* </tr>
+ * <tr>
+ * <td>menuIcon</td>
+ * <td>Image</td>
+ * <td>Image to be be shown along with the submenu item</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
* </table>
* <b>Response</b>
* <p>Indicates that the corresponding request either failed or succeeded. If the response returns with a SUCCESS result code, this means the SubMenu was added to the Command Menu successfully</p>
@@ -66,6 +74,7 @@ public class AddSubMenu extends RPCRequest {
public static final String KEY_POSITION = "position";
public static final String KEY_MENU_NAME = "menuName";
public static final String KEY_MENU_ID = "menuID";
+ public static final String KEY_MENU_ICON = "menuIcon";
/**
* Constructs a new AddSubMenu object
@@ -166,4 +175,21 @@ public class AddSubMenu extends RPCRequest {
public void setMenuName( @NonNull String menuName ) {
setParameters(KEY_MENU_NAME, menuName);
}
+ /**
+ * Returns Image to be be shown along with the submenu item
+ *
+ * @return Image - the submenu icon
+ */
+ public Image getMenuIcon() {
+ return (Image) getObject(Image.class, KEY_MENU_ICON);
+ }
+ /**
+ * Sets image to be be shown along with the submenu item
+ *
+ * @param menuIcon
+ * Image to be be shown along with the submenu item
+ */
+ public void setMenuIcon(Image menuIcon) {
+ setParameters(KEY_MENU_ICON, menuIcon);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/AudioControlCapabilities.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/AudioControlCapabilities.java
new file mode 100644
index 000000000..fcaa7bf4c
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/AudioControlCapabilities.java
@@ -0,0 +1,150 @@
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.RPCStruct;
+
+import java.util.Hashtable;
+
+public class AudioControlCapabilities extends RPCStruct {
+ public static final String KEY_MODULE_NAME = "moduleName";
+ public static final String KEY_SOURCE_AVAILABLE = "sourceAvailable";
+ public static final String KEY_KEEP_CONTEXT_AVAILABLE = "keepContextAvailable";
+ public static final String KEY_VOLUME_AVAILABLE = "volumeAvailable";
+ public static final String KEY_EQUALIZER_AVAILABLE = "equalizerAvailable";
+ public static final String KEY_EQUALIZER_MAX_CHANNEL_ID = "equalizerMaxChannelId";
+
+ /**
+ * Constructs a newly allocated AudioControlCapabilities object
+ */
+ public AudioControlCapabilities() {
+ }
+
+ /**
+ * Constructs a newly allocated AudioControlCapabilities object indicated by the Hashtable parameter
+ *
+ * @param hash The Hashtable to use
+ */
+ public AudioControlCapabilities(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Constructs a newly allocated AudioControlCapabilities object
+ *
+ * @param moduleName short friendly name of the light control module.
+ */
+ public AudioControlCapabilities(@NonNull String moduleName) {
+ this();
+ setModuleName(moduleName);
+ }
+
+ /**
+ * Sets the moduleName portion of the AudioControlCapabilities class
+ *
+ * @param moduleName The short friendly name of the light control module. It should not be used to identify a module by mobile application.
+ */
+ public void setModuleName(@NonNull String moduleName) {
+ setValue(KEY_MODULE_NAME, moduleName);
+ }
+
+ /**
+ * Gets the moduleName portion of the AudioControlCapabilities class
+ *
+ * @return String - The short friendly name of the light control module. It should not be used to identify a module by mobile application.
+ */
+ public String getModuleName() {
+ return getString(KEY_MODULE_NAME);
+ }
+
+ /**
+ * Sets the keepContextAvailable portion of the AudioControlCapabilities class
+ *
+ * @param keepContextAvailable Availability of the keepContext parameter.
+ */
+ public void setKeepContextAvailable(Boolean keepContextAvailable) {
+ setValue(KEY_KEEP_CONTEXT_AVAILABLE, keepContextAvailable);
+ }
+
+ /**
+ * Gets the keepContextAvailable portion of the AudioControlCapabilities class
+ *
+ * @return Boolean - Availability of the keepContext parameter.
+ */
+ public Boolean getKeepContextAvailable() {
+ return getBoolean(KEY_KEEP_CONTEXT_AVAILABLE);
+ }
+
+ /**
+ * Sets the sourceAvailable portion of the AudioControlCapabilities class
+ *
+ * @param sourceAvailable Availability of the control of audio source.
+ */
+ public void setSourceAvailable(Boolean sourceAvailable) {
+ setValue(KEY_SOURCE_AVAILABLE, sourceAvailable);
+ }
+
+ /**
+ * Gets the sourceAvailable portion of the AudioControlCapabilities class
+ *
+ * @return Boolean - Availability of the control of audio source.
+ */
+ public Boolean getSourceAvailable() {
+ return getBoolean(KEY_SOURCE_AVAILABLE);
+ }
+
+ /**
+ * Sets the volumeAvailable portion of the AudioControlCapabilities class
+ *
+ * @param volumeAvailable Availability of the control of audio volume.
+ */
+ public void setVolumeAvailable(Boolean volumeAvailable) {
+ setValue(KEY_VOLUME_AVAILABLE, volumeAvailable);
+ }
+
+ /**
+ * Gets the volumeAvailable portion of the AudioControlCapabilities class
+ *
+ * @return Boolean - Availability of the control of audio volume.
+ */
+ public Boolean getVolumeAvailable() {
+ return getBoolean(KEY_VOLUME_AVAILABLE);
+ }
+
+ /**
+ * Sets the equalizerAvailable portion of the AudioControlCapabilities class
+ *
+ * @param equalizerAvailable Availability of the control of Equalizer Settings.
+ */
+ public void setEqualizerAvailable(Boolean equalizerAvailable) {
+ setValue(KEY_EQUALIZER_AVAILABLE, equalizerAvailable);
+ }
+
+ /**
+ * Gets the equalizerAvailable portion of the AudioControlCapabilities class
+ *
+ * @return Boolean - Availability of the control of Equalizer Settings.
+ */
+ public Boolean getEqualizerAvailable() {
+ return getBoolean(KEY_EQUALIZER_AVAILABLE);
+ }
+
+ /**
+ * Sets the equalizerMaxChannelId portion of the AudioControlCapabilities class
+ *
+ * @param equalizerMaxChannelId Must be included if equalizerAvailable=true, and assume all IDs starting from 1 to this value are valid.
+ */
+ public void setEqualizerMaxChannelId(Integer equalizerMaxChannelId) {
+ setValue(KEY_EQUALIZER_MAX_CHANNEL_ID, equalizerMaxChannelId);
+ }
+
+ /**
+ * Gets the equalizerMaxChannelId portion of the AudioControlCapabilities class
+ *
+ * @return Integer - Must be included if equalizerAvailable=true, and assume all IDs starting from 1 to this value are valid.
+ */
+ public Integer getEqualizerMaxChannelId() {
+ return getInteger(KEY_EQUALIZER_MAX_CHANNEL_ID);
+ }
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/AudioControlData.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/AudioControlData.java
new file mode 100644
index 000000000..b6ec0bfb1
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/AudioControlData.java
@@ -0,0 +1,115 @@
+package com.smartdevicelink.proxy.rpc;
+
+import com.smartdevicelink.proxy.RPCStruct;
+import com.smartdevicelink.proxy.rpc.enums.PrimaryAudioSource;
+
+import java.util.Hashtable;
+import java.util.List;
+
+public class AudioControlData extends RPCStruct {
+ public static final String KEY_SOURCE = "source";
+ public static final String KEY_KEEP_CONTEXT = "keepContext";
+ public static final String KEY_VOLUME = "volume";
+ public static final String KEY_EQUALIZER_SETTINGS = "equalizerSettings";
+
+ /**
+ * Constructs a newly allocated AudioControlData object
+ */
+ public AudioControlData() {
+ }
+
+ /**
+ * Constructs a newly allocated AudioControlData object indicated by the Hashtable parameter
+ *
+ * @param hash The Hashtable to use
+ */
+ public AudioControlData(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Sets the source portion of the AudioControlData class
+ *
+ * @param source In a getter response or a notification, it is the current primary audio source of the system.
+ * In a setter request, it is the target audio source that the system shall switch to.
+ * If the value is MOBILE_APP, the system shall switch to the mobile media app that issues the setter RPC.
+ */
+ public void setSource(PrimaryAudioSource source) {
+ setValue(KEY_SOURCE, source);
+ }
+
+ /**
+ * Gets the source portion of the AudioControlData class
+ *
+ * @return PrimaryAudioSource - In a getter response or a notification, it is the current primary audio source of the system.
+ * In a setter request, it is the target audio source that the system shall switch to.
+ * If the value is MOBILE_APP, the system shall switch to the mobile media app that issues the setter RPC.
+ */
+ public PrimaryAudioSource getSource() {
+ return (PrimaryAudioSource) getObject(PrimaryAudioSource.class, KEY_SOURCE);
+ }
+
+ /**
+ * Sets the keepContext portion of the AudioControlData class
+ *
+ * @param keepContext This parameter shall not be present in any getter responses or notifications.
+ * This parameter is optional in a setter request. The default value is false if it is not included.
+ * If it is false, the system not only changes the audio source but also brings the default application or
+ * system UI associated with the audio source to foreground.
+ * If it is true, the system only changes the audio source, but keeps the current application in foreground.
+ */
+ public void setKeepContext(Boolean keepContext) {
+ setValue(KEY_KEEP_CONTEXT, keepContext);
+ }
+
+ /**
+ * Gets the keepContext portion of the AudioControlData class
+ *
+ * @return Boolean - This parameter shall not be present in any getter responses or notifications.
+ * This parameter is optional in a setter request. The default value is false if it is not included.
+ * If it is false, the system not only changes the audio source but also brings the default application or
+ * system UI associated with the audio source to foreground.
+ * If it is true, the system only changes the audio source, but keeps the current application in foreground.
+ */
+ public Boolean getKeepContext() {
+ return getBoolean(KEY_KEEP_CONTEXT);
+ }
+
+ /**
+ * Sets the volume portion of the AudioControlData class
+ *
+ * @param volume Reflects the volume of audio, from 0%-100%.
+ */
+ public void setVolume(Integer volume) {
+ setValue(KEY_VOLUME, volume);
+ }
+
+ /**
+ * Gets the volume portion of the AudioControlData class
+ *
+ * @return Integer - Reflects the volume of audio, from 0%-100%.
+ */
+ public Integer getVolume() {
+ return getInteger(KEY_VOLUME);
+ }
+
+ /**
+ * Gets the equalizerSettings portion of the AudioControlData class
+ *
+ * @return List<EqualizerSettings> - Defines the list of supported channels (band) and their current/desired settings on HMI.
+ */
+ @SuppressWarnings("unchecked")
+ public List<EqualizerSettings> getEqualizerSettings() {
+ return (List<EqualizerSettings>) getObject(EqualizerSettings.class, KEY_EQUALIZER_SETTINGS);
+ }
+
+ /**
+ * Sets the equalizerSettings portion of the AudioControlData class
+ *
+ * @param equalizerSettings Defines the list of supported channels (band) and their current/desired settings on HMI.
+ */
+ public void setEqualizerSettings(List<EqualizerSettings> equalizerSettings) {
+ setValue(KEY_EQUALIZER_SETTINGS, equalizerSettings);
+ }
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/Choice.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/Choice.java
index 989ac2997..e93196bd5 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/Choice.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/Choice.java
@@ -3,7 +3,9 @@ package com.smartdevicelink.proxy.rpc;
import android.support.annotation.NonNull;
import com.smartdevicelink.proxy.RPCStruct;
+import com.smartdevicelink.util.Version;
+import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
@@ -64,10 +66,12 @@ public class Choice extends RPCStruct {
public static final String KEY_VR_COMMANDS = "vrCommands";
public static final String KEY_CHOICE_ID = "choiceID";
public static final String KEY_IMAGE = "image";
+
/**
* Constructs a newly allocated Choice object
*/
public Choice() { }
+
/**
* Constructs a newly allocated Choice object indicated by the Hashtable parameter
* @param hash The Hashtable to use
@@ -75,18 +79,64 @@ public class Choice extends RPCStruct {
public Choice(Hashtable<String, Object> hash) {
super(hash);
}
+
+ /**
+ * Constructs a newly allocated Choice object
+ * @param choiceID Min: 0 Max: 65535
+ * @param menuName the menu name
+ */
+ public Choice(@NonNull Integer choiceID, @NonNull String menuName) {
+ this();
+ setChoiceID(choiceID);
+ setMenuName(menuName);
+ }
+
/**
* Constructs a newly allocated Choice object
* @param choiceID Min: 0 Max: 65535
* @param menuName the menu name
* @param vrCommands the List of vrCommands
+ *
+ * Deprecated - use {@link #Choice(Integer, String)}
*/
+ @Deprecated
public Choice(@NonNull Integer choiceID, @NonNull String menuName, @NonNull List<String> vrCommands) {
this();
setChoiceID(choiceID);
setMenuName(menuName);
setVrCommands(vrCommands);
}
+
+ /**
+ * VrCommands became optional as of RPC Spec 5.0. On legacy systems, we must still set VrCommands, as
+ * they are expected, even though the developer may not specify them. <br>
+ *
+ * Additionally, VrCommands must be unique, therefore we will use the string value of the command's ID
+ *
+ * @param rpcVersion the rpc spec version that has been negotiated. If value is null the
+ * the max value of RPC spec version this library supports should be used.
+ * @param formatParams if true, the format method will be called on subsequent params
+ */
+ @Override
+ public void format(Version rpcVersion, boolean formatParams){
+
+ if (rpcVersion == null || rpcVersion.getMajor() < 5){
+
+ // make sure there is at least one vr param
+ List<String> existingVrCommands = getVrCommands();
+
+ if (existingVrCommands == null || existingVrCommands.size() == 0) {
+ // if no commands set, set one due to a legacy head unit requirement
+ Integer choiceID = getChoiceID();
+ List<String> vrCommands = new ArrayList<>();
+ vrCommands.add(String.valueOf(choiceID));
+ setVrCommands(vrCommands);
+ }
+ }
+
+ super.format(rpcVersion, formatParams);
+ }
+
/**
* Get the application-scoped identifier that uniquely identifies this choice.
* @return choiceID Min: 0; Max: 65535
@@ -133,7 +183,7 @@ public class Choice extends RPCStruct {
* @param vrCommands the List of vrCommands
* @since SmartDeviceLink 2.0
*/
- public void setVrCommands(@NonNull List<String> vrCommands) {
+ public void setVrCommands(List<String> vrCommands) {
setValue(KEY_VR_COMMANDS, vrCommands);
}
/**
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ClimateControlCapabilities.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ClimateControlCapabilities.java
index 61a967585..335fffa48 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ClimateControlCapabilities.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ClimateControlCapabilities.java
@@ -25,6 +25,10 @@ public class ClimateControlCapabilities extends RPCStruct{
public static final String KEY_DEFROST_ZONE= "defrostZone";
public static final String KEY_VENTILATION_MODE_AVAILABLE= "ventilationModeAvailable";
public static final String KEY_VENTILATION_MODE= "ventilationMode";
+ public static final String KEY_HEATED_STEERING_WHEEL_AVAILABLE = "heatedSteeringWheelAvailable";
+ public static final String KEY_HEATED_WIND_SHIELD_AVAILABLE = "heatedWindshieldAvailable";
+ public static final String KEY_HEATED_REAR_WINDOW_AVAILABLE = "heatedRearWindowAvailable";
+ public static final String KEY_HEATED_MIRRORS_AVAILABLE = "heatedMirrorsAvailable";
public ClimateControlCapabilities() {
}
@@ -287,4 +291,84 @@ public class ClimateControlCapabilities extends RPCStruct{
public void setVentilationMode(List<VentilationMode> ventilationMode) {
setValue(KEY_VENTILATION_MODE, ventilationMode);
}
+
+ /**
+ * Sets the heatedSteeringWheelAvailable portion of the ClimateControlCapabilities class
+ *
+ * @param heatedSteeringWheelAvailable Availability of the control (enable/disable) of heated Steering Wheel.
+ * True: Available, False: Not Available, Not present: Not Available.
+ */
+ public void setHeatedSteeringWheelAvailable(Boolean heatedSteeringWheelAvailable) {
+ setValue(KEY_HEATED_STEERING_WHEEL_AVAILABLE, heatedSteeringWheelAvailable);
+ }
+
+ /**
+ * Gets the heatedSteeringWheelAvailable portion of the ClimateControlCapabilities class
+ *
+ * @return Boolean - Availability of the control (enable/disable) of heated Steering Wheel.
+ * True: Available, False: Not Available, Not present: Not Available.
+ */
+ public Boolean getHeatedSteeringWheelAvailable() {
+ return getBoolean(KEY_HEATED_STEERING_WHEEL_AVAILABLE);
+ }
+
+ /**
+ * Sets the heatedWindshieldAvailable portion of the ClimateControlCapabilities class
+ *
+ * @param heatedWindshieldAvailable Availability of the control (enable/disable) of heated Windshield.
+ * True: Available, False: Not Available, Not present: Not Available.
+ */
+ public void setHeatedWindshieldAvailable(Boolean heatedWindshieldAvailable) {
+ setValue(KEY_HEATED_WIND_SHIELD_AVAILABLE, heatedWindshieldAvailable);
+ }
+
+ /**
+ * Gets the heatedWindshieldAvailable portion of the ClimateControlCapabilities class
+ *
+ * @return Boolean - Availability of the control (enable/disable) of heated Windshield.
+ * True: Available, False: Not Available, Not present: Not Available.
+ */
+ public Boolean getHeatedWindshieldAvailable() {
+ return getBoolean(KEY_HEATED_WIND_SHIELD_AVAILABLE);
+ }
+
+ /**
+ * Sets the heatedRearWindowAvailable portion of the ClimateControlCapabilities class
+ *
+ * @param heatedRearWindowAvailable Availability of the control (enable/disable) of heated Rear Window.
+ * True: Available, False: Not Available, Not present: Not Available.
+ */
+ public void setHeatedRearWindowAvailable(Boolean heatedRearWindowAvailable) {
+ setValue(KEY_HEATED_REAR_WINDOW_AVAILABLE, heatedRearWindowAvailable);
+ }
+
+ /**
+ * Gets the heatedRearWindowAvailable portion of the ClimateControlCapabilities class
+ *
+ * @return Boolean - Availability of the control (enable/disable) of heated Rear Window.
+ * True: Available, False: Not Available, Not present: Not Available.
+ */
+ public Boolean getHeatedRearWindowAvailable() {
+ return getBoolean(KEY_HEATED_REAR_WINDOW_AVAILABLE);
+ }
+
+ /**
+ * Sets the heatedMirrorsAvailable portion of the ClimateControlCapabilities class
+ *
+ * @param heatedMirrorsAvailable Availability of the control (enable/disable) of heated Mirrors.
+ * True: Available, False: Not Available, Not present: Not Available.
+ */
+ public void setHeatedMirrorsAvailable(Boolean heatedMirrorsAvailable) {
+ setValue(KEY_HEATED_MIRRORS_AVAILABLE, heatedMirrorsAvailable);
+ }
+
+ /**
+ * Gets the heatedMirrorsAvailable portion of the ClimateControlCapabilities class
+ *
+ * @return Boolean - Availability of the control (enable/disable) of heated Mirrors.
+ * True: Available, False: Not Available, Not present: Not Available.
+ */
+ public Boolean getHeatedMirrorsAvailable() {
+ return getBoolean(KEY_HEATED_MIRRORS_AVAILABLE);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ClimateControlData.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ClimateControlData.java
index 0da8060f3..1229e4668 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ClimateControlData.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ClimateControlData.java
@@ -3,6 +3,7 @@ package com.smartdevicelink.proxy.rpc;
import com.smartdevicelink.proxy.RPCStruct;
import com.smartdevicelink.proxy.rpc.enums.DefrostZone;
import com.smartdevicelink.proxy.rpc.enums.VentilationMode;
+
import java.util.Hashtable;
public class ClimateControlData extends RPCStruct{
@@ -16,6 +17,10 @@ public class ClimateControlData extends RPCStruct{
public static final String KEY_DUAL_MODE_ENABLE= "dualModeEnable";
public static final String KEY_AC_MAX_ENABLE= "acMaxEnable";
public static final String KEY_VENTILATION_MODE= "ventilationMode";
+ public static final String KEY_HEATED_STEERING_WHEEL_ENABLE = "heatedSteeringWheelEnable";
+ public static final String KEY_HEATED_WIND_SHIELD_ENABLE = "heatedWindshieldEnable";
+ public static final String KEY_HEATED_REAR_WINDOW_ENABLE = "heatedRearWindowEnable";
+ public static final String KEY_HEATED_MIRRORS_ENABLE = "heatedMirrorsEnable";
public ClimateControlData() {
}
@@ -103,4 +108,76 @@ public class ClimateControlData extends RPCStruct{
public VentilationMode getVentilationMode() {
return (VentilationMode) getObject(VentilationMode.class, KEY_VENTILATION_MODE);
}
+
+ /**
+ * Sets the heatedSteeringWheelEnable portion of the ClimateControlCapabilities class
+ *
+ * @param heatedSteeringWheelEnable Value false means disabled/turn off, value true means enabled/turn on.
+ */
+ public void setHeatedSteeringWheelEnable(Boolean heatedSteeringWheelEnable) {
+ setValue(KEY_HEATED_STEERING_WHEEL_ENABLE, heatedSteeringWheelEnable);
+ }
+
+ /**
+ * Gets the heatedSteeringWheelEnable portion of the ClimateControlCapabilities class
+ *
+ * @return Boolean - Value false means disabled/turn off, value true means enabled/turn on.
+ */
+ public Boolean getHeatedSteeringWheelEnable() {
+ return getBoolean(KEY_HEATED_STEERING_WHEEL_ENABLE);
+ }
+
+ /**
+ * Sets the heatedWindshieldEnable portion of the ClimateControlCapabilities class
+ *
+ * @param heatedWindshieldEnable Value false means disabled, value true means enabled.
+ */
+ public void setHeatedWindshieldEnable(Boolean heatedWindshieldEnable) {
+ setValue(KEY_HEATED_WIND_SHIELD_ENABLE, heatedWindshieldEnable);
+ }
+
+ /**
+ * Gets the heatedWindshieldEnable portion of the ClimateControlCapabilities class
+ *
+ * @return Boolean - Value false means disabled, value true means enabled.
+ */
+ public Boolean getHeatedWindshieldEnable() {
+ return getBoolean(KEY_HEATED_WIND_SHIELD_ENABLE);
+ }
+
+ /**
+ * Sets the heatedRearWindowEnable portion of the ClimateControlCapabilities class
+ *
+ * @param heatedRearWindowEnable Value false means disabled, value true means enabled.
+ */
+ public void setHeatedRearWindowEnable(Boolean heatedRearWindowEnable) {
+ setValue(KEY_HEATED_REAR_WINDOW_ENABLE, heatedRearWindowEnable);
+ }
+
+ /**
+ * Gets the heatedRearWindowEnable portion of the ClimateControlCapabilities class
+ *
+ * @return Boolean - Value false means disabled, value true means enabled.
+ */
+ public Boolean getHeatedRearWindowEnable() {
+ return getBoolean(KEY_HEATED_REAR_WINDOW_ENABLE);
+ }
+
+ /**
+ * Sets the heatedMirrorsEnable portion of the ClimateControlCapabilities class
+ *
+ * @param heatedMirrorsEnable Value false means disabled, value true means enabled.
+ */
+ public void setHeatedMirrorsEnable(Boolean heatedMirrorsEnable) {
+ setValue(KEY_HEATED_MIRRORS_ENABLE, heatedMirrorsEnable);
+ }
+
+ /**
+ * Gets the heatedMirrorsEnable portion of the ClimateControlCapabilities class
+ *
+ * @return Boolean - Value false means disabled, value true means enabled.
+ */
+ public Boolean getHeatedMirrorsEnable() {
+ return getBoolean(KEY_HEATED_MIRRORS_ENABLE);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/DeleteFileResponse.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/DeleteFileResponse.java
index 347cd0490..918ca7fce 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/DeleteFileResponse.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/DeleteFileResponse.java
@@ -5,6 +5,7 @@ import android.support.annotation.NonNull;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCResponse;
import com.smartdevicelink.proxy.rpc.enums.Result;
+import com.smartdevicelink.util.Version;
import java.util.Hashtable;
@@ -15,31 +16,69 @@ import java.util.Hashtable;
*/
public class DeleteFileResponse extends RPCResponse {
public static final String KEY_SPACE_AVAILABLE = "spaceAvailable";
- /** Constructs a new DeleteFileResponse object
- *
- */
+ private static final Integer MAX_VALUE = 2000000000;
+ /**
+ * Constructs a new DeleteFileResponse object
+ */
public DeleteFileResponse() {
super(FunctionID.DELETE_FILE.toString());
}
+
public DeleteFileResponse(Hashtable<String, Object> hash) {
super(hash);
}
+
/**
+ * @deprecated use {@link DeleteFileResponse#DeleteFileResponse(Boolean, Result)} instead <br>
+ *
* Constructs a new DeleteFileResponse object
* @param success whether the request is successfully processed
* @param resultCode whether the request is successfully processed
* @param spaceAvailable the total local space available on the module for the registered app.
*/
+ @Deprecated
public DeleteFileResponse(@NonNull Boolean success, @NonNull Result resultCode, @NonNull Integer spaceAvailable) {
this();
setSuccess(success);
setResultCode(resultCode);
setSpaceAvailable(spaceAvailable);
}
- public void setSpaceAvailable(@NonNull Integer spaceAvailable) {
+
+ /**
+ * Constructs a new DeleteFileResponse object
+ * @param success whether the request is successfully processed
+ * @param resultCode whether the request is successfully processed
+ */
+ public DeleteFileResponse(@NonNull Boolean success, @NonNull Result resultCode) {
+ this();
+ setSuccess(success);
+ setResultCode(resultCode);
+ }
+
+ /**
+ * SpaceAvailable became optional as of RPC Spec 5.0. If a system that expected the value to
+ * always have a value connects to such a system, it could return null. Check to see if there
+ * is a value, and if not, set it to MAX_VALUE as defined by the RPC Spec
+ *
+ * @param rpcVersion the rpc spec version that has been negotiated. If value is null the
+ * the max value of RPC spec version this library supports should be used.
+ * @param formatParams if true, the format method will be called on subsequent params
+ */
+ @Override
+ public void format(Version rpcVersion, boolean formatParams){
+ if (rpcVersion == null || rpcVersion.getMajor() >= 5){
+ if (getSpaceAvailable() == null){
+ setSpaceAvailable(MAX_VALUE);
+ }
+ }
+ super.format(rpcVersion, formatParams);
+ }
+
+ public void setSpaceAvailable(Integer spaceAvailable) {
setParameters(KEY_SPACE_AVAILABLE, spaceAvailable);
}
+
public Integer getSpaceAvailable() {
return getInteger(KEY_SPACE_AVAILABLE);
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/DisplayCapabilities.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/DisplayCapabilities.java
index 12bf0ffd8..e97a3d449 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/DisplayCapabilities.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/DisplayCapabilities.java
@@ -11,6 +11,9 @@ import com.smartdevicelink.util.DebugTool;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
+
+import static com.smartdevicelink.proxy.constants.Names.displayType;
+
/**
* Contains information about the display for the SDL system to which the application is currently connected.
* <p><b> Parameter List</b></p>
@@ -22,6 +25,7 @@ import java.util.List;
* <th>SmartDeviceLink Ver. Available</th>
* </tr>
* <tr>
+ * @Deprecated
* <td>displayType</td>
* <td>DisplayType</td>
* <td>The type of display
@@ -29,6 +33,13 @@ import java.util.List;
* <td>SmartDeviceLink 1.0</td>
* </tr>
* <tr>
+ * <td>displayName</td>
+ * <td>String</td>
+ * <td>The name of the display
+ * </td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
+ * <tr>
* <td>textField</td>
* <td>TextField[]</td>
* <td>An array of TextField structures, each of which describes a field in the HMI which the application can write to using operations such as <i>{@linkplain Show}</i>, <i>{@linkplain SetMediaClockTimer}</i>, etc.
@@ -36,13 +47,13 @@ import java.util.List;
* </td>
* <td>SmartDeviceLink 1.0</td>
* </tr>
- * <tr>
+ * <tr>
* <td>mediaClockFormats</td>
* <td>MediaClockFormat[]</td>
* <td>An array of MediaClockFormat elements, defining the valid string formats used in specifying the contents of the media clock field</td>
* <td>SmartDeviceLink 1.0</td>
* </tr>
- * <tr>
+ * <tr>
* <td>graphicSupported</td>
* <td>Boolean</td>
* <td>The display's persistent screen supports referencing a static or dynamic image.</td>
@@ -58,6 +69,7 @@ import java.util.List;
*/
public class DisplayCapabilities extends RPCStruct {
public static final String KEY_DISPLAY_TYPE = "displayType";
+ public static final String KEY_DISPLAY_NAME = "displayName";
public static final String KEY_MEDIA_CLOCK_FORMATS = "mediaClockFormats";
public static final String KEY_TEXT_FIELDS = "textFields";
public static final String KEY_IMAGE_FIELDS = "imageFields";
@@ -83,6 +95,7 @@ public class DisplayCapabilities extends RPCStruct {
* @param mediaClockFormats the List of MediaClockFormat
* @param graphicSupported
*/
+ @Deprecated
public DisplayCapabilities(@NonNull DisplayType displayType, @NonNull List<TextField> textFields, @NonNull List<MediaClockFormat> mediaClockFormats, @NonNull Boolean graphicSupported) {
this();
setDisplayType(displayType);
@@ -91,19 +104,48 @@ public class DisplayCapabilities extends RPCStruct {
setGraphicSupported(graphicSupported);
}
/**
+ * Constructs a newly allocated DisplayCapabilities object
+ * @param displayName the display name (String)
+ * @param textFields the List of textFields
+ * @param mediaClockFormats the List of MediaClockFormat
+ * @param graphicSupported
+ */
+ public DisplayCapabilities(String displayName, @NonNull List<TextField> textFields, @NonNull List<MediaClockFormat> mediaClockFormats, @NonNull Boolean graphicSupported) {
+ this();
+ setDisplayName(displayName);
+ setTextFields(textFields);
+ setMediaClockFormats(mediaClockFormats);
+ setGraphicSupported(graphicSupported);
+ }
+ /**
* Get the type of display
* @return the type of display
- */
+ */
+ @Deprecated
public DisplayType getDisplayType() {
return (DisplayType) getObject(DisplayType.class, KEY_DISPLAY_TYPE);
}
/**
* Set the type of display
* @param displayType the display type
- */
+ */
+ @Deprecated
public void setDisplayType( @NonNull DisplayType displayType ) {
setValue(KEY_DISPLAY_TYPE, displayType);
}
+ /** Get the name of the display
+ * @return the name of the display
+ */
+ public String getDisplayName() {
+ return getString(KEY_DISPLAY_NAME);
+ }
+ /**
+ * Set the name of the display
+ * @param displayName the name of the display
+ */
+ public void setDisplayName( String displayName ) {
+ setValue(KEY_DISPLAY_NAME, displayName);
+ }
/**
*Get an array of TextField structures, each of which describes a field in the HMI which the application can write to using operations such as <i>{@linkplain Show}</i>, <i>{@linkplain SetMediaClockTimer}</i>, etc.
* This array of TextField structures identify all the text fields to which the application can write on the current display (identified by DisplayType ).
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/EqualizerSettings.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/EqualizerSettings.java
new file mode 100644
index 000000000..78e76c808
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/EqualizerSettings.java
@@ -0,0 +1,97 @@
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.RPCStruct;
+
+import java.util.Hashtable;
+
+/**
+ * Defines the each Equalizer channel settings.
+ */
+public class EqualizerSettings extends RPCStruct {
+ public static final String KEY_CHANNEL_ID = "channelId";
+ public static final String KEY_CHANNEL_NAME = "channelName";
+ public static final String KEY_CHANNEL_SETTING = "channelSetting";
+
+ /**
+ * Constructs a newly allocated EqualizerSettings object
+ */
+ public EqualizerSettings() {
+ }
+
+ /**
+ * Constructs a newly allocated EqualizerSettings object indicated by the Hashtable parameter
+ *
+ * @param hash The Hashtable to use
+ */
+ public EqualizerSettings(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Constructs a newly allocated EqualizerSettings object
+ *
+ * @param channelId Min: 0 Max: 100
+ * @param channelSetting Min: 0 Max: 100
+ */
+ public EqualizerSettings(@NonNull Integer channelId, @NonNull Integer channelSetting) {
+ this();
+ setChannelId(channelId);
+ setChannelSetting(channelSetting);
+ }
+
+ /**
+ * Sets the channelId portion of the EqualizerSettings class
+ *
+ * @param channelId
+ */
+ public void setChannelId(@NonNull Integer channelId) {
+ setValue(KEY_CHANNEL_ID, channelId);
+ }
+
+ /**
+ * Gets the channelId portion of the EqualizerSettings class
+ *
+ * @return Integer
+ */
+ public Integer getChannelId() {
+ return getInteger(KEY_CHANNEL_ID);
+ }
+
+ /**
+ * Sets the channelName portion of the EqualizerSettings class
+ *
+ * @param channelName Read-only channel / frequency name (e.i. "Treble, Midrange, Bass" or "125 Hz").
+ */
+ public void setChannelName(String channelName) {
+ setValue(KEY_CHANNEL_NAME, channelName);
+ }
+
+ /**
+ * Gets the channelName portion of the EqualizerSettings class
+ *
+ * @return String - Read-only channel / frequency name (e.i. "Treble, Midrange, Bass" or "125 Hz").
+ */
+ public String getChannelName() {
+ return getString(KEY_CHANNEL_NAME);
+ }
+
+ /**
+ * Sets the channelSetting portion of the EqualizerSettings class
+ *
+ * @param channelSetting Reflects the setting, from 0%-100%.
+ */
+ public void setChannelSetting(@NonNull Integer channelSetting) {
+ setValue(KEY_CHANNEL_SETTING, channelSetting);
+ }
+
+ /**
+ * Gets the channelSetting portion of the EqualizerSettings class
+ *
+ * @return Integer - Reflects the setting, from 0%-100%.
+ */
+ public Integer getChannelSetting() {
+ return getInteger(KEY_CHANNEL_SETTING);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/FuelRange.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/FuelRange.java
new file mode 100644
index 000000000..01027aa8d
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/FuelRange.java
@@ -0,0 +1,66 @@
+package com.smartdevicelink.proxy.rpc;
+
+import com.smartdevicelink.proxy.RPCStruct;
+import com.smartdevicelink.proxy.rpc.enums.FuelType;
+import com.smartdevicelink.util.SdlDataTypeConverter;
+
+import java.util.Hashtable;
+
+public class FuelRange extends RPCStruct{
+ public static final String KEY_TYPE = "type";
+ public static final String KEY_RANGE = "range";
+
+ /**
+ * Constructs a new FuelRange object
+ */
+ public FuelRange() { }
+
+ /**
+ * <p>Constructs a new FuelRange object indicated by the Hashtable parameter
+ * </p>
+ *
+ * @param hash
+ * The Hashtable to use
+ */
+ public FuelRange(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Sets the type portion of the FuelRange class
+ *
+ * @param fuelType
+ */
+ public void setType(FuelType fuelType) {
+ setValue(KEY_TYPE, fuelType);
+ }
+
+ /**
+ * Gets the type portion of the FuelRange class
+ *
+ * @return FuelType.
+ */
+ public FuelType getType() {
+ return (FuelType) getObject(FuelType.class, KEY_TYPE);
+ }
+
+ /**
+ * Gets the range portion of the FuelRange class
+ *
+ * @return Float - The estimate range in KM the vehicle can travel based on fuel level and consumption.
+ */
+ public Float getRange() {
+ Object object = getValue(KEY_RANGE);
+ return SdlDataTypeConverter.objectToFloat(object);
+ }
+
+ /**
+ * Sets the range portion of the FuelRange class
+ *
+ * @param range
+ * The estimate range in KM the vehicle can travel based on fuel level and consumption.
+ */
+ public void setRange(Float range) {
+ setValue(KEY_RANGE, range);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GPSData.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GPSData.java
index 274e5c1be..ca264556f 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GPSData.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GPSData.java
@@ -79,21 +79,21 @@ import java.util.Hashtable;
* <tr>
* <td>pdop</td>
* <td>Integer</td>
- * <td>Positional Dilution of Precision<b>Minvalue: 0<b>Maxvalue: 31
+ * <td>Positional Dilution of Precision. If undefined or unavailable, then value shall be set to 0.<b>Minvalue: 0<b>Maxvalue: 1000
* </td>
* <td>SmartDeviceLink 2.0</td>
* </tr>
* <tr>
* <td>hdop</td>
* <td>Integer</td>
- * <td>Horizontal Dilution of Precision<b>Minvalue: 0<b>Maxvalue: 31
+ * <td>Horizontal Dilution of Precision. If value is unknown, value shall be set to 0.<b>Minvalue: 0<b>Maxvalue: 1000
* </td>
* <td>SmartDeviceLink 2.0</td>
* </tr>
* <tr>
* <td>vdop</td>
* <td>Integer</td>
- * <td>Vertical Dilution of Precision<b>Minvalue: 0<b>Maxvalue: 31
+ * <td>Vertical Dilution of Precision. If value is unknown, value shall be set to 0.<b>Minvalue: 0<b>Maxvalue: 1000
* </td>
* <td>SmartDeviceLink 2.0</td>
* </tr>
@@ -138,7 +138,7 @@ import java.util.Hashtable;
* <td>Integer</td>
* <td>The speed in KPH
* <b>Minvalue: 0
- * <b>Maxvalue: 400
+ * <b>Maxvalue: 500
* </td>
* <td>SmartDeviceLink 2.0</td>
* </tr>
@@ -169,7 +169,7 @@ public class GPSData extends RPCStruct {
* Constructs a newly allocated GPSData object
*/
public GPSData() { }
-
+
/**
* Constructs a newly allocated GPSData object indicated by the Hashtable parameter
* @param hash The Hashtable to use
@@ -180,7 +180,9 @@ public class GPSData extends RPCStruct {
/**
* Constructs a newly allocated GPSData object
+ * @deprecated Use {@link #GPSData(@NonNull Double, @NonNull Double)()} instead
*/
+ @Deprecated
public GPSData(@NonNull Double longitudeDegrees, @NonNull Double latitudeDegrees, @NonNull Integer utcYear,
@NonNull Integer utcMonth, @NonNull Integer utcDay, @NonNull Integer utcHours,
@NonNull Integer utcMinutes, @NonNull Integer utcSeconds, @NonNull CompassDirection compassDirection,
@@ -206,6 +208,15 @@ public class GPSData extends RPCStruct {
setHeading(heading);
setSpeed(speed);
}
+
+ /**
+ * Constructs a newly allocated GPSData object
+ */
+ public GPSData(@NonNull Double longitudeDegrees, @NonNull Double latitudeDegrees) {
+ this();
+ setLongitudeDegrees(longitudeDegrees);
+ setLatitudeDegrees(latitudeDegrees);
+ }
/**
* set longitude degrees
* @param longitudeDegrees
@@ -244,7 +255,7 @@ public class GPSData extends RPCStruct {
* set utc year
* @param utcYear utc year
*/
- public void setUtcYear(@NonNull Integer utcYear) {
+ public void setUtcYear(Integer utcYear) {
setValue(KEY_UTC_YEAR, utcYear);
}
@@ -260,7 +271,7 @@ public class GPSData extends RPCStruct {
* set utc month
* @param utcMonth utc month
*/
- public void setUtcMonth(@NonNull Integer utcMonth) {
+ public void setUtcMonth(Integer utcMonth) {
setValue(KEY_UTC_MONTH, utcMonth);
}
@@ -276,7 +287,7 @@ public class GPSData extends RPCStruct {
* set utc day
* @param utcDay utc day
*/
- public void setUtcDay(@NonNull Integer utcDay) {
+ public void setUtcDay(Integer utcDay) {
setValue(KEY_UTC_DAY, utcDay);
}
@@ -292,7 +303,7 @@ public class GPSData extends RPCStruct {
* set utc hours
* @param utcHours utc hours
*/
- public void setUtcHours(@NonNull Integer utcHours) {
+ public void setUtcHours(Integer utcHours) {
setValue(KEY_UTC_HOURS, utcHours);
}
@@ -308,7 +319,7 @@ public class GPSData extends RPCStruct {
* set utc minutes
* @param utcMinutes utc minutes
*/
- public void setUtcMinutes(@NonNull Integer utcMinutes) {
+ public void setUtcMinutes(Integer utcMinutes) {
setValue(KEY_UTC_MINUTES, utcMinutes);
}
@@ -324,7 +335,7 @@ public class GPSData extends RPCStruct {
* set utc seconds
* @param utcSeconds utc seconds
*/
- public void setUtcSeconds(@NonNull Integer utcSeconds) {
+ public void setUtcSeconds(Integer utcSeconds) {
setValue(KEY_UTC_SECONDS, utcSeconds);
}
@@ -335,7 +346,7 @@ public class GPSData extends RPCStruct {
public Integer getUtcSeconds() {
return getInteger(KEY_UTC_SECONDS);
}
- public void setCompassDirection(@NonNull CompassDirection compassDirection) {
+ public void setCompassDirection(CompassDirection compassDirection) {
setValue(KEY_COMPASS_DIRECTION, compassDirection);
}
public CompassDirection getCompassDirection() {
@@ -346,7 +357,7 @@ public class GPSData extends RPCStruct {
* set the positional dilution of precision
* @param pdop the positional dilution of precision
*/
- public void setPdop(@NonNull Double pdop) {
+ public void setPdop(Double pdop) {
setValue(KEY_PDOP, pdop);
}
@@ -362,7 +373,7 @@ public class GPSData extends RPCStruct {
* set the horizontal dilution of precision
* @param hdop the horizontal dilution of precision
*/
- public void setHdop(@NonNull Double hdop) {
+ public void setHdop(Double hdop) {
setValue(KEY_HDOP, hdop);
}
@@ -379,7 +390,7 @@ public class GPSData extends RPCStruct {
* set the vertical dilution of precision
* @param vdop the vertical dilution of precision
*/
- public void setVdop(@NonNull Double vdop) {
+ public void setVdop(Double vdop) {
setValue(KEY_VDOP, vdop);
}
@@ -396,7 +407,7 @@ public class GPSData extends RPCStruct {
* set what coordinates based on
* @param actual True, if coordinates are based on satellites.False, if based on dead reckoning
*/
- public void setActual(@NonNull Boolean actual) {
+ public void setActual(Boolean actual) {
setValue(KEY_ACTUAL, actual);
}
@@ -412,7 +423,7 @@ public class GPSData extends RPCStruct {
* set the number of satellites in view
* @param satellites the number of satellites in view
*/
- public void setSatellites(@NonNull Integer satellites) {
+ public void setSatellites(Integer satellites) {
setValue(KEY_SATELLITES, satellites);
}
@@ -423,7 +434,7 @@ public class GPSData extends RPCStruct {
public Integer getSatellites() {
return getInteger(KEY_SATELLITES);
}
- public void setDimension(@NonNull Dimension dimension) {
+ public void setDimension(Dimension dimension) {
setValue(KEY_DIMENSION, dimension);
}
public Dimension getDimension() {
@@ -434,7 +445,7 @@ public class GPSData extends RPCStruct {
* set altitude in meters
* @param altitude altitude in meters
*/
- public void setAltitude(@NonNull Double altitude) {
+ public void setAltitude(Double altitude) {
setValue(KEY_ALTITUDE, altitude);
}
@@ -451,7 +462,7 @@ public class GPSData extends RPCStruct {
* set the heading.North is 0, East is 90, etc.
* @param heading the heading.
*/
- public void setHeading(@NonNull Double heading) {
+ public void setHeading(Double heading) {
setValue(KEY_HEADING, heading);
}
@@ -467,7 +478,7 @@ public class GPSData extends RPCStruct {
* set speed in KPH
* @param speed the speed
*/
- public void setSpeed(@NonNull Double speed) {
+ public void setSpeed(Double speed) {
setValue(KEY_SPEED, speed);
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GetVehicleData.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GetVehicleData.java
index e29f01be0..d2ac79454 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GetVehicleData.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GetVehicleData.java
@@ -171,6 +171,14 @@ import static com.smartdevicelink.proxy.rpc.CreateInteractionChoiceSet.KEY_CHOIC
* <td>SmartDeviceLink 2.0</td>
* </tr>
* <tr>
+ * <td>engineOilLife</td>
+ * <td>Boolean</td>
+ * <td>The estimated percentage of remaining oil life of the engine</td>
+ * <td>N</td>
+ * <td>Subscribable</td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
+ * <tr>
* <td>accPedalPosition</td>
* <td>Boolean</td>
* <td>Accelerator pedal position (percentage depressed)</td>
@@ -186,6 +194,14 @@ import static com.smartdevicelink.proxy.rpc.CreateInteractionChoiceSet.KEY_CHOIC
* <td>Subscribable</td>
* <td>SmartDeviceLink 2.0</td>
* </tr>
+ * <tr>
+ * <td>turnSignal</td>
+ * <td>Boolean</td>
+ * <td>@see TurnSignal</td>
+ * <td>N</td>
+ * <td>Subscribable</td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
* </table>
*
*
@@ -218,6 +234,7 @@ public class GetVehicleData extends RPCRequest {
public static final String KEY_PRNDL = "prndl";
public static final String KEY_TIRE_PRESSURE = "tirePressure";
public static final String KEY_ENGINE_TORQUE = "engineTorque";
+ public static final String KEY_ENGINE_OIL_LIFE = "engineOilLife";
public static final String KEY_ODOMETER = "odometer";
public static final String KEY_GPS = "gps";
public static final String KEY_FUEL_LEVEL_STATE = "fuelLevel_State";
@@ -235,6 +252,10 @@ public class GetVehicleData extends RPCRequest {
public static final String KEY_EMERGENCY_EVENT = "emergencyEvent";
public static final String KEY_CLUSTER_MODE_STATUS = "clusterModeStatus";
public static final String KEY_MY_KEY = "myKey";
+ public static final String KEY_FUEL_RANGE = "fuelRange";
+ public static final String KEY_TURN_SIGNAL = "turnSignal";
+ public static final String KEY_ELECTRONIC_PARK_BRAKE_STATUS = "electronicParkBrakeStatus";
+
/**
* Constructs a new GetVehicleData object
*/
@@ -373,6 +394,12 @@ public class GetVehicleData extends RPCRequest {
public Boolean getEngineTorque() {
return getBoolean(KEY_ENGINE_TORQUE);
}
+ public void setEngineOilLife(Boolean engineOilLife) {
+ setParameters(KEY_ENGINE_OIL_LIFE, engineOilLife);
+ }
+ public Boolean getEngineOilLife() {
+ return getBoolean(KEY_ENGINE_OIL_LIFE);
+ }
public void setAccPedalPosition(Boolean accPedalPosition) {
setParameters(KEY_ACC_PEDAL_POSITION, accPedalPosition);
}
@@ -417,5 +444,52 @@ public class GetVehicleData extends RPCRequest {
}
public Boolean getMyKey() {
return getBoolean(KEY_MY_KEY);
- }
+ }
+
+ /**
+ * Sets a boolean value. If true, gets fuelRange data
+ * @param fuelRange
+ * a boolean value
+ */
+ public void setFuelRange(Boolean fuelRange) {
+ setParameters(KEY_FUEL_RANGE, fuelRange);
+ }
+
+ /**
+ * Gets a boolean value.
+ *
+ * @return Boolean -a Boolean value.
+ *
+ */
+ public Boolean getFuelRange() {
+ return getBoolean(KEY_FUEL_RANGE);
+ }
+
+ /**
+ * Sets a boolean value. If true, subscribes turnSignal data
+ * @param turnSignal a boolean value
+ */
+ public void setTurnSignal(Boolean turnSignal) { setParameters(KEY_TURN_SIGNAL, turnSignal); }
+
+ /**
+ * Gets a boolean value. If true, means the turnSignal data has been subscribed.
+ * @return a Boolean value.
+ */
+ public Boolean getTurnSignal() { return getBoolean(KEY_TURN_SIGNAL); }
+
+ /**
+ * Sets a boolean value. If true, subscribes electronicParkBrakeStatus data
+ * @param electronicParkBrakeStatus a boolean value
+ */
+ public void setElectronicParkBrakeStatus(Boolean electronicParkBrakeStatus){
+ setParameters(KEY_ELECTRONIC_PARK_BRAKE_STATUS, electronicParkBrakeStatus);
+ }
+
+ /**
+ * Gets a boolean value. If true, means the electronicParkBrakeStatus data has been subscribed.
+ * @return a Boolean value.
+ */
+ public Boolean getElectronicParkBrakeStatus(){
+ return getBoolean(KEY_ELECTRONIC_PARK_BRAKE_STATUS);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GetVehicleDataResponse.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GetVehicleDataResponse.java
index 2a1eb0a2d..91eefc13c 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GetVehicleDataResponse.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/GetVehicleDataResponse.java
@@ -6,13 +6,16 @@ import android.support.annotation.NonNull;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCResponse;
import com.smartdevicelink.proxy.rpc.enums.ComponentVolumeStatus;
+import com.smartdevicelink.proxy.rpc.enums.ElectronicParkBrakeStatus;
import com.smartdevicelink.proxy.rpc.enums.PRNDL;
import com.smartdevicelink.proxy.rpc.enums.Result;
+import com.smartdevicelink.proxy.rpc.enums.TurnSignal;
import com.smartdevicelink.proxy.rpc.enums.VehicleDataEventStatus;
import com.smartdevicelink.proxy.rpc.enums.WiperStatus;
import com.smartdevicelink.util.SdlDataTypeConverter;
import java.util.Hashtable;
+import java.util.List;
/**
* Get Vehicle Data Response is sent, when GetVehicleData has been called.
@@ -28,6 +31,7 @@ public class GetVehicleDataResponse extends RPCResponse {
public static final String KEY_PRNDL = "prndl";
public static final String KEY_TIRE_PRESSURE = "tirePressure";
public static final String KEY_ENGINE_TORQUE = "engineTorque";
+ public static final String KEY_ENGINE_OIL_LIFE = "engineOilLife";
public static final String KEY_ODOMETER = "odometer";
public static final String KEY_GPS = "gps";
public static final String KEY_FUEL_LEVEL_STATE = "fuelLevel_State";
@@ -45,6 +49,9 @@ public class GetVehicleDataResponse extends RPCResponse {
public static final String KEY_EMERGENCY_EVENT = "emergencyEvent";
public static final String KEY_CLUSTER_MODE_STATUS = "clusterModeStatus";
public static final String KEY_MY_KEY = "myKey";
+ public static final String KEY_FUEL_RANGE = "fuelRange";
+ public static final String KEY_TURN_SIGNAL = "turnSignal";
+ public static final String KEY_ELECTRONIC_PARK_BRAKE_STATUS = "electronicParkBrakeStatus";
/**
* Constructs a new GetVehicleDataResponse object
@@ -191,8 +198,15 @@ public class GetVehicleDataResponse extends RPCResponse {
setParameters(KEY_ENGINE_TORQUE, engineTorque);
}
public Double getEngineTorque() {
- Object object = getParameters(KEY_ENGINE_TORQUE);
- return SdlDataTypeConverter.objectToDouble(object);
+ Object object = getParameters(KEY_ENGINE_TORQUE);
+ return SdlDataTypeConverter.objectToDouble(object);
+ }
+ public void setEngineOilLife(Float engineOilLife) {
+ setParameters(KEY_ENGINE_OIL_LIFE, engineOilLife);
+ }
+ public Float getEngineOilLife() {
+ Object object = getParameters(KEY_ENGINE_OIL_LIFE);
+ return SdlDataTypeConverter.objectToFloat(object);
}
public void setAccPedalPosition(Double accPedalPosition) {
@@ -247,5 +261,56 @@ public class GetVehicleDataResponse extends RPCResponse {
@SuppressWarnings("unchecked")
public MyKey getMyKey() {
return (MyKey) getObject(MyKey.class, KEY_MY_KEY);
- }
+ }
+
+ /**
+ * Sets Fuel Range List. Fuel Range - The estimate range in KM the vehicle can travel based on fuel level and consumption.
+ * @param fuelRange
+ */
+ public void setFuelRange(List<FuelRange> fuelRange) {
+ setParameters(KEY_FUEL_RANGE, fuelRange);
+ }
+
+ /**
+ * Gets Fuel Range List
+ * @return List<FuelRange>
+ * Fuel Range - The estimate range in KM the vehicle can travel based on fuel level and consumption.
+ */
+ @SuppressWarnings("unchecked")
+ public List<FuelRange> getFuelRange() {
+ return (List<FuelRange>) getObject(FuelRange.class, KEY_FUEL_RANGE);
+ }
+
+ /**
+ * Sets turnSignal
+ * @param turnSignal
+ */
+ public void setTurnSignal(TurnSignal turnSignal) {
+ setParameters(KEY_TURN_SIGNAL, turnSignal);
+ }
+
+ /**
+ * Gets turnSignal
+ * @return TurnSignal
+ */
+ @SuppressWarnings("unchecked")
+ public TurnSignal getTurnSignal() {
+ return (TurnSignal) getObject(TurnSignal.class, KEY_TURN_SIGNAL);
+ }
+
+ /**
+ * Sets electronicParkBrakeStatus
+ * @param electronicParkBrakeStatus
+ */
+ public void setElectronicParkBrakeStatus(ElectronicParkBrakeStatus electronicParkBrakeStatus){
+ setParameters(KEY_ELECTRONIC_PARK_BRAKE_STATUS, electronicParkBrakeStatus);
+ }
+
+ /**
+ * Gets electronicParkBrakeStatus
+ * @return ElectronicParkBrakeStatus
+ */
+ public ElectronicParkBrakeStatus getElectronicParkBrakeStatus(){
+ return (ElectronicParkBrakeStatus) getObject(ElectronicParkBrakeStatus.class, KEY_ELECTRONIC_PARK_BRAKE_STATUS);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/HMISettingsControlCapabilities.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/HMISettingsControlCapabilities.java
new file mode 100644
index 000000000..f5377b1b0
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/HMISettingsControlCapabilities.java
@@ -0,0 +1,107 @@
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.RPCStruct;
+
+import java.util.Hashtable;
+
+public class HMISettingsControlCapabilities extends RPCStruct {
+ public static final String KEY_MODULE_NAME = "moduleName";
+ public static final String KEY_DISTANCE_UNIT_AVAILABLE = "distanceUnitAvailable";
+ public static final String KEY_TEMPERATURE_UNIT_AVAILABLE = "temperatureUnitAvailable";
+ public static final String KEY_DISPLAY_MODE_UNIT_AVAILABLE = "displayModeUnitAvailable";
+
+ /**
+ * Constructs a new HMISettingsControlCapabilities object
+ */
+ public HMISettingsControlCapabilities() {
+ }
+
+ /**
+ * <p>Constructs a new HMISettingsControlCapabilities object indicated by the Hashtable parameter
+ * </p>
+ *
+ * @param hash The Hashtable to use
+ */
+ public HMISettingsControlCapabilities(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ public HMISettingsControlCapabilities(@NonNull String moduleName) {
+ this();
+ setModuleName(moduleName);
+ }
+
+ /**
+ * Sets the moduleName portion of the HMISettingsControlCapabilities class
+ *
+ * @param moduleName The short friendly name of the hmi setting module. It should not be used to identify a module by mobile application.
+ */
+ public void setModuleName(@NonNull String moduleName) {
+ setValue(KEY_MODULE_NAME, moduleName);
+ }
+
+ /**
+ * Gets the moduleName portion of the HMISettingsControlCapabilities class
+ *
+ * @return String - The short friendly name of the hmi setting module. It should not be used to identify a module by mobile application.
+ */
+ public String getModuleName() {
+ return getString(KEY_MODULE_NAME);
+ }
+
+ /**
+ * Sets the distanceUnitAvailable portion of the HMISettingsControlCapabilities class
+ *
+ * @param distanceUnitAvailable Availability of the control of distance unit.
+ */
+ public void setDistanceUnitAvailable(Boolean distanceUnitAvailable) {
+ setValue(KEY_DISTANCE_UNIT_AVAILABLE, distanceUnitAvailable);
+ }
+
+ /**
+ * Gets the distanceUnitAvailable portion of the HMISettingsControlCapabilities class
+ *
+ * @return Boolean - Availability of the control of distance unit.
+ */
+ public Boolean getDistanceUnitAvailable() {
+ return getBoolean(KEY_DISTANCE_UNIT_AVAILABLE);
+ }
+
+ /**
+ * Sets the temperatureUnitAvailable portion of the HMISettingsControlCapabilities class
+ *
+ * @param temperatureUnitAvailable Availability of the control of temperature unit.
+ */
+ public void setTemperatureUnitAvailable(Boolean temperatureUnitAvailable) {
+ setValue(KEY_TEMPERATURE_UNIT_AVAILABLE, temperatureUnitAvailable);
+ }
+
+ /**
+ * Gets the temperatureUnitAvailable portion of the HMISettingsControlCapabilities class
+ *
+ * @return Boolean - Availability of the control of temperature unit.
+ */
+ public Boolean getTemperatureUnitAvailable() {
+ return getBoolean(KEY_TEMPERATURE_UNIT_AVAILABLE);
+ }
+
+ /**
+ * Sets the displayModeUnitAvailable portion of the HMISettingsControlCapabilities class
+ *
+ * @param displayModeUnitAvailable Availability of the control of HMI display mode.
+ */
+ public void setDisplayModeUnitAvailable(Boolean displayModeUnitAvailable) {
+ setValue(KEY_DISPLAY_MODE_UNIT_AVAILABLE, displayModeUnitAvailable);
+ }
+
+ /**
+ * Gets the displayModeUnitAvailable portion of the HMISettingsControlCapabilities class
+ *
+ * @return Boolean - Availability of the control of HMI display mode.
+ */
+ public Boolean getDisplayModeUnitAvailable() {
+ return getBoolean(KEY_DISPLAY_MODE_UNIT_AVAILABLE);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/HMISettingsControlData.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/HMISettingsControlData.java
new file mode 100644
index 000000000..e6dc4d301
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/HMISettingsControlData.java
@@ -0,0 +1,79 @@
+package com.smartdevicelink.proxy.rpc;
+
+import com.smartdevicelink.proxy.RPCStruct;
+import com.smartdevicelink.proxy.rpc.enums.DisplayMode;
+import com.smartdevicelink.proxy.rpc.enums.DistanceUnit;
+import com.smartdevicelink.proxy.rpc.enums.TemperatureUnit;
+
+import java.util.Hashtable;
+
+/**
+ * Corresponds to "HMI_SETTINGS" ModuleType
+ */
+
+public class HMISettingsControlData extends RPCStruct {
+ public static final String KEY_DISPLAY_MODE = "displayMode";
+ public static final String KEY_TEMPERATURE_UNIT = "temperatureUnit";
+ public static final String KEY_DISTANCE_UNIT = "distanceUnit";
+
+ public HMISettingsControlData() {
+ }
+
+ public HMISettingsControlData(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Sets the displayMode portion of the HMISettingsControlData class
+ *
+ * @param displayMode
+ */
+ public void setDisplayMode(DisplayMode displayMode) {
+ setValue(KEY_DISPLAY_MODE, displayMode);
+ }
+
+ /**
+ * Gets the displayMode portion of the HMISettingsControlData class
+ *
+ * @return DisplayMode
+ */
+ public DisplayMode getDisplayMode() {
+ return (DisplayMode) getObject(DisplayMode.class, KEY_DISPLAY_MODE);
+ }
+
+ /**
+ * Sets the temperatureUnit portion of the HMISettingsControlData class
+ *
+ * @param temperatureUnit
+ */
+ public void setTemperatureUnit(TemperatureUnit temperatureUnit) {
+ setValue(KEY_TEMPERATURE_UNIT, temperatureUnit);
+ }
+
+ /**
+ * Gets the temperatureUnit portion of the HMISettingsControlData class
+ *
+ * @return TemperatureUnit
+ */
+ public TemperatureUnit getTemperatureUnit() {
+ return (TemperatureUnit) getObject(TemperatureUnit.class, KEY_TEMPERATURE_UNIT);
+ }
+
+ /**
+ * Sets the distanceUnit portion of the HMISettingsControlData class
+ *
+ * @param distanceUnit
+ */
+ public void setDistanceUnit(DistanceUnit distanceUnit) {
+ setValue(KEY_DISTANCE_UNIT, distanceUnit);
+ }
+
+ /**
+ * Gets the distanceUnit portion of the HMISettingsControlData class
+ *
+ * @return DistanceUnit
+ */
+ public DistanceUnit getDistanceUnit() {
+ return (DistanceUnit) getObject(DistanceUnit.class, KEY_DISTANCE_UNIT);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/Image.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/Image.java
index bab596543..f58664054 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/Image.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/Image.java
@@ -40,6 +40,7 @@ import java.util.Hashtable;
public class Image extends RPCStruct {
public static final String KEY_VALUE = "value";
public static final String KEY_IMAGE_TYPE = "imageType";
+ public static final String KEY_IS_TEMPLATE = "isTemplate";
/**
* Constructs a newly allocated Image object
@@ -66,7 +67,7 @@ public class Image extends RPCStruct {
}
/**
- * set either the static hex icon value or the binary image file name identifier (sent by PutFile)
+ * Set either the static hex icon value or the binary image file name identifier (sent by PutFile)
* @param value either the static hex icon value or the binary image file name identifier (sent by PutFile)
*/
public void setValue(@NonNull String value) {
@@ -74,7 +75,7 @@ public class Image extends RPCStruct {
}
/**
- * get either the static hex icon value or the binary image file name identifier (sent by PutFile)
+ * Get either the static hex icon value or the binary image file name identifier (sent by PutFile)
* @return either the static hex icon value or the binary image file name identifier (sent by PutFile)
*/
public String getValue() {
@@ -82,7 +83,7 @@ public class Image extends RPCStruct {
}
/**
- * set the image type
+ * Set the image type (static or dynamic image)
* @param imageType whether it is a static or dynamic image
*/
public void setImageType(@NonNull ImageType imageType) {
@@ -90,10 +91,26 @@ public class Image extends RPCStruct {
}
/**
- * get image type
- * @return the image type
+ * Get image type (static or dynamic image)
+ * @return the image type (static or dynamic image)
*/
public ImageType getImageType() {
return (ImageType) getObject(ImageType.class, KEY_IMAGE_TYPE);
}
+
+ /**
+ * Set whether this Image is a template image whose coloring should be decided by the HMI
+ * @param isTemplate boolean that tells whether this Image is a template image
+ */
+ public void setIsTemplate(Boolean isTemplate){
+ setValue(KEY_IS_TEMPLATE, isTemplate);
+ }
+
+ /**
+ * Get whether this Image is a template image whose coloring should be decided by the HMI
+ * @return boolean that tells whether this Image is a template image
+ */
+ public Boolean getIsTemplate(){
+ return getBoolean(KEY_IS_TEMPLATE);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightCapabilities.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightCapabilities.java
new file mode 100644
index 000000000..b23c8356c
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightCapabilities.java
@@ -0,0 +1,113 @@
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.RPCStruct;
+import com.smartdevicelink.proxy.rpc.enums.LightName;
+
+import java.util.Hashtable;
+
+public class LightCapabilities extends RPCStruct {
+
+ public static final String KEY_NAME = "name";
+ public static final String KEY_DENSITY_AVAILABLE = "densityAvailable";
+ public static final String KEY_RGB_COLOR_SPACE_AVAILABLE = "rgbColorSpaceAvailable";
+ public static final String KEY_STATUS_AVAILABLE = "statusAvailable";
+
+ /**
+ * Constructs a newly allocated LightCapabilities object
+ */
+ public LightCapabilities() {
+ }
+
+ /**
+ * Constructs a newly allocated LightCapabilities object indicated by the Hashtable parameter
+ *
+ * @param hash The Hashtable to use
+ */
+ public LightCapabilities(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Constructs a newly allocated LightCapabilities object
+ *
+ * @param name name of Light
+ */
+ public LightCapabilities(@NonNull LightName name) {
+ this();
+ setName(name);
+ }
+
+ /**
+ * Sets the name portion of the LightCapabilities class
+ *
+ * @param name
+ */
+ public void setName(@NonNull LightName name) {
+ setValue(KEY_NAME, name);
+ }
+
+ /**
+ * Gets the name portion of the LightCapabilities class
+ *
+ * @return LightName
+ */
+ public LightName getName() {
+ return (LightName) getObject(LightName.class, KEY_NAME);
+ }
+
+ /**
+ * Sets the densityAvailable portion of the LightCapabilities class
+ *
+ * @param densityAvailable Indicates if the light's density can be set remotely (similar to a dimmer).
+ */
+ public void setDensityAvailable(Boolean densityAvailable) {
+ setValue(KEY_DENSITY_AVAILABLE, densityAvailable);
+ }
+
+ /**
+ * Gets the densityAvailable portion of the LightCapabilities class
+ *
+ * @return Boolean - Indicates if the light's density can be set remotely (similar to a dimmer).
+ */
+ public Boolean getDensityAvailable() {
+ return getBoolean(KEY_DENSITY_AVAILABLE);
+ }
+
+ /**
+ * Sets the RGBColorSpaceAvailable portion of the LightCapabilities class
+ *
+ * @param RGBColorSpaceAvailable Indicates if the light's color can be set remotely by using the RGB color space.
+ */
+ public void setRGBColorSpaceAvailable(Boolean RGBColorSpaceAvailable) {
+ setValue(KEY_RGB_COLOR_SPACE_AVAILABLE, RGBColorSpaceAvailable);
+ }
+
+ /**
+ * Gets the RGBColorSpaceAvailable portion of the LightCapabilities class
+ *
+ * @return Boolean - Indicates if the light's color can be set remotely by using the RGB color space.
+ */
+ public Boolean getRGBColorSpaceAvailable() {
+ return getBoolean(KEY_RGB_COLOR_SPACE_AVAILABLE);
+ }
+
+ /**
+ * Sets the statusAvailable portion of the LightCapabilities class
+ *
+ * @param statusAvailable Indicates if the status (ON/OFF) can be set remotely. App shall not use read-only values (RAMP_UP/RAMP_DOWN/UNKNOWN/INVALID) in a setInteriorVehicleData request.
+ */
+ public void setStatusAvailable(Boolean statusAvailable) {
+ setValue(KEY_STATUS_AVAILABLE, statusAvailable);
+ }
+
+ /**
+ * Gets the statusAvailable portion of the LightCapabilities class
+ *
+ * @return Boolean - Indicates if the status (ON/OFF) can be set remotely. App shall not use read-only values (RAMP_UP/RAMP_DOWN/UNKNOWN/INVALID) in a setInteriorVehicleData request.
+ */
+ public Boolean getStatusAvailable() {
+ return getBoolean(KEY_STATUS_AVAILABLE);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightControlCapabilities.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightControlCapabilities.java
new file mode 100644
index 000000000..ab84da275
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightControlCapabilities.java
@@ -0,0 +1,78 @@
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.RPCStruct;
+
+import java.util.Hashtable;
+import java.util.List;
+
+public class LightControlCapabilities extends RPCStruct {
+ public static final String KEY_MODULE_NAME = "moduleName";
+ public static final String KEY_SUPPORTED_LIGHTS = "supportedLights";
+
+ /**
+ * Constructs a new LightControlCapabilities object
+ */
+ public LightControlCapabilities() {
+ }
+
+ /**
+ * <p>Constructs a new LightControlCapabilities object indicated by the Hashtable parameter
+ * </p>
+ *
+ * @param hash The Hashtable to use
+ */
+ public LightControlCapabilities(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Constructs a newly allocated LightControlCapabilities object
+ *
+ * @param moduleName short friendly name of the light control module.
+ * @param supportedLights An array of available LightCapabilities that are controllable.
+ */
+ public LightControlCapabilities(@NonNull String moduleName, @NonNull List<LightCapabilities> supportedLights) {
+ this();
+ setModuleName(moduleName);
+ setSupportedLights(supportedLights);
+ }
+
+ /**
+ * Sets the moduleName portion of the LightControlCapabilities class
+ *
+ * @param moduleName The short friendly name of the light control module. It should not be used to identify a module by mobile application.
+ */
+ public void setModuleName(@NonNull String moduleName) {
+ setValue(KEY_MODULE_NAME, moduleName);
+ }
+
+ /**
+ * Gets the moduleName portion of the LightControlCapabilities class
+ *
+ * @return String - The short friendly name of the light control module. It should not be used to identify a module by mobile application.
+ */
+ public String getModuleName() {
+ return getString(KEY_MODULE_NAME);
+ }
+
+ /**
+ * Gets the supportedLights portion of the LightControlCapabilities class
+ *
+ * @return List<LightCapabilities> - An array of available LightCapabilities that are controllable.
+ */
+ @SuppressWarnings("unchecked")
+ public List<LightCapabilities> getSupportedLights() {
+ return (List<LightCapabilities>) getObject(LightCapabilities.class, KEY_SUPPORTED_LIGHTS);
+ }
+
+ /**
+ * Sets the supportedLights portion of the LightControlCapabilities class
+ *
+ * @param supportedLights An array of available LightCapabilities that are controllable.
+ */
+ public void setSupportedLights(@NonNull List<LightCapabilities> supportedLights) {
+ setValue(KEY_SUPPORTED_LIGHTS, supportedLights);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightControlData.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightControlData.java
new file mode 100644
index 000000000..a78b979c5
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightControlData.java
@@ -0,0 +1,58 @@
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.RPCStruct;
+
+import java.util.Hashtable;
+import java.util.List;
+
+public class LightControlData extends RPCStruct {
+ public static final String KEY_LIGHT_STATE = "lightState";
+
+ /**
+ * Constructs a new LightControlData object
+ */
+ public LightControlData() {
+ }
+
+ /**
+ * <p>Constructs a new LightControlData object indicated by the Hashtable parameter
+ * </p>
+ *
+ * @param hash The Hashtable to use
+ */
+ public LightControlData(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Constructs a newly allocated LightControlData object
+ *
+ * @param lightState An array of LightNames and their current or desired status.
+ * Status of the LightNames that are not listed in the array shall remain unchanged.
+ */
+ public LightControlData(@NonNull List<LightState> lightState) {
+ this();
+ setLightState(lightState);
+ }
+
+ /**
+ * Gets the lightState portion of the LightControlData class
+ *
+ * @return List<LightState> - An array of LightNames and their current or desired status. Status of the LightNames that are not listed in the array shall remain unchanged.
+ */
+ @SuppressWarnings("unchecked")
+ public List<LightState> getLightState() {
+ return (List<LightState>) getObject(LightState.class, KEY_LIGHT_STATE);
+ }
+
+ /**
+ * Sets the lightState portion of the LightControlData class
+ *
+ * @param lightState An array of LightNames and their current or desired status. Status of the LightNames that are not listed in the array shall remain unchanged.
+ */
+ public void setLightState(@NonNull List<LightState> lightState) {
+ setValue(KEY_LIGHT_STATE, lightState);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightState.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightState.java
new file mode 100644
index 000000000..90315f785
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/LightState.java
@@ -0,0 +1,119 @@
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.RPCStruct;
+import com.smartdevicelink.proxy.rpc.enums.LightName;
+import com.smartdevicelink.proxy.rpc.enums.LightStatus;
+import com.smartdevicelink.util.SdlDataTypeConverter;
+
+import java.util.Hashtable;
+
+public class LightState extends RPCStruct {
+ public static final String KEY_ID = "id";
+ public static final String KEY_STATUS = "status";
+ public static final String KEY_DENSITY = "density";
+ public static final String KEY_COLOR = "color";
+
+ /**
+ * Constructs a new LightState object
+ */
+ public LightState() {
+ }
+
+ /**
+ * <p>Constructs a new LightState object indicated by the Hashtable parameter
+ * </p>
+ *
+ * @param hash The Hashtable to use
+ */
+ public LightState(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Constructs a newly allocated LightState object
+ *
+ * @param id The name of a light or a group of lights.
+ * @param status Status of Light.
+ */
+ public LightState(@NonNull LightName id, @NonNull LightStatus status) {
+ this();
+ setId(id);
+ setStatus(status);
+ }
+
+ /**
+ * Sets the id portion of the LightState class
+ *
+ * @param id The name of a light or a group of lights.
+ */
+ public void setId(@NonNull LightName id) {
+ setValue(KEY_ID, id);
+ }
+
+ /**
+ * Gets the id portion of the LightState class
+ *
+ * @return LightName - The name of a light or a group of lights.
+ */
+ public LightName getId() {
+ return (LightName) getObject(LightName.class, KEY_ID);
+ }
+
+ /**
+ * Sets the status portion of the LightState class
+ *
+ * @param status
+ */
+ public void setStatus(@NonNull LightStatus status) {
+ setValue(KEY_STATUS, status);
+ }
+
+ /**
+ * Gets the status portion of the LightState class
+ *
+ * @return LightStatus
+ */
+ public LightStatus getStatus() {
+ return (LightStatus) getObject(LightStatus.class, KEY_STATUS);
+ }
+
+ /**
+ * Gets the density portion of the LightState class
+ *
+ * @return Float
+ */
+ public Float getDensity() {
+ Object value = getValue(KEY_DENSITY);
+ return SdlDataTypeConverter.objectToFloat(value);
+ }
+
+ /**
+ * Sets the density portion of the LightState class
+ *
+ * @param density
+ */
+ public void setDensity(Float density) {
+ setValue(KEY_DENSITY, density);
+ }
+
+ /**
+ * Gets the color portion of the LightState class
+ *
+ * @return RGBColor
+ */
+ @SuppressWarnings("unchecked")
+ public RGBColor getColor() {
+ return (RGBColor) getObject(RGBColor.class, KEY_COLOR);
+ }
+
+ /**
+ * Sets the color portion of the LightState class
+ *
+ * @param color
+ */
+ public void setColor(RGBColor color) {
+ setValue(KEY_COLOR, color);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ListFilesResponse.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ListFilesResponse.java
index 550eef9d8..b525bc599 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ListFilesResponse.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ListFilesResponse.java
@@ -5,6 +5,7 @@ import android.support.annotation.NonNull;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCResponse;
import com.smartdevicelink.proxy.rpc.enums.Result;
+import com.smartdevicelink.util.Version;
import java.util.Hashtable;
import java.util.List;
@@ -17,6 +18,7 @@ import java.util.List;
public class ListFilesResponse extends RPCResponse {
public static final String KEY_FILENAMES = "filenames";
public static final String KEY_SPACE_AVAILABLE = "spaceAvailable";
+ private static final Integer MAX_VALUE = 2000000000;
/**
* Constructs a new ListFilesResponse object
@@ -27,27 +29,65 @@ public class ListFilesResponse extends RPCResponse {
public ListFilesResponse(Hashtable<String, Object> hash) {
super(hash);
}
+
/**
+ * @deprecated use {@link ListFilesResponse#ListFilesResponse(Boolean, Result)} instead <br>
+ *
* Constructs a new ListFilesResponse object
* @param success whether the request is successfully processed
* @param resultCode whether the request is successfully processed
*/
+ @Deprecated
public ListFilesResponse(@NonNull Boolean success, @NonNull Result resultCode, @NonNull Integer spaceAvailable) {
this();
setSuccess(success);
setResultCode(resultCode);
setSpaceAvailable(spaceAvailable);
}
+
+ /**
+ * Constructs a new ListFilesResponse object
+ * @param success whether the request is successfully processed
+ * @param resultCode whether the request is successfully processed
+ */
+ public ListFilesResponse(@NonNull Boolean success, @NonNull Result resultCode) {
+ this();
+ setSuccess(success);
+ setResultCode(resultCode);
+ }
+
+ /**
+ * SpaceAvailable became optional as of RPC Spec 5.0. If a system that expected the value to
+ * always have a value connects to such a system, it could return null. Check to see if there
+ * is a value, and if not, set it to MAX_VALUE as defined by the RPC Spec
+ *
+ * @param rpcVersion the rpc spec version that has been negotiated. If value is null the
+ * the max value of RPC spec version this library supports should be used.
+ * @param formatParams if true, the format method will be called on subsequent params
+ */
+ @Override
+ public void format(Version rpcVersion, boolean formatParams){
+ if (rpcVersion == null || rpcVersion.getMajor() >= 5){
+ if (getSpaceAvailable() == null){
+ setSpaceAvailable(MAX_VALUE);
+ }
+ }
+ super.format(rpcVersion, formatParams);
+ }
+
public void setFilenames(List<String> filenames) {
setParameters(KEY_FILENAMES, filenames);
}
+
@SuppressWarnings("unchecked")
public List<String> getFilenames() {
return (List<String>) getObject(String.class, KEY_FILENAMES);
}
- public void setSpaceAvailable(@NonNull Integer spaceAvailable) {
+
+ public void setSpaceAvailable(Integer spaceAvailable) {
setParameters(KEY_SPACE_AVAILABLE, spaceAvailable);
}
+
public Integer getSpaceAvailable() {
return getInteger(KEY_SPACE_AVAILABLE);
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/MassageCushionFirmness.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/MassageCushionFirmness.java
new file mode 100644
index 000000000..8e87eff7d
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/MassageCushionFirmness.java
@@ -0,0 +1,79 @@
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.RPCStruct;
+import com.smartdevicelink.proxy.rpc.enums.MassageCushion;
+
+import java.util.Hashtable;
+
+/**
+ * The intensity or firmness of a cushion.
+ */
+public class MassageCushionFirmness extends RPCStruct {
+ public static final String KEY_CUSHION = "cushion";
+ public static final String KEY_FIRMNESS = "firmness";
+
+ /**
+ * Constructs a new MassageCushionFirmness object
+ */
+ public MassageCushionFirmness() {
+ }
+
+ /**
+ * <p>Constructs a new MassageCushionFirmness object indicated by the Hashtable parameter
+ * </p>
+ *
+ * @param hash The Hashtable to use
+ */
+ public MassageCushionFirmness(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Constructs a newly allocated MassageCushionFirmness object
+ * @param cushion type of MassageCushion for multi-contour massage seat
+ * @param firmness Min: 0 Max: 100
+ */
+ public MassageCushionFirmness(@NonNull MassageCushion cushion, @NonNull Integer firmness) {
+ this();
+ setCushion(cushion);
+ setFirmness(firmness);
+ }
+
+ /**
+ * Sets the cushion portion of the MassageCushionFirmness class
+ *
+ * @param cushion
+ */
+ public void setCushion(@NonNull MassageCushion cushion) {
+ setValue(KEY_CUSHION, cushion);
+ }
+
+ /**
+ * Gets the cushion portion of the MassageCushionFirmness class
+ *
+ * @return MassageCushion.
+ */
+ public MassageCushion getCushion() {
+ return (MassageCushion) getObject(MassageCushion.class, KEY_CUSHION);
+ }
+
+ /**
+ * Sets the firmness portion of the MassageCushionFirmness class
+ *
+ * @param firmness
+ */
+ public void setFirmness(@NonNull Integer firmness) {
+ setValue(KEY_FIRMNESS, firmness);
+ }
+
+ /**
+ * Gets the firmness portion of the MassageCushionFirmness class
+ *
+ * @return Integer
+ */
+ public Integer getFirmness() {
+ return getInteger(KEY_FIRMNESS);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/MassageModeData.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/MassageModeData.java
new file mode 100644
index 000000000..857d4dc7c
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/MassageModeData.java
@@ -0,0 +1,80 @@
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.RPCStruct;
+import com.smartdevicelink.proxy.rpc.enums.MassageMode;
+import com.smartdevicelink.proxy.rpc.enums.MassageZone;
+
+import java.util.Hashtable;
+
+/**
+ * Specify the mode of a massage zone.
+ */
+public class MassageModeData extends RPCStruct {
+ public static final String KEY_MASSAGE_ZONE = "massageZone";
+ public static final String KEY_MASSAGE_MODE = "massageMode";
+
+ /**
+ * Constructs a new MassageModeData object
+ */
+ public MassageModeData() {
+ }
+
+ /**
+ * <p>Constructs a new MassageModeData object indicated by the Hashtable parameter
+ * </p>
+ *
+ * @param hash The Hashtable to use
+ */
+ public MassageModeData(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Constructs a newly allocated MassageModeData object
+ * @param massageZone type of MassageZone for multi-contour massage seat
+ * @param massageMode mode of massage zone.
+ */
+ public MassageModeData(@NonNull MassageZone massageZone, @NonNull MassageMode massageMode) {
+ this();
+ setMassageZone(massageZone);
+ setMassageMode(massageMode);
+ }
+
+ /**
+ * Sets the massageZone portion of the MassageModeData class
+ *
+ * @param massageZone
+ */
+ public void setMassageZone(@NonNull MassageZone massageZone) {
+ setValue(KEY_MASSAGE_ZONE, massageZone);
+ }
+
+ /**
+ * Gets the massageZone portion of the MassageModeData class
+ *
+ * @return MassageZone.
+ */
+ public MassageZone getMassageZone() {
+ return (MassageZone) getObject(MassageZone.class, KEY_MASSAGE_ZONE);
+ }
+
+ /**
+ * Gets the massageMode portion of the MassageModeData class
+ *
+ * @return MassageMode
+ */
+ public MassageMode getMassageMode() {
+ return (MassageMode) getObject(MassageMode.class, KEY_MASSAGE_MODE);
+ }
+
+ /**
+ * Sets the massageMode portion of the MassageModeData class
+ *
+ * @param massageMode
+ */
+ public void setMassageMode(@NonNull MassageMode massageMode) {
+ setValue(KEY_MASSAGE_MODE, massageMode);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ModuleData.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ModuleData.java
index 9ae3f7fd3..85a24c064 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ModuleData.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/ModuleData.java
@@ -4,81 +4,155 @@ import android.support.annotation.NonNull;
import com.smartdevicelink.proxy.RPCStruct;
import com.smartdevicelink.proxy.rpc.enums.ModuleType;
-import com.smartdevicelink.proxy.rpc.enums.Result;
import java.util.Hashtable;
-public class ModuleData extends RPCStruct{
- public static final String KEY_MODULE_TYPE= "moduleType";
- public static final String KEY_RADIO_CONTROL_DATA = "radioControlData";
- public static final String KEY_CLIMATE_CONTROL_DATA = "climateControlData";
-
- public ModuleData() {
- }
-
- public ModuleData(Hashtable<String, Object> hash) {
- super(hash);
- }
-
- public ModuleData(@NonNull ModuleType moduleType) {
- this();
- setModuleType(moduleType);
- }
-
- /**
- * Sets the moduleType portion of the ModuleData class
- *
- * @param moduleType
- * The moduleType indicates which type of data should be changed and identifies which data object exists in this struct.
- * For example, if the moduleType is CLIMATE then a "climateControlData" should exist
- */
- public void setModuleType(@NonNull ModuleType moduleType) {
- setValue(KEY_MODULE_TYPE, moduleType);
- }
-
- /**
- * Gets the moduleType portion of the ModuleData class
- *
- * @return ModuleType - The moduleType indicates which type of data should be changed and identifies which data object exists in this struct.
- * For example, if the moduleType is CLIMATE then a "climateControlData" should exist.
- */
- public ModuleType getModuleType() {
- return (ModuleType) getObject(ModuleType.class, KEY_MODULE_TYPE);
- }
-
- /**
- * Sets the radioControlData portion of the ModuleData class
- *
- * @param radioControlData
- */
- public void setRadioControlData(RadioControlData radioControlData) {
- setValue(KEY_RADIO_CONTROL_DATA, radioControlData);
- }
-
- /**
- * Gets the radioControlData portion of the ModuleData class
- *
- * @return RadioControlData
- */
- public RadioControlData getRadioControlData() {
- return (RadioControlData) getObject(RadioControlData.class, KEY_RADIO_CONTROL_DATA);
- }
-
- /**
- * Sets the climateControlData portion of the ModuleData class
- *
- * @param climateControlData
- */
- public void setClimateControlData(ClimateControlData climateControlData) {
- setValue(KEY_CLIMATE_CONTROL_DATA, climateControlData);
- }
-
- /**
- * Gets the climateControlData portion of the ModuleData class
- *
- * @return ClimateControlData
- */
- public ClimateControlData getClimateControlData() {
- return (ClimateControlData) getObject(ClimateControlData.class, KEY_CLIMATE_CONTROL_DATA);
- }
+public class ModuleData extends RPCStruct {
+ public static final String KEY_MODULE_TYPE = "moduleType";
+ public static final String KEY_RADIO_CONTROL_DATA = "radioControlData";
+ public static final String KEY_CLIMATE_CONTROL_DATA = "climateControlData";
+ public static final String KEY_SEAT_CONTROL_DATA = "seatControlData";
+ public static final String KEY_AUDIO_CONTROL_DATA = "audioControlData";
+ public static final String KEY_LIGHT_CONTROL_DATA = "lightControlData";
+ public static final String KEY_HMI_SETTINGS_CONTROL_DATA = "hmiSettingsControlData";
+
+ public ModuleData() {
+ }
+
+ public ModuleData(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ public ModuleData(@NonNull ModuleType moduleType) {
+ this();
+ setModuleType(moduleType);
+ }
+
+ /**
+ * Sets the moduleType portion of the ModuleData class
+ *
+ * @param moduleType The moduleType indicates which type of data should be changed and identifies which data object exists in this struct.
+ * For example, if the moduleType is CLIMATE then a "climateControlData" should exist
+ */
+ public void setModuleType(@NonNull ModuleType moduleType) {
+ setValue(KEY_MODULE_TYPE, moduleType);
+ }
+
+ /**
+ * Gets the moduleType portion of the ModuleData class
+ *
+ * @return ModuleType - The moduleType indicates which type of data should be changed and identifies which data object exists in this struct.
+ * For example, if the moduleType is CLIMATE then a "climateControlData" should exist.
+ */
+ public ModuleType getModuleType() {
+ return (ModuleType) getObject(ModuleType.class, KEY_MODULE_TYPE);
+ }
+
+ /**
+ * Sets the radioControlData portion of the ModuleData class
+ *
+ * @param radioControlData
+ */
+ public void setRadioControlData(RadioControlData radioControlData) {
+ setValue(KEY_RADIO_CONTROL_DATA, radioControlData);
+ }
+
+ /**
+ * Gets the radioControlData portion of the ModuleData class
+ *
+ * @return RadioControlData
+ */
+ public RadioControlData getRadioControlData() {
+ return (RadioControlData) getObject(RadioControlData.class, KEY_RADIO_CONTROL_DATA);
+ }
+
+ /**
+ * Sets the climateControlData portion of the ModuleData class
+ *
+ * @param climateControlData
+ */
+ public void setClimateControlData(ClimateControlData climateControlData) {
+ setValue(KEY_CLIMATE_CONTROL_DATA, climateControlData);
+ }
+
+ /**
+ * Gets the climateControlData portion of the ModuleData class
+ *
+ * @return ClimateControlData
+ */
+ public ClimateControlData getClimateControlData() {
+ return (ClimateControlData) getObject(ClimateControlData.class, KEY_CLIMATE_CONTROL_DATA);
+ }
+
+ /**
+ * Sets the seatControlData portion of the ModuleData class
+ *
+ * @param seatControlData
+ */
+ public void setSeatControlData(SeatControlData seatControlData) {
+ setValue(KEY_SEAT_CONTROL_DATA, seatControlData);
+ }
+
+ /**
+ * Gets the seatControlData portion of the ModuleData class
+ *
+ * @return SeatControlData
+ */
+ public SeatControlData getSeatControlData() {
+ return (SeatControlData) getObject(SeatControlData.class, KEY_SEAT_CONTROL_DATA);
+ }
+
+ /**
+ * Sets the audioControlData portion of the ModuleData class
+ *
+ * @param audioControlData
+ */
+ public void setAudioControlData(AudioControlData audioControlData) {
+ setValue(KEY_AUDIO_CONTROL_DATA, audioControlData);
+ }
+
+ /**
+ * Gets the audioControlData portion of the ModuleData class
+ *
+ * @return AudioControlData
+ */
+ public AudioControlData getAudioControlData() {
+ return (AudioControlData) getObject(AudioControlData.class, KEY_AUDIO_CONTROL_DATA);
+ }
+
+ /**
+ * Sets the lightControlData portion of the ModuleData class
+ *
+ * @param lightControlData
+ */
+ public void setLightControlData(LightControlData lightControlData) {
+ setValue(KEY_LIGHT_CONTROL_DATA, lightControlData);
+ }
+
+ /**
+ * Gets the lightControlData portion of the ModuleData class
+ *
+ * @return LightControlData
+ */
+ public LightControlData getLightControlData() {
+ return (LightControlData) getObject(LightControlData.class, KEY_LIGHT_CONTROL_DATA);
+ }
+
+ /**
+ * Sets the hmiSettingsControlData portion of the ModuleData class
+ *
+ * @param hmiSettingsControlData
+ */
+ public void setHmiSettingsControlData(HMISettingsControlData hmiSettingsControlData) {
+ setValue(KEY_HMI_SETTINGS_CONTROL_DATA, hmiSettingsControlData);
+ }
+
+ /**
+ * Gets the hmiSettingsControlData portion of the ModuleData class
+ *
+ * @return HMISettingsControlData
+ */
+ public HMISettingsControlData getHmiSettingsControlData() {
+ return (HMISettingsControlData) getObject(HMISettingsControlData.class, KEY_HMI_SETTINGS_CONTROL_DATA);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnHMIStatus.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnHMIStatus.java
index 505549014..6c79eeb5d 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnHMIStatus.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnHMIStatus.java
@@ -7,6 +7,7 @@ import com.smartdevicelink.proxy.RPCNotification;
import com.smartdevicelink.proxy.rpc.enums.AudioStreamingState;
import com.smartdevicelink.proxy.rpc.enums.HMILevel;
import com.smartdevicelink.proxy.rpc.enums.SystemContext;
+import com.smartdevicelink.proxy.rpc.enums.VideoStreamingState;
import java.util.Hashtable;
@@ -53,6 +54,12 @@ import java.util.Hashtable;
* <td>SmartDeviceLink 1.0</td>
* </tr>
* <tr>
+ * <td>videoStreamingState</td>
+ * <td>{@linkplain VideoStreamingState}</td>
+ * <td>If it is NOT_STREAMABLE, the app must stop streaming video to SDL Core(stop service).</td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
+ * <tr>
* <td>systemContext</td>
* <td>{@linkplain SystemContext}</td>
* <td>Indicates that a user-initiated interaction is in-progress
@@ -65,7 +72,8 @@ import java.util.Hashtable;
* @see RegisterAppInterface
*/
public class OnHMIStatus extends RPCNotification {
- public static final String KEY_AUDIO_STREAMING_STATE = "audioStreamingState";
+ public static final String KEY_AUDIO_STREAMING_STATE = "audioStreamingState";
+ public static final String KEY_VIDEO_STREAMING_STATE = "videoStreamingState";
public static final String KEY_SYSTEM_CONTEXT = "systemContext";
public static final String KEY_HMI_LEVEL = "hmiLevel";
@@ -96,6 +104,18 @@ public class OnHMIStatus extends RPCNotification {
setAudioStreamingState(audioStreamingState);
setSystemContext(systemContext);
}
+
+ @Override
+ public void format(com.smartdevicelink.util.Version rpcVersion, boolean formatParams){
+ if(rpcVersion.getMajor() < 5){
+ if(getVideoStreamingState() == null){
+ setVideoStreamingState(VideoStreamingState.STREAMABLE);
+ }
+ }
+
+ super.format(rpcVersion,formatParams);
+ }
+
/**
* <p>Get HMILevel in effect for the application</p>
* @return {@linkplain HMILevel} the current HMI Level in effect for the application
@@ -113,7 +133,7 @@ public class OnHMIStatus extends RPCNotification {
/**
* <p>Get current state of audio streaming for the application</p>
* @return {@linkplain AudioStreamingState} Returns current state of audio streaming for the application
- */
+ */
public AudioStreamingState getAudioStreamingState() {
return (AudioStreamingState) getObject(AudioStreamingState.class, KEY_AUDIO_STREAMING_STATE);
}
@@ -121,10 +141,24 @@ public class OnHMIStatus extends RPCNotification {
* <p>Set the audio streaming state</p>
* @param audioStreamingState the state of audio streaming of the application
*/
- public void setAudioStreamingState( @NonNull AudioStreamingState audioStreamingState ) {
+ public void setAudioStreamingState(@NonNull AudioStreamingState audioStreamingState ) {
setParameters(KEY_AUDIO_STREAMING_STATE, audioStreamingState);
}
/**
+ * <p>Get current state of video streaming for the application</p>
+ * @return {@linkplain VideoStreamingState} Returns current state of video streaming for the application
+ */
+ public VideoStreamingState getVideoStreamingState() {
+ return (VideoStreamingState) getObject(VideoStreamingState.class, KEY_VIDEO_STREAMING_STATE);
+ }
+ /**
+ * <p>Set the video streaming state</p>
+ * @param videoStreamingState the state of video streaming of the application
+ */
+ public void setVideoStreamingState( VideoStreamingState videoStreamingState ) {
+ setParameters(KEY_VIDEO_STREAMING_STATE, videoStreamingState);
+ }
+ /**
* <p>Get the System Context</p>
* @return {@linkplain SystemContext} whether a user-initiated interaction is in-progress (VRSESSION or MENU), or not (MAIN).
*/
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnRCStatus.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnRCStatus.java
new file mode 100644
index 000000000..8be1e0007
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnRCStatus.java
@@ -0,0 +1,69 @@
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.protocol.enums.FunctionID;
+import com.smartdevicelink.proxy.RPCNotification;
+
+import java.util.Hashtable;
+import java.util.List;
+
+public class OnRCStatus extends RPCNotification {
+ public static final String KEY_ALLOCATED_MODULES = "allocatedModules";
+ public static final String KEY_FREE_MODULES = "freeModules";
+ public static final String KEY_ALLOWED = "allowed";
+
+ /**
+ * Constructs a new OnRCStatus object
+ */
+ public OnRCStatus() {
+ super(FunctionID.ON_RC_STATUS.toString());
+ }
+
+ /**
+ * Constructs a new OnRCStatus object indicated by the Hashtable
+ * parameter
+ * @param hash The Hashtable to use
+ */
+ public OnRCStatus(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Constructs a newly allocated OnRCStatus object
+ *
+ * @param allocatedModules Contains a list (zero or more) of module types that are allocated to the application.
+ * @param freeModules Contains a list (zero or more) of module types that are free to access for the application.
+ */
+ public OnRCStatus(@NonNull List<ModuleData> allocatedModules, @NonNull List<ModuleData> freeModules) {
+ this();
+ setAllocatedModules(allocatedModules);
+ setFreeModules(freeModules);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<ModuleData> getAllocatedModules() {
+ return (List<ModuleData>) getObject(ModuleData.class, KEY_ALLOCATED_MODULES);
+ }
+
+ public void setAllocatedModules(@NonNull List<ModuleData> allocatedModules) {
+ setParameters(KEY_ALLOCATED_MODULES, allocatedModules);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<ModuleData> getFreeModules() {
+ return (List<ModuleData>) getObject(ModuleData.class, KEY_FREE_MODULES);
+ }
+
+ public void setFreeModules(@NonNull List<ModuleData> freeModules) {
+ setParameters(KEY_FREE_MODULES, freeModules);
+ }
+
+ public Boolean getAllowed() {
+ return getBoolean(KEY_ALLOWED);
+ }
+
+ public void setAllowed(Boolean allowed) {
+ setParameters(KEY_ALLOWED, allowed);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnSystemRequest.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnSystemRequest.java
index a178b581f..9654d8c2a 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnSystemRequest.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnSystemRequest.java
@@ -37,6 +37,15 @@ import java.util.List;
* <td></td>
* <td>SmartDeviceLink 2.3.2 </td>
* </tr>
+ * </tr>
+ * <tr>
+ * <td>requestSubType</td>
+ * <td>String</td>
+ * <td>This parameter is filled for supporting OEM proprietary data exchanges.</td>
+ * <td>N</td>
+ * <td>Max Length: 255</td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
* <tr>
* <td>url</td>
* <td>Array of Strings</td>
@@ -89,6 +98,7 @@ public class OnSystemRequest extends RPCNotification {
public static final String KEY_BODY = "body";
public static final String KEY_FILE_TYPE = "fileType";
public static final String KEY_REQUEST_TYPE = "requestType";
+ public static final String KEY_REQUEST_SUB_TYPE = "requestSubType";
public static final String KEY_DATA = "data";
public static final String KEY_OFFSET = "offset";
public static final String KEY_LENGTH = "length";
@@ -225,7 +235,7 @@ public class OnSystemRequest extends RPCNotification {
public Headers getHeader() {
return this.headers;
}
-
+
public RequestType getRequestType() {
return (RequestType) getObject(RequestType.class, KEY_REQUEST_TYPE);
}
@@ -234,6 +244,14 @@ public class OnSystemRequest extends RPCNotification {
setParameters(KEY_REQUEST_TYPE, requestType);
}
+ public String getRequestSubType() {
+ return getString(KEY_REQUEST_SUB_TYPE);
+ }
+
+ public void setRequestSubType(String requestSubType) {
+ setParameters(KEY_REQUEST_SUB_TYPE, requestSubType);
+ }
+
public String getUrl() {
Object o = getParameters(KEY_URL);
if (o == null)
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnVehicleData.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnVehicleData.java
index 32dba7500..42bf02305 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnVehicleData.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/OnVehicleData.java
@@ -1,11 +1,14 @@
package com.smartdevicelink.proxy.rpc;
import java.util.Hashtable;
+import java.util.List;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCNotification;
import com.smartdevicelink.proxy.rpc.enums.ComponentVolumeStatus;
+import com.smartdevicelink.proxy.rpc.enums.ElectronicParkBrakeStatus;
import com.smartdevicelink.proxy.rpc.enums.PRNDL;
+import com.smartdevicelink.proxy.rpc.enums.TurnSignal;
import com.smartdevicelink.proxy.rpc.enums.VehicleDataEventStatus;
import com.smartdevicelink.proxy.rpc.enums.WiperStatus;
import com.smartdevicelink.util.DebugTool;
@@ -222,6 +225,14 @@ import static com.smartdevicelink.proxy.constants.Names.timeout;
* <td>SmartDeviceLink 2.0</td>
* </tr>
* <tr>
+ * <td>engineOilLife</td>
+ * <td>Float</td>
+ * <td>The estimated percentage of remaining oil life of the engine</td>
+ * <td>N</td>
+ * <td>minvalue:0; maxvalue:100</td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
+ * <tr>
* <td>accPedalPosition</td>
* <td>Float</td>
* <td>Accelerator pedal position (percentage depressed)</td>
@@ -255,6 +266,7 @@ public class OnVehicleData extends RPCNotification {
public static final String KEY_PRNDL = "prndl";
public static final String KEY_TIRE_PRESSURE = "tirePressure";
public static final String KEY_ENGINE_TORQUE = "engineTorque";
+ public static final String KEY_ENGINE_OIL_LIFE = "engineOilLife";
public static final String KEY_ODOMETER = "odometer";
public static final String KEY_GPS = "gps";
public static final String KEY_FUEL_LEVEL_STATE = "fuelLevel_State";
@@ -272,6 +284,9 @@ public class OnVehicleData extends RPCNotification {
public static final String KEY_EMERGENCY_EVENT = "emergencyEvent";
public static final String KEY_CLUSTER_MODE_STATUS = "clusterModeStatus";
public static final String KEY_MY_KEY = "myKey";
+ public static final String KEY_FUEL_RANGE = "fuelRange";
+ public static final String KEY_TURN_SIGNAL = "turnSignal";
+ public static final String KEY_ELECTRONIC_PARK_BRAKE_STATUS = "electronicParkBrakeStatus";
public OnVehicleData() {
super(FunctionID.ON_VEHICLE_DATA.toString());
@@ -403,8 +418,15 @@ public class OnVehicleData extends RPCNotification {
setParameters(KEY_ENGINE_TORQUE, engineTorque);
}
public Double getEngineTorque() {
- Object object = getParameters(KEY_ENGINE_TORQUE);
- return SdlDataTypeConverter.objectToDouble(object);
+ Object object = getParameters(KEY_ENGINE_TORQUE);
+ return SdlDataTypeConverter.objectToDouble(object);
+ }
+ public void setEngineOilLife(Float engineOilLife) {
+ setParameters(KEY_ENGINE_OIL_LIFE, engineOilLife);
+ }
+ public Float getEngineOilLife() {
+ Object object = getParameters(KEY_ENGINE_OIL_LIFE);
+ return SdlDataTypeConverter.objectToFloat(object);
}
public void setAccPedalPosition(Double accPedalPosition) {
setParameters(KEY_ACC_PEDAL_POSITION, accPedalPosition);
@@ -454,5 +476,56 @@ public class OnVehicleData extends RPCNotification {
@SuppressWarnings("unchecked")
public MyKey getMyKey() {
return (MyKey) getObject(MyKey.class, KEY_MY_KEY);
- }
+ }
+
+ /**
+ * Sets Fuel Range List. Fuel Range - The estimate range in KM the vehicle can travel based on fuel level and consumption.
+ * @param fuelRange
+ */
+ public void setFuelRange(List<FuelRange> fuelRange) {
+ setParameters(KEY_FUEL_RANGE, fuelRange);
+ }
+
+ /**
+ * Gets Fuel Range List.
+ * @return List<FuelRange>
+ * Fuel Range - The estimate range in KM the vehicle can travel based on fuel level and consumption.
+ */
+ @SuppressWarnings("unchecked")
+ public List<FuelRange> getFuelRange() {
+ return (List<FuelRange>) getObject(FuelRange.class, KEY_FUEL_RANGE);
+ }
+
+ /**
+ * Sets turnSignal
+ * @param turnSignal
+ */
+ public void setTurnSignal(TurnSignal turnSignal) {
+ setParameters(KEY_TURN_SIGNAL, turnSignal);
+ }
+
+ /**
+ * Gets turnSignal
+ * @return TurnSignal
+ */
+ @SuppressWarnings("unchecked")
+ public TurnSignal getTurnSignal() {
+ return (TurnSignal) getObject(TurnSignal.class, KEY_TURN_SIGNAL);
+ }
+
+ /**
+ * Sets electronicParkBrakeStatus
+ * @param electronicParkBrakeStatus
+ */
+ public void setElectronicParkBrakeStatus(ElectronicParkBrakeStatus electronicParkBrakeStatus){
+ setParameters(KEY_ELECTRONIC_PARK_BRAKE_STATUS, electronicParkBrakeStatus);
+ }
+
+ /**
+ * Gets electronicParkBrakeStatus
+ * @return ElectronicParkBrakeStatus
+ */
+ public ElectronicParkBrakeStatus getElectronicParkBrakeStatus(){
+ return (ElectronicParkBrakeStatus) getObject(ElectronicParkBrakeStatus.class, KEY_ELECTRONIC_PARK_BRAKE_STATUS);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/PutFile.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/PutFile.java
index 0b13f0a1d..2d9010600 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/PutFile.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/PutFile.java
@@ -9,6 +9,7 @@ import com.smartdevicelink.proxy.rpc.listeners.OnPutFileUpdateListener;
import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener;
import java.util.Hashtable;
+import java.util.zip.CRC32;
/**
* Used to push a binary data onto the SDL module from a mobile device, such as
@@ -73,6 +74,14 @@ import java.util.Hashtable;
* <td>Minvalue=0; Maxvalue=100000000000</td>
* <td>SmartDeviceLink 2.3.2</td>
* </tr>
+ * <tr>
+ * <td>crc</td>
+ * <td>Long</td>
+ * <td>Additional CRC32 checksum to protect data integrity up to 512 Mbits .</td>
+ * <td>N</td>
+ * <td>minvalue="0" maxvalue="4294967295"</td>
+ * <td>SmartDeviceLink 2.3.2</td>
+ * </tr>
* </table>
* <p> <b>Note: </b></p>
* When using PutFiles you may want to check for memory
@@ -119,7 +128,7 @@ public class PutFile extends RPCRequest {
public static final String KEY_SDL_FILE_NAME = "syncFileName";
public static final String KEY_OFFSET = "offset";
public static final String KEY_LENGTH = "length";
-
+ public static final String KEY_CRC = "crc";
/**
* Constructs a new PutFile object
@@ -297,16 +306,61 @@ public class PutFile extends RPCRequest {
return null;
}
+ /**
+ * This takes the file data as an array of bytes and calculates the
+ * CRC32 for it.
+ * @param fileData - the file as a byte array
+ */
+ public void setCRC(byte[] fileData) {
+ if (fileData != null) {
+ CRC32 crc = new CRC32();
+ crc.update(fileData);
+ parameters.put(KEY_CRC, crc.getValue());
+ } else {
+ parameters.remove(KEY_CRC);
+ }
+ }
+
+ /**
+ * This assumes you have created your own CRC32 and are setting it with the file
+ * <STRONG>Please avoid using your own calculations for this, and use the method
+ * included in java.util</STRONG>
+ * @param crc - the CRC32 of the file being set
+ */
+ public void setCRC(Long crc) {
+ if (crc != null) {
+ parameters.put(KEY_CRC, crc);
+ } else {
+ parameters.remove(KEY_CRC);
+ }
+ }
+
+ /**
+ * This returns the CRC, if it has been set, for the file object
+ * @return - a CRC32 Long
+ */
+ public Long getCRC() {
+ final Object o = parameters.get(KEY_CRC);
+ if (o == null){
+ return null;
+ }
+ if (o instanceof Integer) {
+ return ((Integer) o).longValue();
+ }else if(o instanceof Long){
+ return (Long) o;
+ }
+ return null;
+ }
@Override
public final void setOnRPCResponseListener(OnRPCResponseListener listener) {
super.setOnRPCResponseListener(listener);
}
-
+
public void setOnPutFileUpdateListener(OnPutFileUpdateListener listener) {
super.setOnRPCResponseListener(listener); //We can use the same method because it get stored as a parent class
}
-
+
public OnPutFileUpdateListener getOnPutFileUpdateListener() {
return (OnPutFileUpdateListener)getOnRPCResponseListener();
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/PutFileResponse.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/PutFileResponse.java
index 028436d1e..f8d4a3bca 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/PutFileResponse.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/PutFileResponse.java
@@ -5,6 +5,7 @@ import android.support.annotation.NonNull;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCResponse;
import com.smartdevicelink.proxy.rpc.enums.Result;
+import com.smartdevicelink.util.Version;
import java.util.Hashtable;
@@ -15,6 +16,7 @@ import java.util.Hashtable;
*/
public class PutFileResponse extends RPCResponse {
public static final String KEY_SPACE_AVAILABLE = "spaceAvailable";
+ private static final Integer MAX_VALUE = 2000000000;
/**
* Constructs a new PutFileResponse object
@@ -28,26 +30,62 @@ public class PutFileResponse extends RPCResponse {
* parameter
* <p></p>
*
- * @param hash
- * The Hashtable to use
+ * @param hash The Hashtable to use
*/
public PutFileResponse(Hashtable<String, Object> hash) {
super(hash);
}
- /**
- * Constructs a new PutFileResponse object
- * @param success whether the request is successfully processed
- * @param resultCode whether the request is successfully processed
- */
- public PutFileResponse(@NonNull Boolean success, @NonNull Result resultCode, @NonNull Integer spaceAvailable) {
- this();
- setSuccess(success);
- setResultCode(resultCode);
- setSpaceAvailable(spaceAvailable);
- }
- public void setSpaceAvailable(@NonNull Integer spaceAvailable) {
+
+ /**
+ * @deprecated use {@link PutFileResponse#PutFileResponse(Boolean, Result)} <br>
+ *
+ * Constructs a new PutFileResponse object
+ * @param success whether the request is successfully processed
+ * @param resultCode whether the request is successfully processed
+ * @param spaceAvailable the spaceAvailable on the head unit
+ */
+ @Deprecated
+ public PutFileResponse(@NonNull Boolean success, @NonNull Result resultCode, @NonNull Integer spaceAvailable) {
+ this();
+ setSuccess(success);
+ setResultCode(resultCode);
+ setSpaceAvailable(spaceAvailable);
+ }
+
+ /**
+ * Constructs a new PutFileResponse object
+ * @param success whether the request is successfully processed
+ * @param resultCode whether the request is successfully processed
+ */
+ public PutFileResponse(@NonNull Boolean success, @NonNull Result resultCode) {
+ this();
+ setSuccess(success);
+ setResultCode(resultCode);
+ }
+
+ /**
+ * SpaceAvailable became optional as of RPC Spec 5.0. If a system that expected the value to
+ * always have a value connects to such a system, it could return null. Check to see if there
+ * is a value, and if not, set it to MAX_VALUE as defined by the RPC Spec
+ *
+ * @param rpcVersion the rpc spec version that has been negotiated. If value is null the
+ * the max value of RPC spec version this library supports should be used.
+ * @param formatParams if true, the format method will be called on subsequent params
+ */
+ @Override
+ public void format(Version rpcVersion, boolean formatParams){
+ if (rpcVersion == null || rpcVersion.getMajor() >= 5){
+ if (getSpaceAvailable() == null){
+ setSpaceAvailable(MAX_VALUE);
+ }
+ }
+ super.format(rpcVersion, formatParams);
+ }
+
+ public void setSpaceAvailable(Integer spaceAvailable) {
setParameters(KEY_SPACE_AVAILABLE, spaceAvailable);
}
+
public Integer getSpaceAvailable() {
return getInteger(KEY_SPACE_AVAILABLE);
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RGBColor.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RGBColor.java
new file mode 100644
index 000000000..81d43161d
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RGBColor.java
@@ -0,0 +1,141 @@
+package com.smartdevicelink.proxy.rpc;
+
+import com.smartdevicelink.proxy.RPCStruct;
+import java.util.Hashtable;
+
+/**
+ * A color class that stores RGB values
+ * <p><b> Parameter List</b></p>
+ * <table border="1" rules="all">
+ * <tr>
+ * <th>Name</th>
+ * <th>Type</th>
+ * <th>Reg.</th>
+ * <th>Notes</th>
+ * <th>Version Available</th>
+ * </tr>
+ * <tr>
+ * <td>red</td>
+ * <td>Integer</td>
+ * <td>Y</td>
+ * <td><ul><li>minvalue="0"</li><li>maxvalue="255"</li></ul></td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
+ * <tr>
+ * <td>green</td>
+ * <td>Integer</td>
+ * <td>Y</td>
+ * <td><ul><li>minvalue="0"</li><li>maxvalue="255"</li></ul></td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
+ * <tr>
+ * <td>blue</td>
+ * <td>Integer</td>
+ * <td>Y</td>
+ * <td><ul><li>minvalue="0"</li><li>maxvalue="255"</li></ul></td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
+ * </table>
+ * @since SmartDeviceLink 5.0
+ */
+public class RGBColor extends RPCStruct{
+ public static final String KEY_RED = "red";
+ public static final String KEY_GREEN = "green";
+ public static final String KEY_BLUE = "blue";
+ private static final Integer MIN_VALUE = 0, MAX_VALUE = 255;
+
+ /**
+ * Constructs a new RGBColor object
+ */
+ public RGBColor(){
+ this(MIN_VALUE, MIN_VALUE, MIN_VALUE);
+ }
+
+ /**
+ * Constructs a new RGBColor object indicated by the Hashtable parameter
+ * @param hash The Hashtable to use
+ */
+ public RGBColor(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Constructs a new RGB object
+ * @param red red value - min: 0; max: 255
+ * @param green green value - min: 0; max: 255
+ * @param blue blue value - min: 0; max: 255
+ */
+ public RGBColor(Integer red, Integer green, Integer blue) {
+ Hashtable<String, Object> hash = new Hashtable<>();
+ if (red != null && red >= MIN_VALUE && red <= MAX_VALUE) {
+ hash.put(KEY_RED, red);
+ } else {
+ hash.put(KEY_RED, MIN_VALUE);
+ }
+ if (green != null && green >= MIN_VALUE && green <= MAX_VALUE) {
+ hash.put(KEY_GREEN, green);
+ } else {
+ hash.put(KEY_GREEN, MIN_VALUE);
+ }
+ if (blue != null && blue >= MIN_VALUE && blue <= MAX_VALUE) {
+ hash.put(KEY_BLUE, blue);
+ } else {
+ hash.put(KEY_BLUE, MIN_VALUE);
+ }
+ this.store = hash;
+ }
+
+ /**
+ * Sets the red value of the color object
+ * @param color red value - min: 0; max: 255
+ */
+ public void setRed(Integer color) {
+ if (color != null && color >= MIN_VALUE && color <= MAX_VALUE) {
+ setValue(KEY_RED, color);
+ }
+ }
+
+ /**
+ * Gets the red value of the color
+ * @return red value
+ */
+ public Integer getRed() {
+ return getInteger(KEY_RED);
+ }
+
+ /**
+ * Sets the green value of the color object
+ * @param color green value - min: 0; max: 255
+ */
+ public void setGreen(Integer color) {
+ if (color != null && color >= MIN_VALUE && color <= MAX_VALUE) {
+ setValue(KEY_GREEN, color);
+ }
+ }
+
+ /**
+ * Gets the green value of the color
+ * @return green value
+ */
+ public Integer getGreen() {
+ return getInteger(KEY_GREEN);
+ }
+
+ /**
+ * Sets the blue value of the color object
+ * @param color blue value - min: 0; max: 255
+ */
+ public void setBlue(Integer color) {
+ if (color != null && color >= MIN_VALUE && color <= MAX_VALUE) {
+ setValue(KEY_BLUE, color);
+ }
+ }
+
+ /**
+ * Gets the green value of the color
+ * @return green value
+ */
+ public Integer getBlue() {
+ return getInteger(KEY_BLUE);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RadioControlCapabilities.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RadioControlCapabilities.java
index 1eee9a17a..ac46368d8 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RadioControlCapabilities.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RadioControlCapabilities.java
@@ -19,6 +19,9 @@ public class RadioControlCapabilities extends RPCStruct{
public static final String KEY_STATE_AVAILABLE= "stateAvailable";
public static final String KEY_SIGNAL_STRENGTH_AVAILABLE= "signalStrengthAvailable";
public static final String KEY_SIGNAL_CHANGE_THRESHOLD_AVAILABLE= "signalChangeThresholdAvailable";
+ public static final String KEY_HD_RADIO_ENABLE_AVAILABLE = "hdRadioEnableAvailable";
+ public static final String KEY_SIRIUS_XM_RADIO_AVAILABLE = "siriusxmRadioAvailable";
+ public static final String KEY_SIS_DATA_AVAILABLE = "sisDataAvailable";
public RadioControlCapabilities() {
}
@@ -245,4 +248,64 @@ public class RadioControlCapabilities extends RPCStruct{
public Boolean getSignalChangeThresholdAvailable() {
return getBoolean(KEY_SIGNAL_CHANGE_THRESHOLD_AVAILABLE);
}
+
+ /**
+ * Sets the hdRadioEnableAvailable portion of the RadioControlCapabilities class
+ *
+ * @param hdRadioEnableAvailable Availability of the control of enable/disable HD radio.
+ * True: Available, False: Not Available, Not present: Not Available.
+ */
+ public void setHdRadioEnableAvailable(Boolean hdRadioEnableAvailable) {
+ setValue(KEY_HD_RADIO_ENABLE_AVAILABLE, hdRadioEnableAvailable);
+ }
+
+ /**
+ * Gets the hdRadioEnableAvailable portion of the RadioControlCapabilities class
+ *
+ * @return Boolean - Availability of the control of enable/disable HD radio.
+ * True: Available, False: Not Available, Not present: Not Available.
+ */
+ public Boolean getHdRadioEnableAvailable() {
+ return getBoolean(KEY_HD_RADIO_ENABLE_AVAILABLE);
+ }
+
+ /**
+ * Sets the siriusxmRadioAvailable portion of the RadioControlCapabilities class
+ *
+ * @param siriusxmRadioAvailable Availability of sirius XM radio.
+ * True: Available, False: Not Available, Not present: Not Available.
+ */
+ public void setSiriusXMRadioAvailable(Boolean siriusxmRadioAvailable) {
+ setValue(KEY_SIRIUS_XM_RADIO_AVAILABLE, siriusxmRadioAvailable);
+ }
+
+ /**
+ * Gets the siriusxmRadioAvailable portion of the RadioControlCapabilities class
+ *
+ * @return Boolean - Availability of sirius XM radio.
+ * True: Available, False: Not Available, Not present: Not Available.
+ */
+ public Boolean getSiriusXMRadioAvailable() {
+ return getBoolean(KEY_SIRIUS_XM_RADIO_AVAILABLE);
+ }
+
+ /**
+ * Sets the sisDataAvailable portion of the RadioControlCapabilities class
+ *
+ * @param sisDataAvailable Availability of the getting HD radio Station Information Service (SIS) data.
+ * True: Available, False: Not Available, Not present: Not Available.
+ */
+ public void setSisDataAvailable(Boolean sisDataAvailable) {
+ setValue(KEY_SIS_DATA_AVAILABLE, sisDataAvailable);
+ }
+
+ /**
+ * Gets the sisDataAvailable portion of the RadioControlCapabilities class
+ *
+ * @return Boolean - Availability of the getting HD radio Station Information Service (SIS) data.
+ * True: Available, False: Not Available, Not present: Not Available.
+ */
+ public Boolean getSisDataAvailable() {
+ return getBoolean(KEY_SIS_DATA_AVAILABLE);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RadioControlData.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RadioControlData.java
index 4744399ac..fcedfdb0f 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RadioControlData.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RadioControlData.java
@@ -20,6 +20,8 @@ public class RadioControlData extends RPCStruct{
public static final String KEY_SIGNAL_CHANGE_THRESHOLD= "signalChangeThreshold";
public static final String KEY_RADIO_ENABLE= "radioEnable";
public static final String KEY_STATE= "state";
+ public static final String KEY_HD_RADIO_ENABLE = "hdRadioEnable";
+ public static final String KEY_SIS_DATA = "sisData";
public RadioControlData() {
}
@@ -220,4 +222,40 @@ public class RadioControlData extends RPCStruct{
public RadioState getState() {
return (RadioState) getObject(RadioState.class, KEY_STATE);
}
+
+ /**
+ * Sets the hdRadioEnable portion of the RadioControlData class
+ *
+ * @param hdRadioEnable True if the hd radio is on, false if the radio is off.
+ */
+ public void setHdRadioEnable(Boolean hdRadioEnable) {
+ setValue(KEY_HD_RADIO_ENABLE, hdRadioEnable);
+ }
+
+ /**
+ * Gets the hdRadioEnable portion of the RadioControlData class
+ *
+ * @return Boolean - True if the hd radio is on, false if the radio is off.
+ */
+ public Boolean getHdRadioEnable() {
+ return getBoolean(KEY_HD_RADIO_ENABLE);
+ }
+
+ /**
+ * Sets the sisData portion of the RadioControlData class
+ *
+ * @param sisData Read-only Station Information Service (SIS) data provides basic information about the station such as call sign, as well as information not displayable to the consumer such as the station identification number.
+ */
+ public void setSisData(SisData sisData) {
+ setValue(KEY_SIS_DATA, sisData);
+ }
+
+ /**
+ * Gets the sisData portion of the RadioControlData class
+ *
+ * @return SisData - Read-only Station Information Service (SIS) data provides basic information about the station such as call sign, as well as information not displayable to the consumer such as the station identification number.
+ */
+ public SisData getSisData() {
+ return (SisData) getObject(SisData.class, KEY_SIS_DATA);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RegisterAppInterface.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RegisterAppInterface.java
index 970613ccf..5ba1e623d 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RegisterAppInterface.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RegisterAppInterface.java
@@ -6,6 +6,7 @@ import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCRequest;
import com.smartdevicelink.proxy.rpc.enums.AppHMIType;
import com.smartdevicelink.proxy.rpc.enums.Language;
+import com.smartdevicelink.util.Version;
import java.util.Hashtable;
import java.util.List;
@@ -182,7 +183,14 @@ import java.util.List;
* <td>Maxlength: 100</td>
* <td>SmartDeviceLink 2.0 </td>
* </tr>
- *
+ * <tr>
+ * <td>fullAppID</td>
+ * <td>String</td>
+ * <td>ID used to validate app with policy table entries</td>
+ * <td>N</td>
+ * <td>Maxlength: 100</td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
* <tr>
* <td>hmiCapabilities</td>
* <td>HMICapabilities</td>
@@ -200,7 +208,7 @@ import java.util.List;
* <td>Maxlength: 100</td>
* <td>SmartDeviceLink 2.3.2.2</td>
* </tr>
- *
+ *
* <tr>
* <td>systemSoftwareVersion</td>
* <td>String</td>
@@ -209,6 +217,24 @@ import java.util.List;
* <td>Maxlength: 100</td>
* <td>SmartDeviceLink 2.3.2.2</td>
* </tr>
+ *
+ * <tr>
+ * <td>dayColorScheme</td>
+ * <td>TemplateColorScheme</td>
+ * <td>The color scheme that is used for day.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
+ *
+ * <tr>
+ * <td>nightColorScheme</td>
+ * <td>TemplateColorScheme</td>
+ * <td>The color scheme that is used for night.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
* </table>
* <p></p>
* @since SmartDeviceLink 1.0
@@ -220,6 +246,7 @@ public class RegisterAppInterface extends RPCRequest {
public static final String KEY_HMI_DISPLAY_LANGUAGE_DESIRED = "hmiDisplayLanguageDesired";
public static final String KEY_APP_HMI_TYPE = "appHMIType";
public static final String KEY_APP_ID = "appID";
+ public static final String KEY_FULL_APP_ID = "fullAppID";
public static final String KEY_LANGUAGE_DESIRED = "languageDesired";
public static final String KEY_DEVICE_INFO = "deviceInfo";
public static final String KEY_APP_NAME = "appName";
@@ -228,6 +255,10 @@ public class RegisterAppInterface extends RPCRequest {
public static final String KEY_VR_SYNONYMS = "vrSynonyms";
public static final String KEY_SDL_MSG_VERSION = "syncMsgVersion";
public static final String KEY_HASH_ID = "hashID";
+ public static final String KEY_DAY_COLOR_SCHEME = "dayColorScheme";
+ public static final String KEY_NIGHT_COLOR_SCHEME = "nightColorScheme";
+ private static final int APP_ID_MAX_LENGTH = 10;
+
/**
* Constructs a new RegisterAppInterface object
*/
@@ -270,18 +301,18 @@ public class RegisterAppInterface extends RPCRequest {
* @param isMediaApplication a Boolean value
* @param languageDesired a Language Enumeration
* @param hmiDisplayLanguageDesired
- * @param appID a String value representing a unique ID, which an app will be given when approved <br>
+ * @param fullAppID a String value representing a unique ID, which an app will be given when approved <br>
* <b>Notes: </b>Maxlength = 100
*/
public RegisterAppInterface(@NonNull SdlMsgVersion syncMsgVersion, @NonNull String appName, @NonNull Boolean isMediaApplication,
- @NonNull Language languageDesired, @NonNull Language hmiDisplayLanguageDesired, @NonNull String appID) {
+ @NonNull Language languageDesired, @NonNull Language hmiDisplayLanguageDesired, @NonNull String fullAppID) {
this();
setSdlMsgVersion(syncMsgVersion);
setAppName(appName);
setIsMediaApplication(isMediaApplication);
setLanguageDesired(languageDesired);
setHmiDisplayLanguageDesired(hmiDisplayLanguageDesired);
- setAppID(appID);
+ setFullAppID(fullAppID);
}
/**
* Gets the version of the SDL&reg; SmartDeviceLink interface
@@ -552,22 +583,22 @@ public class RegisterAppInterface extends RPCRequest {
public void setHashID(String hashID) {
setParameters(KEY_HASH_ID, hashID);
- }
-
+ }
+
/**
* Gets the unique ID, which an app will be given when approved
- *
+ *
* @return String - a String value representing the unique ID, which an app
* will be given when approved
* @since SmartDeviceLink 2.0
*/
- public String getAppID() {
- return getString(KEY_APP_ID);
- }
+ public String getAppID() {
+ return getString(KEY_APP_ID);
+ }
/**
* Sets a unique ID, which an app will be given when approved
- *
+ *
* @param appID
* a String value representing a unique ID, which an app will be
* given when approved
@@ -575,7 +606,102 @@ public class RegisterAppInterface extends RPCRequest {
* <b>Notes: </b>Maxlength = 100
* @since SmartDeviceLink 2.0
*/
- public void setAppID(@NonNull String appID) {
- setParameters(KEY_APP_ID, appID);
- }
+ public void setAppID(@NonNull String appID) {
+ if (appID != null) {
+ setParameters(KEY_APP_ID, appID.toLowerCase());
+ } else {
+ setParameters(KEY_APP_ID, appID);
+ }
+ }
+
+ /**
+ * Gets the unique ID, which an app will be given when approved
+ *
+ * @return String - a String value representing the unique ID, which an app
+ * will be given when approved
+ * @since SmartDeviceLink 5.0
+ */
+ public String getFullAppID() {
+ return getString(KEY_FULL_APP_ID);
+ }
+
+ /**
+ * Sets a unique ID, which an app will be given when approved <br>
+ * Note: this will automatically parse the fullAppID into the smaller appId and set the appId value as well
+ * @param fullAppID
+ * a String value representing a unique ID, which an app will be
+ * given when approved
+ * <p></p>
+ * <b>Notes: </b>Maxlength = 100
+ * @since SmartDeviceLink 5.0
+ */
+ public void setFullAppID(String fullAppID) {
+ if (fullAppID != null) {
+ fullAppID = fullAppID.toLowerCase();
+ setParameters(KEY_FULL_APP_ID, fullAppID);
+ String appID;
+ if (fullAppID.length() <= APP_ID_MAX_LENGTH) {
+ appID = fullAppID;
+ } else {
+ appID = fullAppID.replace("-", "").substring(0, APP_ID_MAX_LENGTH);
+ }
+ setAppID(appID);
+ } else {
+ setParameters(KEY_FULL_APP_ID, null);
+ }
+ }
+
+ @Override
+ public void format(Version rpcVersion, boolean formatParams) {
+ if(rpcVersion == null || rpcVersion.getMajor() >= 5) {
+ if (getFullAppID() == null) {
+ setFullAppID(getAppID());
+ }
+ }
+ super.format(rpcVersion, formatParams);
+ }
+
+ /**
+ * Gets the color scheme that is currently used for day
+ *
+ * @return TemplateColorScheme - a TemplateColorScheme object representing the colors that are used
+ * for day color scheme
+ * @since SmartDeviceLink 5.0
+ */
+ public TemplateColorScheme getDayColorScheme(){
+ return (TemplateColorScheme) getObject(TemplateColorScheme.class, KEY_DAY_COLOR_SCHEME);
+ }
+
+ /**
+ * Sets the color scheme that is intended to be used for day
+ *
+ * @param templateColorScheme a TemplateColorScheme object representing the colors that will be
+ * used for day color scheme
+ * @since SmartDeviceLink 5.0
+ */
+ public void setDayColorScheme(TemplateColorScheme templateColorScheme){
+ setParameters(KEY_DAY_COLOR_SCHEME, templateColorScheme);
+ }
+
+ /**
+ * Gets the color scheme that is currently used for night
+ *
+ * @return TemplateColorScheme - a TemplateColorScheme object representing the colors that are used
+ * for night color scheme
+ * @since SmartDeviceLink 5.0
+ */
+ public TemplateColorScheme getNightColorScheme(){
+ return (TemplateColorScheme) getObject(TemplateColorScheme.class, KEY_NIGHT_COLOR_SCHEME);
+ }
+
+ /**
+ * Sets the color scheme that is intended to be used for night
+ *
+ * @param templateColorScheme a TemplateColorScheme object representing the colors that will be
+ * used for night color scheme
+ * @since SmartDeviceLink 5.0
+ */
+ public void setNightColorScheme(TemplateColorScheme templateColorScheme){
+ setParameters(KEY_NIGHT_COLOR_SCHEME, templateColorScheme);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RegisterAppInterfaceResponse.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RegisterAppInterfaceResponse.java
index 0fea2f9a9..746129a85 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RegisterAppInterfaceResponse.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RegisterAppInterfaceResponse.java
@@ -5,6 +5,7 @@ import android.support.annotation.NonNull;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCResponse;
import com.smartdevicelink.proxy.Version;
+import com.smartdevicelink.proxy.rpc.enums.ButtonName;
import com.smartdevicelink.proxy.rpc.enums.HmiZoneCapabilities;
import com.smartdevicelink.proxy.rpc.enums.Language;
import com.smartdevicelink.proxy.rpc.enums.PrerecordedSpeech;
@@ -39,8 +40,8 @@ public class RegisterAppInterfaceResponse extends RPCResponse {
public static final String KEY_HMI_CAPABILITIES = "hmiCapabilities"; //As of v4.0
public static final String KEY_SDL_VERSION = "sdlVersion"; //As of v4.0
public static final String KEY_SYSTEM_SOFTWARE_VERSION = "systemSoftwareVersion"; //As of v4.0
- public static final String KEY_PCM_STREAM_CAPABILITIES = "pcmStreamCapabilities";
-
+ public static final String KEY_ICON_RESUMED = "iconResumed";
+ public static final String KEY_PCM_STREAM_CAPABILITIES = "pcmStreamCapabilities";
/**
* Constructs a new RegisterAppInterfaceResponse object
@@ -77,6 +78,33 @@ public class RegisterAppInterfaceResponse extends RPCResponse {
setSuccess(success);
setResultCode(resultCode);
}
+
+ @Override
+ public void format(com.smartdevicelink.util.Version rpcVersion, boolean formatParams){
+ //Add in 5.0.0 of the rpc spec
+ if(getIconResumed() == null){
+ setIconResumed(Boolean.FALSE);
+ }
+
+ List<ButtonCapabilities> capabilities = getButtonCapabilities();
+ if(capabilities != null){
+ List<ButtonCapabilities> additions = new ArrayList<>();
+ for(ButtonCapabilities capability : capabilities){
+ if(ButtonName.OK.equals(capability.getName())){
+ if(rpcVersion == null || rpcVersion.getMajor() < 5){
+ //If version is < 5, the play pause button must also be added
+ additions.add(new ButtonCapabilities(ButtonName.PLAY_PAUSE, capability.getShortPressAvailable(), capability.getLongPressAvailable(), capability.getUpDownAvailable()));
+ }
+ }
+ }
+ capabilities.addAll(additions);
+ setButtonCapabilities(capabilities);
+ }
+
+
+ super.format(rpcVersion,formatParams);
+ }
+
@SuppressWarnings("unchecked")
public SdlMsgVersion getSdlMsgVersion() {
return (SdlMsgVersion) getObject(SdlMsgVersion.class, KEY_SDL_MSG_VERSION);
@@ -376,7 +404,26 @@ public class RegisterAppInterfaceResponse extends RPCResponse {
setParameters(KEY_SYSTEM_SOFTWARE_VERSION, systemSoftwareVersion);
}
- public String getSystemSoftwareVersion() {
- return getString(KEY_SYSTEM_SOFTWARE_VERSION);
+ public String getSystemSoftwareVersion() {
+ return getString(KEY_SYSTEM_SOFTWARE_VERSION);
}
+
+ /**
+ * Sets Icon Resumed Boolean
+ * @param iconResumed - if param not included, set to false
+ */
+ public void setIconResumed(Boolean iconResumed){
+ if(iconResumed == null){
+ iconResumed = false;
+ }
+ setParameters(KEY_ICON_RESUMED, iconResumed);
+ }
+
+ /**
+ * Tells developer whether or not their app icon has been resumed on core.
+ * @return boolean - true if icon was resumed, false if not
+ */
+ public Boolean getIconResumed() {
+ return getBoolean(KEY_ICON_RESUMED);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RemoteControlCapabilities.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RemoteControlCapabilities.java
index ec51aa633..4c9861101 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RemoteControlCapabilities.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/RemoteControlCapabilities.java
@@ -1,82 +1,158 @@
package com.smartdevicelink.proxy.rpc;
import com.smartdevicelink.proxy.RPCStruct;
+
import java.util.Hashtable;
import java.util.List;
-public class RemoteControlCapabilities extends RPCStruct{
- public static final String KEY_CLIMATE_CONTROL_CAPABILITIES= "climateControlCapabilities";
- public static final String KEY_RADIO_CONTROL_CAPABILITIES = "radioControlCapabilities";
- public static final String KEY_BUTTON_CAPABILITIES = "buttonCapabilities";
-
- public RemoteControlCapabilities() {
- }
-
- public RemoteControlCapabilities(Hashtable<String, Object> hash) {
- super(hash);
- }
-
- /**
- * Sets the climateControlCapabilities portion of the RemoteControlCapabilities class
- *
- * @param climateControlCapabilities
- * If included, the platform supports RC climate controls.
- * For this baseline version, maxsize=1. i.e. only one climate control module is supported.
- */
- public void setClimateControlCapabilities(List<ClimateControlCapabilities> climateControlCapabilities) {
- setValue(KEY_CLIMATE_CONTROL_CAPABILITIES, climateControlCapabilities);
- }
-
- /**
- * Gets the climateControlCapabilities portion of the RemoteControlCapabilities class
- *
- * @return List<ClimateControlCapabilities>
- * If included, the platform supports RC climate controls.
- * For this baseline version, maxsize=1. i.e. only one climate control module is supported.
- */
- public List<ClimateControlCapabilities> getClimateControlCapabilities() {
- return (List<ClimateControlCapabilities>) getObject(ClimateControlCapabilities.class, KEY_CLIMATE_CONTROL_CAPABILITIES);
- }
-
- /**
- * Sets the radioControlCapabilities portion of the RemoteControlCapabilities class
- *
- * @param radioControlCapabilities
- * If included, the platform supports RC climate controls.
- * For this baseline version, maxsize=1. i.e. only one radio control module is supported.
- */
- public void setRadioControlCapabilities(List<RadioControlCapabilities> radioControlCapabilities) {
- setValue(KEY_RADIO_CONTROL_CAPABILITIES, radioControlCapabilities);
- }
-
- /**
- * Gets the radioControlCapabilities portion of the RemoteControlCapabilities class
- *
- * @return List<RadioControlCapabilities>
- * If included, the platform supports RC climate controls.
- * For this baseline version, maxsize=1. i.e. only one radio control module is supported.
- */
- public List<RadioControlCapabilities> getRadioControlCapabilities() {
- return (List<RadioControlCapabilities>) getObject(RadioControlCapabilities.class, KEY_RADIO_CONTROL_CAPABILITIES);
- }
-
- /**
- * Sets the buttonCapabilities portion of the RemoteControlCapabilities class
- *
- * @param buttonCapabilities
- * If included, the platform supports RC button controls with the included button names.
- */
- public void setButtonCapabilities(List<ButtonCapabilities> buttonCapabilities) {
- setValue(KEY_BUTTON_CAPABILITIES, buttonCapabilities);
- }
-
- /**
- * Gets the buttonCapabilities portion of the RemoteControlCapabilities class
- *
- * @return List<ButtonCapabilities>
- * If included, the platform supports RC button controls with the included button names.
- */
- public List<ButtonCapabilities> getButtonCapabilities() {
- return (List<ButtonCapabilities>) getObject(ButtonCapabilities.class, KEY_BUTTON_CAPABILITIES);
- }
+public class RemoteControlCapabilities extends RPCStruct {
+ public static final String KEY_CLIMATE_CONTROL_CAPABILITIES = "climateControlCapabilities";
+ public static final String KEY_RADIO_CONTROL_CAPABILITIES = "radioControlCapabilities";
+ public static final String KEY_BUTTON_CAPABILITIES = "buttonCapabilities";
+ public static final String KEY_SEAT_CONTROL_CAPABILITIES = "seatControlCapabilities";
+ public static final String KEY_AUDIO_CONTROL_CAPABILITIES = "audioControlCapabilities";
+ public static final String KEY_HMI_SETTINGS_CONTROL_CAPABILITIES = "hmiSettingsControlCapabilities";
+ public static final String KEY_LIGHT_CONTROL_CAPABILITIES = "lightControlCapabilities";
+
+ public RemoteControlCapabilities() {
+ }
+
+ public RemoteControlCapabilities(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Sets the climateControlCapabilities portion of the RemoteControlCapabilities class
+ *
+ * @param climateControlCapabilities If included, the platform supports RC climate controls.
+ * For this baseline version, maxsize=1. i.e. only one climate control module is supported.
+ */
+ public void setClimateControlCapabilities(List<ClimateControlCapabilities> climateControlCapabilities) {
+ setValue(KEY_CLIMATE_CONTROL_CAPABILITIES, climateControlCapabilities);
+ }
+
+ /**
+ * Gets the climateControlCapabilities portion of the RemoteControlCapabilities class
+ *
+ * @return List<ClimateControlCapabilities>
+ * If included, the platform supports RC climate controls.
+ * For this baseline version, maxsize=1. i.e. only one climate control module is supported.
+ */
+ public List<ClimateControlCapabilities> getClimateControlCapabilities() {
+ return (List<ClimateControlCapabilities>) getObject(ClimateControlCapabilities.class, KEY_CLIMATE_CONTROL_CAPABILITIES);
+ }
+
+ /**
+ * Sets the radioControlCapabilities portion of the RemoteControlCapabilities class
+ *
+ * @param radioControlCapabilities If included, the platform supports RC climate controls.
+ * For this baseline version, maxsize=1. i.e. only one radio control module is supported.
+ */
+ public void setRadioControlCapabilities(List<RadioControlCapabilities> radioControlCapabilities) {
+ setValue(KEY_RADIO_CONTROL_CAPABILITIES, radioControlCapabilities);
+ }
+
+ /**
+ * Gets the radioControlCapabilities portion of the RemoteControlCapabilities class
+ *
+ * @return List<RadioControlCapabilities>
+ * If included, the platform supports RC climate controls.
+ * For this baseline version, maxsize=1. i.e. only one radio control module is supported.
+ */
+ public List<RadioControlCapabilities> getRadioControlCapabilities() {
+ return (List<RadioControlCapabilities>) getObject(RadioControlCapabilities.class, KEY_RADIO_CONTROL_CAPABILITIES);
+ }
+
+ /**
+ * Sets the buttonCapabilities portion of the RemoteControlCapabilities class
+ *
+ * @param buttonCapabilities If included, the platform supports RC button controls with the included button names.
+ */
+ public void setButtonCapabilities(List<ButtonCapabilities> buttonCapabilities) {
+ setValue(KEY_BUTTON_CAPABILITIES, buttonCapabilities);
+ }
+
+ /**
+ * Gets the buttonCapabilities portion of the RemoteControlCapabilities class
+ *
+ * @return List<ButtonCapabilities>
+ * If included, the platform supports RC button controls with the included button names.
+ */
+ public List<ButtonCapabilities> getButtonCapabilities() {
+ return (List<ButtonCapabilities>) getObject(ButtonCapabilities.class, KEY_BUTTON_CAPABILITIES);
+ }
+
+ /**
+ * Sets the seatControlCapabilities portion of the RemoteControlCapabilities class
+ *
+ * @param seatControlCapabilities If included, the platform supports seat controls.
+ */
+ public void setSeatControlCapabilities(List<SeatControlCapabilities> seatControlCapabilities) {
+ setValue(KEY_SEAT_CONTROL_CAPABILITIES, seatControlCapabilities);
+ }
+
+ /**
+ * Gets the seatControlCapabilities portion of the RemoteControlCapabilities class
+ *
+ * @return List<SeatControlCapabilities>
+ * If included, the platform supports seat controls.
+ */
+ public List<SeatControlCapabilities> getSeatControlCapabilities() {
+ return (List<SeatControlCapabilities>) getObject(SeatControlCapabilities.class, KEY_SEAT_CONTROL_CAPABILITIES);
+ }
+
+ /**
+ * Sets the audioControlCapabilities portion of the RemoteControlCapabilities class
+ *
+ * @param audioControlCapabilities If included, the platform supports audio controls.
+ */
+ public void setAudioControlCapabilities(List<AudioControlCapabilities> audioControlCapabilities) {
+ setValue(KEY_AUDIO_CONTROL_CAPABILITIES, audioControlCapabilities);
+ }
+
+ /**
+ * Gets the audioControlCapabilities portion of the RemoteControlCapabilities class
+ *
+ * @return List<AudioControlCapabilities>
+ * If included, the platform supports audio controls.
+ */
+ public List<AudioControlCapabilities> getAudioControlCapabilities() {
+ return (List<AudioControlCapabilities>) getObject(AudioControlCapabilities.class, KEY_AUDIO_CONTROL_CAPABILITIES);
+ }
+
+ /**
+ * Sets the hmiSettingsControlCapabilities portion of the RemoteControlCapabilities class
+ *
+ * @param hmiSettingsControlCapabilities If included, the platform supports hmi setting controls.
+ */
+ public void setHmiSettingsControlCapabilities(HMISettingsControlCapabilities hmiSettingsControlCapabilities) {
+ setValue(KEY_HMI_SETTINGS_CONTROL_CAPABILITIES, hmiSettingsControlCapabilities);
+ }
+
+ /**
+ * Gets the hmiSettingsControlCapabilities portion of the RemoteControlCapabilities class
+ *
+ * @return HMISettingsControlCapabilities - If included, the platform supports hmi setting controls.
+ */
+ public HMISettingsControlCapabilities getHmiSettingsControlCapabilities() {
+ return (HMISettingsControlCapabilities) getObject(HMISettingsControlCapabilities.class, KEY_HMI_SETTINGS_CONTROL_CAPABILITIES);
+ }
+
+ /**
+ * Sets the lightControlCapabilities portion of the RemoteControlCapabilities class
+ *
+ * @param lightControlCapabilities If included, the platform supports light controls.
+ */
+ public void setLightControlCapabilities(LightControlCapabilities lightControlCapabilities) {
+ setValue(KEY_LIGHT_CONTROL_CAPABILITIES, lightControlCapabilities);
+ }
+
+ /**
+ * Gets the lightControlCapabilities portion of the RemoteControlCapabilities class
+ *
+ * @return LightControlCapabilities - If included, the platform supports light controls.
+ */
+ public LightControlCapabilities getLightControlCapabilities() {
+ return (LightControlCapabilities) getObject(LightControlCapabilities.class, KEY_LIGHT_CONTROL_CAPABILITIES);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SdlMsgVersion.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SdlMsgVersion.java
index 128d2050f..3e1637e22 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SdlMsgVersion.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SdlMsgVersion.java
@@ -74,7 +74,17 @@ public class SdlMsgVersion extends RPCStruct {
this();
setMajorVersion(majorVersion);
setMinorVersion(minorVersion);
+
+ }
+
+ @Override
+ public void format(com.smartdevicelink.util.Version rpcVersion, boolean formatParams) {
+ if(getPatchVersion() == null){
+ setPatchVersion(0);
+ }
+ super.format(rpcVersion,formatParams);
}
+
public Integer getMajorVersion() {
return getInteger( KEY_MAJOR_VERSION );
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SeatControlCapabilities.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SeatControlCapabilities.java
new file mode 100644
index 000000000..e1d488cb5
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SeatControlCapabilities.java
@@ -0,0 +1,339 @@
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.RPCStruct;
+
+import java.util.Hashtable;
+
+public class SeatControlCapabilities extends RPCStruct {
+ public static final String KEY_MODULE_NAME = "moduleName";
+ public static final String KEY_HEATING_ENABLED_AVAILABLE = "heatingEnabledAvailable";
+ public static final String KEY_COOLING_ENABLED_AVAILABLE = "coolingEnabledAvailable";
+ public static final String KEY_HEATING_LEVEL_AVAILABLE = "heatingLevelAvailable";
+ public static final String KEY_COOLING_LEVEL_AVAILABLE = "coolingLevelAvailable";
+ public static final String KEY_HORIZONTAL_POSITION_AVAILABLE = "horizontalPositionAvailable";
+ public static final String KEY_VERTICAL_POSITION_AVAILABLE = "verticalPositionAvailable";
+ public static final String KEY_FRONT_VERTICAL_POSITION_AVAILABLE = "frontVerticalPositionAvailable";
+ public static final String KEY_BACK_VERTICAL_POSITION_AVAILABLE = "backVerticalPositionAvailable";
+ public static final String KEY_BACK_TILT_ANGLE_AVAILABLE = "backTiltAngleAvailable";
+ public static final String KEY_HEAD_SUPPORT_HORIZONTAL_POSITION_AVAILABLE = "headSupportHorizontalPositionAvailable";
+ public static final String KEY_HEAD_SUPPORT_VERTICAL_POSITION_AVAILABLE = "headSupportVerticalPositionAvailable";
+ public static final String KEY_MASSAGE_ENABLED_AVAILABLE = "massageEnabledAvailable";
+ public static final String KEY_MASSAGE_MODE_AVAILABLE = "massageModeAvailable";
+ public static final String KEY_MASSAGE_CUSHION_FIRMNESS_AVAILABLE = "massageCushionFirmnessAvailable";
+ public static final String KEY_MEMORY_AVAILABLE = "memoryAvailable";
+
+ /**
+ * Constructs a new SeatControlCapabilities object
+ */
+ public SeatControlCapabilities() {
+ }
+
+ /**
+ * <p>Constructs a new SeatControlCapabilities object indicated by the Hashtable parameter
+ * </p>
+ *
+ * @param hash The Hashtable to use
+ */
+ public SeatControlCapabilities(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Constructs a newly allocated SeatControlCapabilities object
+ * @param moduleName short friendly name of the light control module.
+ */
+ public SeatControlCapabilities(@NonNull String moduleName) {
+ this();
+ setModuleName(moduleName);
+ }
+
+ /**
+ * Get the moduleName portion of the SeatControlCapabilities class
+ *
+ * @return String
+ */
+ public String getModuleName() {
+ return getString(KEY_MODULE_NAME);
+ }
+
+ /**
+ * Sets the moduleName portion of the SeatControlCapabilities class
+ *
+ * @param moduleName - The short friendly name of the light control module. It should not be used to identify a module by mobile application.
+ */
+ public void setModuleName(@NonNull String moduleName) {
+ setValue(KEY_MODULE_NAME, moduleName);
+ }
+
+ /**
+ * Sets the heatingEnabledAvailable portion of the SeatControlCapabilities class
+ *
+ * @param heatingEnabledAvailable
+ */
+ public void setHeatingEnabledAvailable(Boolean heatingEnabledAvailable) {
+ setValue(KEY_HEATING_ENABLED_AVAILABLE, heatingEnabledAvailable);
+ }
+
+ /**
+ * Gets the heatingEnabledAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getHeatingEnabledAvailable() {
+ return getBoolean(KEY_HEATING_ENABLED_AVAILABLE);
+ }
+
+ /**
+ * Sets the coolingEnabledAvailable portion of the SeatControlCapabilities class
+ *
+ * @param coolingEnabledAvailable
+ */
+ public void setCoolingEnabledAvailable(Boolean coolingEnabledAvailable) {
+ setValue(KEY_COOLING_ENABLED_AVAILABLE, coolingEnabledAvailable);
+ }
+
+ /**
+ * Gets the coolingEnabledAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getCoolingEnabledAvailable() {
+ return getBoolean(KEY_COOLING_ENABLED_AVAILABLE);
+ }
+
+ /**
+ * Sets the heatingLevelAvailable portion of the SeatControlCapabilities class
+ *
+ * @param heatingLevelAvailable
+ */
+ public void setHeatingLevelAvailable(Boolean heatingLevelAvailable) {
+ setValue(KEY_HEATING_LEVEL_AVAILABLE, heatingLevelAvailable);
+ }
+
+ /**
+ * Gets the heatingLevelAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getHeatingLevelAvailable() {
+ return getBoolean(KEY_HEATING_LEVEL_AVAILABLE);
+ }
+
+ /**
+ * Sets the coolingLevelAvailable portion of the SeatControlCapabilities class
+ *
+ * @param coolingLevelAvailable
+ */
+ public void setCoolingLevelAvailable(Boolean coolingLevelAvailable) {
+ setValue(KEY_COOLING_LEVEL_AVAILABLE, coolingLevelAvailable);
+ }
+
+ /**
+ * Gets the coolingLevelAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getCoolingLevelAvailable() {
+ return getBoolean(KEY_COOLING_LEVEL_AVAILABLE);
+ }
+
+ /**
+ * Sets the horizontalPositionAvailable portion of the SeatControlCapabilities class
+ *
+ * @param horizontalPositionAvailable
+ */
+ public void setHorizontalPositionAvailable(Boolean horizontalPositionAvailable) {
+ setValue(KEY_HORIZONTAL_POSITION_AVAILABLE, horizontalPositionAvailable);
+ }
+
+ /**
+ * Gets the horizontalPositionAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getHorizontalPositionAvailable() {
+ return getBoolean(KEY_HORIZONTAL_POSITION_AVAILABLE);
+ }
+
+ /**
+ * Sets the verticalPositionAvailable portion of the SeatControlCapabilities class
+ *
+ * @param verticalPositionAvailable
+ */
+ public void setVerticalPositionAvailable(Boolean verticalPositionAvailable) {
+ setValue(KEY_VERTICAL_POSITION_AVAILABLE, verticalPositionAvailable);
+ }
+
+ /**
+ * Gets the verticalPositionAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getVerticalPositionAvailable() {
+ return getBoolean(KEY_VERTICAL_POSITION_AVAILABLE);
+ }
+
+ /**
+ * Sets the frontVerticalPositionAvailable portion of the SeatControlCapabilities class
+ *
+ * @param frontVerticalPositionAvailable
+ */
+ public void setFrontVerticalPositionAvailable(Boolean frontVerticalPositionAvailable) {
+ setValue(KEY_FRONT_VERTICAL_POSITION_AVAILABLE, frontVerticalPositionAvailable);
+ }
+
+ /**
+ * Gets the frontVerticalPositionAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getFrontVerticalPositionAvailable() {
+ return getBoolean(KEY_FRONT_VERTICAL_POSITION_AVAILABLE);
+ }
+
+ /**
+ * Sets the backVerticalPositionAvailable portion of the SeatControlCapabilities class
+ *
+ * @param backVerticalPositionAvailable
+ */
+ public void setBackVerticalPositionAvailable(Boolean backVerticalPositionAvailable) {
+ setValue(KEY_BACK_VERTICAL_POSITION_AVAILABLE, backVerticalPositionAvailable);
+ }
+
+ /**
+ * Gets the backVerticalPositionAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getBackVerticalPositionAvailable() {
+ return getBoolean(KEY_BACK_VERTICAL_POSITION_AVAILABLE);
+ }
+
+ /**
+ * Sets the backTiltAngleAvailable portion of the SeatControlCapabilities class
+ *
+ * @param backTiltAngleAvailable
+ */
+ public void setBackTiltAngleAvailable(Boolean backTiltAngleAvailable) {
+ setValue(KEY_BACK_TILT_ANGLE_AVAILABLE, backTiltAngleAvailable);
+ }
+
+ /**
+ * Gets the backTiltAngleAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getBackTiltAngleAvailable() {
+ return getBoolean(KEY_BACK_TILT_ANGLE_AVAILABLE);
+ }
+
+ /**
+ * Sets the headSupportHorizontalPositionAvailable portion of the SeatControlCapabilities class
+ *
+ * @param headSupportHorizontalPositionAvailable
+ */
+ public void setHeadSupportHorizontalPositionAvailable(Boolean headSupportHorizontalPositionAvailable) {
+ setValue(KEY_HEAD_SUPPORT_HORIZONTAL_POSITION_AVAILABLE, headSupportHorizontalPositionAvailable);
+ }
+
+ /**
+ * Gets the headSupportHorizontalPositionAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getHeadSupportHorizontalPositionAvailable() {
+ return getBoolean(KEY_HEAD_SUPPORT_HORIZONTAL_POSITION_AVAILABLE);
+ }
+
+ /**
+ * Sets the headSupportVerticalPositionAvailable portion of the SeatControlCapabilities class
+ *
+ * @param headSupportVerticalPositionAvailable
+ */
+ public void setHeadSupportVerticalPositionAvailable(Boolean headSupportVerticalPositionAvailable) {
+ setValue(KEY_HEAD_SUPPORT_VERTICAL_POSITION_AVAILABLE, headSupportVerticalPositionAvailable);
+ }
+
+ /**
+ * Gets the headSupportVerticalPositionAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getHeadSupportVerticalPositionAvailable() {
+ return getBoolean(KEY_HEAD_SUPPORT_VERTICAL_POSITION_AVAILABLE);
+ }
+
+ /**
+ * Sets the massageEnabledAvailable portion of the SeatControlCapabilities class
+ *
+ * @param massageEnabledAvailable
+ */
+ public void setMassageEnabledAvailable(Boolean massageEnabledAvailable) {
+ setValue(KEY_MASSAGE_ENABLED_AVAILABLE, massageEnabledAvailable);
+ }
+
+ /**
+ * Gets the massageEnabledAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getMassageEnabledAvailable() {
+ return getBoolean(KEY_MASSAGE_ENABLED_AVAILABLE);
+ }
+
+ /**
+ * Sets the massageModeAvailable portion of the SeatControlCapabilities class
+ *
+ * @param massageModeAvailable
+ */
+ public void setMassageModeAvailable(Boolean massageModeAvailable) {
+ setValue(KEY_MASSAGE_MODE_AVAILABLE, massageModeAvailable);
+ }
+
+ /**
+ * Gets the massageModeAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getMassageModeAvailable() {
+ return getBoolean(KEY_MASSAGE_MODE_AVAILABLE);
+ }
+
+ /**
+ * Sets the massageCushionFirmnessAvailable portion of the SeatControlCapabilities class
+ *
+ * @param massageCushionFirmnessAvailable
+ */
+ public void setMassageCushionFirmnessAvailable(Boolean massageCushionFirmnessAvailable) {
+ setValue(KEY_MASSAGE_CUSHION_FIRMNESS_AVAILABLE, massageCushionFirmnessAvailable);
+ }
+
+ /**
+ * Gets the massageCushionFirmnessAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getMassageCushionFirmnessAvailable() {
+ return getBoolean(KEY_MASSAGE_CUSHION_FIRMNESS_AVAILABLE);
+ }
+
+ /**
+ * Sets the memoryAvailable portion of the SeatControlCapabilities class
+ *
+ * @param memoryAvailable
+ */
+ public void setMemoryAvailable(Boolean memoryAvailable) {
+ setValue(KEY_MEMORY_AVAILABLE, memoryAvailable);
+ }
+
+ /**
+ * Gets the memoryAvailable portion of the SeatControlCapabilities class
+ *
+ * @return Boolean.
+ */
+ public Boolean getMemoryAvailable() {
+ return getBoolean(KEY_MEMORY_AVAILABLE);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SeatControlData.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SeatControlData.java
new file mode 100644
index 000000000..26d52d713
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SeatControlData.java
@@ -0,0 +1,347 @@
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.RPCStruct;
+import com.smartdevicelink.proxy.rpc.enums.SupportedSeat;
+
+import java.util.Hashtable;
+import java.util.List;
+
+/**
+ * Seat control data corresponds to "SEAT" ModuleType.
+ */
+public class SeatControlData extends RPCStruct {
+ public static final String KEY_ID = "id";
+ public static final String KEY_HEATING_ENABLED = "heatingEnabled";
+ public static final String KEY_COOLING_ENABLED = "coolingEnabled";
+ public static final String KEY_HEATING_LEVEL = "heatingLevel";
+ public static final String KEY_COOLING_LEVEL = "coolingLevel";
+ public static final String KEY_HORIZONTAL_POSITION = "horizontalPosition";
+ public static final String KEY_VERTICAL_POSITION = "verticalPosition";
+ public static final String KEY_FRONT_VERTICAL_POSITION = "frontVerticalPosition";
+ public static final String KEY_BACK_VERTICAL_POSITION = "backVerticalPosition";
+ public static final String KEY_BACK_TILT_ANGLE = "backTiltAngle";
+ public static final String KEY_HEAD_SUPPORT_HORIZONTAL_POSITION = "headSupportHorizontalPosition";
+ public static final String KEY_HEAD_SUPPORT_VERTICAL_POSITION = "headSupportVerticalPosition";
+ public static final String KEY_MASSAGE_ENABLED = "massageEnabled";
+ public static final String KEY_MASSAGE_MODE = "massageMode";
+ public static final String KEY_MASSAGE_CUSHION_FIRMNESS = "massageCushionFirmness";
+ public static final String KEY_MEMORY = "memory";
+
+ /**
+ * Constructs a new SeatControlData object
+ */
+ public SeatControlData() {
+ }
+
+ /**
+ * <p>Constructs a new SeatControlData object indicated by the Hashtable parameter
+ * </p>
+ *
+ * @param hash The Hashtable to use
+ */
+ public SeatControlData(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Constructs a newly allocated SeatControlData object
+ * @param id type of SupportedSeat.
+ */
+ public SeatControlData(@NonNull SupportedSeat id) {
+ this();
+ setId(id);
+ }
+
+ /**
+ * Sets the id portion of the SeatControlData class
+ *
+ * @param id
+ */
+ public void setId(@NonNull SupportedSeat id) {
+ setValue(KEY_ID, id);
+ }
+
+ /**
+ * Gets the id portion of the SeatControlData class
+ *
+ * @return SupportedSeat.
+ */
+ public SupportedSeat getId() {
+ return (SupportedSeat) getObject(SupportedSeat.class, KEY_ID);
+ }
+
+ /**
+ * Sets the heatingEnabled portion of the SeatControlData class
+ *
+ * @param heatingEnabled
+ */
+ public void setHeatingEnabled(Boolean heatingEnabled) {
+ setValue(KEY_HEATING_ENABLED, heatingEnabled);
+ }
+
+ /**
+ * Gets the heatingEnabled portion of the SeatControlData class
+ *
+ * @return Boolean.
+ */
+ public Boolean getHeatingEnabled() {
+ return getBoolean(KEY_HEATING_ENABLED);
+ }
+
+ /**
+ * Sets the coolingEnabled portion of the SeatControlData class
+ *
+ * @param coolingEnabled
+ */
+ public void setCoolingEnabled(Boolean coolingEnabled) {
+ setValue(KEY_COOLING_ENABLED, coolingEnabled);
+ }
+
+ /**
+ * Gets the coolingEnabled portion of the SeatControlData class
+ *
+ * @return Boolean.
+ */
+ public Boolean getCoolingEnabled() {
+ return getBoolean(KEY_COOLING_ENABLED);
+ }
+
+ /**
+ * Sets the heatingLevel portion of the SeatControlData class
+ *
+ * @param heatingLevel
+ */
+ public void setHeatingLevel(Integer heatingLevel) {
+ setValue(KEY_HEATING_LEVEL, heatingLevel);
+ }
+
+ /**
+ * Gets the heatingLevel portion of the SeatControlData class
+ *
+ * @return Integer
+ */
+ public Integer getHeatingLevel() {
+ return getInteger(KEY_HEATING_LEVEL);
+ }
+
+ /**
+ * Sets the coolingLevel portion of the SeatControlData class
+ *
+ * @param coolingLevel
+ */
+ public void setCoolingLevel(Integer coolingLevel) {
+ setValue(KEY_COOLING_LEVEL, coolingLevel);
+ }
+
+ /**
+ * Gets the coolingLevel portion of the SeatControlData class
+ *
+ * @return Integer
+ */
+ public Integer getCoolingLevel() {
+ return getInteger(KEY_COOLING_LEVEL);
+ }
+
+ /**
+ * Sets the horizontalPosition portion of the SeatControlData class
+ *
+ * @param horizontalPosition
+ */
+ public void setHorizontalPosition(Integer horizontalPosition) {
+ setValue(KEY_HORIZONTAL_POSITION, horizontalPosition);
+ }
+
+ /**
+ * Gets the horizontalPosition portion of the SeatControlData class
+ *
+ * @return Integer
+ */
+ public Integer getHorizontalPosition() {
+ return getInteger(KEY_HORIZONTAL_POSITION);
+ }
+
+ /**
+ * Sets the verticalPosition portion of the SeatControlData class
+ *
+ * @param verticalPosition
+ */
+ public void setVerticalPosition(Integer verticalPosition) {
+ setValue(KEY_VERTICAL_POSITION, verticalPosition);
+ }
+
+ /**
+ * Gets the verticalPosition portion of the SeatControlData class
+ *
+ * @return Integer
+ */
+ public Integer getVerticalPosition() {
+ return getInteger(KEY_VERTICAL_POSITION);
+ }
+
+ /**
+ * Sets the frontVerticalPosition portion of the SeatControlData class
+ *
+ * @param frontVerticalPosition
+ */
+ public void setFrontVerticalPosition(Integer frontVerticalPosition) {
+ setValue(KEY_FRONT_VERTICAL_POSITION, frontVerticalPosition);
+ }
+
+ /**
+ * Gets the frontVerticalPosition portion of the SeatControlData class
+ *
+ * @return Integer
+ */
+ public Integer getFrontVerticalPosition() {
+ return getInteger(KEY_FRONT_VERTICAL_POSITION);
+ }
+
+ /**
+ * Sets the backVerticalPosition portion of the SeatControlData class
+ *
+ * @param backVerticalPosition
+ */
+ public void setBackVerticalPosition(Integer backVerticalPosition) {
+ setValue(KEY_BACK_VERTICAL_POSITION, backVerticalPosition);
+ }
+
+ /**
+ * Gets the backVerticalPosition portion of the SeatControlData class
+ *
+ * @return Integer
+ */
+ public Integer getBackVerticalPosition() {
+ return getInteger(KEY_BACK_VERTICAL_POSITION);
+ }
+
+ /**
+ * Sets the backTiltAngle portion of the SeatControlData class
+ *
+ * @param backTiltAngle
+ */
+ public void setBackTiltAngle(Integer backTiltAngle) {
+ setValue(KEY_BACK_TILT_ANGLE, backTiltAngle);
+ }
+
+ /**
+ * Gets the backTiltAngle portion of the SeatControlData class
+ *
+ * @return Integer
+ */
+ public Integer getBackTiltAngle() {
+ return getInteger(KEY_BACK_TILT_ANGLE);
+ }
+
+ /**
+ * Sets the headSupportHorizontalPosition portion of the SeatControlData class
+ *
+ * @param headSupportHorizontalPosition
+ */
+ public void setHeadSupportHorizontalPosition(Integer headSupportHorizontalPosition) {
+ setValue(KEY_HEAD_SUPPORT_HORIZONTAL_POSITION, headSupportHorizontalPosition);
+ }
+
+ /**
+ * Gets the headSupportHorizontalPosition portion of the SeatControlData class
+ *
+ * @return Integer
+ */
+ public Integer getHeadSupportHorizontalPosition() {
+ return getInteger(KEY_HEAD_SUPPORT_HORIZONTAL_POSITION);
+ }
+
+ /**
+ * Sets the headSupportVerticalPosition portion of the SeatControlData class
+ *
+ * @param headSupportVerticalPosition
+ */
+ public void setHeadSupportVerticalPosition(Integer headSupportVerticalPosition) {
+ setValue(KEY_HEAD_SUPPORT_VERTICAL_POSITION, headSupportVerticalPosition);
+ }
+
+ /**
+ * Gets the headSupportVerticalPosition portion of the SeatControlData class
+ *
+ * @return Integer
+ */
+ public Integer getHeadSupportVerticalPosition() {
+ return getInteger(KEY_HEAD_SUPPORT_VERTICAL_POSITION);
+ }
+
+ /**
+ * Sets the massageEnabled portion of the SeatControlData class
+ *
+ * @param massageEnabled
+ */
+ public void setMassageEnabled(Boolean massageEnabled) {
+ setValue(KEY_MASSAGE_ENABLED, massageEnabled);
+ }
+
+ /**
+ * Gets the massageEnabled portion of the SeatControlData class
+ *
+ * @return Boolean.
+ */
+ public Boolean getMassageEnabled() {
+ return getBoolean(KEY_MASSAGE_ENABLED);
+ }
+
+ /**
+ * Gets the List<MassageModeData> portion of the SeatControlData class
+ *
+ * @return List<MassageModeData>.
+ */
+ @SuppressWarnings("unchecked")
+ public List<MassageModeData> getMassageMode() {
+ return (List<MassageModeData>) getObject(MassageModeData.class, KEY_MASSAGE_MODE);
+ }
+
+ /**
+ * Sets the massageMode portion of the SeatControlData class
+ *
+ * @param massageMode
+ */
+ public void setMassageMode(List<MassageModeData> massageMode) {
+ setValue(KEY_MASSAGE_MODE, massageMode);
+ }
+
+ /**
+ * Gets the List<MassageCushionFirmness> portion of the SeatControlData class
+ *
+ * @return List<MassageCushionFirmness>.
+ */
+ @SuppressWarnings("unchecked")
+ public List<MassageCushionFirmness> getMassageCushionFirmness() {
+ return (List<MassageCushionFirmness>) getObject(MassageCushionFirmness.class, KEY_MASSAGE_CUSHION_FIRMNESS);
+ }
+
+ /**
+ * Sets the massageCushionFirmness portion of the SeatControlData class
+ *
+ * @param massageCushionFirmness
+ */
+ public void setMassageCushionFirmness(List<MassageCushionFirmness> massageCushionFirmness) {
+ setValue(KEY_MASSAGE_CUSHION_FIRMNESS, massageCushionFirmness);
+ }
+
+ /**
+ * Sets the memory portion of the SeatControlData class
+ *
+ * @param memory
+ */
+ public void setMemory(SeatMemoryAction memory) {
+ setValue(KEY_MEMORY, memory);
+ }
+
+ /**
+ * Gets the memory portion of the SeatControlData class
+ *
+ * @return SeatMemoryAction.
+ */
+ @SuppressWarnings("unchecked")
+ public SeatMemoryAction getMemory() {
+ return (SeatMemoryAction) getObject(SeatMemoryAction.class, KEY_MEMORY);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SeatMemoryAction.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SeatMemoryAction.java
new file mode 100644
index 000000000..a8673a9eb
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SeatMemoryAction.java
@@ -0,0 +1,95 @@
+package com.smartdevicelink.proxy.rpc;
+
+import android.support.annotation.NonNull;
+
+import com.smartdevicelink.proxy.RPCStruct;
+import com.smartdevicelink.proxy.rpc.enums.SeatMemoryActionType;
+
+import java.util.Hashtable;
+
+public class SeatMemoryAction extends RPCStruct {
+ public static final String KEY_ID = "id";
+ public static final String KEY_LABEL = "label";
+ public static final String KEY_ACTION = "action";
+
+ /**
+ * Constructs a new SeatMemoryAction object
+ */
+ public SeatMemoryAction() {
+ }
+
+ /**
+ * <p>Constructs a new SeatMemoryAction object indicated by the Hashtable parameter
+ * </p>
+ *
+ * @param hash The Hashtable to use
+ */
+ public SeatMemoryAction(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Constructs a newly allocated SeatMemoryAction object
+ * @param id Min: 0 Max: 10
+ * @param action type of SeatMemoryActionType.
+ */
+ public SeatMemoryAction(@NonNull Integer id, @NonNull SeatMemoryActionType action) {
+ this();
+ setId(id);
+ setAction(action);
+ }
+
+ /**
+ * Sets the id portion of the SeatMemoryAction class
+ *
+ * @param id
+ */
+ public void setId(@NonNull Integer id) {
+ setValue(KEY_ID, id);
+ }
+
+ /**
+ * Gets the id portion of the SeatMemoryAction class
+ *
+ * @return Integer
+ */
+ public Integer getId() {
+ return getInteger(KEY_ID);
+ }
+
+ /**
+ * Sets the label portion of the SeatMemoryAction class
+ *
+ * @param label
+ */
+ public void setLabel(String label) {
+ setValue(KEY_LABEL, label);
+ }
+
+ /**
+ * Gets the label portion of the SeatMemoryAction class
+ *
+ * @return String
+ */
+ public String getLabel() {
+ return getString(KEY_LABEL);
+ }
+
+ /**
+ * Sets the action portion of the SeatMemoryAction class
+ *
+ * @param action
+ */
+ public void setAction(@NonNull SeatMemoryActionType action) {
+ setValue(KEY_ACTION, action);
+ }
+
+ /**
+ * Gets the action portion of the SeatMemoryAction class
+ *
+ * @return SeatMemoryActionType.
+ */
+ public SeatMemoryActionType getAction() {
+ return (SeatMemoryActionType) getObject(SeatMemoryActionType.class, KEY_ACTION);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetDisplayLayout.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetDisplayLayout.java
index d9bb2ec69..2bff6d1ec 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetDisplayLayout.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetDisplayLayout.java
@@ -30,6 +30,23 @@ import java.util.Hashtable;
* <td>maxlength: 500</td>
* <td>SmartDeviceLink 2.0</td>
* </tr>
+ * <tr>
+ * <td>dayColorScheme</td>
+ * <td>TemplateColorScheme</td>
+ * <td>The color scheme that is used for day.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
+ *
+ * <tr>
+ * <td>nightColorScheme</td>
+ * <td>TemplateColorScheme</td>
+ * <td>The color scheme that is used for night.</td>
+ * <td>N</td>
+ * <td></td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
*
* </table>
*<p><b>Response </b></p>
@@ -46,6 +63,8 @@ import java.util.Hashtable;
*/
public class SetDisplayLayout extends RPCRequest {
public static final String KEY_DISPLAY_LAYOUT = "displayLayout";
+ public static final String KEY_DAY_COLOR_SCHEME = "dayColorScheme";
+ public static final String KEY_NIGHT_COLOR_SCHEME = "nightColorScheme";
/**
* Constructs a new SetDisplayLayout object
*/
@@ -94,4 +113,48 @@ public class SetDisplayLayout extends RPCRequest {
public String getDisplayLayout() {
return getString(KEY_DISPLAY_LAYOUT);
}
+
+ /**
+ * Gets the color scheme that is currently used for day
+ *
+ * @return TemplateColorScheme - a TemplateColorScheme object representing the colors that are used
+ * for day color scheme
+ * @since SmartDeviceLink 5.0
+ */
+ public TemplateColorScheme getDayColorScheme(){
+ return (TemplateColorScheme) getObject(TemplateColorScheme.class, KEY_DAY_COLOR_SCHEME);
+ }
+
+ /**
+ * Sets the color scheme that is intended to be used for day
+ *
+ * @param templateColorScheme a TemplateColorScheme object representing the colors that will be
+ * used for day color scheme
+ * @since SmartDeviceLink 5.0
+ */
+ public void setDayColorScheme(TemplateColorScheme templateColorScheme){
+ setParameters(KEY_DAY_COLOR_SCHEME, templateColorScheme);
+ }
+
+ /**
+ * Gets the color scheme that is currently used for night
+ *
+ * @return TemplateColorScheme - a TemplateColorScheme object representing the colors that are used
+ * for night color scheme
+ * @since SmartDeviceLink 5.0
+ */
+ public TemplateColorScheme getNightColorScheme(){
+ return (TemplateColorScheme) getObject(TemplateColorScheme.class, KEY_NIGHT_COLOR_SCHEME);
+ }
+
+ /**
+ * Sets the color scheme that is intended to be used for night
+ *
+ * @param templateColorScheme a TemplateColorScheme object representing the colors that will be
+ * used for night color scheme
+ * @since SmartDeviceLink 5.0
+ */
+ public void setNightColorScheme(TemplateColorScheme templateColorScheme){
+ setParameters(KEY_NIGHT_COLOR_SCHEME, templateColorScheme);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetMediaClockTimer.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetMediaClockTimer.java
index 4ec73b9d7..8dd53449d 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetMediaClockTimer.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SetMediaClockTimer.java
@@ -4,6 +4,7 @@ import android.support.annotation.NonNull;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.proxy.RPCRequest;
+import com.smartdevicelink.proxy.rpc.enums.AudioStreamingIndicator;
import com.smartdevicelink.proxy.rpc.enums.UpdateMode;
import java.util.Hashtable;
@@ -54,6 +55,13 @@ import java.util.Hashtable;
* <td>SmartDeviceLink 1.0</td>
* </tr>
* <tr>
+ * <td>audioStreamingIndicator</td>
+ * <td>AudioStreamingIndicator</td>
+ * <td></td>
+ * <td>N</td>
+ * <td></td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
*
* </table>
*
@@ -76,6 +84,7 @@ public class SetMediaClockTimer extends RPCRequest {
public static final String KEY_START_TIME = "startTime";
public static final String KEY_END_TIME = "endTime";
public static final String KEY_UPDATE_MODE = "updateMode";
+ public static final String KEY_AUDIO_STREAMING_INDICATOR = "audioStreamingIndicator";
/**
* Constructs a new SetMediaClockTimer object
*/
@@ -168,4 +177,20 @@ public class SetMediaClockTimer extends RPCRequest {
public void setUpdateMode( @NonNull UpdateMode updateMode ) {
setParameters(KEY_UPDATE_MODE, updateMode);
}
+
+ /**
+ * Gets the playback status of a media app
+ *
+ * @return AudioStreamingIndicator - a Enumeration value
+ */
+ public AudioStreamingIndicator getAudioStreamingIndicator() {
+ return (AudioStreamingIndicator) getObject(AudioStreamingIndicator.class, KEY_AUDIO_STREAMING_INDICATOR);
+ }
+
+ /**
+ * Sets the playback status of a media app
+ */
+ public void setAudioStreamingIndicator(AudioStreamingIndicator audioStreamingIndicator ) {
+ setParameters(KEY_AUDIO_STREAMING_INDICATOR, audioStreamingIndicator);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SingleTireStatus.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SingleTireStatus.java
index 6aa49ad28..e3a63c276 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SingleTireStatus.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SingleTireStatus.java
@@ -4,6 +4,7 @@ import android.support.annotation.NonNull;
import com.smartdevicelink.proxy.RPCStruct;
import com.smartdevicelink.proxy.rpc.enums.ComponentVolumeStatus;
+import com.smartdevicelink.proxy.rpc.enums.TPMS;
import java.util.Hashtable;
@@ -25,11 +26,27 @@ import java.util.Hashtable;
* </td>
* <td>SmartDeviceLink 2.0</td>
* </tr>
+ * <tr>
+ * <td>tpms</td>
+ * <td>TPMS</td>
+ * <td>The status of TPMS according to the particular tire.
+ * See {@linkplain com.smartdevicelink.proxy.rpc.enums.TPMS}
+ * </td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
+ * <tr>
+ * <td>pressure</td>
+ * <td>Float</td>
+ * <td>The pressure value of the particular tire in kilo pascal.</td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
* </table>
* @since SmartDeviceLink 2.0
*/
public class SingleTireStatus extends RPCStruct {
public static final String KEY_STATUS = "status";
+ public static final String KEY_TPMS = "tpms";
+ public static final String KEY_PRESSURE = "pressure";
/**
* Constructs a newly allocated SingleTireStatus object
@@ -54,18 +71,44 @@ public class SingleTireStatus extends RPCStruct {
}
/**
- * set the volume status of a single tire
- * @param status the volume status of a single tire
+ * set the volume status of a single tire
+ * @param status the volume status of a single tire
*/
public void setStatus(@NonNull ComponentVolumeStatus status) {
setValue(KEY_STATUS, status);
}
/**
- * get the volume status of a single tire
- * @return the volume status of a single tire
+ * get the volume status of a single tire
+ * @return the volume status of a single tire
*/
public ComponentVolumeStatus getStatus() {
return (ComponentVolumeStatus) getObject(ComponentVolumeStatus.class, KEY_STATUS);
}
+
+ /**
+ * Set the status of TPMS according to the particular tire.
+ * @param tpms The status of TPMS
+ */
+ public void setTPMS(@NonNull TPMS tpms) { setValue(KEY_TPMS, tpms); }
+
+ /**
+ * Get the status of TPMS according to the particular tire.
+ * @return the TPMS status
+ */
+ public TPMS getTPMS() {
+ return (TPMS) getObject(TPMS.class, KEY_TPMS);
+ }
+
+ /**
+ * @param pressure The pressure value of the particular tire in kilo pascal.
+ */
+ public void setPressure(@NonNull Float pressure) { setValue(KEY_PRESSURE, pressure); }
+
+ /**
+ * @return the pressure value of the particular tire in kilo pascal.
+ */
+ public Float getPressure() {
+ return getFloat(KEY_PRESSURE);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SisData.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SisData.java
new file mode 100644
index 000000000..13b30e37d
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SisData.java
@@ -0,0 +1,123 @@
+package com.smartdevicelink.proxy.rpc;
+
+import com.smartdevicelink.proxy.RPCStruct;
+
+import java.util.Hashtable;
+
+public class SisData extends RPCStruct {
+ public static final String KEY_STATION_SHORT_NAME = "stationShortName";
+ public static final String KEY_STATION_ID_NUMBER = "stationIDNumber";
+ public static final String KEY_STATION_LONG_NAME = "stationLongName";
+ public static final String KEY_STATION_LOCATION = "stationLocation";
+ public static final String KEY_STATION_MESSAGE = "stationMessage";
+
+ /**
+ * Constructs a new SisData object
+ */
+ public SisData() {
+ }
+
+ /**
+ * <p>Constructs a new SisData object indicated by the Hashtable parameter
+ * </p>
+ *
+ * @param hash The Hashtable to use
+ */
+ public SisData(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Sets the stationShortName portion of the SisData class
+ *
+ * @param stationShortName Identifies the 4-alpha-character station call sign plus an optional (-FM) extension.
+ */
+ public void setStationShortName(String stationShortName) {
+ setValue(KEY_STATION_SHORT_NAME, stationShortName);
+ }
+
+ /**
+ * Gets the stationShortName portion of the SisData class
+ *
+ * @return String - Identifies the 4-alpha-character station call sign plus an optional (-FM) extension.
+ */
+ public String getStationShortName() {
+ return getString(KEY_STATION_SHORT_NAME);
+ }
+
+ /**
+ * Sets the stationIDNumber portion of the SisData class
+ *
+ * @param stationIDNumber
+ */
+ public void setStationIDNumber(StationIDNumber stationIDNumber) {
+ setValue(KEY_STATION_ID_NUMBER, stationIDNumber);
+ }
+
+ /**
+ * Gets the stationIDNumber portion of the SisData class
+ *
+ * @return StationIDNumber.
+ */
+ @SuppressWarnings("unchecked")
+ public StationIDNumber getStationIDNumber() {
+ return (StationIDNumber) getObject(StationIDNumber.class, KEY_STATION_ID_NUMBER);
+ }
+
+ /**
+ * Sets the stationLongName portion of the SisData class
+ *
+ * @param stationLongName Identifies the station call sign or other identifying information in the long format.
+ */
+ public void setStationLongName(String stationLongName) {
+ setValue(KEY_STATION_LONG_NAME, stationLongName);
+ }
+
+ /**
+ * Gets the stationLongName portion of the SisData class
+ *
+ * @return String - Identifies the station call sign or other identifying information in the long format.
+ */
+ public String getStationLongName() {
+ return getString(KEY_STATION_LONG_NAME);
+ }
+
+ /**
+ * Sets the stationLocation portion of the SisData class
+ *
+ * @param stationLocation Provides the 3-dimensional geographic station location.
+ */
+ public void setStationLocation(GPSData stationLocation) {
+ setValue(KEY_STATION_LOCATION, stationLocation);
+ }
+
+ /**
+ * Gets the stationLocation portion of the SisData class
+ *
+ * @return GPSData - Provides the 3-dimensional geographic station location.
+ */
+ @SuppressWarnings("unchecked")
+ public GPSData getStationLocation() {
+ return (GPSData) getObject(GPSData.class, KEY_STATION_LOCATION);
+ }
+
+ /**
+ * Sets the stationMessage portion of the SisData class
+ *
+ * @param stationMessage May be used to convey textual information of general interest to the consumer such as weather forecasts or public service announcements.
+ * Includes a high priority delivery feature to convey emergencies that may be in the listening area.
+ */
+ public void setStationMessage(String stationMessage) {
+ setValue(KEY_STATION_MESSAGE, stationMessage);
+ }
+
+ /**
+ * Gets the stationMessage portion of the SisData class
+ *
+ * @return String - May be used to convey textual information of general interest to the consumer such as weather forecasts or public service announcements.
+ * Includes a high priority delivery feature to convey emergencies that may be in the listening area.
+ */
+ public String getStationMessage() {
+ return getString(KEY_STATION_MESSAGE);
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/StationIDNumber.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/StationIDNumber.java
new file mode 100644
index 000000000..a8e926a2b
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/StationIDNumber.java
@@ -0,0 +1,54 @@
+package com.smartdevicelink.proxy.rpc;
+
+import com.smartdevicelink.proxy.RPCStruct;
+
+import java.util.Hashtable;
+
+public class StationIDNumber extends RPCStruct {
+ public static final String KEY_COUNTRY_CODE = "countryCode";
+ public static final String KEY_FCC_FACILITY_ID = "fccFacilityId";
+
+ public StationIDNumber() {
+ }
+
+ public StationIDNumber(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Sets the countryCode portion of the StationIDNumber class
+ *
+ * @param countryCode Binary Representation of ITU Country Code. USA Code is 001.
+ */
+ public void setCountryCode(Integer countryCode) {
+ setValue(KEY_COUNTRY_CODE, countryCode);
+ }
+
+ /**
+ * Gets the countryCode portion of the StationIDNumber class
+ *
+ * @return Integer - Binary Representation of ITU Country Code. USA Code is 001.
+ */
+ public Integer getCountryCode() {
+ return getInteger(KEY_COUNTRY_CODE);
+ }
+
+ /**
+ * Sets the fccFacilityId portion of the StationIDNumber class
+ *
+ * @param fccFacilityId Binary representation of unique facility ID assigned by the FCC; FCC controlled for U.S. territory.
+ */
+ public void setFccFacilityId(Integer fccFacilityId) {
+ setValue(KEY_FCC_FACILITY_ID, fccFacilityId);
+ }
+
+ /**
+ * Gets the fccFacilityId portion of the StationIDNumber class
+ *
+ * @return Integer - Binary representation of unique facility ID assigned by the FCC; FCC controlled for U.S. territory.
+ */
+ public Integer getFccFacilityId() {
+ return getInteger(KEY_FCC_FACILITY_ID);
+ }
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SubscribeVehicleData.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SubscribeVehicleData.java
index ddbf54c4a..420d907b1 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SubscribeVehicleData.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SubscribeVehicleData.java
@@ -163,6 +163,14 @@ import java.util.Hashtable;
* <td>SmartDeviceLink 2.0 </td>
* </tr>
* <tr>
+ * <td>engineOilLife</td>
+ * <td>Boolean</td>
+ * <td>The estimated percentage of remaining oil life of the engine</td>
+ * <td>N</td>
+ * <td>Subscribable</td>
+ * <td>SmartDeviceLink 5.0 </td>
+ * </tr>
+ * <tr>
* <td>accPedalPosition</td>
* <td>Boolean</td>
* <td>Accelerator pedal position (percentage depressed)</td>
@@ -218,6 +226,14 @@ import java.util.Hashtable;
* <td>Subscribable</td>
* <td>SmartDeviceLink 2.0 </td>
* </tr>
+ * <tr>
+ * <td>turnSignal</td>
+ * <td>Boolean</td>
+ * <td>@see TurnSignal</td>
+ * <td>N</td>
+ * <td>Subscribable</td>
+ * <td>SmartDeviceLink 5.0 </td>
+ * </tr>
* </table>
*
* <p> <b>Response</b></p>
@@ -244,6 +260,7 @@ public class SubscribeVehicleData extends RPCRequest {
public static final String KEY_PRNDL = "prndl";
public static final String KEY_TIRE_PRESSURE = "tirePressure";
public static final String KEY_ENGINE_TORQUE = "engineTorque";
+ public static final String KEY_ENGINE_OIL_LIFE = "engineOilLife";
public static final String KEY_ODOMETER = "odometer";
public static final String KEY_GPS = "gps";
public static final String KEY_FUEL_LEVEL_STATE = "fuelLevel_State";
@@ -262,6 +279,9 @@ public class SubscribeVehicleData extends RPCRequest {
public static final String KEY_CLUSTER_MODE_STATUS = "clusterModeStatus";
public static final String KEY_MY_KEY = "myKey";
public static final String KEY_SPEED = "speed";
+ public static final String KEY_FUEL_RANGE = "fuelRange";
+ public static final String KEY_TURN_SIGNAL = "turnSignal";
+ public static final String KEY_ELECTRONIC_PARK_BRAKE_STATUS = "electronicParkBrakeStatus";
/**
* Constructs a new SubscribeVehicleData object
@@ -640,28 +660,49 @@ public class SubscribeVehicleData extends RPCRequest {
/**
* Sets a boolean value. If true, subscribes Engine Torque data
- *
+ *
* @param engineTorque
* a boolean value
*/
- public void setEngineTorque(Boolean engineTorque) {
+ public void setEngineTorque(Boolean engineTorque) {
setParameters(KEY_ENGINE_TORQUE, engineTorque);
- }
+ }
+
+ /**
+ * Gets a boolean value. If true, means the Engine Oil Life data has been
+ * subscribed.
+ *
+ * @return Boolean -a Boolean value. If true, means the Engine Oil Life data
+ * has been subscribed.
+ */
+ public Boolean getEngineOilLife() {
+ return getBoolean(KEY_ENGINE_OIL_LIFE);
+ }
+
+ /**
+ * Sets a boolean value. If true, subscribes Engine Oil Life data
+ *
+ * @param engineOilLife
+ * a boolean value
+ */
+ public void setEngineOilLife(Boolean engineOilLife) {
+ setParameters(KEY_ENGINE_OIL_LIFE, engineOilLife);
+ }
/**
* Gets a boolean value. If true, means the Engine Torque data has been
* subscribed.
- *
+ *
* @return Boolean -a Boolean value. If true, means the Engine Torque data
* has been subscribed.
*/
- public Boolean getEngineTorque() {
- return getBoolean(KEY_ENGINE_TORQUE);
- }
+ public Boolean getEngineTorque() {
+ return getBoolean(KEY_ENGINE_TORQUE);
+ }
/**
* Sets a boolean value. If true, subscribes accPedalPosition data
- *
+ *
* @param accPedalPosition
* a boolean value
*/
@@ -716,6 +757,55 @@ public class SubscribeVehicleData extends RPCRequest {
}
public Boolean getMyKey() {
return getBoolean(KEY_MY_KEY);
- }
-
+ }
+
+ /**
+ * Sets a boolean value. If true, subscribes fuelRange data
+ *
+ * @param fuelRange
+ * a boolean value
+ */
+ public void setFuelRange(Boolean fuelRange) {
+ setParameters(KEY_FUEL_RANGE, fuelRange);
+ }
+
+ /**
+ * Gets a boolean value. If true, means the Fuel Range data has been
+ * subscribed.
+ *
+ * @return Boolean -a Boolean value. If true, means the Fuel Range data
+ * has been subscribed.
+ *
+ */
+ public Boolean getFuelRange() {
+ return getBoolean(KEY_FUEL_RANGE);
+ }
+
+ /**
+ * Sets a boolean value. If true, subscribes turnSignal data
+ * @param turnSignal a boolean value
+ */
+ public void setTurnSignal(Boolean turnSignal) { setParameters(KEY_TURN_SIGNAL, turnSignal); }
+
+ /**
+ * Gets a boolean value. If true, means the turnSignal data has been subscribed.
+ * @return a Boolean value.
+ */
+ public Boolean getTurnSignal() { return getBoolean(KEY_TURN_SIGNAL); }
+
+ /**
+ * Sets a boolean value. If true, subscribes electronicParkBrakeStatus data
+ * @param electronicParkBrakeStatus a boolean value
+ */
+ public void setElectronicParkBrakeStatus(boolean electronicParkBrakeStatus){
+ setParameters(KEY_ELECTRONIC_PARK_BRAKE_STATUS, electronicParkBrakeStatus);
+ }
+
+ /**
+ * Gets a boolean value. If true, means the electronicParkBrakeStatus data has been subscribed.
+ * @return a Boolean value.
+ */
+ public Boolean getElectronicParkBrakeStatus(){
+ return getBoolean(KEY_ELECTRONIC_PARK_BRAKE_STATUS);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SubscribeVehicleDataResponse.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SubscribeVehicleDataResponse.java
index 86f23c69b..47d32936d 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SubscribeVehicleDataResponse.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SubscribeVehicleDataResponse.java
@@ -21,6 +21,7 @@ public class SubscribeVehicleDataResponse extends RPCResponse {
public static final String KEY_PRNDL = "prndl";
public static final String KEY_TIRE_PRESSURE = "tirePressure";
public static final String KEY_ENGINE_TORQUE = "engineTorque";
+ public static final String KEY_ENGINE_OIL_LIFE = "engineOilLife";
public static final String KEY_ODOMETER = "odometer";
public static final String KEY_GPS = "gps";
public static final String KEY_FUEL_LEVEL_STATE = "fuelLevel_State";
@@ -38,6 +39,9 @@ public class SubscribeVehicleDataResponse extends RPCResponse {
public static final String KEY_EMERGENCY_EVENT = "emergencyEvent";
public static final String KEY_CLUSTER_MODE_STATUS = "clusterModeStatus";
public static final String KEY_MY_KEY = "myKey";
+ public static final String KEY_FUEL_RANGE = "fuelRange";
+ public static final String KEY_TURN_SIGNAL = "turnSignal";
+ public static final String KEY_ELECTRONIC_PARK_BRAKE_STATUS = "electronicParkBrakeStatus";
/**
* Constructs a new SubscribeVehicleDataResponse object
@@ -338,6 +342,21 @@ public class SubscribeVehicleDataResponse extends RPCResponse {
return (VehicleDataResult) getObject(VehicleDataResult.class, KEY_ENGINE_TORQUE);
}
/**
+ * Sets Engine Oil Life
+ * @param engineOilLife
+ */
+ public void setEngineOilLife(VehicleDataResult engineOilLife) {
+ setParameters(KEY_ENGINE_OIL_LIFE, engineOilLife);
+ }
+ /**
+ * Gets Engine Oil Life
+ * @return VehicleDataResult
+ */
+ @SuppressWarnings("unchecked")
+ public VehicleDataResult getEngineOilLife() {
+ return (VehicleDataResult) getObject(VehicleDataResult.class, KEY_ENGINE_OIL_LIFE);
+ }
+ /**
* Sets AccPedal Position
* @param accPedalPosition
*/
@@ -396,5 +415,55 @@ public class SubscribeVehicleDataResponse extends RPCResponse {
@SuppressWarnings("unchecked")
public VehicleDataResult getMyKey() {
return (VehicleDataResult) getObject(VehicleDataResult.class, KEY_MY_KEY);
- }
+ }
+
+ /**
+ * Sets Fuel Range
+ * @param fuelRange
+ */
+ public void setFuelRange(VehicleDataResult fuelRange) {
+ setParameters(KEY_FUEL_RANGE, fuelRange);
+ }
+
+ /**
+ * Gets Fuel Range
+ * @return VehicleDataResult
+ */
+ @SuppressWarnings("unchecked")
+ public VehicleDataResult getFuelRange() {
+ return (VehicleDataResult) getObject(VehicleDataResult.class, KEY_FUEL_RANGE);
+ }
+
+ /**
+ * Sets turnSignal
+ * @param turnSignal
+ */
+ public void setTurnSignal(VehicleDataResult turnSignal) {
+ setParameters(KEY_TURN_SIGNAL, turnSignal);
+ }
+
+ /**
+ * Gets turnSignal
+ * @return VehicleDataResult
+ */
+ @SuppressWarnings("unchecked")
+ public VehicleDataResult getTurnSignal() {
+ return (VehicleDataResult) getObject(VehicleDataResult.class, KEY_TURN_SIGNAL);
+ }
+
+ /**
+ * Sets electronicParkBrakeStatus
+ * @param electronicParkBrakeStatus
+ */
+ public void setElectronicParkBrakeStatus(VehicleDataResult electronicParkBrakeStatus){
+ setParameters(KEY_ELECTRONIC_PARK_BRAKE_STATUS, electronicParkBrakeStatus);
+ }
+
+ /**
+ * Gets electronicParkBrakeStatus
+ * @return VehicleDataResult
+ */
+ public VehicleDataResult getElectronicParkBrakeStatus(){
+ return (VehicleDataResult) getObject(VehicleDataResult.class, KEY_ELECTRONIC_PARK_BRAKE_STATUS);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SystemRequest.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SystemRequest.java
index 7c614c447..ee7dad05b 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SystemRequest.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/SystemRequest.java
@@ -29,7 +29,14 @@ import java.util.List;
* <td></td>
* <td>SmartDeviceLink 3.0 </td>
* </tr>
- *
+ * <tr>
+ * <td>requestSubType</td>
+ * <td>String</td>
+ * <td>This parameter is filled for supporting OEM proprietary data exchanges.</td>
+ * <td>N</td>
+ * <td>Max Length: 255</td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
* <tr>
* <td>fileName</td>
* <td>String</td>
@@ -48,6 +55,7 @@ import java.util.List;
public class SystemRequest extends RPCRequest {
public static final String KEY_FILE_NAME = "fileName";
public static final String KEY_REQUEST_TYPE = "requestType";
+ public static final String KEY_REQUEST_SUB_TYPE = "requestSubType";
public static final String KEY_DATA = "data";
/**
* Constructs a new SystemRequest object
@@ -98,4 +106,12 @@ public class SystemRequest extends RPCRequest {
public void setRequestType(@NonNull RequestType requestType) {
setParameters(KEY_REQUEST_TYPE, requestType);
}
+
+ public String getRequestSubType() {
+ return getString(KEY_REQUEST_SUB_TYPE);
+ }
+
+ public void setRequestSubType(String requestSubType) {
+ setParameters(KEY_REQUEST_SUB_TYPE, requestSubType);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/TemplateColorScheme.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/TemplateColorScheme.java
new file mode 100644
index 000000000..db915a4eb
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/TemplateColorScheme.java
@@ -0,0 +1,111 @@
+package com.smartdevicelink.proxy.rpc;
+
+import com.smartdevicelink.proxy.RPCStruct;
+import java.util.Hashtable;
+
+/**
+ * A color scheme for all display layout templates.
+ * <p><b> Parameter List</b></p>
+ * <table border="1" rules="all">
+ * <tr>
+ * <th>Name</th>
+ * <th>Type</th>
+ * <th>Description</th>
+ * <th>Reg.</th>
+ * <th>Version Available</th>
+ * </tr>
+ * <tr>
+ * <td>primaryColor</td>
+ * <td>RGBColor</td>
+ * <td>The primary "accent" color</td>
+ * <td>N</td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
+ * <tr>
+ * <td>secondaryColor</td>
+ * <td>RGBColor</td>
+ * <td>The secondary "accent" color</td>
+ * <td>N</td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
+ * <tr>
+ * <td>backgroundColor</td>
+ * <td>RGBColor</td>
+ * <td>The color of the background</td>
+ * <td>N</td>
+ * <td>SmartDeviceLink 5.0</td>
+ * </tr>
+ * </table>
+ * @since SmartDeviceLink 5.0
+ */
+public class TemplateColorScheme extends RPCStruct {
+
+ public static final String KEY_PRIMARY_COLOR = "primaryColor";
+ public static final String KEY_SECONDARY_COLOR = "secondaryColor";
+ public static final String KEY_BACKGROUND_COLOR = "backgroundColor";
+
+ /**
+ * Constructs a new TemplateColorScheme object
+ */
+ public TemplateColorScheme(){
+ }
+
+ /**
+ * Constructs a new TemplateColorScheme object indicated by the Hashtable parameter
+ * @param hash The Hashtable to use
+ */
+ public TemplateColorScheme(Hashtable<String, Object> hash) {
+ super(hash);
+ }
+
+ /**
+ * Sets the primaryColor of the scheme
+ * @param color an RGBColor object representing the primaryColor
+ */
+ public void setPrimaryColor(RGBColor color) {
+ setValue(KEY_PRIMARY_COLOR, color);
+ }
+
+ /**
+ * Gets the primaryColor of the scheme
+ * @return an RGBColor object representing the primaryColor
+ */
+ public RGBColor getPrimaryColor() {
+ return (RGBColor) getObject(RGBColor.class, KEY_PRIMARY_COLOR);
+ }
+
+ /**
+ * Sets the secondaryColor of the scheme
+ * @param color an RGBColor object representing the secondaryColor
+ */
+ public void setSecondaryColor(RGBColor color) {
+ setValue(KEY_SECONDARY_COLOR, color);
+ }
+
+ /**
+ * Gets the secondaryColor of the scheme
+ * @return an RGBColor object representing the secondaryColor
+ */
+ public RGBColor getSecondaryColor() {
+ return (RGBColor) getObject(RGBColor.class, KEY_SECONDARY_COLOR);
+ }
+
+ /**
+ * Sets the backgroundColor of the scheme
+ * @param color an RGBColor object representing the backgroundColor
+ */
+ public void setBackgroundColor(RGBColor color) {
+ setValue(KEY_BACKGROUND_COLOR, color);
+ }
+
+ /**
+ * Gets the backgroundColor of the scheme
+ * @return an RGBColor object representing the backgroundColor
+ */
+ public RGBColor getBackgroundColor() {
+ return (RGBColor) getObject(RGBColor.class, KEY_BACKGROUND_COLOR);
+ }
+}
+
+
+
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnregisterAppInterface.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnregisterAppInterface.java
index a00e375bd..b832d81c4 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnregisterAppInterface.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnregisterAppInterface.java
@@ -36,4 +36,4 @@ public class UnregisterAppInterface extends RPCRequest {
public UnregisterAppInterface(Hashtable<String, Object> hash) {
super(hash);
}
-} \ No newline at end of file
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnsubscribeVehicleData.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnsubscribeVehicleData.java
index 8a50ec286..ca2439b9e 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnsubscribeVehicleData.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnsubscribeVehicleData.java
@@ -158,6 +158,14 @@ import com.smartdevicelink.proxy.RPCRequest;
* <td>SmartDeviceLink 2.0 </td>
* </tr>
* <tr>
+ * <td>engineOilLife</td>
+ * <td>Boolean</td>
+ * <td>The estimated percentage of remaining oil life of the engine</td>
+ * <td>N</td>
+ * <td>Subscribable</td>
+ * <td>SmartDeviceLink 5.0 </td>
+ * </tr>
+ * <tr>
* <td>accPedalPosition</td>
* <td>Boolean</td>
* <td>Accelerator pedal position (percentage depressed)</td>
@@ -213,6 +221,14 @@ import com.smartdevicelink.proxy.RPCRequest;
* <td>Subscribable</td>
* <td>SmartDeviceLink 2.0 </td>
* </tr>
+ * <tr>
+ * <td>turnSignal</td>
+ * <td>Boolean</td>
+ * <td>@see TurnSignal</td>
+ * <td>N</td>
+ * <td>Subscribable</td>
+ * <td>SmartDeviceLink 5.0 </td>
+ * </tr>
* </table>
* <p><b> Response</b></p>
* <p><b>Non-default Result Codes:</b></p>
@@ -238,6 +254,7 @@ public class UnsubscribeVehicleData extends RPCRequest {
public static final String KEY_PRNDL = "prndl";
public static final String KEY_TIRE_PRESSURE = "tirePressure";
public static final String KEY_ENGINE_TORQUE = "engineTorque";
+ public static final String KEY_ENGINE_OIL_LIFE = "engineOilLife";
public static final String KEY_ODOMETER = "odometer";
public static final String KEY_GPS = "gps";
public static final String KEY_FUEL_LEVEL_STATE = "fuelLevel_State";
@@ -255,7 +272,9 @@ public class UnsubscribeVehicleData extends RPCRequest {
public static final String KEY_EMERGENCY_EVENT = "emergencyEvent";
public static final String KEY_CLUSTER_MODE_STATUS = "clusterModeStatus";
public static final String KEY_MY_KEY = "myKey";
-
+ public static final String KEY_FUEL_RANGE = "fuelRange";
+ public static final String KEY_TURN_SIGNAL = "turnSignal";
+ public static final String KEY_ELECTRONIC_PARK_BRAKE_STATUS = "electronicParkBrakeStatus";
/**
* Constructs a new UnsubscribeVehicleData object
@@ -634,24 +653,46 @@ public class UnsubscribeVehicleData extends RPCRequest {
/**
* Sets a boolean value. If true, unsubscribes Engine Torque data
- *
+ *
* @param engineTorque
* a boolean value
*/
- public void setEngineTorque(Boolean engineTorque) {
+ public void setEngineTorque(Boolean engineTorque) {
setParameters(KEY_ENGINE_TORQUE, engineTorque);
- }
+ }
/**
* Gets a boolean value. If true, means the Engine Torque data has been
* unsubscribed.
- *
+ *
* @return Boolean -a Boolean value. If true, means the Engine Torque data
* has been unsubscribed.
*/
- public Boolean getEngineTorque() {
- return getBoolean(KEY_ENGINE_TORQUE);
- }
+ public Boolean getEngineTorque() {
+ return getBoolean(KEY_ENGINE_TORQUE);
+ }
+
+ /**
+ * Sets a boolean value. If true, unsubscribes Engine Oil Life data
+ *
+ * @param engineOilLife
+ * a boolean value
+ */
+ public void setEngineOilLife(Boolean engineOilLife) {
+ setParameters(KEY_ENGINE_OIL_LIFE, engineOilLife);
+ }
+
+ /**
+ * Gets a boolean value. If true, means the Engine Oil Life data has been
+ * unsubscribed.
+ *
+ * @return Boolean -a Boolean value. If true, means the Engine Oil Life data
+ * has been unsubscribed.
+ */
+ public Boolean getEngineOilLife() {
+ return getBoolean(KEY_ENGINE_OIL_LIFE);
+ }
+
/**
* Sets a boolean value. If true, unsubscribes accPedalPosition data
@@ -711,5 +752,54 @@ public class UnsubscribeVehicleData extends RPCRequest {
}
public Boolean getMyKey() {
return getBoolean(KEY_MY_KEY);
- }
+ }
+
+ /**
+ * Sets a boolean value. If true, unsubscribes fuelRange data
+ *
+ * @param fuelRange
+ * a boolean value
+ */
+ public void setFuelRange(Boolean fuelRange) {
+ setParameters(KEY_FUEL_RANGE, fuelRange);
+ }
+
+ /**
+ * Gets a boolean value. If true, means the fuelRange data has been
+ * unsubscribed.
+ *
+ * @return Boolean -a Boolean value. If true, means the fuelRange data
+ * has been unsubscribed.
+ */
+ public Boolean getFuelRange() {
+ return getBoolean(KEY_FUEL_RANGE);
+ }
+
+ /**
+ * Sets a boolean value. If true, subscribes turnSignal data
+ * @param turnSignal a boolean value
+ */
+ public void setTurnSignal(Boolean turnSignal) { setParameters(KEY_TURN_SIGNAL, turnSignal); }
+
+ /**
+ * Gets a boolean value. If true, means the turnSignal data has been subscribed.
+ * @return a Boolean value.
+ */
+ public Boolean getTurnSignal() { return getBoolean(KEY_TURN_SIGNAL); }
+
+ /**
+ * Sets a boolean value. If true, subscribes electronicParkBrakeStatus data
+ * @param electronicParkBrakeStatus a boolean value
+ */
+ public void setElectronicParkBrakeStatus(Boolean electronicParkBrakeStatus) {
+ setParameters(KEY_ELECTRONIC_PARK_BRAKE_STATUS, electronicParkBrakeStatus);
+ }
+
+ /**
+ * Gets a boolean value. If true, means the electronicParkBrakeStatus data has been subscribed.
+ * @return a Boolean value.
+ */
+ public Boolean getElectronicParkBrakeStatus() {
+ return getBoolean(KEY_ELECTRONIC_PARK_BRAKE_STATUS);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnsubscribeVehicleDataResponse.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnsubscribeVehicleDataResponse.java
index bba857522..0ed8aac33 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnsubscribeVehicleDataResponse.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/UnsubscribeVehicleDataResponse.java
@@ -24,6 +24,7 @@ public class UnsubscribeVehicleDataResponse extends RPCResponse {
public static final String KEY_PRNDL = "prndl";
public static final String KEY_TIRE_PRESSURE = "tirePressure";
public static final String KEY_ENGINE_TORQUE = "engineTorque";
+ public static final String KEY_ENGINE_OIL_LIFE = "engineOilLife";
public static final String KEY_ODOMETER = "odometer";
public static final String KEY_GPS = "gps";
public static final String KEY_FUEL_LEVEL_STATE = "fuelLevel_State";
@@ -41,6 +42,9 @@ public class UnsubscribeVehicleDataResponse extends RPCResponse {
public static final String KEY_EMERGENCY_EVENT = "emergencyEvent";
public static final String KEY_CLUSTER_MODE_STATUS = "clusterModeStatus";
public static final String KEY_MY_KEY = "myKey";
+ public static final String KEY_FUEL_RANGE = "fuelRange";
+ public static final String KEY_TURN_SIGNAL = "turnSignal";
+ public static final String KEY_ELECTRONIC_PARK_BRAKE_STATUS = "electronicParkBrakeStatus";
/**
* Constructs a new UnsubscribeVehicleDataResponse object
@@ -343,6 +347,21 @@ public class UnsubscribeVehicleDataResponse extends RPCResponse {
return (VehicleDataResult) getObject(VehicleDataResult.class, KEY_ENGINE_TORQUE);
}
/**
+ * Sets Engine Oil Life
+ * @param engineOilLife
+ */
+ public void setEngineOilLife(VehicleDataResult engineOilLife) {
+ setParameters(KEY_ENGINE_OIL_LIFE, engineOilLife);
+ }
+ /**
+ * Gets Engine Oil Life
+ * @return VehicleDataResult
+ */
+ @SuppressWarnings("unchecked")
+ public VehicleDataResult getEngineOilLife() {
+ return (VehicleDataResult) getObject(VehicleDataResult.class, KEY_ENGINE_OIL_LIFE);
+ }
+ /**
* Sets AccPedal Position
* @param accPedalPosition
*/
@@ -401,5 +420,55 @@ public class UnsubscribeVehicleDataResponse extends RPCResponse {
@SuppressWarnings("unchecked")
public VehicleDataResult getMyKey() {
return (VehicleDataResult) getObject(VehicleDataResult.class, KEY_MY_KEY);
- }
+ }
+
+ /**
+ * Sets Fuel Range
+ * @param fuelRange
+ */
+ public void setFuelRange(VehicleDataResult fuelRange) {
+ setParameters(KEY_FUEL_RANGE, fuelRange);
+ }
+
+ /**
+ * Gets Fuel Range
+ * @return VehicleDataResult
+ */
+ @SuppressWarnings("unchecked")
+ public VehicleDataResult getFuelRange() {
+ return (VehicleDataResult) getObject(VehicleDataResult.class, KEY_FUEL_RANGE);
+ }
+
+ /**
+ * Sets turnSignal
+ * @param turnSignal
+ */
+ public void setTurnSignal(VehicleDataResult turnSignal) {
+ setParameters(KEY_TURN_SIGNAL, turnSignal);
+ }
+
+ /**
+ * Gets turnSignal
+ * @return VehicleDataResult
+ */
+ @SuppressWarnings("unchecked")
+ public VehicleDataResult getTurnSignal() {
+ return (VehicleDataResult) getObject(VehicleDataResult.class, KEY_TURN_SIGNAL);
+ }
+
+ /**
+ * Sets electronicParkBrakeStatus
+ * @param electronicParkBrakeStatus
+ */
+ public void setElectronicParkBrakeStatus(VehicleDataResult electronicParkBrakeStatus){
+ setParameters(KEY_ELECTRONIC_PARK_BRAKE_STATUS, electronicParkBrakeStatus);
+ }
+
+ /**
+ * Gets electronicParkBrakeStatus
+ * @return VehicleDataResult
+ */
+ public VehicleDataResult getElectronicParkBrakeStatus(){
+ return (VehicleDataResult) getObject(VehicleDataResult.class, KEY_ELECTRONIC_PARK_BRAKE_STATUS);
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/VideoStreamingCapability.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/VideoStreamingCapability.java
index 6600cf38d..c558673e5 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/VideoStreamingCapability.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/VideoStreamingCapability.java
@@ -26,10 +26,22 @@ public class VideoStreamingCapability extends RPCStruct {
return (ImageResolution) getObject(ImageResolution.class, KEY_PREFERRED_RESOLUTION);
}
+ /**
+ * Set the max bitrate supported by this module.
+ *
+ * <b>NOTE: </b> Unit is in kbps.
+ * @param maxBitrate in kbps
+ */
public void setMaxBitrate(Integer maxBitrate){
setValue(KEY_MAX_BITRATE, maxBitrate);
}
+ /**
+ * Retrieves the max bitrate supported by this module.
+ *
+ * <b>NOTE: </b> Unit is in kbps.
+ * @return max bitrate in kbps
+ */
public Integer getMaxBitrate(){
return getInteger(KEY_MAX_BITRATE);
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/AppHMIType.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/AppHMIType.java
index 0a4f56255..1bb045006 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/AppHMIType.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/AppHMIType.java
@@ -56,7 +56,7 @@ public enum AppHMIType {
* Convert String to AppHMIType
* @param value String
* @return AppHMIType
- */
+ */
public static AppHMIType valueForString(String value) {
try{
return valueOf(value);
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/AudioStreamingIndicator.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/AudioStreamingIndicator.java
new file mode 100644
index 000000000..00a15d9f0
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/AudioStreamingIndicator.java
@@ -0,0 +1,48 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+/**
+ * Identifies the playback status of a media app
+ *
+ * @since SmartDeviceLink 5.0
+ */
+public enum AudioStreamingIndicator {
+ /**
+ * Default playback indicator.
+ *
+ * @since SmartDeviceLink 5.0
+ */
+ PLAY_PAUSE,
+
+ /**
+ * Indicates that a button press of the Play/Pause button would start the playback.
+ *
+ * @since SmartDeviceLink 5.0
+ */
+ PLAY,
+ /**
+ * Indicates that a button press of the Play/Pause button would pause the current playback.
+ *
+ * @since SmartDeviceLink 5.0
+ */
+ PAUSE,
+ /**
+ * Indicates that a button press of the Play/Pause button would stop the current playback.
+ *
+ * @since SmartDeviceLink 5.0
+ */
+ STOP,
+ ;
+
+ /**
+ * Convert String to AudioStreamingIndicator
+ * @param value String
+ * @return AudioStreamingIndicator
+ */
+ public static AudioStreamingIndicator valueForString(String value) {
+ try{
+ return valueOf(value);
+ }catch(Exception e){
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ButtonName.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ButtonName.java
index f478a78ee..6d4cecffc 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ButtonName.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ButtonName.java
@@ -23,10 +23,21 @@ package com.smartdevicelink.proxy.rpc.enums;
*/
public enum ButtonName{
/**
+ * <br><b>THIS ENUM VALUE WILL CHANGE IN FUNCITONALITY DURING THE NEXT MAJOR RELEASE!</b>
+ * <br><br>
+ * This ButtonName value originally was used for both the OK button and PLAY_PAUSE button. As of
+ * SmartDeviceLink 5.0.0, the functionality was broken out into the OK and PLAY_PAUSE buttons.
+ * <br><br> For this version of the library OK will be received for both OK and PLAY_PAUSE to
+ * mitigate a potential break in functionliaty. If the desire is only for the OK functionality,
+ * this button should still be used. If the desired functionality was actually for the play/pause
+ * toggle, then the new PLAY_PAUSE should be used.
+ * <br><br>
* Represents the button usually labeled "OK". A typical use of this button
- * is for the user to press it to make a selection.
- *
+ * is for the user to press it to make a selection (and until a major library version release,
+ * play pause toggle).
+ *
* @since SmartDeviceLink 1.0
+ * @see #PLAY_PAUSE
*/
OK,
/**
@@ -136,6 +147,17 @@ public enum ButtonName{
SOURCE,
SHUFFLE,
REPEAT,
+ /**
+ * Represents the play/pause button. A typical use of this button
+ * is for the user to press it to toggle between media playing and pausing.
+ *
+ * <br><br><b>NOTE:</b> This functionality used to be represented by the OK button.
+ *
+ * @since SmartDeviceLink 5.0
+ * @see #OK
+ */
+ PLAY_PAUSE,
+
;
public static ButtonName valueForString(String value) {
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/DisplayMode.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/DisplayMode.java
new file mode 100644
index 000000000..5a0c0c7e4
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/DisplayMode.java
@@ -0,0 +1,16 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+public enum DisplayMode {
+ DAY,
+ NIGHT,
+ AUTO,
+ ;
+
+ public static DisplayMode valueForString(String value) {
+ try {
+ return valueOf(value);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/DistanceUnit.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/DistanceUnit.java
new file mode 100644
index 000000000..36e103bf3
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/DistanceUnit.java
@@ -0,0 +1,15 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+public enum DistanceUnit {
+ MILES,
+ KILOMETERS,
+ ;
+
+ public static DistanceUnit valueForString(String value) {
+ try {
+ return valueOf(value);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ElectronicParkBrakeStatus.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ElectronicParkBrakeStatus.java
new file mode 100644
index 000000000..f3951c7a1
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ElectronicParkBrakeStatus.java
@@ -0,0 +1,38 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+public enum ElectronicParkBrakeStatus {
+ /**
+ * Park brake actuators have been fully applied.
+ */
+ CLOSED,
+ /**
+ * Park brake actuators are transitioning to either Apply/Closed or Release/Open state.
+ */
+ TRANSITION,
+ /**
+ * Park brake actuators are released.
+ */
+ OPEN,
+ /**
+ * When driver pulls the Electronic Park Brake switch while driving "at speed".
+ */
+ DRIVE_ACTIVE,
+ /**
+ * When system has a fault or is under maintenance.
+ */
+ FAULT,
+ ;
+
+ /**
+ * Convert String to ElectronicParkBrakeStatus
+ * @param value String
+ * @return ElectronicParkBrakeStatus
+ */
+ public static ElectronicParkBrakeStatus valueForString(String value) {
+ try{
+ return valueOf(value);
+ }catch(Exception e){
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/FuelType.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/FuelType.java
new file mode 100644
index 000000000..8241ebd45
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/FuelType.java
@@ -0,0 +1,31 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+public enum FuelType {
+ GASOLINE,
+ DIESEL,
+ /**
+ * For vehicles using compressed natural gas.
+ */
+ CNG,
+ /**
+ * For vehicles using liquefied petroleum gas.
+ */
+ LPG,
+ /**
+ * For FCEV (fuel cell electric vehicle).
+ */
+ HYDROGEN,
+ /**
+ * For BEV (Battery Electric Vehicle), PHEV (Plug-in Hybrid Electric Vehicle), solar vehicles and other vehicles which run on a battery.
+ */
+ BATTERY,
+ ;
+
+ public static FuelType valueForString(String value) {
+ try{
+ return valueOf(value);
+ }catch(Exception e){
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ImageFieldName.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ImageFieldName.java
index bf92ef5f4..799b1e99d 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ImageFieldName.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ImageFieldName.java
@@ -58,7 +58,7 @@ public enum ImageFieldName {
/** The secondary image field for ShowConstant TBT.
*
- */
+ */
showConstantTBTNextTurnIcon,
/**
* The optional image of a destination / location
@@ -66,6 +66,12 @@ public enum ImageFieldName {
* @since SmartDeviceLink 4.0
*/
locationImage,
+ /**
+ * The secondary graphic image field
+ *
+ * @since SmartDeviceLink 5.0
+ */
+ secondaryGraphic,
;
/**
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/LightName.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/LightName.java
new file mode 100644
index 000000000..c3812f2da
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/LightName.java
@@ -0,0 +1,134 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+public enum LightName {
+ /*Common Single Light*/
+ FRONT_LEFT_HIGH_BEAM,
+ FRONT_RIGHT_HIGH_BEAM,
+ FRONT_LEFT_LOW_BEAM,
+ FRONT_RIGHT_LOW_BEAM,
+ FRONT_LEFT_PARKING_LIGHT,
+ FRONT_RIGHT_PARKING_LIGHT,
+ FRONT_LEFT_FOG_LIGHT,
+ FRONT_RIGHT_FOG_LIGHT,
+ FRONT_LEFT_DAYTIME_RUNNING_LIGHT,
+ FRONT_RIGHT_DAYTIME_RUNNING_LIGHT,
+ FRONT_LEFT_TURN_LIGHT,
+ FRONT_RIGHT_TURN_LIGHT,
+ REAR_LEFT_FOG_LIGHT,
+ REAR_RIGHT_FOG_LIGHT,
+ REAR_LEFT_TAIL_LIGHT,
+ REAR_RIGHT_TAIL_LIGHT,
+ REAR_LEFT_BRAKE_LIGHT,
+ REAR_RIGHT_BRAKE_LIGHT,
+ REAR_LEFT_TURN_LIGHT,
+ REAR_RIGHT_TURN_LIGHT,
+ REAR_REGISTRATION_PLATE_LIGHT,
+
+ /**
+ * Include all high beam lights: front_left and front_right.
+ */
+ HIGH_BEAMS,
+ /**
+ * Include all low beam lights: front_left and front_right.
+ */
+ LOW_BEAMS,
+ /**
+ * Include all fog lights: front_left, front_right, rear_left and rear_right.
+ */
+ FOG_LIGHTS,
+ /**
+ * Include all daytime running lights: front_left and front_right.
+ */
+ RUNNING_LIGHTS,
+ /**
+ * Include all parking lights: front_left and front_right.
+ */
+ PARKING_LIGHTS,
+ /**
+ * Include all brake lights: rear_left and rear_right.
+ */
+ BRAKE_LIGHTS,
+ REAR_REVERSING_LIGHTS,
+ SIDE_MARKER_LIGHTS,
+
+ /**
+ * Include all left turn signal lights: front_left, rear_left, left_side and mirror_mounted.
+ */
+ LEFT_TURN_LIGHTS,
+ /**
+ * Include all right turn signal lights: front_right, rear_right, right_side and mirror_mounted.
+ */
+ RIGHT_TURN_LIGHTS,
+ /**
+ * Include all hazard lights: front_left, front_right, rear_left and rear_right.
+ */
+ HAZARD_LIGHTS,
+ /**
+ * Cargo lamps illuminate the cargo area.
+ */
+ REAR_CARGO_LIGHTS,
+ /**
+ * Truck bed lamps light up the bed of the truck.
+ */
+ REAR_TRUCK_BED_LIGHTS,
+ /**
+ * Trailer lights are lamps mounted on a trailer hitch.
+ */
+ REAR_TRAILER_LIGHTS,
+ /**
+ * It is the spotlights mounted on the left side of a vehicle.
+ */
+ LEFT_SPOT_LIGHTS,
+ /**
+ * It is the spotlights mounted on the right side of a vehicle.
+ */
+ RIGHT_SPOT_LIGHTS,
+ /**
+ * Puddle lamps illuminate the ground beside the door as the customer is opening or approaching the door.
+ */
+ LEFT_PUDDLE_LIGHTS,
+ /**
+ * Puddle lamps illuminate the ground beside the door as the customer is opening or approaching the door.
+ */
+ RIGHT_PUDDLE_LIGHTS,
+
+ /*Interior Lights by common function groups*/
+
+ AMBIENT_LIGHTS,
+ OVERHEAD_LIGHTS,
+ READING_LIGHTS,
+ TRUNK_LIGHTS,
+
+
+ /*Lights by location*/
+
+ /**
+ * Include exterior lights located in front of the vehicle. For example, fog lights and low beams.
+ */
+ EXTERIOR_FRONT_LIGHTS,
+ /**
+ * Include exterior lights located at the back of the vehicle. For example, license plate lights, reverse lights, cargo lights, bed lights an trailer assist lights.
+ */
+ EXTERIOR_REAR_LIGHTS,
+ /**
+ * Include exterior lights located at the left side of the vehicle. For example, left puddle lights and spot lights.
+ */
+ EXTERIOR_LEFT_LIGHTS,
+ /**
+ * Include exterior lights located at the right side of the vehicle. For example, right puddle lights and spot lights.
+ */
+ EXTERIOR_RIGHT_LIGHTS,
+ /**
+ * Include all exterior lights around the vehicle.
+ */
+ EXTERIOR_ALL_LIGHTS,
+ ;
+
+ public static LightName valueForString(String value) {
+ try {
+ return valueOf(value);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/LightStatus.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/LightStatus.java
new file mode 100644
index 000000000..98c4b175c
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/LightStatus.java
@@ -0,0 +1,19 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+public enum LightStatus {
+ ON,
+ OFF,
+ RAMP_UP,
+ RAMP_DOWN,
+ UNKNOWN,
+ INVALID,
+ ;
+
+ public static LightStatus valueForString(String value) {
+ try {
+ return valueOf(value);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/MassageCushion.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/MassageCushion.java
new file mode 100644
index 000000000..ed23b4899
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/MassageCushion.java
@@ -0,0 +1,21 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+/**
+ * List possible cushions of a multi-contour massage seat.
+ */
+public enum MassageCushion {
+ TOP_LUMBAR,
+ MIDDLE_LUMBAR,
+ BOTTOM_LUMBAR,
+ BACK_BOLSTERS,
+ SEAT_BOLSTERS,
+ ;
+
+ public static MassageCushion valueForString(String value) {
+ try {
+ return valueOf(value);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/MassageMode.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/MassageMode.java
new file mode 100644
index 000000000..59a200bdb
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/MassageMode.java
@@ -0,0 +1,19 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+/**
+ * List possible modes of a massage zone.
+ */
+public enum MassageMode {
+ OFF,
+ LOW,
+ HIGH,
+ ;
+
+ public static MassageMode valueForString(String value) {
+ try {
+ return valueOf(value);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/MassageZone.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/MassageZone.java
new file mode 100644
index 000000000..9f0e23ffe
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/MassageZone.java
@@ -0,0 +1,24 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+/**
+ * List possible zones of a multi-contour massage seat.
+ */
+public enum MassageZone {
+ /**
+ * The back of a multi-contour massage seat. or SEAT_BACK
+ */
+ LUMBAR,
+ /**
+ * The bottom a multi-contour massage seat. or SEAT_BOTTOM
+ */
+ SEAT_CUSHION,
+ ;
+
+ public static MassageZone valueForString(String value) {
+ try {
+ return valueOf(value);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ModuleType.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ModuleType.java
index faef92d36..c4bedfd46 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ModuleType.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/ModuleType.java
@@ -1,15 +1,19 @@
package com.smartdevicelink.proxy.rpc.enums;
public enum ModuleType {
- CLIMATE,
- RADIO,
- ;
+ CLIMATE,
+ RADIO,
+ SEAT,
+ AUDIO,
+ LIGHT,
+ HMI_SETTINGS,
+ ;
- public static ModuleType valueForString(String value) {
- try{
- return valueOf(value);
- }catch(Exception e){
- return null;
- }
- }
+ public static ModuleType valueForString(String value) {
+ try {
+ return valueOf(value);
+ } catch (Exception e) {
+ return null;
+ }
+ }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/PredefinedLayout.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/PredefinedLayout.java
new file mode 100644
index 000000000..458320d1e
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/PredefinedLayout.java
@@ -0,0 +1,140 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+import java.util.EnumSet;
+
+/**
+ A template layout an app uses to display information. The broad details of the layout are defined, but the details depend on the IVI system. Used in SetDisplayLayout.
+ */
+public enum PredefinedLayout {
+
+ /**
+ A default layout
+ */
+ DEFAULT("DEFAULT"),
+
+ /**
+ The default media layout
+ */
+ MEDIA("MEDIA"),
+
+ /**
+ The default non-media layout
+ */
+ NON_MEDIA("NON-MEDIA"),
+
+ /**
+ A media layout containing preset buttons
+ */
+ ONSCREEN_PRESETS("ONSCREEN_PRESETS"),
+
+ /**
+ The default navigation layout with a fullscreen map
+ */
+ NAV_FULLSCREEN_MAP("NAV_FULLSCREEN_MAP"),
+
+ /**
+ A list layout used for navigation apps
+ */
+ NAV_LIST("NAV_LIST"),
+
+ /**
+ A keyboard layout used for navigation apps
+ */
+ NAV_KEYBOARD("NAV_KEYBOARD"),
+
+ /**
+ A layout with a single graphic on the left and text on the right
+ */
+ GRAPHIC_WITH_TEXT("GRAPHIC_WITH_TEXT"),
+
+ /**
+ A layout with text on the left and a single graphic on the right
+ */
+ TEXT_WITH_GRAPHIC("TEXT_WITH_GRAPHIC"),
+
+ /**
+ A layout with only softbuttons placed in a tile layout
+ */
+ TILES_ONLY("TILES_ONLY"),
+
+ /**
+ A layout with only soft buttons that only accept text
+ */
+ TEXTBUTTONS_ONLY("TEXTBUTTONS_ONLY"),
+
+ /**
+ A layout with a single graphic on the left and soft buttons in a tile layout on the right
+ */
+ GRAPHIC_WITH_TILES("GRAPHIC_WITH_TILES"),
+
+ /**
+ A layout with soft buttons in a tile layout on the left and a single graphic on the right
+ */
+ TILES_WITH_GRAPHIC("TILES_WITH_GRAPHIC"),
+
+ /**
+ A layout with a single graphic on the left and both text and soft buttons on the right
+ */
+ GRAPHIC_WITH_TEXT_AND_SOFTBUTTONS("GRAPHIC_WITH_TEXT_AND_SOFTBUTTONS"),
+
+ /**
+ A layout with both text and soft buttons on the left and a single graphic on the right
+ */
+ TEXT_AND_SOFTBUTTONS_WITH_GRAPHIC("TEXT_AND_SOFTBUTTONS_WITH_GRAPHIC"),
+
+ /**
+ A layout with a single graphic on the left and text-only soft buttons on the right
+ */
+ GRAPHIC_WITH_TEXTBUTTONS("GRAPHIC_WITH_TEXTBUTTONS"),
+
+ /**
+ A layout with text-only soft buttons on the left and a single graphic on the right
+ */
+ TEXTBUTTONS_WITH_GRAPHIC("TEXTBUTTONS_WITH_GRAPHIC"),
+
+ /**
+ A layout with a single large graphic and soft buttons
+ */
+ LARGE_GRAPHIC_WITH_SOFTBUTTONS("LARGE_GRAPHIC_WITH_SOFTBUTTONS"),
+
+ /**
+ A layout with two graphics and soft buttons
+ */
+ DOUBLE_GRAPHIC_WITH_SOFTBUTTONS("DOUBLE_GRAPHIC_WITH_SOFTBUTTONS"),
+
+ /**
+ A layout with only a single large graphic
+ */
+ LARGE_GRAPHIC_ONLY("LARGE_GRAPHIC_ONLY"),
+ ;
+
+ private final String INTERNAL_NAME;
+
+ private PredefinedLayout(String internalName) {
+ this.INTERNAL_NAME = internalName;
+ }
+ /**
+ * Returns a String representing a PredefinedLayout
+ */
+ public String toString() {
+ return this.INTERNAL_NAME;
+ }
+
+ /**
+ * Returns a PredefinedLayout
+ * @param value a String
+ * @return PredefinedLayout
+ */
+ public static PredefinedLayout valueForString(String value) {
+ if(value == null){
+ return null;
+ }
+
+ for (PredefinedLayout anEnum : EnumSet.allOf(PredefinedLayout.class)) {
+ if (anEnum.toString().equals(value)) {
+ return anEnum;
+ }
+ }
+ return null;
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/PrimaryAudioSource.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/PrimaryAudioSource.java
index b06045d1a..27f83d7d4 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/PrimaryAudioSource.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/PrimaryAudioSource.java
@@ -5,11 +5,15 @@ package com.smartdevicelink.proxy.rpc.enums;
* @since SmartDeviceLink 2.0
*/
public enum PrimaryAudioSource {
- /**
- * Currently no source selected
- */
+ /**
+ * Currently no source selected
+ */
NO_SOURCE_SELECTED,
/**
+ * CD is current source
+ */
+ CD,
+ /**
* USB is current source
*/
USB,
@@ -32,18 +36,23 @@ public enum PrimaryAudioSource {
/**
* Mobile app is current source
*/
- MOBILE_APP;
+ MOBILE_APP,
+ AM,
+ FM,
+ XM,
+ DAB,
+ ;
/**
* Convert String to PrimaryAudioSource
* @param value String
* @return PrimaryAudioSource
- */
+ */
public static PrimaryAudioSource valueForString(String value) {
- try{
- return valueOf(value);
- }catch(Exception e){
- return null;
- }
+ try{
+ return valueOf(value);
+ }catch(Exception e){
+ return null;
+ }
}
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/RequestType.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/RequestType.java
index 0ddcfef3a..75707802e 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/RequestType.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/RequestType.java
@@ -67,7 +67,11 @@ public enum RequestType {
/**
* @since SmartDeviceLink 4.0
*/
- FOTA,
+ FOTA,
+ /**
+ * @since SmartDeviceLink 5.0
+ */
+ OEM_SPECIFIC,
;
/**
* Convert String to RequestType
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/Result.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/Result.java
index c0a15f235..25b9a16f5 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/Result.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/Result.java
@@ -177,6 +177,11 @@ public enum Result {
* The requested data is read only thus cannot be change via remote control
*/
READ_ONLY,
+ /**
+ * The data sent failed to pass CRC check in receiver end
+ */
+ CORRUPTED_DATA,
+
;
/**
* Convert String to Result
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SdlDisconnectedReason.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SdlDisconnectedReason.java
index 0d1902e3a..60ecf5450 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SdlDisconnectedReason.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SdlDisconnectedReason.java
@@ -25,7 +25,8 @@ public enum SdlDisconnectedReason {
* This only occurs when multiplexing is running and it is found to be on an old gen 1 system.
*/
LEGACY_BLUETOOTH_MODE_ENABLED,
- RPC_SESSION_ENDED
+ RPC_SESSION_ENDED,
+ PRIMARY_TRANSPORT_CYCLE_REQUEST
;
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SeatMemoryActionType.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SeatMemoryActionType.java
new file mode 100644
index 000000000..e81b2694a
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SeatMemoryActionType.java
@@ -0,0 +1,25 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+public enum SeatMemoryActionType {
+ /**
+ * Save current seat positions and settings to seat memory.
+ */
+ SAVE,
+ /**
+ * Restore / apply the seat memory settings to the current seat.
+ */
+ RESTORE,
+ /**
+ * No action to be performed.
+ */
+ NONE,
+ ;
+
+ public static SeatMemoryActionType valueForString(String value) {
+ try {
+ return valueOf(value);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SpeechCapabilities.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SpeechCapabilities.java
index 2b5d17740..7d8330d0a 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SpeechCapabilities.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SpeechCapabilities.java
@@ -30,7 +30,12 @@ public enum SpeechCapabilities {
* The SDL platform can play the prerecorded sound of 1 second of silence (i.e. no sound at all).
*/
- SILENCE;
+ SILENCE,
+
+ /**
+ * The SDL platform can play audio files in conjunction with/without TTS text.
+ */
+ FILE;
/**
* Convert String to SpeechCapabilities
* @param value String
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/StaticIconName.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/StaticIconName.java
new file mode 100644
index 000000000..455995ff3
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/StaticIconName.java
@@ -0,0 +1,910 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+/**
+ * Enumeration of Static Icon Names
+ */
+public enum StaticIconName {
+
+ /**
+ * Icon Name accept call / active phone call in progress / initiate a phone call
+ */
+ ACCEPT_CALL("0x29"),
+
+ /**
+ * Icon Name add waypoint
+ */
+ ADD_WAYPOINT("0x1B"),
+
+ /**
+ * Icon Name album
+ */
+ ALBUM("0x21"),
+
+ /**
+ * Icon Name ambient lighting
+ */
+ AMBIENT_LIGHTING("0x3d"),
+
+ /**
+ * Icon Name arrow - north
+ */
+ ARROW_NORTH("0x40"),
+
+ /**
+ * Icon Name audio mute
+ */
+ AUDIO_MUTE("0x12"),
+
+ /**
+ * Icon Name audiobook episode
+ */
+ AUDIOBOOK_EPISODE("0x83"),
+
+ /**
+ * Icon Name audiobook narrator
+ */
+ AUDIOBOOK_NARRATOR("0x82"),
+
+ /**
+ * Icon Name auxillary audio
+ */
+ AUXILLARY_AUDIO("0x45"),
+
+ /**
+ * Icon Name back / return
+ */
+ BACK("0x86"),
+
+ /**
+ * Icon Name battery capacity 0 of 5
+ */
+ BATTERY_CAPACITY_0_OF_5("0xF7"),
+
+ /**
+ * Icon Name battery capacity 1 of 5
+ */
+ BATTERY_CAPACITY_1_OF_5("0xF8"),
+
+ /**
+ * Icon Name battery capacity 2 of 5
+ */
+ BATTERY_CAPACITY_2_OF_5("0xF9"),
+
+ /**
+ * Icon Name battery capacity 3 of 5
+ */
+ BATTERY_CAPACITY_3_OF_5("0xFA"),
+
+ /**
+ * Icon Name battery capacity 4 of 5
+ */
+ BATTERY_CAPACITY_4_OF_5("0xf6"),
+
+ /**
+ * Icon Name battery capacity 5 of 5
+ */
+ BATTERY_CAPACITY_5_OF_5("0xFB"),
+
+ /**
+ * Icon Name bluetooth audio source
+ */
+ BLUETOOTH_AUDIO_SOURCE("0x09"),
+
+ /**
+ * Icon Name bluetooth1
+ */
+ BLUETOOTH1("0xcc"),
+
+ /**
+ * Icon Name bluetooth2
+ */
+ BLUETOOTH2("0xCD"),
+
+ /**
+ * Icon Name browse
+ */
+ BROWSE("0x77"),
+
+ /**
+ * Icon Name cell phone in roaming mode
+ */
+ CELL_PHONE_IN_ROAMING_MODE("0x66"),
+
+ /**
+ * Icon Name cell service signal strength 0 of 5 bars
+ */
+ CELL_SERVICE_SIGNAL_STRENGTH_0_OF_5_BARS("0x67"),
+
+ /**
+ * Icon Name cell service signal strength 1 of 5 bars
+ */
+ CELL_SERVICE_SIGNAL_STRENGTH_1_OF_5_BARS("0x68"),
+
+ /**
+ * Icon Name cell service signal strength 2 of 5 bars
+ */
+ CELL_SERVICE_SIGNAL_STRENGTH_2_OF_5_BARS("0x69"),
+
+ /**
+ * Icon Name cell service signal strength 3 of 5 bars
+ */
+ CELL_SERVICE_SIGNAL_STRENGTH_3_OF_5_BARS("0x6A"),
+
+ /**
+ * Icon Name cell service signal strength 4 of 5 bars
+ */
+ CELL_SERVICE_SIGNAL_STRENGTH_4_OF_5_BARS("0x6B"),
+
+ /**
+ * Icon Name cell service signal strength 5 of 5 bars
+ */
+ CELL_SERVICE_SIGNAL_STRENGTH_5_OF_5_BARS("0xd3"),
+
+ /**
+ * Icon Name change lane left
+ */
+ CHANGE_LANE_LEFT("0xc3"),
+
+ /**
+ * Icon Name change lane right
+ */
+ CHANGE_LANE_RIGHT("0xc1"),
+
+ /**
+ * Icon Name check box checked
+ */
+ CHECK_BOX_CHECKED("0x27"),
+
+ /**
+ * Icon Name check box unchecked
+ */
+ CHECK_BOX_UNCHECKED("0x28"),
+
+ /**
+ * Icon Name climate
+ */
+ CLIMATE("0xd1"),
+
+ /**
+ * Icon Name clock
+ */
+ CLOCK("0xfc"),
+
+ /**
+ * Icon Name compose (e.g. message)
+ */
+ COMPOSE("0x1A"),
+
+ /**
+ * Icon Name contact / person
+ */
+ CONTACT("0x5C"),
+
+ /**
+ * Icon Name continue
+ */
+ CONTINUE("0x42"),
+
+ /**
+ * Icon Name dash / bullet point
+ */
+ DASH("0x7F"),
+
+ /**
+ * Icon Name date / calendar
+ */
+ DATE("0x87"),
+
+ /**
+ * Icon Name delete/remove - trash
+ */
+ DELETE("0x0F"),
+
+ /**
+ * Icon Name destination
+ */
+ DESTINATION("0x94"),
+
+ /**
+ * Icon Name destination ferry ahead
+ */
+ DESTINATION_FERRY_AHEAD("0x4D"),
+
+ /**
+ * Icon Name ebookmark (e.g. message, feed)
+ */
+ EBOOKMARK("0x2B"),
+
+ /**
+ * Icon Name end call / reject call
+ */
+ END_CALL("0x2C"),
+
+ /**
+ * Icon Name fail / X
+ */
+ FAIL("0xD6"),
+
+ /**
+ * Icon Name fast forward 30 secs
+ */
+ FAST_FORWARD_30_SECS("0x08"),
+
+ /**
+ * Icon Name favorite / heart
+ */
+ FAVORITE_HEART("0x0E"),
+
+ /**
+ * Icon Name favorite / star
+ */
+ FAVORITE_STAR("0x95"),
+
+ /**
+ * Icon Name fax number
+ */
+ FAX_NUMBER("0x80"),
+
+ /**
+ * Icon Name filename
+ */
+ FILENAME("0x50"),
+
+ /**
+ * Icon Name filter / search
+ */
+ FILTER("0x79"),
+
+ /**
+ * Icon Name folder
+ */
+ FOLDER("0x1C"),
+
+ /**
+ * Icon Name fuel prices
+ */
+ FUEL_PRICES("0xe9"),
+
+ /**
+ * Icon Name full map
+ */
+ FULL_MAP("0x0c"),
+
+ /**
+ * Icon Name generic phone number
+ */
+ GENERIC_PHONE_NUMBER("0x53"),
+
+ /**
+ * Icon Name genre
+ */
+ GENRE("0x4E"),
+
+ /**
+ * Icon Name global keyboard
+ */
+ GLOBAL_KEYBOARD("0xea"),
+
+ /**
+ * Icon Name highway exit information
+ */
+ HIGHWAY_EXIT_INFORMATION("0xf4"),
+
+ /**
+ * Icon Name home phone number
+ */
+ HOME_PHONE_NUMBER("0x55"),
+
+ /**
+ * Icon Name hyperlink
+ */
+ HYPERLINK("0x78"),
+
+ /**
+ * Icon Name ID3 tag unknown
+ */
+ ID3_TAG_UNKNOWN("0x51"),
+
+ /**
+ * Icon Name incoming calls (in list of phone calls)
+ */
+ INCOMING_CALLS("0x57"),
+
+ /**
+ * Icon Name information
+ */
+ INFORMATION("0x5d"),
+
+ /**
+ * Icon Name IPOD media source
+ */
+ IPOD_MEDIA_SOURCE("0x0D"),
+
+ /**
+ * Icon Name join calls
+ */
+ JOIN_CALLS("0x02"),
+
+ /**
+ * Icon Name keep left
+ */
+ KEEP_LEFT("0x46"),
+
+ /**
+ * Icon Name keep right
+ */
+ KEEP_RIGHT("0x48"),
+
+ /**
+ * Icon Name key / keycode
+ */
+ KEY("0x7D"),
+
+ /**
+ * Icon Name left
+ */
+ LEFT("0x9f"),
+
+ /**
+ * Icon Name left arrow / back
+ */
+ LEFT_ARROW("0x4B"),
+
+ /**
+ * Icon Name left exit
+ */
+ LEFT_EXIT("0xaf"),
+
+ /**
+ * Icon Name LINE IN audio source
+ */
+ LINE_IN_AUDIO_SOURCE("0x06"),
+
+ /**
+ * Icon Name locked
+ */
+ LOCKED("0x22"),
+
+ /**
+ * Icon Name media control - left arrow
+ */
+ MEDIA_CONTROL_LEFT_ARROW("0x17"),
+
+ /**
+ * Icon Name media control - recording
+ */
+ MEDIA_CONTROL_RECORDING("0x20"),
+
+ /**
+ * Icon Name media control - right arrow
+ */
+ MEDIA_CONTROL_RIGHT_ARROW("0x15"),
+
+ /**
+ * Icon Name media control - stop (e.g. streaming)
+ */
+ MEDIA_CONTROL_STOP("0x16"),
+
+ /**
+ * Icon Name microphone
+ */
+ MICROPHONE("0xe8"),
+
+ /**
+ * Icon Name missed calls (in list of phone calls)
+ */
+ MISSED_CALLS("0x58"),
+
+ /**
+ * Icon Name mobile phone number
+ */
+ MOBILE_PHONE_NUMBER("0x54"),
+
+ /**
+ * Icon Name move down / download
+ */
+ MOVE_DOWN("0xE5"),
+
+ /**
+ * Icon Name move up
+ */
+ MOVE_UP("0xe4"),
+
+ /**
+ * Icon Name MP3 tag artist
+ */
+ MP3_TAG_ARTIST("0x24"),
+
+ /**
+ * Icon Name navigation / navigation settings
+ */
+ NAVIGATION("0x8e"),
+
+ /**
+ * Icon Name navigation current direction
+ */
+ NAVIGATION_CURRENT_DIRECTION("0x0a"),
+
+ /**
+ * Icon Name negative rating - thumbs down
+ */
+ NEGATIVE_RATING_THUMBS_DOWN("0x14"),
+
+ /**
+ * Icon Name new/unread text message/email
+ */
+ NEW("0x5E"),
+
+ /**
+ * Icon Name office phone number / work phone number
+ */
+ OFFICE_PHONE_NUMBER("0x56"),
+
+ /**
+ * Icon Name opened/read text message/email
+ */
+ OPENED("0x5F"),
+
+ /**
+ * Icon Name origin / nearby locale / current position
+ */
+ ORIGIN("0x96"),
+
+ /**
+ * Icon Name outgoing calls (in list of phone calls)
+ */
+ OUTGOING_CALLS("0x59"),
+
+ /**
+ * Icon Name phone call 1
+ */
+ PHONE_CALL_1("0x1D"),
+
+ /**
+ * Icon Name phone call 2
+ */
+ PHONE_CALL_2("0x1E"),
+
+ /**
+ * Icon Name phone device
+ */
+ PHONE_DEVICE("0x03"),
+
+ /**
+ * Icon Name phonebook
+ */
+ PHONEBOOK("0x81"),
+
+ /**
+ * Icon Name photo / picture
+ */
+ PHOTO("0x88"),
+
+ /**
+ * Icon Name play / pause - pause active
+ */
+ PLAY("0xD0"),
+
+ /**
+ * Icon Name playlist
+ */
+ PLAYLIST("0x4F"),
+
+ /**
+ * Icon Name pop-up
+ */
+ POPUP("0x76"),
+
+ /**
+ * Icon Name positive rating - thumbs up
+ */
+ POSITIVE_RATING_THUMBS_UP("0x13"),
+
+ /**
+ * Icon Name power
+ */
+ POWER("0x5b"),
+
+ /**
+ * Icon Name primary phone (favorite)
+ */
+ PRIMARY_PHONE("0x1F"),
+
+ /**
+ * Icon Name radio button checked
+ */
+ RADIO_BUTTON_CHECKED("0x25"),
+
+ /**
+ * Icon Name radio button unchecked
+ */
+ RADIO_BUTTON_UNCHECKED("0x26"),
+
+ /**
+ * Icon Name recent calls / history
+ */
+ RECENT_CALLS("0xe7"),
+
+ /**
+ * Icon Name recent destinations
+ */
+ RECENT_DESTINATIONS("0xf2"),
+
+ /**
+ * Icon Name redo
+ */
+ REDO("0x19"),
+
+ /**
+ * Icon Name refresh
+ */
+ REFRESH("0x97"),
+
+ /**
+ * Icon Name remote diagnostics - check engine
+ */
+ REMOTE_DIAGNOSTICS_CHECK_ENGINE("0x7E"),
+
+ /**
+ * Icon Name rendered 911 assist / emergency assistance
+ */
+ RENDERED_911_ASSIST("0xac"),
+
+ /**
+ * Icon Name repeat
+ */
+ REPEAT("0xe6"),
+
+ /**
+ * Icon Name repeat play
+ */
+ REPEAT_PLAY("0x73"),
+
+ /**
+ * Icon Name reply
+ */
+ REPLY("0x04"),
+
+ /**
+ * Icon Name rewind 30 secs
+ */
+ REWIND_30_SECS("0x07"),
+
+ /**
+ * Icon Name right
+ */
+ RIGHT("0xa3"),
+
+ /**
+ * Icon Name right exit
+ */
+ RIGHT_EXIT("0xb1"),
+
+ /**
+ * Icon Name ringtones
+ */
+ RINGTONES("0x5A"),
+
+ /**
+ * Icon Name roundabout left hand 1
+ */
+ ROUNDABOUT_LEFT_HAND_1("0xee"),
+
+ /**
+ * Icon Name roundabout left hand 2
+ */
+ ROUNDABOUT_LEFT_HAND_2("0x8c"),
+
+ /**
+ * Icon Name roundabout left hand 3
+ */
+ ROUNDABOUT_LEFT_HAND_3("0x84"),
+
+ /**
+ * Icon Name roundabout left hand 4
+ */
+ ROUNDABOUT_LEFT_HAND_4("0x72"),
+
+ /**
+ * Icon Name roundabout left hand 5
+ */
+ ROUNDABOUT_LEFT_HAND_5("0x6e"),
+
+ /**
+ * Icon Name roundabout left hand 6
+ */
+ ROUNDABOUT_LEFT_HAND_6("0x64"),
+
+ /**
+ * Icon Name roundabout left hand 7
+ */
+ ROUNDABOUT_LEFT_HAND_7("0x60"),
+
+ /**
+ * Icon Name roundabout right hand 1
+ */
+ ROUNDABOUT_RIGHT_HAND_1("0x62"),
+
+ /**
+ * Icon Name roundabout right hand 2
+ */
+ ROUNDABOUT_RIGHT_HAND_2("0x6c"),
+
+ /**
+ * Icon Name roundabout right hand 3
+ */
+ ROUNDABOUT_RIGHT_HAND_3("0x70"),
+
+ /**
+ * Icon Name roundabout right hand 4
+ */
+ ROUNDABOUT_RIGHT_HAND_4("0x7a"),
+
+ /**
+ * Icon Name roundabout right hand 5
+ */
+ ROUNDABOUT_RIGHT_HAND_5("0x8a"),
+
+ /**
+ * Icon Name roundabout right hand 6
+ */
+ ROUNDABOUT_RIGHT_HAND_6("0xec"),
+
+ /**
+ * Icon Name roundabout right hand 7
+ */
+ ROUNDABOUT_RIGHT_HAND_7("0xf0"),
+
+ /**
+ * Icon Name RSS
+ */
+ RSS("0x89"),
+
+ /**
+ * Icon Name settings / menu
+ */
+ SETTINGS("0x49"),
+
+ /**
+ * Icon Name sharp left
+ */
+ SHARP_LEFT("0xa5"),
+
+ /**
+ * Icon Name sharp right
+ */
+ SHARP_RIGHT("0xa7"),
+
+ /**
+ * Icon Name show
+ */
+ SHOW("0xe1"),
+
+ /**
+ * Icon Name shuffle play
+ */
+ SHUFFLE_PLAY("0x74"),
+
+ /**
+ * Icon Name ski places / elevation / altitude
+ */
+ SKI_PLACES("0xab"),
+
+ /**
+ * Icon Name slight left
+ */
+ SLIGHT_LEFT("0x9d"),
+
+ /**
+ * Icon Name slight right
+ */
+ SLIGHT_RIGHT("0xa1"),
+
+ /**
+ * Icon Name smartphone
+ */
+ SMARTPHONE("0x05"),
+
+ /**
+ * Icon Name sort list
+ */
+ SORT_LIST("0x7B"),
+
+ /**
+ * Icon Name speed dial numbers - number 0
+ */
+ SPEED_DIAL_NUMBERS_NUMBER_0("0xE0"),
+
+ /**
+ * Icon Name speed dial numbers - number 1
+ */
+ SPEED_DIAL_NUMBERS_NUMBER_1("0xD7"),
+
+ /**
+ * Icon Name speed dial numbers - number 2
+ */
+ SPEED_DIAL_NUMBERS_NUMBER_2("0xD8"),
+
+ /**
+ * Icon Name speed dial numbers - number 3
+ */
+ SPEED_DIAL_NUMBERS_NUMBER_3("0xD9"),
+
+ /**
+ * Icon Name speed dial numbers - number 4
+ */
+ SPEED_DIAL_NUMBERS_NUMBER_4("0xDA"),
+
+ /**
+ * Icon Name speed dial numbers - number 5
+ */
+ SPEED_DIAL_NUMBERS_NUMBER_5("0xDB"),
+
+ /**
+ * Icon Name speed dial numbers - number 6
+ */
+ SPEED_DIAL_NUMBERS_NUMBER_6("0xDC"),
+
+ /**
+ * Icon Name speed dial numbers - number 7
+ */
+ SPEED_DIAL_NUMBERS_NUMBER_7("0xDD"),
+
+ /**
+ * Icon Name speed dial numbers - number 8
+ */
+ SPEED_DIAL_NUMBERS_NUMBER_8("0xDE"),
+
+ /**
+ * Icon Name speed dial numbers - number 9
+ */
+ SPEED_DIAL_NUMBERS_NUMBER_9("0xDF"),
+
+ /**
+ * Icon Name success / check
+ */
+ SUCCESS("0xD5"),
+
+ /**
+ * Icon Name track title / song title
+ */
+ TRACK_TITLE("0x4C"),
+
+ /**
+ * Icon Name traffic report
+ */
+ TRAFFIC_REPORT("0x2A"),
+
+ /**
+ * Icon Name turn list
+ */
+ TURN_LIST("0x10"),
+
+ /**
+ * Icon Name u-turn left traffic
+ */
+ UTURN_LEFT_TRAFFIC("0xad"),
+
+ /**
+ * Icon Name u-turn right traffic
+ */
+ UTURN_RIGHT_TRAFFIC("0xa9"),
+
+ /**
+ * Icon Name undo
+ */
+ UNDO("0x18"),
+
+ /**
+ * Icon Name unlocked
+ */
+ UNLOCKED("0x23"),
+
+ /**
+ * Icon Name USB media audio source
+ */
+ USB_MEDIA_AUDIO_SOURCE("0x0B"),
+
+ /**
+ * Icon Name voice control scrollbar - list item no. 1
+ */
+ VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_1("0xC7"),
+
+ /**
+ * Icon Name voice control scrollbar - list item no. 2
+ */
+ VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_2("0xC8"),
+
+ /**
+ * Icon Name voice control scrollbar - list item no. 3
+ */
+ VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_3("0xC9"),
+
+ /**
+ * Icon Name voice control scrollbar - list item no. 4
+ */
+ VOICE_CONTROL_SCROLLBAR_LIST_ITEM_NO_4("0xCA"),
+
+ /**
+ * Icon Name voice recognition - failed
+ */
+ VOICE_RECOGNITION_FAILED("0x90"),
+
+ /**
+ * Icon Name voice recognition - pause
+ */
+ VOICE_RECOGNITION_PAUSE("0x92"),
+
+ /**
+ * Icon Name voice recognition - successful
+ */
+ VOICE_RECOGNITION_SUCCESSFUL("0x8F"),
+
+ /**
+ * Icon Name voice recognition - system active
+ */
+ VOICE_RECOGNITION_SYSTEM_ACTIVE("0x11"),
+
+ /**
+ * Icon Name voice recognition - system listening
+ */
+ VOICE_RECOGNITION_SYSTEM_LISTENING("0x91"),
+
+ /**
+ * Icon Name voice recognition - try again
+ */
+ VOICE_RECOGNITION_TRY_AGAIN("0x93"),
+
+ /**
+ * Icon Name warning / safety alert
+ */
+ WARNING("0xfe"),
+
+ /**
+ * Icon Name weather
+ */
+ WEATHER("0xeb"),
+
+ /**
+ * Icon Name wifi full
+ */
+ WIFI_FULL("0x43"),
+
+ /**
+ * Icon Name zoom in
+ */
+ ZOOM_IN("0x98"),
+
+ /**
+ * Icon Name zoom out
+ */
+ ZOOM_OUT("0x9a"),
+
+ ;
+
+ private final String INTERNAL_NAME;
+
+ private StaticIconName(String internalName) {
+ this.INTERNAL_NAME = internalName;
+ }
+
+ public static StaticIconName valueForString(String value) {
+ if(value == null){
+ return null;
+ }
+
+ for (StaticIconName type : StaticIconName.values()) {
+ if (type.toString().equals(value)) {
+ return type;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return INTERNAL_NAME;
+ }
+
+} \ No newline at end of file
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SupportedSeat.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SupportedSeat.java
new file mode 100644
index 000000000..c68f2e79d
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/SupportedSeat.java
@@ -0,0 +1,18 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+/**
+ * List possible seats that is a remote controllable seat.
+ */
+public enum SupportedSeat {
+ DRIVER,
+ FRONT_PASSENGER,
+ ;
+
+ public static SupportedSeat valueForString(String value) {
+ try {
+ return valueOf(value);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/TPMS.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/TPMS.java
new file mode 100644
index 000000000..69b60e211
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/TPMS.java
@@ -0,0 +1,51 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+/**
+ * Enums for Tire Pressure Monitoring Systems
+ *
+ * @since SmartDeviceLink 5.0
+ */
+public enum TPMS {
+
+ /**
+ * If set the status of the tire is not known.
+ */
+ UNKNOWN,
+ /**
+ * TPMS does not function.
+ */
+ SYSTEM_FAULT,
+ /**
+ * The sensor of the tire does not function.
+ */
+ SENSOR_FAULT,
+ /**
+ * TPMS is reporting a low tire pressure for the tire.
+ */
+ LOW,
+ /**
+ * TPMS is active and the tire pressure is monitored.
+ */
+ SYSTEM_ACTIVE,
+ /**
+ * TPMS is reporting that the tire must be trained.
+ */
+ TRAIN,
+ /**
+ * TPMS reports the training for the tire is completed.
+ */
+ TRAINING_COMPLETE,
+ /**
+ * TPMS reports the tire is not trained.
+ */
+ NOT_TRAINED,
+ ;
+
+ public static TPMS valueForString(String value) {
+ try{
+ return valueOf(value);
+ }catch(Exception e){
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/TurnSignal.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/TurnSignal.java
new file mode 100644
index 000000000..923cd842e
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/TurnSignal.java
@@ -0,0 +1,35 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+/**
+ * Enumeration that describes the status of the turn light indicator.
+ *
+ * @since SmartDeviceLink 5.0
+ */
+public enum TurnSignal {
+
+ /**
+ * Turn signal is OFF
+ */
+ OFF,
+ /**
+ * Left turn signal is on
+ */
+ LEFT,
+ /**
+ * Right turn signal is on
+ */
+ RIGHT,
+ /**
+ * Both signals (left and right) are on.
+ */
+ BOTH,
+ ;
+
+ public static TurnSignal valueForString(String value) {
+ try{
+ return valueOf(value);
+ }catch(Exception e){
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/VehicleDataType.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/VehicleDataType.java
index adebca268..01525ef4a 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/VehicleDataType.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/VehicleDataType.java
@@ -82,6 +82,10 @@ public enum VehicleDataType {
*/
VEHICLEDATA_ENGINETORQUE,
/**
+ * Notifies ENGINEOILLIFEData may be subscribed
+ */
+ VEHICLEDATA_ENGINEOILLIFE,
+ /**
* Notifies ACCPEDALData may be subscribed
*/
VEHICLEDATA_ACCPEDAL,
@@ -108,8 +112,22 @@ public enum VehicleDataType {
/**
* Notifies MYKEYData may be subscribed
*/
- VEHICLEDATA_MYKEY;
- /**
+ VEHICLEDATA_MYKEY,
+
+ VEHICLEDATA_FUELRANGE,
+
+ /**
+ * Notifies TURNSIGNALData may be subscribed
+ */
+ VEHICLEDATA_TURNSIGNAL,
+
+ /**
+ * Notifies ELECTRONICPARKBRAKESTATUSData may be subscribed
+ */
+ VEHICLEDATA_ELECTRONICPARKBRAKESTATUS,
+ ;
+
+ /**
* Convert String to VehicleDataType
* @param value String
* @return VehicleDataType
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/VideoStreamingState.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/VideoStreamingState.java
new file mode 100644
index 000000000..80384016b
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/enums/VideoStreamingState.java
@@ -0,0 +1,23 @@
+package com.smartdevicelink.proxy.rpc.enums;
+
+/**
+ * Enumeration that describes possible states of video streaming.
+ * @since SmartDeviceLink 5.0
+ */
+public enum VideoStreamingState {
+ /**
+ * @since SmartDeviceLink 5.0
+ */
+ STREAMABLE,
+ /**
+ * @since SmartDeviceLink 5.0
+ */
+ NOT_STREAMABLE;
+ public static VideoStreamingState valueForString(String value) {
+ try{
+ return valueOf(value);
+ }catch(Exception e){
+ return null;
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/listeners/OnMultipleRequestListener.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/listeners/OnMultipleRequestListener.java
index 107de1bf9..88f119bdd 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/listeners/OnMultipleRequestListener.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/listeners/OnMultipleRequestListener.java
@@ -5,8 +5,6 @@ import android.util.Log;
import com.smartdevicelink.proxy.RPCResponse;
import com.smartdevicelink.proxy.rpc.enums.Result;
-import org.json.JSONException;
-
import java.util.Vector;
/**
@@ -25,6 +23,18 @@ public abstract class OnMultipleRequestListener extends OnRPCResponseListener {
rpcResponseListener = new OnRPCResponseListener() {
@Override
public void onResponse(int correlationId, RPCResponse response) {
+ OnMultipleRequestListener.this.onResponse(correlationId, response);
+ update(correlationId);
+ }
+
+ @Override
+ public void onError(int correlationId, Result resultCode, String info) {
+ super.onError(correlationId, resultCode, info);
+ OnMultipleRequestListener.this.onError(correlationId, resultCode, info);
+ update(correlationId);
+ }
+
+ private synchronized void update(int correlationId){
correlationIds.remove(Integer.valueOf(correlationId));
if(correlationIds.size()>0){
onUpdate(correlationIds.size());
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/listeners/OnRPCListener.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/listeners/OnRPCListener.java
new file mode 100644
index 000000000..8de606b7c
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/listeners/OnRPCListener.java
@@ -0,0 +1,55 @@
+package com.smartdevicelink.proxy.rpc.listeners;
+
+import com.smartdevicelink.proxy.RPCMessage;
+
+public abstract class OnRPCListener {
+
+ /**
+ * Generic listener for all RPCs including Requests, response, and notificaiton
+ */
+ public final static int UPDATE_LISTENER_TYPE_ALL_RPCS = -1;
+
+ /**
+ * Generic listener type that will work for most RPCs
+ */
+ public final static int UPDATE_LISTENER_TYPE_BASE_RPC = 0;
+ /**
+ * Listener type specific to putfile
+ */
+ public final static int UPDATE_LISTENER_TYPE_PUT_FILE = 1;
+ /**
+ * Listener type specific to sendRequests and sendSequentialRequests
+ */
+ public final static int UPDATE_LISTENER_TYPE_MULTIPLE_REQUESTS = 2;
+
+ /**
+ * Stores what type of listener this instance is. This prevents of from having to use reflection
+ */
+ int listenerType;
+
+ /**
+ * This is the base listener for all RPCs.
+ */
+ public OnRPCListener(){
+ setListenerType(UPDATE_LISTENER_TYPE_ALL_RPCS);
+ }
+
+ protected final void setListenerType(int type){
+ this.listenerType = type;
+ }
+ /**
+ * This is used to see what type of listener this instance is. It is needed
+ * because some RPCs require additional callbacks. Types are constants located in this class
+ * @return the type of listener this is
+ */
+ public int getListenerType(){
+ return this.listenerType;
+ }
+
+ /**
+ * This is the only method that must be extended.
+ * @param message This will be the response message received from the core side. It should be cast into a corresponding RPC Response type. ie, if setting this
+ * for a PutFile request, the message parameter should be cast to a PutFileResponse class.
+ */
+ public abstract void onReceived(final RPCMessage message);
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/listeners/OnRPCResponseListener.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/listeners/OnRPCResponseListener.java
index c21244926..2c40fe0df 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/listeners/OnRPCResponseListener.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/rpc/listeners/OnRPCResponseListener.java
@@ -1,77 +1,53 @@
-package com.smartdevicelink.proxy.rpc.listeners;
-
-import com.smartdevicelink.proxy.RPCResponse;
-import com.smartdevicelink.proxy.rpc.enums.Result;
-
-public abstract class OnRPCResponseListener {
- /**
- * Generic listener type that will work for most RPCs
- */
- public final static int UPDATE_LISTENER_TYPE_BASE_RPC = 0;
- /**
- * Listener type specific to putfile
- */
- public final static int UPDATE_LISTENER_TYPE_PUT_FILE = 1;
- /**
- * Listener type specific to sendRequests and sendSequentialRequests
- */
- public final static int UPDATE_LISTENER_TYPE_MULTIPLE_REQUESTS = 2;
-
- /**
- * Stores what type of listener this instance is. This prevents of from having to use reflection
- */
- int listenerType;
-
- /**
- * This is the base listener for all RPCs.
- */
- public OnRPCResponseListener(){
- setListenerType(UPDATE_LISTENER_TYPE_BASE_RPC);
- }
-
- protected final void setListenerType(int type){
- this.listenerType = type;
- }
- /**
- * This is used to see what type of listener this instance is. It is needed
- * because some RPCs require additional callbacks. Types are constants located in this class
- * @return the type of listener this is
- */
- public int getListenerType(){
- return this.listenerType;
- }
-
- /* *****************************************************************
- ************************* Event Callbacks *************************
- *******************************************************************/
-
- /**
- * This method will be called once the packet has been entered into the queue of messages to send
- * @param correlationId
- */
- public void onStart(int correlationId){
-
- };
-
- /**
- * This is the only method that must be extended. Other methods that are able to be extended are
- * onStart and onError.
- * @param correlationId
- * @param response This will be the response message received from the core side. It should be cast into a corresponding RPC Response type. ie, if setting this
- * for a PutFile request, the message parameter should be cast to a PutFileResponse class.
- */
- public abstract void onResponse(int correlationId, final RPCResponse response);
-
- /**
- * Called when there was some sort of error during the original request.
- * @param correlationId
- * @param resultCode
- * @param info
- */
- public void onError(int correlationId, Result resultCode, String info){
-
- };
-
-
-
-}
+package com.smartdevicelink.proxy.rpc.listeners;
+
+import com.smartdevicelink.proxy.RPCMessage;
+import com.smartdevicelink.proxy.RPCResponse;
+import com.smartdevicelink.proxy.rpc.enums.Result;
+
+public abstract class OnRPCResponseListener extends OnRPCListener {
+
+
+ public OnRPCResponseListener(){
+ setListenerType(OnRPCListener.UPDATE_LISTENER_TYPE_BASE_RPC);
+ }
+
+ public final void onReceived(final RPCMessage message){
+ if (message != null && message instanceof RPCResponse){
+ onResponse(((RPCResponse) message).getCorrelationID(), (RPCResponse)message);
+ }
+ }
+
+ /* *****************************************************************
+ ************************* Event Callbacks *************************
+ *******************************************************************/
+
+ /**
+ * This method will be called once the packet has been entered into the queue of messages to send
+ * @param correlationId
+ */
+ public void onStart(int correlationId){
+
+ };
+
+ /**
+ * This is the only method that must be extended. Other methods that are able to be extended are
+ * onStart and onError.
+ * @param correlationId
+ * @param response This will be the response message received from the core side. It should be cast into a corresponding RPC Response type. ie, if setting this
+ * for a PutFile request, the message parameter should be cast to a PutFileResponse class.
+ */
+ public abstract void onResponse(int correlationId, final RPCResponse response);
+
+ /**
+ * Called when there was some sort of error during the original request.
+ * @param correlationId
+ * @param resultCode
+ * @param info
+ */
+ public void onError(int correlationId, Result resultCode, String info){
+
+ };
+
+
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/security/SdlSecurityBase.java b/sdl_android/src/main/java/com/smartdevicelink/security/SdlSecurityBase.java
index b5efacaf1..b3f324267 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/security/SdlSecurityBase.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/security/SdlSecurityBase.java
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import android.app.Service;
+import android.content.Context;
import com.smartdevicelink.SdlConnection.SdlSession;
import com.smartdevicelink.protocol.enums.SessionType;
@@ -16,6 +17,7 @@ public abstract class SdlSecurityBase {
protected boolean isInitSuccess = false;
protected byte sessionId = 0;
protected static Service appService = null;
+ protected static Context context;
protected List<SessionType> startServiceList = new ArrayList<SessionType>();
public SdlSecurityBase() {
@@ -84,12 +86,25 @@ public abstract class SdlSecurityBase {
appId = val;
}
+ @Deprecated
public static Service getAppService() {
- return appService;
+ return appService;
}
-
+
+ @Deprecated
public static void setAppService(Service val) {
- appService = val;
+ appService = val;
+ if (val != null && val.getApplicationContext() != null){
+ setContext(val.getApplicationContext());
+ }
+ }
+
+ public static Context getContext() {
+ return context;
+ }
+
+ public static void setContext(Context val) {
+ context = val;
}
public List<String> getMakeList() {
diff --git a/sdl_android/src/main/java/com/smartdevicelink/streaming/AbstractPacketizer.java b/sdl_android/src/main/java/com/smartdevicelink/streaming/AbstractPacketizer.java
index 722fa54f9..1a2c393cd 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/streaming/AbstractPacketizer.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/streaming/AbstractPacketizer.java
@@ -6,6 +6,7 @@ import java.io.InputStream;
import com.smartdevicelink.SdlConnection.SdlSession;
import com.smartdevicelink.protocol.enums.SessionType;
import com.smartdevicelink.proxy.RPCRequest;
+import com.smartdevicelink.util.Version;
abstract public class AbstractPacketizer {
@@ -19,7 +20,7 @@ abstract public class AbstractPacketizer {
protected byte[] buffer;
protected boolean upts = false;
protected RPCRequest _request = null;
- protected byte _wiproVersion = 1;
+ protected Version _wiproVersion = new Version("1.0.0");
//protected long ts = 0, intervalBetweenReports = 5000, delta = 0;
protected long intervalBetweenReports = 5000, delta = 0;
@@ -38,13 +39,30 @@ abstract public class AbstractPacketizer {
}
}
+ @Deprecated
public AbstractPacketizer(IStreamListener streamListener, InputStream is, RPCRequest request, SessionType sType, byte rpcSessionID, byte wiproVersion, SdlSession session) throws IOException, IllegalArgumentException {
this._streamListener = streamListener;
this.is = is;
_rpcSessionID = rpcSessionID;
_serviceType = sType;
_request = request;
- _wiproVersion = wiproVersion;
+ _wiproVersion = new Version(wiproVersion+".0.0");
+ this._session = session;
+ if (this._session != null) {
+ bufferSize = this._session.getMtu();
+ buffer = new byte[bufferSize];
+ }else{
+ throw new IllegalArgumentException("Session variable is null");
+ }
+ }
+
+ public AbstractPacketizer(IStreamListener streamListener, InputStream is, RPCRequest request, SessionType sType, byte rpcSessionID, Version protocolVersion, SdlSession session) throws IOException, IllegalArgumentException {
+ this._streamListener = streamListener;
+ this.is = is;
+ _rpcSessionID = rpcSessionID;
+ _serviceType = sType;
+ _request = request;
+ _wiproVersion = protocolVersion;
this._session = session;
if (this._session != null) {
bufferSize = this._session.getMtu();
diff --git a/sdl_android/src/main/java/com/smartdevicelink/streaming/StreamPacketizer.java b/sdl_android/src/main/java/com/smartdevicelink/streaming/StreamPacketizer.java
index f6a668279..24f8eb926 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/streaming/StreamPacketizer.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/streaming/StreamPacketizer.java
@@ -8,7 +8,9 @@ import java.util.concurrent.LinkedBlockingQueue;
import com.smartdevicelink.SdlConnection.SdlConnection;
import com.smartdevicelink.SdlConnection.SdlSession;
+import com.smartdevicelink.protocol.AbstractProtocol;
import com.smartdevicelink.protocol.ProtocolMessage;
+import com.smartdevicelink.protocol.WiProProtocol;
import com.smartdevicelink.protocol.enums.SessionType;
import com.smartdevicelink.proxy.interfaces.IAudioStreamListener;
import com.smartdevicelink.proxy.interfaces.IVideoStreamListener;
@@ -33,7 +35,7 @@ public class StreamPacketizer extends AbstractPacketizer implements IVideoStream
// a limit of the buffer size, we avoid buffer overflows when underlying transport is too slow.
private static final int MAX_QUEUE_SIZE = 256 * 1024;
- public SdlConnection sdlConnection = null;
+ public SdlConnection sdlConnection = null; //TODO remove completely
private Object mPauseLock;
private boolean mPaused;
private boolean isServiceProtected = false;
@@ -140,10 +142,14 @@ public class StreamPacketizer extends AbstractPacketizer implements IVideoStream
}
finally
{
- if (sdlConnection != null)
- {
- sdlConnection.endService(_serviceType, _rpcSessionID);
- }
+ if(_session == null) {
+ if (sdlConnection != null) {
+ sdlConnection.endService(_serviceType, _rpcSessionID);
+ }
+ }else{
+ _session.endService(_serviceType,_rpcSessionID);
+ }
+
}
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/streaming/StreamRPCPacketizer.java b/sdl_android/src/main/java/com/smartdevicelink/streaming/StreamRPCPacketizer.java
index 5652aafc3..8aab788c9 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/streaming/StreamRPCPacketizer.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/streaming/StreamRPCPacketizer.java
@@ -22,6 +22,7 @@ import com.smartdevicelink.proxy.rpc.PutFileResponse;
import com.smartdevicelink.proxy.rpc.StreamRPCResponse;
import com.smartdevicelink.proxy.rpc.enums.Result;
import com.smartdevicelink.proxy.rpc.listeners.OnPutFileUpdateListener;
+import com.smartdevicelink.util.Version;
public class StreamRPCPacketizer extends AbstractPacketizer implements IPutFileResponseListener, Runnable{
@@ -36,7 +37,9 @@ public class StreamRPCPacketizer extends AbstractPacketizer implements IPutFileR
private Object mPauseLock;
private boolean mPaused;
private boolean isRPCProtected = false;
- private OnPutFileUpdateListener callBack;
+ private OnPutFileUpdateListener callBack;
+
+ private Version rpcSpecVersion;
public StreamRPCPacketizer(SdlProxyBase<IProxyListenerBase> proxy, IStreamListener streamListener, InputStream is, RPCRequest request, SessionType sType, byte rpcSessionID, byte wiproVersion, long lLength, SdlSession session) throws IOException {
super(streamListener, is, request, sType, rpcSessionID, wiproVersion, session);
@@ -56,6 +59,24 @@ public class StreamRPCPacketizer extends AbstractPacketizer implements IPutFileR
}
}
+ public StreamRPCPacketizer(SdlProxyBase<IProxyListenerBase> proxy, IStreamListener streamListener, InputStream is, RPCRequest request, SessionType sType, byte rpcSessionID, Version wiproVersion, Version rpcSpecVersion, long lLength, SdlSession session) throws IOException {
+ super(streamListener, is, request, sType, rpcSessionID, wiproVersion, session);
+ this.rpcSpecVersion = rpcSpecVersion;
+ lFileSize = lLength;
+ iInitialCorrID = request.getCorrelationID();
+ mPauseLock = new Object();
+ mPaused = false;
+ isRPCProtected = request.isPayloadProtected();
+ if (proxy != null) {
+ _proxy = proxy;
+ _proxyListener = _proxy.getProxyListener();
+ _proxy.addPutFileResponseListener(this);
+ }
+ if(_request.getFunctionName().equalsIgnoreCase(FunctionID.PUT_FILE.toString())){
+ callBack = ((PutFile)_request).getOnPutFileUpdateListener();
+ }
+ }
+
@Override
public void start() throws IOException {
if (thread == null) {
@@ -201,7 +222,8 @@ public class StreamRPCPacketizer extends AbstractPacketizer implements IPutFileR
if (msg.getOffset() != 0)
msg.setLength((Long)null); //only need to send length when offset 0
- msgBytes = JsonRPCMarshaller.marshall(msg, _wiproVersion);
+ msg.format(rpcSpecVersion,true);
+ msgBytes = JsonRPCMarshaller.marshall(msg, (byte)_wiproVersion.getMajor());
pm = new ProtocolMessage();
pm.setData(msgBytes);
diff --git a/sdl_android/src/main/java/com/smartdevicelink/streaming/video/RTPH264Packetizer.java b/sdl_android/src/main/java/com/smartdevicelink/streaming/video/RTPH264Packetizer.java
index 6946d1fbb..1e2b9c5da 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/streaming/video/RTPH264Packetizer.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/streaming/video/RTPH264Packetizer.java
@@ -219,7 +219,6 @@ public class RTPH264Packetizer extends AbstractPacketizer implements IVideoStrea
* The thread routine.
*/
public void run() {
- SdlConnection connection = _session.getSdlConnection();
while (mThread != null && !mThread.isInterrupted()) {
ByteBuffer frame;
@@ -249,8 +248,8 @@ public class RTPH264Packetizer extends AbstractPacketizer implements IVideoStrea
// XXX: This is added to sync with StreamPacketizer. Actually it shouldn't be here since
// it's confusing that a packetizer takes care of End Service request.
- if (connection != null) {
- connection.endService(_serviceType, _rpcSessionID);
+ if (_session != null) {
+ _session.endService(_serviceType, _rpcSessionID);
}
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/streaming/video/VideoStreamingParameters.java b/sdl_android/src/main/java/com/smartdevicelink/streaming/video/VideoStreamingParameters.java
index f565a22dc..121176cc2 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/streaming/video/VideoStreamingParameters.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/streaming/video/VideoStreamingParameters.java
@@ -133,7 +133,7 @@ public class VideoStreamingParameters {
* @see VideoStreamingCapability
*/
public void update(VideoStreamingCapability capability){
- if(capability.getMaxBitrate()!=null){ this.bitrate = capability.getMaxBitrate(); }
+ if(capability.getMaxBitrate()!=null){ this.bitrate = capability.getMaxBitrate() * 1000; } // NOTE: the unit of maxBitrate in getSystemCapability is kbps.
ImageResolution resolution = capability.getPreferredResolution();
if(resolution!=null){
if(resolution.getResolutionHeight()!=null && resolution.getResolutionHeight() > 0){ this.resolution.setResolutionHeight(resolution.getResolutionHeight()); }
@@ -215,4 +215,4 @@ public class VideoStreamingParameters {
builder.append("}");
return builder.toString();
}
-} \ No newline at end of file
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/BTTransport.java b/sdl_android/src/main/java/com/smartdevicelink/transport/BTTransport.java
index 5d0c9bed5..74ca18478 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/BTTransport.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/BTTransport.java
@@ -26,6 +26,7 @@ import com.smartdevicelink.util.DebugTool;
* Bluetooth Transport Implementation. This transport advertises its existence to SDL by publishing an SDP record and waiting for an incoming connection from SDL. Connection is verified by checking for the SDL UUID. For more detailed information please refer to the <a href="#bluetoothTransport">Bluetooth Transport Guide</a>.
*
*/
+@Deprecated
public class BTTransport extends SdlTransport {
//936DA01F9ABD4D9D80C702AF85C822A8
private final static UUID SDL_V4_MOBILE_APPLICATION_SVC_CLASS = new UUID(0x936DA01F9ABD4D9DL, 0x80C702AF85C822A8L);
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/BTTransportConfig.java b/sdl_android/src/main/java/com/smartdevicelink/transport/BTTransportConfig.java
index 5de6022b2..0f2c4a7e5 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/BTTransportConfig.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/BTTransportConfig.java
@@ -5,6 +5,7 @@ import com.smartdevicelink.transport.enums.TransportType;
/**
* Container of Bluetooth transport specific configuration.
*/
+@Deprecated
public final class BTTransportConfig extends BaseTransportConfig {
private boolean bKeepSocketActive = true;
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBaseTransport.java b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBaseTransport.java
new file mode 100644
index 000000000..d1dc5cbb3
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBaseTransport.java
@@ -0,0 +1,120 @@
+/*
+ * 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 android.os.Handler;
+
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
+
+public abstract class MultiplexBaseTransport {
+
+ // Constants that indicate the current connection state
+ public static final int STATE_NONE = 0; // we're doing nothing
+ public static final int STATE_LISTEN = 1; // now listening for incoming connections
+ public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
+ public static final int STATE_CONNECTED = 3; // now connected to a remote device
+ public static final int STATE_ERROR = 4; // Something bad happened, we wil not try to restart the thread
+
+ public static final String LOG = "log";
+ public static final String DEVICE_NAME = "device_name";
+ public static final String DEVICE_ADDRESS = "device_address";
+
+ protected int mState = STATE_NONE;
+ protected final Handler handler;
+ protected final TransportType transportType;
+
+ protected TransportRecord transportRecord;
+ @Deprecated
+ public static String currentlyConnectedDevice = null;
+ protected String connectedDeviceName = null;
+ public String connectedDeviceAddress = null;
+
+
+ protected MultiplexBaseTransport(Handler handler, TransportType transportType){
+ this.handler = handler;
+ this.transportType = transportType;
+ }
+
+ protected synchronized void setState(int state) {
+ if(state == mState){
+ return; //State hasn't changed. Will not updated listeners.
+ }
+ //Log.d(TAG, "Setting state from: " +mState + " to: " +state);
+ int previousState = mState;
+ mState = state;
+
+ // Give the new state to the Handler so the UI Activity can update
+ //Also sending the previous state so we know if we lost a connection
+ handler.obtainMessage(SdlRouterService.MESSAGE_STATE_CHANGE, state, previousState, getTransportRecord()).sendToTarget();
+ }
+
+ public String getAddress(){
+ return connectedDeviceAddress;
+ }
+
+ public String getDeviceName(){
+ return connectedDeviceName;
+ }
+
+ /**
+ * Should only be called after a connection has been established
+ * @return
+ */
+ public TransportRecord getTransportRecord() {
+ if(transportRecord == null){
+ transportRecord = new TransportRecord(transportType,connectedDeviceAddress);
+ }
+ return transportRecord;
+ }
+
+ /**
+ * Return the current connection state. */
+ public synchronized int getState() {
+ return mState;
+ }
+
+ public boolean isConnected()
+ {
+ return (mState == STATE_CONNECTED);
+ }
+
+ public synchronized void stop() {
+ stop(STATE_NONE);
+ }
+
+ protected abstract void stop(int state);
+
+ public abstract void write(byte[] out, int offset, int count);
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java
index c27182d76..dd66784f7 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexBluetoothTransport.java
@@ -32,13 +32,16 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
+import com.smartdevicelink.protocol.SdlPacket;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
+
/**
* This class does all the work for setting up and managing Bluetooth
* connections with other devices. It has a thread that listens for
@@ -48,58 +51,38 @@ import android.util.Log;
* @author Joey Grover
*
*/
-public class MultiplexBluetoothTransport {
+public class MultiplexBluetoothTransport extends MultiplexBaseTransport{
//finals
private static final String TAG = "Bluetooth Transport";
private static final UUID SERVER_UUID= new UUID(0x936DA01F9ABD4D9DL, 0x80C702AF85C822A8L);
// Name for the SDP record when creating server socket
private static final String NAME_SECURE =" SdlRouterService";
// Key names received from the BluetoothSerialServer Handler
- public static final String DEVICE_NAME = "device_name";
- public static final String DEVICE_ADDRESS = "device_address";
- public static final String TOAST = "toast";
private static final long MS_TILL_TIMEOUT = 2500;
private static final int READ_BUFFER_SIZE = 4096;
- private static final Object THREAD_LOCK = new Object();;
+ private final Object THREAD_LOCK = new Object();;
protected static final String SHARED_PREFS = "sdl.bluetoothprefs";
- // Constants that indicate the current connection state
- public static final int STATE_NONE = 0; // we're doing nothing
- public static final int STATE_LISTEN = 1; // now listening for incoming connections
- public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
- public static final int STATE_CONNECTED = 3; // now connected to a remote device
- public static final int STATE_ERROR = 4; // Something bad happend, we wil not try to restart the thread
-
// Member fields
private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
- private final Handler mHandler;
- private AcceptThread mSecureAcceptThread;
+ private AcceptThread mSecureAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private ConnectedWriteThread mConnectedWriteThread;
- private int mState;
private int mBluetoothLevel = 0;
Handler timeOutHandler;
Runnable socketRunable;
boolean keepSocketAlive = true;
- public static String currentlyConnectedDevice = null;
- public static String currentlyConnectedDeviceAddress = null;
-
-
/**
* Constructor. Prepares a new BluetoothChat session.
* @param handler A Handler to send messages back to the UI Activity
*/
public MultiplexBluetoothTransport(Handler handler) {
- //Log.w(TAG, "Creating Bluetooth Serial Adapter");
- // mAdapter = BluetoothAdapter.getDefaultAdapter();
- mState = STATE_NONE;
- mHandler = handler;
-
- //This will keep track of which method worked last night
+ super(handler, TransportType.BLUETOOTH);
+ //This will keep track of which method worked last night
mBluetoothLevel = SdlRouterService.getBluetoothPrefs(SHARED_PREFS);
}
@@ -149,19 +132,6 @@ public class MultiplexBluetoothTransport {
//Log.d(TAG, "Setting state from: " +mState + " to: " +state);
mState = state;
}
- /**
- * Set the current state of the chat connection
- * @param state An integer defining the current connection state
- */
- private synchronized void setState(int state) {
- //Log.d(TAG, "Setting state from: " +mState + " to: " +state);
- int previousState = mState;
- mState = state;
-
- // Give the new state to the Handler so the UI Activity can update
- //Also sending the previous state so we know if we lost a connection
- mHandler.obtainMessage(SdlRouterService.MESSAGE_STATE_CHANGE, state, previousState).sendToTarget();
- }
/**
* Return the current connection state. */
@@ -261,19 +231,25 @@ public class MultiplexBluetoothTransport {
mConnectedWriteThread = new ConnectedWriteThread(socket);
mConnectedWriteThread.start();
-
+ //Store a static name of the device that is connected.
+ if(device != null){
+ connectedDeviceName = device.getName();
+ connectedDeviceAddress = device.getAddress();
+ if(connectedDeviceAddress!=null){
+ //Update the transport record with the address
+ transportRecord = new TransportRecord(transportType, connectedDeviceAddress);
+ }
+ }
// Send the name of the connected device back to the UI Activity
- Message msg = mHandler.obtainMessage(SdlRouterService.MESSAGE_DEVICE_NAME);
+ Message msg = handler.obtainMessage(SdlRouterService.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
- //Store a static name of the device that is connected.
- currentlyConnectedDevice = device.getName();
- if(currentlyConnectedDevice != null){
- bundle.putString(DEVICE_NAME, currentlyConnectedDevice);
- bundle.putString(DEVICE_ADDRESS, device.getAddress());
+ if(connectedDeviceName != null) {
+ bundle.putString(DEVICE_NAME, connectedDeviceName);
+ bundle.putString(DEVICE_ADDRESS, connectedDeviceAddress);
}
msg.setData(bundle);
- mHandler.sendMessage(msg);
+ handler.sendMessage(msg);
setState(STATE_CONNECTED);
}
@@ -328,11 +304,11 @@ public class MultiplexBluetoothTransport {
*/
private void connectionFailed() {
// Send a failure message back to the Activity
- Message msg = mHandler.obtainMessage(SdlRouterService.MESSAGE_TOAST);
+ Message msg = handler.obtainMessage(SdlRouterService.MESSAGE_LOG);
Bundle bundle = new Bundle();
- bundle.putString(TOAST, "Unable to connect device");
+ bundle.putString(LOG, "Unable to connect device");
msg.setData(bundle);
- mHandler.sendMessage(msg);
+ handler.sendMessage(msg);
// Start the service over to restart listening mode
// BluetoothSerialServer.this.start();
@@ -343,11 +319,11 @@ public class MultiplexBluetoothTransport {
*/
private void connectionLost() {
// Send a failure message back to the Activity
- Message msg = mHandler.obtainMessage(SdlRouterService.MESSAGE_TOAST);
+ Message msg = handler.obtainMessage(SdlRouterService.MESSAGE_LOG);
Bundle bundle = new Bundle();
- bundle.putString(TOAST, "Device connection was lost");
+ bundle.putString(LOG, "Device connection was lost");
msg.setData(bundle);
- mHandler.sendMessage(msg);
+ handler.sendMessage(msg);
stop();
}
@@ -778,8 +754,6 @@ public class MultiplexBluetoothTransport {
byte input = 0;
int bytesRead = 0;
byte[] buffer = new byte[READ_BUFFER_SIZE];
- MultiplexBluetoothTransport.currentlyConnectedDevice = mmSocket.getRemoteDevice().getName();
- MultiplexBluetoothTransport.currentlyConnectedDeviceAddress = mmSocket.getRemoteDevice().getAddress();
// Keep listening to the InputStream while connected
boolean stateProgress;
@@ -788,7 +762,7 @@ public class MultiplexBluetoothTransport {
while (true) {
try {
bytesRead = mmInStream.read(buffer);
- //Log.i(getClass().getName(), "Received " + bytesRead + " bytes from Bluetooth");
+ // Log.i(getClass().getName(), "Received " + bytesRead + " bytes from Bluetooth");
for (int i = 0; i < bytesRead; i++) {
input = buffer[i];
@@ -802,7 +776,9 @@ public class MultiplexBluetoothTransport {
if (psm.getState() == SdlPsm.FINISHED_STATE) {
//Log.d(TAG, "Packet formed, sending off");
- mHandler.obtainMessage(SdlRouterService.MESSAGE_READ, psm.getFormedPacket()).sendToTarget();
+ SdlPacket packet = psm.getFormedPacket();
+ packet.setTransportRecord(getTransportRecord());
+ handler.obtainMessage(SdlRouterService.MESSAGE_READ, packet).sendToTarget();
psm.reset();
}
}
@@ -833,14 +809,10 @@ public class MultiplexBluetoothTransport {
}
}
- public boolean isConnected()
- {
- return !(mState == STATE_NONE);
- }
- @Deprecated
+
public BluetoothSocket getBTSocket(BluetoothServerSocket bsSocket){
- if(bsSocket == null || Build.VERSION.SDK_INT > Build.VERSION_CODES.O){ //Reflection is no longer allowed on SDK classes
+ if(bsSocket == null){
return null;
}
Field[] f = bsSocket.getClass().getDeclaredFields();
@@ -866,12 +838,11 @@ public class MultiplexBluetoothTransport {
return null;
}
-
- @Deprecated
+
public int getChannel(BluetoothSocket bsSocket){
int channel = -1;
- if (bsSocket == null || Build.VERSION.SDK_INT > Build.VERSION_CODES.O){ //Reflection is no longer allowed on SDK classes
+ if (bsSocket == null){
return channel;
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTcpTransport.java b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTcpTransport.java
new file mode 100644
index 000000000..d5843f4c2
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTcpTransport.java
@@ -0,0 +1,413 @@
+/*
+ * 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 android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import com.smartdevicelink.protocol.SdlPacket;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.WiFiSocketFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+import static com.smartdevicelink.util.DebugTool.logError;
+import static com.smartdevicelink.util.NativeLogTool.logInfo;
+
+public class MultiplexTcpTransport extends MultiplexBaseTransport {
+
+ private static final String TAG = "MultiplexTcpTransport";
+
+ private static final int READ_BUFFER_SIZE = 4096;
+ private static final int RECONNECT_DELAY = 5000;
+ private static final int RECONNECT_RETRY_COUNT = 30;
+
+ private final String ipAddress;
+ private final int port;
+ private final boolean autoReconnect;
+ private Socket mSocket = null;
+ private InputStream mInputStream = null;
+ private OutputStream mOutputStream = null;
+ private MultiplexTcpTransport.TcpTransportThread mThread = null;
+ private WriterThread writerThread;
+ private Context mContext;
+
+
+ public MultiplexTcpTransport(int port, String ipAddress, boolean autoReconnect, Handler handler, Context context) {
+ super(handler, TransportType.TCP);
+ this.ipAddress = ipAddress;
+ this.port = port;
+ connectedDeviceAddress = ipAddress + ":" + port;
+ this.autoReconnect = autoReconnect;
+ mContext = context;
+ setState(STATE_NONE);
+ }
+
+ public synchronized void start(){
+ if(getState() == STATE_NONE) {
+ synchronized (this) {
+ setState(STATE_CONNECTING);
+ logInfo("TCPTransport: openConnection request accepted. Starting transport thread");
+ try {
+ mThread = new MultiplexTcpTransport.TcpTransportThread();
+ mThread.setDaemon(true);
+ mThread.start();
+
+ // Initialize the SiphonServer
+ if (SiphonServer.getSiphonEnabledStatus()) {
+ SiphonServer.init();
+ }
+
+ } catch (Exception e) {
+ logError("TCPTransport: Exception during transport thread starting", e);
+ }
+ }
+ } else {
+ logInfo("TCPTransport: openConnection request rejected. Another connection is not finished");
+ }
+
+ // Send the name of the connected device back to the UI Activity
+ Message msg = handler.obtainMessage(SdlRouterService.MESSAGE_DEVICE_NAME);
+ Bundle bundle = new Bundle();
+ bundle.putString(DEVICE_NAME, connectedDeviceName);
+ bundle.putString(DEVICE_ADDRESS, connectedDeviceAddress);
+ msg.setData(bundle);
+ handler.sendMessage(msg);
+ }
+
+
+ @Override
+ protected void stop(int state) {
+ try {
+ if(mThread != null) {
+ mThread.halt();
+ mThread.interrupt();
+ }
+
+ if (writerThread != null) {
+ writerThread.cancel();
+ writerThread = null;
+ }
+
+ if(mSocket != null){
+ mSocket.close();
+ }
+ mSocket = null;
+ } catch (IOException e) {
+ logError("TCPTransport.disconnect: Exception during disconnect: " + e.getMessage());
+ }
+
+ setState(state);
+ }
+
+ @Override
+ public void write(byte[] out, int offset, int count) {
+ // Create temporary object
+ MultiplexTcpTransport.WriterThread r;
+ // Synchronize a copy of the ConnectedThread
+ synchronized (this) {
+ if (mState != STATE_CONNECTED) return;
+ r = writerThread;
+ //r.write(out,offset,count);
+ }
+ // Perform the write unsynchronized
+ r.write(out,offset,count);
+ }
+
+ /**
+ * Implementation of waiting required delay that cannot be interrupted
+ * @param timeMs Time in milliseconds of required delay
+ */
+ private void waitFor(long timeMs) {
+ long endTime = System.currentTimeMillis() +timeMs;
+ while (System.currentTimeMillis() < endTime) {
+ synchronized (this) {
+ try {
+ wait(endTime - System.currentTimeMillis());
+ } catch (Exception e) {
+ // Nothing To Do, simple wait
+ }
+ }
+ }
+ }
+
+ private void startWriteThread() {
+ if (writerThread == null) {
+ writerThread = new MultiplexTcpTransport.WriterThread();
+ writerThread.start();
+ }
+ }
+
+ /**
+ * Internal class that represents separate thread, that does actual work, related to connecting/reading/writing data
+ */
+ private class TcpTransportThread extends Thread {
+ SdlPsm psm;
+ public TcpTransportThread(){
+ psm = new SdlPsm();
+ }
+ /**
+ * Represents current thread state - halted or not. This flag is used to change internal behavior depending
+ * on current state.
+ */
+ private Boolean isHalted = false;
+
+ /**
+ * Method that marks thread as halted.
+ */
+ public void halt() {
+ isHalted = true;
+ }
+
+ /**
+ * Tries to connect to the SmartDeviceLink core. Behavior depends autoReconnect configuration param:
+ * a) If autoReconnect is false, then only one connect try will be performed.
+ * b) If autoReconnect is true, then in case of connection error continuous reconnect will be performed
+ * after short delay until connection will be established or retry count will be reached
+ *
+ * @return true if connection established and false otherwise
+ */
+ private boolean connect() {
+ boolean bConnected;
+ int remainingRetry = RECONNECT_RETRY_COUNT;
+
+ synchronized (MultiplexTcpTransport.this) {
+ do {
+ try {
+
+ if ((null != mSocket) && (!mSocket.isClosed())) {
+ logInfo("TCPTransport.connect: Socket is not closed. Trying to close it");
+ mSocket.close();
+ }
+
+ logInfo(String.format("TCPTransport.connect: Socket is closed. Trying to connect to %s", getAddress()));
+ mSocket = WiFiSocketFactory.createSocket(mContext);
+ mSocket.connect(new InetSocketAddress(ipAddress, port));
+ mOutputStream = mSocket.getOutputStream();
+ mInputStream = mSocket.getInputStream();
+ startWriteThread();
+ } catch (IOException e) {
+ logError("TCPTransport.connect: Exception during connect stage: " + e.getMessage());
+ }
+
+ bConnected = (null != mSocket) && mSocket.isConnected();
+
+ if(bConnected){
+ logInfo("TCPTransport.connect: Socket connected");
+ setState(STATE_CONNECTED);
+ }else{
+ if(autoReconnect){
+ remainingRetry--;
+ logInfo(String.format("TCPTransport.connect: Socket not connected. AutoReconnect is ON. retryCount is: %d. Waiting for reconnect delay: %d"
+ , remainingRetry, RECONNECT_DELAY));
+ waitFor(RECONNECT_DELAY);
+ } else {
+ logInfo("TCPTransport.connect: Socket not connected. AutoReconnect is OFF");
+ }
+ }
+ } while ((!bConnected) && (autoReconnect) && (remainingRetry > 0) && (!isHalted));
+
+ return bConnected;
+ }
+ }
+
+ /**
+ * Performs actual thread work
+ */
+ @Override
+ public void run() {
+ logInfo("TCPTransport.run: transport thread created. Starting connect stage");
+ psm.reset();
+ while(!isHalted) {
+ setState(STATE_CONNECTING);
+ if(!connect()){
+ if (isHalted) {
+ logInfo("TCPTransport.run: Connection failed, but thread already halted");
+ } else {
+ MultiplexTcpTransport.this.stop(STATE_NONE);
+ }
+ break;
+ }
+
+ synchronized (MultiplexTcpTransport.this) {
+ setState(STATE_CONNECTED);
+ }
+
+ byte input;
+ byte[] buffer = new byte[READ_BUFFER_SIZE];
+ int bytesRead;
+ boolean stateProgress = false;
+ while (!isHalted) {
+ //logInfo("TCPTransport.run: Waiting for data...");
+ try {
+ //input = (byte) mInputStream.read();
+ bytesRead = mInputStream.read(buffer);
+ } catch (IOException e) {
+ internalHandleStreamReadError();
+ break;
+ }
+
+ if (bytesRead == -1) {
+ // Javadoc says -1 indicates end of input stream. In TCP case this means loss
+ // of connection from HU (no exception is thrown when HU connection is lost).
+ internalHandleStreamReadError();
+ break;
+ }
+
+ synchronized (MultiplexTcpTransport.this) {
+ if (mThread.isInterrupted()) {
+ logInfo("TCPTransport.run: Got new data but thread is interrupted");
+ break;
+ }
+ }
+ for (int i = 0; i < bytesRead; i++) {
+ //logInfo("TCPTransport.run: Got new data");
+ // Send the response of what we received
+ input = buffer[i];
+ stateProgress = psm.handleByte(input);
+ 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)
+ {
+ synchronized (MultiplexTcpTransport.this) {
+ Log.d(TAG, "Packet formed, sending off");
+ SdlPacket packet = psm.getFormedPacket();
+ packet.setTransportRecord(getTransportRecord());
+ handler.obtainMessage(SdlRouterService.MESSAGE_READ, packet).sendToTarget();
+ }
+ //We put a trace statement in the message read so we can avoid all the extra bytes
+ psm.reset();
+ }
+ //FIXME logInfo(String.format("TCPTransport.run: Received %d bytes", bytesRead));
+ }
+ }
+ }
+
+ logInfo("TCPTransport.run: Thread terminated");
+ setState(STATE_NONE);
+ }
+
+ /**
+ * Internal handling of Tcp disconnection
+ */
+ private void internalHandleTCPDisconnect() {
+ if(isHalted){
+ logInfo("TCPTransport.run: TCP disconnect received, but thread already halted");
+ } else {
+ logInfo("TCPTransport.run: TCP disconnect received");
+ MultiplexTcpTransport.this.stop(STATE_NONE);
+ }
+ }
+
+ /**
+ * Internal handling of reading data from input stream
+ */
+ private void internalHandleStreamReadError() {
+ if(isHalted){
+ logError("TCPTransport.run: Exception during reading data, but thread already halted");
+ } else {
+ logError("TCPTransport.run: Exception during reading data");
+ MultiplexTcpTransport.this.stop(STATE_NONE);
+ }
+ }
+ }
+
+ private class WriterThread extends Thread {
+ private boolean mCancelled = false;
+ private boolean mVerbose = false;
+
+ public void write(byte[] msgBytes, int offset, int count) {
+ if ((msgBytes == null) || (msgBytes.length == 0)) {
+ logInfo("TCPTransport.sendBytesOverTransport: nothing to send");
+ return;
+ }
+
+ if (offset + count > msgBytes.length) {
+ count = msgBytes.length - offset;
+ }
+
+ OutputStream out;
+ synchronized (MultiplexTcpTransport.this) {
+ out = mOutputStream;
+ }
+
+ if ((out != null) && (!mCancelled)) {
+ try {
+ out.write(msgBytes, offset, count);
+ if (mVerbose) {
+ logInfo("TCPTransport.sendBytesOverTransport: successfully sent data");
+ }
+ } catch (IOException e) {
+ logError("TCPTransport.sendBytesOverTransport: error during sending data: " + e.getMessage());
+ }
+ } else {
+ if (mCancelled) {
+ logError("TCPTransport: sendBytesOverTransport request accepted, thread is cancelled");
+ } else {
+ logError("TCPTransport: sendBytesOverTransport request accepted, but output stream is null");
+ }
+ }
+ }
+
+ public synchronized void cancel() {
+ mCancelled = true;
+ if (mOutputStream != null) {
+ synchronized (MultiplexTcpTransport.this) {
+ try {
+ mOutputStream.flush();
+ } catch (IOException e) {
+ logError("TCPTransport flushing output stream failed: " + e.getMessage());
+ }
+
+ try {
+ mOutputStream.close();
+ } catch (IOException e) {
+ logError("TCPTransport closing output stream failed: " + e.getMessage());
+ }
+ mOutputStream = null;
+ }
+ }
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTransport.java b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTransport.java
index c7cb0e59e..eac5a27e0 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTransport.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTransport.java
@@ -1,3 +1,35 @@
+/*
+ * 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 android.annotation.SuppressLint;
@@ -12,7 +44,11 @@ import com.smartdevicelink.SdlConnection.SdlConnection;
import com.smartdevicelink.exception.SdlException;
import com.smartdevicelink.protocol.SdlPacket;
import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
+
+import java.util.List;
+@Deprecated
public class MultiplexTransport extends SdlTransport{
private final static String TAG = "Multiplex Transport";
private String sComment = "Multiplexing";
@@ -256,6 +292,10 @@ public class MultiplexTransport extends SdlTransport{
}
@Override
+ public void onHardwareDisconnected(TransportRecord transportRecord, List<TransportRecord> connected) {
+ onHardwareDisconnected(TransportType.BLUETOOTH);
+ }
+ @Override
public void onHardwareDisconnected(TransportType type) {
super.onHardwareDisconnected(type);
if(connected){
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTransportConfig.java b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTransportConfig.java
index 82fadbee2..8a3e39d20 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTransportConfig.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTransportConfig.java
@@ -1,10 +1,47 @@
+/*
+ * 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.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
import android.content.ComponentName;
import android.content.Context;
+import java.util.Arrays;
+import java.util.List;
+
+@SuppressWarnings("WeakerAccess")
public class MultiplexTransportConfig extends BaseTransportConfig{
/**
@@ -35,19 +72,26 @@ public class MultiplexTransportConfig extends BaseTransportConfig{
ComponentName service;
int securityLevel;
-
+ List<TransportType> primaryTransports, secondaryTransports;
+ boolean requiresHighBandwidth = false;
+ TransportListener transportListener;
public MultiplexTransportConfig(Context context, String appId) {
this.context = context;
this.appId = appId;
this.securityLevel = FLAG_MULTI_SECURITY_MED;
+ this.primaryTransports = Arrays.asList(TransportType.USB, TransportType.BLUETOOTH);
+ this.secondaryTransports = Arrays.asList(TransportType.TCP, TransportType.USB, TransportType.BLUETOOTH);
+
}
public MultiplexTransportConfig(Context context, String appId, int securityLevel) {
this.context = context;
this.appId = appId;
this.securityLevel = securityLevel;
+ this.primaryTransports = Arrays.asList(TransportType.USB, TransportType.BLUETOOTH);
+ this.secondaryTransports = Arrays.asList(TransportType.TCP, TransportType.USB, TransportType.BLUETOOTH);
}
/**
@@ -60,28 +104,162 @@ public class MultiplexTransportConfig extends BaseTransportConfig{
public TransportType getTransportType() {
return TransportType.MULTIPLEX;
}
-
+
+ /**
+ * Gets the context attached to this config
+ * @return context supplied during creation
+ */
public Context getContext(){
return this.context;
}
-
+ /**
+ * Gets the ComponentName of the router service attached to this config
+ * @return ComponentName of the router service that will be bound to
+ */
public ComponentName getService() {
return service;
}
-
+ /**
+ * Supplies the config with the router service that should be bound to
+ * @param service the router service that should be bound to
+ */
public void setService(ComponentName service) {
this.service = service;
}
-
+
+ /**
+ * Sets the security level that should be used to verify a router service that is to be bound
+ * @param securityLevel the security level that will be used to perform certain tests
+ * @see #FLAG_MULTI_SECURITY_OFF
+ * @see #FLAG_MULTI_SECURITY_LOW
+ * @see #FLAG_MULTI_SECURITY_MED
+ * @see #FLAG_MULTI_SECURITY_HIGH
+ */
public void setSecurityLevel(int securityLevel){
this.securityLevel = securityLevel;
}
-
+
+ /**
+ * Get the securitly level that will be used to verify a router service before binding
+ * @return the set security level
+ * @see #FLAG_MULTI_SECURITY_OFF
+ * @see #FLAG_MULTI_SECURITY_LOW
+ * @see #FLAG_MULTI_SECURITY_MED
+ * @see #FLAG_MULTI_SECURITY_HIGH
+ */
public int getSecurityLevel(){
return securityLevel;
}
-
+
+ /**
+ * Set whether or not this app requires the use of a transport that supports high bandwidth
+ * services. Common use is when an app uses the video/audio streaming services and there is no
+ * other integration that could be useful to the user.
+ * <br><br> <b>For example:</b>
+ * <br><b>1. </b>If an app intends to perform audio or video streaming and does not wish
+ * to appear on the module when that isn't possible, a value of true should be sent.
+ * <br><b>2. </b>If the same app wishes to appear on the module even when those services aren't available
+ * a value of true should be sent. In this case, the app could display a message prompting the
+ * user to "Please connect USB or Wifi" or it could have a separate integration like giving turn
+ * by turn directions in place of streaming the full navigation map.
+ * @param requiresHighBandwidth whether the app should be treated as requiring a high
+ * bandwidth transport.
+ */
+ public void setRequiresHighBandwidth(boolean requiresHighBandwidth){
+ this.requiresHighBandwidth = requiresHighBandwidth;
+ }
+
+ /**
+ * Get the setting from this config to see whether the app should be treated as requiring a high
+ * bandwidth transport.
+ * @return whether the app should be treated as requiring a high
+ * bandwidth transport.
+ */
+ public boolean requiresHighBandwidth(){
+ return this.requiresHighBandwidth;
+ }
+
+ /**
+ * This will set the order in which a primary transport is determined to be accepted or not.
+ * In the case of previous protocol versions ( < 5.1)
+ * @param transports list of transports that can be used as primary
+ */
+ public void setPrimaryTransports(List<TransportType> transports){
+ if(transports != null){
+ //Sanitize
+ transports.remove(TransportType.MULTIPLEX);
+ this.primaryTransports = transports;
+ }
+ }
+
+ /**
+ * Get the list of primary transports that are set to be accepted by this config
+ * @return acceptable primary transports
+ */
+ public List<TransportType> getPrimaryTransports(){
+ return this.primaryTransports;
+ }
+
+ /**
+ * This will set the order in which a primary transport is determined to be accepted or not.
+ * In the case of previous protocol versions ( < 5.1)
+ * @param transports list of transports that can be used as secondary
+ **/
+ public void setSecondaryTransports(List<TransportType> transports){
+ if(transports != null){
+ //Sanitize
+ transports.remove(TransportType.MULTIPLEX);
+ this.secondaryTransports = transports;
+ }
+ }
+
+ /**
+ * Get the list of secondary transports that are set to be accepted by this config
+ * @return acceptable secondary transports
+ */
+ public List<TransportType> getSecondaryTransports(){
+ return this.secondaryTransports;
+ }
+
+ /**
+ * Set a lister for transport events. Useful when connected high bandwidth services like audio
+ * or video streaming
+ * @param listener the TransportListener that will be called back when transport events happen
+ */
+ public void setTransportListener(TransportListener listener){
+ this.transportListener = listener;
+ }
+
+ /**
+ * Getter for the supplied transport listener
+ * @return the transport listener if any
+ */
+ public TransportListener getTransportListener(){
+ return this.transportListener;
+ }
+
+ /**
+ * Callback to be used if the state of the transports needs to be monitored for any reason.
+ */
+ public interface TransportListener{
+ /**
+ * Gets called whenever there is a change in the available transports for use
+ * @param connectedTransports the currently connected transports
+ * @param audioStreamTransportAvail true if there is either an audio streaming supported
+ * transport currently connected or a transport is
+ * available to connect with. False if there is no
+ * transport connected to support audio streaming and
+ * no possibility in the foreseeable future.
+ * @param videoStreamTransportAvail true if there is either a video streaming supported
+ * transport currently connected or a transport is
+ * available to connect with. False if there is no
+ * transport connected to support video streaming and
+ * no possibility in the foreseeable future.
+ */
+ void onTransportEvent(List<TransportRecord> connectedTransports, boolean audioStreamTransportAvail,boolean videoStreamTransportAvail);
+ }
+
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexUsbTransport.java b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexUsbTransport.java
new file mode 100644
index 000000000..e807f7ac7
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexUsbTransport.java
@@ -0,0 +1,327 @@
+/*
+ * 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 android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.smartdevicelink.protocol.SdlPacket;
+import com.smartdevicelink.transport.enums.TransportType;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class MultiplexUsbTransport extends MultiplexBaseTransport{
+
+ private static final String TAG = "MultiplexUsbTransport";
+
+ public static final String MANUFACTURER = "manufacturer";
+ public static final String MODEL = "model";
+ public static final String VERSION = "version";
+ public static final String URI = "uri";
+ public static final String SERIAL = "serial";
+ public static final String DESCRIPTION = "description";
+
+ private final Bundle deviceInfo;
+ private ReaderThread readerThread;
+ private WriterThread writerThread;
+ private final ParcelFileDescriptor parcelFileDescriptor;
+
+ MultiplexUsbTransport(ParcelFileDescriptor parcelFileDescriptor, Handler handler, Bundle bundle){
+ super(handler, TransportType.USB);
+ if(parcelFileDescriptor == null){
+ Log.e(TAG, "Error with object");
+ this.parcelFileDescriptor = null;
+ throw new ExceptionInInitializerError("ParcelFileDescriptor can't be null");
+ }else{
+ this.parcelFileDescriptor = parcelFileDescriptor;
+ connectedDeviceName = "USB";
+ deviceInfo = bundle;
+ if(deviceInfo != null){
+ //Fill in info
+ connectedDeviceAddress = bundle.getString(SERIAL);
+ if(connectedDeviceAddress == null){
+ connectedDeviceAddress = bundle.getString(URI);
+ if(connectedDeviceAddress == null) {
+ connectedDeviceAddress = bundle.getString(DESCRIPTION);
+ if (connectedDeviceAddress == null) {
+ connectedDeviceAddress = bundle.getString(MODEL);
+ if (connectedDeviceAddress == null) {
+ connectedDeviceAddress = bundle.getString(MANUFACTURER);
+ }
+ }
+ }
+ }
+
+ }else{
+ connectedDeviceAddress = "USB";
+ }
+ }
+ }
+
+ public synchronized void start(){
+ setState(STATE_CONNECTING);
+ FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
+ readerThread = new ReaderThread(fileDescriptor);
+ writerThread = new WriterThread(fileDescriptor);
+
+
+ // Send the name of the connected device back to the UI Activity
+ Message msg = handler.obtainMessage(SdlRouterService.MESSAGE_DEVICE_NAME);
+ Bundle bundle = new Bundle();
+ bundle.putString(DEVICE_NAME, connectedDeviceName);
+ bundle.putString(DEVICE_ADDRESS, connectedDeviceAddress);
+ msg.setData(bundle);
+ handler.sendMessage(msg);
+
+ setState(STATE_CONNECTED);
+ readerThread.start();
+ writerThread.start();
+ }
+
+ protected synchronized void stop(int stateToTransitionTo) {
+ //Log.d(TAG, "Attempting to close the Usb transports");
+ if (writerThread != null) {
+ writerThread.cancel();
+ writerThread = null;
+ }
+
+ if (readerThread != null) {
+ readerThread.cancel();
+ readerThread = null;
+ }
+
+ if(parcelFileDescriptor != null){
+ try {
+ parcelFileDescriptor.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ setState(stateToTransitionTo);
+ }
+
+
+ /**
+ * Write to the ConnectedThread in an unsynchronized manner
+ * @param out The bytes to write
+ */
+ public void write(byte[] out, int offset, int count) {
+ // Create temporary object
+ MultiplexUsbTransport.WriterThread r;
+ // Synchronize a copy of the ConnectedThread
+ synchronized (this) {
+ if (mState != STATE_CONNECTED) return;
+ r = writerThread;
+ //r.write(out,offset,count);
+ }
+ // Perform the write unsynchronized
+ r.write(out,offset,count);
+ }
+
+ /**
+ * Indicate that the connection attempt failed and notify the UI Activity.
+ */
+ private void connectionFailed() {
+ // Send a failure message back to the Activity
+ Message msg = handler.obtainMessage(SdlRouterService.MESSAGE_LOG);
+ Bundle bundle = new Bundle();
+ bundle.putString(LOG, "Unable to connect device");
+ msg.setData(bundle);
+ handler.sendMessage(msg);
+
+ // Start the service over to restart listening mode
+ // BluetoothSerialServer.this.start();
+ }
+
+ /**
+ * Indicate that the connection was lost and notify the UI Activity.
+ */
+ private void connectionLost() {
+ // Send a failure message back to the Activity
+ Message msg = handler.obtainMessage(SdlRouterService.MESSAGE_LOG);
+ Bundle bundle = new Bundle();
+ bundle.putString(LOG, "Device connection was lost");
+ msg.setData(bundle);
+ handler.sendMessage(msg);
+ stop();
+
+ }
+
+ private class ReaderThread extends Thread{
+ SdlPsm psm;
+
+ final InputStream inputStream;
+
+ public ReaderThread(final FileDescriptor fileDescriptor){
+ psm = new SdlPsm();
+ inputStream = new FileInputStream(fileDescriptor);
+ }
+
+ @Override
+ public void run() { //FIXME probably check to see what the BT does
+ super.run();
+ final int READ_BUFFER_SIZE = 4096;
+ byte[] buffer = new byte[READ_BUFFER_SIZE];
+ int bytesRead;
+ boolean stateProgress;
+
+ // read loop
+ while (!isInterrupted()) {
+ try {
+ bytesRead = inputStream.read(buffer);
+ if (bytesRead == -1) {
+ if (isInterrupted()) {
+ Log.e(TAG,"EOF reached, and thread is interrupted");
+ } else {
+ Log.i(TAG,"EOF reached, disconnecting!");
+ connectionLost();
+ }
+ return;
+ }
+ if (isInterrupted()) {
+ Log.w(TAG,"Read some data, but thread is interrupted");
+ return;
+ }
+ byte input;
+ for(int i=0;i<bytesRead; i++){
+ input=buffer[i];
+ stateProgress = psm.handleByte(input);
+ 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();
+ buffer = new byte[READ_BUFFER_SIZE];
+ }
+
+ if(psm.getState() == SdlPsm.FINISHED_STATE){
+ synchronized (MultiplexUsbTransport.this) {
+ //Log.d(TAG, "Packet formed, sending off");
+ SdlPacket packet = psm.getFormedPacket();
+ packet.setTransportRecord(getTransportRecord());
+ handler.obtainMessage(SdlRouterService.MESSAGE_READ, packet).sendToTarget();
+ }
+ //We put a trace statement in the message read so we can avoid all the extra bytes
+ psm.reset();
+ buffer = new byte[READ_BUFFER_SIZE]; //FIXME just do an array copy and send off
+ }
+ }
+ } catch (IOException e) {
+ if (isInterrupted()) {
+ Log.w(TAG,"Can't read data, and thread is interrupted");
+ } else {
+ Log.w(TAG,"Can't read data, disconnecting!");
+ connectionLost();
+ }
+ return;
+ } catch (Exception e){
+ connectionLost();
+ }
+ }
+ }
+
+
+ public synchronized void cancel() {
+ try {
+ //Log.d(TAG, "Calling Cancel in the Read thread");
+ if(inputStream!=null){
+ inputStream.close();
+ }
+
+ } catch (IOException|NullPointerException e) { // NPE is ONLY to catch error on mmInStream
+ // Log.trace(TAG, "Read Thread: " + e.getMessage());
+ // Socket or stream is already closed
+ }
+ }
+
+ }
+
+
+ /**
+ * This thread runs during a connection with a remote device.
+ * It handles all incoming and outgoing transmissions.
+ */
+ private class WriterThread extends Thread {
+ private final OutputStream mmOutStream;
+
+ public WriterThread(FileDescriptor fileDescriptor) {
+ //Log.d(TAG, "Creating a Connected - Write Thread");
+ OutputStream tmpOut = null;
+ setName("SDL Router BT Write Thread");
+ // Get the Usb output streams
+ mmOutStream = new FileOutputStream(fileDescriptor);
+
+
+ }
+ /**
+ * Write to the connected OutStream.
+ * @param buffer The bytes to write
+ */
+ public void write(byte[] buffer, int offset, int count) {
+ try {
+ if(buffer==null){
+ Log.w(TAG, "Can't write to device, nothing to send");
+ return;
+ }
+ //This would be a good spot to log out all bytes received
+ mmOutStream.write(buffer, offset, count);
+ //Log.w(TAG, "Wrote out to device: bytes = "+ count);
+ } catch (IOException|NullPointerException e) { // STRICTLY to catch mmOutStream NPE
+ // Exception during write
+ //OMG! WE MUST NOT BE CONNECTED ANYMORE! LET THE USER KNOW
+ Log.e(TAG, "Error sending bytes to connected device!");
+ connectionLost();
+ }
+ }
+
+ public synchronized void cancel() {
+ try {
+ if(mmOutStream!=null){
+ mmOutStream.flush();
+ mmOutStream.close();
+
+ }
+ } catch (IOException e) {
+ // close() of connect socket failed
+ Log.d(TAG, "Write Thread: " + e.getMessage());
+ }
+ }
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/RouterServiceValidator.java b/sdl_android/src/main/java/com/smartdevicelink/transport/RouterServiceValidator.java
index d4b341721..868c71054 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/RouterServiceValidator.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/RouterServiceValidator.java
@@ -23,6 +23,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Build;
+import android.support.annotation.NonNull;
import android.util.Log;
import com.smartdevicelink.util.AndroidTools;
@@ -99,6 +100,14 @@ public class RouterServiceValidator {
inDebugMode = inDebugMode();
this.service = service;
}
+
+ public RouterServiceValidator(@NonNull MultiplexTransportConfig config){
+ this.context = config.context;
+ this.service = config.service;
+ setSecurityLevel(config.securityLevel);
+ inDebugMode = inDebugMode();
+ }
+
/**
* Main function to call to ensure we are connecting to a validated router service
* @return whether or not the currently running router service can be trusted.
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java b/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java
index 251765ed2..b96ac4f65 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java
@@ -1,3 +1,35 @@
+/*
+ * 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 android.annotation.TargetApi;
@@ -12,11 +44,14 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.hardware.usb.UsbManager;
import android.os.Build;
+import android.os.Parcelable;
import android.util.Log;
import com.smartdevicelink.R;
import com.smartdevicelink.transport.RouterServiceValidator.TrustedListCallback;
+import com.smartdevicelink.transport.enums.TransportType;
import com.smartdevicelink.util.AndroidTools;
import com.smartdevicelink.util.SdlAppInfo;
import com.smartdevicelink.util.ServiceFinder;
@@ -132,6 +167,12 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver{
//List obtained. Let's start our service
queuedService = componentName;
finalIntent.setAction("com.sdl.noaction"); //Replace what's there so we do go into some unintended loop
+ String transportType = finalIntent.getStringExtra(TransportConstants.START_ROUTER_SERVICE_TRANSPORT_CONNECTED);
+ if(transportType!= null ){
+ if(TransportType.USB.toString().equals(transportType)){
+ finalIntent.putExtra(UsbManager.EXTRA_ACCESSORY, (Parcelable)null);
+ }
+ }
onSdlEnabled(finalContext, finalIntent);
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/SdlPsm.java b/sdl_android/src/main/java/com/smartdevicelink/transport/SdlPsm.java
index 1fc40bda4..f5b650722 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/SdlPsm.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/SdlPsm.java
@@ -2,8 +2,8 @@ package com.smartdevicelink.transport;
import com.smartdevicelink.protocol.SdlPacket;
-import static com.smartdevicelink.protocol.WiProProtocol.V1_HEADER_SIZE;
-import static com.smartdevicelink.protocol.WiProProtocol.V1_V2_MTU_SIZE;
+import static com.smartdevicelink.protocol.SdlProtocol.V1_HEADER_SIZE;
+import static com.smartdevicelink.protocol.SdlProtocol.V1_V2_MTU_SIZE;
public class SdlPsm{
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java b/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
index 71b295fbe..50c5b5412 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
@@ -1,3 +1,35 @@
+/*
+ * 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 static com.smartdevicelink.transport.TransportConstants.CONNECTED_DEVICE_STRING_EXTRA_NAME;
@@ -6,7 +38,9 @@ import static com.smartdevicelink.transport.TransportConstants.HARDWARE_DISCONNE
import static com.smartdevicelink.transport.TransportConstants.SEND_PACKET_TO_APP_LOCATION_EXTRA_NAME;
import java.lang.ref.WeakReference;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -55,6 +89,7 @@ import android.os.IBinder.DeathRecipient;
import android.os.Message;
import android.os.Messenger;
import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
@@ -67,6 +102,7 @@ import com.smartdevicelink.protocol.BinaryFrameHeader;
import com.smartdevicelink.protocol.ProtocolMessage;
import com.smartdevicelink.protocol.SdlPacket;
import com.smartdevicelink.protocol.SdlPacketFactory;
+import com.smartdevicelink.protocol.enums.ControlFrameTags;
import com.smartdevicelink.protocol.enums.FrameType;
import com.smartdevicelink.protocol.enums.FunctionID;
import com.smartdevicelink.protocol.enums.MessageType;
@@ -75,6 +111,7 @@ import com.smartdevicelink.proxy.rpc.UnregisterAppInterface;
import com.smartdevicelink.transport.enums.TransportType;
import com.smartdevicelink.transport.utl.ByteAraryMessageAssembler;
import com.smartdevicelink.transport.utl.ByteArrayMessageSpliter;
+import com.smartdevicelink.transport.utl.TransportRecord;
import com.smartdevicelink.util.AndroidTools;
import com.smartdevicelink.util.BitConverter;
import com.smartdevicelink.util.SdlAppInfo;
@@ -82,6 +119,7 @@ import com.smartdevicelink.util.SdlAppInfo;
import static com.smartdevicelink.transport.TransportConstants.FOREGROUND_EXTRA;
import static com.smartdevicelink.transport.TransportConstants.SDL_NOTIFICATION_CHANNEL_ID;
import static com.smartdevicelink.transport.TransportConstants.SDL_NOTIFICATION_CHANNEL_NAME;
+import static com.smartdevicelink.transport.TransportConstants.TRANSPORT_DISCONNECTED;
/**
* <b>This class should not be modified by anyone outside of the approved contributors of the SmartDeviceLink project.</b>
@@ -97,8 +135,8 @@ public class SdlRouterService extends Service{
/**
* <b> NOTE: DO NOT MODIFY THIS UNLESS YOU KNOW WHAT YOU'RE DOING.</b>
*/
- protected static final int ROUTER_SERVICE_VERSION_NUMBER = 7;
-
+ protected static final int ROUTER_SERVICE_VERSION_NUMBER = 8;
+
private static final String ROUTER_SERVICE_PROCESS = "com.smartdevicelink.router";
private static final int FOREGROUND_SERVICE_ID = 849;
@@ -122,22 +160,32 @@ public class SdlRouterService extends Service{
@SuppressWarnings("unused")
public static final int MESSAGE_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
- public static final int MESSAGE_TOAST = 5;
-
+ public static final int MESSAGE_LOG = 5;
+
@SuppressWarnings("FieldCanBeLocal")
private final int UNREGISTER_APP_INTERFACE_CORRELATION_ID = 65530;
+ /* Bluetooth Transport */
+ private MultiplexBluetoothTransport bluetoothTransport = null;
+ private final Handler bluetoothHandler = new TransportHandler(this);
+
+ /* USB Transport */
+ private MultiplexUsbTransport usbTransport;
+ private final Handler usbHandler = new TransportHandler(this);
+
+ /* TCP Transport */
+ private MultiplexTcpTransport tcpTransport;
+ private final Handler tcpHandler = new TransportHandler(this);
+
/**
* Preference location where the service stores known SDL status based on device address
*/
protected static final String SDL_DEVICE_STATUS_SHARED_PREFS = "sdl.device.status";
- private MultiplexBluetoothTransport mSerialService = null;
+
private static boolean connectAsClient = false;
private static boolean closing = false;
- private boolean isTransportConnected = false;
- private TransportType connectedTransportType = null;
private Handler altTransportTimerHandler, foregroundTimeoutHandler;
private Runnable altTransportTimerRunnable, foregroundTimeoutRunnable;
@@ -147,7 +195,7 @@ public class SdlRouterService extends Service{
private boolean initPassed = false;
public static HashMap<String,RegisteredApp> registeredApps;
- private SparseArray<String> sessionMap;
+ private SparseArray<String> bluetoothSessionMap, usbSessionMap, tcpSessionMap;
private SparseIntArray sessionHashIdMap;
private SparseIntArray cleanedSessionMap;
private final Object SESSION_LOCK = new Object(), REGISTERED_APPS_LOCK = new Object(),
@@ -155,11 +203,10 @@ public class SdlRouterService extends Service{
private static Messenger altTransportService = null;
- private String connectedDeviceName = ""; //The name of the connected Device
- private boolean startSequenceComplete = false;
+ private boolean startSequenceComplete = false;
private ExecutorService packetExecutor = null;
- PacketWriteTaskMaster packetWriteTaskMaster = null;
+ HashMap<TransportType, PacketWriteTaskMaster> packetWriteTaskMasterMap = null;
/**
@@ -214,8 +261,8 @@ public class SdlRouterService extends Service{
//Should we ask for all relevant data in this packet?
if(bluetoothAvailable()){
if(startSequenceComplete &&
- !connectAsClient && (mSerialService ==null
- || mSerialService.getState() == MultiplexBluetoothTransport.STATE_NONE)){
+ !connectAsClient && (bluetoothTransport ==null
+ || bluetoothTransport.getState() == MultiplexBluetoothTransport.STATE_NONE)){
Log.e(TAG, "Serial service not initialized while registering app");
//Maybe we should try to do a connect here instead
Log.d(TAG, "Serial service being restarted");
@@ -245,23 +292,22 @@ public class SdlRouterService extends Service{
Log.d(TAG, "Disconnect received. Action: " + intent.getAction());
if(action.equalsIgnoreCase(BluetoothAdapter.ACTION_STATE_CHANGED)){
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- if(adapter != null) {
- int bluetoothState = adapter.getState();
- switch (bluetoothState) {
- case BluetoothAdapter.STATE_TURNING_ON:
- case BluetoothAdapter.STATE_ON:
- //There is nothing to do in the case the adapter is turning on or just switched to on
- return;
- case BluetoothAdapter.STATE_TURNING_OFF:
- case BluetoothAdapter.STATE_OFF:
- Log.d(TAG, "Bluetooth is shutting off, SDL Router Service is closing.");
- connectAsClient = false;
- shouldServiceRemainOpen(intent);
- return;
- default:
- break;
- }
+ int bluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
+ switch (bluetoothState) {
+ case BluetoothAdapter.STATE_TURNING_ON:
+ case BluetoothAdapter.STATE_ON:
+ //There is nothing to do in the case the adapter is turning on or just switched to on
+ return;
+ case BluetoothAdapter.STATE_TURNING_OFF:
+ case BluetoothAdapter.STATE_OFF:
+ Log.d(TAG, "Bluetooth is shutting off, SDL Router Service is closing.");
+ connectAsClient = false;
+ if(!shouldServiceRemainOpen(intent)){
+ closeSelf();
+ }
+ return;
+ default:
+ break;
}
}
//Otherwise
@@ -269,7 +315,7 @@ public class SdlRouterService extends Service{
if (legacyModeEnabled) {
Log.d(TAG, "Legacy mode enabled and bluetooth d/c'ed, restarting router service bluetooth.");
enableLegacyMode(false);
- onTransportDisconnected(TransportType.BLUETOOTH);
+ onTransportDisconnected(new TransportRecord(TransportType.BLUETOOTH,null));
initBluetoothSerialService();
}
}
@@ -356,9 +402,12 @@ public class SdlRouterService extends Service{
}
break;
}
-
- RegisteredApp app = service.new RegisteredApp(appId,msg.replyTo);
- synchronized(service.REGISTERED_APPS_LOCK){
+
+ int routerMessagingVersion = receivedBundle.getInt(TransportConstants.ROUTER_MESSAGING_VERSION,1);
+
+ RegisteredApp app = service.new RegisteredApp(appId, routerMessagingVersion, msg.replyTo);
+
+ synchronized(service.REGISTERED_APPS_LOCK){
RegisteredApp old = registeredApps.put(app.getAppId(), app);
if(old!=null){
Log.w(TAG, "Replacing already existing app with this app id");
@@ -370,10 +419,15 @@ public class SdlRouterService extends Service{
returnBundle = new Bundle();
//Add params if connected
- if(service.isTransportConnected){
- returnBundle.putString(TransportConstants.HARDWARE_CONNECTED, service.connectedTransportType.name());
- if(MultiplexBluetoothTransport.currentlyConnectedDevice!=null){
- returnBundle.putString(CONNECTED_DEVICE_STRING_EXTRA_NAME, MultiplexBluetoothTransport.currentlyConnectedDevice);
+ if(service.isPrimaryTransportConnected()){
+ ArrayList<TransportRecord> records = service.getConnectedTransports();
+ returnBundle.putString(TransportConstants.HARDWARE_CONNECTED, records.get(records.size()-1).getType().name());
+ if(app.routerMessagingVersion > 1) {
+ returnBundle.putParcelableArrayList(TransportConstants.CURRENT_HARDWARE_CONNECTED, records);
+ }
+
+ if(service.bluetoothTransport != null){
+ returnBundle.putString(CONNECTED_DEVICE_STRING_EXTRA_NAME, service.bluetoothTransport.getDeviceName());
}
}
//Add the version of this router service
@@ -419,6 +473,7 @@ public class SdlRouterService extends Service{
break;
case TransportConstants.ROUTER_SEND_PACKET:
+ //Log.d(TAG, "Received packet to send");
if(receivedBundle!=null){
Runnable packetRun = new Runnable(){
@Override
@@ -427,6 +482,7 @@ public class SdlRouterService extends Service{
if(buffAppId == null){
buffAppId = "" + receivedBundle.getLong(TransportConstants.APP_ID_EXTRA, -1);
}
+
RegisteredApp buffApp;
synchronized(service.REGISTERED_APPS_LOCK){
buffApp = registeredApps.get(buffAppId);
@@ -435,6 +491,25 @@ public class SdlRouterService extends Service{
if(buffApp !=null){
buffApp.handleIncommingClientMessage(receivedBundle);
}else{
+ TransportType transportType = TransportType.valueForString(receivedBundle.getString(TransportConstants.TRANSPORT_TYPE));
+ if(transportType == null){
+
+ /* We check bluetooth first because we assume if this value
+ * isn't included it is an older version of the proxy and
+ * therefore will be expecting this to be bluetooth.
+ */
+ if(service.bluetoothTransport != null && service.bluetoothTransport.isConnected()){
+ transportType = TransportType.BLUETOOTH;
+ } else if(service.usbTransport!= null && service.usbTransport.isConnected()){
+ transportType = TransportType.USB;
+ } else if(service.tcpTransport != null && service.tcpTransport.isConnected()){
+ transportType = TransportType.TCP;
+ }
+ //Log.d(TAG, "Transport type was null, so router set it to " + transportType.name());
+ if(transportType != null){
+ receivedBundle.putString(TransportConstants.TRANSPORT_TYPE, transportType.name());
+ }
+ }
service.writeBytesToTransport(receivedBundle);
}
}
@@ -456,7 +531,29 @@ public class SdlRouterService extends Service{
if(registeredApps!=null){
RegisteredApp appRequesting = registeredApps.get(appIdRequesting);
if(appRequesting!=null){
+ //Retrieve the transport the app is requesting a new session
+ String transport = receivedBundle.getString(TransportConstants.TRANSPORT_TYPE);
+ TransportType requestingTransport = null;
+ if(transport != null){
+ try{
+ requestingTransport = TransportType.valueOf(transport);
+ }catch (IllegalArgumentException e){}
+ }
+ if(requestingTransport == null){
+ /* We check bluetooth first because we assume if this value
+ * isn't included it is an older version of the proxy and
+ * therefore will be expecting this to be bluetooth.
+ */
+ if(service.bluetoothTransport != null && service.bluetoothTransport.isConnected()){
+ requestingTransport = TransportType.BLUETOOTH;
+ }else if(service.usbTransport!= null && service.usbTransport.isConnected()){
+ requestingTransport = TransportType.USB;
+ }else if(service.tcpTransport != null && service.tcpTransport.isConnected()){
+ requestingTransport = TransportType.TCP;
+ }
+ }
appRequesting.getSessionIds().add((long)-1); //Adding an extra session
+ appRequesting.getAwaitingSession().add(requestingTransport);
extraSessionResponse.arg1 = TransportConstants.ROUTER_REQUEST_NEW_SESSION_RESPONSE_SUCESS;
}else{
extraSessionResponse.arg1 = TransportConstants.ROUTER_REQUEST_NEW_SESSION_RESPONSE_FAILED_APP_NOT_FOUND;
@@ -480,7 +577,7 @@ public class SdlRouterService extends Service{
appIdWithSession = "" + receivedBundle.getLong(TransportConstants.APP_ID_EXTRA, -1);
}
long sessionId = receivedBundle.getLong(TransportConstants.SESSION_ID_EXTRA, -1);
- service.removeSessionFromMap((int)sessionId);
+
Message removeSessionResponse = Message.obtain();
removeSessionResponse.what = TransportConstants.ROUTER_REMOVE_SESSION_RESPONSE;
if(appIdWithSession.length()>0){
@@ -489,6 +586,8 @@ public class SdlRouterService extends Service{
if(registeredApps!=null){
RegisteredApp appRequesting = registeredApps.get(appIdWithSession);
if(appRequesting!=null){
+ //Might need to check which session is on which transport
+ service.removeSessionFromMap((int)sessionId, appRequesting.getTransportsForSession((int)sessionId));
if(appRequesting.removeSession(sessionId)){
removeSessionResponse.arg1 = TransportConstants.ROUTER_REMOVE_SESSION_RESPONSE_SUCESS;
}else{
@@ -513,6 +612,49 @@ public class SdlRouterService extends Service{
Log.e(TAG, "No reply address included, can't send a reply");
}
break;
+ case TransportConstants.ROUTER_REQUEST_SECONDARY_TRANSPORT_CONNECTION:
+ // Currently this only handles one TCP connection
+
+ String ipAddress = receivedBundle.getString(ControlFrameTags.RPC.TransportEventUpdate.TCP_IP_ADDRESS);
+ int port = receivedBundle.getInt(ControlFrameTags.RPC.TransportEventUpdate.TCP_PORT);
+
+ if(ipAddress != null){
+ if(service.tcpTransport != null){
+ switch (service.tcpTransport.getState()){
+ case MultiplexBaseTransport.STATE_CONNECTED:
+ case MultiplexBaseTransport.STATE_CONNECTING:
+ // A TCP connection is currently active. This version of the
+ // router service can't handle multiple TCP transports so just
+ // return a connected message to requester.
+ if(msg.replyTo != null){
+ // Send a transport connect message to the app that requested
+ // the tcp transport
+ try {
+ msg.replyTo.send(service.createHardwareConnectedMessage(service.tcpTransport.transportRecord));
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ //Nothing else to do, so return out of this method
+ return;
+
+ case MultiplexBaseTransport.STATE_NONE:
+ case MultiplexBaseTransport.STATE_LISTEN:
+ case MultiplexBaseTransport.STATE_ERROR:
+ //Clear out tcp transport
+ service.tcpTransport.stop(MultiplexBaseTransport.STATE_NONE);
+ service.tcpTransport = null;
+ //Do not return, need to create a new TCP connection
+ }
+
+ }//else { TCP transport does not exists.}
+
+ //TCP transport either doesn't exist or is not connected. Start one up.
+ service.tcpTransport = new MultiplexTcpTransport(port, ipAddress, true, service.tcpHandler, service);
+ service.tcpTransport.start();
+
+ }
+ break;
default:
super.handleMessage(msg);
}
@@ -553,7 +695,7 @@ public class SdlRouterService extends Service{
&& altTransportService.equals(msg.replyTo)){
//The same transport that was connected to the router service is now telling us it's disconnected. Let's inform clients and clear our saved messenger
altTransportService = null;
- service.onTransportDisconnected(TransportType.valueOf(receivedBundle.getString(TransportConstants.HARDWARE_DISCONNECTED)));
+ service.onTransportDisconnected(new TransportRecord(TransportType.valueOf(receivedBundle.getString(TransportConstants.HARDWARE_DISCONNECTED)),null));
service.shouldServiceRemainOpen(null); //this will close the service if bluetooth is not available
}
}else if(receivedBundle.containsKey(TransportConstants.HARDWARE_CONNECTED)){
@@ -574,7 +716,8 @@ public class SdlRouterService extends Service{
//Let the alt transport know they are good to go
retMsg.arg1 = TransportConstants.ROUTER_REGISTER_ALT_TRANSPORT_RESPONSE_SUCESS;
- service.onTransportConnected(TransportType.valueOf(receivedBundle.getString(TransportConstants.HARDWARE_CONNECTED)));
+ service.onTransportConnected(new TransportRecord(TransportType.valueOf(receivedBundle.getString(TransportConstants.HARDWARE_CONNECTED)),null));
+
}else{ //There seems to be some other transport connected
//Error
retMsg.arg1 = TransportConstants.ROUTER_REGISTER_ALT_TRANSPORT_ALREADY_CONNECTED;
@@ -636,14 +779,14 @@ public class SdlRouterService extends Service{
if(msg.replyTo!=null){
Message message = Message.obtain();
message.what = TransportConstants.ROUTER_STATUS_CONNECTED_STATE_RESPONSE;
- message.arg1 = (service.isTransportConnected) ? 1 : 0;
+ message.arg1 = (service.isPrimaryTransportConnected()) ? 1 : 0;
try {
msg.replyTo.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
- if(service.isTransportConnected && ((TransportConstants.ROUTER_STATUS_FLAG_TRIGGER_PING & flags) == TransportConstants.ROUTER_STATUS_FLAG_TRIGGER_PING)){
+ if(service.isPrimaryTransportConnected() && ((TransportConstants.ROUTER_STATUS_FLAG_TRIGGER_PING & flags) == TransportConstants.ROUTER_STATUS_FLAG_TRIGGER_PING)){
if(service.pingIntent == null){
service.initPingIntent();
}
@@ -656,7 +799,65 @@ public class SdlRouterService extends Service{
}
}
}
-
+
+
+ /**
+ * Target we publish for alternative transport (USB) clients to send messages to RouterHandler.
+ */
+ final Messenger usbTransferMessenger = new Messenger(new UsbTransferHandler(this));
+
+ /**
+ * Handler of incoming messages from an alternative transport (USB).
+ */
+ @SuppressWarnings("Convert2Diamond")
+ static class UsbTransferHandler extends Handler {
+ final WeakReference<SdlRouterService> provider;
+
+ public UsbTransferHandler(SdlRouterService provider){
+ this.provider = new WeakReference<SdlRouterService>(provider);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if(this.provider.get() == null){
+ return;
+ }
+ SdlRouterService service = this.provider.get();
+ switch(msg.what){
+ case TransportConstants.USB_CONNECTED_WITH_DEVICE:
+ int flags = msg.arg1;
+ ParcelFileDescriptor parcelFileDescriptor = (ParcelFileDescriptor)msg.obj;
+ if(parcelFileDescriptor != null){
+ //New USB constructor with PFD
+ service.usbTransport = new MultiplexUsbTransport(parcelFileDescriptor,service.usbHandler,msg.getData());
+ service.usbTransport.start();
+
+ }
+ if(msg.replyTo!=null){
+ Message message = Message.obtain();
+ message.what = TransportConstants.ROUTER_USB_ACC_RECEIVED;
+ try {
+ msg.replyTo.send(message);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ if(service.isPrimaryTransportConnected() && ((TransportConstants.ROUTER_STATUS_FLAG_TRIGGER_PING & flags) == TransportConstants.ROUTER_STATUS_FLAG_TRIGGER_PING)){
+ if(service.pingIntent == null){
+ service.initPingIntent();
+ }
+ AndroidTools.sendExplicitBroadcast(service.getApplicationContext(),service.pingIntent, null);
+ }
+ break;
+ case TransportConstants.ALT_TRANSPORT_CONNECTED:
+ break;
+ default:
+ Log.w(TAG, "Unsupported request: " + msg.what);
+ break;
+ }
+ }
+ }
+
/* **************************************************************************************************************************************
*********************************************** Life Cycle **************************************************************
****************************************************************************************************************************************/
@@ -678,6 +879,8 @@ public class SdlRouterService extends Service{
return this.routerMessenger.getBinder();
}else if(TransportConstants.BIND_REQUEST_TYPE_STATUS.equals(requestType)){
return this.routerStatusMessenger.getBinder();
+ }else if(TransportConstants.BIND_REQUEST_TYPE_USB_PROVIDER.equals(requestType)){
+ return this.usbTransferMessenger.getBinder();
}else{
Log.w(TAG, "Unknown bind request type");
}
@@ -707,15 +910,65 @@ public class SdlRouterService extends Service{
Iterator<RegisteredApp> it = apps.iterator();
while(it.hasNext()){
RegisteredApp app = it.next();
- result = app.sendMessage(message);
- if(result == RegisteredApp.SEND_MESSAGE_ERROR_MESSENGER_DEAD_OBJECT){
- app.close();
- it.remove();
+ //Format the message for the receiving app and appropriate messaging version
+ if(formatMessage(app, message)) {
+ result = app.sendMessage(message);
+ if (result == RegisteredApp.SEND_MESSAGE_ERROR_MESSENGER_DEAD_OBJECT) {
+ app.close();
+ it.remove();
+ }
}
}
}
}
+
+ /**
+ * Formats the message for the app that is to receive it
+ * @param app
+ * @param message
+ * @return if the message should be sent or not
+ */
+ protected boolean formatMessage(RegisteredApp app, Message message){
+ if( app.routerMessagingVersion <= 1){
+ Bundle bundle = message.getData();
+ if (bundle != null){
+ if(message.what == TransportConstants.HARDWARE_CONNECTION_EVENT) {
+
+ switch (message.arg1){
+ case TransportConstants.HARDWARE_CONNECTION_EVENT_CONNECTED:
+ if(app.isRegisteredOnTransport(-1, null)){
+ //App is already registered on a transport and does not need this update
+ return false;
+ }
+ break;
+ case TransportConstants.HARDWARE_CONNECTION_EVENT_DISCONNECTED:
+ if(bundle.containsKey(TransportConstants.HARDWARE_DISCONNECTED)){
+ TransportType transportType = TransportType.valueOf(bundle.getString(TransportConstants.HARDWARE_DISCONNECTED));
+ if(!app.isRegisteredOnTransport(-1, transportType)){
+ //App is not registered on this transport, not sending
+ return false;
+ }
+ }
+ if (bundle.containsKey(TransportConstants.TRANSPORT_DISCONNECTED)) {
+ //Unable to handle new parcel TransportRecord
+ bundle.remove(TransportConstants.TRANSPORT_DISCONNECTED);
+ }
+ break;
+ }
+
+ //All connection event messages should have this as part of the bundle
+ if (bundle.containsKey(TransportConstants.CURRENT_HARDWARE_CONNECTED)) {
+ //Unable to handle new parcel TransportRecord
+ bundle.remove(TransportConstants.CURRENT_HARDWARE_CONNECTED);
+ }
+
+
+ }
+ }
+ }
+ return true;
+ }
@SuppressWarnings("unused")
private void pingClients(){
@@ -733,7 +986,10 @@ public class SdlRouterService extends Service{
Vector<Long> sessions = app.getSessionIds();
for(Long session:sessions){
if(session !=null && session != -1){
- attemptToCleanUpModule(session.intValue(), cachedModuleVersion);
+ List<TransportType> transportTypes = app.getTransportsForSession(session.intValue());
+ if(transportTypes != null && transportTypes.size() > 0){
+ attemptToCleanUpModule(session.intValue(), cachedModuleVersion, transportTypes.get(0) );
+ }
}
}
it.remove();
@@ -796,6 +1052,12 @@ public class SdlRouterService extends Service{
@Override
public void onCreate() {
super.onCreate();
+ //This must be done regardless of if this service shuts down or not
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ enterForeground("Waiting for connection...", FOREGROUND_TIMEOUT/1000, false);
+ resetForegroundTimeOut(FOREGROUND_TIMEOUT/1000);
+ }
+
if(!initCheck()){ // Run checks on process and permissions
deployNextRouterService();
@@ -804,16 +1066,14 @@ public class SdlRouterService extends Service{
}
initPassed = true;
+
synchronized(REGISTERED_APPS_LOCK){
registeredApps = new HashMap<String,RegisteredApp>();
}
closing = false;
- Log.i(TAG, "SDL Router Service has been created");
-
-
synchronized(SESSION_LOCK){
- this.sessionMap = new SparseArray<String>();
+ this.bluetoothSessionMap = new SparseArray<String>();
this.sessionHashIdMap = new SparseIntArray();
this.cleanedSessionMap = new SparseIntArray();
}
@@ -861,10 +1121,13 @@ public class SdlRouterService extends Service{
}
public void startUpSequence(){
- IntentFilter disconnectFilter = new IntentFilter("android.bluetooth.adapter.action.STATE_CHANGED");
- disconnectFilter.addAction("android.bluetooth.device.action.CLASS_CHANGED");
- disconnectFilter.addAction("android.bluetooth.device.action.ACL_DISCONNECTED");
- disconnectFilter.addAction("android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED");
+ IntentFilter disconnectFilter = new IntentFilter();
+ disconnectFilter.addAction(BluetoothDevice.ACTION_CLASS_CHANGED);
+ disconnectFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
+ disconnectFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
+ disconnectFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
+ }
registerReceiver(mListenForDisconnect,disconnectFilter );
IntentFilter filter = new IntentFilter();
@@ -900,16 +1163,20 @@ public class SdlRouterService extends Service{
}
if(intent != null ){
if(intent.getBooleanExtra(FOREGROUND_EXTRA, false)){
- String address = null;
- if(intent.hasExtra(BluetoothDevice.EXTRA_DEVICE)){
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- if(device != null){
- address = device.getAddress();
+ if(!this.isPrimaryTransportConnected()) { //If there is no transport connected we need to ensure the service is moved to the foreground
+ String address = null;
+ if(intent.hasExtra(BluetoothDevice.EXTRA_DEVICE)){
+ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if(device != null){
+ address = device.getAddress();
+ }
}
+ int timeout = getNotificationTimeout(address);
+ enterForeground("Waiting for connection...", timeout, false);
+ resetForegroundTimeOut(timeout);
+ }else{
+ enterForeground(createConnectedNotificationText(),0,true);
}
- int timeout = getNotificationTimeout(address);
- enterForeground("Waiting for connection...", timeout, false);
- resetForegroundTimeOut(timeout);
}
if(intent.hasExtra(TransportConstants.PING_ROUTER_SERVICE_EXTRA)){
//Make sure we are listening on RFCOMM
@@ -919,10 +1186,13 @@ public class SdlRouterService extends Service{
}
}
}
- shouldServiceRemainOpen(intent);
+ if(!shouldServiceRemainOpen(intent)){
+ closeSelf();
+ }
return super.onStartCommand(intent, flags, startId);
}
+ @SuppressWarnings("ConstantConditions")
@Override
public void onDestroy(){
stopClientPings();
@@ -944,9 +1214,9 @@ public class SdlRouterService extends Service{
}
}
synchronized(SESSION_LOCK){
- if(this.sessionMap!=null){
- this.sessionMap.clear();
- this.sessionMap = null;
+ if(this.bluetoothSessionMap !=null){
+ this.bluetoothSessionMap.clear();
+ this.bluetoothSessionMap = null;
}
if(this.sessionHashIdMap!=null){
this.sessionHashIdMap.clear();
@@ -963,11 +1233,19 @@ public class SdlRouterService extends Service{
}
exitForeground();
-
- if(packetWriteTaskMaster!=null){
- packetWriteTaskMaster.close();
- packetWriteTaskMaster = null;
+ if(packetWriteTaskMasterMap != null && packetWriteTaskMasterMap.values() != null) {
+ Collection<PacketWriteTaskMaster> tasks = packetWriteTaskMasterMap.values();
+ for (PacketWriteTaskMaster packetWriteTaskMaster : tasks) {
+ if (packetWriteTaskMaster != null) {
+ packetWriteTaskMaster.close();
+ }
+ }
+ }
+ if(packetWriteTaskMasterMap != null){
+ packetWriteTaskMasterMap.clear();
}
+ packetWriteTaskMasterMap = null;
+
super.onDestroy();
System.gc(); //Lower end phones need this hint
@@ -1008,7 +1286,6 @@ public class SdlRouterService extends Service{
*/
@SuppressLint("MissingPermission")
private int getNotificationTimeout(String address){
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if(address != null){
if(hasSDLConnected(address)){
return FOREGROUND_TIMEOUT * 2;
@@ -1138,7 +1415,6 @@ public class SdlRouterService extends Service{
notification = builder.build();
}
if (notification == null) {
- Log.e(TAG, "Notification was null");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
stopSelf(); //A valid notification must be supplied for SDK 27+
}
@@ -1152,30 +1428,88 @@ public class SdlRouterService extends Service{
private void exitForeground(){
synchronized (NOTIFICATION_LOCK) {
- if (isForeground && !isTransportConnected) { //Ensure that the service is in the foreground and no longer connected to a transport
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- if (notificationManager != null
- && notificationManager.getNotificationChannel(SDL_NOTIFICATION_CHANNEL_ID) != null ) {
- notificationManager.deleteNotificationChannel(TransportConstants.SDL_NOTIFICATION_CHANNEL_ID);
- }
- }
-
+ if (isForeground && !isPrimaryTransportConnected()) { //Ensure that the service is in the foreground and no longer connected to a transport
this.stopForeground(true);
isForeground = false;
}
}
}
+
+
+ /**
+ * Creates a notification message to attach to the foreground service notification.
+ *
+ * @return string to be used as the message
+ */
+ private String createConnectedNotificationText(){
+ StringBuilder builder = new StringBuilder();
+ builder.append("Connected to ");
+
+ if(bluetoothTransport!= null && bluetoothTransport.isConnected()){
+ if(bluetoothTransport.getDeviceName() != null){
+ builder.append(bluetoothTransport.getDeviceName());
+ if(0 == (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE)) {
+ //If this is production, just the device name is fine
+ return builder.toString();
+ }
+ }else{
+ builder.append(TransportType.BLUETOOTH.name().toLowerCase());
+ }
+ }
+
+ if(usbTransport != null && usbTransport.isConnected()){
+ if(builder.length() > 13){ //13 characters for initial Connected to string
+ builder.append(" & ");
+ }
+ builder.append(TransportType.USB.name());
+ }
+
+ return builder.toString();
+ }
/* **************************************************************************************************************************************
*********************************************** Helper Methods **************************************************************
****************************************************************************************************************************************/
-
+
+ @SuppressWarnings("SameReturnValue")
+ @Deprecated
public String getConnectedDeviceName(){
- return connectedDeviceName;
+ return null;
}
-
+
+ private ArrayList<TransportRecord> getConnectedTransports(){
+ ArrayList<TransportRecord> connected = new ArrayList<>();
+ if(bluetoothTransport != null && bluetoothTransport.isConnected()){
+ connected.add(bluetoothTransport.getTransportRecord());
+ }
+
+ if(tcpTransport != null && tcpTransport.isConnected()){
+ connected.add(tcpTransport.getTransportRecord());
+ }
+
+ if(usbTransport != null && usbTransport.isConnected()){
+ connected.add(usbTransport.getTransportRecord());
+ }
+
+ return connected;
+ }
+
+ private boolean isPrimaryTransportConnected(){
+ return isTransportConnected(TransportType.BLUETOOTH) || isTransportConnected(TransportType.USB);
+ }
+
+ private boolean isTransportConnected(TransportType transportType){
+ if(bluetoothTransport != null && transportType.equals(TransportType.BLUETOOTH)){
+ return bluetoothTransport.isConnected();
+ }else if(tcpTransport != null && transportType.equals(TransportType.TCP)){
+ return tcpTransport.isConnected();
+ }else if(usbTransport != null && transportType.equals(TransportType.USB)){
+ return usbTransport.isConnected();
+ }
+ return false;
+ }
+
/**
* Checks to make sure bluetooth adapter is available and on
* @return if the bluetooth adapter is available and is enabled
@@ -1197,9 +1531,12 @@ public class SdlRouterService extends Service{
* 4. Anything else
*/
public boolean shouldServiceRemainOpen(Intent intent){
- //Log.d(TAG, "Determining if this service should remain open");
-
- if(altTransportService!=null || altTransportTimerHandler !=null){
+ ArrayList<TransportRecord> connectedTransports = getConnectedTransports();
+
+ if(connectedTransports != null && !connectedTransports.isEmpty()){ // stay open if we have any transports connected
+ Log.d(TAG, "1 or more transports connected, remaining open");
+ return true;
+ }else if(altTransportService!=null || altTransportTimerHandler !=null){
//We have been started by an alt transport, we must remain open. "My life for Auir...."
Log.d(TAG, "Alt Transport connected, remaining open");
return true;
@@ -1211,8 +1548,8 @@ public class SdlRouterService extends Service{
}else if(!bluetoothAvailable()){//If bluetooth isn't on...there's nothing to see here
//Bluetooth is off, we should shut down
Log.d(TAG, "Bluetooth not available, shutting down service");
- closeSelf();
- return false;
+
+ return connectedTransports != null && connectedTransports.size() > 0; //If a transport is connected the list will be >0
}else{
Log.d(TAG, "Service to remain open");
return true;
@@ -1224,11 +1561,14 @@ public class SdlRouterService extends Service{
*/
public void closeSelf(){
closing = true;
+
if(getBaseContext()!=null){
stopSelf();
- }else{
- onDestroy();
}
+
+ //For good measure.
+ onDestroy();
+
}
private synchronized void initBluetoothSerialService(){
if(legacyModeEnabled){
@@ -1236,34 +1576,44 @@ public class SdlRouterService extends Service{
return;
}
//init serial service
- if(mSerialService == null || mSerialService.getState() == MultiplexBluetoothTransport.STATE_ERROR){
- Log.i(TAG, "Initializing bluetooth transport");
- mSerialService = new MultiplexBluetoothTransport(mHandlerBT);
+ if(bluetoothTransport == null || bluetoothTransport.getState() == MultiplexBluetoothTransport.STATE_ERROR){
+ bluetoothTransport = new MultiplexBluetoothTransport(bluetoothHandler);
}
- if (mSerialService != null) {
+ if (bluetoothTransport != null) {
// Only if the state is STATE_NONE, do we know that we haven't started already
- if (mSerialService.getState() == MultiplexBluetoothTransport.STATE_NONE) {
+ if (bluetoothTransport.getState() == MultiplexBluetoothTransport.STATE_NONE) {
// Start the Bluetooth services
Log.i(TAG, "Starting bluetooth transport");
- mSerialService.start();
+ bluetoothTransport.start();
}
}
}
-
+
+ @Deprecated
public void onTransportConnected(final TransportType type){
- isTransportConnected = true;
+ onTransportConnected(new TransportRecord(type,null));
+ }
+
+ public void onTransportConnected(final TransportRecord record){
cancelForegroundTimeOut();
- enterForeground("Connected to " + this.getConnectedDeviceName(),0, true);
+ enterForeground(createConnectedNotificationText(),0,true);
+
+ if(packetWriteTaskMasterMap == null){
+ packetWriteTaskMasterMap = new HashMap<>();
+ }
+
+ TransportType type = record.getType();
+ PacketWriteTaskMaster packetWriteTaskMaster = packetWriteTaskMasterMap.get(type);
+
if(packetWriteTaskMaster!=null){
packetWriteTaskMaster.close();
- packetWriteTaskMaster = null;
}
packetWriteTaskMaster = new PacketWriteTaskMaster();
+ packetWriteTaskMaster.setTransportType(type);
packetWriteTaskMaster.start();
-
- connectedTransportType = type;
-
+ packetWriteTaskMasterMap.put(type,packetWriteTaskMaster);
+
Intent startService = new Intent();
startService.setAction(TransportConstants.START_ROUTER_SERVICE_ACTION);
@@ -1271,6 +1621,11 @@ public class SdlRouterService extends Service{
startService.putExtra(TransportConstants.FORCE_TRANSPORT_CONNECTED, true);
startService.putExtra(TransportConstants.START_ROUTER_SERVICE_SDL_ENABLED_APP_PACKAGE, getBaseContext().getPackageName());
startService.putExtra(TransportConstants.START_ROUTER_SERVICE_SDL_ENABLED_CMP_NAME, new ComponentName(this, this.getClass()));
+
+ if(record!= null && record.getType() != null){
+ startService.putExtra(TransportConstants.START_ROUTER_SERVICE_TRANSPORT_CONNECTED, record.getType().toString());
+ }
+
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
startService.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
}
@@ -1280,52 +1635,91 @@ public class SdlRouterService extends Service{
//HARDWARE_CONNECTED
if(!(registeredApps== null || registeredApps.isEmpty())){
//If we have clients
- notifyClients(createHardwareConnectedMessage(type));
+ notifyClients(createHardwareConnectedMessage(record));
}
}
- private Message createHardwareConnectedMessage(final TransportType type){
+ private Message createHardwareConnectedMessage(final TransportRecord record){
Message message = Message.obtain();
message.what = TransportConstants.HARDWARE_CONNECTION_EVENT;
+ message.arg1 = TransportConstants.HARDWARE_CONNECTION_EVENT_CONNECTED;
Bundle bundle = new Bundle();
- bundle.putString(TransportConstants.HARDWARE_CONNECTED, type.name());
- if(MultiplexBluetoothTransport.currentlyConnectedDevice!=null){
- bundle.putString(CONNECTED_DEVICE_STRING_EXTRA_NAME, MultiplexBluetoothTransport.currentlyConnectedDevice);
+ bundle.putString(TransportConstants.HARDWARE_CONNECTED, record.getType().name());
+ bundle.putParcelableArrayList(TransportConstants.CURRENT_HARDWARE_CONNECTED, getConnectedTransports());
+
+ if(bluetoothTransport != null){
+ bundle.putString(CONNECTED_DEVICE_STRING_EXTRA_NAME, bluetoothTransport.getDeviceName());
}
+
message.setData(bundle);
return message;
}
-
- public void onTransportDisconnected(TransportType type){
- if(altTransportService!=null){ //If we still have an alt transport open, then we don't need to tell the clients to close
- return;
- }
- Log.e(TAG, "Notifying client service of hardware disconnect.");
- connectedTransportType = null;
- isTransportConnected = false;
- stopClientPings();
-
- exitForeground();//Leave our foreground state as we don't have a connection anymore
-
- if(packetWriteTaskMaster!=null){
- packetWriteTaskMaster.close();
- packetWriteTaskMaster = null;
- }
-
+
+ @Deprecated
+ public void onTransportDisconnected(TransportType type) {
+ onTransportDisconnected(new TransportRecord(type,null));
+ }
+
+ public void onTransportDisconnected(TransportRecord record){
cachedModuleVersion = -1; //Reset our cached version
if(registeredApps != null && !registeredApps.isEmpty()){
Message message = Message.obtain();
message.what = TransportConstants.HARDWARE_CONNECTION_EVENT;
+ message.arg1 = TransportConstants.HARDWARE_CONNECTION_EVENT_DISCONNECTED;
+
Bundle bundle = new Bundle();
- bundle.putString(HARDWARE_DISCONNECTED, type.name());
+ bundle.putParcelable(TRANSPORT_DISCONNECTED, record);
+ //For legacy
+ bundle.putString(HARDWARE_DISCONNECTED, record.getType().name());
bundle.putBoolean(TransportConstants.ENABLE_LEGACY_MODE_EXTRA, legacyModeEnabled);
+
+ //Still connected transports
+ bundle.putParcelableArrayList(TransportConstants.CURRENT_HARDWARE_CONNECTED,getConnectedTransports());
+
message.setData(bundle);
notifyClients(message);
}
+ if(!getConnectedTransports().isEmpty()){
+ // Updates notification to one of still connected transport
+ enterForeground(createConnectedNotificationText(),0,true);
+ return;
+ }else{
+ exitForeground();//Leave our foreground state as we don't have a connection anymore
+ if(!shouldServiceRemainOpen(null)){
+ closeSelf();
+ }
+ }
+
+ if(altTransportService!=null){ //If we still have an alt transport open, then we don't need to tell the clients to close
+ return;
+ }
+ switch (record.getType()){
+ case BLUETOOTH:
+ if(!connectAsClient ){
+ if(!legacyModeEnabled && !closing){
+ initBluetoothSerialService();
+ }
+ }
+ break;
+ case USB:
+ break;
+ case TCP:
+ break;
+ }
+ Log.e(TAG, "Notifying client service of hardware disconnect.");
+
+ stopClientPings();
+
+
+ PacketWriteTaskMaster packetWriteTaskMaster = packetWriteTaskMasterMap.remove(record.getType());
+ if(packetWriteTaskMaster!=null){
+ packetWriteTaskMaster.close();
+ }
+
//We've notified our clients, less clean up the mess now.
synchronized(SESSION_LOCK){
- this.sessionMap.clear();
+ this.bluetoothSessionMap.clear();
this.sessionHashIdMap.clear();
}
synchronized(REGISTERED_APPS_LOCK){
@@ -1335,7 +1729,28 @@ public class SdlRouterService extends Service{
registeredApps.clear();
}
}
-
+
+ @Deprecated
+ public void onTransportError(TransportType transportType){
+ onTransportError(new TransportRecord(transportType,null));
+ }
+
+ public void onTransportError(TransportRecord transport){
+ switch (transport.getType()){
+ case BLUETOOTH:
+ if(bluetoothTransport !=null){
+ bluetoothTransport.setStateManually(MultiplexBluetoothTransport.STATE_NONE);
+ bluetoothTransport = null;
+ }
+ break;
+ case USB:
+ break;
+ case TCP:
+ break;
+ }
+
+ }
+
public void onPacketRead(SdlPacket packet){
try {
//Log.i(TAG, "******** Read packet with header: " +(packet).toString());
@@ -1355,13 +1770,16 @@ public class SdlRouterService extends Service{
e.printStackTrace();
}
}
-
- private final Handler mHandlerBT = new BluetoothHandler(this);
- private static class BluetoothHandler extends Handler{
+
+ /**
+ * Handler for all Multiplex Based transports.
+ * It will ensure messages are properly queued back to the router service.
+ */
+ private static class TransportHandler extends Handler{
final WeakReference<SdlRouterService> provider;
- public BluetoothHandler(SdlRouterService provider){
+ public TransportHandler(SdlRouterService provider){
this.provider = new WeakReference<SdlRouterService>(provider);
}
@Override
@@ -1374,78 +1792,94 @@ public class SdlRouterService extends Service{
case MESSAGE_DEVICE_NAME:
Bundle bundle = msg.getData();
if(bundle !=null) {
- service.connectedDeviceName = bundle.getString(MultiplexBluetoothTransport.DEVICE_NAME);
- service.setSDLConnectedStatus(bundle.getString(MultiplexBluetoothTransport.DEVICE_ADDRESS),true);
+ service.setSDLConnectedStatus(bundle.getString(MultiplexBaseTransport.DEVICE_ADDRESS),true);
}
break;
case MESSAGE_STATE_CHANGE:
+ TransportRecord transportRecord = (TransportRecord) msg.obj;
switch (msg.arg1) {
- case MultiplexBluetoothTransport.STATE_CONNECTED:
- service.onTransportConnected(TransportType.BLUETOOTH);
+ case MultiplexBaseTransport.STATE_CONNECTED:
+ service.onTransportConnected(transportRecord);
break;
- case MultiplexBluetoothTransport.STATE_CONNECTING:
+ case MultiplexBaseTransport.STATE_CONNECTING:
// Currently attempting to connect - update UI?
break;
- case MultiplexBluetoothTransport.STATE_LISTEN:
+ case MultiplexBaseTransport.STATE_LISTEN:
break;
- case MultiplexBluetoothTransport.STATE_NONE:
+ case MultiplexBaseTransport.STATE_NONE:
// We've just lost the connection
- if(!connectAsClient ){
- if(!service.legacyModeEnabled && !closing){
- service.initBluetoothSerialService();
- }
- service.onTransportDisconnected(TransportType.BLUETOOTH);
- }
+ service.onTransportDisconnected(transportRecord);
break;
- case MultiplexBluetoothTransport.STATE_ERROR:
- if(service.mSerialService!=null){
- Log.d(TAG, "Bluetooth serial server error received, setting state to none, and clearing local copy");
- service.mSerialService.setStateManually(MultiplexBluetoothTransport.STATE_NONE);
- service.mSerialService = null;
- }
+ case MultiplexBaseTransport.STATE_ERROR:
+ service.onTransportError(transportRecord);
break;
}
break;
-
+
case MESSAGE_READ:
service.onPacketRead((SdlPacket) msg.obj);
break;
}
}
}
-
+
@SuppressWarnings("unused") //The return false after the packet null check is not dead code. Read the getByteArray method from bundle
public boolean writeBytesToTransport(Bundle bundle){
if(bundle == null){
return false;
}
- if(mSerialService !=null && mSerialService.getState()==MultiplexBluetoothTransport.STATE_CONNECTED){
- byte[] packet = bundle.getByteArray(TransportConstants.BYTES_TO_SEND_EXTRA_NAME);
- if(packet!=null){
- int offset = bundle.getInt(TransportConstants.BYTES_TO_SEND_EXTRA_OFFSET, 0); //If nothing, start at the beginning of the array
- int count = bundle.getInt(TransportConstants.BYTES_TO_SEND_EXTRA_COUNT, packet.length); //In case there isn't anything just send the whole packet.
- mSerialService.write(packet,offset,count);
- return true;
- }
+ byte[] packet = bundle.getByteArray(TransportConstants.BYTES_TO_SEND_EXTRA_NAME);
+ if(packet==null) {
+ Log.w(TAG, "Ignoring null packet");
return false;
- }else if(sendThroughAltTransport(bundle)){
- return true;
}
- else{
- Log.e(TAG, "Can't send data, no transport connected");
- return false;
- }
+ int offset = bundle.getInt(TransportConstants.BYTES_TO_SEND_EXTRA_OFFSET, 0); //If nothing, start at the beginning of the array
+ int count = bundle.getInt(TransportConstants.BYTES_TO_SEND_EXTRA_COUNT, packet.length); //In case there isn't anything just send the whole packet.
+ TransportType transportType = TransportType.valueForString(bundle.getString(TransportConstants.TRANSPORT_TYPE));
+ switch ((transportType)){
+ case BLUETOOTH:
+ if(bluetoothTransport !=null && bluetoothTransport.getState() == MultiplexBluetoothTransport.STATE_CONNECTED) {
+ bluetoothTransport.write(packet, offset, count);
+ return true;
+ }
+ case USB:
+ if(usbTransport != null && usbTransport.getState() == MultiplexBaseTransport.STATE_CONNECTED) {
+ usbTransport.write(packet, offset, count);
+ return true;
+ }
+ case TCP:
+ if(tcpTransport != null && tcpTransport.getState() == MultiplexBaseTransport.STATE_CONNECTED) {
+ tcpTransport.write(packet, offset, count);
+ return true;
+ }
+ default:
+ if(sendThroughAltTransport(bundle)){
+ return true;
+ }
+ }
+ Log.e(TAG, "Can't send data, no transport of specified type connected");
+ return false;
}
- private boolean manuallyWriteBytes(byte[] bytes, int offset, int count){
- if(mSerialService !=null && mSerialService.getState()==MultiplexBluetoothTransport.STATE_CONNECTED){
- if(bytes!=null){
- mSerialService.write(bytes,offset,count);
- return true;
- }
- return false;
- }else {
- return sendThroughAltTransport(bytes,offset,count);
+ private boolean manuallyWriteBytes(TransportType transportType, byte[] packet, int offset, int count){
+ switch ((transportType)){
+ case BLUETOOTH:
+ if(bluetoothTransport !=null && bluetoothTransport.getState() == MultiplexBluetoothTransport.STATE_CONNECTED) {
+ bluetoothTransport.write(packet, offset, count);
+ return true;
+ }
+ case USB:
+ if(usbTransport != null && usbTransport.getState() == MultiplexBaseTransport.STATE_CONNECTED) {
+ usbTransport.write(packet, offset, count);
+ return true;
+ }
+ case TCP:
+ if(tcpTransport != null && tcpTransport.getState() == MultiplexBaseTransport.STATE_CONNECTED) {
+ tcpTransport.write(packet, offset, count);
+ return true;
+ }
+ default:
+ return sendThroughAltTransport(packet, offset, count);
}
}
@@ -1507,35 +1941,64 @@ public class SdlRouterService extends Service{
* @return whether or not the sending was successful
*/
public boolean sendPacketToRegisteredApp(SdlPacket packet) {
- if(registeredApps!=null && (registeredApps.size()>0)){
- int session = packet.getSessionId();
- boolean shouldAssertNewSession = packet.getFrameType() == FrameType.Control && (packet.getFrameInfo() == SdlPacket.FRAME_INFO_START_SERVICE_ACK || packet.getFrameInfo() == SdlPacket.FRAME_INFO_START_SERVICE_NAK);
- String appid = getAppIDForSession(session, shouldAssertNewSession); //Find where this packet should go
- if(appid!=null && appid.length()>0){
+ if(registeredApps != null && registeredApps.size() > 0 ){
+ final int session = packet.getSessionId();
+ boolean isNewSessionRequest = false, isNewTransportRequest = false;
+
+ final int frameInfo = packet.getFrameInfo();
+ if(packet.getFrameType() == FrameType.Control){
+ isNewSessionRequest = (frameInfo == SdlPacket.FRAME_INFO_START_SERVICE_ACK ||frameInfo == SdlPacket.FRAME_INFO_START_SERVICE_NAK)
+ && packet.getServiceType() == SdlPacket.SERVICE_TYPE_RPC;
+ isNewTransportRequest = (frameInfo == SdlPacket.FRAME_INFO_REGISTER_SECONDARY_TRANSPORT_ACK
+ || frameInfo == SdlPacket.FRAME_INFO_REGISTER_SECONDARY_TRANSPORT_NAK); // && packet.getServiceType() != SdlPacket.SERVICE_TYPE_RPC;
+ }
+
+ //Find where this packet should go
+ String appid = getAppIDForSession(session, isNewSessionRequest, isNewTransportRequest, packet.getTransportRecord().getType());
+
+ if(appid != null && appid.length() > 0){
+
RegisteredApp app;
synchronized(REGISTERED_APPS_LOCK){
app = registeredApps.get(appid);
}
- if(app==null){
+
+ if(app == null){
Log.e(TAG, "No app found for app id " + appid + " Removing session mapping and sending unregisterAI to head unit.");
+
//We have no app to match the app id tied to this session
- removeSessionFromMap(session);
- byte[] uai = createForceUnregisterApp((byte)session, (byte)packet.getVersion());
- manuallyWriteBytes(uai,0,uai.length);
- int hashId = 0;
- synchronized(this.SESSION_LOCK){
- if(this.sessionHashIdMap.indexOfKey(session)>=0){
- hashId = this.sessionHashIdMap.get(session);
- this.sessionHashIdMap.delete(session);
- }
- }
- byte[] stopService = (SdlPacketFactory.createEndSession(SessionType.RPC, (byte)session, 0, (byte)packet.getVersion(),BitConverter.intToByteArray(hashId))).constructPacket();
- manuallyWriteBytes(stopService,0,stopService.length);
- return false;
+ removeSessionFromMap(session, Collections.singletonList(packet.getTransportRecord().getType()));
+
+ final int serviceType = packet.getServiceType();
+ if(serviceType == SdlPacket.SERVICE_TYPE_RPC || serviceType == SdlPacket.SERVICE_TYPE_BULK_DATA) {
+ //This is a primary transport packet as it is an RPC packet
+ //Create an unregister app interface to remove the app as it doesn't appear to exist anymore
+ byte[] uai = createForceUnregisterApp((byte) session, (byte) packet.getVersion());
+ manuallyWriteBytes(packet.getTransportRecord().getType(),uai, 0, uai.length);
+
+ int hashId = 0;
+ synchronized(this.SESSION_LOCK){
+ if(this.sessionHashIdMap.indexOfKey(session)>=0){
+ hashId = this.sessionHashIdMap.get(session);
+ this.sessionHashIdMap.delete(session);
+ }
+ }
+
+ //TODO stop other services on that transport for the session with no app
+ SdlPacket endService = SdlPacketFactory.createEndSession(SessionType.RPC, (byte)session, 0, (byte)packet.getVersion(),BitConverter.intToByteArray(hashId));
+ byte[] stopService = endService.constructPacket();
+ manuallyWriteBytes(packet.getTransportRecord().getType(), stopService,0,stopService.length);
+ }else{
+ Log.w(TAG, "No where to send a packet from what appears to be a non primary transport");
+ }
+
+ return false;
}
+
+ //There is an app id and can continue to normal flow
byte version = (byte)packet.getVersion();
- if(shouldAssertNewSession && version>1 && packet.getFrameInfo() == SdlPacket.FRAME_INFO_START_SERVICE_ACK){ //we know this was a start session response
+ if(isNewSessionRequest && version > 1 && packet.getFrameInfo() == SdlPacket.FRAME_INFO_START_SERVICE_ACK){ //we know this was a start session response
if (packet.getPayload() != null && packet.getDataSize() == 4){ //hashid will be 4 bytes in length
synchronized(SESSION_LOCK){
this.sessionHashIdMap.put(session, (BitConverter.intFromByteArray(packet.getPayload(), 0)));
@@ -1574,6 +2037,7 @@ public class SdlRouterService extends Service{
if(packetSize < ByteArrayMessageSpliter.MAX_BINDER_SIZE){ //This is a small enough packet just send on through
//Log.w(TAG, " Packet size is just right " + packetSize + " is smaller than " + ByteArrayMessageSpliter.MAX_BINDER_SIZE + " = " + (packetSize<ByteArrayMessageSpliter.MAX_BINDER_SIZE));
message.what = TransportConstants.ROUTER_RECEIVED_PACKET;
+ packet.setMessagingVersion(app.routerMessagingVersion);
bundle.putParcelable(FORMED_PACKET_EXTRA_NAME, packet);
bundle.putInt(TransportConstants.BYTES_TO_SEND_FLAGS, TransportConstants.BYTES_TO_SEND_FLAG_NONE);
message.setData(bundle);
@@ -1608,10 +2072,11 @@ public class SdlRouterService extends Service{
}
}else{ //If we can't find a session for this packet we just drop the packet
- Log.e(TAG, "App Id was NULL for session!");
- if(removeSessionFromMap(session)){ //If we found the session id still tied to an app in our map we need to remove it and send the proper shutdown sequence.
+ Log.e(TAG, "App Id was NULL for session! " + session);
+ TransportType transportType = packet.getTransportRecord().getType();
+ if(removeSessionFromMap(session, Collections.singletonList(transportType))){ //If we found the session id still tied to an app in our map we need to remove it and send the proper shutdown sequence.
Log.i(TAG, "Removed session from map. Sending unregister request to module.");
- attemptToCleanUpModule(session, packet.getVersion());
+ attemptToCleanUpModule(session, packet.getVersion(), transportType);
}else{ //There was no mapping so let's try to resolve this
if(packet.getFrameType() == FrameType.Single && packet.getServiceType() == SdlPacket.SERVICE_TYPE_RPC){
@@ -1619,14 +2084,14 @@ public class SdlRouterService extends Service{
if(binFrameHeader!=null && FunctionID.UNREGISTER_APP_INTERFACE.getId() == binFrameHeader.getFunctionID()){
Log.d(TAG, "Received an unregister app interface with no where to send it, dropping the packet.");
}else{
- attemptToCleanUpModule(session, packet.getVersion());
+ attemptToCleanUpModule(session, packet.getVersion(),transportType);
}
}else if((packet.getFrameType() == FrameType.Control
&& (packet.getFrameInfo() == SdlPacket.FRAME_INFO_END_SERVICE_ACK || packet.getFrameInfo() == SdlPacket.FRAME_INFO_END_SERVICE_NAK))){
//We want to ignore this
Log.d(TAG, "Received a stop service ack/nak with no where to send it, dropping the packet.");
}else{
- attemptToCleanUpModule(session, packet.getVersion());
+ attemptToCleanUpModule(session, packet.getVersion(),transportType);
}
}
}
@@ -1640,10 +2105,10 @@ public class SdlRouterService extends Service{
* @param session the session id that is to be cleaned up
* @param version the last known version that this session was operating with
*/
- private void attemptToCleanUpModule(int session, int version){
+ private void attemptToCleanUpModule(int session, int version, TransportType primaryTransport){
Log.i(TAG, "Attempting to stop session " + session);
byte[] uai = createForceUnregisterApp((byte)session, (byte)version);
- manuallyWriteBytes(uai,0,uai.length);
+ manuallyWriteBytes(primaryTransport,uai,0,uai.length);
int hashId = 0;
synchronized(this.SESSION_LOCK){
if(this.sessionHashIdMap.indexOfKey(session)>=0){
@@ -1653,7 +2118,7 @@ public class SdlRouterService extends Service{
}
}
byte[] stopService = (SdlPacketFactory.createEndSession(SessionType.RPC, (byte)session, 0, (byte)version,BitConverter.intToByteArray(hashId))).constructPacket();
- manuallyWriteBytes(stopService,0,stopService.length);
+ manuallyWriteBytes(primaryTransport,stopService,0,stopService.length);
}
private boolean sendPacketMessageToClient(RegisteredApp app, Message message, byte version){
@@ -1669,19 +2134,22 @@ public class SdlRouterService extends Service{
for(int i=0; i<size;i++){
sessionId = sessions.get(i).intValue();
unregister = createForceUnregisterApp((byte)sessionId,version);
- manuallyWriteBytes(unregister,0,unregister.length);
- int hashId = 0;
- synchronized(this.SESSION_LOCK){
- if(this.sessionHashIdMap.indexOfKey(sessionId)>=0){
- hashId = this.sessionHashIdMap.get(sessionId);
+ List<TransportType> transportTypes = app.getTransportsForSession(sessionId);
+ if(transportTypes != null && !transportTypes.isEmpty()) {
+ manuallyWriteBytes(transportTypes.get(0),unregister, 0, unregister.length);
+ int hashId = 0;
+ synchronized (this.SESSION_LOCK) {
+ if (this.sessionHashIdMap.indexOfKey(sessionId) >= 0) {
+ hashId = this.sessionHashIdMap.get(sessionId);
+ }
+ }
+ stopService = (SdlPacketFactory.createEndSession(SessionType.RPC, (byte) sessionId, 0, version, BitConverter.intToByteArray(hashId))).constructPacket();
+
+ manuallyWriteBytes(transportTypes.get(0),stopService, 0, stopService.length);
+ synchronized (SESSION_LOCK) {
+ this.bluetoothSessionMap.remove(sessionId);
+ this.sessionHashIdMap.delete(sessionId);
}
- }
- stopService = (SdlPacketFactory.createEndSession(SessionType.RPC, (byte)sessionId, 0, version,BitConverter.intToByteArray(hashId))).constructPacket();
-
- manuallyWriteBytes(stopService,0,stopService.length);
- synchronized(SESSION_LOCK){
- this.sessionMap.remove(sessionId);
- this.sessionHashIdMap.delete(sessionId);
}
}
synchronized(REGISTERED_APPS_LOCK){
@@ -1693,9 +2161,9 @@ public class SdlRouterService extends Service{
}
private synchronized void closeBluetoothSerialServer(){
- if(mSerialService != null){
- mSerialService.stop();
- mSerialService = null;
+ if(bluetoothTransport != null){
+ bluetoothTransport.stop();
+ bluetoothTransport = null;
}
}
@@ -1729,14 +2197,14 @@ public class SdlRouterService extends Service{
@SuppressWarnings("MissingPermission")
private synchronized boolean bluetoothConnect(BluetoothDevice device){
Log.d(TAG,"Connecting to device: " + device.getName());
- if(mSerialService == null || !mSerialService.isConnected())
+ if(bluetoothTransport == null || !bluetoothTransport.isConnected())
{ // Set up the Bluetooth serial object
- mSerialService = new MultiplexBluetoothTransport(mHandlerBT);
+ bluetoothTransport = new MultiplexBluetoothTransport(bluetoothHandler);
}
// We've been given a device - let's connect to it
- if(mSerialService.getState()!=MultiplexBluetoothTransport.STATE_CONNECTING){
- mSerialService.connect(device);
- if(mSerialService.getState() == MultiplexBluetoothTransport.STATE_CONNECTING){
+ if(bluetoothTransport.getState()!=MultiplexBluetoothTransport.STATE_CONNECTING){
+ bluetoothTransport.connect(device);
+ if(bluetoothTransport.getState() == MultiplexBluetoothTransport.STATE_CONNECTING){
return true;
}
}
@@ -1833,7 +2301,9 @@ public class SdlRouterService extends Service{
public void run() {
altTransportTimerHandler = null;
altTransportTimerRunnable = null;
- shouldServiceRemainOpen(null);
+ if(!shouldServiceRemainOpen(null)){
+ closeSelf();
+ }
}
};
altTransportTimerHandler.postDelayed(altTransportTimerRunnable, ALT_TRANSPORT_TIMEOUT_RUNNABLE);
@@ -1844,28 +2314,43 @@ public class SdlRouterService extends Service{
* @param sessionId the session id that is to be removed from our current mapping
* @return if the key was found
*/
- private boolean removeSessionFromMap(int sessionId){
+ private boolean removeSessionFromMap(int sessionId, List<TransportType> transportTypes){
synchronized(SESSION_LOCK){
- if(sessionMap!=null){
- if(sessionMap.indexOfKey(sessionId)>=0){
- sessionMap.remove(sessionId);
- return true;
+ boolean retVal = false;
+ if(transportTypes != null) { //FIXME I don't believe this should be null
+ if (transportTypes.contains(TransportType.BLUETOOTH) && bluetoothSessionMap != null) {
+ if (bluetoothSessionMap.indexOfKey(sessionId) >= 0) {
+ bluetoothSessionMap.remove(sessionId);
+ retVal = true;
+ }
+ } else if (transportTypes.contains(TransportType.USB) && usbSessionMap != null) {
+ if (usbSessionMap.indexOfKey(sessionId) >= 0) {
+ usbSessionMap.remove(sessionId);
+ retVal = true;
+ }
+ } else if (transportTypes.contains(TransportType.TCP) && tcpSessionMap != null) {
+ if (tcpSessionMap.indexOfKey(sessionId) >= 0) {
+ tcpSessionMap.remove(sessionId);
+ retVal = true;
+ }
}
}
- return false;
+ return retVal;
}
}
+
+
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private boolean removeAllSessionsWithAppId(String appId){
synchronized(SESSION_LOCK){
- if(sessionMap!=null){
- SparseArray<String> iter = sessionMap.clone();
+ if(bluetoothSessionMap !=null){
+ SparseArray<String> iter = bluetoothSessionMap.clone();
int size = iter.size();
for(int i = 0; i<size; i++){
if(iter.valueAt(i).compareTo(appId) == 0){
sessionHashIdMap.delete(iter.keyAt(i));
- sessionMap.removeAt(i);
+ bluetoothSessionMap.removeAt(i);
}
}
return true;
@@ -1884,11 +2369,14 @@ public class SdlRouterService extends Service{
int size = sessions.size(), sessionId;
for(int i=0; i<size;i++){
//Log.d(TAG, "Investigating session " +sessions.get(i).intValue());
- //Log.d(TAG, "App id is: " + sessionMap.get(sessions.get(i).intValue()));
+ //Log.d(TAG, "App id is: " + bluetoothSessionMap.get(sessions.get(i).intValue()));
sessionId = sessions.get(i).intValue();
- removeSessionFromMap(sessionId);
+ List<TransportType> transportTypes = app.getTransportsForSession(sessionId);
+ removeSessionFromMap(sessionId, transportTypes);
if(cleanModule){
- attemptToCleanUpModule(sessionId, cachedModuleVersion);
+ if(transportTypes != null && transportTypes.size() > 0){
+ attemptToCleanUpModule(sessionId, cachedModuleVersion, transportTypes.get(0));
+ }
}
}
}
@@ -1905,27 +2393,103 @@ public class SdlRouterService extends Service{
return false;
}
- private String getAppIDForSession(int sessionId, boolean shouldAssertNewSession){
+ private String getAppIDForSession(int sessionId, boolean newSession, boolean newTransport, TransportType transportType){
synchronized(SESSION_LOCK){
//Log.d(TAG, "Looking for session: " + sessionId);
- if(sessionMap == null){
- Log.w(TAG, "Session map was null during look up. Creating one on the fly");
- sessionMap = new SparseArray<String>(); //THIS SHOULD NEVER BE NULL! WHY IS THIS HAPPENING?!?!?!
- }
- String appId = sessionMap.get(sessionId);// SdlRouterService.this.sessionMap.get(sessionId);
- if(appId==null && shouldAssertNewSession){
- int pos;
- synchronized(REGISTERED_APPS_LOCK){
- for (RegisteredApp app : registeredApps.values()) {
- pos = app.containsSessionId(-1);
- if(pos != -1){
- app.setSessionId(pos,sessionId);
- appId = app.getAppId();
- sessionMap.put(sessionId, appId);
- break;
+ //First get the session map for the correct transport
+ SparseArray<String> sessionMap;
+ switch(transportType){
+ case BLUETOOTH:
+ if(bluetoothSessionMap == null){
+ bluetoothSessionMap = new SparseArray<String>();
+ }
+ sessionMap = bluetoothSessionMap;
+ break;
+ case USB:
+ if(usbSessionMap == null){
+ usbSessionMap = new SparseArray<String>();
+ }
+ sessionMap = usbSessionMap;
+ break;
+ case TCP:
+ if(tcpSessionMap == null){
+ tcpSessionMap = new SparseArray<String>();
+ }
+ sessionMap = tcpSessionMap;
+ break;
+ default:
+ return null;
+ }
+
+ String appId = sessionMap.get(sessionId);
+ if(appId==null){
+ // If service type is RPC then we know we need to just skip ahead and see if there
+ // is a registered app awaiting a session.
+ if(newSession) {
+ int pos;
+ synchronized (REGISTERED_APPS_LOCK) {
+ for (RegisteredApp app : registeredApps.values()) {
+ if(app.getAwaitingSession().contains(transportType)) {
+ pos = app.containsSessionId(-1);
+ if (pos != -1) {
+ app.setSessionId(pos, sessionId);
+ app.registerTransport(sessionId, transportType);
+ app.getAwaitingSession().remove(transportType);
+ appId = app.getAppId();
+ sessionMap.put(sessionId, appId);
+ break;
+ }
+ }
}
}
+ }else if(newTransport){
+
+ // If this is anything other than RPC with a start service response we can assume
+ // the app wants to use a new transport as secondary.
+
+ // We would only receive a start service response for RPC service when an app is
+ // attempting to register for the first time. Other services can be ran on
+ //secondary transports.
+ switch (transportType){
+ case BLUETOOTH: //Check for BT as a secondary transport
+ //USB is potential primary
+ appId = usbSessionMap.get(sessionId);
+ // No other suitable transport for primary transport
+ break;
+ case USB: //Check for USB as a secondary transport
+ //BT potential primary transport
+ appId = bluetoothSessionMap.get(sessionId);
+ // No other suitable transport for primary transport
+ break;
+ case TCP: //Check for TCP as a secondary transport
+ //BT potential primary transport
+ appId = bluetoothSessionMap.get(sessionId);
+ if(appId == null){
+ //USB is potential primary transport
+ appId = usbSessionMap.get(sessionId);
+ }
+ break;
+ default:
+ return null;
+ }
+
+ if(appId != null){
+ //This means that there is a session id of the same id on another transport
+ synchronized(REGISTERED_APPS_LOCK){
+ RegisteredApp app = registeredApps.get(appId);
+ //Ensure a registered app actually exists and is not null
+ if(app != null){
+ //Register this new transport for the app and add the entry to the
+ //session map associated with this transport
+ app.registerTransport(sessionId, transportType);
+ sessionMap.put(sessionId,appId);
+ }else{
+ Log.w(TAG, "No registered app found when register secondary transport");
+ }
+ }
+ }
}
+
}
//Log.d(TAG, sessionId + " session returning App Id: " + appId);
return appId;
@@ -1995,6 +2559,7 @@ public class SdlRouterService extends Service{
private byte[] createForceUnregisterApp(byte sessionId,byte version){
UnregisterAppInterface request = new UnregisterAppInterface();
request.setCorrelationID(UNREGISTER_APP_INTERFACE_CORRELATION_ID);
+ request.format(null,true);
byte[] msgBytes = JsonRPCMarshaller.marshall(request, version);
ProtocolMessage pm = new ProtocolMessage();
pm.setData(msgBytes);
@@ -2024,24 +2589,24 @@ public class SdlRouterService extends Service{
* Method for finding the next, highest priority write task from all connected apps.
* @return the next task for writing out packets if one exists
*/
- protected PacketWriteTask getNextTask(){
+ protected PacketWriteTask getNextTask(TransportType transportType){
final long currentTime = System.currentTimeMillis();
RegisteredApp priorityApp = null;
long currentPriority = -Long.MAX_VALUE, peekWeight;
synchronized(REGISTERED_APPS_LOCK){
PacketWriteTask peekTask;
for (RegisteredApp app : registeredApps.values()) {
- peekTask = app.peekNextTask();
+ peekTask = app.peekNextTask(transportType);
if(peekTask!=null){
peekWeight = peekTask.getWeight(currentTime);
//Log.v(TAG, "App " + app.appId +" has a task with weight "+ peekWeight);
if(peekWeight>currentPriority){
if(app.queuePaused){
- app.notIt();//Reset the timer
+ app.notIt(transportType);//Reset the timer
continue;
}
if(priorityApp!=null){
- priorityApp.notIt();
+ priorityApp.notIt(transportType);
}
currentPriority = peekWeight;
priorityApp = app;
@@ -2049,7 +2614,7 @@ public class SdlRouterService extends Service{
}
}
if(priorityApp!=null){
- return priorityApp.getNextTask();
+ return priorityApp.getNextTask(transportType);
}
}
return null;
@@ -2066,7 +2631,7 @@ public class SdlRouterService extends Service{
private void startClientPings(){
synchronized(this){
- if(!isTransportConnected){ //If we aren't connected, bail
+ if(!isPrimaryTransportConnected()){ //If we aren't connected, bail
return;
}
if(isPingingClients){
@@ -2142,7 +2707,7 @@ public class SdlRouterService extends Service{
@Deprecated
static class LocalRouterService implements Parcelable{
Intent launchIntent = null;
- int version = 0;
+ int version ;
final long timestamp;
ComponentName name;
@@ -2249,31 +2814,61 @@ public class SdlRouterService extends Service{
protected static final int SEND_MESSAGE_ERROR_MESSENGER_DEAD_OBJECT = 0x04;
protected static final int PAUSE_TIME_FOR_QUEUE = 1500;
-
+
+ private final Object TRANSPORT_LOCK = new Object();
+
final String appId;
final Messenger messenger;
final Vector<Long> sessionIds;
+ final Vector<TransportType> awaitingSession;
+ final int routerMessagingVersion;
+
ByteAraryMessageAssembler buffer;
int priorityForBuffingMessage;
DeathRecipient deathNote = null;
//Packet queue vars
- PacketWriteTaskBlockingQueue queue;
- Handler queueWaitHandler= null;
+ final HashMap<TransportType, PacketWriteTaskBlockingQueue> queues;
+ Handler queueWaitHandler;
Runnable queueWaitRunnable = null;
boolean queuePaused = false;
+
+ //Primary will always be first
+ final SparseArray<ArrayList<TransportType>> registeredTransports;
/**
* This is a simple class to hold onto a reference of a registered app.
* @param appId the supplied id for this app that is attempting to register
* @param messenger the specific messenger that is tied to this app
*/
+ @Deprecated
public RegisteredApp(String appId, Messenger messenger){
this.appId = appId;
this.messenger = messenger;
this.sessionIds = new Vector<Long>();
- this.queue = new PacketWriteTaskBlockingQueue();
+ this.queues = new HashMap<>();
queueWaitHandler = new Handler();
+ registeredTransports = new SparseArray<ArrayList<TransportType>>();
+ awaitingSession = new Vector<>();
setDeathNote();
+ routerMessagingVersion = 1;
+ }
+
+ /**
+ * This is a simple class to hold onto a reference of a registered app.
+ * @param appId the supplied id for this app that is attempting to register
+ * @param routerMessagingVersion
+ * @param messenger the specific messenger that is tied to this app
+ */
+ public RegisteredApp(String appId, int routerMessagingVersion, Messenger messenger){
+ this.appId = appId;
+ this.messenger = messenger;
+ this.sessionIds = new Vector<Long>();
+ this.queues = new HashMap<>();
+ queueWaitHandler = new Handler();
+ registeredTransports = new SparseArray<ArrayList<TransportType>>();
+ awaitingSession = new Vector<>();
+ setDeathNote(); //messaging Version
+ this.routerMessagingVersion = routerMessagingVersion;
}
@@ -2283,10 +2878,14 @@ public class SdlRouterService extends Service{
public void close(){
clearDeathNote();
clearBuffer();
- if(this.queue!=null){
- this.queue.clear();
- queue = null;
+ Collection<PacketWriteTaskBlockingQueue> queueCollection = queues.values();
+ for(PacketWriteTaskBlockingQueue queue : queueCollection) {
+ if (queue != null) {
+ queue.clear();
+ }
}
+ queueCollection.clear();
+
if(queueWaitHandler!=null){
if(queueWaitRunnable!=null){
queueWaitHandler.removeCallbacks(queueWaitRunnable);
@@ -2327,6 +2926,7 @@ public class SdlRouterService extends Service{
int location = sessionIds.indexOf(sessionId);
if(location>=0){
Long removedSessionId = sessionIds.remove(location);
+ registeredTransports.remove(sessionId.intValue());
return removedSessionId != null;
}else{
return false;
@@ -2342,30 +2942,163 @@ public class SdlRouterService extends Service{
*/
public void setSessionId(int position,long sessionId) throws ArrayIndexOutOfBoundsException {
this.sessionIds.set(position, sessionId);
+ synchronized (TRANSPORT_LOCK){
+ this.registeredTransports.put((int)sessionId, new ArrayList<TransportType>());
+ }
}
@SuppressWarnings("unused")
public void clearSessionIds(){
this.sessionIds.clear();
}
-
+
+ public Vector<TransportType> getAwaitingSession() {
+ return awaitingSession;
+ }
+
+ protected void registerTransport(int sessionId, TransportType transportType){
+ synchronized (TRANSPORT_LOCK){
+ ArrayList<TransportType> transportTypes = this.registeredTransports.get(sessionId);
+ if(transportTypes!= null){
+ if(queues.get(transportType) == null){
+ queues.put(transportType, new PacketWriteTaskBlockingQueue());
+ }
+ transportTypes.add(transportType);
+ this.registeredTransports.put(sessionId,transportTypes);
+ }
+
+ }
+ }
+
+ /**
+ *
+ * @param sessionId the session id to find if a transport is registered. -1 for sessionId will
+ * trigger a search through all sessions.
+ * @param transportType the transport type to find if a transport is registered. If null is
+ * passed, will return true for any transport being registered on
+ * @return
+ */
+ protected boolean isRegisteredOnTransport(int sessionId, TransportType transportType){
+ synchronized (TRANSPORT_LOCK){
+ if(this.registeredTransports.indexOfKey(sessionId) >= 0){
+ if(transportType == null){
+ return this.registeredTransports.get(sessionId).size() > 0;
+ }
+ return this.registeredTransports.get(sessionId).indexOf(transportType) >= 0;
+ }else if(sessionId < 0 ){
+
+ //Check if any session is registered on this transport
+ int numberOfSessions = registeredTransports.size();
+ ArrayList<TransportType> transportTypes;
+ for(int i = 0; i < numberOfSessions; i++){
+ transportTypes = registeredTransports.valueAt(i);
+ if(transportTypes != null) {
+ if(transportType == null && transportTypes.size() > 0){
+ return true;
+ }
+ for (TransportType type : transportTypes) {
+ if (type.equals(transportType)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+
+ }else{
+ return false;
+ }
+ }
+ }
+
+ protected List<TransportType> getTransportsForSession(int sessionId){
+ synchronized (TRANSPORT_LOCK){
+ if(this.registeredTransports.indexOfKey(sessionId) >= 0){
+ return this.registeredTransports.get(sessionId);
+ }else{
+ return null;
+ }
+ }
+ }
+
+ protected boolean unregisterTransport(int sessionId, TransportType transportType){
+ synchronized (TRANSPORT_LOCK){
+ if(this.registeredTransports.indexOfKey(sessionId) >= 0){
+ return this.registeredTransports.get(sessionId).remove(transportType);
+ }else{
+ return false;
+ }
+ }
+ }
+
+ protected void unregisterAllTransports(int sessionId){
+ synchronized (TRANSPORT_LOCK){
+ if(this.registeredTransports.indexOfKey(sessionId) >= 0){
+ this.registeredTransports.get(sessionId).clear();
+ }else if(sessionId == -1){
+ int size = this.registeredTransports.size();
+ for(int i = 0; i <size; i++){
+ this.registeredTransports.get(i).clear();
+ }
+ }
+ }
+ }
+
+
+ /**
+ * This method will attempt to return a transport type that can be associated to this
+ * registered app
+ * @return
+ */
+ private TransportType getCompatPrimaryTransport(){
+ if(this.registeredTransports != null){
+ List<TransportType> transportTypes = this.registeredTransports.valueAt(0);
+ if(transportTypes != null){
+ if(transportTypes.get(0) != null){
+ return transportTypes.get(0);
+ }
+ }
+ }
+
+ //No transport stored
+ if(bluetoothTransport != null && bluetoothTransport.isConnected()){
+ return TransportType.BLUETOOTH;
+ } else if(usbTransport!= null && usbTransport.isConnected()){
+ return TransportType.USB;
+ } else if(tcpTransport != null && tcpTransport.isConnected()){
+ return TransportType.TCP;
+ }
+
+ return TransportType.BLUETOOTH;
+ }
+
@SuppressWarnings("SameReturnValue")
public boolean handleIncommingClientMessage(final Bundle receivedBundle){
int flags = receivedBundle.getInt(TransportConstants.BYTES_TO_SEND_FLAGS, TransportConstants.BYTES_TO_SEND_FLAG_NONE);
+ TransportType transportType = TransportType.valueForString(receivedBundle.getString(TransportConstants.TRANSPORT_TYPE));
+ if(transportType == null){
+ transportType = getCompatPrimaryTransport();
+ receivedBundle.putString(TransportConstants.TRANSPORT_TYPE, transportType.name());
+ }
+
if(flags!=TransportConstants.BYTES_TO_SEND_FLAG_NONE){
byte[] packet = receivedBundle.getByteArray(TransportConstants.BYTES_TO_SEND_EXTRA_NAME);
if(flags == TransportConstants.BYTES_TO_SEND_FLAG_LARGE_PACKET_START){
this.priorityForBuffingMessage = receivedBundle.getInt(TransportConstants.PACKET_PRIORITY_COEFFICIENT,0);
}
- handleMessage(flags, packet);
+ handleMessage(flags, packet, transportType);
}else{
//Add the write task on the stack
- if(queue!=null){
- queue.add(new PacketWriteTask(receivedBundle));
- if(packetWriteTaskMaster!=null){
- packetWriteTaskMaster.alert();
- }
+ PacketWriteTaskBlockingQueue queue = queues.get(transportType);
+ if(queue == null){ //TODO check to see if there is any better place to put this
+ queue = new PacketWriteTaskBlockingQueue();
+ queues.put(transportType,queue);
}
+ queue.add(new PacketWriteTask(receivedBundle));
+ PacketWriteTaskMaster packetWriteTaskMaster = packetWriteTaskMasterMap.get(transportType);
+ if(packetWriteTaskMaster!=null){
+ packetWriteTaskMaster.alert();
+ }
}
return true;
}
@@ -2385,12 +3118,18 @@ public class SdlRouterService extends Service{
}
}
}
-
- public void handleMessage(int flags, byte[] packet){
+
+ @Deprecated
+ public void handleMessage(int flags, byte[] packet) {
+ handleMessage(flags,packet,null);
+ }
+
+ public void handleMessage(int flags, byte[] packet, TransportType transportType){
if(flags == TransportConstants.BYTES_TO_SEND_FLAG_LARGE_PACKET_START){
clearBuffer();
buffer = new ByteAraryMessageAssembler();
buffer.init();
+ buffer.setTransportType(transportType);
}
if(buffer != null){
if (!buffer.handleMessage(flags, packet)) { //If this returns false
@@ -2398,8 +3137,10 @@ public class SdlRouterService extends Service{
}
if (buffer.isFinished()) { //We are finished building the buffer so we should write the bytes out
byte[] bytes = buffer.getBytes();
+ PacketWriteTaskBlockingQueue queue = queues.get(transportType);
if (queue != null) {
- queue.add(new PacketWriteTask(bytes, 0, bytes.length, this.priorityForBuffingMessage));
+ queue.add(new PacketWriteTask(bytes, 0, bytes.length, this.priorityForBuffingMessage,transportType));
+ PacketWriteTaskMaster packetWriteTaskMaster = packetWriteTaskMasterMap.get(transportType);
if (packetWriteTaskMaster != null) {
packetWriteTaskMaster.alert();
}
@@ -2409,14 +3150,16 @@ public class SdlRouterService extends Service{
}
}
- protected PacketWriteTask peekNextTask(){
+ protected PacketWriteTask peekNextTask(TransportType transportType){
+ PacketWriteTaskBlockingQueue queue = queues.get(transportType);
if(queue !=null){
return queue.peek();
}
return null;
}
- protected PacketWriteTask getNextTask(){
+ protected PacketWriteTask getNextTask(TransportType transportType){
+ PacketWriteTaskBlockingQueue queue = queues.get(transportType);
if(queue !=null){
return queue.poll();
}
@@ -2427,7 +3170,8 @@ public class SdlRouterService extends Service{
* This will inform the local app object that it was not picked to have the highest priority. This will allow the user to continue to perform interactions
* with the module and not be bogged down by large packet requests.
*/
- protected void notIt(){
+ protected void notIt(final TransportType transportType){
+ PacketWriteTaskBlockingQueue queue = queues.get(transportType);
if(queue!=null && queue.peek().priorityCoefficient>0){ //If this has any sort of priority coefficient we want to make it wait.
//Flag to wait
if(queueWaitHandler == null){
@@ -2439,12 +3183,11 @@ public class SdlRouterService extends Service{
@Override
public void run() {
pauseQueue(false);
+ PacketWriteTaskMaster packetWriteTaskMaster = packetWriteTaskMasterMap.get(transportType);
if(packetWriteTaskMaster!=null){
packetWriteTaskMaster.alert();
}
-
}
-
};
}
if(queuePaused){
@@ -2514,15 +3257,22 @@ public class SdlRouterService extends Service{
private final int offset, size, priorityCoefficient;
private final long timestamp;
final Bundle receivedBundle;
+ TransportType transportType;
@SuppressWarnings("SameParameterValue")
- public PacketWriteTask(byte[] bytes, int offset, int size, int priorityCoefficient){
+ @Deprecated
+ public PacketWriteTask(byte[] bytes, int offset, int size, int priorityCoefficient) {
+ this(bytes, offset, size, priorityCoefficient,null);
+ }
+
+ public PacketWriteTask(byte[] bytes, int offset, int size, int priorityCoefficient, TransportType transportType){
timestamp = System.currentTimeMillis();
bytesToWrite = bytes;
this.offset = offset;
this.size = size;
this.priorityCoefficient = priorityCoefficient;
receivedBundle = null;
+ this.transportType = transportType;
}
public PacketWriteTask(Bundle bundle){
@@ -2532,14 +3282,20 @@ public class SdlRouterService extends Service{
offset = bundle.getInt(TransportConstants.BYTES_TO_SEND_EXTRA_OFFSET, 0); //If nothing, start at the beginning of the array
size = bundle.getInt(TransportConstants.BYTES_TO_SEND_EXTRA_COUNT, bytesToWrite.length); //In case there isn't anything just send the whole packet.
this.priorityCoefficient = bundle.getInt(TransportConstants.PACKET_PRIORITY_COEFFICIENT,0);
+ this.transportType = TransportType.valueForString(receivedBundle.getString(TransportConstants.TRANSPORT_TYPE));
+
}
-
+
+ protected void setTransportType(TransportType transportType){
+ this.transportType = transportType;
+ }
+
@Override
public void run() {
- if(receivedBundle!=null){
+ if(receivedBundle != null){
writeBytesToTransport(receivedBundle);
}else if(bytesToWrite !=null){
- manuallyWriteBytes(bytesToWrite, offset, size);
+ manuallyWriteBytes(this.transportType, bytesToWrite, offset, size);
}
}
@@ -2557,18 +3313,22 @@ public class SdlRouterService extends Service{
private class PacketWriteTaskMaster extends Thread{
protected final Object QUEUE_LOCK = new Object();
private boolean isHalted = false, isWaiting = false;
-
+ private TransportType transportType;
+
public PacketWriteTaskMaster(){
this.setName("PacketWriteTaskMaster");
}
-
+ protected void setTransportType(TransportType transportType){
+ this.transportType = transportType;
+ }
+
@Override
public void run() {
while(!isHalted){
try{
PacketWriteTask task;
synchronized(QUEUE_LOCK){
- task = getNextTask();
+ task = getNextTask(transportType);
if(task != null){
task.run();
}else{
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterStatusProvider.java b/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterStatusProvider.java
index 8dbca61a7..2b3a17a8e 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterStatusProvider.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterStatusProvider.java
@@ -12,6 +12,7 @@ import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -20,6 +21,8 @@ import android.os.RemoteException;
import android.util.Log;
import android.os.Looper;
+import static com.smartdevicelink.transport.TransportConstants.FOREGROUND_EXTRA;
+
public class SdlRouterStatusProvider {
private static final String TAG = "SdlRouterStateProvider";
@@ -99,7 +102,13 @@ public class SdlRouterStatusProvider {
Intent bindingIntent = new Intent();
bindingIntent.setClassName(this.routerService.getPackageName(), this.routerService.getClassName());//This sets an explicit intent
//Quickly make sure it's just up and running
- context.startService(bindingIntent);
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+ context.startService(bindingIntent);
+ }else {
+ bindingIntent.putExtra(FOREGROUND_EXTRA, true);
+ context.startForegroundService(bindingIntent);
+
+ }
bindingIntent.setAction( TransportConstants.BIND_REQUEST_TYPE_STATUS);
return context.bindService(bindingIntent, routerConnection, Context.BIND_AUTO_CREATE);
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/TransportBroker.java b/sdl_android/src/main/java/com/smartdevicelink/transport/TransportBroker.java
index 3db2aa1e1..1a88fb1b1 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/TransportBroker.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/TransportBroker.java
@@ -1,3 +1,35 @@
+/*
+ * 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 android.annotation.SuppressLint;
@@ -22,622 +54,723 @@ import com.smartdevicelink.protocol.SdlPacket;
import com.smartdevicelink.transport.enums.TransportType;
import com.smartdevicelink.transport.utl.ByteAraryMessageAssembler;
import com.smartdevicelink.transport.utl.ByteArrayMessageSpliter;
+import com.smartdevicelink.transport.utl.TransportRecord;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.List;
import java.util.Locale;
public class TransportBroker {
-
- private static final String TAG = "SdlTransportBroker";
- private final String WHERE_TO_REPLY_PREFIX = "com.sdl.android.";
- private String appId = null;
- private String whereToReply = null;
- private Context currentContext = null;
-
- private final Object INIT_LOCK = new Object();
-
- private TransportType queuedOnTransportConnect = null;
-
- Messenger routerServiceMessenger = null;
- final Messenger clientMessenger;
-
- boolean isBound = false, registeredWithRouterService = false;
- private String routerPackage = null, routerClassName = null;
- private ComponentName routerService = null;
-
-
- private SdlPacket bufferedPacket = null;
- private ByteAraryMessageAssembler bufferedPayloadAssembler = null;
-
- private ServiceConnection routerConnection;
- private int routerServiceVersion = 1;
-
- private void initRouterConnection(){
- routerConnection= new ServiceConnection() {
-
- public void onServiceConnected(ComponentName className, IBinder service) {
- Log.d(TAG, "Bound to service " + className.toString());
- routerServiceMessenger = new Messenger(service);
- isBound = true;
- //So we just established our connection
- //Register with router service
- sendRegistrationMessage();
- }
-
- public void onServiceDisconnected(ComponentName className) {
- Log.d(TAG, "Unbound from service " + className.getClassName());
- routerServiceMessenger = null;
- registeredWithRouterService = false;
- isBound = false;
- onHardwareDisconnected(null);
- }
- };
- }
-
- protected synchronized boolean sendMessageToRouterService(Message message){
- return sendMessageToRouterService(message,0);
- }
-
- protected synchronized boolean sendMessageToRouterService(Message message, int retryCount){
- if(message == null){
- Log.w(TAG, "Attempted to send null message");
- return false;
- }
- //Log.i(TAG, "Attempting to send message type - " + message.what);
- if(isBound && routerServiceMessenger !=null){
- if(registeredWithRouterService
- || message.what == TransportConstants.ROUTER_REGISTER_CLIENT){ //We can send a message if we are registered or are attempting to register
- try {
- routerServiceMessenger.send(message);
- return true;
- } catch (RemoteException e) {
- e.printStackTrace();
- //Let's check to see if we should retry
- if(e instanceof TransactionTooLargeException
- || (retryCount<5 && routerServiceMessenger.getBinder().isBinderAlive() && routerServiceMessenger.getBinder().pingBinder())){ //We probably just failed on a small transaction =\
- try {
- Thread.sleep(100);
- } catch (InterruptedException e1) {
- e1.printStackTrace();
- }
- return sendMessageToRouterService(message, retryCount++);
- }else{
- //DeadObject, time to kill our connection
- Log.d(TAG, "Dead object while attempting to send packet");
- routerServiceMessenger = null;
- registeredWithRouterService = false;
- isBound = false;
- onHardwareDisconnected(null);
- return false;
- }
- } catch (NullPointerException e){
- Log.d(TAG, "Null messenger while attempting to send packet"); // NPE, routerServiceMessenger is null
- routerServiceMessenger = null;
- registeredWithRouterService = false;
- isBound = false;
- onHardwareDisconnected(null);
- return false;
- }
- }else{
- Log.e(TAG, "Unable to send message to router service. Not registered.");
- return false;
- }
- }else{
- Log.e(TAG, "Unable to send message to router service. Not bound.");
- return false;
- }
- }
-
-
+
+ private static final String TAG = "SdlTransportBroker";
+
+ /**
+ * See version document included with library
+ */
+ private static final int MAX_MESSAGING_VERSION = 2;
+ private static final int MIN_MESSAGING_VERSION = 1;
+
+ private final String WHERE_TO_REPLY_PREFIX = "com.sdl.android.";
+ private String appId = null;
+ private String whereToReply = null;
+ private Context currentContext = null;
+
+ private final Object INIT_LOCK = new Object();
+
+ private TransportType queuedOnTransportConnect = null;
+
+ Messenger routerServiceMessenger = null;
+ final Messenger clientMessenger;
+
+ boolean isBound = false, registeredWithRouterService = false;
+ private String routerPackage = null, routerClassName = null;
+ private ComponentName routerService = null;
+
+
+ private SdlPacket bufferedPacket = null;
+ private ByteAraryMessageAssembler bufferedPayloadAssembler = null;
+
+ private ServiceConnection routerConnection;
+ private int routerServiceVersion = 1;
+ private int messagingVersion = MAX_MESSAGING_VERSION;
+
+ private void initRouterConnection() {
+ routerConnection = new ServiceConnection() {
+
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "Bound to service " + className.toString());
+ routerServiceMessenger = new Messenger(service);
+ isBound = true;
+ //So we just established our connection
+ //Register with router service
+ sendRegistrationMessage();
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ Log.d(TAG, "Unbound from service " + className.getClassName());
+ routerServiceMessenger = null;
+ registeredWithRouterService = false;
+ isBound = false;
+ onHardwareDisconnected(null, null);
+ }
+ };
+ }
+
+ protected synchronized boolean sendMessageToRouterService(Message message) {
+ return sendMessageToRouterService(message, 0);
+ }
+
+ protected synchronized boolean sendMessageToRouterService(Message message, int retryCount) {
+ if (message == null) {
+ Log.w(TAG, "Attempted to send null message");
+ return false;
+ }
+ //Log.i(TAG, "Attempting to send message type - " + message.what);
+ if (isBound && routerServiceMessenger != null) {
+ if (registeredWithRouterService
+ || message.what == TransportConstants.ROUTER_REGISTER_CLIENT) { //We can send a message if we are registered or are attempting to register
+ try {
+ routerServiceMessenger.send(message);
+ return true;
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ //Let's check to see if we should retry
+ if (e instanceof TransactionTooLargeException
+ || (retryCount < 5 && routerServiceMessenger.getBinder().isBinderAlive() && routerServiceMessenger.getBinder().pingBinder())) { //We probably just failed on a small transaction =\
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e1) {
+ e1.printStackTrace();
+ }
+ return sendMessageToRouterService(message, retryCount++);
+ } else {
+ //DeadObject, time to kill our connection
+ Log.d(TAG, "Dead object while attempting to send packet");
+ routerServiceMessenger = null;
+ registeredWithRouterService = false;
+ isBound = false;
+ onHardwareDisconnected(null, null);
+ return false;
+ }
+ } catch (NullPointerException e) {
+ Log.d(TAG, "Null messenger while attempting to send packet"); // NPE, routerServiceMessenger is null
+ routerServiceMessenger = null;
+ registeredWithRouterService = false;
+ isBound = false;
+ onHardwareDisconnected(null, null);
+ return false;
+ }
+ } else {
+ Log.e(TAG, "Unable to send message to router service. Not registered.");
+ return false;
+ }
+ } else {
+ Log.e(TAG, "Unable to send message to router service. Not bound.");
+ return false;
+ }
+ }
+
+
/**
* Handler of incoming messages from service.
*/
- static class ClientHandler extends Handler {
+ static class ClientHandler extends Handler {
ClassLoader loader;
final WeakReference<TransportBroker> provider;
- public ClientHandler(TransportBroker provider){
- this.provider = new WeakReference<TransportBroker>(provider);
- loader = getClass().getClassLoader();
- }
- @Override
+ public ClientHandler(TransportBroker provider) {
+ this.provider = new WeakReference<TransportBroker>(provider);
+ loader = getClass().getClassLoader();
+ }
+
+ @Override
public void handleMessage(Message msg) {
- TransportBroker broker = provider.get();
- if(broker == null){
- Log.e(TAG, "Broker object null, unable to process message");
- return;
- }
- Bundle bundle = msg.getData();
-
- if(bundle!=null){
- bundle.setClassLoader(loader);
- }
- //Log.d(TAG, "Bundle: " + bundle.toString());
+ TransportBroker broker = provider.get();
+ if (broker == null) {
+ Log.e(TAG, "Broker object null, unable to process message");
+ return;
+ }
+ Bundle bundle = msg.getData();
+
+ if (bundle != null) {
+ bundle.setClassLoader(loader);
+ }
+ //Log.d(TAG, "Bundle: " + bundle.toString());
/* DO NOT MOVE
* This needs to be first to make sure we already know if we are attempting to enter legacy mode or not
*/
- if(bundle !=null
- && bundle.containsKey(TransportConstants.ENABLE_LEGACY_MODE_EXTRA)){
- boolean enableLegacy = bundle.getBoolean(TransportConstants.ENABLE_LEGACY_MODE_EXTRA, false);
- broker.enableLegacyMode(enableLegacy);
- }
-
- //Find out what message we have and what to do with it
+ if (bundle != null
+ && bundle.containsKey(TransportConstants.ENABLE_LEGACY_MODE_EXTRA)) {
+ boolean enableLegacy = bundle.getBoolean(TransportConstants.ENABLE_LEGACY_MODE_EXTRA, false);
+ broker.enableLegacyMode(enableLegacy);
+ }
+
+ //Find out what message we have and what to do with it
switch (msg.what) {
- case TransportConstants.ROUTER_REGISTER_CLIENT_RESPONSE:
- switch(msg.arg1){
- case TransportConstants.REGISTRATION_RESPONSE_SUCESS:
- // yay! we have been registered. Now what?
- broker.registeredWithRouterService = true;
- if(bundle !=null){
- if(bundle.containsKey(TransportConstants.HARDWARE_CONNECTED)){
- if(bundle.containsKey(TransportConstants.CONNECTED_DEVICE_STRING_EXTRA_NAME)){
- //Keep track if we actually get this
- }
- broker.onHardwareConnected(TransportType.valueOf(bundle.getString(TransportConstants.HARDWARE_CONNECTED)));
- }
- if(bundle.containsKey(TransportConstants.ROUTER_SERVICE_VERSION)){
- broker.routerServiceVersion = bundle.getInt(TransportConstants.ROUTER_SERVICE_VERSION);
- }
- }
- break;
- case TransportConstants.REGISTRATION_RESPONSE_DENIED_LEGACY_MODE_ENABLED:
- Log.d(TAG, "Denied registration because router is in legacy mode" );
- broker.registeredWithRouterService = false;
- broker.enableLegacyMode(true);
- //We call this so we can start the process of legacy connection
- //onHardwareDisconnected(TransportType.BLUETOOTH);
- broker.onLegacyModeEnabled();
- break;
- default:
- broker.registeredWithRouterService = false;
- Log.w(TAG, "Registration denied from router service. Reason - " + msg.arg1);
- break;
- };
-
-
- break;
- case TransportConstants.ROUTER_UNREGISTER_CLIENT_RESPONSE:
- if(msg.arg1==TransportConstants.UNREGISTRATION_RESPONSE_SUCESS){
- // We've been unregistered. Now what?
-
-
- }else{ //We were denied our unregister request to the router service, let's see why
- Log.w(TAG, "Unregister request denied from router service. Reason - " + msg.arg1);
- //Do we care?
- }
-
- break;
- case TransportConstants.ROUTER_RECEIVED_PACKET:
- //So the intent has a packet with it. PEFRECT! Let's send it through the library
- int flags = bundle.getInt(TransportConstants.BYTES_TO_SEND_FLAGS, TransportConstants.BYTES_TO_SEND_FLAG_NONE);
-
- if(bundle.containsKey(TransportConstants.FORMED_PACKET_EXTRA_NAME)){
- Parcelable packet = bundle.getParcelable(TransportConstants.FORMED_PACKET_EXTRA_NAME);
-
- if(flags == TransportConstants.BYTES_TO_SEND_FLAG_NONE){
- if(packet!=null){ //Log.i(TAG, "received packet to process "+ packet.toString());
- broker.onPacketReceived(packet);
- }else{
- Log.w(TAG, "Received null packet from router service, not passing along");
- }
- }else if(flags == TransportConstants.BYTES_TO_SEND_FLAG_SDL_PACKET_INCLUDED){
- broker.bufferedPacket = (SdlPacket) packet;
- if(broker.bufferedPayloadAssembler !=null){
- broker.bufferedPayloadAssembler.close();
- broker.bufferedPayloadAssembler = null;
- }
-
- broker.bufferedPayloadAssembler = new ByteAraryMessageAssembler();
- broker.bufferedPayloadAssembler.init();
- }
- }else if(bundle.containsKey(TransportConstants.BYTES_TO_SEND_EXTRA_NAME)){
- //This should contain the payload
- if(broker.bufferedPayloadAssembler!=null){
- byte[] chunk = bundle.getByteArray(TransportConstants.BYTES_TO_SEND_EXTRA_NAME);
- if(!broker.bufferedPayloadAssembler.handleMessage(flags, chunk)){
- //If there was a problem
- Log.e(TAG, "Error handling bytes for split packet");
- }
- if(broker.bufferedPayloadAssembler.isFinished()){
- broker.bufferedPacket.setPayload(broker.bufferedPayloadAssembler.getBytes());
-
- broker.bufferedPayloadAssembler.close();
- broker.bufferedPayloadAssembler = null;
- broker.onPacketReceived(broker.bufferedPacket);
- broker.bufferedPacket = null;
- }
- }
- //}
- //}
- }else{
- Log.w(TAG, "Flase positive packet reception");
- }
- break;
- case TransportConstants.HARDWARE_CONNECTION_EVENT:
- if(bundle.containsKey(TransportConstants.HARDWARE_DISCONNECTED)){
- //We should shut down, so call
- Log.d(TAG, "Hardware disconnected");
- if(isLegacyModeEnabled()){
- broker.onLegacyModeEnabled();
- }else{
- broker.onHardwareDisconnected(TransportType.valueOf(bundle.getString(TransportConstants.HARDWARE_DISCONNECTED)));
- }
- break;
- }
-
- if(bundle.containsKey(TransportConstants.HARDWARE_CONNECTED)){
- if(bundle!=null && bundle.containsKey(TransportConstants.CONNECTED_DEVICE_STRING_EXTRA_NAME)){
- //Keep track if we actually get this
- }
- broker.onHardwareConnected(TransportType.valueOf(bundle.getString(TransportConstants.HARDWARE_CONNECTED)));
- break;
- }
- break;
- default:
+ case TransportConstants.ROUTER_REGISTER_CLIENT_RESPONSE:
+ switch (msg.arg1) {
+ case TransportConstants.REGISTRATION_RESPONSE_SUCESS:
+ // yay! we have been registered. Now what?
+ broker.registeredWithRouterService = true;
+ if (bundle != null) {
+ if (bundle.containsKey(TransportConstants.HARDWARE_CONNECTED)) {
+ if (bundle.containsKey(TransportConstants.CONNECTED_DEVICE_STRING_EXTRA_NAME)) {
+ //Keep track if we actually get this
+ }
+ //broker.onHardwareConnected(TransportType.valueOf(bundle.getString(TransportConstants.HARDWARE_CONNECTED)));
+ }
+
+ if (bundle.containsKey(TransportConstants.CURRENT_HARDWARE_CONNECTED)) {
+ ArrayList<TransportRecord> transports = bundle.getParcelableArrayList(TransportConstants.CURRENT_HARDWARE_CONNECTED);
+ broker.onHardwareConnected(transports);
+ }
+ if (bundle.containsKey(TransportConstants.ROUTER_SERVICE_VERSION)) {
+ broker.routerServiceVersion = bundle.getInt(TransportConstants.ROUTER_SERVICE_VERSION);
+ }
+ }
+ break;
+ case TransportConstants.REGISTRATION_RESPONSE_DENIED_LEGACY_MODE_ENABLED:
+ Log.d(TAG, "Denied registration because router is in legacy mode");
+ broker.registeredWithRouterService = false;
+ broker.enableLegacyMode(true);
+ //We call this so we can start the process of legacy connection
+ //onHardwareDisconnected(TransportType.BLUETOOTH);
+ broker.onLegacyModeEnabled();
+ break;
+ default:
+ broker.registeredWithRouterService = false;
+ Log.w(TAG, "Registration denied from router service. Reason - " + msg.arg1);
+ break;
+ }
+ ;
+
+
+ break;
+ case TransportConstants.ROUTER_UNREGISTER_CLIENT_RESPONSE:
+ if (msg.arg1 == TransportConstants.UNREGISTRATION_RESPONSE_SUCESS) {
+ // We've been unregistered. Now what?
+
+
+ } else { //We were denied our unregister request to the router service, let's see why
+ Log.w(TAG, "Unregister request denied from router service. Reason - " + msg.arg1);
+ //Do we care?
+ }
+
+ break;
+ case TransportConstants.ROUTER_RECEIVED_PACKET:
+ //So the intent has a packet with it. PEFRECT! Let's send it through the library
+ int flags = bundle.getInt(TransportConstants.BYTES_TO_SEND_FLAGS, TransportConstants.BYTES_TO_SEND_FLAG_NONE);
+
+ if (bundle.containsKey(TransportConstants.FORMED_PACKET_EXTRA_NAME)) {
+ Parcelable packet = bundle.getParcelable(TransportConstants.FORMED_PACKET_EXTRA_NAME);
+
+ if (flags == TransportConstants.BYTES_TO_SEND_FLAG_NONE) {
+ if (packet != null) { //Log.i(TAG, "received packet to process "+ packet.toString());
+ broker.onPacketReceived(packet);
+ } else {
+ Log.w(TAG, "Received null packet from router service, not passing along");
+ }
+ } else if (flags == TransportConstants.BYTES_TO_SEND_FLAG_SDL_PACKET_INCLUDED) {
+ broker.bufferedPacket = (SdlPacket) packet;
+ if (broker.bufferedPayloadAssembler != null) {
+ broker.bufferedPayloadAssembler.close();
+ broker.bufferedPayloadAssembler = null;
+ }
+
+ broker.bufferedPayloadAssembler = new ByteAraryMessageAssembler();
+ broker.bufferedPayloadAssembler.init();
+ }
+ } else if (bundle.containsKey(TransportConstants.BYTES_TO_SEND_EXTRA_NAME)) {
+ //This should contain the payload
+ if (broker.bufferedPayloadAssembler != null) {
+ byte[] chunk = bundle.getByteArray(TransportConstants.BYTES_TO_SEND_EXTRA_NAME);
+ if (!broker.bufferedPayloadAssembler.handleMessage(flags, chunk)) {
+ //If there was a problem
+ Log.e(TAG, "Error handling bytes for split packet");
+ }
+ if (broker.bufferedPayloadAssembler.isFinished()) {
+ broker.bufferedPacket.setPayload(broker.bufferedPayloadAssembler.getBytes());
+
+ broker.bufferedPayloadAssembler.close();
+ broker.bufferedPayloadAssembler = null;
+ broker.onPacketReceived(broker.bufferedPacket);
+ broker.bufferedPacket = null;
+ }
+ }
+ //}
+ //}
+ } else {
+ Log.w(TAG, "Flase positive packet reception");
+ }
+ break;
+ case TransportConstants.HARDWARE_CONNECTION_EVENT:
+ if (bundle.containsKey(TransportConstants.TRANSPORT_DISCONNECTED)
+ || bundle.containsKey(TransportConstants.HARDWARE_DISCONNECTED)) {
+ //We should shut down, so call
+ Log.d(TAG, "Hardware disconnected");
+ if (isLegacyModeEnabled()) {
+ broker.onLegacyModeEnabled();
+ } else {
+ if (bundle.containsKey(TransportConstants.TRANSPORT_DISCONNECTED)) {
+ TransportRecord disconnectedTransport = bundle.getParcelable(TransportConstants.TRANSPORT_DISCONNECTED);
+ List<TransportRecord> connectedTransports = bundle.getParcelableArrayList(TransportConstants.CURRENT_HARDWARE_CONNECTED);
+ broker.onHardwareDisconnected(disconnectedTransport, connectedTransports);
+ } else {
+ TransportType transportType = TransportType.valueOf(bundle.getString(TransportConstants.HARDWARE_DISCONNECTED));
+ broker.onHardwareDisconnected(new TransportRecord(transportType, null), null);
+ }
+
+
+ }
+ break;
+ }
+
+ if (bundle.containsKey(TransportConstants.HARDWARE_CONNECTED) || bundle.containsKey(TransportConstants.CURRENT_HARDWARE_CONNECTED)) {
+ //broker.onHardwareConnected(TransportType.valueOf(bundle.getString(TransportConstants.HARDWARE_CONNECTED)));
+
+ if (bundle.containsKey(TransportConstants.CURRENT_HARDWARE_CONNECTED)) {
+ ArrayList<TransportRecord> transports = bundle.getParcelableArrayList(TransportConstants.CURRENT_HARDWARE_CONNECTED);
+ broker.onHardwareConnected(transports);
+ }
+ break;
+ }
+ break;
+ default:
super.handleMessage(msg);
- }
-
+ }
+
+ }
+ }
+
+
+ /***************************************************************************************************************************************
+ *********************************************** Life Cycle **************************************************************
+ ****************************************************************************************************************************************/
+
+
+ @SuppressLint("SimpleDateFormat")
+ public TransportBroker(Context context, String appId, ComponentName service) {
+ synchronized (INIT_LOCK) {
+ clientMessenger = new Messenger(new ClientHandler(this));
+ initRouterConnection();
+ //So the user should have set the AppId, lets define where the intents need to be sent
+ SimpleDateFormat s = new SimpleDateFormat("hhmmssss"); //So we have a time stamp of the event
+ String timeStamp = s.format(new Date(System.currentTimeMillis()));
+ if (whereToReply == null) {
+ if (appId == null) { //This should really just throw an error
+ whereToReply = WHERE_TO_REPLY_PREFIX + "." + timeStamp;
+ } else {
+ whereToReply = WHERE_TO_REPLY_PREFIX + appId + "." + timeStamp;
+ }
+ }
+ //this.appId = appId.concat(timeStamp);
+ this.appId = appId;
+ queuedOnTransportConnect = null;
+ currentContext = context;
+ //Log.d(TAG, "Registering our reply receiver: " + whereToReply);
+ this.routerService = service;
+ }
+ }
+
+ /**
+ * This beings the initial connection with the router service.
+ */
+ public boolean start() {
+ //Log.d(TAG, "Starting up transport broker for " + whereToReply);
+ synchronized (INIT_LOCK) {
+ if (currentContext == null) {
+ throw new IllegalStateException("This instance can't be started since it's local reference of context is null. Ensure when suppling a context to the TransportBroker that it is valid");
+ }
+ if (routerConnection == null) {
+ initRouterConnection();
+ }
+ //Log.d(TAG, "Registering our reply receiver: " + whereToReply);
+ if (!isBound) {
+ return registerWithRouterService();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public void resetSession() {
+ synchronized (INIT_LOCK) {
+ unregisterWithRouterService();
+ routerServiceMessenger = null;
+ queuedOnTransportConnect = null;
+ unBindFromRouterService();
+ }
+ }
+
+ /**
+ * This method will end our communication with the router service.
+ */
+ public void stop() {
+ //Log.d(TAG, "STOPPING transport broker for " + whereToReply);
+ synchronized (INIT_LOCK) {
+ unregisterWithRouterService();
+ unBindFromRouterService();
+ routerServiceMessenger = null;
+ queuedOnTransportConnect = null;
+ currentContext = null;
+
+ }
+ }
+
+ private void unBindFromRouterService() {
+ try {
+ if (getContext() != null && routerConnection != null) {
+ getContext().unbindService(routerConnection);
+ } else {
+ Log.w(TAG, "Unable to unbind from router service, context was null");
+ }
+
+ } catch (IllegalArgumentException e) {
+ //This is ok
+ }
+ }
+
+ /***************************************************************************************************************************************
+ *********************************************** Event Callbacks **************************************************************
+ ****************************************************************************************************************************************/
+
+
+ public void onServiceUnregsiteredFromRouterService(int unregisterCode) {
+ queuedOnTransportConnect = null;
+ }
+
+ @Deprecated
+ public void onHardwareDisconnected(TransportType type) {
+ routerServiceDisconnect();
+ }
+
+ public void onHardwareDisconnected(TransportRecord record, List<TransportRecord> connectedTransports) {
+
+ }
+
+ private void routerServiceDisconnect() {
+ synchronized (INIT_LOCK) {
+ unBindFromRouterService();
+ routerServiceMessenger = null;
+ routerConnection = null;
+ queuedOnTransportConnect = null;
+ }
+ }
+
+ /**
+ * WILL NO LONGER BE CALLED
+ *
+ * @param type
+ * @return
+ */
+ @Deprecated
+ public boolean onHardwareConnected(TransportType type) {
+ synchronized (INIT_LOCK) {
+ if (routerServiceMessenger == null) {
+ queuedOnTransportConnect = type;
+ return false;
+ }
+ return true;
+ }
+ }
+
+ public boolean onHardwareConnected(List<TransportRecord> transports) {
+ synchronized (INIT_LOCK) {
+ if (routerServiceMessenger == null && transports != null && transports.size() > 0) {
+ queuedOnTransportConnect = transports.get(transports.size() - 1).getType();
+ return false;
+ }
+ return true;
+ }
+ }
+
+ public void onPacketReceived(Parcelable packet) {
+
+ }
+
+ public void onLegacyModeEnabled() {
+
+ }
+
+ /**
+ * We want to check to see if the Router service is already up and running
+ *
+ * @param context
+ * @return
+ */
+ private boolean isRouterServiceRunning(Context context) {
+ if (context == null) {
+
+ return false;
+ }
+ ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
+ //We will check to see if it contains this name, should be pretty specific
+ if ((service.service.getClassName()).toLowerCase(Locale.US).contains(SdlBroadcastReceiver.SDL_ROUTER_SERVICE_CLASS_NAME)) {
+ this.routerClassName = service.service.getClassName();
+ this.routerPackage = service.service.getPackageName();
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ public boolean sendPacketToRouterService(SdlPacket packet) { //We use ints because that is all that is supported by the outputstream class
+ //Log.d(TAG,whereToReply + "Sending packet to router service");
+
+ if (routerServiceMessenger == null) {
+ Log.d(TAG, whereToReply + " tried to send packet, but no where to send");
+ return false;
+ }
+ if (packet == null
+ //|| offset<0
+ //|| count<0
+ ) {//|| count>(bytes.length-offset)){
+ Log.w(TAG, whereToReply + "incorrect params supplied");
+ return false;
+ }
+ byte[] bytes = packet.constructPacket();
+ if (bytes.length < ByteArrayMessageSpliter.MAX_BINDER_SIZE) {//Determine if this is under the packet length.
+ Message message = Message.obtain(); //Do we need to always obtain new? or can we just swap bundles?
+ message.what = TransportConstants.ROUTER_SEND_PACKET;
+ Bundle bundle = new Bundle();
+ if (routerServiceVersion < TransportConstants.RouterServiceVersions.APPID_STRING) {
+ bundle.putLong(TransportConstants.APP_ID_EXTRA, convertAppId(appId));
+ }
+ bundle.putString(TransportConstants.APP_ID_EXTRA_STRING, appId);
+ bundle.putByteArray(TransportConstants.BYTES_TO_SEND_EXTRA_NAME, bytes); //Do we just change this to the args and objs
+ bundle.putInt(TransportConstants.BYTES_TO_SEND_EXTRA_OFFSET, 0);
+ bundle.putInt(TransportConstants.BYTES_TO_SEND_EXTRA_COUNT, bytes.length);
+ bundle.putInt(TransportConstants.BYTES_TO_SEND_FLAGS, TransportConstants.BYTES_TO_SEND_FLAG_NONE);
+ bundle.putInt(TransportConstants.PACKET_PRIORITY_COEFFICIENT, packet.getPrioirtyCoefficient());
+ if (packet.getTransportRecord() != null) {
+ //Log.d(TAG, "Sending packet on transport " + packet.getTransportType().name());
+ TransportRecord record = packet.getTransportRecord();
+ bundle.putString(TransportConstants.TRANSPORT_TYPE, record.getType().name());
+ bundle.putString(TransportConstants.TRANSPORT_ADDRESS, record.getAddress());
+ } else {
+ //Log.d(TAG, "No transport to be found");
+ }
+ message.setData(bundle);
+
+ sendMessageToRouterService(message);
+ return true;
+ } else { //Message is too big for IPC transaction
+ //Log.w(TAG, "Message too big for single IPC transaction. Breaking apart. Size - " + bytes.length);
+ ByteArrayMessageSpliter splitter = new ByteArrayMessageSpliter(appId, TransportConstants.ROUTER_SEND_PACKET, bytes, packet.getPrioirtyCoefficient());
+ splitter.setRouterServiceVersion(routerServiceVersion);
+ splitter.setTransportRecord(packet.getTransportRecord());
+ while (splitter.isActive()) {
+ sendMessageToRouterService(splitter.nextMessage());
+ }
+ return splitter.close();
+ }
+
+ }
+
+ /**
+ * This registers this service with the router service
+ */
+ private boolean registerWithRouterService() {
+ if (getContext() == null) {
+ Log.e(TAG, "Context set to null, failing out");
+ return false;
+ }
+
+ if (routerServiceMessenger != null) {
+ Log.w(TAG, "Already registered with router service");
+ return false;
+ }
+ //Make sure we know where to bind to
+ if (this.routerService == null) {
+ if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.O) && !isRouterServiceRunning(getContext())) {//We should be able to ignore this case because of the validation now
+ Log.d(TAG, whereToReply + " found no router service. Shutting down.");
+ this.onHardwareDisconnected(null);
+ return false;
+ }
+ } else {//We were already told where to bind. This should be the case.
+ this.routerClassName = this.routerService.getClassName();
+ this.routerPackage = this.routerService.getPackageName();
+ }
+
+ if (!sendBindingIntent()) {
+ Log.e(TAG, "Something went wrong while trying to bind with the router service.");
+ SdlBroadcastReceiver.queryForConnectedService(currentContext);
+ return false;
+ }
+ return true;
+
+ }
+
+ @SuppressLint("InlinedApi")
+ private boolean sendBindingIntent() {
+ if (this.routerPackage != null && this.routerClassName != null) {
+ Log.d(TAG, "Sending bind request to " + this.routerPackage + " - " + this.routerClassName);
+ Intent bindingIntent = new Intent();
+ bindingIntent.setClassName(this.routerPackage, this.routerClassName);//This sets an explicit intent
+ //Quickly make sure it's just up and running
+ getContext().startService(bindingIntent);
+ bindingIntent.setAction(TransportConstants.BIND_REQUEST_TYPE_CLIENT);
+ return getContext().bindService(bindingIntent, routerConnection, Context.BIND_AUTO_CREATE);
+ } else {
+ return false;
+ }
+ }
+
+ private void sendRegistrationMessage() {
+ Message msg = Message.obtain();
+ msg.what = TransportConstants.ROUTER_REGISTER_CLIENT;
+ msg.replyTo = this.clientMessenger;
+ Bundle bundle = new Bundle();
+ bundle.putLong(TransportConstants.APP_ID_EXTRA, convertAppId(appId)); //We send this no matter what due to us not knowing what router version we are connecting to
+ bundle.putString(TransportConstants.APP_ID_EXTRA_STRING, appId);
+ bundle.putInt(TransportConstants.ROUTER_MESSAGING_VERSION, messagingVersion);
+ msg.setData(bundle);
+ sendMessageToRouterService(msg);
+ }
+
+ private void unregisterWithRouterService() {
+ Log.i(TAG, "Attempting to unregister with Sdl Router Service");
+ if (isBound && routerServiceMessenger != null) {
+ Message msg = Message.obtain();
+ msg.what = TransportConstants.ROUTER_UNREGISTER_CLIENT;
+ msg.replyTo = this.clientMessenger; //Including this in case this app isn't actually registered with the router service
+ Bundle bundle = new Bundle();
+ if (routerServiceVersion < TransportConstants.RouterServiceVersions.APPID_STRING) {
+ bundle.putLong(TransportConstants.APP_ID_EXTRA, convertAppId(appId));
+ }
+ bundle.putString(TransportConstants.APP_ID_EXTRA_STRING, appId);
+ msg.setData(bundle);
+ sendMessageToRouterService(msg);
+ } else {
+ Log.w(TAG, "Unable to unregister, not bound to router service");
+ }
+
+ routerServiceMessenger = null;
+ }
+
+ protected ComponentName getRouterService() {
+ return this.routerService;
+ }
+
+ /**
+ * Since it doesn't always make sense to add another service, use this method to get
+ * the appropriate context that the rest of this class is using.
+ *
+ * @return The currently used context for this class
+ */
+ private Context getContext() {
+ return currentContext;
+ }
+
+
+ public static Long convertAppId(String appId) {
+ if (appId == null) {
+ return -1L;
+ }
+ try {
+ return Long.valueOf(appId);
+ } catch (NumberFormatException e) {
+ return -1L;
+ }
+ }
+
+ /***************************************************************************************************************************************
+ *********************************************** LEGACY *******************************************************************************
+ ****************************************************************************************************************************************/
+ /*
+ * Due to old implementations of SDL/Applink, old versions can't support multiple sessions per RFCOMM channel.
+ * This causes a race condition in the router service where only the first app registered will be able to communicate with the
+ * head unit. With this additional code, the router service will:
+ * 1) Acknowledge it's connected to an old system
+ * 2) d/c its bluetooth
+ * 3) Send a message to all clients connected that legacy mode is enabled
+ * 4) Each client spins up their own bluetooth RFCOMM listening channel
+ * 5) Head unit will need to query apps again
+ * 6) HU should then connect to each app by their own RFCOMM channel bypassing the router service
+ * 7) When the phone is D/C from the head unit the router service will reset and tell clients legacy mode is now off
+ */
+
+ private static boolean legacyModeEnabled = false;
+ private static Object LEGACY_LOCK = new Object();
+
+ protected void enableLegacyMode(boolean enable) {
+ synchronized (LEGACY_LOCK) {
+ legacyModeEnabled = enable;
+ }
+ }
+
+ protected static boolean isLegacyModeEnabled() {
+ synchronized (LEGACY_LOCK) {
+ return legacyModeEnabled;
+ }
+
+ }
+
+ /***************************************************************************************************************************************
+ **************************************************** LEGACY END ***********************************************************************
+ ****************************************************************************************************************************************/
+
+ /**
+ * Use this method to let the router service know that you are requesting a new session from the head unit.
+ */
+ @Deprecated
+ public void requestNewSession() {
+ requestNewSession(null);
+ }
+
+ public void requestNewSession(TransportRecord transportRecord) {
+ Message msg = Message.obtain();
+ msg.what = TransportConstants.ROUTER_REQUEST_NEW_SESSION;
+ msg.replyTo = this.clientMessenger; //Including this in case this app isn't actually registered with the router service
+ Bundle bundle = new Bundle();
+ if (routerServiceVersion < TransportConstants.RouterServiceVersions.APPID_STRING) {
+ bundle.putLong(TransportConstants.APP_ID_EXTRA, convertAppId(appId));
+ }
+ bundle.putString(TransportConstants.APP_ID_EXTRA_STRING, appId);
+ if (transportRecord != null) {
+ bundle.putString(TransportConstants.TRANSPORT_TYPE, transportRecord.getType().name());
+ bundle.putString(TransportConstants.TRANSPORT_ADDRESS, transportRecord.getAddress());
+ }
+ msg.setData(bundle);
+ this.sendMessageToRouterService(msg);
+ }
+
+ /**
+ * Request secondary transport and communicate details to router service
+ *
+ * @param sessionId
+ * @param bundle
+ */
+ public void requestSecondaryTransportConnection(byte sessionId, Bundle bundle) {
+ Message msg = Message.obtain();
+ msg.what = TransportConstants.ROUTER_REQUEST_SECONDARY_TRANSPORT_CONNECTION;
+ msg.replyTo = this.clientMessenger;
+ if (bundle == null) {
+ bundle = new Bundle();
+ }
+ bundle.putByte(TransportConstants.SESSION_ID_EXTRA, sessionId);
+ msg.setData(bundle);
+ this.sendMessageToRouterService(msg);
+ }
+
+
+ public void removeSession(long sessionId) {
+ Message msg = Message.obtain();
+ msg.what = TransportConstants.ROUTER_REMOVE_SESSION;
+ msg.replyTo = this.clientMessenger; //Including this in case this app isn't actually registered with the router service
+ Bundle bundle = new Bundle();
+ if (routerServiceVersion < TransportConstants.RouterServiceVersions.APPID_STRING) {
+ bundle.putLong(TransportConstants.APP_ID_EXTRA, convertAppId(appId));
}
+ bundle.putString(TransportConstants.APP_ID_EXTRA_STRING, appId);
+ bundle.putLong(TransportConstants.SESSION_ID_EXTRA, sessionId);
+ msg.setData(bundle);
+ this.sendMessageToRouterService(msg);
}
-
-
-
- /***************************************************************************************************************************************
- *********************************************** Life Cycle **************************************************************
- ****************************************************************************************************************************************/
-
-
- @SuppressLint("SimpleDateFormat")
- public TransportBroker(Context context, String appId, ComponentName service){
- synchronized(INIT_LOCK){
- clientMessenger = new Messenger(new ClientHandler(this));
- initRouterConnection();
- //So the user should have set the AppId, lets define where the intents need to be sent
- SimpleDateFormat s = new SimpleDateFormat("hhmmssss"); //So we have a time stamp of the event
- String timeStamp = s.format(new Date(System.currentTimeMillis()));
- if(whereToReply==null){
- if(appId==null){ //This should really just throw an error
- whereToReply = WHERE_TO_REPLY_PREFIX + "."+ timeStamp;
- }else{
- whereToReply = WHERE_TO_REPLY_PREFIX + appId +"."+ timeStamp;
- }
- }
- this.appId = appId.concat(timeStamp);
- queuedOnTransportConnect = null;
- currentContext = context;
- //Log.d(TAG, "Registering our reply receiver: " + whereToReply);
- this.routerService = service;
- }
- }
-
- /**
- * This beings the initial connection with the router service.
- */
- public boolean start(){
- //Log.d(TAG, "Starting up transport broker for " + whereToReply);
- synchronized(INIT_LOCK){
- if(currentContext==null){
- throw new IllegalStateException("This instance can't be started since it's local reference of context is null. Ensure when suppling a context to the TransportBroker that it is valid");
- }
- if(routerConnection==null){
- initRouterConnection();
- }
- //Log.d(TAG, "Registering our reply receiver: " + whereToReply);
- if(!isBound){
- return registerWithRouterService();
- }else{
- return false;
- }
- }
- }
-
- public void resetSession(){
- synchronized(INIT_LOCK){
- unregisterWithRouterService();
- routerServiceMessenger = null;
- queuedOnTransportConnect = null;
- unBindFromRouterService();
- }
- }
- /**
- * This method will end our communication with the router service.
- */
- public void stop(){
- //Log.d(TAG, "STOPPING transport broker for " + whereToReply);
- synchronized(INIT_LOCK){
- unregisterWithRouterService();
- unBindFromRouterService();
- routerServiceMessenger = null;
- queuedOnTransportConnect = null;
- currentContext = null;
-
- }
- }
-
- private void unBindFromRouterService(){
- try{
- if(getContext()!=null && routerConnection!=null){
- getContext().unbindService(routerConnection);
- }else{
- Log.w(TAG, "Unable to unbind from router service, context was null");
- }
-
- }catch(IllegalArgumentException e){
- //This is ok
- }
- }
- /***************************************************************************************************************************************
- *********************************************** Event Callbacks **************************************************************
- ****************************************************************************************************************************************/
-
-
- public void onServiceUnregsiteredFromRouterService(int unregisterCode){
- queuedOnTransportConnect = null;
- }
-
- public void onHardwareDisconnected(TransportType type){
- synchronized(INIT_LOCK){
- unBindFromRouterService();
- routerServiceMessenger = null;
- routerConnection = null;
- queuedOnTransportConnect = null;
- }
- }
-
- public boolean onHardwareConnected(TransportType type){
- synchronized(INIT_LOCK){
- if(routerServiceMessenger==null){
- queuedOnTransportConnect = type;
- return false;
- }
- return true;
- }
-
- }
-
- public void onPacketReceived(Parcelable packet){
-
- }
-
- public void onLegacyModeEnabled(){
-
- }
-
- /**
- * We want to check to see if the Router service is already up and running
- * @param context
- * @return
- */
- private boolean isRouterServiceRunning(Context context){
- if(context==null){
-
- return false;
- }
- ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
- for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
- //We will check to see if it contains this name, should be pretty specific
- if ((service.service.getClassName()).toLowerCase(Locale.US).contains(SdlBroadcastReceiver.SDL_ROUTER_SERVICE_CLASS_NAME)) {
- this.routerClassName = service.service.getClassName();
- this.routerPackage = service.service.getPackageName();
- return true;
- }
- }
- return false;
- }
-
-
- public boolean sendPacketToRouterService(SdlPacket packet){ //We use ints because that is all that is supported by the outputstream class
- //Log.d(TAG,whereToReply + "Sending packet to router service");
-
- if(routerServiceMessenger==null){
- Log.d(TAG,whereToReply + " tried to send packet, but no where to send");
- return false;
- }
- if(packet == null
- //|| offset<0
- //|| count<0
- ){//|| count>(bytes.length-offset)){
- Log.w(TAG,whereToReply + "incorrect params supplied");
- return false;
- }
- byte[] bytes = packet.constructPacket();
- if(bytes.length<ByteArrayMessageSpliter.MAX_BINDER_SIZE){//Determine if this is under the packet length.
- Message message = Message.obtain(); //Do we need to always obtain new? or can we just swap bundles?
- message.what = TransportConstants.ROUTER_SEND_PACKET;
- Bundle bundle = new Bundle();
- if(routerServiceVersion< TransportConstants.RouterServiceVersions.APPID_STRING){
- bundle.putLong(TransportConstants.APP_ID_EXTRA,convertAppId(appId));
- }
- bundle.putString(TransportConstants.APP_ID_EXTRA_STRING, appId);
- bundle.putByteArray(TransportConstants.BYTES_TO_SEND_EXTRA_NAME, bytes); //Do we just change this to the args and objs
- bundle.putInt(TransportConstants.BYTES_TO_SEND_EXTRA_OFFSET, 0);
- bundle.putInt(TransportConstants.BYTES_TO_SEND_EXTRA_COUNT, bytes.length);
- bundle.putInt(TransportConstants.BYTES_TO_SEND_FLAGS, TransportConstants.BYTES_TO_SEND_FLAG_NONE);
- bundle.putInt(TransportConstants.PACKET_PRIORITY_COEFFICIENT, packet.getPrioirtyCoefficient());
- message.setData(bundle);
-
- sendMessageToRouterService(message);
- return true;
- }else{ //Message is too big for IPC transaction
- //Log.w(TAG, "Message too big for single IPC transaction. Breaking apart. Size - " + bytes.length);
- ByteArrayMessageSpliter splitter = new ByteArrayMessageSpliter(appId,TransportConstants.ROUTER_SEND_PACKET,bytes,packet.getPrioirtyCoefficient() );
- splitter.setRouterServiceVersion(routerServiceVersion);
- while(splitter.isActive()){
- sendMessageToRouterService(splitter.nextMessage());
- }
- return splitter.close();
- }
-
- }
-
- /**
- * This registers this service with the router service
- */
- private boolean registerWithRouterService(){
- if(getContext()==null){
- Log.e(TAG, "Context set to null, failing out");
- return false;
- }
-
- if(routerServiceMessenger!=null){
- Log.w(TAG, "Already registered with router service");
- return false;
- }
- //Make sure we know where to bind to
- if(this.routerService==null){
- if((Build.VERSION.SDK_INT < Build.VERSION_CODES.O) && !isRouterServiceRunning(getContext())){//We should be able to ignore this case because of the validation now
- Log.d(TAG,whereToReply + " found no router service. Shutting down.");
- this.onHardwareDisconnected(null);
- return false;
- }
- }else{//We were already told where to bind. This should be the case.
- this.routerClassName = this.routerService.getClassName();
- this.routerPackage = this.routerService.getPackageName();
- }
-
- if(!sendBindingIntent()){
- Log.e(TAG, "Something went wrong while trying to bind with the router service.");
- SdlBroadcastReceiver.queryForConnectedService(currentContext);
- return false;
- }
- return true;
-
- }
-
- @SuppressLint("InlinedApi")
- private boolean sendBindingIntent(){
- if(this.routerPackage !=null && this.routerClassName !=null){
- Log.d(TAG, "Sending bind request to " + this.routerPackage + " - " + this.routerClassName);
- Intent bindingIntent = new Intent();
- bindingIntent.setClassName(this.routerPackage, this.routerClassName);//This sets an explicit intent
- //Quickly make sure it's just up and running
- getContext().startService(bindingIntent);
- bindingIntent.setAction( TransportConstants.BIND_REQUEST_TYPE_CLIENT);
- return getContext().bindService(bindingIntent, routerConnection, Context.BIND_AUTO_CREATE);
- }else{
- return false;
- }
- }
-
- private void sendRegistrationMessage(){
- Message msg = Message.obtain();
- msg.what = TransportConstants.ROUTER_REGISTER_CLIENT;
- msg.replyTo = this.clientMessenger;
- Bundle bundle = new Bundle();
- bundle.putLong(TransportConstants.APP_ID_EXTRA,convertAppId(appId)); //We send this no matter what due to us not knowing what router version we are connecting to
- bundle.putString(TransportConstants.APP_ID_EXTRA_STRING, appId);
- msg.setData(bundle);
- sendMessageToRouterService(msg);
- }
-
- private void unregisterWithRouterService(){
- Log.i(TAG, "Attempting to unregister with Sdl Router Service");
- if(isBound && routerServiceMessenger!=null){
- Message msg = Message.obtain();
- msg.what = TransportConstants.ROUTER_UNREGISTER_CLIENT;
- msg.replyTo = this.clientMessenger; //Including this in case this app isn't actually registered with the router service
- Bundle bundle = new Bundle();
- if(routerServiceVersion< TransportConstants.RouterServiceVersions.APPID_STRING){
- bundle.putLong(TransportConstants.APP_ID_EXTRA,convertAppId(appId));
- }
- bundle.putString(TransportConstants.APP_ID_EXTRA_STRING, appId);
- msg.setData(bundle);
- sendMessageToRouterService(msg);
- }else{
- Log.w(TAG, "Unable to unregister, not bound to router service");
- }
-
- routerServiceMessenger = null;
- }
-
-
-
- /**
- * Since it doesn't always make sense to add another service, use this method to get
- * the appropriate context that the rest of this class is using.
- * @return The currently used context for this class
- */
- private Context getContext(){
- return currentContext;
- }
-
-
- public static Long convertAppId(String appId){
- if(appId == null){
- return -1L;
- }
- try{
- return Long.valueOf(appId);
- }catch(NumberFormatException e){
- return -1L;
- }
- }
- /***************************************************************************************************************************************
- *********************************************** LEGACY *******************************************************************************
- ****************************************************************************************************************************************/
- /*
- * Due to old implementations of SDL/Applink, old versions can't support multiple sessions per RFCOMM channel.
- * This causes a race condition in the router service where only the first app registered will be able to communicate with the
- * head unit. With this additional code, the router service will:
- * 1) Acknowledge it's connected to an old system
- * 2) d/c its bluetooth
- * 3) Send a message to all clients connected that legacy mode is enabled
- * 4) Each client spins up their own bluetooth RFCOMM listening channel
- * 5) Head unit will need to query apps again
- * 6) HU should then connect to each app by their own RFCOMM channel bypassing the router service
- * 7) When the phone is D/C from the head unit the router service will reset and tell clients legacy mode is now off
- */
-
- private static boolean legacyModeEnabled = false;
- private static Object LEGACY_LOCK = new Object();
-
- protected void enableLegacyMode(boolean enable){
- synchronized(LEGACY_LOCK){
- legacyModeEnabled = enable;
- }
- }
- protected static boolean isLegacyModeEnabled(){
- synchronized(LEGACY_LOCK){
- return legacyModeEnabled;
- }
-
- }
-
- /***************************************************************************************************************************************
- **************************************************** LEGACY END ***********************************************************************
- ****************************************************************************************************************************************/
-
- /**
- * Use this method to let the router service know that you are requesting a new session from the head unit.
- */
- public void requestNewSession(){
- Message msg = Message.obtain();
- msg.what = TransportConstants.ROUTER_REQUEST_NEW_SESSION;
- msg.replyTo = this.clientMessenger; //Including this in case this app isn't actually registered with the router service
- Bundle bundle = new Bundle();
- if(routerServiceVersion< TransportConstants.RouterServiceVersions.APPID_STRING){
- bundle.putLong(TransportConstants.APP_ID_EXTRA,convertAppId(appId));
- }
- bundle.putString(TransportConstants.APP_ID_EXTRA_STRING, appId);
- msg.setData(bundle);
- this.sendMessageToRouterService(msg);
- }
-
- public void removeSession(long sessionId){
- Message msg = Message.obtain();
- msg.what = TransportConstants.ROUTER_REMOVE_SESSION;
- msg.replyTo = this.clientMessenger; //Including this in case this app isn't actually registered with the router service
- Bundle bundle = new Bundle();
- if(routerServiceVersion< TransportConstants.RouterServiceVersions.APPID_STRING){
- bundle.putLong(TransportConstants.APP_ID_EXTRA,convertAppId(appId));
- }
- bundle.putString(TransportConstants.APP_ID_EXTRA_STRING, appId);
- bundle.putLong(TransportConstants.SESSION_ID_EXTRA, sessionId);
- msg.setData(bundle);
- this.sendMessageToRouterService(msg);
- }
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/TransportConstants.java b/sdl_android/src/main/java/com/smartdevicelink/transport/TransportConstants.java
index 5d86bc87b..a66651502 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/TransportConstants.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/TransportConstants.java
@@ -27,24 +27,30 @@ public class TransportConstants {
public static final String START_ROUTER_SERVICE_SDL_ENABLED_EXTRA = "sdl_enabled";
public static final String START_ROUTER_SERVICE_SDL_ENABLED_APP_PACKAGE = "package_name";
public static final String START_ROUTER_SERVICE_SDL_ENABLED_CMP_NAME = "component_name";
+ public static final String START_ROUTER_SERVICE_TRANSPORT_CONNECTED = "transport_connected"; //Extra for the transport that just connected
public static final String START_ROUTER_SERVICE_SDL_ENABLED_PING = "ping";
+ @Deprecated
public static final String FORCE_TRANSPORT_CONNECTED = "force_connect"; //This is legacy, do not refactor this.
public static final String ROUTER_SERVICE_VALIDATED = "router_service_validated";
-
+ @Deprecated
public static final String REPLY_TO_INTENT_EXTRA = "ReplyAddress";
public static final String CONNECT_AS_CLIENT_BOOLEAN_EXTRA = "connectAsClient";
public static final String PACKAGE_NAME_STRING = "package.name";
public static final String APP_ID_EXTRA = "app.id";//Sent as a Long. This is no longer used
public static final String APP_ID_EXTRA_STRING = "app.id.string";
+ public static final String ROUTER_MESSAGING_VERSION = "router.messaging.version";
public static final String SESSION_ID_EXTRA = "session.id";
public static final String ENABLE_LEGACY_MODE_EXTRA = "ENABLE_LEGACY_MODE_EXTRA";
-
+
+ @Deprecated
public static final String HARDWARE_DISCONNECTED = "hardware.disconect";
- public static final String HARDWARE_CONNECTED = "hardware.connected";
-
+ public static final String TRANSPORT_DISCONNECTED = "transport.disconect";
+ public static final String HARDWARE_CONNECTED = "hardware.connected";
+ public static final String CURRENT_HARDWARE_CONNECTED = "current.hardware.connected";
+
public static final String SEND_PACKET_TO_APP_LOCATION_EXTRA_NAME = "senderintent";
public static final String SEND_PACKET_TO_ROUTER_LOCATION_EXTRA_NAME = "routerintent";
@@ -52,6 +58,7 @@ public class TransportConstants {
public static final String BIND_REQUEST_TYPE_CLIENT = "BIND_REQUEST_TYPE_CLIENT";
public static final String BIND_REQUEST_TYPE_ALT_TRANSPORT = "BIND_REQUEST_TYPE_ALT_TRANSPORT";
public static final String BIND_REQUEST_TYPE_STATUS = "BIND_REQUEST_TYPE_STATUS";
+ public static final String BIND_REQUEST_TYPE_USB_PROVIDER = "BIND_REQUEST_TYPE_USB_PROVIDER";
public static final String PING_ROUTER_SERVICE_EXTRA = "ping.router.service";
@@ -73,10 +80,11 @@ public class TransportConstants {
}
- /**
+ /*
* Alt transport
*
*/
+
/**
* This will be the response when a hardware connect event comes through from an alt transport.
* This is because it only makes sense to register an alt transport when a connection is established with that
@@ -99,7 +107,7 @@ public class TransportConstants {
*/
public static final int ROUTER_SHUTTING_DOWN_REASON_NEWER_SERVICE = 0x00;
- /**
+ /*
* Router to Client binding service
*
*/
@@ -141,7 +149,9 @@ public class TransportConstants {
* attached to the message
*/
public static final int HARDWARE_CONNECTION_EVENT = 0x05;
-
+ public static final int HARDWARE_CONNECTION_EVENT_CONNECTED = 0x10;
+ public static final int HARDWARE_CONNECTION_EVENT_DISCONNECTED = 0x30;
+
public static final int ROUTER_REQUEST_BT_CLIENT_CONNECT = 0x10;
public static final int ROUTER_REQUEST_BT_CLIENT_CONNECT_RESPONSE = 0x11;
@@ -151,6 +161,10 @@ public class TransportConstants {
* A replyTo must be provided or else there won't be a response
*/
public static final int ROUTER_REQUEST_NEW_SESSION = 0x12;
+ //Request arguments
+ //See TRANSPORT_TYPE & TRANSPORT_ADDRESS
+
+
public static final int ROUTER_REQUEST_NEW_SESSION_RESPONSE = 0x13;
//Response arguments
public static final int ROUTER_REQUEST_NEW_SESSION_RESPONSE_SUCESS = 0x00;
@@ -173,9 +187,7 @@ public class TransportConstants {
* Command to have router service to send a packet
*/
public static final int ROUTER_SEND_PACKET = 0x20;
-
-
//response
/**
* Router has received a packet and sent it to the client
@@ -183,6 +195,11 @@ public class TransportConstants {
public static final int ROUTER_RECEIVED_PACKET = 0x26;
//response
+ /**
+ * Command to tell router service details of secondary transport
+ */
+ public static final int ROUTER_REQUEST_SECONDARY_TRANSPORT_CONNECTION = 0x30;
+
//BUNDLE EXTRAS
public static final String FORMED_PACKET_EXTRA_NAME = "packet";
@@ -193,7 +210,10 @@ public class TransportConstants {
public static final String BYTES_TO_SEND_FLAGS = "flags";
public static final String PACKET_PRIORITY_COEFFICIENT = "priority_coefficient";
-
+
+ public static final String TRANSPORT_TYPE = "transport_type";
+ public static final String TRANSPORT_ADDRESS = "transport_address";
+
public static final int BYTES_TO_SEND_FLAG_NONE = 0x00;
public static final int BYTES_TO_SEND_FLAG_SDL_PACKET_INCLUDED = 0x01;
public static final int BYTES_TO_SEND_FLAG_LARGE_PACKET_START = 0x02;
@@ -201,7 +221,7 @@ public class TransportConstants {
public static final int BYTES_TO_SEND_FLAG_LARGE_PACKET_END = 0x08;
public static final String CONNECTED_DEVICE_STRING_EXTRA_NAME = "devicestring";
-
+
public static final int PACKET_SENDING_ERROR_NOT_REGISTERED_APP = 0x00;
public static final int PACKET_SENDING_ERROR_NOT_CONNECTED = 0x01;
public static final int PACKET_SENDING_ERROR_UKNOWN = 0xFF;
@@ -220,7 +240,24 @@ public class TransportConstants {
public static final int ROUTER_STATUS_FLAG_TRIGGER_PING = 0x02;
+ /**
+ * Usb Transfer binder
+ */
-
+ public static final int USB_CONNECTED_WITH_DEVICE = 0x55;
+ public static final int ROUTER_USB_ACC_RECEIVED = 0x56;
+
+
+ /**
+ * Multiple-transports related constants
+ *
+ */
+ public static final String IAP_BLUETOOTH = "IAP_BLUETOOTH";
+ public static final String IAP_USB = "IAP_USB";
+ public static final String IAP_USB_HOST_MODE = "TCP_WIFI";
+ public static final String IAP_CARPLAY = "IAP_CARPLAY";
+ public static final String SPP_BLUETOOTH = "SPP_BLUETOOTH";
+ public static final String AOA_USB = "AOA_USB";
+ public static final String TCP_WIFI = "TCP_WIFI";
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java b/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java
new file mode 100644
index 000000000..38df218b2
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java
@@ -0,0 +1,381 @@
+/*
+ * 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 android.content.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcelable;
+import android.util.Log;
+
+import com.smartdevicelink.protocol.SdlPacket;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.transport.utl.TransportRecord;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+@SuppressWarnings("unused")
+public class TransportManager {
+ private static final String TAG = "TransportManager";
+
+ private final Object TRANSPORT_STATUS_LOCK;
+
+ TransportBrokerImpl transport;
+ final List<TransportRecord> transportStatus;
+ final TransportEventListener transportListener;
+
+ //Legacy Transport
+ MultiplexBluetoothTransport legacyBluetoothTransport;
+ LegacyBluetoothHandler legacyBluetoothHandler;
+
+
+ /**
+ * Managing transports
+ * List for status of all transports
+ * If transport is not connected. Request Router service connect to it. Get connected message
+ */
+
+ public TransportManager(MultiplexTransportConfig config, TransportEventListener listener){
+
+ this.transportListener = listener;
+ this.TRANSPORT_STATUS_LOCK = new Object();
+ synchronized (TRANSPORT_STATUS_LOCK){
+ this.transportStatus = new ArrayList<>();
+ }
+
+ if(config.service == null) {
+ config.service = SdlBroadcastReceiver.consumeQueuedRouterService();
+ }
+
+ RouterServiceValidator validator = new RouterServiceValidator(config);
+ if(validator.validate()){
+ transport = new TransportBrokerImpl(config.context, config.appId,config.service);
+ }else{
+ enterLegacyMode("Router service is not trusted. Entering legacy mode");
+ }
+ }
+
+ public void start(){
+ if(transport != null){
+ transport.start();
+ }else if(legacyBluetoothTransport != null){
+ legacyBluetoothTransport.start();
+ }
+ }
+
+ public void close(long sessionId){
+ if(transport != null) {
+ transport.removeSession(sessionId);
+ transport.stop();
+ }else if(legacyBluetoothTransport != null){
+ legacyBluetoothTransport.stop();
+ legacyBluetoothTransport = null;
+ }
+ }
+
+ /**
+ * 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
+ */
+ 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
+ */
+ 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;
+ }
+ }
+
+ /**
+ * Retrieves the currently connected transports
+ * @return the currently connected transports
+ */
+ public List<TransportRecord> getConnectedTransports(){
+ return this.transportStatus;
+ }
+
+ public boolean isHighBandwidthAvailable(){
+ synchronized (TRANSPORT_STATUS_LOCK) {
+ for (TransportRecord record : transportStatus) {
+ if (record.getType().equals(TransportType.USB)
+ || record.getType().equals(TransportType.TCP)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ public ComponentName getRouterService(){
+ if(transport != null) {
+ return transport.getRouterService();
+ }
+ return null;
+ }
+
+ public void sendPacket(SdlPacket packet){
+ if(transport !=null){
+ transport.sendPacketToRouterService(packet);
+ }else if(legacyBluetoothTransport != null){
+ byte[] data = packet.constructPacket();
+ legacyBluetoothTransport.write(data, 0, data.length);
+ }
+ }
+
+ public void requestNewSession(TransportRecord transportRecord){
+ if(transport != null){
+ transport.requestNewSession(transportRecord);
+ }else if(legacyBluetoothTransport != null){
+ Log.w(TAG, "Session requested for non-bluetooth transport while in legacy mode");
+ }
+ }
+
+ public void requestSecondaryTransportConnection(byte sessionId, Bundle params){
+ transport.requestSecondaryTransportConnection(sessionId, params);
+ }
+
+ protected class TransportBrokerImpl extends TransportBroker{
+
+ public TransportBrokerImpl(Context context, String appId, ComponentName routerService){
+ super(context,appId,routerService);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ @Deprecated
+ public boolean onHardwareConnected(TransportType transportType){
+ return false;
+ }
+
+ @Override
+ public boolean onHardwareConnected(List<TransportRecord> transports) {
+ super.onHardwareConnected(transports);
+ synchronized (TRANSPORT_STATUS_LOCK){
+ transportStatus.clear();
+ transportStatus.addAll(transports);
+ }
+ transportListener.onTransportConnected(transports);
+ return true;
+ }
+
+
+ @Override
+ public void onHardwareDisconnected(TransportRecord record, List<TransportRecord> connectedTransports) {
+ if(record != null){
+ Log.d(TAG, "Transport disconnected - " + record);
+ }else{
+ Log.d(TAG, "Transport disconnected");
+
+ }
+
+ synchronized (TRANSPORT_STATUS_LOCK){
+ TransportManager.this.transportStatus.remove(record);
+ //Might check connectedTransports vs transportStatus to ensure they are equal
+ }
+
+ if(isLegacyModeEnabled()
+ && record != null
+ && TransportType.BLUETOOTH.equals(record.getType()) //Make sure it's bluetooth that has be d/c
+ && legacyBluetoothTransport == null){ //Make sure we aren't already in legacy mode
+ //Legacy mode has been enabled so we need to cycle
+ enterLegacyMode("Router service has enabled legacy mode");
+ }else{
+ //Inform the transport listener that a transport has disconnected
+ transportListener.onTransportDisconnected("", record, connectedTransports);
+ }
+ }
+
+ @Override
+ public void onPacketReceived(Parcelable packet) {
+ if(packet!=null){
+ transportListener.onPacketReceived((SdlPacket)packet);
+ }
+ }
+ }
+
+ private synchronized void enterLegacyMode(final String info){
+ if(legacyBluetoothTransport != null && legacyBluetoothHandler != null){
+ return; //Already in legacy mode
+ }
+
+ if(transportListener.onLegacyModeEnabled(info)) {
+ if(Looper.myLooper() == null){
+ Looper.prepare();
+ }
+ legacyBluetoothHandler = new LegacyBluetoothHandler(this);
+ legacyBluetoothTransport = new MultiplexBluetoothTransport(legacyBluetoothHandler);
+ }else{
+ new Handler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ transportListener.onError(info + " - Legacy mode unacceptable; shutting down.");
+
+ }
+ },500);
+ }
+ }
+
+ protected synchronized void exitLegacyMode(String info ){
+ if(legacyBluetoothTransport != null){
+ legacyBluetoothTransport.stop();
+ legacyBluetoothTransport = null;
+ }
+ legacyBluetoothHandler = null;
+ synchronized (TRANSPORT_STATUS_LOCK){
+ TransportManager.this.transportStatus.clear();
+ }
+ transportListener.onTransportDisconnected(info, new TransportRecord(TransportType.BLUETOOTH,null),null);
+ }
+
+ public interface TransportEventListener{
+ /** Called to indicate and deliver a packet received from transport */
+ void onPacketReceived(SdlPacket packet);
+
+ /** Called to indicate that transport connection was established */
+ void onTransportConnected(List<TransportRecord> transports);
+
+ /** Called to indicate that transport was disconnected (by either side) */
+ void onTransportDisconnected(String info, TransportRecord type, List<TransportRecord> connectedTransports);
+
+ // Called when the transport manager experiences an unrecoverable failure
+ void onError(String info);
+ /**
+ * Called when the transport manager has determined it needs to move towards a legacy style
+ * transport connection. It will always be bluetooth.
+ * @param info simple info string about the situation
+ * @return if the listener is ok with entering legacy mode
+ */
+ boolean onLegacyModeEnabled(String info);
+ }
+
+
+
+ protected static class LegacyBluetoothHandler extends Handler{
+
+ final WeakReference<TransportManager> provider;
+
+ public LegacyBluetoothHandler(TransportManager provider){
+ this.provider = new WeakReference<>(provider);
+ }
+ @Override
+ public void handleMessage(Message msg) {
+ if(this.provider.get() == null){
+ return;
+ }
+ TransportManager service = this.provider.get();
+ if(service.transportListener == null){
+ return;
+ }
+ switch (msg.what) {
+ case SdlRouterService.MESSAGE_STATE_CHANGE:
+ switch (msg.arg1) {
+ case MultiplexBaseTransport.STATE_CONNECTED:
+ synchronized (service.TRANSPORT_STATUS_LOCK){
+ service.transportStatus.clear();
+ service.transportStatus.add(service.legacyBluetoothTransport.getTransportRecord());
+ }
+ service.transportListener.onTransportConnected(service.transportStatus);
+ break;
+ case MultiplexBaseTransport.STATE_CONNECTING:
+ // Currently attempting to connect - update UI?
+ break;
+ case MultiplexBaseTransport.STATE_LISTEN:
+ break;
+ case MultiplexBaseTransport.STATE_NONE:
+ // We've just lost the connection
+ service.exitLegacyMode("Lost connection");
+ break;
+ case MultiplexBaseTransport.STATE_ERROR:
+ Log.d(TAG, "Bluetooth serial server error received, setting state to none, and clearing local copy");
+ service.exitLegacyMode("Transport error");
+ break;
+ }
+ break;
+
+ case SdlRouterService.MESSAGE_READ:
+ service.transportListener.onPacketReceived((SdlPacket) msg.obj);
+ break;
+ }
+ }
+ }
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java b/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java
index e0e1c93f2..4b878c2aa 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/USBAccessoryAttachmentActivity.java
@@ -1,36 +1,80 @@
+/*
+ * 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 android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
-import android.content.pm.ResolveInfo;
+import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
+import android.os.Build;
import android.os.Bundle;
+import android.os.Parcelable;
+import android.support.annotation.RequiresApi;
import android.util.Log;
import com.smartdevicelink.util.AndroidTools;
+import com.smartdevicelink.util.DebugTool;
+import com.smartdevicelink.util.SdlAppInfo;
+import com.smartdevicelink.util.ServiceFinder;
import java.util.List;
+import java.util.Vector;
+
+import static com.smartdevicelink.transport.TransportConstants.FOREGROUND_EXTRA;
/**
* The USBAccessoryAttachmentActivity is a proxy to listen for
* USB_ACCESSORY_ATTACHED intents.
- *
+ * <br><br>
* Unfortunately, the USB_ACCESSORY_ATTACHED intent can only be sent to an
* activity. So this class is a workaround to get that intent.
- *
+ * <br><br>
* Some reference: http://stackoverflow.com/questions/6981736/android-3-1-usb-host-broadcastreceiver-does-not-receive-usb-device-attached/9814826#9814826
- *
+ * <br><br>
* Inspired by OpenXC-Android: https://github.com/openxc/openxc-android
- *
- * <strong>NOTA BENE:</strong> An application that wants to use USB transport
+ * <br><br>
+ * <strong>NOTE:</strong> An application that wants to use USB transport
* must make the following changes to AndroidManifest.xml:
- *
- * 1. add these lines to <manifest>…</manifest>:
+ * <br><br>
+ * <b>1.</b> Add these lines to the {@literal <manifest>…</manifest>} scope:<br>
+ * <pre>{@code
* <!-- Required to use the USB Accessory mode -->
* <uses-feature android:name="android.hardware.usb.accessory"/>
- *
- * 2. add these lines to <application>…</application>:
- * <activity android:name="com.smartdevicelink.transport.USBAccessoryAttachmentActivity">
+ * }</pre>
+ * <b>2.</b> Add these lines to the {@literal <application>…</application>} scope:
+ * <pre>{@code <activity android:name="com.smartdevicelink.transport.USBAccessoryAttachmentActivity">
* <intent-filter>
* <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"/>
* </intent-filter>
@@ -38,13 +82,18 @@ import java.util.List;
* android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
* android:resource="@xml/accessory_filter"/>
* </activity>
- *
- * 3. set minimum SDK version to 12:
- * <uses-sdk android:minSdkVersion="12"/>
+ * }</pre>
+ * <b>3.</b> Set minimum SDK version to 12:
+ * <pre>{@code <uses-sdk android:minSdkVersion="12"/>}</pre>
*/
+@RequiresApi(12)
public class USBAccessoryAttachmentActivity extends Activity {
- private static final String TAG =
- USBAccessoryAttachmentActivity.class.getSimpleName();
+
+ private static final String TAG = USBAccessoryAttachmentActivity.class.getSimpleName();
+ private static final int USB_SUPPORTED_ROUTER_SERVICE_VERSION = 8;
+
+ UsbAccessory usbAccessory;
+ Parcelable permissionGranted;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -64,20 +113,107 @@ public class USBAccessoryAttachmentActivity extends Activity {
Log.d(TAG, sourceAction + " with action: " + action);
if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {
- Intent usbAccessoryAttachedIntent =
- new Intent(USBTransport.ACTION_USB_ACCESSORY_ATTACHED);
- usbAccessoryAttachedIntent.putExtra(UsbManager.EXTRA_ACCESSORY,
- intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY));
- usbAccessoryAttachedIntent
- .putExtra(UsbManager.EXTRA_PERMISSION_GRANTED,
- intent.getParcelableExtra(
- UsbManager.EXTRA_PERMISSION_GRANTED));
-
+ usbAccessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ permissionGranted = intent.getParcelableExtra(UsbManager.EXTRA_PERMISSION_GRANTED);
- AndroidTools.sendExplicitBroadcast(getApplicationContext(),usbAccessoryAttachedIntent,null);
+ wakeUpRouterService(getApplicationContext());
}
+ }
+
+ @SuppressWarnings("deprecation")
+ private void wakeUpRouterService(final Context context){
+ new ServiceFinder(context, context.getPackageName(), new ServiceFinder.ServiceFinderCallback() {
+ @Override
+ public void onComplete(Vector<ComponentName> routerServices) {
+ Vector<ComponentName> runningBluetoothServicePackage = new Vector<>(routerServices);
+ if (runningBluetoothServicePackage.isEmpty()) {
+ //If there isn't a service running we should try to start one
+ //We will try to sort the SDL enabled apps and find the one that's been installed the longest
+ Intent serviceIntent;
+ List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator());
+
+ if (sdlAppInfoList != null && !sdlAppInfoList.isEmpty()) {
+ SdlAppInfo optimalRouterService = sdlAppInfoList.get(0);
+
+ if(optimalRouterService.getRouterServiceVersion() < USB_SUPPORTED_ROUTER_SERVICE_VERSION){
+ // The most optimal router service doesn't support the USB connection
+ // At this point to ensure that USB connection is still possible it might be
+ // worth trying to use the legacy USB transport scheme
+ attemptLegacyUsbConnection();
+ return;
+ }
+
+ serviceIntent = new Intent();
+ serviceIntent.setComponent(optimalRouterService.getRouterServiceComponentName());
+ } else{
+ Log.d(TAG, "No SDL Router Services found");
+ Log.d(TAG, "WARNING: This application has not specified its SdlRouterService correctly in the manifest. THIS WILL THROW AN EXCEPTION IN FUTURE RELEASES!!");
+ // At this point to ensure that USB connection is still possible it might be
+ // worth trying to use the legacy USB transport scheme
+ attemptLegacyUsbConnection();
+ return;
+ }
+ serviceIntent.setAction(TransportConstants.BIND_REQUEST_TYPE_ALT_TRANSPORT);
+
+ ComponentName startedService;
+ try {
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+ startedService = context.startService(serviceIntent);
+ }else {
+ serviceIntent.putExtra(FOREGROUND_EXTRA, true);
+ startedService = context.startForegroundService(serviceIntent);
+ }
+
+ if(startedService == null){
+ // A router service was not started or is not running.
+ DebugTool.logError(TAG + " - Error starting router service. Attempting legacy connection ");
+ attemptLegacyUsbConnection();
+ return;
+ }
+
+ //Make sure to send this out for old apps to close down
+ SdlRouterService.LocalRouterService self = SdlRouterService.getLocalRouterService(serviceIntent, serviceIntent.getComponent());
+ Intent restart = new Intent(SdlRouterService.REGISTER_NEWER_SERVER_INSTANCE_ACTION);
+ restart.putExtra(SdlBroadcastReceiver.LOCAL_ROUTER_SERVICE_EXTRA, self);
+ restart.putExtra(SdlBroadcastReceiver.LOCAL_ROUTER_SERVICE_DID_START_OWN, true);
+ context.sendBroadcast(restart);
+
+ if (usbAccessory!=null) {
+ new UsbTransferProvider(context, serviceIntent.getComponent(), usbAccessory, new UsbTransferProvider.UsbTransferCallback() {
+ @Override
+ public void onUsbTransferUpdate(boolean success) {
+ finish();
+ }
+ });
+
+ }
+
+ } catch (SecurityException e) {
+ Log.e(TAG, "Security exception, process is bad");
+ }
+ } else {
+ if (usbAccessory!=null) {
+ new UsbTransferProvider(context,runningBluetoothServicePackage.get(0),usbAccessory, new UsbTransferProvider.UsbTransferCallback(){
+ @Override
+ public void onUsbTransferUpdate(boolean success) {
+ finish();
+ }
+ });
+
+ }
+ }
+ }
+ });
+ }
+
+ private void attemptLegacyUsbConnection(){
+ DebugTool.logInfo("Attempting to send USB connection intent using legacy method");
+ Intent usbAccessoryAttachedIntent = new Intent(USBTransport.ACTION_USB_ACCESSORY_ATTACHED);
+ usbAccessoryAttachedIntent.putExtra(UsbManager.EXTRA_ACCESSORY, usbAccessory);
+ usbAccessoryAttachedIntent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, permissionGranted);
+ AndroidTools.sendExplicitBroadcast(getApplicationContext(),usbAccessoryAttachedIntent,null);
finish();
}
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/USBTransport.java b/sdl_android/src/main/java/com/smartdevicelink/transport/USBTransport.java
index 8a0d57294..9b1bf1efd 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/USBTransport.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/USBTransport.java
@@ -33,6 +33,7 @@ import com.smartdevicelink.util.DebugTool;
* some data is sent again or the USB is physically disconnected.
*/
@SuppressLint("NewApi")
+@Deprecated
public class USBTransport extends SdlTransport {
// Boolean to monitor if the transport is in a disconnecting state
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/USBTransportConfig.java b/sdl_android/src/main/java/com/smartdevicelink/transport/USBTransportConfig.java
index 4e82807cb..b819a6844 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/USBTransportConfig.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/USBTransportConfig.java
@@ -5,27 +5,78 @@ import com.smartdevicelink.transport.enums.TransportType;
import android.content.Context;
import android.hardware.usb.UsbAccessory;
+/**
+ * <b>NOTE: </b> This should no longer be used. See the MultplexTransportConfig and guides to
+ * understand how to implement USB multiplexing. This class and method of USB connection will be
+ * removed in the next major release. If a router service is available to handle multiplexing of the
+ * usb transport it will be used, and this app will connect to whatever router service hosts the USB
+ * connection.
+ * @see MultiplexTransportConfig
+ */
+@Deprecated
public class USBTransportConfig extends BaseTransportConfig {
private Context mainActivity = null;
private UsbAccessory usbAccessory = null;
private Boolean queryUsbAcc = true;
-
+
+ /**
+ * <b>NOTE: </b> This should no longer be used. See the MultplexTransportConfig and guides to
+ * understand how to implement USB multiplexing. This class and method of USB connection will be
+ * removed in the next major release. If a router service is available to handle multiplexing of the
+ * usb transport it will be used, and this app will connect to whatever router service hosts the USB
+ * connection.
+ * @param mainActivity context used to start USB transport
+ * @see MultiplexTransportConfig
+ */
public USBTransportConfig (Context mainActivity) {
this.mainActivity = mainActivity;
}
-
+
+ /**
+ * <b>NOTE: </b> This should no longer be used. See the MultplexTransportConfig and guides to
+ * understand how to implement USB multiplexing. This class and method of USB connection will be
+ * removed in the next major release. If a router service is available to handle multiplexing of the
+ * usb transport it will be used, and this app will connect to whatever router service hosts the USB
+ * connection.
+ * @param mainActivity context used to start USB transport
+ * @param usbAccessory the accessory that was given to this app
+ * @see MultiplexTransportConfig
+ */
public USBTransportConfig (Context mainActivity, UsbAccessory usbAccessory) {
this.mainActivity = mainActivity;
this.usbAccessory = usbAccessory;
}
-
+
+ /**
+ * <b>NOTE: </b> This should no longer be used. See the MultplexTransportConfig and guides to
+ * understand how to implement USB multiplexing. This class and method of USB connection will be
+ * removed in the next major release. If a router service is available to handle multiplexing of the
+ * usb transport it will be used, and this app will connect to whatever router service hosts the USB
+ * connection.
+ * @param mainActivity context used to start USB transport
+ * @param shareConnection enable other sessions on this app to use this USB connection
+ * @param queryUsbAcc attempt to query the USB accessory if none is provided
+ * @see MultiplexTransportConfig
+ */
public USBTransportConfig (Context mainActivity, boolean shareConnection, boolean queryUsbAcc) {
this.mainActivity = mainActivity;
this.queryUsbAcc = queryUsbAcc;
super.shareConnection = shareConnection;
}
-
+
+ /**
+ * <b>NOTE: </b> This should no longer be used. See the MultplexTransportConfig and guides to
+ * understand how to implement USB multiplexing. This class and method of USB connection will be
+ * removed in the next major release. If a router service is available to handle multiplexing of the
+ * usb transport it will be used, and this app will connect to whatever router service hosts the USB
+ * connection.
+ * @param mainActivity context used to start USB transport
+ * @param usbAccessory the accessory that was given to this app
+ * @param shareConnection enable other sessions on this app to use this USB connection
+ * @param queryUsbAcc attempt to query the USB accessory if none is provided
+ * @see MultiplexTransportConfig
+ */
public USBTransportConfig (Context mainActivity, UsbAccessory usbAccessory, boolean shareConnection, boolean queryUsbAcc) {
this.mainActivity = mainActivity;
this.queryUsbAcc = queryUsbAcc;
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/UsbTransferProvider.java b/sdl_android/src/main/java/com/smartdevicelink/transport/UsbTransferProvider.java
new file mode 100644
index 000000000..9657a2c27
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/UsbTransferProvider.java
@@ -0,0 +1,220 @@
+/*
+ * 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 android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.smartdevicelink.util.AndroidTools;
+import java.lang.ref.WeakReference;
+
+@TargetApi(12)
+public class UsbTransferProvider {
+ private static final String TAG = "UsbTransferProvider";
+
+ private Context context ;
+ private boolean isBound = false;
+ private ComponentName routerService;
+ private int flags = 0;
+
+ final Messenger clientMessenger;
+
+ UsbTransferCallback callback;
+ Messenger routerServiceMessenger = null;
+ ParcelFileDescriptor usbPfd;
+ Bundle usbInfoBundle;
+
+ private ServiceConnection routerConnection= new ServiceConnection() {
+
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "Bound to service " + className.toString());
+ routerServiceMessenger = new Messenger(service);
+ isBound = true;
+ //So we just established our connection
+ //Register with router service
+ Message msg = Message.obtain();
+ msg.what = TransportConstants.USB_CONNECTED_WITH_DEVICE;
+ msg.arg1 = flags;
+ msg.replyTo = clientMessenger;
+ msg.obj = usbPfd;
+ if(usbInfoBundle != null){
+ msg.setData(usbInfoBundle);
+ }
+ try {
+ routerServiceMessenger.send(msg);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ Log.d(TAG, "UN-Bound from service " + className.getClassName());
+ routerServiceMessenger = null;
+ isBound = false;
+ }
+ };
+
+ public UsbTransferProvider(Context context, ComponentName service, UsbAccessory usbAccessory, UsbTransferCallback callback){
+ if(context == null || service == null || usbAccessory == null){
+ throw new IllegalStateException("Supplied params are not correct. Context == null? "+ (context==null) + " ComponentName == null? " + (service == null) + " Usb Accessory == null? " + usbAccessory);
+ }
+ this.context = context;
+ this.routerService = service;
+ this.callback = callback;
+ this.clientMessenger = new Messenger(new ClientHandler(this));
+ usbPfd = getFileDescriptor(usbAccessory);
+ if(usbPfd != null){
+ usbInfoBundle = new Bundle();
+ usbInfoBundle.putString(MultiplexUsbTransport.MANUFACTURER, usbAccessory.getManufacturer());
+ usbInfoBundle.putString(MultiplexUsbTransport.MODEL, usbAccessory.getModel());
+ usbInfoBundle.putString(MultiplexUsbTransport.VERSION, usbAccessory.getVersion());
+ usbInfoBundle.putString(MultiplexUsbTransport.URI, usbAccessory.getUri());
+ usbInfoBundle.putString(MultiplexUsbTransport.SERIAL, usbAccessory.getSerial());
+ usbInfoBundle.putString(MultiplexUsbTransport.DESCRIPTION, usbAccessory.getDescription());
+ checkIsConnected();
+ }
+
+ }
+
+ @SuppressLint("NewApi")
+ private ParcelFileDescriptor getFileDescriptor(UsbAccessory accessory) {
+ try {
+ UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
+
+ if (manager != null) {
+ return manager.openAccessory(accessory);
+ }
+ }catch (Exception e){}
+
+ return null;
+ }
+
+ public void setFlags(int flags){
+ this.flags = flags;
+ }
+
+ public void checkIsConnected(){
+ if(!AndroidTools.isServiceExported(context,routerService) || !bindToService()){
+ //We are unable to bind to service
+ Log.e(TAG, "Unable to bind to service");
+ unBindFromService();
+ }
+ }
+
+ public void cancel(){
+ if(isBound){
+ unBindFromService();
+ }
+ }
+
+ private boolean bindToService(){
+ if(isBound){
+ return true;
+ }
+ if(clientMessenger == null){
+ return false;
+ }
+ Intent bindingIntent = new Intent();
+ bindingIntent.setClassName(this.routerService.getPackageName(), this.routerService.getClassName());//This sets an explicit intent
+ //Quickly make sure it's just up and running
+ context.startService(bindingIntent);
+ bindingIntent.setAction( TransportConstants.BIND_REQUEST_TYPE_USB_PROVIDER);
+ return context.bindService(bindingIntent, routerConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ private void unBindFromService(){
+ try{
+ if(context!=null && routerConnection!=null){
+ context.unbindService(routerConnection);
+ }else{
+ Log.w(TAG, "Unable to unbind from router service, context was null");
+ }
+
+ }catch(IllegalArgumentException e){
+ //This is ok
+ }
+ }
+
+ private void finish(){
+ if(callback != null){
+ callback.onUsbTransferUpdate(true);
+ }
+ unBindFromService();
+ routerServiceMessenger =null;
+ }
+
+ static class ClientHandler extends Handler {
+ final WeakReference<UsbTransferProvider> provider;
+
+ public ClientHandler(UsbTransferProvider provider){
+ super(Looper.getMainLooper());
+ this.provider = new WeakReference<UsbTransferProvider>(provider);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if(provider.get()==null){
+ return;
+ }
+ switch (msg.what) {
+ case TransportConstants.ROUTER_USB_ACC_RECEIVED:
+ Log.d(TAG, "Successful USB transfer");
+ provider.get().finish();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ public interface UsbTransferCallback{
+ void onUsbTransferUpdate(boolean success);
+ }
+
+
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/enums/TransportType.java b/sdl_android/src/main/java/com/smartdevicelink/transport/enums/TransportType.java
index ac4a75b7d..2c09c72fc 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/enums/TransportType.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/enums/TransportType.java
@@ -5,7 +5,7 @@ package com.smartdevicelink.transport.enums;
*/
public enum TransportType {
/**
- * Experimental multiplexing (only supports bluetooth at the moment)
+ * Transport type will be anything the multiplexing service connects to.
*/
MULTIPLEX,
/**
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/utl/ByteAraryMessageAssembler.java b/sdl_android/src/main/java/com/smartdevicelink/transport/utl/ByteAraryMessageAssembler.java
index 98b8b666e..61fd2e13e 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/utl/ByteAraryMessageAssembler.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/utl/ByteAraryMessageAssembler.java
@@ -6,18 +6,29 @@ import java.io.IOException;
import android.util.Log;
import com.smartdevicelink.transport.TransportConstants;
+import com.smartdevicelink.transport.enums.TransportType;
public class ByteAraryMessageAssembler {
private static final String TAG = "ByteAraryMessageAssembler";
ByteArrayOutputStream buffer;
boolean isFinished;
-
+ TransportType transportType;
+
+
public void init(){
close();
this.isFinished = false;
buffer = new ByteArrayOutputStream();
}
-
+
+ public void setTransportType(TransportType transportType){
+ this.transportType = transportType;
+ }
+
+ public TransportType getTransportType() {
+ return transportType;
+ }
+
public boolean close(){
if(buffer!=null){
try {
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/utl/ByteArrayMessageSpliter.java b/sdl_android/src/main/java/com/smartdevicelink/transport/utl/ByteArrayMessageSpliter.java
index 6957d2b8a..999fdacb3 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/transport/utl/ByteArrayMessageSpliter.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/utl/ByteArrayMessageSpliter.java
@@ -5,6 +5,7 @@ import java.io.IOException;
import com.smartdevicelink.transport.TransportBroker;
import com.smartdevicelink.transport.TransportConstants;
+import com.smartdevicelink.transport.enums.TransportType;
import android.os.Bundle;
import android.os.Message;
@@ -25,6 +26,7 @@ public class ByteArrayMessageSpliter {
int orginalSize;
int priorityCoef;
int routerServiceVersion = 1;
+ TransportRecord transportRecord;
public ByteArrayMessageSpliter(String appId,int what, byte[] bytes, int priorityCoef){
this.appId = appId;
@@ -51,6 +53,10 @@ public class ByteArrayMessageSpliter {
this.routerServiceVersion = version;
}
+ public void setTransportRecord(TransportRecord transportRecord){
+ this.transportRecord = transportRecord;
+ }
+
public boolean isActive(){
if(stream!=null){
return stream.available()>0;
@@ -94,7 +100,11 @@ public class ByteArrayMessageSpliter {
bundle.putByteArray(TransportConstants.BYTES_TO_SEND_EXTRA_NAME, buffer); //Do we just change this to the args and objs
bundle.putInt(TransportConstants.BYTES_TO_SEND_EXTRA_OFFSET, 0);
bundle.putInt(TransportConstants.BYTES_TO_SEND_EXTRA_COUNT, bytesRead);
-
+ if(transportRecord != null){
+ bundle.putString(TransportConstants.TRANSPORT_TYPE, transportRecord.getType().name());
+ bundle.putString(TransportConstants.TRANSPORT_ADDRESS, transportRecord.getAddress());
+ }
+
//Determine which flag should be sent for this division of the packet
if(firstPacket){
bundle.putInt(TransportConstants.BYTES_TO_SEND_FLAGS, TransportConstants.BYTES_TO_SEND_FLAG_LARGE_PACKET_START);
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/utl/TransportRecord.java b/sdl_android/src/main/java/com/smartdevicelink/transport/utl/TransportRecord.java
new file mode 100644
index 000000000..bcfc2e373
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/utl/TransportRecord.java
@@ -0,0 +1,126 @@
+/*
+ * 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.utl;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.smartdevicelink.transport.enums.TransportType;
+
+public class TransportRecord implements Parcelable{
+
+ private TransportType type;
+ private String address;
+
+ public TransportRecord(TransportType transportType, String address){
+ this.type = transportType;
+ this.address = address;
+ }
+
+ public TransportType getType() {
+ return type;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if(obj == null) {
+ return false;
+ }
+
+ if (obj instanceof TransportRecord) {
+ TransportRecord record = (TransportRecord) obj;
+ return record.type != null && record.type.equals(type) //Transport type is the same
+ && ((record.address == null && address == null) //Both addresses are null
+ || (record.address != null && record.address.equals(address))); //Or they match
+ }
+
+ return super.equals(obj);
+ }
+
+ @Override
+ public String toString(){
+ StringBuilder builder = new StringBuilder();
+ builder.append("Transport Type: ");
+ builder.append(type.name());
+ builder.append(" Address: ");
+ builder.append(address);
+ return builder.toString();
+ }
+
+ public TransportRecord(Parcel p){
+ if (p.readInt() == 1) { //We should have a transport type attached
+ String transportName = p.readString();
+ if(transportName != null){
+ this.type = TransportType.valueOf(transportName);
+ }
+ }
+
+ if (p.readInt() == 1) { //We should have a transport address attached
+ address = p.readString();
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(type!=null? 1 : 0);
+ if(type != null){
+ dest.writeString(type.name());
+ }
+
+ dest.writeInt(address !=null? 1 : 0);
+ if(address != null){
+ dest.writeString(address);
+ }
+ }
+
+ public static final Parcelable.Creator<TransportRecord> CREATOR = new Parcelable.Creator<TransportRecord>() {
+ public TransportRecord createFromParcel(Parcel in) {
+ return new TransportRecord(in);
+ }
+
+ @Override
+ public TransportRecord[] newArray(int size) {
+ return new TransportRecord[size];
+ }
+
+ };
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/utl/WiFiSocketFactory.java b/sdl_android/src/main/java/com/smartdevicelink/transport/utl/WiFiSocketFactory.java
new file mode 100644
index 000000000..b35070d89
--- /dev/null
+++ b/sdl_android/src/main/java/com/smartdevicelink/transport/utl/WiFiSocketFactory.java
@@ -0,0 +1,96 @@
+package com.smartdevicelink.transport.utl;
+
+import android.Manifest;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.os.Build;
+
+import java.io.IOException;
+import java.net.Socket;
+
+import javax.net.SocketFactory;
+
+import static com.smartdevicelink.util.NativeLogTool.logInfo;
+
+public class WiFiSocketFactory {
+ /**
+ * Try to create a TCP socket which is bound to Wi-Fi network (for Android 5+)
+ *
+ * On Android 5 and later, this method tries to create a Socket instance which is bound to a
+ * Wi-Fi network. If the phone is not connected to a Wi-Fi network, or the app lacks
+ * required permission (ACCESS_NETWORK_STATE), then this method simply creates a Socket instance
+ * with "new Socket();".
+ *
+ * @return a Socket instance, preferably bound to a Wi-Fi network
+ */
+ public static Socket createSocket(Context context) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ Socket socket = createWiFiSocket(context);
+ if (socket != null) {
+ logInfo("Created a Socket bound to Wi-Fi network");
+ return socket;
+ }
+ }
+
+ return new Socket();
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private static Socket createWiFiSocket(Context context) {
+ PackageManager pm = context.getPackageManager();
+ if (pm == null) {
+ logInfo("PackageManager isn't available.");
+ return null;
+ }
+ // getAllNetworks() and getNetworkCapabilities() require ACCESS_NETWORK_STATE
+ if (pm.checkPermission(Manifest.permission.ACCESS_NETWORK_STATE, context.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
+ logInfo("Router service doesn't have ACCESS_NETWORK_STATE permission. It cannot bind a TCP transport to Wi-Fi network.");
+ return null;
+ }
+
+ ConnectivityManager connMan = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (connMan == null) {
+ logInfo("ConnectivityManager isn't available.");
+ return null;
+ }
+
+ Network[] allNetworks = connMan.getAllNetworks();
+ if (allNetworks == null) {
+ logInfo("Failed to acquire a list of networks.");
+ return null;
+ }
+
+ // Samsung Galaxy S9 (with Android 8.0.0) provides two `Network` instances which have
+ // TRANSPORT_WIFI capability. The first one throws an IOException upon creating a Socket,
+ // and the second one actually works. To support such case, here we iterate over all
+ // `Network` instances until we can create a Socket.
+ for (Network network : allNetworks) {
+ if (network == null) {
+ continue;
+ }
+
+ NetworkCapabilities capabilities = connMan.getNetworkCapabilities(network);
+ if (capabilities == null) {
+ continue;
+ }
+
+ if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ try {
+ SocketFactory factory = network.getSocketFactory();
+ if (factory != null) {
+ return factory.createSocket();
+ }
+ } catch (IOException e) {
+ logInfo("IOException during socket creation (ignored): " + e.getMessage());
+ }
+ }
+ }
+
+ logInfo("Cannot find Wi-Fi network to bind a TCP transport.");
+ return null;
+ }
+}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java b/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
index 81ca436c7..62f379031 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
@@ -126,8 +126,8 @@ public class AndroidTools {
* Sends the provided intent to the specified destinations making it an explicit intent, rather
* than an implicit intent. A direct replacement of sendBroadcast(Intent). As of Android 8.0
* (API 26+) implicit broadcasts are no longer sent to broadcast receivers that are declared via
- * the AndroidManifest. Ihe method will also send the broadcast implicitly if no list of apps is
- * provided for backwards comparability.
+ * the AndroidManifest. If no apps are found to receive the intent, this method will send the
+ * broadcast implicitly if no list of apps is provided.
*
* @param intent - the intent to send explicitly
* @param apps - the list of apps that this broadcast will be sent to. If null is passed in
@@ -143,7 +143,6 @@ public class AndroidTools {
if (apps == null) {
apps = context.getPackageManager().queryBroadcastReceivers(intent, 0);
- context.sendBroadcast(intent);
}
if (apps != null && apps.size()>0) {
@@ -155,6 +154,9 @@ public class AndroidTools {
//In case there is missing info in the app reference we want to keep moving
}
}
+ } else {
+ // fallback to implicit broadcast if we cannot resolve apps info.
+ context.sendBroadcast(intent);
}
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java b/sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java
index cee0650e3..38e881b60 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/util/SdlAppInfo.java
@@ -68,13 +68,17 @@ public class SdlAppInfo {
this.routerServiceComponentName = new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
Bundle metadata = resolveInfo.serviceInfo.metaData;
+ if(metadata != null) {
- if(metadata.containsKey(SDL_ROUTER_VERSION_METADATA)){
- this.routerServiceVersion = metadata.getInt(SDL_ROUTER_VERSION_METADATA);
- }
+ if (metadata.containsKey(SDL_ROUTER_VERSION_METADATA)){
+ this.routerServiceVersion = metadata.getInt(SDL_ROUTER_VERSION_METADATA);
+ }
- if(metadata.containsKey(SDL_CUSTOM_ROUTER_METADATA)){
- this.isCustomRouterService = metadata.getBoolean(SDL_CUSTOM_ROUTER_METADATA);
+ if (metadata.containsKey(SDL_CUSTOM_ROUTER_METADATA)) {
+ this.isCustomRouterService = metadata.getBoolean(SDL_CUSTOM_ROUTER_METADATA);
+ }
+ } else {
+ Log.w(TAG, packageName + " has not supplied metadata with their router service!");
}
}
diff --git a/sdl_android/src/main/java/com/smartdevicelink/util/Version.java b/sdl_android/src/main/java/com/smartdevicelink/util/Version.java
index 8621c8cfd..78eac8db4 100644
--- a/sdl_android/src/main/java/com/smartdevicelink/util/Version.java
+++ b/sdl_android/src/main/java/com/smartdevicelink/util/Version.java
@@ -3,7 +3,7 @@ package com.smartdevicelink.util;
public class Version {
- int major,minor,patch;
+ final int major,minor,patch;
public Version(){
major = 0;
@@ -11,6 +11,12 @@ public class Version {
patch = 0;
}
+ public Version(int major, int minor, int patch){
+ this.major = major;
+ this.minor = minor;
+ this.patch = patch;
+ }
+
public Version(String versionString){
String[] versions = versionString.split("\\.");
if(versions.length!=3){
@@ -34,6 +40,28 @@ public class Version {
return patch;
}
+ /**
+ * Method to test if this instance of Version is newer than the supplied one.
+ * @param version the version to check against
+ * @return 1 if this instance is newer, -1 if supplied version is newer, and 0 if they are equal
+ */
+ public int isNewerThan(Version version){
+ if(this.major > version.major){
+ return 1;
+ }else if(this.major == version.major){
+ if(this.minor > version.minor){
+ return 1;
+ } else if(this.minor == version.minor){
+ if(this.patch > version.patch){
+ return 1;
+ }else if(this.patch == version.patch){
+ return 0;
+ }
+ }
+ }
+ return -1;
+ }
+
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
diff --git a/sdl_android/src/main/res/drawable-hdpi/sdl_lockscreen_icon.png b/sdl_android/src/main/res/drawable-hdpi/sdl_lockscreen_icon.png
new file mode 100644
index 000000000..625eb35ea
--- /dev/null
+++ b/sdl_android/src/main/res/drawable-hdpi/sdl_lockscreen_icon.png
Binary files differ
diff --git a/sdl_android/src/main/res/drawable-mdpi/sdl_lockscreen_icon.png b/sdl_android/src/main/res/drawable-mdpi/sdl_lockscreen_icon.png
new file mode 100644
index 000000000..d13a55e0b
--- /dev/null
+++ b/sdl_android/src/main/res/drawable-mdpi/sdl_lockscreen_icon.png
Binary files differ
diff --git a/sdl_android/src/main/res/drawable-mdpi/transparent.png b/sdl_android/src/main/res/drawable-mdpi/transparent.png
new file mode 100644
index 000000000..f21003d3a
--- /dev/null
+++ b/sdl_android/src/main/res/drawable-mdpi/transparent.png
Binary files differ
diff --git a/sdl_android/src/main/res/drawable-xhdpi/sdl_lockscreen_icon.png b/sdl_android/src/main/res/drawable-xhdpi/sdl_lockscreen_icon.png
new file mode 100644
index 000000000..d7de7cabe
--- /dev/null
+++ b/sdl_android/src/main/res/drawable-xhdpi/sdl_lockscreen_icon.png
Binary files differ
diff --git a/sdl_android/src/main/res/drawable-xxhdpi/sdl_lockscreen_icon.png b/sdl_android/src/main/res/drawable-xxhdpi/sdl_lockscreen_icon.png
new file mode 100644
index 000000000..bd0c40e67
--- /dev/null
+++ b/sdl_android/src/main/res/drawable-xxhdpi/sdl_lockscreen_icon.png
Binary files differ
diff --git a/sdl_android/src/main/res/drawable-xxxhdpi/sdl_lockscreen_icon.png b/sdl_android/src/main/res/drawable-xxxhdpi/sdl_lockscreen_icon.png
new file mode 100644
index 000000000..21962c148
--- /dev/null
+++ b/sdl_android/src/main/res/drawable-xxxhdpi/sdl_lockscreen_icon.png
Binary files differ
diff --git a/sdl_android/src/main/res/layout/activity_sdllock_screen.xml b/sdl_android/src/main/res/layout/activity_sdllock_screen.xml
new file mode 100644
index 000000000..dd2c2a6bb
--- /dev/null
+++ b/sdl_android/src/main/res/layout/activity_sdllock_screen.xml
@@ -0,0 +1,44 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/lockscreen_relative_layout"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="#2c3d4d">
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/lockscreen_linear_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center_horizontal|center_vertical">
+
+ <ImageView
+ android:id="@+id/lockscreen_image"
+ android:layout_width="120dp"
+ android:layout_height="120dp"
+ android:scaleType="fitXY"
+ android:layout_gravity="center_horizontal"
+ android:contentDescription="@string/lockscreen_image_description"
+ android:background="@drawable/sdl_lockscreen_icon"/>
+
+ <ImageView
+ android:id="@+id/device_image"
+ android:layout_width="120dp"
+ android:layout_height="120dp"
+ android:layout_marginTop="30dp"
+ android:scaleType="fitXY"
+ android:layout_gravity="center_horizontal"
+ android:contentDescription="@string/lockscreen_device_image_description"/>
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/lockscreen_text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="@string/lockscreen_text"
+ android:textSize="18sp"
+ android:gravity="center|bottom"
+ android:textColor="#FFFFFF"
+ android:paddingBottom="10dp"/>
+
+</RelativeLayout> \ No newline at end of file
diff --git a/sdl_android/src/main/res/values/sdl.xml b/sdl_android/src/main/res/values/sdl.xml
index 679a8cf61..ca8b15851 100644
--- a/sdl_android/src/main/res/values/sdl.xml
+++ b/sdl_android/src/main/res/values/sdl.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="sdl_router_service_version_name" translatable="false">sdl_router_version</string>
- <integer name="sdl_router_service_version_value">7</integer>
+
+ <integer name="sdl_router_service_version_value">8</integer>
<string name="sdl_router_service_is_custom_name" translatable="false">sdl_custom_router</string>
</resources>
diff --git a/sdl_android/src/main/res/values/strings.xml b/sdl_android/src/main/res/values/strings.xml
new file mode 100644
index 000000000..1d55ec24d
--- /dev/null
+++ b/sdl_android/src/main/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="lockscreen_text">Locked for your safety</string>
+ <string name="lockscreen_image_description">SDL Icon</string>
+ <string name="lockscreen_device_image_description">Device Icon</string>
+</resources> \ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 5eeb895cf..a358feb22 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':sdl_android'
+include ':sdl_android', ':hello_sdl_android' \ No newline at end of file
diff --git a/third_party.md b/third_party.md
new file mode 100644
index 000000000..667e841a9
--- /dev/null
+++ b/third_party.md
@@ -0,0 +1,39 @@
+### SDL ANDROID
+
+Copyright (C) 2018 SmartDeviceLink Consortium, Inc.
+
+#### License
+Copyright (c) 2017 - 2018, 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.
+
+#### Third Party Licenses
+
+Both the source and binary distributions of this software contain
+some third party software. All the third party software included
+or linked is redistributed under the terms and conditions of their
+original licenses.
+
+The third party software included and used by this project is:
+
+**Gradle 4.4**
+
+* Licensed under Apache License, Version 2.0
+* See [https://services.gradle.org/distributions/gradle-4.4-all.zip](https://services.gradle.org/distributions/gradle-4.4-all.zip)
+
+**Android 2009**
+
+* Copyright (C) 2009 The Android Open Source Project
+* Licensed under Apache License, Version 2.0
+* The library is included in the MultiplexBluetoothTransport file
+* See [https://services.gradle.org/distributions/gradle-4.4-all.zip](https://services.gradle.org/distributions/gradle-4.4-all.zip) \ No newline at end of file