summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Fischer <joeljfischer@gmail.com>2018-05-16 11:58:43 -0400
committerGitHub <noreply@github.com>2018-05-16 11:58:43 -0400
commit78836671221b36a686e5c768367476a16faa74d8 (patch)
treee5d79fda0828def5e32b71660a95e80a9b0f946e
parent09b01baa64b9764e7908422cb45c7b3244bcd595 (diff)
parent22ad2c2383fc18c939a3a07bc58e35e0791c6a0e (diff)
downloadsdl_ios-78836671221b36a686e5c768367476a16faa74d8.tar.gz
Merge pull request #931 from smartdevicelink/feature/issue_620_swift_sdl_example_app
Added Swift Ex. App & Expanded Obj-C Ex. App
-rw-r--r--SmartDeviceLink-Example-Swift-Info.plist81
-rw-r--r--SmartDeviceLink-iOS.xcodeproj/project.pbxproj754
-rw-r--r--SmartDeviceLink_Example/AlertManager.h22
-rw-r--r--SmartDeviceLink_Example/AlertManager.m45
-rw-r--r--SmartDeviceLink_Example/AlertManager.swift36
-rw-r--r--SmartDeviceLink_Example/AppConstants.h100
-rw-r--r--SmartDeviceLink_Example/AppConstants.m95
-rw-r--r--SmartDeviceLink_Example/AppDelegate.h (renamed from SmartDeviceLink_Example/Classes/AppDelegate.h)0
-rw-r--r--SmartDeviceLink_Example/AppDelegate.m (renamed from SmartDeviceLink_Example/Classes/AppDelegate.m)0
-rw-r--r--SmartDeviceLink_Example/AppDelegate.swift44
-rw-r--r--SmartDeviceLink_Example/AppUserDefaults.swift43
-rw-r--r--SmartDeviceLink_Example/AudioManager.h26
-rw-r--r--SmartDeviceLink_Example/AudioManager.m277
-rw-r--r--SmartDeviceLink_Example/AudioManager.swift229
-rw-r--r--SmartDeviceLink_Example/Base.lproj/ConnectionTCPTableViewController.storyboard22
-rw-r--r--SmartDeviceLink_Example/Base.lproj/Main.storyboard18
-rw-r--r--SmartDeviceLink_Example/ButtonManager.h31
-rw-r--r--SmartDeviceLink_Example/ButtonManager.m146
-rw-r--r--SmartDeviceLink_Example/ButtonManager.swift121
-rw-r--r--SmartDeviceLink_Example/Classes/ConnectionIAPTableViewController.m2
-rw-r--r--SmartDeviceLink_Example/Classes/ConnectionTCPTableViewController.m2
-rw-r--r--SmartDeviceLink_Example/Classes/ProxyManager.h9
-rw-r--r--SmartDeviceLink_Example/Classes/ProxyManager.m444
-rw-r--r--SmartDeviceLink_Example/ConnectionContainerViewController.swift82
-rw-r--r--SmartDeviceLink_Example/ConnectionIAPTableViewController.storyboard69
-rw-r--r--SmartDeviceLink_Example/ConnectionIAPTableViewController.swift72
-rw-r--r--SmartDeviceLink_Example/ConnectionTCPTableViewController.storyboard135
-rw-r--r--SmartDeviceLink_Example/ConnectionTCPTableViewController.swift88
-rw-r--r--SmartDeviceLink_Example/Images.xcassets/car_icon.imageset/Contents.json (renamed from SmartDeviceLink_Example/Images.xcassets/star_softbutton_icon.imageset/Contents.json)2
-rw-r--r--SmartDeviceLink_Example/Images.xcassets/car_icon.imageset/car.pngbin0 -> 14551 bytes
-rw-r--r--SmartDeviceLink_Example/Images.xcassets/hexagon_off_softbutton_icon.imageset/hexagon_black_softbutton_icon.pngbin669 -> 0 bytes
-rw-r--r--SmartDeviceLink_Example/Images.xcassets/hexagon_on_softbutton_icon.imageset/hexagon_pink_softbutton_icon.pngbin791 -> 0 bytes
-rw-r--r--SmartDeviceLink_Example/Images.xcassets/laptop_icon.imageset/Contents.json (renamed from SmartDeviceLink_Example/Images.xcassets/hexagon_on_softbutton_icon.imageset/Contents.json)2
-rw-r--r--SmartDeviceLink_Example/Images.xcassets/laptop_icon.imageset/screen.pngbin0 -> 8264 bytes
-rw-r--r--SmartDeviceLink_Example/Images.xcassets/microphone.imageset/Contents.json (renamed from SmartDeviceLink_Example/Images.xcassets/hexagon_off_softbutton_icon.imageset/Contents.json)2
-rw-r--r--SmartDeviceLink_Example/Images.xcassets/microphone.imageset/microphone.pngbin0 -> 2608 bytes
-rw-r--r--SmartDeviceLink_Example/Images.xcassets/phone.imageset/Contents.json21
-rw-r--r--SmartDeviceLink_Example/Images.xcassets/phone.imageset/phone.pngbin0 -> 3434 bytes
-rw-r--r--SmartDeviceLink_Example/Images.xcassets/star_softbutton_icon.imageset/star_black_softbutton_icon.pngbin909 -> 0 bytes
-rw-r--r--SmartDeviceLink_Example/Images.xcassets/wheel_icon.imageset/Contents.json21
-rw-r--r--SmartDeviceLink_Example/Images.xcassets/wheel_icon.imageset/wheel.pngbin0 -> 16899 bytes
-rw-r--r--SmartDeviceLink_Example/LaunchScreen.xib37
-rw-r--r--SmartDeviceLink_Example/Main.storyboard66
-rw-r--r--SmartDeviceLink_Example/MenuManager.h24
-rw-r--r--SmartDeviceLink_Example/MenuManager.m106
-rw-r--r--SmartDeviceLink_Example/MenuManager.swift154
-rw-r--r--SmartDeviceLink_Example/PerformInteractionManager.h24
-rw-r--r--SmartDeviceLink_Example/PerformInteractionManager.m56
-rw-r--r--SmartDeviceLink_Example/PerformInteractionManager.swift65
-rw-r--r--SmartDeviceLink_Example/Protocol+ProxyManagerDelegate.swift13
-rw-r--r--SmartDeviceLink_Example/ProxyManager.swift285
-rw-r--r--SmartDeviceLink_Example/RPCPermissionsManager.h21
-rw-r--r--SmartDeviceLink_Example/RPCPermissionsManager.m138
-rw-r--r--SmartDeviceLink_Example/RPCPermissionsManager.swift119
-rw-r--r--SmartDeviceLink_Example/SmartDeviceLink-Example-ObjC-Info.plist (renamed from SmartDeviceLink_Example/Info.plist)4
-rw-r--r--SmartDeviceLink_Example/SmartDeviceLink-Example-Swift-Bridging-Header.h5
-rw-r--r--SmartDeviceLink_Example/VehicleDataManager.h33
-rw-r--r--SmartDeviceLink_Example/VehicleDataManager.m216
-rw-r--r--SmartDeviceLink_Example/VehicleDataManager.swift184
59 files changed, 4065 insertions, 526 deletions
diff --git a/SmartDeviceLink-Example-Swift-Info.plist b/SmartDeviceLink-Example-Swift-Info.plist
new file mode 100644
index 000000000..e35e656dd
--- /dev/null
+++ b/SmartDeviceLink-Example-Swift-Info.plist
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>NSSpeechRecognitionUsageDescription</key>
+ <string>Requesting access to the speech recognition API</string>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>7.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>5.2.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIBackgroundModes</key>
+ <array>
+ <string>external-accessory</string>
+ </array>
+ <key>UIFileSharingEnabled</key>
+ <true/>
+ <key>UILaunchStoryboardName</key>
+ <string>LaunchScreen</string>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UISupportedExternalAccessoryProtocols</key>
+ <array>
+ <string>com.smartdevicelink.prot29</string>
+ <string>com.smartdevicelink.prot28</string>
+ <string>com.smartdevicelink.prot27</string>
+ <string>com.smartdevicelink.prot26</string>
+ <string>com.smartdevicelink.prot25</string>
+ <string>com.smartdevicelink.prot24</string>
+ <string>com.smartdevicelink.prot23</string>
+ <string>com.smartdevicelink.prot22</string>
+ <string>com.smartdevicelink.prot21</string>
+ <string>com.smartdevicelink.prot20</string>
+ <string>com.smartdevicelink.prot19</string>
+ <string>com.smartdevicelink.prot18</string>
+ <string>com.smartdevicelink.prot17</string>
+ <string>com.smartdevicelink.prot16</string>
+ <string>com.smartdevicelink.prot15</string>
+ <string>com.smartdevicelink.prot14</string>
+ <string>com.smartdevicelink.prot13</string>
+ <string>com.smartdevicelink.prot12</string>
+ <string>com.smartdevicelink.prot11</string>
+ <string>com.smartdevicelink.prot10</string>
+ <string>com.smartdevicelink.prot9</string>
+ <string>com.smartdevicelink.prot8</string>
+ <string>com.smartdevicelink.prot7</string>
+ <string>com.smartdevicelink.prot6</string>
+ <string>com.smartdevicelink.prot5</string>
+ <string>com.smartdevicelink.prot4</string>
+ <string>com.smartdevicelink.prot3</string>
+ <string>com.smartdevicelink.prot2</string>
+ <string>com.smartdevicelink.prot1</string>
+ <string>com.smartdevicelink.prot0</string>
+ <string>com.ford.sync.prot0</string>
+ <string>com.smartdevicelink.multisession</string>
+ </array>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ </array>
+</dict>
+</plist>
diff --git a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
index d4bea2ff0..a4993e762 100644
--- a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
+++ b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
@@ -366,12 +366,10 @@
5D4029E41A76F0760006B0C2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5D4029E11A76F0760006B0C2 /* Main.storyboard */; };
5D4346471E6F0BDA00B639C6 /* SDLLogFileModuleSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D4346461E6F0BDA00B639C6 /* SDLLogFileModuleSpec.m */; };
5D43465B1E6F154400B639C6 /* SDLLogConfigurationSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D43465A1E6F154400B639C6 /* SDLLogConfigurationSpec.m */; };
- 5D4346651E6F38E600B639C6 /* SmartDeviceLinkSwift.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D4346631E6F38E600B639C6 /* SmartDeviceLinkSwift.h */; settings = {ATTRIBUTES = (Public, ); }; };
5D43466B1E6F3B4C00B639C6 /* SDLLogFilterSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D43466A1E6F3B4C00B639C6 /* SDLLogFilterSpec.m */; };
5D43466D1E6F522000B639C6 /* SDLLogModelSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D43466C1E6F522000B639C6 /* SDLLogModelSpec.m */; };
5D43466F1E6F55BD00B639C6 /* SDLLogManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D43466E1E6F55BD00B639C6 /* SDLLogManagerSpec.m */; };
5D4346731E6F617D00B639C6 /* TestLogTarget.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D4346721E6F617D00B639C6 /* TestLogTarget.m */; };
- 5D4346861E771B5700B639C6 /* SDLLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D4346851E771B5700B639C6 /* SDLLog.swift */; };
5D4631041F2120A30092EFDC /* SDLControlFramePayloadType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D4631031F2120A30092EFDC /* SDLControlFramePayloadType.h */; };
5D4631081F21261A0092EFDC /* SDLControlFramePayloadRPCStartServiceAck.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D4631061F21261A0092EFDC /* SDLControlFramePayloadRPCStartServiceAck.h */; };
5D4631091F21261B0092EFDC /* SDLControlFramePayloadRPCStartServiceAck.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D4631071F21261A0092EFDC /* SDLControlFramePayloadRPCStartServiceAck.m */; };
@@ -968,10 +966,10 @@
5DA49CE61F1EA83300E65FC5 /* SDLControlFramePayloadRPCStartService.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DA49CE41F1EA83300E65FC5 /* SDLControlFramePayloadRPCStartService.m */; };
5DA8A0E91E955F710039C50D /* SDLStreamingMediaManagerConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8966F31E56977C00413EAB /* SDLStreamingMediaManagerConstants.m */; };
5DA8A0EA1E955FE00039C50D /* SDLLogModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DBF06301E64A9C600A5CF03 /* SDLLogModel.m */; };
- 5DAB5F562098E5D100A020C8 /* SDLProtocolConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DAB5F542098E5D100A020C8 /* SDLProtocolConstants.h */; };
- 5DAB5F572098E5D100A020C8 /* SDLProtocolConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DAB5F552098E5D100A020C8 /* SDLProtocolConstants.m */; };
5DAB5F512098994C00A020C8 /* SDLMenuCellSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DAB5F502098994C00A020C8 /* SDLMenuCellSpec.m */; };
5DAB5F5320989A8300A020C8 /* SDLVoiceCommandSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DAB5F5220989A8300A020C8 /* SDLVoiceCommandSpec.m */; };
+ 5DAB5F562098E5D100A020C8 /* SDLProtocolConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DAB5F542098E5D100A020C8 /* SDLProtocolConstants.h */; };
+ 5DAB5F572098E5D100A020C8 /* SDLProtocolConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DAB5F552098E5D100A020C8 /* SDLProtocolConstants.m */; };
5DAD5F7F204DEDEB0025624C /* SDLScreenManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DAD5F7D204DEDEB0025624C /* SDLScreenManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
5DAD5F80204DEDEB0025624C /* SDLScreenManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DAD5F7E204DEDEB0025624C /* SDLScreenManager.m */; };
5DAD5F8520507E1F0025624C /* SDLScreenManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DAD5F8420507E1F0025624C /* SDLScreenManagerSpec.m */; };
@@ -1060,17 +1058,54 @@
5DF40B26208FA7DE00DD6FDA /* SDLMenuManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DF40B25208FA7DE00DD6FDA /* SDLMenuManagerSpec.m */; };
5DF40B28208FDA9700DD6FDA /* SDLVoiceCommandManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DF40B27208FDA9700DD6FDA /* SDLVoiceCommandManagerSpec.m */; };
5DFFB9151BD7C89700DB3F04 /* SDLConnectionManagerType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DFFB9141BD7C89700DB3F04 /* SDLConnectionManagerType.h */; };
- 880E8C2920697FEE00CF86C2 /* SDLSystemCapabilityManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 880E8C2720697FEE00CF86C2 /* SDLSystemCapabilityManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 880E8C2A20697FEE00CF86C2 /* SDLSystemCapabilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 880E8C2820697FEE00CF86C2 /* SDLSystemCapabilityManager.m */; };
+ 8800871E20A6356D008E1EA0 /* ButtonManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8800871B20A6338C008E1EA0 /* ButtonManager.m */; };
+ 8803A0AF208E2A3A009FDC02 /* AudioManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8803A0AC208E2907009FDC02 /* AudioManager.m */; };
+ 8803A0B2208E7CA4009FDC02 /* VehicleDataManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8803A0B1208E7CA4009FDC02 /* VehicleDataManager.m */; };
+ 880E35B42088F75A00181259 /* SDLSystemCapabilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 880E35B22088F75A00181259 /* SDLSystemCapabilityManager.m */; };
+ 880E35B52088F75A00181259 /* SDLSystemCapabilityManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 880E35B32088F75A00181259 /* SDLSystemCapabilityManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 880E35B82088F78E00181259 /* SDLSystemCapabilityManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 880E35B72088F78E00181259 /* SDLSystemCapabilityManagerSpec.m */; };
+ 8814AEA720AB65FC00466E0F /* MenuManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8814AEA620AB65FC00466E0F /* MenuManager.m */; };
+ 8814AEAA20AB663800466E0F /* PerformInteractionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8814AEA920AB663800466E0F /* PerformInteractionManager.m */; };
+ 8814AEAC20AB667B00466E0F /* PerformInteractionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8814AEAB20AB667B00466E0F /* PerformInteractionManager.swift */; };
+ 88166B00207E41E900076236 /* MenuManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88166AFF207E41E900076236 /* MenuManager.swift */; };
+ 8829568B207CF68800EF056C /* SmartDeviceLink.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D61FA1C1A84237100846EE7 /* SmartDeviceLink.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ 88295690207CF68800EF056C /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5D4029D31A76F0340006B0C2 /* Images.xcassets */; };
+ 88295693207CF68800EF056C /* SmartDeviceLink.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5D61FA1C1A84237100846EE7 /* SmartDeviceLink.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ 8829569E207CFD0E00EF056C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8829569D207CFD0E00EF056C /* AppDelegate.swift */; };
8850DB601F4475D30053A48D /* TestMultipleFilesConnectionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8850DB5F1F4475D30053A48D /* TestMultipleFilesConnectionManager.m */; };
- 886D313F206A956B001185B4 /* SDLSystemCapabilityManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 886D313E206A956B001185B4 /* SDLSystemCapabilityManagerSpec.m */; };
+ 8863B59D207D3849002D6459 /* AppConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 8863B597207D2388002D6459 /* AppConstants.m */; };
+ 8870C3EA208662540070E018 /* AudioManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8870C3E82086623F0070E018 /* AudioManager.swift */; };
8877F5EB1F34A3BE00DC128A /* SDLSendHapticDataSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8877F5EA1F34A3BE00DC128A /* SDLSendHapticDataSpec.m */; };
8877F5EE1F34A72200DC128A /* SDLSendHapticDataResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 8877F5EC1F34A72200DC128A /* SDLSendHapticDataResponse.h */; settings = {ATTRIBUTES = (Public, ); }; };
8877F5EF1F34A72200DC128A /* SDLSendHapticDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8877F5ED1F34A72200DC128A /* SDLSendHapticDataResponse.m */; };
8877F5F11F34AA2D00DC128A /* SDLSendHapticDataResponseSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8877F5F01F34AA2D00DC128A /* SDLSendHapticDataResponseSpec.m */; };
+ 88802FE920853AE600E9EBC6 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 5D9FDA971F2A7D3F00A495C8 /* LICENSE */; };
+ 88802FEA20853AE600E9EBC6 /* SDLAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5D6F7A3D1BC811FC0070BF37 /* SDLAssets.xcassets */; };
+ 88802FEB20853AE600E9EBC6 /* SDLLockScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5D616B481D552F7A00553F6B /* SDLLockScreen.storyboard */; };
+ 88802FF120853BB700E9EBC6 /* SDLLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D4346851E771B5700B639C6 /* SDLLog.swift */; };
+ 88802FF420853BED00E9EBC6 /* SmartDeviceLinkSwift.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D4346631E6F38E600B639C6 /* SmartDeviceLinkSwift.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 88802FF520853CD500E9EBC6 /* SmartDeviceLinkSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88802FEF20853AE600E9EBC6 /* SmartDeviceLinkSwift.framework */; };
+ 88802FF620853CD500E9EBC6 /* SmartDeviceLinkSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 88802FEF20853AE600E9EBC6 /* SmartDeviceLinkSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ 888D178F207E7F42008E9F8F /* ButtonManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 888D178D207E7F0E008E9F8F /* ButtonManager.swift */; };
+ 888D1790207E815C008E9F8F /* AppConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 8863B597207D2388002D6459 /* AppConstants.m */; };
+ 88A0AA56207CFE5D0075132C /* AppUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A0AA55207CFE5C0075132C /* AppUserDefaults.swift */; };
+ 88A0AA58207CFE650075132C /* ProxyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A0AA57207CFE650075132C /* ProxyManager.swift */; };
+ 88A0AA5C207CFE740075132C /* ConnectionContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A0AA59207CFE740075132C /* ConnectionContainerViewController.swift */; };
+ 88A0AA5D207CFE740075132C /* ConnectionIAPTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A0AA5A207CFE740075132C /* ConnectionIAPTableViewController.swift */; };
+ 88A0AA5E207CFE740075132C /* ConnectionTCPTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A0AA5B207CFE740075132C /* ConnectionTCPTableViewController.swift */; };
+ 88A0AA65207CFF980075132C /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 88A0AA61207CFF970075132C /* LaunchScreen.xib */; };
+ 88A0AA66207CFF980075132C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 88A0AA62207CFF970075132C /* Main.storyboard */; };
+ 88A0AA67207CFF980075132C /* ConnectionIAPTableViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 88A0AA63207CFF970075132C /* ConnectionIAPTableViewController.storyboard */; };
+ 88A0AA68207CFF980075132C /* ConnectionTCPTableViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 88A0AA64207CFF980075132C /* ConnectionTCPTableViewController.storyboard */; };
88B848C31F45E1A600DED768 /* TestResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 88B848C21F45E1A600DED768 /* TestResponse.m */; };
88B848C91F462E3600DED768 /* TestFileProgressResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 88B848C81F462E3600DED768 /* TestFileProgressResponse.m */; };
+ 88B849C52080F4B3002A034D /* RPCPermissionsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B849C32080F4AF002A034D /* RPCPermissionsManager.swift */; };
+ 88B849C820812442002A034D /* VehicleDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B849C620812412002A034D /* VehicleDataManager.swift */; };
88D2AAE41F682BB20078D5B2 /* SDLLogConstantsSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 88D2AAE31F682BB20078D5B2 /* SDLLogConstantsSpec.m */; };
+ 88DA6D10209794A400AD8297 /* AlertManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 88DA6D0F209794A400AD8297 /* AlertManager.m */; };
+ 88DE80B720A5C8DD00BA9CF0 /* RPCPermissionsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 88DE80B620A5C8DD00BA9CF0 /* RPCPermissionsManager.m */; };
+ 88DFB053207F8E100079D19D /* Protocol+ProxyManagerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DFB051207F8DF50079D19D /* Protocol+ProxyManagerDelegate.swift */; };
+ 88DFB055207F96EE0079D19D /* AlertManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DFB054207F96EE0079D19D /* AlertManager.swift */; };
88EED8381F33AE1700E6C42E /* SDLHapticRect.h in Headers */ = {isa = PBXBuildFile; fileRef = 88EED8361F33AE1700E6C42E /* SDLHapticRect.h */; settings = {ATTRIBUTES = (Public, ); }; };
88EED8391F33AE1700E6C42E /* SDLHapticRect.m in Sources */ = {isa = PBXBuildFile; fileRef = 88EED8371F33AE1700E6C42E /* SDLHapticRect.m */; };
88EED83B1F33BECB00E6C42E /* SDLHapticRectSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 88EED83A1F33BECB00E6C42E /* SDLHapticRectSpec.m */; };
@@ -1189,34 +1224,48 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
- 5D43468B1E788E2200B639C6 /* PBXContainerItemProxy */ = {
+ 5D61FA281A84237100846EE7 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5D4019A71A76EC350006B0C2 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 5D61FA1B1A84237100846EE7;
remoteInfo = SmartDeviceLink;
};
- 5D61FA281A84237100846EE7 /* PBXContainerItemProxy */ = {
+ 5D61FA2A1A84237100846EE7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 5D4019A71A76EC350006B0C2 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 5D4019AE1A76EC350006B0C2;
+ remoteInfo = "SmartDeviceLink-Example";
+ };
+ 5D61FA311A84237100846EE7 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5D4019A71A76EC350006B0C2 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 5D61FA1B1A84237100846EE7;
remoteInfo = SmartDeviceLink;
};
- 5D61FA2A1A84237100846EE7 /* PBXContainerItemProxy */ = {
+ 8829567F207CF68800EF056C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5D4019A71A76EC350006B0C2 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = 5D4019AE1A76EC350006B0C2;
- remoteInfo = "SmartDeviceLink-Example";
+ remoteGlobalIDString = 5D61FA1B1A84237100846EE7;
+ remoteInfo = SmartDeviceLink;
};
- 5D61FA311A84237100846EE7 /* PBXContainerItemProxy */ = {
+ 88802FF220853BBF00E9EBC6 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5D4019A71A76EC350006B0C2 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 5D61FA1B1A84237100846EE7;
remoteInfo = SmartDeviceLink;
};
+ 88802FF720853CD500E9EBC6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 5D4019A71A76EC350006B0C2 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 88802CD720853AE600E9EBC6;
+ remoteInfo = SmartDeviceLinkSwift;
+ };
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -1245,6 +1294,18 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 88295692207CF68800EF056C /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ 88802FF620853CD500E9EBC6 /* SmartDeviceLinkSwift.framework in Embed Frameworks */,
+ 88295693207CF68800EF056C /* SmartDeviceLink.framework in Embed Frameworks */,
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
@@ -1614,12 +1675,11 @@
5D3E48CA1D7722FE0000BFEF /* NSBundle+SDLBundle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+SDLBundle.m"; sourceTree = "<group>"; };
5D4019AF1A76EC350006B0C2 /* SDL Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SDL Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
5D4029D31A76F0340006B0C2 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = SmartDeviceLink_Example/Images.xcassets; sourceTree = SOURCE_ROOT; };
- 5D4029D51A76F0410006B0C2 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = SmartDeviceLink_Example/Info.plist; sourceTree = SOURCE_ROOT; };
+ 5D4029D51A76F0410006B0C2 /* SmartDeviceLink-Example-ObjC-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "SmartDeviceLink-Example-ObjC-Info.plist"; path = "SmartDeviceLink_Example/SmartDeviceLink-Example-ObjC-Info.plist"; sourceTree = SOURCE_ROOT; };
5D4029E01A76F0760006B0C2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = SmartDeviceLink_Example/Base.lproj/LaunchScreen.xib; sourceTree = SOURCE_ROOT; };
5D4029E21A76F0760006B0C2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = SmartDeviceLink_Example/Base.lproj/Main.storyboard; sourceTree = SOURCE_ROOT; };
5D4346461E6F0BDA00B639C6 /* SDLLogFileModuleSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLLogFileModuleSpec.m; path = LoggingSpecs/SDLLogFileModuleSpec.m; sourceTree = "<group>"; };
5D43465A1E6F154400B639C6 /* SDLLogConfigurationSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLLogConfigurationSpec.m; path = LoggingSpecs/SDLLogConfigurationSpec.m; sourceTree = "<group>"; };
- 5D4346611E6F38E600B639C6 /* SmartDeviceLinkSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SmartDeviceLinkSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5D4346631E6F38E600B639C6 /* SmartDeviceLinkSwift.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SmartDeviceLinkSwift.h; sourceTree = "<group>"; };
5D4346641E6F38E600B639C6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5D43466A1E6F3B4C00B639C6 /* SDLLogFilterSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLLogFilterSpec.m; path = LoggingSpecs/SDLLogFilterSpec.m; sourceTree = "<group>"; };
@@ -1653,8 +1713,8 @@
5D535DC41B72473800CF7760 /* SDLGlobals.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLGlobals.m; sourceTree = "<group>"; };
5D53C46B1B7A99B9003526EA /* SDLStreamingMediaManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLStreamingMediaManager.h; sourceTree = "<group>"; };
5D53C46C1B7A99B9003526EA /* SDLStreamingMediaManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLStreamingMediaManager.m; sourceTree = "<group>"; };
- 5D59350B1A855EB300687FB9 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = SmartDeviceLink_Example/Classes/AppDelegate.h; sourceTree = SOURCE_ROOT; };
- 5D59350C1A855EB300687FB9 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = SmartDeviceLink_Example/Classes/AppDelegate.m; sourceTree = SOURCE_ROOT; };
+ 5D59350B1A855EB300687FB9 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = SmartDeviceLink_Example/AppDelegate.h; sourceTree = SOURCE_ROOT; };
+ 5D59350C1A855EB300687FB9 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = SmartDeviceLink_Example/AppDelegate.m; sourceTree = SOURCE_ROOT; };
5D5935111A855EBE00687FB9 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = SmartDeviceLink_Example/Classes/main.m; sourceTree = SOURCE_ROOT; };
5D59DD461B14FDEE00BE744D /* SDLLockScreenStatusManagerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLLockScreenStatusManagerSpec.m; path = ProxySpecs/SDLLockScreenStatusManagerSpec.m; sourceTree = "<group>"; };
5D5DBF071D48E39C00D4F914 /* FBSnapshotTestCase.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FBSnapshotTestCase.framework; path = sdl_ios/Carthage/Build/iOS/FBSnapshotTestCase.framework; sourceTree = "<group>"; };
@@ -2235,10 +2295,10 @@
5DA3F36F1BC4489A0026F2D0 /* SDLManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLManager.m; sourceTree = "<group>"; };
5DA49CE31F1EA83300E65FC5 /* SDLControlFramePayloadRPCStartService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLControlFramePayloadRPCStartService.h; sourceTree = "<group>"; };
5DA49CE41F1EA83300E65FC5 /* SDLControlFramePayloadRPCStartService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLControlFramePayloadRPCStartService.m; sourceTree = "<group>"; };
- 5DAB5F542098E5D100A020C8 /* SDLProtocolConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLProtocolConstants.h; sourceTree = "<group>"; };
- 5DAB5F552098E5D100A020C8 /* SDLProtocolConstants.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLProtocolConstants.m; sourceTree = "<group>"; };
5DAB5F502098994C00A020C8 /* SDLMenuCellSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLMenuCellSpec.m; path = DevAPISpecs/SDLMenuCellSpec.m; sourceTree = "<group>"; };
5DAB5F5220989A8300A020C8 /* SDLVoiceCommandSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLVoiceCommandSpec.m; path = DevAPISpecs/SDLVoiceCommandSpec.m; sourceTree = "<group>"; };
+ 5DAB5F542098E5D100A020C8 /* SDLProtocolConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLProtocolConstants.h; sourceTree = "<group>"; };
+ 5DAB5F552098E5D100A020C8 /* SDLProtocolConstants.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLProtocolConstants.m; sourceTree = "<group>"; };
5DAD5F7D204DEDEB0025624C /* SDLScreenManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLScreenManager.h; sourceTree = "<group>"; };
5DAD5F7E204DEDEB0025624C /* SDLScreenManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLScreenManager.m; sourceTree = "<group>"; };
5DAD5F8420507E1F0025624C /* SDLScreenManagerSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLScreenManagerSpec.m; sourceTree = "<group>"; };
@@ -2337,20 +2397,58 @@
5DF40B25208FA7DE00DD6FDA /* SDLMenuManagerSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLMenuManagerSpec.m; path = DevAPISpecs/SDLMenuManagerSpec.m; sourceTree = "<group>"; };
5DF40B27208FDA9700DD6FDA /* SDLVoiceCommandManagerSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLVoiceCommandManagerSpec.m; path = DevAPISpecs/SDLVoiceCommandManagerSpec.m; sourceTree = "<group>"; };
5DFFB9141BD7C89700DB3F04 /* SDLConnectionManagerType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLConnectionManagerType.h; sourceTree = "<group>"; };
- 880E8C2720697FEE00CF86C2 /* SDLSystemCapabilityManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLSystemCapabilityManager.h; sourceTree = "<group>"; };
- 880E8C2820697FEE00CF86C2 /* SDLSystemCapabilityManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLSystemCapabilityManager.m; sourceTree = "<group>"; };
+ 8800871A20A6338C008E1EA0 /* ButtonManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ButtonManager.h; sourceTree = "<group>"; };
+ 8800871B20A6338C008E1EA0 /* ButtonManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ButtonManager.m; sourceTree = "<group>"; };
+ 8803A0AB208E2907009FDC02 /* AudioManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AudioManager.h; sourceTree = "<group>"; };
+ 8803A0AC208E2907009FDC02 /* AudioManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AudioManager.m; sourceTree = "<group>"; };
+ 8803A0B0208E7CA4009FDC02 /* VehicleDataManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VehicleDataManager.h; sourceTree = "<group>"; };
+ 8803A0B1208E7CA4009FDC02 /* VehicleDataManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VehicleDataManager.m; sourceTree = "<group>"; };
+ 880E35B22088F75A00181259 /* SDLSystemCapabilityManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSystemCapabilityManager.m; sourceTree = "<group>"; };
+ 880E35B32088F75A00181259 /* SDLSystemCapabilityManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLSystemCapabilityManager.h; sourceTree = "<group>"; };
+ 880E35B72088F78E00181259 /* SDLSystemCapabilityManagerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSystemCapabilityManagerSpec.m; sourceTree = "<group>"; };
+ 8814AEA520AB65FC00466E0F /* MenuManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MenuManager.h; sourceTree = "<group>"; };
+ 8814AEA620AB65FC00466E0F /* MenuManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MenuManager.m; sourceTree = "<group>"; };
+ 8814AEA820AB663800466E0F /* PerformInteractionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PerformInteractionManager.h; sourceTree = "<group>"; };
+ 8814AEA920AB663800466E0F /* PerformInteractionManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PerformInteractionManager.m; sourceTree = "<group>"; };
+ 8814AEAB20AB667B00466E0F /* PerformInteractionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PerformInteractionManager.swift; sourceTree = "<group>"; };
+ 88166AFF207E41E900076236 /* MenuManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuManager.swift; sourceTree = "<group>"; };
+ 88295697207CF68800EF056C /* SDL Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SDL Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 88295698207CF68800EF056C /* SmartDeviceLink-Example-Swift-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "SmartDeviceLink-Example-Swift-Info.plist"; path = "/Users/nicolelivioradio.com/sdl_ios/SmartDeviceLink-Example-Swift-Info.plist"; sourceTree = "<absolute>"; };
+ 8829569C207CFD0D00EF056C /* SmartDeviceLink-Example-Swift-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SmartDeviceLink-Example-Swift-Bridging-Header.h"; sourceTree = "<group>"; };
+ 8829569D207CFD0E00EF056C /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
8850DB5E1F4475D30053A48D /* TestMultipleFilesConnectionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestMultipleFilesConnectionManager.h; sourceTree = "<group>"; };
8850DB5F1F4475D30053A48D /* TestMultipleFilesConnectionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestMultipleFilesConnectionManager.m; sourceTree = "<group>"; };
- 886D313E206A956B001185B4 /* SDLSystemCapabilityManagerSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLSystemCapabilityManagerSpec.m; sourceTree = "<group>"; };
+ 8863B596207D2388002D6459 /* AppConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppConstants.h; sourceTree = "<group>"; };
+ 8863B597207D2388002D6459 /* AppConstants.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppConstants.m; sourceTree = "<group>"; };
+ 8870C3E82086623F0070E018 /* AudioManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioManager.swift; sourceTree = "<group>"; };
8877F5EA1F34A3BE00DC128A /* SDLSendHapticDataSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSendHapticDataSpec.m; sourceTree = "<group>"; };
8877F5EC1F34A72200DC128A /* SDLSendHapticDataResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLSendHapticDataResponse.h; sourceTree = "<group>"; };
8877F5ED1F34A72200DC128A /* SDLSendHapticDataResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSendHapticDataResponse.m; sourceTree = "<group>"; };
8877F5F01F34AA2D00DC128A /* SDLSendHapticDataResponseSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSendHapticDataResponseSpec.m; sourceTree = "<group>"; };
+ 88802FEF20853AE600E9EBC6 /* SmartDeviceLinkSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SmartDeviceLinkSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 888D178D207E7F0E008E9F8F /* ButtonManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonManager.swift; sourceTree = "<group>"; };
+ 88A0AA55207CFE5C0075132C /* AppUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppUserDefaults.swift; sourceTree = "<group>"; };
+ 88A0AA57207CFE650075132C /* ProxyManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxyManager.swift; sourceTree = "<group>"; };
+ 88A0AA59207CFE740075132C /* ConnectionContainerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionContainerViewController.swift; sourceTree = "<group>"; };
+ 88A0AA5A207CFE740075132C /* ConnectionIAPTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionIAPTableViewController.swift; sourceTree = "<group>"; };
+ 88A0AA5B207CFE740075132C /* ConnectionTCPTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionTCPTableViewController.swift; sourceTree = "<group>"; };
+ 88A0AA61207CFF970075132C /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = "<group>"; };
+ 88A0AA62207CFF970075132C /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
+ 88A0AA63207CFF970075132C /* ConnectionIAPTableViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = ConnectionIAPTableViewController.storyboard; sourceTree = "<group>"; };
+ 88A0AA64207CFF980075132C /* ConnectionTCPTableViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = ConnectionTCPTableViewController.storyboard; sourceTree = "<group>"; };
88B848C11F45E1A600DED768 /* TestResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestResponse.h; sourceTree = "<group>"; };
88B848C21F45E1A600DED768 /* TestResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestResponse.m; sourceTree = "<group>"; };
88B848C71F462E3600DED768 /* TestFileProgressResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestFileProgressResponse.h; sourceTree = "<group>"; };
88B848C81F462E3600DED768 /* TestFileProgressResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestFileProgressResponse.m; sourceTree = "<group>"; };
+ 88B849C32080F4AF002A034D /* RPCPermissionsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RPCPermissionsManager.swift; sourceTree = "<group>"; };
+ 88B849C620812412002A034D /* VehicleDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleDataManager.swift; sourceTree = "<group>"; };
88D2AAE31F682BB20078D5B2 /* SDLLogConstantsSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLLogConstantsSpec.m; sourceTree = "<group>"; };
+ 88DA6D0E209794A400AD8297 /* AlertManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AlertManager.h; sourceTree = "<group>"; };
+ 88DA6D0F209794A400AD8297 /* AlertManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AlertManager.m; sourceTree = "<group>"; };
+ 88DE80B520A5C8DD00BA9CF0 /* RPCPermissionsManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RPCPermissionsManager.h; sourceTree = "<group>"; };
+ 88DE80B620A5C8DD00BA9CF0 /* RPCPermissionsManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RPCPermissionsManager.m; sourceTree = "<group>"; };
+ 88DFB051207F8DF50079D19D /* Protocol+ProxyManagerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Protocol+ProxyManagerDelegate.swift"; sourceTree = "<group>"; };
+ 88DFB054207F96EE0079D19D /* AlertManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertManager.swift; sourceTree = "<group>"; };
88EED8361F33AE1700E6C42E /* SDLHapticRect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLHapticRect.h; sourceTree = "<group>"; };
88EED8371F33AE1700E6C42E /* SDLHapticRect.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLHapticRect.m; sourceTree = "<group>"; };
88EED83A1F33BECB00E6C42E /* SDLHapticRectSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLHapticRectSpec.m; sourceTree = "<group>"; };
@@ -2479,13 +2577,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 5D43465D1E6F38E600B639C6 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
5D61FA181A84237100846EE7 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -2505,6 +2596,22 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 8829568A207CF68800EF056C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 88802FF520853CD500E9EBC6 /* SmartDeviceLinkSwift.framework in Frameworks */,
+ 8829568B207CF68800EF056C /* SmartDeviceLink.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 88802E5220853AE600E9EBC6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -2883,13 +2990,6 @@
path = MessageSpecs;
sourceTree = "<group>";
};
- 5D0218E71A8D611600D1BF62 /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- );
- name = Frameworks;
- sourceTree = "<group>";
- };
5D0218EB1A8E795700D1BF62 /* UI */ = {
isa = PBXGroup;
children = (
@@ -3108,7 +3208,7 @@
5D4019A61A76EC350006B0C2 = {
isa = PBXGroup;
children = (
- 5D4019B11A76EC350006B0C2 /* Example */,
+ 5D4019B11A76EC350006B0C2 /* Examples */,
5D61FA1D1A84237100846EE7 /* SmartDeviceLink */,
5D61FA2C1A84237100846EE7 /* SmartDeviceLinkTests */,
5D4346621E6F38E600B639C6 /* SmartDeviceLinkSwift */,
@@ -3123,34 +3223,31 @@
5D4019AF1A76EC350006B0C2 /* SDL Example.app */,
5D61FA1C1A84237100846EE7 /* SmartDeviceLink.framework */,
5D61FA261A84237100846EE7 /* SmartDeviceLinkTests.xctest */,
- 5D4346611E6F38E600B639C6 /* SmartDeviceLinkSwift.framework */,
+ 88295697207CF68800EF056C /* SDL Example.app */,
+ 88802FEF20853AE600E9EBC6 /* SmartDeviceLinkSwift.framework */,
);
name = Products;
sourceTree = "<group>";
};
- 5D4019B11A76EC350006B0C2 /* Example */ = {
+ 5D4019B11A76EC350006B0C2 /* Examples */ = {
isa = PBXGroup;
children = (
- 5D48329E1A92865900252386 /* SDL */,
- 5D48329A1A8EA31500252386 /* Utilities */,
- 5D0218EB1A8E795700D1BF62 /* UI */,
- 5D59350B1A855EB300687FB9 /* AppDelegate.h */,
- 5D59350C1A855EB300687FB9 /* AppDelegate.m */,
- 5D4029D31A76F0340006B0C2 /* Images.xcassets */,
- 5D4029DF1A76F0760006B0C2 /* LaunchScreen.xib */,
- 5D4029E11A76F0760006B0C2 /* Main.storyboard */,
- 5D4019B21A76EC350006B0C2 /* Supporting Files */,
+ 88295699207CFBD900EF056C /* Shared Assets */,
+ 88295678207CF47F00EF056C /* Swift */,
+ 88295677207CF46C00EF056C /* Objective-C */,
);
- name = Example;
+ name = Examples;
path = SmartDeviceLink_Example;
sourceTree = "<group>";
};
5D4019B21A76EC350006B0C2 /* Supporting Files */ = {
isa = PBXGroup;
children = (
- 5D0218E71A8D611600D1BF62 /* Frameworks */,
+ 5D59350B1A855EB300687FB9 /* AppDelegate.h */,
+ 5D59350C1A855EB300687FB9 /* AppDelegate.m */,
+ 5D4029DF1A76F0760006B0C2 /* LaunchScreen.xib */,
5D5935111A855EBE00687FB9 /* main.m */,
- 5D4029D51A76F0410006B0C2 /* Info.plist */,
+ 5D4029D51A76F0410006B0C2 /* SmartDeviceLink-Example-ObjC-Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
@@ -3221,6 +3318,7 @@
5D4832991A8EA27200252386 /* Storyboards */ = {
isa = PBXGroup;
children = (
+ 5D4029E11A76F0760006B0C2 /* Main.storyboard */,
5D0218F71A8E7A7300D1BF62 /* ConnectionTCPTableViewController.storyboard */,
5D0219031A8E9F6D00D1BF62 /* ConnectionIAPTableViewController.storyboard */,
);
@@ -3241,6 +3339,20 @@
children = (
5D48329F1A92868E00252386 /* ProxyManager.h */,
5D4832A01A92868E00252386 /* ProxyManager.m */,
+ 88DA6D0E209794A400AD8297 /* AlertManager.h */,
+ 88DA6D0F209794A400AD8297 /* AlertManager.m */,
+ 8803A0AB208E2907009FDC02 /* AudioManager.h */,
+ 8803A0AC208E2907009FDC02 /* AudioManager.m */,
+ 8800871A20A6338C008E1EA0 /* ButtonManager.h */,
+ 8800871B20A6338C008E1EA0 /* ButtonManager.m */,
+ 8814AEA520AB65FC00466E0F /* MenuManager.h */,
+ 8814AEA620AB65FC00466E0F /* MenuManager.m */,
+ 8814AEA820AB663800466E0F /* PerformInteractionManager.h */,
+ 8814AEA920AB663800466E0F /* PerformInteractionManager.m */,
+ 88DE80B520A5C8DD00BA9CF0 /* RPCPermissionsManager.h */,
+ 88DE80B620A5C8DD00BA9CF0 /* RPCPermissionsManager.m */,
+ 8803A0B0208E7CA4009FDC02 /* VehicleDataManager.h */,
+ 8803A0B1208E7CA4009FDC02 /* VehicleDataManager.m */,
);
name = SDL;
sourceTree = "<group>";
@@ -4408,7 +4520,7 @@
name = TCP;
sourceTree = "<group>";
};
- 5DAD5F8120507DE40025624C /* Show */ = {
+ 5DAD5F8120507DE40025624C /* Screen */ = {
isa = PBXGroup;
children = (
5DF40B24208FA7C500DD6FDA /* Menu */,
@@ -4567,7 +4679,7 @@
5D8204291BCEA91400D0A41B /* Permissions */,
DA8966E71E56937100413EAB /* Streaming */,
5D0A736F203F0C450001595D /* Screen */,
- 886D313C206A94BA001185B4 /* System Capabilities */,
+ 880E35B12088F73400181259 /* System Capabilities */,
);
name = Managers;
sourceTree = "<group>";
@@ -4586,11 +4698,11 @@
children = (
5DAD5F8120507DE40025624C /* Screen */,
DA8966ED1E5693D100413EAB /* Streaming */,
+ 880E35B62088F77C00181259 /* System Capabilities */,
5D1654541D3E753100554D93 /* Lifecycle */,
5D76E31A1D3805E600647CFA /* LockScreen */,
5D9F507F1BE7E6C900FEF399 /* Permissions */,
5D9F507E1BE7E46600FEF399 /* Files */,
- 886D313D206A951E001185B4 /* System Capabilities */,
5D5DBF0A1D48E5E600D4F914 /* SDLLockScreenViewControllerSnapshotTests.m */,
);
name = Managers;
@@ -4745,23 +4857,119 @@
name = Menu;
sourceTree = "<group>";
};
- 886D313C206A94BA001185B4 /* System Capabilities */ = {
+ 880E35B12088F73400181259 /* System Capabilities */ = {
isa = PBXGroup;
children = (
- 880E8C2720697FEE00CF86C2 /* SDLSystemCapabilityManager.h */,
- 880E8C2820697FEE00CF86C2 /* SDLSystemCapabilityManager.m */,
+ 880E35B32088F75A00181259 /* SDLSystemCapabilityManager.h */,
+ 880E35B22088F75A00181259 /* SDLSystemCapabilityManager.m */,
);
name = "System Capabilities";
sourceTree = "<group>";
};
- 886D313D206A951E001185B4 /* System Capabilities */ = {
+ 880E35B62088F77C00181259 /* System Capabilities */ = {
isa = PBXGroup;
children = (
- 886D313E206A956B001185B4 /* SDLSystemCapabilityManagerSpec.m */,
+ 880E35B72088F78E00181259 /* SDLSystemCapabilityManagerSpec.m */,
);
name = "System Capabilities";
sourceTree = "<group>";
};
+ 88295677207CF46C00EF056C /* Objective-C */ = {
+ isa = PBXGroup;
+ children = (
+ 5D48329E1A92865900252386 /* SDL */,
+ 5D48329A1A8EA31500252386 /* Utilities */,
+ 5D0218EB1A8E795700D1BF62 /* UI */,
+ 5D4019B21A76EC350006B0C2 /* Supporting Files */,
+ );
+ name = "Objective-C";
+ sourceTree = "<group>";
+ };
+ 88295678207CF47F00EF056C /* Swift */ = {
+ isa = PBXGroup;
+ children = (
+ 88295679207CF48C00EF056C /* SDL */,
+ 8829567C207CF4AB00EF056C /* Utilities */,
+ 8829567B207CF49F00EF056C /* UI */,
+ 8829567A207CF49600EF056C /* Supporting Files */,
+ );
+ name = Swift;
+ sourceTree = "<group>";
+ };
+ 88295679207CF48C00EF056C /* SDL */ = {
+ isa = PBXGroup;
+ children = (
+ 88A0AA57207CFE650075132C /* ProxyManager.swift */,
+ 88DFB054207F96EE0079D19D /* AlertManager.swift */,
+ 8870C3E82086623F0070E018 /* AudioManager.swift */,
+ 888D178D207E7F0E008E9F8F /* ButtonManager.swift */,
+ 88166AFF207E41E900076236 /* MenuManager.swift */,
+ 8814AEAB20AB667B00466E0F /* PerformInteractionManager.swift */,
+ 88B849C32080F4AF002A034D /* RPCPermissionsManager.swift */,
+ 88B849C620812412002A034D /* VehicleDataManager.swift */,
+ );
+ name = SDL;
+ sourceTree = "<group>";
+ };
+ 8829567A207CF49600EF056C /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 8829569D207CFD0E00EF056C /* AppDelegate.swift */,
+ 88A0AA61207CFF970075132C /* LaunchScreen.xib */,
+ 88295698207CF68800EF056C /* SmartDeviceLink-Example-Swift-Info.plist */,
+ 8829569C207CFD0D00EF056C /* SmartDeviceLink-Example-Swift-Bridging-Header.h */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ 8829567B207CF49F00EF056C /* UI */ = {
+ isa = PBXGroup;
+ children = (
+ 88A0AA5F207CFEA60075132C /* Connection */,
+ 88A0AA59207CFE740075132C /* ConnectionContainerViewController.swift */,
+ 88A0AA5A207CFE740075132C /* ConnectionIAPTableViewController.swift */,
+ 88A0AA5B207CFE740075132C /* ConnectionTCPTableViewController.swift */,
+ );
+ name = UI;
+ sourceTree = "<group>";
+ };
+ 8829567C207CF4AB00EF056C /* Utilities */ = {
+ isa = PBXGroup;
+ children = (
+ 88A0AA55207CFE5C0075132C /* AppUserDefaults.swift */,
+ 88DFB051207F8DF50079D19D /* Protocol+ProxyManagerDelegate.swift */,
+ );
+ name = Utilities;
+ sourceTree = "<group>";
+ };
+ 88295699207CFBD900EF056C /* Shared Assets */ = {
+ isa = PBXGroup;
+ children = (
+ 5D4029D31A76F0340006B0C2 /* Images.xcassets */,
+ 8863B596207D2388002D6459 /* AppConstants.h */,
+ 8863B597207D2388002D6459 /* AppConstants.m */,
+ );
+ name = "Shared Assets";
+ sourceTree = "<group>";
+ };
+ 88A0AA5F207CFEA60075132C /* Connection */ = {
+ isa = PBXGroup;
+ children = (
+ 88A0AA60207CFEAC0075132C /* Storyboards */,
+ );
+ name = Connection;
+ sourceTree = "<group>";
+ };
+ 88A0AA60207CFEAC0075132C /* Storyboards */ = {
+ isa = PBXGroup;
+ children = (
+ 88A0AA63207CFF970075132C /* ConnectionIAPTableViewController.storyboard */,
+ 88A0AA64207CFF980075132C /* ConnectionTCPTableViewController.storyboard */,
+ 88A0AA62207CFF970075132C /* Main.storyboard */,
+ );
+ name = Storyboards;
+ sourceTree = "<group>";
+ };
88B848C41F45E20900DED768 /* Helpers */ = {
isa = PBXGroup;
children = (
@@ -4885,14 +5093,6 @@
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
- 5D43465E1E6F38E600B639C6 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 5D4346651E6F38E600B639C6 /* SmartDeviceLinkSwift.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
5D61FA191A84237100846EE7 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
@@ -5158,7 +5358,7 @@
5DD67CB81E661C4A009CD394 /* SDLLogTargetFile.h in Headers */,
5D61FD591A84238C00846EE7 /* SDLReadDID.h in Headers */,
5D82041A1BCD80BA00D0A41B /* SDLLockScreenConfiguration.h in Headers */,
- 880E8C2920697FEE00CF86C2 /* SDLSystemCapabilityManager.h in Headers */,
+ 880E35B52088F75A00181259 /* SDLSystemCapabilityManager.h in Headers */,
5D61FC611A84238C00846EE7 /* SDLChoice.h in Headers */,
5D1BF6AF204742FB00D36881 /* SDLDisplayCapabilities+ShowManagerExtensions.h in Headers */,
5D7F87F31CE3C29E002DD7C4 /* SDLFileWrapper.h in Headers */,
@@ -5308,12 +5508,20 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 88802E5320853AE600E9EBC6 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 88802FF420853BED00E9EBC6 /* SmartDeviceLinkSwift.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
- 5D4019AE1A76EC350006B0C2 /* SmartDeviceLink-Example */ = {
+ 5D4019AE1A76EC350006B0C2 /* SmartDeviceLink-Example-ObjC */ = {
isa = PBXNativeTarget;
- buildConfigurationList = 5D4019D21A76EC350006B0C2 /* Build configuration list for PBXNativeTarget "SmartDeviceLink-Example" */;
+ buildConfigurationList = 5D4019D21A76EC350006B0C2 /* Build configuration list for PBXNativeTarget "SmartDeviceLink-Example-ObjC" */;
buildPhases = (
5D4019AB1A76EC350006B0C2 /* Sources */,
5D4019AC1A76EC350006B0C2 /* Frameworks */,
@@ -5325,30 +5533,11 @@
dependencies = (
5D61FA321A84237100846EE7 /* PBXTargetDependency */,
);
- name = "SmartDeviceLink-Example";
+ name = "SmartDeviceLink-Example-ObjC";
productName = "SmartDeviceLink-iOS";
productReference = 5D4019AF1A76EC350006B0C2 /* SDL Example.app */;
productType = "com.apple.product-type.application";
};
- 5D4346601E6F38E600B639C6 /* SmartDeviceLinkSwift */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 5D4346661E6F38E600B639C6 /* Build configuration list for PBXNativeTarget "SmartDeviceLinkSwift" */;
- buildPhases = (
- 5D43465C1E6F38E600B639C6 /* Sources */,
- 5D43465D1E6F38E600B639C6 /* Frameworks */,
- 5D43465E1E6F38E600B639C6 /* Headers */,
- 5D43465F1E6F38E600B639C6 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- 5D43468C1E788E2200B639C6 /* PBXTargetDependency */,
- );
- name = SmartDeviceLinkSwift;
- productName = SmartDeviceLinkSwift;
- productReference = 5D4346611E6F38E600B639C6 /* SmartDeviceLinkSwift.framework */;
- productType = "com.apple.product-type.framework";
- };
5D61FA1B1A84237100846EE7 /* SmartDeviceLink */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5D61FA351A84237100846EE7 /* Build configuration list for PBXNativeTarget "SmartDeviceLink" */;
@@ -5387,6 +5576,45 @@
productReference = 5D61FA261A84237100846EE7 /* SmartDeviceLinkTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
+ 8829567D207CF68800EF056C /* SmartDeviceLink-Example-Swift */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 88295694207CF68800EF056C /* Build configuration list for PBXNativeTarget "SmartDeviceLink-Example-Swift" */;
+ buildPhases = (
+ 88295680207CF68800EF056C /* Sources */,
+ 8829568A207CF68800EF056C /* Frameworks */,
+ 8829568C207CF68800EF056C /* Resources */,
+ 88295692207CF68800EF056C /* Embed Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 8829567E207CF68800EF056C /* PBXTargetDependency */,
+ 88802FF820853CD500E9EBC6 /* PBXTargetDependency */,
+ );
+ name = "SmartDeviceLink-Example-Swift";
+ productName = "SmartDeviceLink-iOS";
+ productReference = 88295697207CF68800EF056C /* SDL Example.app */;
+ productType = "com.apple.product-type.application";
+ };
+ 88802CD720853AE600E9EBC6 /* SmartDeviceLinkSwift */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 88802FEC20853AE600E9EBC6 /* Build configuration list for PBXNativeTarget "SmartDeviceLinkSwift" */;
+ buildPhases = (
+ 88802CD820853AE600E9EBC6 /* Sources */,
+ 88802E5220853AE600E9EBC6 /* Frameworks */,
+ 88802E5320853AE600E9EBC6 /* Headers */,
+ 88802FE820853AE600E9EBC6 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 88802FF320853BBF00E9EBC6 /* PBXTargetDependency */,
+ );
+ name = SmartDeviceLinkSwift;
+ productName = SmartDeviceLink;
+ productReference = 88802FEF20853AE600E9EBC6 /* SmartDeviceLinkSwift.framework */;
+ productType = "com.apple.product-type.framework";
+ };
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -5410,11 +5638,6 @@
};
};
};
- 5D4346601E6F38E600B639C6 = {
- CreatedOnToolsVersion = 8.2.1;
- LastSwiftMigration = 0900;
- ProvisioningStyle = Automatic;
- };
5D61FA1B1A84237100846EE7 = {
CreatedOnToolsVersion = 6.1.1;
LastSwiftMigration = 0930;
@@ -5423,6 +5646,9 @@
CreatedOnToolsVersion = 6.1.1;
LastSwiftMigration = 0920;
};
+ 8829567D207CF68800EF056C = {
+ LastSwiftMigration = 0930;
+ };
};
};
buildConfigurationList = 5D4019AA1A76EC350006B0C2 /* Build configuration list for PBXProject "SmartDeviceLink-iOS" */;
@@ -5438,10 +5664,11 @@
projectDirPath = "";
projectRoot = "";
targets = (
- 5D4019AE1A76EC350006B0C2 /* SmartDeviceLink-Example */,
5D61FA1B1A84237100846EE7 /* SmartDeviceLink */,
5D61FA251A84237100846EE7 /* SmartDeviceLinkTests */,
- 5D4346601E6F38E600B639C6 /* SmartDeviceLinkSwift */,
+ 5D4019AE1A76EC350006B0C2 /* SmartDeviceLink-Example-ObjC */,
+ 8829567D207CF68800EF056C /* SmartDeviceLink-Example-Swift */,
+ 88802CD720853AE600E9EBC6 /* SmartDeviceLinkSwift */,
);
};
/* End PBXProject section */
@@ -5459,13 +5686,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 5D43465F1E6F38E600B639C6 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
5D61FA1A1A84237100846EE7 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -5493,6 +5713,28 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 8829568C207CF68800EF056C /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 88A0AA66207CFF980075132C /* Main.storyboard in Resources */,
+ 88A0AA68207CFF980075132C /* ConnectionTCPTableViewController.storyboard in Resources */,
+ 88A0AA65207CFF980075132C /* LaunchScreen.xib in Resources */,
+ 88295690207CF68800EF056C /* Images.xcassets in Resources */,
+ 88A0AA67207CFF980075132C /* ConnectionIAPTableViewController.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 88802FE820853AE600E9EBC6 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 88802FE920853AE600E9EBC6 /* LICENSE in Resources */,
+ 88802FEA20853AE600E9EBC6 /* SDLAssets.xcassets in Resources */,
+ 88802FEB20853AE600E9EBC6 /* SDLLockScreen.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -5501,22 +5743,22 @@
buildActionMask = 2147483647;
files = (
5D4832A51A94F90D00252386 /* ConnectionTransitionContext.m in Sources */,
+ 8800871E20A6356D008E1EA0 /* ButtonManager.m in Sources */,
5D0218FC1A8E7E1700D1BF62 /* ConnectionContainerViewController.m in Sources */,
+ 88DA6D10209794A400AD8297 /* AlertManager.m in Sources */,
+ 8803A0AF208E2A3A009FDC02 /* AudioManager.m in Sources */,
5D0218FF1A8E9E0D00D1BF62 /* ConnectionIAPTableViewController.m in Sources */,
+ 8803A0B2208E7CA4009FDC02 /* VehicleDataManager.m in Sources */,
5D48329D1A8EA33D00252386 /* Preferences.m in Sources */,
+ 8814AEA720AB65FC00466E0F /* MenuManager.m in Sources */,
+ 8814AEAA20AB663800466E0F /* PerformInteractionManager.m in Sources */,
5D59350F1A855EB300687FB9 /* AppDelegate.m in Sources */,
5D5935121A855EBE00687FB9 /* main.m in Sources */,
5D4832A81A95191B00252386 /* ConnectionAnimatedTransition.m in Sources */,
+ 88DE80B720A5C8DD00BA9CF0 /* RPCPermissionsManager.m in Sources */,
5D4832A11A92868E00252386 /* ProxyManager.m in Sources */,
5D0218F61A8E79C400D1BF62 /* ConnectionTCPTableViewController.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 5D43465C1E6F38E600B639C6 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 5D4346861E771B5700B639C6 /* SDLLog.swift in Sources */,
+ 8863B59D207D3849002D6459 /* AppConstants.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -5890,7 +6132,7 @@
5D61FC931A84238C00846EE7 /* SDLDisplayType.m in Sources */,
5D61FCE31A84238C00846EE7 /* SDLKeyboardLayout.m in Sources */,
5D61FE0C1A84238C00846EE7 /* SDLVehicleType.m in Sources */,
- 880E8C2A20697FEE00CF86C2 /* SDLSystemCapabilityManager.m in Sources */,
+ 880E35B42088F75A00181259 /* SDLSystemCapabilityManager.m in Sources */,
DA9F7E941DCC04E400ACAE48 /* SDLUnsubscribeWayPoints.m in Sources */,
5D61FDCC1A84238C00846EE7 /* SDLTextFieldName.m in Sources */,
5D61FC751A84238C00846EE7 /* SDLDeleteCommandResponse.m in Sources */,
@@ -5985,7 +6227,7 @@
162E836E1A9BDE8B00906325 /* SDLUnsubscribeButtonResponseSpec.m in Sources */,
5DEF69611FD6FB75004B8C2F /* SDLAudioStreamManagerSpec.m in Sources */,
162E835B1A9BDE8B00906325 /* SDLPerformInteractionResponseSpec.m in Sources */,
- 886D313F206A956B001185B4 /* SDLSystemCapabilityManagerSpec.m in Sources */,
+ 880E35B82088F78E00181259 /* SDLSystemCapabilityManagerSpec.m in Sources */,
162E832D1A9BDE8B00906325 /* SDLEncodedSyncPDataSpec.m in Sources */,
1EE8C44C1F385C7100FDC2CF /* SDLRDSDataSpec.m in Sources */,
5DB92D241AC47B2C00C15BB0 /* SDLHexUtilitySpec.m in Sources */,
@@ -6264,14 +6506,39 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 88295680207CF68800EF056C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 88A0AA5C207CFE740075132C /* ConnectionContainerViewController.swift in Sources */,
+ 88B849C52080F4B3002A034D /* RPCPermissionsManager.swift in Sources */,
+ 8870C3EA208662540070E018 /* AudioManager.swift in Sources */,
+ 88DFB055207F96EE0079D19D /* AlertManager.swift in Sources */,
+ 888D178F207E7F42008E9F8F /* ButtonManager.swift in Sources */,
+ 88A0AA5E207CFE740075132C /* ConnectionTCPTableViewController.swift in Sources */,
+ 88DFB053207F8E100079D19D /* Protocol+ProxyManagerDelegate.swift in Sources */,
+ 88B849C820812442002A034D /* VehicleDataManager.swift in Sources */,
+ 8829569E207CFD0E00EF056C /* AppDelegate.swift in Sources */,
+ 88A0AA58207CFE650075132C /* ProxyManager.swift in Sources */,
+ 88166B00207E41E900076236 /* MenuManager.swift in Sources */,
+ 8814AEAC20AB667B00466E0F /* PerformInteractionManager.swift in Sources */,
+ 888D1790207E815C008E9F8F /* AppConstants.m in Sources */,
+ 88A0AA5D207CFE740075132C /* ConnectionIAPTableViewController.swift in Sources */,
+ 88A0AA56207CFE5D0075132C /* AppUserDefaults.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 88802CD820853AE600E9EBC6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 88802FF120853BB700E9EBC6 /* SDLLog.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
- 5D43468C1E788E2200B639C6 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 5D61FA1B1A84237100846EE7 /* SmartDeviceLink */;
- targetProxy = 5D43468B1E788E2200B639C6 /* PBXContainerItemProxy */;
- };
5D61FA291A84237100846EE7 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5D61FA1B1A84237100846EE7 /* SmartDeviceLink */;
@@ -6279,7 +6546,7 @@
};
5D61FA2B1A84237100846EE7 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = 5D4019AE1A76EC350006B0C2 /* SmartDeviceLink-Example */;
+ target = 5D4019AE1A76EC350006B0C2 /* SmartDeviceLink-Example-ObjC */;
targetProxy = 5D61FA2A1A84237100846EE7 /* PBXContainerItemProxy */;
};
5D61FA321A84237100846EE7 /* PBXTargetDependency */ = {
@@ -6287,6 +6554,21 @@
target = 5D61FA1B1A84237100846EE7 /* SmartDeviceLink */;
targetProxy = 5D61FA311A84237100846EE7 /* PBXContainerItemProxy */;
};
+ 8829567E207CF68800EF056C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 5D61FA1B1A84237100846EE7 /* SmartDeviceLink */;
+ targetProxy = 8829567F207CF68800EF056C /* PBXContainerItemProxy */;
+ };
+ 88802FF320853BBF00E9EBC6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 5D61FA1B1A84237100846EE7 /* SmartDeviceLink */;
+ targetProxy = 88802FF220853BBF00E9EBC6 /* PBXContainerItemProxy */;
+ };
+ 88802FF820853CD500E9EBC6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 88802CD720853AE600E9EBC6 /* SmartDeviceLinkSwift */;
+ targetProxy = 88802FF720853CD500E9EBC6 /* PBXContainerItemProxy */;
+ };
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
@@ -6450,7 +6732,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
DEVELOPMENT_TEAM = NCVC2MHU7M;
- INFOPLIST_FILE = "$(SRCROOT)/SmartDeviceLink_Example/Info.plist";
+ INFOPLIST_FILE = "$(SRCROOT)/SmartDeviceLink_Example/SmartDeviceLink-Example-ObjC-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.smartdevicelink.SDLTestApp;
@@ -6464,7 +6746,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
DEVELOPMENT_TEAM = NCVC2MHU7M;
- INFOPLIST_FILE = "$(SRCROOT)/SmartDeviceLink_Example/Info.plist";
+ INFOPLIST_FILE = "$(SRCROOT)/SmartDeviceLink_Example/SmartDeviceLink-Example-ObjC-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.smartdevicelink.SDLTestApp;
@@ -6472,65 +6754,6 @@
};
name = Release;
};
- 5D4346671E6F38E600B639C6 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ENABLE_MODULES = YES;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CODE_SIGN_IDENTITY = "";
- CURRENT_PROJECT_VERSION = 1;
- DEBUG_INFORMATION_FORMAT = dwarf;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- INFOPLIST_FILE = SmartDeviceLinkSwift/Info.plist;
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
- PRODUCT_BUNDLE_IDENTIFIER = com.smartdevicelink.SmartDeviceLinkSwift;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SKIP_INSTALL = YES;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- SWIFT_SWIFT3_OBJC_INFERENCE = On;
- SWIFT_VERSION = 4.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- VERSIONING_SYSTEM = "apple-generic";
- VERSION_INFO_PREFIX = "";
- };
- name = Debug;
- };
- 5D4346681E6F38E600B639C6 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ENABLE_MODULES = YES;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CODE_SIGN_IDENTITY = "";
- COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 1;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- INFOPLIST_FILE = SmartDeviceLinkSwift/Info.plist;
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
- PRODUCT_BUNDLE_IDENTIFIER = com.smartdevicelink.SmartDeviceLinkSwift;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SKIP_INSTALL = YES;
- SWIFT_SWIFT3_OBJC_INFERENCE = On;
- SWIFT_VERSION = 4.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- VERSIONING_SYSTEM = "apple-generic";
- VERSION_INFO_PREFIX = "";
- };
- name = Release;
- };
5D61FA361A84237100846EE7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -6628,7 +6851,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- DEVELOPMENT_TEAM = "";
+ DEVELOPMENT_TEAM = NCVC2MHU7M;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
@@ -6664,7 +6887,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- DEVELOPMENT_TEAM = "";
+ DEVELOPMENT_TEAM = NCVC2MHU7M;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
@@ -6690,6 +6913,142 @@
};
name = Release;
};
+ 88295695207CF68800EF056C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ DEVELOPMENT_TEAM = NCVC2MHU7M;
+ INFOPLIST_FILE = "SmartDeviceLink-Example-Swift-Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.smartdevicelink.SDLTestApp;
+ PRODUCT_NAME = "SDL Example";
+ SWIFT_OBJC_BRIDGING_HEADER = "SmartDeviceLink_Example/SmartDeviceLink-Example-Swift-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 3.0;
+ };
+ name = Debug;
+ };
+ 88295696207CF68800EF056C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ DEVELOPMENT_TEAM = NCVC2MHU7M;
+ INFOPLIST_FILE = "SmartDeviceLink-Example-Swift-Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.smartdevicelink.SDLTestApp;
+ PRODUCT_NAME = "SDL Example";
+ SWIFT_OBJC_BRIDGING_HEADER = "SmartDeviceLink_Example/SmartDeviceLink-Example-Swift-Bridging-Header.h";
+ SWIFT_VERSION = 3.0;
+ };
+ name = Release;
+ };
+ 88802FED20853AE600E9EBC6 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_STATIC_ANALYZER_MODE = deep;
+ CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES;
+ CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_FLOAT_CONVERSION = YES;
+ CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = NCVC2MHU7M;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ FRAMEWORK_SEARCH_PATHS = "$(inherited)";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+ GCC_WARN_SIGN_COMPARE = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = YES;
+ INFOPLIST_FILE = SmartDeviceLinkSwift/Info.plist;
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ LIBRARY_SEARCH_PATHS = "$(inherited)";
+ PRODUCT_BUNDLE_IDENTIFIER = com.smartdevicelink.SmartDeviceLinkSwift;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ RUN_CLANG_STATIC_ANALYZER = YES;
+ SKIP_INSTALL = YES;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_SWIFT3_OBJC_INFERENCE = On;
+ SWIFT_VERSION = 4.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Debug;
+ };
+ 88802FEE20853AE600E9EBC6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_STATIC_ANALYZER_MODE = deep;
+ CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES;
+ CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_FLOAT_CONVERSION = YES;
+ CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = NCVC2MHU7M;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ FRAMEWORK_SEARCH_PATHS = "$(inherited)";
+ GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+ GCC_WARN_SIGN_COMPARE = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = YES;
+ INFOPLIST_FILE = SmartDeviceLinkSwift/Info.plist;
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ LIBRARY_SEARCH_PATHS = "$(inherited)";
+ PRODUCT_BUNDLE_IDENTIFIER = com.smartdevicelink.SmartDeviceLinkSwift;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ RUN_CLANG_STATIC_ANALYZER = YES;
+ SKIP_INSTALL = YES;
+ SWIFT_SWIFT3_OBJC_INFERENCE = On;
+ SWIFT_VERSION = 4.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Release;
+ };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -6702,7 +7061,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 5D4019D21A76EC350006B0C2 /* Build configuration list for PBXNativeTarget "SmartDeviceLink-Example" */ = {
+ 5D4019D21A76EC350006B0C2 /* Build configuration list for PBXNativeTarget "SmartDeviceLink-Example-ObjC" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5D4019D31A76EC350006B0C2 /* Debug */,
@@ -6711,15 +7070,6 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 5D4346661E6F38E600B639C6 /* Build configuration list for PBXNativeTarget "SmartDeviceLinkSwift" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 5D4346671E6F38E600B639C6 /* Debug */,
- 5D4346681E6F38E600B639C6 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
5D61FA351A84237100846EE7 /* Build configuration list for PBXNativeTarget "SmartDeviceLink" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -6738,6 +7088,24 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ 88295694207CF68800EF056C /* Build configuration list for PBXNativeTarget "SmartDeviceLink-Example-Swift" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 88295695207CF68800EF056C /* Debug */,
+ 88295696207CF68800EF056C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 88802FEC20853AE600E9EBC6 /* Build configuration list for PBXNativeTarget "SmartDeviceLinkSwift" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 88802FED20853AE600E9EBC6 /* Debug */,
+ 88802FEE20853AE600E9EBC6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
/* End XCConfigurationList section */
};
rootObject = 5D4019A71A76EC350006B0C2 /* Project object */;
diff --git a/SmartDeviceLink_Example/AlertManager.h b/SmartDeviceLink_Example/AlertManager.h
new file mode 100644
index 000000000..1d4471b95
--- /dev/null
+++ b/SmartDeviceLink_Example/AlertManager.h
@@ -0,0 +1,22 @@
+//
+// AlertManager.h
+// SmartDeviceLink-Example-ObjC
+//
+// Created by Nicole on 4/30/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@class SDLAlert;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface AlertManager : NSObject
+
++ (SDLAlert *)alertWithMessage:(NSString *)textField1 textField2:(nullable NSString *)textField2;
++ (SDLAlert *)alertWithMessageAndCloseButton:(NSString *)textField1 textField2:(nullable NSString *)textField2;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/AlertManager.m b/SmartDeviceLink_Example/AlertManager.m
new file mode 100644
index 000000000..cab877a5e
--- /dev/null
+++ b/SmartDeviceLink_Example/AlertManager.m
@@ -0,0 +1,45 @@
+//
+// AlertManager.m
+// SmartDeviceLink-Example-ObjC
+//
+// Created by Nicole on 4/30/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import "AlertManager.h"
+#import "SmartDeviceLink.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation AlertManager
+
+/**
+ * Creates an alert with a single line of text
+ *
+ * @param textField1 The first line of a message to display in the alert
+ * @param textField2 The second line of a message to display in the alert
+ * @return An SDLAlert object
+ */
++ (SDLAlert *)alertWithMessage:(NSString *)textField1 textField2:(nullable NSString *)textField2 {
+ return [[SDLAlert alloc] initWithAlertText1:textField1 alertText2:textField2 duration:5000];
+}
+
+/**
+ * Creates an alert with up to two lines of text and a close button that will dismiss the alert when tapped
+ *
+ * @param textField1 The first line of a message to display in the alert
+ * @param textField2 The second line of a message to display in the alert
+ * @return An SDLAlert object
+ */
++ (SDLAlert *)alertWithMessageAndCloseButton:(NSString *)textField1 textField2:(nullable NSString *)textField2 {
+ return [[SDLAlert alloc] initWithAlertText1:textField1 alertText2:textField2 alertText3:nil duration:5000 softButtons:@[[self sdlex_okSoftButton]]];
+}
+
++ (SDLSoftButton *)sdlex_okSoftButton {
+ SDLSoftButton *okSoftButton = [[SDLSoftButton alloc] initWithType:SDLSoftButtonTypeText text:@"OK" image:nil highlighted:YES buttonId:1 systemAction:nil handler:nil];
+ return okSoftButton;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/AlertManager.swift b/SmartDeviceLink_Example/AlertManager.swift
new file mode 100644
index 000000000..c463e7d36
--- /dev/null
+++ b/SmartDeviceLink_Example/AlertManager.swift
@@ -0,0 +1,36 @@
+//
+// AlertManager.swift
+// SmartDeviceLink-Example-Swift
+//
+// Created by Nicole on 4/12/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+import Foundation
+import SmartDeviceLink
+
+class AlertManager {
+ private class var okSoftButton: SDLSoftButton {
+ return SDLSoftButton(type: .text, text: "OK", image: nil, highlighted: true, buttonId: 1, systemAction: nil, handler: nil)
+ }
+
+ /// Creates an alert with one or two lines of text.
+ ///
+ /// - Parameters:
+ /// - textField1: The first line of a message to display in the alert
+ /// - textField2: The second line of a message to display in the alert
+ /// - Returns: An SDLAlert object
+ class func alertWithMessage(_ textField1: String, textField2: String? = nil) -> SDLAlert {
+ return SDLAlert(alertText1: textField1, alertText2: nil, alertText3: nil)
+ }
+
+ /// Creates an alert with up to two lines of text and a close button that will dismiss the alert when tapped
+ ///
+ /// - Parameters:
+ /// - textField1: The first line of a message to display in the alert
+ /// - textField2: The second line of a message to display in the alert
+ /// - Returns: An SDLAlert object
+ class func alertWithMessageAndCloseButton(_ textField1: String, textField2: String? = nil) -> SDLAlert {
+ return SDLAlert(alertText1: textField1, alertText2: textField2, alertText3: nil, duration: 5000, softButtons: [AlertManager.okSoftButton])
+ }
+}
diff --git a/SmartDeviceLink_Example/AppConstants.h b/SmartDeviceLink_Example/AppConstants.h
new file mode 100644
index 000000000..c38b1b70b
--- /dev/null
+++ b/SmartDeviceLink_Example/AppConstants.h
@@ -0,0 +1,100 @@
+//
+// AppConstants.h
+// SmartDeviceLink
+//
+// Created by Nicole on 4/10/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - SDL Configuration
+extern NSString * const ExampleAppName;
+extern NSString * const ExampleAppNameShort;
+extern NSString * const ExampleAppNameTTS;
+extern NSString * const ExampleAppId;
+extern BOOL const ExampleAppShouldRestartSDLManagerOnDisconnect;
+
+#pragma mark - SDL Textfields
+extern NSString * const SmartDeviceLinkText;
+extern NSString * const ExampleAppText;
+
+#pragma mark - SDL Soft Buttons
+extern NSString * const ToggleSoftButton;
+extern NSString * const ToggleSoftButtonImageOnState;
+extern NSString * const ToggleSoftButtonImageOffState;
+extern NSString * const ToggleSoftButtonTextOnState;
+extern NSString * const ToggleSoftButtonTextOffState;
+extern NSString * const ToggleSoftButtonTextTextOnText;
+extern NSString * const ToggleSoftButtonTextTextOffText;
+
+extern NSString * const AlertSoftButton;
+extern NSString * const AlertSoftButtonImageState;
+extern NSString * const AlertSoftButtonTextState;
+extern NSString * const AlertSoftButtonText;
+
+extern NSString * const TextVisibleSoftButton;
+extern NSString * const TextVisibleSoftButtonTextOnState;
+extern NSString * const TextVisibleSoftButtonTextOffState;
+extern NSString * const TextVisibleSoftButtonTextOnText;
+extern NSString * const TextVisibleSoftButtonTextOffText;
+
+extern NSString * const ImagesVisibleSoftButton;
+extern NSString * const ImagesVisibleSoftButtonImageOnState;
+extern NSString * const ImagesVisibleSoftButtonImageOffState;
+extern NSString * const ImagesVisibleSoftButtonImageOnText;
+extern NSString * const ImagesVisibleSoftButtonImageOffText;
+
+#pragma martk - SDL Text-To-Speech
+extern NSString * const TTSGoodJob;
+extern NSString * const TTSYouMissed;
+
+#pragma martk - SDL Voice Commands
+extern NSString * const VCStart;
+extern NSString * const VCStop;
+
+#pragma mark - SDL Perform Interaction Choice Set Menu
+extern NSString * const PICSInitialText;
+extern NSString * const PICSInitialPrompt;
+extern NSString * const PICSHelpPrompt;
+extern NSString * const PICSTimeoutPrompt;
+extern NSString * const PICSFirstChoice;
+extern NSString * const PICSSecondChoice;
+extern NSString * const PICSThirdChoice;
+
+#pragma mark - SDL Add Command Menu
+extern NSString * const ACSpeakAppNameMenuName;
+extern NSString * const ACShowChoiceSetMenuName;
+extern NSString * const ACGetVehicleDataMenuName;
+extern NSString * const ACRecordInCarMicrophoneAudioMenuName;
+extern NSString * const ACDialPhoneNumberMenuName;
+extern NSString * const ACSubmenuMenuName;
+extern NSString * const ACSubmenuItemMenuName;
+
+
+#pragma mark - SDL Image Names
+extern NSString * const ExampleAppLogoName;
+extern NSString * const CarIconImageName;
+extern NSString * const LaptopIconImageName;
+extern NSString * const WheelIconImageName;
+extern NSString * const SpeakBWIconImageName;
+extern NSString * const CarBWIconImageName;
+extern NSString * const MenuBWIconImageName;
+extern NSString * const PhoneBWIconImageName;
+extern NSString * const MicrophoneBWIconImageName;
+
+#pragma mark - SDL App Name in Different Languages
+extern NSString * const ExampleAppNameSpanish;
+extern NSString * const ExampleAppNameFrench;
+
+#pragma mark - SDL Vehicle Data
+extern NSString * const VehicleDataOdometerName;
+extern NSString * const VehicleDataSpeedName;
+
+@interface AppConstants : NSObject
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/AppConstants.m b/SmartDeviceLink_Example/AppConstants.m
new file mode 100644
index 000000000..c9ff9ad91
--- /dev/null
+++ b/SmartDeviceLink_Example/AppConstants.m
@@ -0,0 +1,95 @@
+//
+// AppConstants.m
+// SmartDeviceLink
+//
+// Created by Nicole on 4/10/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import "AppConstants.h"
+
+#pragma mark - SDL Configuration
+NSString * const ExampleAppName = @"SDL Example App";
+NSString * const ExampleAppNameShort = @"SDL";
+NSString * const ExampleAppNameTTS = @"S D L Example App";
+NSString * const ExampleAppId = @"9c21";
+BOOL const ExampleAppShouldRestartSDLManagerOnDisconnect = NO;
+
+#pragma mark - SDL Textfields
+NSString * const SmartDeviceLinkText = @"SmartDeviceLink (SDL)";
+NSString * const ExampleAppText = @"Example App";
+
+#pragma mark - SDL Soft Buttons
+NSString * const ToggleSoftButton = @"ToggleSoftButton";
+NSString * const ToggleSoftButtonImageOnState = @"ToggleSoftButtonImageOnState";
+NSString * const ToggleSoftButtonImageOffState = @"ToggleSoftButtonImageOffState";
+NSString * const ToggleSoftButtonTextOnState = @"ToggleSoftButtonTextOnState";
+NSString * const ToggleSoftButtonTextOffState = @"ToggleSoftButtonTextOffState";
+NSString * const ToggleSoftButtonTextTextOnText = @"➖";
+NSString * const ToggleSoftButtonTextTextOffText = @"➕";
+
+NSString * const AlertSoftButton = @"AlertSoftButton";
+NSString * const AlertSoftButtonImageState = @"AlertSoftButtonImageState";
+NSString * const AlertSoftButtonTextState = @"AlertSoftButtonTextState";
+NSString * const AlertSoftButtonText = @"Tap Me";
+
+NSString * const TextVisibleSoftButton = @"TextVisibleSoftButton";
+NSString * const TextVisibleSoftButtonTextOnState = @"TextVisibleSoftButtonTextOnState";
+NSString * const TextVisibleSoftButtonTextOffState = @"TextVisibleSoftButtonTextOffState";
+NSString * const TextVisibleSoftButtonTextOnText = @"➖Text";
+NSString * const TextVisibleSoftButtonTextOffText = @"➕Text";
+
+NSString * const ImagesVisibleSoftButton = @"ImagesVisibleSoftButton";
+NSString * const ImagesVisibleSoftButtonImageOnState = @"ImagesVisibleSoftButtonImageOnState";
+NSString * const ImagesVisibleSoftButtonImageOffState = @"ImagesVisibleSoftButtonImageOffState";
+NSString * const ImagesVisibleSoftButtonImageOnText = @"➖Icons";
+NSString * const ImagesVisibleSoftButtonImageOffText = @"➕Icons";
+
+#pragma mart - SDL Text-To-Speech
+NSString * const TTSGoodJob = @"Good Job";
+NSString * const TTSYouMissed = @"You Missed";
+
+#pragma martk - SDL Voice Commands
+NSString * const VCStart = @"Start";
+NSString * const VCStop = @"Stop";
+
+#pragma mark - SDL Perform Interaction Choice Set Menu
+NSString * const PICSInitialText = @"Perform Interaction Choice Set Menu Example";
+NSString * const PICSInitialPrompt = @"Select an item from the menu";
+NSString * const PICSHelpPrompt = @"Select a menu row using your voice or by tapping on the screen";
+NSString * const PICSTimeoutPrompt = @"Closing the menu";
+NSString * const PICSFirstChoice = @"First Choice";
+NSString * const PICSSecondChoice = @"Second Choice";
+NSString * const PICSThirdChoice = @"Third Choice";
+
+#pragma mark - SDL Add Command Menu
+NSString * const ACSpeakAppNameMenuName = @"Speak App Name";
+NSString * const ACShowChoiceSetMenuName = @"Show Perform Interaction Choice Set";
+NSString * const ACGetVehicleDataMenuName = @"Get Vehicle Speed";
+NSString * const ACRecordInCarMicrophoneAudioMenuName = @"Record In-Car Microphone Audio";
+NSString * const ACDialPhoneNumberMenuName = @"Dial Phone Number";
+NSString * const ACSubmenuMenuName = @"Submenu";
+NSString * const ACSubmenuItemMenuName = @"Item";
+
+#pragma mark - SDL Image Names
+NSString * const ExampleAppLogoName = @"sdl_logo_green";
+NSString * const CarIconImageName = @"car_icon";
+NSString * const LaptopIconImageName = @"laptop_icon";
+NSString * const WheelIconImageName = @"wheel_icon";
+NSString * const SpeakBWIconImageName = @"speak";
+NSString * const CarBWIconImageName = @"car";
+NSString * const MenuBWIconImageName = @"choice_set";
+NSString * const PhoneBWIconImageName = @"phone";
+NSString * const MicrophoneBWIconImageName = @"microphone";
+
+#pragma mark - SDL App Name in Different Languages
+NSString * const ExampleAppNameSpanish = @"SDL Aplicación de ejemplo";
+NSString * const ExampleAppNameFrench = @"SDL Exemple App";
+
+#pragma mark - SDL Vehicle Data
+NSString * const VehicleDataOdometerName = @"Odometer";
+NSString * const VehicleDataSpeedName = @"Speed";
+
+@implementation AppConstants
+
+@end
diff --git a/SmartDeviceLink_Example/Classes/AppDelegate.h b/SmartDeviceLink_Example/AppDelegate.h
index b86efb1a6..b86efb1a6 100644
--- a/SmartDeviceLink_Example/Classes/AppDelegate.h
+++ b/SmartDeviceLink_Example/AppDelegate.h
diff --git a/SmartDeviceLink_Example/Classes/AppDelegate.m b/SmartDeviceLink_Example/AppDelegate.m
index 1ceb6f765..1ceb6f765 100644
--- a/SmartDeviceLink_Example/Classes/AppDelegate.m
+++ b/SmartDeviceLink_Example/AppDelegate.m
diff --git a/SmartDeviceLink_Example/AppDelegate.swift b/SmartDeviceLink_Example/AppDelegate.swift
new file mode 100644
index 000000000..fd42468d3
--- /dev/null
+++ b/SmartDeviceLink_Example/AppDelegate.swift
@@ -0,0 +1,44 @@
+//
+// AppDelegate.swift
+// SmartDeviceLink-ExampleSwift
+//
+// Created by Bretty White on 5/12/17.
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+import UIKit
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ var window: UIWindow?
+
+ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
+
+ AppUserDefaults.setDefaults()
+
+ return true
+ }
+
+ func applicationWillResignActive(_ application: UIApplication) {
+ // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
+ // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
+ }
+
+ func applicationDidEnterBackground(_ application: UIApplication) {
+ // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
+ // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
+ }
+
+ func applicationWillEnterForeground(_ application: UIApplication) {
+ // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
+ }
+
+ func applicationDidBecomeActive(_ application: UIApplication) {
+ // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
+ }
+
+ func applicationWillTerminate(_ application: UIApplication) {
+ // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
+ }
+}
diff --git a/SmartDeviceLink_Example/AppUserDefaults.swift b/SmartDeviceLink_Example/AppUserDefaults.swift
new file mode 100644
index 000000000..2589ab467
--- /dev/null
+++ b/SmartDeviceLink_Example/AppUserDefaults.swift
@@ -0,0 +1,43 @@
+//
+// ESUserDefaults.swift
+// SmartDeviceLink-iOS
+//
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+import UIKit
+
+class AppUserDefaults {
+ struct Keys {
+ static let ipAddress = "ipAddress"
+ static let port = "port"
+ }
+
+ static let shared = AppUserDefaults()
+
+ static func setDefaults() {
+ var defaults: [String : Any] = [:]
+
+ defaults[Keys.ipAddress] = String()
+ defaults[Keys.port] = String()
+
+ UserDefaults.standard.register(defaults: defaults)
+ }
+
+ var ipAddress: String? {
+ get {
+ return UserDefaults.standard.string(forKey: Keys.ipAddress)
+ }
+ set {
+ UserDefaults.standard.set(newValue!, forKey: Keys.ipAddress)
+ }
+ }
+
+ var port: String? {
+ get {
+ return UserDefaults.standard.string(forKey: Keys.port)
+ }
+ set {
+ UserDefaults.standard.setValue(newValue!, forKeyPath: Keys.port)
+ }
+ }
+}
diff --git a/SmartDeviceLink_Example/AudioManager.h b/SmartDeviceLink_Example/AudioManager.h
new file mode 100644
index 000000000..b02138e2c
--- /dev/null
+++ b/SmartDeviceLink_Example/AudioManager.h
@@ -0,0 +1,26 @@
+//
+// AudioManager.h
+// SmartDeviceLink
+//
+// Created by Nicole on 4/23/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@class SDLManager;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface AudioManager : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+- (instancetype)initWithManager:(SDLManager *)manager;
+- (void)stopManager;
+
+- (void)startRecording;
+- (void)stopRecording;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/AudioManager.m b/SmartDeviceLink_Example/AudioManager.m
new file mode 100644
index 000000000..6d1b66c48
--- /dev/null
+++ b/SmartDeviceLink_Example/AudioManager.m
@@ -0,0 +1,277 @@
+//
+// AudioManager.m
+// SmartDeviceLink
+//
+// Created by Nicole on 4/23/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import "AlertManager.h"
+#import "AudioManager.h"
+#import <AVFoundation/AVFoundation.h>
+#import "SDLLogMacros.h"
+#import "SmartDeviceLink.h"
+#import <Speech/Speech.h>
+
+
+typedef NS_ENUM(NSUInteger, AudioRecordingState) {
+ AudioRecordingStateListening,
+ AudioRecordingStateNotListening
+};
+
+typedef NS_ENUM(NSUInteger, SpeechRecognitionAuthState) {
+ SpeechRecognitionAuthStateAuthorized,
+ SpeechRecognitionAuthStateNotAuthorized,
+ SpeechRecognitionAuthStateBadRegion
+};
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface AudioManager () <SFSpeechRecognizerDelegate>
+
+@property (strong, nonatomic) SDLManager *sdlManager;
+@property (strong, nonatomic, nullable) NSMutableData *audioData;
+@property (assign, nonatomic) AudioRecordingState audioRecordingState;
+
+@property (assign, nonatomic) SpeechRecognitionAuthState speechRecognitionAuthState;
+@property (strong, nonatomic, nullable) SFSpeechAudioBufferRecognitionRequest *speechRecognitionRequest;
+@property (strong, nonatomic) SFSpeechRecognizer *speechRecognizer;
+@property (strong, nonatomic, nullable) SFSpeechRecognitionTask *speechRecognitionTask;
+@property (strong, nonatomic) NSString *speechTranscription;
+
+@property (nonatomic, copy, nullable) SDLResponseHandler audioPassThruEndedHandler;
+@property (nonatomic, copy, nullable) void (^audioDataReceivedHandler)(NSData *__nullable audioData);
+
+@end
+
+
+@implementation AudioManager
+
+#pragma mark - Lifecycle
+
+- (instancetype)initWithManager:(SDLManager *)manager {
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+
+ _sdlManager = manager;
+ _audioData = [NSMutableData data];
+ _audioRecordingState = AudioRecordingStateNotListening;
+ _speechRecognitionAuthState = SpeechRecognitionAuthStateNotAuthorized;
+ NSLocale *speechDefaultLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en-US"];
+ _speechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:speechDefaultLocale];
+ _speechRecognizer.delegate = self;
+ _speechRecognitionAuthState = [AudioManager sdlex_checkSpeechRecognizerAuth:self.speechRecognizer];
+
+ if (self.speechRecognitionAuthState != SpeechRecognitionAuthStateAuthorized) {
+ [self sdlex_requestSFSpeechRecognizerAuthorization];
+ }
+
+ return self;
+}
+
+/**
+ * Resets the manager
+ */
+- (void)stopManager {
+ self.audioRecordingState = AudioRecordingStateNotListening;
+ self.audioData = [NSMutableData data];
+ self.speechTranscription = @"";
+}
+
+/**
+ * Starts an audio recording using the in-car microphone. During the recording, a pop-up will let the user know that they are being recorded. The pop-up is only dismissed when the recording stops.
+ */
+- (void)startRecording {
+ if (self.speechRecognitionAuthState != SpeechRecognitionAuthStateAuthorized) {
+ SDLLogW(@"This app does not have permission to access the Speech Recognition API");
+ [self.sdlManager sendRequest:[AlertManager alertWithMessageAndCloseButton:@"You must give this app permission to access Speech Recognition" textField2:nil]];
+ return;
+ }
+
+ if (self.audioRecordingState != AudioRecordingStateNotListening) {
+ SDLLogW(@"Audio recording already in progress");
+ return;
+ }
+
+ [self sdlex_startSpeechRecognitionTask];
+
+ UInt32 recordingDurationInMilliseconds = 10000;
+ SDLPerformAudioPassThru *performAudioPassThru = [[SDLPerformAudioPassThru alloc] initWithInitialPrompt:@"Starting sound recording" audioPassThruDisplayText1:@"Say Something" audioPassThruDisplayText2:[NSString stringWithFormat:@"Recording for %d seconds", (recordingDurationInMilliseconds / 1000)] samplingRate:SDLSamplingRate16KHZ bitsPerSample:SDLBitsPerSample16Bit audioType:SDLAudioTypePCM maxDuration:recordingDurationInMilliseconds muteAudio:true audioDataHandler:self.audioDataReceivedHandler];
+
+ [self.sdlManager sendRequest:performAudioPassThru withResponseHandler:self.audioPassThruEndedHandler];
+}
+
+/**
+ * Manually stop an ongoing audio recording.
+ */
+- (void)stopRecording {
+ if (self.audioRecordingState != AudioRecordingStateListening) { return; }
+ self.audioRecordingState = AudioRecordingStateNotListening;
+
+ SDLEndAudioPassThru *endAudioPassThru = [[SDLEndAudioPassThru alloc] init];
+ [self.sdlManager sendRequest:endAudioPassThru];
+}
+
+#pragma mark - Audio Pass Thru Notifications
+
+/**
+ * SDL streams the audio data as it is collected.
+ */
+- (nullable void (^)(NSData * _Nullable))audioDataReceivedHandler {
+ if (!_audioDataReceivedHandler) {
+ __weak typeof(self) weakSelf = self;
+ self.audioDataReceivedHandler = ^(NSData * _Nullable audioData) {
+ if (audioData.length == 0) { return; }
+ if (weakSelf.audioRecordingState == AudioRecordingStateNotListening) {
+ weakSelf.audioData = [NSMutableData data];
+ weakSelf.audioRecordingState = AudioRecordingStateListening;
+ }
+
+ AVAudioPCMBuffer *buffer = [weakSelf sdlex_createPCMBufferWithData:[NSMutableData dataWithData:audioData]];
+ if (buffer == nil) { return; }
+ [weakSelf.speechRecognitionRequest appendAudioPCMBuffer:buffer];
+ };
+ }
+
+ return _audioDataReceivedHandler;
+}
+
+/**
+ * Called when `PerformAudioPassThru` request times out or when a `EndAudioPassThru` request is sent
+ *
+ * @return A SDLResponseHandler
+ */
+- (nullable SDLResponseHandler)audioPassThruEndedHandler {
+ if (!_audioPassThruEndedHandler) {
+ __weak typeof(self) weakSelf = self;
+ self.audioPassThruEndedHandler = ^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
+ if (response == nil) { return; }
+ weakSelf.audioRecordingState = AudioRecordingStateNotListening;
+
+ SDLResult resultCode = response.resultCode;
+ if ([resultCode isEqualToEnum:SDLResultSuccess]) {
+ // The `PerformAudioPassThru` timed out or the "Done" button was pressed in the pop-up.
+ SDLLogD(@"Audio Pass Thru ended successfully");
+ NSString *alertMessage = [NSString stringWithFormat:@"You said: %@", weakSelf.speechTranscription.length == 0 ? @"No speech detected" : weakSelf.speechTranscription];
+ [weakSelf.sdlManager sendRequest:[AlertManager alertWithMessageAndCloseButton:alertMessage textField2:nil]];
+ } else if ([resultCode isEqualToEnum:SDLResultAborted]) {
+ // The "Cancel" button was pressed in the pop-up. Ignore this audio pass thru.
+ SDLLogD(@"Audio recording canceled");
+ } else {
+ SDLLogD(@"Audio recording not successful: \(response.resultCode)");
+ }
+
+ [weakSelf sdlex_stopSpeechRecognitionTask];
+ };
+ }
+
+ return _audioPassThruEndedHandler;
+}
+
+#pragma mark - Audio Data Conversion
+
+/**
+ * Converts the audio data to PCM formatted audio that can be passed, if desired, to the iOS SFSpeech framework (SDL does not provide speech recognition, however the SFSpeech framework or another third party library can be used for speech recognition). The audio format and sample rate should match those set in the `SDLPerformAudioPassThru`.
+ *
+ * @param data The audio data
+ * @return An AVAudioPCMBuffer object
+ */
+- (AVAudioPCMBuffer *)sdlex_createPCMBufferWithData:(NSMutableData *)data {
+ [self.audioData appendData:data];
+
+ AVAudioFormat *audioFormat = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatInt16 sampleRate:16000 channels:1 interleaved:NO];
+ UInt32 numberOfFrames = (UInt32)data.length / audioFormat.streamDescription->mBytesPerFrame;
+ AVAudioPCMBuffer *buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:audioFormat frameCapacity:numberOfFrames];
+ buffer.frameLength = numberOfFrames;
+
+ memcpy(buffer.int16ChannelData[0], data.bytes, data.length);
+
+ return buffer;
+}
+
+#pragma mark - Speech Recognition
+
+/**
+ * Configures speech recognition
+ */
+- (void)sdlex_startSpeechRecognitionTask {
+ self.speechRecognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
+
+ if (self.speechRecognitionRequest == nil || self.speechRecognizer == nil) {
+ SDLLogE(@"Unable to do speech recognition");
+ return;
+ }
+
+ self.speechRecognitionRequest.shouldReportPartialResults = YES;
+ self.speechRecognitionRequest.taskHint = SFSpeechRecognitionTaskHintSearch;
+
+ self.speechRecognitionTask = [self.speechRecognizer recognitionTaskWithRequest:self.speechRecognitionRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
+ if (result == nil) { return; }
+ if (error != nil) {
+ SDLLogE(@"Speech recognition error: %@", error.localizedDescription);
+ return;
+ }
+
+ NSString *speechTranscription = result.bestTranscription.formattedString;
+ SDLLogD(@"Ongoing transcription: %@", speechTranscription);
+ self.speechTranscription = speechTranscription;
+ }];
+}
+
+/**
+ * Cleans up a speech detection session that has ended
+ */
+- (void)sdlex_stopSpeechRecognitionTask {
+ self.audioRecordingState = AudioRecordingStateNotListening;
+ self.audioData = [NSMutableData data];
+ self.speechTranscription = @"";
+ [self.speechRecognitionTask cancel];
+ [self.speechRecognitionRequest endAudio];
+ self.speechRecognitionTask = nil;
+ self.speechRecognitionRequest = nil;
+}
+
+#pragma mark - Speech Recognition Authorization
+
+- (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available {
+ self.speechRecognitionAuthState = [AudioManager sdlex_checkSpeechRecognizerAuth:speechRecognizer];
+}
+
+/**
+ * Checks the current authorization status of the Speech Recognition API. The user can change this status via the native Settings app.
+ *
+ * @param speechRecognizer The SFSpeechRecognizer
+ * @return The current authorization status
+ */
++ (SpeechRecognitionAuthState)sdlex_checkSpeechRecognizerAuth:(SFSpeechRecognizer *)speechRecognizer {
+ if (speechRecognizer == nil) {
+ return SpeechRecognitionAuthStateBadRegion;
+ }
+
+ if (SFSpeechRecognizer.authorizationStatus == SFSpeechRecognizerAuthorizationStatusAuthorized) {
+ return SpeechRecognitionAuthStateAuthorized;
+ } else {
+ return SpeechRecognitionAuthStateNotAuthorized;
+ }
+}
+
+/**
+ * Asks the user via an alert if they want to authorize this app to access the Speech Recognition API.
+ */
+- (void)sdlex_requestSFSpeechRecognizerAuthorization {
+ [SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (status == SFSpeechRecognizerAuthorizationStatusAuthorized) {
+ self.speechRecognitionAuthState = SpeechRecognitionAuthStateAuthorized;
+ } else {
+ self.speechRecognitionAuthState = SpeechRecognitionAuthStateNotAuthorized;
+ }
+ });
+ }];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/AudioManager.swift b/SmartDeviceLink_Example/AudioManager.swift
new file mode 100644
index 000000000..a2e80929d
--- /dev/null
+++ b/SmartDeviceLink_Example/AudioManager.swift
@@ -0,0 +1,229 @@
+//
+// AudioManager.swift
+// SmartDeviceLink
+//
+// Created by Nicole on 4/17/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+import Foundation
+import SmartDeviceLink
+import SmartDeviceLinkSwift
+import Speech
+
+fileprivate enum AudioRecordingState {
+ case listening, notListening
+}
+
+fileprivate enum SpeechRecognitionAuthState {
+ case authorized, notAuthorized, badRegion
+}
+
+@available(iOS 10.0, *)
+class AudioManager: NSObject {
+ fileprivate let sdlManager: SDLManager
+ fileprivate var audioData: Data?
+ fileprivate var audioRecordingState: AudioRecordingState
+
+ fileprivate var speechRecognitionAuthState: SpeechRecognitionAuthState
+ fileprivate var speechRecognitionRequest: SFSpeechAudioBufferRecognitionRequest?
+ fileprivate var speechRecognizer: SFSpeechRecognizer?
+ fileprivate var speechRecognitionTask: SFSpeechRecognitionTask?
+ fileprivate var speechTranscription: String = ""
+ private let speechDefaultLocale = Locale(identifier: "en-US")
+
+ init(sdlManager: SDLManager) {
+ self.sdlManager = sdlManager
+ audioData = Data()
+ audioRecordingState = .notListening
+ speechRecognitionAuthState = .notAuthorized
+ speechRecognizer = SFSpeechRecognizer(locale: speechDefaultLocale)
+
+ super.init()
+
+ speechRecognizer?.delegate = self
+ speechRecognitionAuthState = AudioManager.checkAuthorization(speechRecognizer: speechRecognizer)
+
+ if speechRecognitionAuthState != .authorized {
+ requestSFSpeechRecognizerAuthorization()
+ }
+ }
+
+ /// Resets the manager to its default values
+ func stopManager() {
+ audioRecordingState = .notListening
+ audioData = Data()
+ speechTranscription = ""
+ }
+
+ /// Starts an audio recording using the in-car microphone. During the recording, a pop-up will let the user know that they are being recorded. The pop-up is only dismissed when the recording stops.
+ func startRecording() {
+ guard speechRecognitionAuthState == .authorized else {
+ SDLLog.w("This app does not have permission to access the Speech Recognition API")
+ sdlManager.send(AlertManager.alertWithMessageAndCloseButton("You must give this app permission to access Speech Recognition"))
+ return
+ }
+
+ guard audioRecordingState == .notListening else {
+ SDLLog.w("Audio recording already in progress")
+ return
+ }
+
+ startSpeechRecognitionTask()
+ let recordingDurationMilliseconds: UInt32 = 10000
+ let performAudioPassThru = SDLPerformAudioPassThru(initialPrompt: "Starting sound recording", audioPassThruDisplayText1: "Say Something", audioPassThruDisplayText2: "Recording for \(recordingDurationMilliseconds / 1000) seconds", samplingRate: .rate16KHZ, bitsPerSample: .sample16Bit, audioType: .PCM, maxDuration: recordingDurationMilliseconds, muteAudio: true, audioDataHandler: audioDataReceivedHandler)
+
+ sdlManager.send(request: performAudioPassThru, responseHandler: audioPassThruEndedHandler)
+ }
+
+ /// Manually stop an ongoing audio recording.
+ func stopRecording() {
+ guard audioRecordingState == .listening else { return }
+ audioRecordingState = .notListening
+
+ let endAudioPassThruRequest = SDLEndAudioPassThru()
+ sdlManager.send(endAudioPassThruRequest)
+ }
+}
+
+// MARK: - Audio Pass Thru Notifications
+
+@available(iOS 10.0, *)
+private extension AudioManager {
+ /// SDL streams the audio data as it is collected.
+ var audioDataReceivedHandler: SDLAudioPassThruHandler? {
+ return { [weak self] data in
+ guard let data = data else { return }
+ if self?.audioRecordingState == .notListening {
+ self?.audioRecordingState = .listening
+ }
+
+ guard let buffer = self?.createPCMBuffer(with: data) else { return }
+ self?.speechRecognitionRequest!.append(buffer)
+ }
+ }
+
+ /// Called when `PerformAudioPassThru` request times out or when a `EndAudioPassThru` request is sent
+ var audioPassThruEndedHandler: SDLResponseHandler? {
+ return { [weak self] (request, response, error) in
+ guard let response = response else { return }
+
+ switch response.resultCode {
+ case .success: // The `PerformAudioPassThru` timed out or the "Done" button was pressed in the pop-up.
+ SDLLog.d("Audio Pass Thru ended successfully")
+ guard let speechTranscription = self?.speechTranscription else { return }
+ self?.sdlManager.send(AlertManager.alertWithMessageAndCloseButton("You said: \(speechTranscription.isEmpty ? "No speech detected" : speechTranscription)"))
+ case .aborted: // The "Cancel" button was pressed in the pop-up. Ignore this audio pass thru.
+ SDLLog.d("Audio recording canceled")
+ default:
+ SDLLog.d("Audio recording not successful: \(response.resultCode)")
+ }
+
+ self?.stopSpeechRecognitionTask()
+ }
+ }
+
+ /// Converts the audio data to PCM formatted audio that can be passed, if desired, to the iOS SFSpeech framework (SDL does not provide speech recognition, however the SFSpeech framework or another third party library can be used for speech recognition). The audio format and sample rate should match those set in the `SDLPerformAudioPassThru`.
+ ///
+ /// - Parameter data: The audio data
+ /// - Returns: An AVAudioPCMBuffer object
+ func createPCMBuffer(with data: Data) -> AVAudioPCMBuffer {
+ audioData?.append(data)
+
+ let audioFormat = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 16000, channels: 1, interleaved: false)
+ let numFrames = UInt32(data.count) / (audioFormat.streamDescription.pointee.mBytesPerFrame)
+ let buffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: numFrames)
+ buffer.frameLength = numFrames
+ let bufferChannels = buffer.int16ChannelData!
+ let bufferDataCount = data.copyBytes(to: UnsafeMutableBufferPointer(start: bufferChannels[0], count: data.count))
+
+ SDLLog.v("Audio data has \(bufferDataCount) bytes in \(buffer)")
+
+ return buffer
+ }
+}
+
+// MARK: - Speech Recognition
+
+@available(iOS 10.0, *)
+private extension AudioManager {
+ /// Configures speech recognition
+ func startSpeechRecognitionTask() {
+ speechRecognitionRequest = SFSpeechAudioBufferRecognitionRequest()
+ guard let speechRecognitionRequest = speechRecognitionRequest, let speechRecognizer = speechRecognizer else {
+ SDLLog.e("Unable to do speech recognition")
+ return
+ }
+
+ speechRecognitionRequest.shouldReportPartialResults = true
+ speechRecognitionRequest.taskHint = .search
+
+ speechRecognitionTask = speechRecognizer.recognitionTask(with: speechRecognitionRequest) { [weak self] result, error in
+ guard let result = result else { return }
+
+ if error != nil {
+ SDLLog.e("Speech recognition error: \(error!.localizedDescription)")
+ }
+
+ let speechTranscription = result.bestTranscription.formattedString
+ SDLLog.d("Ongoing transcription: \(speechTranscription)")
+ self?.speechTranscription = speechTranscription
+ }
+ }
+
+ /// Cleans up a speech detection session that has ended
+ func stopSpeechRecognitionTask() {
+ audioRecordingState = .notListening
+ audioData = Data()
+ speechTranscription = ""
+
+ guard self.speechRecognitionTask != nil, self.speechRecognitionRequest != nil else { return }
+ self.speechRecognitionTask!.cancel()
+ self.speechRecognitionRequest!.endAudio()
+ self.speechRecognitionTask = nil
+ self.speechRecognitionRequest = nil
+ }
+}
+
+// MARK: - Speech Recognition Authorization
+
+@available(iOS 10.0, *)
+extension AudioManager: SFSpeechRecognizerDelegate {
+ func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
+ speechRecognitionAuthState = AudioManager.checkAuthorization(speechRecognizer: speechRecognizer)
+ }
+
+ /// Checks the current authorization status of the Speech Recognition API. The user can change this status via the native Settings app.
+ ///
+ /// - Parameter speechRecognizer: The SFSpeechRecognizer
+ /// - Returns: The current authorization status
+ fileprivate static func checkAuthorization(speechRecognizer: SFSpeechRecognizer?) -> SpeechRecognitionAuthState {
+ // Check if the speech recognizer init'd successfully
+ guard speechRecognizer != nil else {
+ return .badRegion
+ }
+
+ // Check authorization status
+ switch SFSpeechRecognizer.authorizationStatus() {
+ case .authorized:
+ return .authorized
+ default:
+ return .notAuthorized
+ }
+ }
+
+ /// Asks the user via an alert if they want to authorize this app to access the Speech Recognition API.
+ fileprivate func requestSFSpeechRecognizerAuthorization() {
+ SFSpeechRecognizer.requestAuthorization { authStatus in
+ OperationQueue.main.addOperation {
+ switch authStatus {
+ case .authorized:
+ self.speechRecognitionAuthState = .authorized
+ default:
+ self.speechRecognitionAuthState = .notAuthorized
+ }
+ }
+ }
+ }
+}
+
diff --git a/SmartDeviceLink_Example/Base.lproj/ConnectionTCPTableViewController.storyboard b/SmartDeviceLink_Example/Base.lproj/ConnectionTCPTableViewController.storyboard
index 6f06da1a2..d72ed86c3 100644
--- a/SmartDeviceLink_Example/Base.lproj/ConnectionTCPTableViewController.storyboard
+++ b/SmartDeviceLink_Example/Base.lproj/ConnectionTCPTableViewController.storyboard
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="l5Q-ZP-1BO">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="l5Q-ZP-1BO">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -22,14 +22,14 @@
<tableViewSection headerTitle="TCP Server" id="bF6-yi-Ial">
<cells>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="pbJ-oz-jNt">
- <rect key="frame" x="0.0" y="56" width="375" height="44"/>
+ <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="pbJ-oz-jNt" id="B7X-yY-lwJ">
- <rect key="frame" x="0.0" y="0.0" width="375" height="43"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="IP Address" clearsOnBeginEditing="YES" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="xqM-s4-9RV">
- <rect key="frame" x="8" y="0.0" width="359" height="44"/>
+ <rect key="frame" x="16" y="0.0" width="343" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="5Pw-mh-x83"/>
</constraints>
@@ -45,14 +45,14 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="C5b-fS-v3d">
- <rect key="frame" x="0.0" y="100" width="375" height="44"/>
+ <rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="C5b-fS-v3d" id="ZD4-xA-og5">
- <rect key="frame" x="0.0" y="0.0" width="375" height="43"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Port" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="hsI-ld-8xY">
- <rect key="frame" x="8" y="0.0" width="359" height="44"/>
+ <rect key="frame" x="16" y="0.0" width="343" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="FpG-5e-MHT"/>
</constraints>
@@ -72,14 +72,14 @@
<tableViewSection headerTitle="" id="rgl-Lm-uDH">
<cells>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="ybX-Eh-Hbx">
- <rect key="frame" x="0.0" y="164" width="375" height="44"/>
+ <rect key="frame" x="0.0" y="163.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ybX-Eh-Hbx" id="uI9-fK-205">
- <rect key="frame" x="0.0" y="0.0" width="375" height="43"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="t37-4W-6F4">
- <rect key="frame" x="8" y="0.0" width="359" height="43"/>
+ <rect key="frame" x="16" y="0.0" width="343" height="43"/>
<fontDescription key="fontDescription" type="system" pointSize="23"/>
<state key="normal" title="Connect">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
diff --git a/SmartDeviceLink_Example/Base.lproj/Main.storyboard b/SmartDeviceLink_Example/Base.lproj/Main.storyboard
index e7cf57e32..848eb40ab 100644
--- a/SmartDeviceLink_Example/Base.lproj/Main.storyboard
+++ b/SmartDeviceLink_Example/Base.lproj/Main.storyboard
@@ -1,8 +1,12 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="mM3-m6-I5t">
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="mM3-m6-I5t">
+ <device id="retina4_7" orientation="portrait">
+ <adaptation id="fullscreen"/>
+ </device>
<dependencies>
<deployment identifier="iOS"/>
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Navigation Controller-->
@@ -11,7 +15,7 @@
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="mM3-m6-I5t" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="eMh-g9-C8T">
- <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
+ <rect key="frame" x="0.0" y="20" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
@@ -32,14 +36,14 @@
<viewControllerLayoutGuide type="bottom" id="fet-m3-F1O"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="jkb-9Y-Hwh">
- <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
<navigationItem key="navigationItem" id="t1a-s2-nn6">
<nil key="title"/>
<segmentedControl key="titleView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bar" selectedSegmentIndex="0" id="RYa-fE-Qek">
- <rect key="frame" x="180" y="7" width="240" height="30"/>
+ <rect key="frame" x="67.5" y="7" width="240" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<segments>
<segment title="TCP Debug"/>
diff --git a/SmartDeviceLink_Example/ButtonManager.h b/SmartDeviceLink_Example/ButtonManager.h
new file mode 100644
index 000000000..867f50c7c
--- /dev/null
+++ b/SmartDeviceLink_Example/ButtonManager.h
@@ -0,0 +1,31 @@
+//
+// ButtonManager.h
+// SmartDeviceLink
+//
+// Created by Nicole on 5/11/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@class SDLManager;
+@class SDLSoftButtonObject;
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef void(^RefreshUIHandler)(void);
+
+@interface ButtonManager : NSObject
+
+@property (assign, nonatomic, getter=isTextEnabled, readonly) BOOL textEnabled;
+@property (assign, nonatomic, getter=isHexagonEnabled, readonly) BOOL toggleEnabled;
+@property (assign, nonatomic, getter=areImagesEnabled, readonly) BOOL imagesEnabled;
+
+- (instancetype)init NS_UNAVAILABLE;
+- (instancetype)initWithManager:(SDLManager *)manager refreshUIHandler:(RefreshUIHandler)refreshUIHandler;
+
+- (NSArray<SDLSoftButtonObject *> *)allScreenSoftButtons;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/ButtonManager.m b/SmartDeviceLink_Example/ButtonManager.m
new file mode 100644
index 000000000..3aed337b3
--- /dev/null
+++ b/SmartDeviceLink_Example/ButtonManager.m
@@ -0,0 +1,146 @@
+//
+// ButtonManager.m
+// SmartDeviceLink
+//
+// Created by Nicole on 5/11/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import "ButtonManager.h"
+#import "AlertManager.h"
+#import "AppConstants.h"
+#import "SmartDeviceLink.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface ButtonManager ()
+
+@property (copy, nonatomic, nullable) RefreshUIHandler refreshUIHandler;
+@property (strong, nonatomic) SDLManager *sdlManager;
+
+@property (assign, nonatomic, getter=isTextEnabled, readwrite) BOOL textEnabled;
+@property (assign, nonatomic, getter=isHexagonEnabled, readwrite) BOOL toggleEnabled;
+@property (assign, nonatomic, getter=areImagesEnabled, readwrite) BOOL imagesEnabled;
+
+@end
+
+@implementation ButtonManager
+
+- (instancetype)initWithManager:(SDLManager *)manager refreshUIHandler:(RefreshUIHandler)refreshUIHandler {
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+
+ _sdlManager = manager;
+ _refreshUIHandler = refreshUIHandler;
+
+ _textEnabled = YES;
+ _imagesEnabled = YES;
+ _toggleEnabled = YES;
+
+ return self;
+}
+
+#pragma mark - Setters
+
+- (void)setTextEnabled:(BOOL)textEnabled {
+ _textEnabled = textEnabled;
+ if (self.refreshUIHandler == nil) { return; }
+ self.refreshUIHandler();
+}
+
+- (void)setImagesEnabled:(BOOL)imagesEnabled {
+ _imagesEnabled = imagesEnabled;
+
+ SDLSoftButtonObject *object = [self.sdlManager.screenManager softButtonObjectNamed:AlertSoftButton];
+ [object transitionToNextState];
+
+ if (self.refreshUIHandler == nil) { return; }
+ self.refreshUIHandler();
+}
+
+- (void)setToggleEnabled:(BOOL)toggleEnabled {
+ _toggleEnabled = toggleEnabled;
+ SDLSoftButtonObject *object = [self.sdlManager.screenManager softButtonObjectNamed:ToggleSoftButton];
+ [object transitionToStateNamed:(toggleEnabled ? ToggleSoftButtonImageOnState : ToggleSoftButtonImageOffState)];
+}
+
+#pragma mark - Custom Soft Buttons
+
+- (NSArray<SDLSoftButtonObject *> *)allScreenSoftButtons {
+ return @[[self sdlex_softButtonAlertWithManager:self.sdlManager], [self sdlex_softButtonToggleWithManager:self.sdlManager], [self sdlex_softButtonTextVisibleWithManager:self.sdlManager], [self sdlex_softButtonImagesVisibleWithManager:self.sdlManager]];
+}
+
+- (SDLSoftButtonObject *)sdlex_softButtonAlertWithManager:(SDLManager *)manager {
+ SDLSoftButtonState *alertImageAndTextState = [[SDLSoftButtonState alloc] initWithStateName:AlertSoftButtonImageState text:AlertSoftButtonText image:[UIImage imageNamed:CarIconImageName]];
+ SDLSoftButtonState *alertTextState = [[SDLSoftButtonState alloc] initWithStateName:AlertSoftButtonTextState text:AlertSoftButtonText image:nil];
+
+ __weak typeof(self) weakself = self;
+ SDLSoftButtonObject *alertSoftButton = [[SDLSoftButtonObject alloc] initWithName:AlertSoftButton states:@[alertImageAndTextState, alertTextState] initialStateName:alertImageAndTextState.name handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {
+ if (buttonPress == nil) { return; }
+
+ [weakself.sdlManager sendRequest:[AlertManager alertWithMessageAndCloseButton:@"You pushed the soft button!" textField2:nil]];
+
+ SDLLogD(@"Star icon soft button press fired");
+ }];
+
+ return alertSoftButton;
+}
+
+- (SDLSoftButtonObject *)sdlex_softButtonToggleWithManager:(SDLManager *)manager {
+ SDLSoftButtonState *toggleImageOnState = [[SDLSoftButtonState alloc] initWithStateName:ToggleSoftButtonImageOnState text:nil image:[UIImage imageNamed:WheelIconImageName]];
+ SDLSoftButtonState *toggleImageOffState = [[SDLSoftButtonState alloc] initWithStateName:ToggleSoftButtonImageOffState text:nil image:[UIImage imageNamed:LaptopIconImageName]];
+
+ __weak typeof(self) weakself = self;
+ SDLSoftButtonObject *toggleButton = [[SDLSoftButtonObject alloc] initWithName:ToggleSoftButton states:@[toggleImageOnState, toggleImageOffState] initialStateName:toggleImageOnState.name handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {
+ if (buttonPress == nil) { return; }
+ weakself.toggleEnabled = !weakself.toggleEnabled;
+ SDLLogD(@"Toggle icon button press fired %d", self.toggleEnabled);
+ }];
+
+ return toggleButton;
+}
+
+- (SDLSoftButtonObject *)sdlex_softButtonTextVisibleWithManager:(SDLManager *)manager {
+ SDLSoftButtonState *textOnState = [[SDLSoftButtonState alloc] initWithStateName:TextVisibleSoftButtonTextOnState text:TextVisibleSoftButtonTextOnText image:nil];
+ SDLSoftButtonState *textOffState = [[SDLSoftButtonState alloc] initWithStateName:TextVisibleSoftButtonTextOffState text:TextVisibleSoftButtonTextOffText image:nil];
+
+ __weak typeof(self) weakself = self;
+ SDLSoftButtonObject *textButton = [[SDLSoftButtonObject alloc] initWithName:TextVisibleSoftButton states:@[textOnState, textOffState] initialStateName:textOnState.name handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {
+ if (buttonPress == nil) { return; }
+
+ weakself.textEnabled = !weakself.textEnabled;
+ SDLSoftButtonObject *object = [weakself.sdlManager.screenManager softButtonObjectNamed:TextVisibleSoftButton];
+ [object transitionToNextState];
+
+ SDLLogD(@"Text visibility soft button press fired %d", weakself.textEnabled);
+ }];
+
+ return textButton;
+}
+
+- (SDLSoftButtonObject *)sdlex_softButtonImagesVisibleWithManager:(SDLManager *)manager {
+ SDLSoftButtonState *imagesOnState = [[SDLSoftButtonState alloc] initWithStateName:ImagesVisibleSoftButtonImageOnState text:ImagesVisibleSoftButtonImageOnText image:nil];
+ SDLSoftButtonState *imagesOffState = [[SDLSoftButtonState alloc] initWithStateName:ImagesVisibleSoftButtonImageOffState text:ImagesVisibleSoftButtonImageOffText image:nil];
+
+ __weak typeof(self) weakself = self;
+ SDLSoftButtonObject *imagesButton = [[SDLSoftButtonObject alloc] initWithName:ImagesVisibleSoftButton states:@[imagesOnState, imagesOffState] initialStateName:imagesOnState.name handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {
+ if (buttonPress == nil) {
+ return;
+ }
+
+ weakself.imagesEnabled = !weakself.imagesEnabled;
+
+ SDLSoftButtonObject *object = [weakself.sdlManager.screenManager softButtonObjectNamed:ImagesVisibleSoftButton];
+ [object transitionToNextState];
+
+ SDLLogD(@"Image visibility soft button press fired %d", weakself.imagesEnabled);
+ }];
+
+ return imagesButton;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/ButtonManager.swift b/SmartDeviceLink_Example/ButtonManager.swift
new file mode 100644
index 000000000..617553e0b
--- /dev/null
+++ b/SmartDeviceLink_Example/ButtonManager.swift
@@ -0,0 +1,121 @@
+//
+// ButtonManager.swift
+// SmartDeviceLink
+//
+// Created by Nicole on 4/11/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+import Foundation
+import SmartDeviceLink
+import SmartDeviceLinkSwift
+
+typealias RefreshUIHandler = (() -> Void)
+
+class ButtonManager: NSObject {
+ fileprivate let sdlManager: SDLManager!
+ fileprivate var refreshUIHandler: RefreshUIHandler?
+
+ /// SDL UI textfields are visible if true; hidden if false
+ public fileprivate(set) var textEnabled: Bool {
+ didSet {
+ guard let refreshUIHandler = refreshUIHandler else { return }
+ refreshUIHandler()
+ }
+ }
+
+ /// SDL UI images are visible if true; hidden if false
+ public fileprivate(set) var imagesEnabled: Bool {
+ didSet {
+ guard let refreshUIHandler = refreshUIHandler, let alertSoftButton = sdlManager.screenManager.softButtonObjectNamed(AlertSoftButton) else { return }
+ alertSoftButton.transitionToNextState()
+ refreshUIHandler()
+ }
+ }
+
+ /// Keeps track of the toggle soft button current state. The image or text changes when the button is selected
+ fileprivate var toggleEnabled: Bool {
+ didSet {
+ guard let hexagonSoftButton = sdlManager.screenManager.softButtonObjectNamed(ToggleSoftButton), hexagonSoftButton.transition(toState: toggleEnabled ? ToggleSoftButtonImageOnState : ToggleSoftButtonImageOffState) else { return }
+ }
+ }
+
+ init(sdlManager: SDLManager, updateScreenHandler: RefreshUIHandler? = nil) {
+ self.sdlManager = sdlManager
+ self.refreshUIHandler = updateScreenHandler
+ textEnabled = true
+ imagesEnabled = true
+ toggleEnabled = true
+ super.init()
+ }
+
+ /// Creates and returns an array of all soft buttons for the UI
+ ///
+ /// - Parameter manager: The SDL Manager
+ /// - Returns: An array of all soft buttons for the UI
+ func allScreenSoftButtons(with manager: SDLManager) -> [SDLSoftButtonObject] {
+ return [softButtonAlert(with: manager), softButtonToggle(), softButtonTextVisible(), softButtonImagesVisible()]
+ }
+}
+
+// MARK: - Custom Soft Buttons
+
+private extension ButtonManager {
+ /// Returns a soft button that shows an alert when tapped.
+ ///
+ /// - Parameter manager: The SDL Manager for showing the alert
+ /// - Returns: A soft button
+ func softButtonAlert(with manager: SDLManager) -> SDLSoftButtonObject {
+ let imageSoftButtonState = SDLSoftButtonState(stateName: AlertSoftButtonImageState, text: nil, image: UIImage(named: CarIconImageName))
+ let textSoftButtonState = SDLSoftButtonState(stateName: AlertSoftButtonTextState, text: AlertSoftButtonText, image: nil)
+ return SDLSoftButtonObject(name: AlertSoftButton, states: [imageSoftButtonState, textSoftButtonState], initialStateName: imageSoftButtonState.name) { (buttonPress, buttonEvent) in
+ guard buttonPress != nil else { return }
+ let alert = AlertManager.alertWithMessageAndCloseButton("You pressed the button!")
+ manager.send(alert)
+ }
+ }
+
+ /// Returns a soft button that toggles between two states: on and off. If images are currently visible, the button image toggles; if images aren't visible, the button text toggles.
+ ///
+ /// - Returns: A soft button
+ func softButtonToggle() -> SDLSoftButtonObject {
+ let imageOnState = SDLSoftButtonState(stateName: ToggleSoftButtonImageOnState, text: nil, image: UIImage(named: WheelIconImageName))
+ let imageOffState = SDLSoftButtonState(stateName: ToggleSoftButtonImageOffState, text: nil, image: UIImage(named: LaptopIconImageName))
+ return SDLSoftButtonObject(name: ToggleSoftButton, states: [imageOnState, imageOffState], initialStateName: imageOnState.name) { [unowned self] (buttonPress, buttonEvent) in
+ guard buttonPress != nil else { return }
+ self.toggleEnabled = !self.toggleEnabled
+ }
+ }
+
+ /// Returns a soft button that toggles the textfield visibility state for the SDL UI. The button's text toggles based on the current text visibility.
+ ///
+ /// - Returns: A soft button
+ func softButtonTextVisible() -> SDLSoftButtonObject {
+ let textVisibleState = SDLSoftButtonState(stateName: TextVisibleSoftButtonTextOnState, text: TextVisibleSoftButtonTextOnText, artwork: nil)
+ let textNotVisibleState = SDLSoftButtonState(stateName: TextVisibleSoftButtonTextOffState, text: TextVisibleSoftButtonTextOffText, image: nil)
+ return SDLSoftButtonObject(name: TextVisibleSoftButton, states: [textVisibleState, textNotVisibleState], initialStateName: textVisibleState.name) { [unowned self] (buttonPress, buttonEvent) in
+ guard buttonPress != nil else { return }
+ self.textEnabled = !self.textEnabled
+
+ // Update the button state
+ let softButton = self.sdlManager.screenManager.softButtonObjectNamed(TextVisibleSoftButton)
+ softButton?.transitionToNextState()
+ }
+ }
+
+ /// Returns a soft button that toggles the image visibility state for the SDL UI. The button's text toggles based on the current image visibility.
+ ///
+ /// - Returns: A soft button
+ func softButtonImagesVisible() -> SDLSoftButtonObject {
+ let imagesVisibleState = SDLSoftButtonState(stateName: ImagesVisibleSoftButtonImageOnState, text: ImagesVisibleSoftButtonImageOnText, image: nil)
+ let imagesNotVisibleState = SDLSoftButtonState(stateName: ImagesVisibleSoftButtonImageOffState, text: ImagesVisibleSoftButtonImageOffText, image: nil)
+ return SDLSoftButtonObject(name: ImagesVisibleSoftButton, states: [imagesVisibleState, imagesNotVisibleState], initialStateName: imagesVisibleState.name) { [unowned self] (buttonPress, buttonEvent) in
+ guard buttonPress != nil else { return }
+ self.imagesEnabled = !self.imagesEnabled
+
+ // Update the button state
+ let softButton = self.sdlManager.screenManager.softButtonObjectNamed(ImagesVisibleSoftButton)
+ softButton?.transitionToNextState()
+ }
+ }
+}
diff --git a/SmartDeviceLink_Example/Classes/ConnectionIAPTableViewController.m b/SmartDeviceLink_Example/Classes/ConnectionIAPTableViewController.m
index 17ee2ae19..31a0f3fdf 100644
--- a/SmartDeviceLink_Example/Classes/ConnectionIAPTableViewController.m
+++ b/SmartDeviceLink_Example/Classes/ConnectionIAPTableViewController.m
@@ -45,7 +45,7 @@
ProxyState state = [ProxyManager sharedManager].state;
switch (state) {
case ProxyStateStopped: {
- [[ProxyManager sharedManager] startIAP];
+ [[ProxyManager sharedManager] startWithProxyTransportType:ProxyTransportTypeIAP];
} break;
case ProxyStateSearchingForConnection: {
[[ProxyManager sharedManager] reset];
diff --git a/SmartDeviceLink_Example/Classes/ConnectionTCPTableViewController.m b/SmartDeviceLink_Example/Classes/ConnectionTCPTableViewController.m
index 94d6ebec4..e567eb44e 100644
--- a/SmartDeviceLink_Example/Classes/ConnectionTCPTableViewController.m
+++ b/SmartDeviceLink_Example/Classes/ConnectionTCPTableViewController.m
@@ -56,7 +56,7 @@
ProxyState state = [ProxyManager sharedManager].state;
switch (state) {
case ProxyStateStopped: {
- [[ProxyManager sharedManager] startTCP];
+ [[ProxyManager sharedManager] startWithProxyTransportType:ProxyTransportTypeTCP];
} break;
case ProxyStateSearchingForConnection: {
[[ProxyManager sharedManager] reset];
diff --git a/SmartDeviceLink_Example/Classes/ProxyManager.h b/SmartDeviceLink_Example/Classes/ProxyManager.h
index 333bb6dbf..59872b335 100644
--- a/SmartDeviceLink_Example/Classes/ProxyManager.h
+++ b/SmartDeviceLink_Example/Classes/ProxyManager.h
@@ -5,11 +5,8 @@
#import <Foundation/Foundation.h>
@class SDLManager;
-@class SDLStreamingMediaManager;
-
typedef NS_ENUM(NSUInteger, ProxyTransportType) {
- ProxyTransportTypeUnknown,
ProxyTransportTypeTCP,
ProxyTransportTypeIAP
};
@@ -20,6 +17,7 @@ typedef NS_ENUM(NSUInteger, ProxyState) {
ProxyStateConnected
};
+NS_ASSUME_NONNULL_BEGIN
@interface ProxyManager : NSObject
@@ -27,8 +25,9 @@ typedef NS_ENUM(NSUInteger, ProxyState) {
@property (strong, nonatomic) SDLManager *sdlManager;
+ (instancetype)sharedManager;
-- (void)startIAP;
-- (void)startTCP;
+- (void)startWithProxyTransportType:(ProxyTransportType)proxyTransportType;
- (void)reset;
@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/Classes/ProxyManager.m b/SmartDeviceLink_Example/Classes/ProxyManager.m
index adf083eef..bb2ba88c3 100644
--- a/SmartDeviceLink_Example/Classes/ProxyManager.m
+++ b/SmartDeviceLink_Example/Classes/ProxyManager.m
@@ -2,34 +2,28 @@
// ProxyManager.m
// SmartDeviceLink-iOS
-#import "SmartDeviceLink.h"
-#import "ProxyManager.h"
+#import "AppConstants.h"
+#import "AlertManager.h"
+#import "ButtonManager.h"
+#import "MenuManager.h"
+#import "PerformInteractionManager.h"
#import "Preferences.h"
-
-NSString *const SDLAppName = @"SDL Example App";
-NSString *const SDLAppId = @"9999";
-
-
-BOOL const ShouldRestartOnDisconnect = NO;
-
-typedef NS_ENUM(NSUInteger, SDLHMIFirstState) {
- SDLHMIFirstStateNone,
- SDLHMIFirstStateNonNone,
- SDLHMIFirstStateFull
-};
-
+#import "ProxyManager.h"
+#import "RPCPermissionsManager.h"
+#import "SmartDeviceLink.h"
+#import "VehicleDataManager.h"
NS_ASSUME_NONNULL_BEGIN
+
@interface ProxyManager () <SDLManagerDelegate>
// Describes the first time the HMI state goes non-none and full.
-@property (assign, nonatomic) SDLHMIFirstState firstTimeState;
-
-@property (assign, nonatomic, getter=isTextEnabled) BOOL textEnabled;
-@property (assign, nonatomic, getter=isHexagonEnabled) BOOL hexagonEnabled;
-@property (assign, nonatomic, getter=areImagesEnabled) BOOL imagesEnabled;
+@property (assign, nonatomic) SDLHMILevel firstHMILevel;
+@property (strong, nonatomic) VehicleDataManager *vehicleDataManager;
+@property (strong, nonatomic) ButtonManager *buttonManager;
+@property (nonatomic, copy, nullable) RefreshUIHandler refreshUIHandler;
@end
@@ -49,43 +43,16 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)init {
self = [super init];
- if (self == nil) {
+ if (!self) {
return nil;
}
-
+
_state = ProxyStateStopped;
- _firstTimeState = SDLHMIFirstStateNone;
+ _firstHMILevel = SDLHMILevelNone;
- _textEnabled = YES;
- _hexagonEnabled = YES;
- _imagesEnabled = YES;
-
return self;
}
-- (void)startIAP {
- [self sdlex_updateProxyState:ProxyStateSearchingForConnection];
- // Check for previous instance of sdlManager
- if (self.sdlManager) { return; }
- SDLLifecycleConfiguration *lifecycleConfig = [self.class sdlex_setLifecycleConfigurationPropertiesOnConfiguration:[SDLLifecycleConfiguration defaultConfigurationWithAppName:SDLAppName appId:SDLAppId]];
- [self sdlex_setupConfigurationWithLifecycleConfiguration:lifecycleConfig];
-}
-
-- (void)startTCP {
- [self sdlex_updateProxyState:ProxyStateSearchingForConnection];
- // Check for previous instance of sdlManager
- if (self.sdlManager) { return; }
- SDLLifecycleConfiguration *lifecycleConfig = [self.class sdlex_setLifecycleConfigurationPropertiesOnConfiguration:[SDLLifecycleConfiguration debugConfigurationWithAppName:SDLAppName appId:SDLAppId ipAddress:[Preferences sharedPreferences].ipAddress port:[Preferences sharedPreferences].port]];
- [self sdlex_setupConfigurationWithLifecycleConfiguration:lifecycleConfig];
-}
-
-- (void)sdlex_setupConfigurationWithLifecycleConfiguration:(SDLLifecycleConfiguration *)lifecycleConfiguration {
- SDLConfiguration *config = [SDLConfiguration configurationWithLifecycle:lifecycleConfiguration lockScreen:[SDLLockScreenConfiguration enabledConfigurationWithAppIcon:[UIImage imageNamed:@"AppIcon60x60@2x"] backgroundColor:nil] logging:[self.class sdlex_logConfiguration]];
- self.sdlManager = [[SDLManager alloc] initWithConfiguration:config delegate:self];
-
- [self startManager];
-}
-
- (void)startManager {
__weak typeof (self) weakSelf = self;
[self.sdlManager startWithReadyHandler:^(BOOL success, NSError * _Nullable error) {
@@ -94,107 +61,69 @@ NS_ASSUME_NONNULL_BEGIN
[weakSelf sdlex_updateProxyState:ProxyStateStopped];
return;
}
-
+
+ self.vehicleDataManager = [[VehicleDataManager alloc] initWithManager:self.sdlManager refreshUIHandler:self.refreshUIHandler];
+ self.buttonManager = [[ButtonManager alloc] initWithManager:self.sdlManager refreshUIHandler:self.refreshUIHandler];
+
[weakSelf sdlex_updateProxyState:ProxyStateConnected];
+ [RPCPermissionsManager setupPermissionsCallbacksWithManager:weakSelf.sdlManager];
+ [weakSelf sdlex_showInitialData];
- [weakSelf sdlex_setupPermissionsCallbacks];
-
- if ([weakSelf.sdlManager.hmiLevel isEqualToEnum:SDLHMILevelFull]) {
- [weakSelf sdlex_showInitialData];
- }
+ SDLLogD(@"SDL file manager storage: %lu mb", self.sdlManager.fileManager.bytesAvailable / 1024 / 1024);
}];
}
- (void)reset {
- [self sdlex_updateProxyState:ProxyStateStopped];
- [self.sdlManager stop];
- // Remove reference
- self.sdlManager = nil;
-}
-
-
-#pragma mark - Helpers
-
-- (void)sdlex_showInitialData {
- if (![self.sdlManager.hmiLevel isEqualToEnum:SDLHMILevelFull]) {
+ if (self.sdlManager == nil) {
+ [self sdlex_updateProxyState:ProxyStateStopped];
return;
}
- SDLSetDisplayLayout *displayLayout = [[SDLSetDisplayLayout alloc] initWithLayout:SDLPredefinedLayoutNonMedia];
- [self.sdlManager sendRequest:displayLayout];
-
- [self sdlex_updateScreen];
-
- self.sdlManager.screenManager.softButtonObjects = [self sdlex_softButtons];
+ [self.sdlManager stop];
}
-- (void)setTextEnabled:(BOOL)textEnabled {
- _textEnabled = textEnabled;
- [self sdlex_updateScreen];
+- (void)sdlex_updateProxyState:(ProxyState)newState {
+ if (self.state != newState) {
+ [self willChangeValueForKey:@"state"];
+ _state = newState;
+ [self didChangeValueForKey:@"state"];
+ }
}
-- (void)setImagesEnabled:(BOOL)imagesEnabled {
- _imagesEnabled = imagesEnabled;
- [self sdlex_updateScreen];
- [self setHexagonButtonIconEnabled:self.isHexagonEnabled imagesEnabled:imagesEnabled];
-}
+#pragma mark - SDL Configuration
-- (void)setHexagonEnabled:(BOOL)hexagonEnabled {
- _hexagonEnabled = hexagonEnabled;
- [self setHexagonButtonIconEnabled:hexagonEnabled imagesEnabled:self.areImagesEnabled];
-}
+- (void)startWithProxyTransportType:(ProxyTransportType)proxyTransportType {
+ [self sdlex_updateProxyState:ProxyStateSearchingForConnection];
-- (void)setHexagonButtonIconEnabled:(BOOL)hexagonEnabled imagesEnabled:(BOOL)imagesEnabled {
- SDLSoftButtonObject *object = [self.sdlManager.screenManager softButtonObjectNamed:@"HexagonButton"];
- imagesEnabled ? [object transitionToStateNamed:(hexagonEnabled ? @"imageOnState" : @"imageOffState")] : [object transitionToStateNamed:(hexagonEnabled ? @"textOnState" : @"textOffState")];
-}
+ // Check for previous instance of sdlManager
+ if (self.sdlManager) { return; }
-- (void)sdlex_updateScreen {
- [self.sdlManager.screenManager beginUpdates];
- self.sdlManager.screenManager.textAlignment = SDLTextAlignmentLeft;
- self.sdlManager.screenManager.textField1 = self.isTextEnabled ? @"SmartDeviceLink" : nil;
- self.sdlManager.screenManager.textField2 = self.isTextEnabled ? @"Example App" : nil;
+ SDLLifecycleConfiguration *lifecycleConfig = proxyTransportType == ProxyTransportTypeIAP ? [self.class sdlex_iapLifecycleConfiguration] : [self.class sdlex_tcpLifecycleConfiguration];
+ [self sdlex_setupConfigurationWithLifecycleConfiguration:lifecycleConfig];
+}
- if (self.sdlManager.systemCapabilityManager.displayCapabilities.graphicSupported) {
- self.sdlManager.screenManager.primaryGraphic = self.areImagesEnabled ? [SDLArtwork persistentArtworkWithImage:[UIImage imageNamed:@"sdl_logo_green"] asImageFormat:SDLArtworkImageFormatPNG] : nil;
- }
++ (SDLLifecycleConfiguration *)sdlex_iapLifecycleConfiguration {
+ return [self.class sdlex_setLifecycleConfigurationPropertiesOnConfiguration:[SDLLifecycleConfiguration defaultConfigurationWithAppName:ExampleAppName appId:ExampleAppId]];
+}
- [self.sdlManager.screenManager endUpdatesWithCompletionHandler:^(NSError * _Nullable error) {
- SDLLogD(@"Updated text and graphics, error? %@", error);
- }];
++ (SDLLifecycleConfiguration *)sdlex_tcpLifecycleConfiguration {
+ return [self.class sdlex_setLifecycleConfigurationPropertiesOnConfiguration:[SDLLifecycleConfiguration debugConfigurationWithAppName:ExampleAppName appId:ExampleAppId ipAddress:[Preferences sharedPreferences].ipAddress port:[Preferences sharedPreferences].port]];
}
-- (void)sdlex_setupPermissionsCallbacks {
- // This will tell you whether or not you can use the Show RPC right at this moment
- BOOL isAvailable = [self.sdlManager.permissionManager isRPCAllowed:@"Show"];
- SDLLogD(@"Show is allowed? %@", @(isAvailable));
+- (void)sdlex_setupConfigurationWithLifecycleConfiguration:(SDLLifecycleConfiguration *)lifecycleConfiguration {
+ SDLConfiguration *config = [SDLConfiguration configurationWithLifecycle:lifecycleConfiguration lockScreen:[SDLLockScreenConfiguration enabledConfigurationWithAppIcon:[UIImage imageNamed:ExampleAppLogoName] backgroundColor:nil] logging:[self.class sdlex_logConfiguration]];
+ self.sdlManager = [[SDLManager alloc] initWithConfiguration:config delegate:self];
- // This will set up a block that will tell you whether or not you can use none, all, or some of the RPCs specified, and notifies you when those permissions change
- SDLPermissionObserverIdentifier observerId = [self.sdlManager.permissionManager addObserverForRPCs:@[@"Show", @"Alert"] groupType:SDLPermissionGroupTypeAllAllowed withHandler:^(NSDictionary<SDLPermissionRPCName, NSNumber<SDLBool> *> * _Nonnull change, SDLPermissionGroupStatus status) {
- SDLLogD(@"Show changed permission to status: %@, dict: %@", @(status), change);
- }];
- // The above block will be called immediately, this will then remove the block from being called any more
- [self.sdlManager.permissionManager removeObserverForIdentifier:observerId];
-
- // This will give us the current status of the group of RPCs, as if we had set up an observer, except these are one-shot calls
- NSArray *rpcGroup =@[@"AddCommand", @"PerformInteraction"];
- SDLPermissionGroupStatus commandPICSStatus = [self.sdlManager.permissionManager groupStatusOfRPCs:rpcGroup];
- NSDictionary *commandPICSStatusDict = [self.sdlManager.permissionManager statusOfRPCs:rpcGroup];
- SDLLogD(@"Command / PICS status: %@, dict: %@", @(commandPICSStatus), commandPICSStatusDict);
-
- // This will set up a long-term observer for the RPC group and will tell us when the status of any specified RPC changes (due to the `SDLPermissionGroupTypeAny`) option.
- [self.sdlManager.permissionManager addObserverForRPCs:rpcGroup groupType:SDLPermissionGroupTypeAny withHandler:^(NSDictionary<SDLPermissionRPCName, NSNumber<SDLBool> *> * _Nonnull change, SDLPermissionGroupStatus status) {
- SDLLogD(@"Command / PICS changed permission to status: %@, dict: %@", @(status), change);
- }];
+ [self startManager];
}
+ (SDLLifecycleConfiguration *)sdlex_setLifecycleConfigurationPropertiesOnConfiguration:(SDLLifecycleConfiguration *)config {
- SDLArtwork *appIconArt = [SDLArtwork persistentArtworkWithImage:[UIImage imageNamed:@"AppIcon60x60@2x"] asImageFormat:SDLArtworkImageFormatPNG];
+ SDLArtwork *appIconArt = [SDLArtwork persistentArtworkWithImage:[UIImage imageNamed:ExampleAppLogoName] asImageFormat:SDLArtworkImageFormatPNG];
- config.shortAppName = @"SDL Example";
+ config.shortAppName = ExampleAppNameShort;
config.appIcon = appIconArt;
- config.voiceRecognitionCommandNames = @[@"S D L Example"];
- config.ttsName = [SDLTTSChunk textChunksFromString:config.shortAppName];
+ config.voiceRecognitionCommandNames = @[ExampleAppNameTTS];
+ config.ttsName = [SDLTTSChunk textChunksFromString:ExampleAppName];
config.language = SDLLanguageEnUs;
config.languagesSupported = @[SDLLanguageEnUs, SDLLanguageFrCa, SDLLanguageEsMx];
@@ -203,236 +132,141 @@ NS_ASSUME_NONNULL_BEGIN
+ (SDLLogConfiguration *)sdlex_logConfiguration {
SDLLogConfiguration *logConfig = [SDLLogConfiguration debugConfiguration];
- SDLLogFileModule *sdlExampleModule = [SDLLogFileModule moduleWithName:@"SDL Example" files:[NSSet setWithArray:@[@"ProxyManager"]]];
+ SDLLogFileModule *sdlExampleModule = [SDLLogFileModule moduleWithName:@"SDL Obj-C Example App" files:[NSSet setWithArray:@[@"ProxyManager", @"AlertManager", @"AudioManager", @"ButtonManager", @"MenuManager", @"PerformInteractionManager", @"RPCPermissionsManager", @"VehicleDataManager"]]];
logConfig.modules = [logConfig.modules setByAddingObject:sdlExampleModule];
logConfig.targets = [logConfig.targets setByAddingObject:[SDLLogTargetFile logger]];
- // logConfig.filters = [logConfig.filters setByAddingObject:[SDLLogFilter filterByAllowingModules:[NSSet setWithObject:@"Transport"]]];
+ logConfig.globalLogLevel = SDLLogLevelVerbose;
return logConfig;
}
-- (void)sdlex_updateProxyState:(ProxyState)newState {
- if (self.state != newState) {
- [self willChangeValueForKey:@"state"];
- _state = newState;
- [self didChangeValueForKey:@"state"];
- }
-}
-
-#pragma mark - RPC builders
-
-+ (SDLSpeak *)sdlex_appNameSpeak {
- SDLSpeak *speak = [[SDLSpeak alloc] init];
- speak.ttsChunks = [SDLTTSChunk textChunksFromString:@"S D L Example App"];
-
- return speak;
-}
-
-+ (SDLSpeak *)sdlex_goodJobSpeak {
- SDLSpeak *speak = [[SDLSpeak alloc] init];
- speak.ttsChunks = [SDLTTSChunk textChunksFromString:@"Good Job"];
-
- return speak;
-}
-
-+ (SDLSpeak *)sdlex_youMissedItSpeak {
- SDLSpeak *speak = [[SDLSpeak alloc] init];
- speak.ttsChunks = [SDLTTSChunk textChunksFromString:@"You missed it"];
-
- return speak;
-}
-
-+ (SDLCreateInteractionChoiceSet *)sdlex_createOnlyChoiceInteractionSet {
- SDLCreateInteractionChoiceSet *createInteractionSet = [[SDLCreateInteractionChoiceSet alloc] init];
- createInteractionSet.interactionChoiceSetID = @0;
-
- NSString *theOnlyChoiceName = @"The Only Choice";
- SDLChoice *theOnlyChoice = [[SDLChoice alloc] init];
- theOnlyChoice.choiceID = @0;
- theOnlyChoice.menuName = theOnlyChoiceName;
- theOnlyChoice.vrCommands = @[theOnlyChoiceName];
-
- createInteractionSet.choiceSet = @[theOnlyChoice];
-
- return createInteractionSet;
-}
+#pragma mark - Screen UI Helpers
-+ (void)sdlex_sendPerformOnlyChoiceInteractionWithManager:(SDLManager *)manager {
- SDLPerformInteraction *performOnlyChoiceInteraction = [[SDLPerformInteraction alloc] init];
- performOnlyChoiceInteraction.initialText = @"Choose the only one! You have 5 seconds...";
- performOnlyChoiceInteraction.initialPrompt = [SDLTTSChunk textChunksFromString:@"Choose it"];
- performOnlyChoiceInteraction.interactionMode = SDLInteractionModeBoth;
- performOnlyChoiceInteraction.interactionChoiceSetIDList = @[@0];
- performOnlyChoiceInteraction.helpPrompt = [SDLTTSChunk textChunksFromString:@"Do it"];
- performOnlyChoiceInteraction.timeoutPrompt = [SDLTTSChunk textChunksFromString:@"Too late"];
- performOnlyChoiceInteraction.timeout = @5000;
- performOnlyChoiceInteraction.interactionLayout = SDLLayoutModeListOnly;
-
- [manager sendRequest:performOnlyChoiceInteraction withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLPerformInteractionResponse * _Nullable response, NSError * _Nullable error) {
- SDLLogD(@"Perform Interaction fired");
- if ((response == nil) || (error != nil)) {
- SDLLogE(@"Something went wrong, no perform interaction response: %@", error);
- }
-
- if ([response.choiceID isEqualToNumber:@0]) {
- [manager sendRequest:[self sdlex_goodJobSpeak]];
- } else {
- [manager sendRequest:[self sdlex_youMissedItSpeak]];
- }
- }];
+- (void)sdlex_createMenus {
+ [self.sdlManager sendRequest:[PerformInteractionManager createInteractionChoiceSet]];
+ self.sdlManager.screenManager.menu = [MenuManager allMenuItemsWithManager:self.sdlManager];
+ self.sdlManager.screenManager.voiceCommands = [MenuManager allVoiceMenuItemsWithManager:self.sdlManager];
}
-- (NSArray<SDLSoftButtonObject *> *)sdlex_softButtons {
- SDLSoftButtonState *starImageState = [[SDLSoftButtonState alloc] initWithStateName:@"imageState" text:@"Press" image:[UIImage imageNamed:@"star_softbutton_icon"]];
- SDLSoftButtonState *starTextState = [[SDLSoftButtonState alloc] initWithStateName:@"textState" text:@"Press" image:nil];
-
- __weak typeof(self) weakself = self;
- SDLSoftButtonObject *starButton = [[SDLSoftButtonObject alloc] initWithName:@"StarButton" states:@[starImageState, starTextState] initialStateName:@"imageState" handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {
- if (buttonPress == nil) {
- return;
- }
-
- SDLAlert* alert = [[SDLAlert alloc] init];
- alert.alertText1 = @"You pushed the soft button!";
- [weakself.sdlManager sendRequest:alert];
-
- SDLLogD(@"Star icon soft button press fired");
- }];
-
- SDLSoftButtonState *hexImageOnState = [[SDLSoftButtonState alloc] initWithStateName:@"imageOnState" text:nil image:[UIImage imageNamed:@"hexagon_on_softbutton_icon"]];
- SDLSoftButtonState *hexImageOffState = [[SDLSoftButtonState alloc] initWithStateName:@"imageOffState" text:nil image:[UIImage imageNamed:@"hexagon_off_softbutton_icon"]];
- SDLSoftButtonState *hexTextOnState = [[SDLSoftButtonState alloc] initWithStateName:@"textOnState" text:@"➖Hex" image:nil];
- SDLSoftButtonState *hexTextOffState = [[SDLSoftButtonState alloc] initWithStateName:@"textOffState" text:@"➕Hex" image:nil];
- SDLSoftButtonObject *hexButton = [[SDLSoftButtonObject alloc] initWithName:@"HexagonButton" states:@[hexImageOnState, hexImageOffState, hexTextOnState, hexTextOffState] initialStateName:hexImageOnState.name handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {
- if (buttonPress == nil) { return; }
-
- weakself.hexagonEnabled = !weakself.hexagonEnabled;
- SDLLogD(@"Hexagon icon button press fired %d", self.hexagonEnabled);
- }];
-
- SDLSoftButtonState *textOnState = [[SDLSoftButtonState alloc] initWithStateName:@"onState" text:@"➖Text" image:nil];
- SDLSoftButtonState *textOffState = [[SDLSoftButtonState alloc] initWithStateName:@"offState" text:@"➕Text" image:nil];
- SDLSoftButtonObject *textButton = [[SDLSoftButtonObject alloc] initWithName:@"TextButton" states:@[textOnState, textOffState] initialStateName:@"onState" handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {
- if (buttonPress == nil) {
- return;
- }
-
- weakself.textEnabled = !weakself.textEnabled;
- SDLSoftButtonObject *object = [weakself.sdlManager.screenManager softButtonObjectNamed:@"TextButton"];
- [object transitionToNextState];
-
- SDLLogD(@"Text visibility soft button press fired %d", weakself.textEnabled);
- }];
-
- SDLSoftButtonState *imagesOnState = [[SDLSoftButtonState alloc] initWithStateName:@"onState" text:@"➖Icons" image:nil];
- SDLSoftButtonState *imagesOffState = [[SDLSoftButtonState alloc] initWithStateName:@"offState" text:@"➕Icons" image:nil];
- SDLSoftButtonObject *imagesButton = [[SDLSoftButtonObject alloc] initWithName:@"ImagesButton" states:@[imagesOnState, imagesOffState] initialStateName:@"onState" handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {
- if (buttonPress == nil) {
- return;
- }
-
- weakself.imagesEnabled = !weakself.imagesEnabled;
-
- SDLSoftButtonObject *object = [weakself.sdlManager.screenManager softButtonObjectNamed:@"ImagesButton"];
- [object transitionToNextState];
-
- SDLLogD(@"Image visibility soft button press fired %d", weakself.imagesEnabled);
- }];
+- (void)sdlex_showInitialData {
+ if (![self.sdlManager.hmiLevel isEqualToEnum:SDLHMILevelFull]) { return; }
- return @[starButton, hexButton, textButton, imagesButton];
+ [self sdlex_updateScreen];
+ self.sdlManager.screenManager.softButtonObjects = [self.buttonManager allScreenSoftButtons];
}
-+ (void)sdlex_sendGetVehicleDataWithManager:(SDLManager *)manager {
- SDLGetVehicleData *getVehicleData = [[SDLGetVehicleData alloc] initWithAccelerationPedalPosition:YES airbagStatus:YES beltStatus:YES bodyInformation:YES clusterModeStatus:YES deviceStatus:YES driverBraking:YES eCallInfo:YES emergencyEvent:YES engineTorque:YES externalTemperature:YES fuelLevel:YES fuelLevelState:YES gps:YES headLampStatus:YES instantFuelConsumption:YES myKey:YES odometer:YES prndl:YES rpm:YES speed:YES steeringWheelAngle:YES tirePressure:YES vin:YES wiperStatus:YES];
-
- [manager sendRequest:getVehicleData withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
- SDLLogD(@"vehicle data response: %@", response);
- }];
-}
+- (nullable RefreshUIHandler)refreshUIHandler {
+ if(!_refreshUIHandler) {
+ __weak typeof(self) weakSelf = self;
+ weakSelf.refreshUIHandler = ^{
+ [weakSelf sdlex_updateScreen];
+ };
+ }
-+ (void)sdlex_sendDialNumberWithManager:(SDLManager *)manager {
- SDLDialNumber *dialNumber = [[SDLDialNumber alloc] initWithNumber:@"5555555555"];
- [manager sendRequest:dialNumber withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
- SDLLogD(@"Dial number response: %@", response);
- }];
+ return _refreshUIHandler;
}
-- (void)sdlex_prepareRemoteSystem {
- SDLCreateInteractionChoiceSet *choiceSet = [self.class sdlex_createOnlyChoiceInteractionSet];
- [self.sdlManager sendRequest:choiceSet];
-
- __weak typeof(self) weakself = self;
- SDLMenuCell *speakCell = [[SDLMenuCell alloc] initWithTitle:@"Speak" icon:[SDLArtwork artworkWithImage:[UIImage imageNamed:@"speak"] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:@[@"Speak"] handler:^(SDLTriggerSource _Nonnull triggerSource) {
- [weakself.sdlManager sendRequest:[ProxyManager sdlex_appNameSpeak]];
- }];
+- (void)sdlex_updateScreen {
+ if (![self.sdlManager.hmiLevel isEqualToEnum:SDLHMILevelFull]) { return; }
- SDLMenuCell *interactionSetCell = [[SDLMenuCell alloc] initWithTitle:@"Perform Interaction" icon:[SDLArtwork artworkWithImage:[UIImage imageNamed:@"choice_set"] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:@[@"Perform Interaction"] handler:^(SDLTriggerSource _Nonnull triggerSource) {
- [ProxyManager sdlex_sendPerformOnlyChoiceInteractionWithManager:weakself.sdlManager];
- }];
+ SDLScreenManager *screenManager = self.sdlManager.screenManager;
+ BOOL isTextEnabled = self.buttonManager.isTextEnabled;
+ BOOL areImagesVisible = self.buttonManager.areImagesEnabled;
- SDLMenuCell *getVehicleDataCell = [[SDLMenuCell alloc] initWithTitle:@"Get Vehicle Data" icon:[SDLArtwork artworkWithImage:[UIImage imageNamed:@"car"] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:@[@"Get Vehicle Data"] handler:^(SDLTriggerSource _Nonnull triggerSource) {
- [ProxyManager sdlex_sendGetVehicleDataWithManager:weakself.sdlManager];
- }];
+ [screenManager beginUpdates];
+ screenManager.textAlignment = SDLTextAlignmentLeft;
+ screenManager.textField1 = isTextEnabled ? SmartDeviceLinkText : nil;
+ screenManager.textField2 = isTextEnabled ? [NSString stringWithFormat:@"Obj-C %@", ExampleAppText] : nil;
+ screenManager.textField3 = isTextEnabled ? self.vehicleDataManager.vehicleOdometerData : nil;
- NSMutableArray *menuArray = [NSMutableArray array];
- for (int i = 0; i < 75; i++) {
- SDLMenuCell *cell = [[SDLMenuCell alloc] initWithTitle:[NSString stringWithFormat:@"%i", i] icon:[SDLArtwork artworkWithImage:[UIImage imageNamed:@"hexagon_on_softbutton_icon"] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource){}];
- [menuArray addObject:cell];
+ if (self.sdlManager.systemCapabilityManager.displayCapabilities.graphicSupported) {
+ screenManager.primaryGraphic = areImagesVisible ? [SDLArtwork persistentArtworkWithImage:[UIImage imageNamed:@"sdl_logo_green"] asImageFormat:SDLArtworkImageFormatPNG] : nil;
}
- SDLMenuCell *submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Submenu" subCells:[menuArray copy]];
-
- SDLVoiceCommand *voiceCommand = [[SDLVoiceCommand alloc] initWithVoiceCommands:@[@"Test"] handler:^{
- [ProxyManager sdlex_sendPerformOnlyChoiceInteractionWithManager:weakself.sdlManager];
+ [screenManager endUpdatesWithCompletionHandler:^(NSError * _Nullable error) {
+ SDLLogD(@"Updated text and graphics, error? %@", error);
}];
-
- self.sdlManager.screenManager.menu = @[speakCell, interactionSetCell, getVehicleDataCell, submenuCell];
- self.sdlManager.screenManager.voiceCommands = @[voiceCommand];
}
#pragma mark - SDLManagerDelegate
- (void)managerDidDisconnect {
- // Reset our state
- self.firstTimeState = SDLHMIFirstStateNone;
[self sdlex_updateProxyState:ProxyStateStopped];
- if (ShouldRestartOnDisconnect) {
+ self.firstHMILevel = SDLHMILevelNone;
+
+ // If desired, automatically start searching for a new connection to Core
+ if (ExampleAppShouldRestartSDLManagerOnDisconnect) {
[self startManager];
}
}
- (void)hmiLevel:(SDLHMILevel)oldLevel didChangeToLevel:(SDLHMILevel)newLevel {
- if (![newLevel isEqualToEnum:SDLHMILevelNone] && (self.firstTimeState == SDLHMIFirstStateNone)) {
+ if (![newLevel isEqualToEnum:SDLHMILevelNone] && ([self.firstHMILevel isEqualToEnum:SDLHMILevelNone])) {
// This is our first time in a non-NONE state
- self.firstTimeState = SDLHMIFirstStateNonNone;
+ self.firstHMILevel = newLevel;
// Send AddCommands
- [self sdlex_prepareRemoteSystem];
+ [self sdlex_createMenus];
+ [self.vehicleDataManager subscribeToVehicleOdometer];
}
-
- if ([newLevel isEqualToEnum:SDLHMILevelFull] && (self.firstTimeState != SDLHMIFirstStateFull)) {
- // This is our first time in a FULL state
- self.firstTimeState = SDLHMIFirstStateFull;
+
+ if ([newLevel isEqualToEnum:SDLHMILevelFull]) {
+ // The SDL app is in the foreground
+ SDLLogD(@"The HMI level is full");
+ } else if ([newLevel isEqualToEnum:SDLHMILevelLimited]) {
+ // An active NAV or MEDIA SDL app is in the background
+ SDLLogD(@"The HMI level is limited");
+ } else if ([newLevel isEqualToEnum:SDLHMILevelBackground]) {
+ // The SDL app is not in the foreground
+ SDLLogD(@"The HMI level is background");
+ } else if ([newLevel isEqualToEnum:SDLHMILevelNone]) {
+ // The SDL app is not yet running
+ SDLLogD(@"The HMI level is none");
}
if ([newLevel isEqualToEnum:SDLHMILevelFull]) {
- // We're always going to try to show the initial state, because if we've already shown it, it won't be shown, and we need to guard against some possible weird states
+ // We're always going to try to show the initial state. because if we've already shown it, it won't be shown, and we need to guard against some possible weird states
[self sdlex_showInitialData];
}
}
+- (void)systemContext:(nullable SDLSystemContext)oldContext didChangeToContext:(SDLSystemContext)newContext {
+ if ([newContext isEqualToEnum:SDLSystemContextAlert]) {
+ SDLLogD(@"The System Context is Alert");
+ } else if ([newContext isEqualToEnum:SDLSystemContextHMIObscured]) {
+ SDLLogD(@"The System Context is HMI Obscured");
+ } else if ([newContext isEqualToEnum:SDLSystemContextMain]) {
+ SDLLogD(@"The System Context is Main");
+ } else if ([newContext isEqualToEnum:SDLSystemContextMenu]) {
+ SDLLogD(@"The System Context is Menu");
+ } else if ([newContext isEqualToEnum:SDLSystemContextVoiceRecognitionSession]) {
+ SDLLogD(@"The System Context is Voice Recognition Session");
+ }
+}
+
+- (void)audioStreamingState:(nullable SDLAudioStreamingState)oldState didChangeToState:(SDLAudioStreamingState)newState {
+ if ([newState isEqualToEnum:SDLAudioStreamingStateAudible]) {
+ // The SDL app's audio can be heard
+ SDLLogD(@"The Audio Streaming State is Audible");
+ } else if ([newState isEqualToEnum:SDLAudioStreamingStateNotAudible]) {
+ // The SDL app's audio cannot be heard
+ SDLLogD(@"The Audio Streaming State is Not Audible");
+ } else if ([newState isEqualToEnum:SDLAudioStreamingStateAttenuated]) {
+ // The SDL app's audio volume has been lowered to let the system speak over the audio. This usually happens with voice recognition commands.
+ SDLLogD(@"The Audio Streaming State is Not Attenuated");
+ }
+}
+
- (nullable SDLLifecycleConfigurationUpdate *)managerShouldUpdateLifecycleToLanguage:(SDLLanguage)language {
SDLLifecycleConfigurationUpdate *update = [[SDLLifecycleConfigurationUpdate alloc] init];
if ([language isEqualToEnum:SDLLanguageEnUs]) {
- update.appName = SDLAppName;
+ update.appName = ExampleAppName;
} else if ([language isEqualToString:SDLLanguageEsMx]) {
- NSString *SDLAppNameSpanish = @"SDL Aplicación de ejemplo";
- update.appName = SDLAppNameSpanish;
+ update.appName = ExampleAppNameSpanish;
} else if ([language isEqualToString:SDLLanguageFrCa]) {
- NSString *SDLAppNameFrench = @"SDL Exemple App";
- update.appName = SDLAppNameFrench;
+ update.appName = ExampleAppNameFrench;
} else {
return nil;
}
diff --git a/SmartDeviceLink_Example/ConnectionContainerViewController.swift b/SmartDeviceLink_Example/ConnectionContainerViewController.swift
new file mode 100644
index 000000000..e990712fa
--- /dev/null
+++ b/SmartDeviceLink_Example/ConnectionContainerViewController.swift
@@ -0,0 +1,82 @@
+//
+// ConnectionContainerViewController.swift
+// SmartDeviceLink-ExampleSwift
+//
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+import UIKit
+
+class ConnectionContainerViewController: UIViewController {
+ @IBOutlet weak var segmentedControl: UISegmentedControl!
+ var viewControllers: [UIViewController] = []
+ var currentViewController: UIViewController?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ navigationController?.navigationBar.isTranslucent = false
+ let tcpControllerStoryboard = UIStoryboard(name: "ConnectionTCPTableViewController", bundle: nil)
+ let iapControllerStoryboard = UIStoryboard(name: "ConnectionIAPTableViewController", bundle: nil)
+ let tcpController = tcpControllerStoryboard.instantiateViewController(withIdentifier :"ConnectionTCPTableViewController")
+ let iapController = iapControllerStoryboard.instantiateViewController(withIdentifier :"ConnectionIAPTableViewController")
+ viewControllers.append(tcpController)
+ viewControllers.append(iapController)
+
+ segmentedControl.selectedSegmentIndex = 0
+ loadChildViewController(index: 0)
+
+ let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(slideToLeftWithGestureRecognizer(gestureRecognizer:)))
+ let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(slideToRightWithGestureRecognizer(gestureRecognizer:)))
+ leftSwipe.direction = .left
+ rightSwipe.direction = .right
+ view.addGestureRecognizer(leftSwipe)
+ view.addGestureRecognizer(rightSwipe)
+ }
+
+ override func didReceiveMemoryWarning() {
+ super.didReceiveMemoryWarning()
+ // Dispose of any resources that can be recreated.
+ }
+
+ @IBAction func slideToLeftWithGestureRecognizer(gestureRecognizer: UISwipeGestureRecognizer) {
+ if segmentedControl.selectedSegmentIndex == 0 {
+ segmentedControl.selectedSegmentIndex = 1
+ removeFromView()
+ loadChildViewController(index: 1)
+ }
+ }
+
+ @IBAction func slideToRightWithGestureRecognizer(gestureRecognizer: UISwipeGestureRecognizer) {
+ if segmentedControl.selectedSegmentIndex == 1 {
+ segmentedControl.selectedSegmentIndex = 0
+ removeFromView()
+ loadChildViewController(index: 0)
+ }
+ }
+ // Grab changes in segmentedControl
+ @IBAction func indexChanged(_ sender: AnyObject) {
+ switch segmentedControl.selectedSegmentIndex {
+ case 0:
+ removeFromView()
+ loadChildViewController(index: 0)
+ case 1:
+ removeFromView()
+ loadChildViewController(index: 1)
+ default:
+ break
+ }
+ }
+ // Mark: - View functions
+ func removeFromView() {
+ let vc = self.childViewControllers.last
+ vc?.view.removeFromSuperview()
+ vc?.removeFromParentViewController()
+ }
+
+ func loadChildViewController(index: Int?) {
+ let initialViewController: UIViewController = viewControllers[index!] as! UIViewController
+ self.addChildViewController(initialViewController)
+ view.addSubview(initialViewController.view)
+ initialViewController.didMove(toParentViewController: self)
+ }
+}
diff --git a/SmartDeviceLink_Example/ConnectionIAPTableViewController.storyboard b/SmartDeviceLink_Example/ConnectionIAPTableViewController.storyboard
new file mode 100644
index 000000000..ef04daa8e
--- /dev/null
+++ b/SmartDeviceLink_Example/ConnectionIAPTableViewController.storyboard
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="J12-ul-Tx1">
+ <device id="retina4_7" orientation="portrait">
+ <adaptation id="fullscreen"/>
+ </device>
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
+ <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <scenes>
+ <!--ConnectionIAP Table View Controller-->
+ <scene sceneID="kGx-OZ-JDF">
+ <objects>
+ <tableViewController storyboardIdentifier="ConnectionIAPTableViewController" id="J12-ul-Tx1" customClass="ConnectionIAPTableViewController" customModule="SmartDeviceLink_Example_Swift" customModuleProvider="target" sceneMemberID="viewController">
+ <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" id="MzB-GZ-Ook">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <sections>
+ <tableViewSection id="Qz3-D9-j37">
+ <cells>
+ <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="2sd-U1-9xV">
+ <rect key="frame" x="0.0" y="35" width="375" height="44"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="2sd-U1-9xV" id="EhZ-2E-WQ5">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rjq-vZ-OjB">
+ <rect key="frame" x="16" y="0.0" width="343" height="44"/>
+ <fontDescription key="fontDescription" type="system" pointSize="23"/>
+ <state key="normal" title="Connect">
+ <color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ </state>
+ <connections>
+ <action selector="connectButtonWasPressed:" destination="J12-ul-Tx1" eventType="touchUpInside" id="OEM-Ca-Pms"/>
+ </connections>
+ </button>
+ </subviews>
+ <constraints>
+ <constraint firstItem="rjq-vZ-OjB" firstAttribute="top" secondItem="EhZ-2E-WQ5" secondAttribute="top" id="8GY-v0-41a"/>
+ <constraint firstAttribute="bottom" secondItem="rjq-vZ-OjB" secondAttribute="bottom" id="FKB-JG-o5G"/>
+ <constraint firstAttribute="trailingMargin" secondItem="rjq-vZ-OjB" secondAttribute="trailing" id="ISQ-6b-S34"/>
+ <constraint firstItem="rjq-vZ-OjB" firstAttribute="leading" secondItem="EhZ-2E-WQ5" secondAttribute="leadingMargin" id="PiJ-h3-NOR"/>
+ </constraints>
+ </tableViewCellContentView>
+ </tableViewCell>
+ </cells>
+ </tableViewSection>
+ </sections>
+ <connections>
+ <outlet property="dataSource" destination="J12-ul-Tx1" id="kTG-wP-6Fl"/>
+ <outlet property="delegate" destination="J12-ul-Tx1" id="gKA-WB-R0A"/>
+ </connections>
+ </tableView>
+ <connections>
+ <outlet property="connectButton" destination="rjq-vZ-OjB" id="Sz8-r7-ddN"/>
+ <outlet property="connectTableViewCell" destination="2sd-U1-9xV" id="UME-sB-vsD"/>
+ <outlet property="table" destination="MzB-GZ-Ook" id="SME-OU-FAK"/>
+ </connections>
+ </tableViewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="N5a-E0-fOt" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="898" y="630"/>
+ </scene>
+ </scenes>
+</document>
diff --git a/SmartDeviceLink_Example/ConnectionIAPTableViewController.swift b/SmartDeviceLink_Example/ConnectionIAPTableViewController.swift
new file mode 100644
index 000000000..f5bacb922
--- /dev/null
+++ b/SmartDeviceLink_Example/ConnectionIAPTableViewController.swift
@@ -0,0 +1,72 @@
+//
+// ConnectionIAPTableViewController.swift
+// SmartDeviceLink-ExampleSwift
+//
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+import UIKit
+
+class ConnectionIAPTableViewController: UITableViewController, ProxyManagerDelegate {
+
+ @IBOutlet weak var connectTableViewCell: UITableViewCell!
+ @IBOutlet weak var table: UITableView!
+ @IBOutlet weak var connectButton: UIButton!
+
+ var state: ProxyState = .stopped
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ ProxyManager.sharedManager.delegate = self
+ table.keyboardDismissMode = .onDrag
+ table.isScrollEnabled = false
+ initButton()
+ }
+
+ override func didReceiveMemoryWarning() {
+ super.didReceiveMemoryWarning()
+ }
+
+ func initButton() {
+ self.connectTableViewCell.backgroundColor = UIColor.red
+ self.connectButton.setTitle("Connect", for: .normal)
+ self.connectButton.setTitleColor(.white, for: .normal)
+ }
+ // MARK: - IBActions
+ @IBAction func connectButtonWasPressed(_ sender: UIButton) {
+
+ switch state {
+ case .stopped:
+ ProxyManager.sharedManager.start(with: .iap)
+ case .searching:
+ ProxyManager.sharedManager.resetConnection()
+ case .connected:
+ ProxyManager.sharedManager.resetConnection()
+ }
+ }
+ // MARK: - Delegate Functions
+ func didChangeProxyState(_ newState: ProxyState) {
+ state = newState
+ var newColor: UIColor? = nil
+ var newTitle: String? = nil
+
+ switch newState {
+ case .stopped:
+ newColor = UIColor.red
+ newTitle = "Connect"
+ case .searching:
+ newColor = UIColor.blue
+ newTitle = "Stop Searching"
+ case .connected:
+ newColor = UIColor.green
+ newTitle = "Disconnect"
+ }
+
+ if (newColor != nil) || (newTitle != nil) {
+ DispatchQueue.main.async(execute: {[weak self]() -> Void in
+ self?.connectTableViewCell.backgroundColor = newColor
+ self?.connectButton.setTitle(newTitle, for: .normal)
+ self?.connectButton.setTitleColor(.white, for: .normal)
+ })
+ }
+ }
+}
diff --git a/SmartDeviceLink_Example/ConnectionTCPTableViewController.storyboard b/SmartDeviceLink_Example/ConnectionTCPTableViewController.storyboard
new file mode 100644
index 000000000..84f74c3b1
--- /dev/null
+++ b/SmartDeviceLink_Example/ConnectionTCPTableViewController.storyboard
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="l5Q-ZP-1BO">
+ <device id="retina4_7" orientation="portrait">
+ <adaptation id="fullscreen"/>
+ </device>
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
+ <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <scenes>
+ <!--ConnectionTCP Table View Controller-->
+ <scene sceneID="geJ-kX-PTm">
+ <objects>
+ <tableViewController storyboardIdentifier="ConnectionTCPTableViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="l5Q-ZP-1BO" customClass="ConnectionTCPTableViewController" customModule="SmartDeviceLink_Example_Swift" customModuleProvider="target" sceneMemberID="viewController">
+ <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" id="7ZH-AV-Zyf">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <sections>
+ <tableViewSection headerTitle="TCP Server" id="bF6-yi-Ial">
+ <cells>
+ <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="pbJ-oz-jNt">
+ <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="pbJ-oz-jNt" id="B7X-yY-lwJ">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="IP Address" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="xqM-s4-9RV">
+ <rect key="frame" x="16" y="0.0" width="343" height="44"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="44" id="5Pw-mh-x83"/>
+ </constraints>
+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
+ <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="URL"/>
+ </textField>
+ </subviews>
+ <constraints>
+ <constraint firstAttribute="centerY" secondItem="xqM-s4-9RV" secondAttribute="centerY" id="PcX-lz-oQo"/>
+ <constraint firstItem="xqM-s4-9RV" firstAttribute="trailing" secondItem="B7X-yY-lwJ" secondAttribute="trailingMargin" id="YF9-Uh-Yqm"/>
+ <constraint firstItem="xqM-s4-9RV" firstAttribute="leading" secondItem="B7X-yY-lwJ" secondAttribute="leadingMargin" id="pBt-SK-tuZ"/>
+ </constraints>
+ </tableViewCellContentView>
+ </tableViewCell>
+ <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="C5b-fS-v3d">
+ <rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="C5b-fS-v3d" id="ZD4-xA-og5">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Port" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="hsI-ld-8xY">
+ <rect key="frame" x="16" y="0.0" width="343" height="44"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="44" id="FpG-5e-MHT"/>
+ </constraints>
+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
+ <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="numberPad"/>
+ </textField>
+ </subviews>
+ <constraints>
+ <constraint firstAttribute="centerY" secondItem="hsI-ld-8xY" secondAttribute="centerY" id="X1e-g3-RJN"/>
+ <constraint firstItem="hsI-ld-8xY" firstAttribute="leading" secondItem="ZD4-xA-og5" secondAttribute="leadingMargin" id="oeB-5U-tOl"/>
+ <constraint firstItem="hsI-ld-8xY" firstAttribute="trailing" secondItem="ZD4-xA-og5" secondAttribute="trailingMargin" id="wXl-bK-7vU"/>
+ </constraints>
+ </tableViewCellContentView>
+ </tableViewCell>
+ </cells>
+ </tableViewSection>
+ <tableViewSection headerTitle="" id="rgl-Lm-uDH">
+ <cells>
+ <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="ybX-Eh-Hbx">
+ <rect key="frame" x="0.0" y="163.5" width="375" height="44"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ybX-Eh-Hbx" id="uI9-fK-205">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="t37-4W-6F4">
+ <rect key="frame" x="16" y="0.0" width="343" height="43"/>
+ <fontDescription key="fontDescription" type="system" pointSize="23"/>
+ <state key="normal" title="Connect">
+ <color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ </state>
+ <connections>
+ <action selector="connectButtonWasPressed:" destination="l5Q-ZP-1BO" eventType="touchUpInside" id="4Kr-4D-O7b"/>
+ </connections>
+ </button>
+ </subviews>
+ <constraints>
+ <constraint firstItem="t37-4W-6F4" firstAttribute="top" secondItem="uI9-fK-205" secondAttribute="top" id="IfU-4k-EXx"/>
+ <constraint firstItem="t37-4W-6F4" firstAttribute="leading" secondItem="uI9-fK-205" secondAttribute="leadingMargin" id="cc3-uk-9fL"/>
+ <constraint firstAttribute="bottom" secondItem="t37-4W-6F4" secondAttribute="bottom" id="hnD-4g-xvT"/>
+ <constraint firstAttribute="trailingMargin" secondItem="t37-4W-6F4" secondAttribute="trailing" id="j4p-fi-0LP"/>
+ </constraints>
+ </tableViewCellContentView>
+ </tableViewCell>
+ </cells>
+ </tableViewSection>
+ </sections>
+ <connections>
+ <outlet property="dataSource" destination="l5Q-ZP-1BO" id="r5q-yg-LY6"/>
+ <outlet property="delegate" destination="l5Q-ZP-1BO" id="xFj-yP-z0A"/>
+ </connections>
+ </tableView>
+ <navigationItem key="navigationItem" id="JNL-hN-wDm">
+ <nil key="title"/>
+ <segmentedControl key="titleView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bar" selectedSegmentIndex="0" id="rXi-EW-KGG">
+ <rect key="frame" x="180" y="7" width="240" height="30"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <segments>
+ <segment title="TCP Debug"/>
+ <segment title="iAP"/>
+ </segments>
+ <connections>
+ <action selector="connectionTypeSegmentedControlDidChange:" destination="l5Q-ZP-1BO" eventType="valueChanged" id="uaO-bf-NQR"/>
+ </connections>
+ </segmentedControl>
+ </navigationItem>
+ <connections>
+ <outlet property="connectButton" destination="t37-4W-6F4" id="f6v-Q4-ggs"/>
+ <outlet property="connectTableViewCell" destination="ybX-Eh-Hbx" id="hyh-CW-oXx"/>
+ <outlet property="ipAddressTextField" destination="xqM-s4-9RV" id="daz-uN-Rxa"/>
+ <outlet property="portTextField" destination="hsI-ld-8xY" id="5pF-XP-Xh3"/>
+ <outlet property="table" destination="7ZH-AV-Zyf" id="4nR-6A-RzX"/>
+ </connections>
+ </tableViewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="0fm-wO-kFd" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="688" y="499"/>
+ </scene>
+ </scenes>
+</document>
diff --git a/SmartDeviceLink_Example/ConnectionTCPTableViewController.swift b/SmartDeviceLink_Example/ConnectionTCPTableViewController.swift
new file mode 100644
index 000000000..3cf1e91c3
--- /dev/null
+++ b/SmartDeviceLink_Example/ConnectionTCPTableViewController.swift
@@ -0,0 +1,88 @@
+//
+// ConnectionTCPTableViewController.swift
+// SmartDeviceLink-ExampleSwift
+//
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+import UIKit
+
+class ConnectionTCPTableViewController: UITableViewController, UINavigationControllerDelegate, ProxyManagerDelegate {
+
+ @IBOutlet weak var ipAddressTextField: UITextField!
+ @IBOutlet weak var portTextField: UITextField!
+ @IBOutlet weak var connectTableViewCell: UITableViewCell!
+ @IBOutlet weak var connectButton: UIButton!
+ @IBOutlet weak var table: UITableView!
+
+ var state: ProxyState = .stopped
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ ProxyManager.sharedManager.delegate = self
+ table.keyboardDismissMode = .onDrag
+ table.isScrollEnabled = false
+ ipAddressTextField.text = AppUserDefaults.shared.ipAddress
+ portTextField.text = AppUserDefaults.shared.port
+ initButton()
+ }
+
+ override func didReceiveMemoryWarning() {
+ super.didReceiveMemoryWarning()
+ }
+
+ func initButton() {
+ self.connectTableViewCell.backgroundColor = UIColor.red
+ self.connectButton.setTitle("Connect", for: .normal)
+ self.connectButton.setTitleColor(.white, for: .normal)
+ }
+ // MARK: - IBActions
+ @IBAction func connectButtonWasPressed(_ sender: UIButton) {
+
+ let ipAddress = ipAddressTextField.text
+ let port = portTextField.text
+
+ if ipAddress != "" || port != "" {
+ AppUserDefaults.shared.ipAddress = ipAddress
+ AppUserDefaults.shared.port = port
+
+ switch state {
+ case .stopped:
+ ProxyManager.sharedManager.start(with: .tcp)
+ case .searching:
+ ProxyManager.sharedManager.resetConnection()
+ case .connected:
+ ProxyManager.sharedManager.resetConnection()
+ }
+ } else {
+ let alertMessage = UIAlertController(title: "Missing Info!", message: "Make sure to set your IP Address and Port", preferredStyle: .alert)
+ alertMessage.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
+ self.present(alertMessage, animated: true, completion: nil)
+ }
+ }
+ // MARK: - Delegate Functions
+ func didChangeProxyState(_ newState: ProxyState) {
+ state = newState
+ var newColor: UIColor? = nil
+ var newTitle: String? = nil
+
+ switch newState {
+ case .stopped:
+ newColor = UIColor.red
+ newTitle = "Connect"
+ case .searching:
+ newColor = UIColor.blue
+ newTitle = "Stop Searching"
+ case .connected:
+ newColor = UIColor.green
+ newTitle = "Disconnect"
+ }
+
+ if (newColor != nil) || (newTitle != nil) {
+ DispatchQueue.main.async(execute: {[weak self]() -> Void in
+ self?.connectTableViewCell.backgroundColor = newColor
+ self?.connectButton.setTitle(newTitle, for: .normal)
+ self?.connectButton.setTitleColor(.white, for: .normal)
+ })
+ }
+ }
+}
diff --git a/SmartDeviceLink_Example/Images.xcassets/star_softbutton_icon.imageset/Contents.json b/SmartDeviceLink_Example/Images.xcassets/car_icon.imageset/Contents.json
index 1a3c6d569..6e2269ebd 100644
--- a/SmartDeviceLink_Example/Images.xcassets/star_softbutton_icon.imageset/Contents.json
+++ b/SmartDeviceLink_Example/Images.xcassets/car_icon.imageset/Contents.json
@@ -2,7 +2,7 @@
"images" : [
{
"idiom" : "universal",
- "filename" : "star_black_softbutton_icon.png",
+ "filename" : "car.png",
"scale" : "1x"
},
{
diff --git a/SmartDeviceLink_Example/Images.xcassets/car_icon.imageset/car.png b/SmartDeviceLink_Example/Images.xcassets/car_icon.imageset/car.png
new file mode 100644
index 000000000..de2eb2699
--- /dev/null
+++ b/SmartDeviceLink_Example/Images.xcassets/car_icon.imageset/car.png
Binary files differ
diff --git a/SmartDeviceLink_Example/Images.xcassets/hexagon_off_softbutton_icon.imageset/hexagon_black_softbutton_icon.png b/SmartDeviceLink_Example/Images.xcassets/hexagon_off_softbutton_icon.imageset/hexagon_black_softbutton_icon.png
deleted file mode 100644
index 2ec628d9e..000000000
--- a/SmartDeviceLink_Example/Images.xcassets/hexagon_off_softbutton_icon.imageset/hexagon_black_softbutton_icon.png
+++ /dev/null
Binary files differ
diff --git a/SmartDeviceLink_Example/Images.xcassets/hexagon_on_softbutton_icon.imageset/hexagon_pink_softbutton_icon.png b/SmartDeviceLink_Example/Images.xcassets/hexagon_on_softbutton_icon.imageset/hexagon_pink_softbutton_icon.png
deleted file mode 100644
index 8e588ebb5..000000000
--- a/SmartDeviceLink_Example/Images.xcassets/hexagon_on_softbutton_icon.imageset/hexagon_pink_softbutton_icon.png
+++ /dev/null
Binary files differ
diff --git a/SmartDeviceLink_Example/Images.xcassets/hexagon_on_softbutton_icon.imageset/Contents.json b/SmartDeviceLink_Example/Images.xcassets/laptop_icon.imageset/Contents.json
index 5e22962d4..616325375 100644
--- a/SmartDeviceLink_Example/Images.xcassets/hexagon_on_softbutton_icon.imageset/Contents.json
+++ b/SmartDeviceLink_Example/Images.xcassets/laptop_icon.imageset/Contents.json
@@ -2,7 +2,7 @@
"images" : [
{
"idiom" : "universal",
- "filename" : "hexagon_pink_softbutton_icon.png",
+ "filename" : "screen.png",
"scale" : "1x"
},
{
diff --git a/SmartDeviceLink_Example/Images.xcassets/laptop_icon.imageset/screen.png b/SmartDeviceLink_Example/Images.xcassets/laptop_icon.imageset/screen.png
new file mode 100644
index 000000000..33b727eae
--- /dev/null
+++ b/SmartDeviceLink_Example/Images.xcassets/laptop_icon.imageset/screen.png
Binary files differ
diff --git a/SmartDeviceLink_Example/Images.xcassets/hexagon_off_softbutton_icon.imageset/Contents.json b/SmartDeviceLink_Example/Images.xcassets/microphone.imageset/Contents.json
index 9affc0da6..4620dff89 100644
--- a/SmartDeviceLink_Example/Images.xcassets/hexagon_off_softbutton_icon.imageset/Contents.json
+++ b/SmartDeviceLink_Example/Images.xcassets/microphone.imageset/Contents.json
@@ -2,7 +2,7 @@
"images" : [
{
"idiom" : "universal",
- "filename" : "hexagon_black_softbutton_icon.png",
+ "filename" : "microphone.png",
"scale" : "1x"
},
{
diff --git a/SmartDeviceLink_Example/Images.xcassets/microphone.imageset/microphone.png b/SmartDeviceLink_Example/Images.xcassets/microphone.imageset/microphone.png
new file mode 100644
index 000000000..8ccae2bcb
--- /dev/null
+++ b/SmartDeviceLink_Example/Images.xcassets/microphone.imageset/microphone.png
Binary files differ
diff --git a/SmartDeviceLink_Example/Images.xcassets/phone.imageset/Contents.json b/SmartDeviceLink_Example/Images.xcassets/phone.imageset/Contents.json
new file mode 100644
index 000000000..feb2dff17
--- /dev/null
+++ b/SmartDeviceLink_Example/Images.xcassets/phone.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "phone.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/SmartDeviceLink_Example/Images.xcassets/phone.imageset/phone.png b/SmartDeviceLink_Example/Images.xcassets/phone.imageset/phone.png
new file mode 100644
index 000000000..7c7eff383
--- /dev/null
+++ b/SmartDeviceLink_Example/Images.xcassets/phone.imageset/phone.png
Binary files differ
diff --git a/SmartDeviceLink_Example/Images.xcassets/star_softbutton_icon.imageset/star_black_softbutton_icon.png b/SmartDeviceLink_Example/Images.xcassets/star_softbutton_icon.imageset/star_black_softbutton_icon.png
deleted file mode 100644
index 70812b60a..000000000
--- a/SmartDeviceLink_Example/Images.xcassets/star_softbutton_icon.imageset/star_black_softbutton_icon.png
+++ /dev/null
Binary files differ
diff --git a/SmartDeviceLink_Example/Images.xcassets/wheel_icon.imageset/Contents.json b/SmartDeviceLink_Example/Images.xcassets/wheel_icon.imageset/Contents.json
new file mode 100644
index 000000000..e5dbc5bd1
--- /dev/null
+++ b/SmartDeviceLink_Example/Images.xcassets/wheel_icon.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "wheel.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/SmartDeviceLink_Example/Images.xcassets/wheel_icon.imageset/wheel.png b/SmartDeviceLink_Example/Images.xcassets/wheel_icon.imageset/wheel.png
new file mode 100644
index 000000000..bd99c3f49
--- /dev/null
+++ b/SmartDeviceLink_Example/Images.xcassets/wheel_icon.imageset/wheel.png
Binary files differ
diff --git a/SmartDeviceLink_Example/LaunchScreen.xib b/SmartDeviceLink_Example/LaunchScreen.xib
new file mode 100644
index 000000000..fc726aac2
--- /dev/null
+++ b/SmartDeviceLink_Example/LaunchScreen.xib
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16E195" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
+ <device id="retina4_7" orientation="portrait">
+ <adaptation id="fullscreen"/>
+ </device>
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <objects>
+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+ <view contentMode="scaleToFill" id="iN0-l3-epB">
+ <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sdl_logo_green" translatesAutoresizingMaskIntoConstraints="NO" id="poo-xI-0Ul">
+ <rect key="frame" x="135" y="135" width="210" height="210"/>
+ </imageView>
+ </subviews>
+ <color key="backgroundColor" red="0.22352941176470587" green="0.30588235294117649" blue="0.37647058823529411" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <constraints>
+ <constraint firstAttribute="bottom" secondItem="poo-xI-0Ul" secondAttribute="bottom" constant="135" id="Aoi-5X-ydr"/>
+ <constraint firstItem="poo-xI-0Ul" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="135" id="VYi-CO-nXk"/>
+ <constraint firstAttribute="trailing" secondItem="poo-xI-0Ul" secondAttribute="trailing" constant="135" id="ZvS-nt-v4W"/>
+ <constraint firstItem="poo-xI-0Ul" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="135" id="dyt-I7-yml"/>
+ </constraints>
+ <nil key="simulatedStatusBarMetrics"/>
+ <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+ <point key="canvasLocation" x="548" y="455"/>
+ </view>
+ </objects>
+ <resources>
+ <image name="sdl_logo_green" width="131" height="122"/>
+ </resources>
+</document>
diff --git a/SmartDeviceLink_Example/Main.storyboard b/SmartDeviceLink_Example/Main.storyboard
new file mode 100644
index 000000000..0bb92be82
--- /dev/null
+++ b/SmartDeviceLink_Example/Main.storyboard
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="mM3-m6-I5t">
+ <device id="retina4_7" orientation="portrait">
+ <adaptation id="fullscreen"/>
+ </device>
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <scenes>
+ <!--Navigation Controller-->
+ <scene sceneID="Tfy-dw-box">
+ <objects>
+ <navigationController automaticallyAdjustsScrollViewInsets="NO" id="mM3-m6-I5t" sceneMemberID="viewController">
+ <toolbarItems/>
+ <navigationBar key="navigationBar" contentMode="scaleToFill" id="eMh-g9-C8T">
+ <rect key="frame" x="0.0" y="20" width="375" height="44"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </navigationBar>
+ <nil name="viewControllers"/>
+ <connections>
+ <segue destination="cXb-Co-0MA" kind="relationship" relationship="rootViewController" id="tbn-vJ-YS8"/>
+ </connections>
+ </navigationController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="eXu-Zc-53v" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="896" y="527"/>
+ </scene>
+ <!--Connection Container View Controller-->
+ <scene sceneID="vG9-Hv-OW2">
+ <objects>
+ <viewController id="cXb-Co-0MA" customClass="ConnectionContainerViewController" customModule="SmartDeviceLink_Example_Swift" customModuleProvider="target" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="bfp-O0-sxl"/>
+ <viewControllerLayoutGuide type="bottom" id="fet-m3-F1O"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="jkb-9Y-Hwh">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ </view>
+ <navigationItem key="navigationItem" id="t1a-s2-nn6">
+ <nil key="title"/>
+ <segmentedControl key="titleView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bar" selectedSegmentIndex="0" id="RYa-fE-Qek">
+ <rect key="frame" x="67.5" y="7" width="240" height="30"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <segments>
+ <segment title="TCP Debug"/>
+ <segment title="iAP"/>
+ </segments>
+ <connections>
+ <action selector="indexChanged:" destination="cXb-Co-0MA" eventType="valueChanged" id="mRP-MF-F8c"/>
+ </connections>
+ </segmentedControl>
+ </navigationItem>
+ <connections>
+ <outlet property="segmentedControl" destination="RYa-fE-Qek" id="Ude-uG-TAL"/>
+ </connections>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="ETn-uq-A6g" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="1576" y="527"/>
+ </scene>
+ </scenes>
+</document>
diff --git a/SmartDeviceLink_Example/MenuManager.h b/SmartDeviceLink_Example/MenuManager.h
new file mode 100644
index 000000000..dfcc15445
--- /dev/null
+++ b/SmartDeviceLink_Example/MenuManager.h
@@ -0,0 +1,24 @@
+//
+// MenuManager.h
+// SmartDeviceLink-Example-ObjC
+//
+// Created by Nicole on 5/15/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@class SDLManager;
+@class SDLMenuCell;
+@class SDLVoiceCommand;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MenuManager : NSObject
+
++ (NSArray<SDLMenuCell *> *)allMenuItemsWithManager:(SDLManager *)manager;
++ (NSArray<SDLVoiceCommand *> *)allVoiceMenuItemsWithManager:(SDLManager *)manager;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/MenuManager.m b/SmartDeviceLink_Example/MenuManager.m
new file mode 100644
index 000000000..ccf91cef8
--- /dev/null
+++ b/SmartDeviceLink_Example/MenuManager.m
@@ -0,0 +1,106 @@
+//
+// MenuManager.m
+// SmartDeviceLink-Example-ObjC
+//
+// Created by Nicole on 5/15/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import "MenuManager.h"
+#import "AlertManager.h"
+#import "AudioManager.h"
+#import "AppConstants.h"
+#import "PerformInteractionManager.h"
+#import "RPCPermissionsManager.h"
+#import "SmartDeviceLink.h"
+#import "VehicleDataManager.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation MenuManager
+
++ (NSArray<SDLMenuCell *> *)allMenuItemsWithManager:(SDLManager *)manager {
+ return @[[self sdlex_menuCellSpeakNameWithManager:manager],
+ [self sdlex_menuCellGetVehicleSpeedWithManager:manager],
+ [self sdlex_menuCellShowPerformInteractionWithManager:manager],
+ [self sdlex_menuCellRecordInCarMicrophoneAudioWithManager:manager],
+ [self sdlex_menuCellDialNumberWithManager:manager],
+ [self sdlex_menuCellWithSubmenuWithManager:manager]];
+}
+
++ (NSArray<SDLVoiceCommand *> *)allVoiceMenuItemsWithManager:(SDLManager *)manager {
+ if (!manager.systemCapabilityManager.vrCapability) {
+ SDLLogE(@"The head unit does not support voice recognition");
+ return @[];
+ }
+
+ return @[[self.class sdlex_voiceCommandStartWithManager:manager], [self.class sdlex_voiceCommandStopWithManager:manager]];
+}
+
+#pragma mark - Menu Items
+
++ (SDLMenuCell *)sdlex_menuCellSpeakNameWithManager:(SDLManager *)manager {
+ return [[SDLMenuCell alloc] initWithTitle:ACSpeakAppNameMenuName icon:[SDLArtwork artworkWithImage:[UIImage imageNamed:SpeakBWIconImageName] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:@[ACSpeakAppNameMenuName] handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ [manager sendRequest:[[SDLSpeak alloc] initWithTTS:ExampleAppNameTTS]];
+ }];
+}
+
++ (SDLMenuCell *)sdlex_menuCellGetVehicleSpeedWithManager:(SDLManager *)manager {
+ return [[SDLMenuCell alloc] initWithTitle:ACGetVehicleDataMenuName icon:[SDLArtwork artworkWithImage:[UIImage imageNamed:CarBWIconImageName] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:@[ACGetVehicleDataMenuName] handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ [VehicleDataManager getVehicleSpeedWithManager:manager];
+ }];
+}
+
++ (SDLMenuCell *)sdlex_menuCellShowPerformInteractionWithManager:(SDLManager *)manager {
+ return [[SDLMenuCell alloc] initWithTitle:ACShowChoiceSetMenuName icon:[SDLArtwork artworkWithImage:[UIImage imageNamed:MenuBWIconImageName] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:@[ACShowChoiceSetMenuName] handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ [PerformInteractionManager showPerformInteractionChoiceSetWithManager:manager triggerSource:triggerSource];
+ }];
+}
+
++ (SDLMenuCell *)sdlex_menuCellRecordInCarMicrophoneAudioWithManager:(SDLManager *)manager {
+ AudioManager *audioManager = [[AudioManager alloc] initWithManager:manager];
+ return [[SDLMenuCell alloc] initWithTitle:ACRecordInCarMicrophoneAudioMenuName icon:[SDLArtwork artworkWithImage:[UIImage imageNamed:MicrophoneBWIconImageName] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:@[ACRecordInCarMicrophoneAudioMenuName] handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ [audioManager startRecording];
+ }];
+}
+
++ (SDLMenuCell *)sdlex_menuCellDialNumberWithManager:(SDLManager *)manager {
+ return [[SDLMenuCell alloc] initWithTitle:ACDialPhoneNumberMenuName icon:[SDLArtwork artworkWithImage:[UIImage imageNamed:PhoneBWIconImageName] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:@[ACDialPhoneNumberMenuName] handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ if (![RPCPermissionsManager isDialNumberRPCAllowedWithManager:manager]) {
+ [manager sendRequest:[AlertManager alertWithMessageAndCloseButton:@"This app does not have the required permissions to dial a number" textField2:nil]];
+ return;
+ }
+
+ [VehicleDataManager checkPhoneCallCapabilityWithManager:manager phoneNumber:@"555-555-5555"];
+ }];
+}
+
++ (SDLMenuCell *)sdlex_menuCellWithSubmenuWithManager:(SDLManager *)manager {
+ NSMutableArray *submenuItems = [NSMutableArray array];
+ for (int i = 0; i < 75; i++) {
+ SDLMenuCell *cell = [[SDLMenuCell alloc] initWithTitle:[NSString stringWithFormat:@"%@ %i", ACSubmenuItemMenuName, i] icon:[SDLArtwork artworkWithImage:[UIImage imageNamed:MenuBWIconImageName] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ [manager sendRequest:[AlertManager alertWithMessageAndCloseButton:[NSString stringWithFormat:@"You selected %@ %i", ACSubmenuItemMenuName, i] textField2:nil]];
+ }];
+ [submenuItems addObject:cell];
+ }
+
+ return [[SDLMenuCell alloc] initWithTitle:ACSubmenuMenuName subCells:[submenuItems copy]];
+}
+
+#pragma mark - Voice Commands
+
++ (SDLVoiceCommand *)sdlex_voiceCommandStartWithManager:(SDLManager *)manager {
+ return [[SDLVoiceCommand alloc] initWithVoiceCommands:@[VCStop] handler:^{
+ [manager sendRequest:[AlertManager alertWithMessageAndCloseButton:[NSString stringWithFormat:@"%@ voice command selected!", VCStop] textField2:nil]];
+ }];
+}
+
++ (SDLVoiceCommand *)sdlex_voiceCommandStopWithManager:(SDLManager *)manager {
+ return [[SDLVoiceCommand alloc] initWithVoiceCommands:@[VCStart] handler:^{
+ [manager sendRequest:[AlertManager alertWithMessageAndCloseButton:[NSString stringWithFormat:@"%@ voice command selected!", VCStart] textField2:nil]];
+ }];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/MenuManager.swift b/SmartDeviceLink_Example/MenuManager.swift
new file mode 100644
index 000000000..cba211043
--- /dev/null
+++ b/SmartDeviceLink_Example/MenuManager.swift
@@ -0,0 +1,154 @@
+//
+// MenuManager.swift
+// SmartDeviceLink-Example-Swift
+//
+// Created by Nicole on 4/11/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+import Foundation
+import SmartDeviceLink
+import SmartDeviceLinkSwift
+
+class MenuManager: NSObject {
+ /// Creates and returns the menu items
+ ///
+ /// - Parameter manager: The SDL Manager
+ /// - Returns: An array of SDLAddCommand objects
+ class func allMenuItems(with manager: SDLManager) -> [SDLMenuCell] {
+ return [menuCellSpeakName(with: manager),
+ menuCellGetVehicleSpeed(with: manager),
+ menuCellShowPerformInteraction(with: manager),
+ menuCellRecordInCarMicrophoneAudio(with: manager),
+ menuCellDialNumber(with: manager),
+ menuCellWithSubmenu(with: manager)]
+ }
+
+ /// Creates and returns the voice commands. The voice commands are menu items that are selected using the voice recognition system.
+ ///
+ /// - Parameter manager: The SDL Manager
+ /// - Returns: An array of SDLVoiceCommand objects
+ class func allVoiceMenuItems(with manager: SDLManager) -> [SDLVoiceCommand] {
+ guard manager.systemCapabilityManager.vrCapability else {
+ SDLLog.e("The head unit does not support voice recognition")
+ return []
+ }
+ return [voiceCommandStart(with: manager), voiceCommandStop(with: manager)]
+ }
+}
+
+// MARK: - Root Menu
+
+private extension MenuManager {
+ /// Menu item that speaks the app name when selected
+ ///
+ /// - Parameter manager: The SDL Manager
+ /// - Returns: A SDLMenuCell object
+ class func menuCellSpeakName(with manager: SDLManager) -> SDLMenuCell {
+ return SDLMenuCell(title: ACSpeakAppNameMenuName, icon: SDLArtwork(image: UIImage(named: SpeakBWIconImageName)!, persistent: true, as: .PNG), voiceCommands: [ACSpeakAppNameMenuName], handler: { _ in
+ manager.send(request: SDLSpeak(tts: ExampleAppNameTTS), responseHandler: { (_, response, error) in
+ guard response?.resultCode == .success else { return }
+ SDLLog.e("Error sending the Speak RPC: \(error?.localizedDescription ?? "no error message")")
+ })
+ })
+ }
+
+ /// Menu item that requests vehicle data when selected
+ ///
+ /// - Parameter manager: The SDL Manager
+ /// - Returns: A SDLMenuCell object
+ class func menuCellGetVehicleSpeed(with manager: SDLManager) -> SDLMenuCell {
+ return SDLMenuCell(title: ACGetVehicleDataMenuName, icon: SDLArtwork(image: UIImage(named: CarBWIconImageName)!, persistent: true, as: .PNG), voiceCommands: [ACGetVehicleDataMenuName], handler: { _ in
+ VehicleDataManager.getVehicleSpeed(with: manager)
+ })
+ }
+
+ /// Menu item that shows a custom menu (i.e. a Perform Interaction Choice Set) when selected
+ ///
+ /// - Parameter manager: The SDL Manager
+ /// - Returns: A SDLMenuCell object
+ class func menuCellShowPerformInteraction(with manager: SDLManager) -> SDLMenuCell {
+ return SDLMenuCell(title: ACShowChoiceSetMenuName, icon: SDLArtwork(image: UIImage(named: MenuBWIconImageName)!, persistent: true, as: .PNG), voiceCommands: [ACShowChoiceSetMenuName], handler: { triggerSource in
+ PerformInteractionManager.showPerformInteractionChoiceSet(with: manager, triggerSource: triggerSource)
+ })
+ }
+
+ /// Menu item that starts recording sounds via the in-car microphone when selected
+ ///
+ /// - Parameter manager: The SDL Manager
+ /// - Returns: A SDLMenuCell object
+ class func menuCellRecordInCarMicrophoneAudio(with manager: SDLManager) -> SDLMenuCell {
+ if #available(iOS 10.0, *) {
+ let audioManager = AudioManager(sdlManager: manager)
+ return SDLMenuCell(title: ACRecordInCarMicrophoneAudioMenuName, icon: SDLArtwork(image: UIImage(named: MicrophoneBWIconImageName)!, persistent: true, as: .PNG), voiceCommands: [ACRecordInCarMicrophoneAudioMenuName], handler: { _ in
+ audioManager.startRecording()
+ })
+ }
+
+ return SDLMenuCell(title: ACRecordInCarMicrophoneAudioMenuName, icon: SDLArtwork(image: UIImage(named: SpeakBWIconImageName)!, persistent: true, as: .PNG), voiceCommands: [ACRecordInCarMicrophoneAudioMenuName], handler: { _ in
+ manager.send(AlertManager.alertWithMessageAndCloseButton("Speech recognition feature only available on iOS 10+"))
+ })
+ }
+
+ /// Menu item that dials a phone number when selected
+ ///
+ /// - Parameter manager: The SDL Manager
+ /// - Returns: A SDLMenuCell object
+ class func menuCellDialNumber(with manager: SDLManager) -> SDLMenuCell {
+ return SDLMenuCell(title: ACDialPhoneNumberMenuName, icon: SDLArtwork(image: UIImage(named: PhoneBWIconImageName)!, persistent: true, as: .PNG), voiceCommands: [ACDialPhoneNumberMenuName], handler: { _ in
+ guard RPCPermissionsManager.isDialNumberRPCAllowed(with: manager) else {
+ manager.send(AlertManager.alertWithMessageAndCloseButton("This app does not have the required permissions to dial a number"))
+ return
+ }
+
+ VehicleDataManager.checkPhoneCallCapability(manager: manager, phoneNumber:"555-555-5555")
+ })
+ }
+
+ /// Menu item that opens a submenu when selected
+ ///
+ /// - Parameter manager: The SDL Manager
+ /// - Returns: A SDLMenuCell object
+ class func menuCellWithSubmenu(with manager: SDLManager) -> SDLMenuCell {
+ var submenuItems = [SDLMenuCell]()
+ for i in 0..<75 {
+ let submenuTitle = "Submenu Item \(i)"
+ submenuItems.append(SDLMenuCell(title: submenuTitle, icon: SDLArtwork(image: UIImage(named: MenuBWIconImageName)!, persistent: true, as: .PNG), voiceCommands: [submenuTitle, "Item \(i)", "\(i)"], handler: { (triggerSource) in
+ let message = "\(submenuTitle) selected!"
+ switch triggerSource {
+ case .menu:
+ manager.send(AlertManager.alertWithMessageAndCloseButton(message))
+ case .voiceRecognition:
+ manager.send(SDLSpeak(tts: message))
+ default: break
+ }
+ }))
+ }
+
+ return SDLMenuCell(title: "Submenu", subCells: submenuItems)
+ }
+}
+
+// MARK: - Menu Voice Commands
+
+private extension MenuManager {
+ /// Voice command menu item that shows an alert when triggered via the VR system
+ ///
+ /// - Parameter manager: The SDL Manager
+ /// - Returns: A SDLVoiceCommand object
+ class func voiceCommandStart(with manager: SDLManager) -> SDLVoiceCommand {
+ return SDLVoiceCommand(voiceCommands: [VCStart], handler: {
+ manager.send(AlertManager.alertWithMessageAndCloseButton("\(VCStart) voice command selected!"))
+ })
+ }
+
+ /// Voice command menu item that shows an alert when triggered via the VR system
+ ///
+ /// - Parameter manager: The SDL Manager
+ /// - Returns: A SDLVoiceCommand object
+ class func voiceCommandStop(with manager: SDLManager) -> SDLVoiceCommand {
+ return SDLVoiceCommand(voiceCommands: [VCStop], handler: {
+ manager.send(AlertManager.alertWithMessageAndCloseButton("\(VCStop) voice command selected!"))
+ })
+ }
+}
diff --git a/SmartDeviceLink_Example/PerformInteractionManager.h b/SmartDeviceLink_Example/PerformInteractionManager.h
new file mode 100644
index 000000000..73e79e515
--- /dev/null
+++ b/SmartDeviceLink_Example/PerformInteractionManager.h
@@ -0,0 +1,24 @@
+//
+// PerformInteractionManager.h
+// SmartDeviceLink-Example-ObjC
+//
+// Created by Nicole on 5/15/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "SDLTriggerSource.h"
+
+@class SDLCreateInteractionChoiceSet;
+@class SDLManager;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface PerformInteractionManager : NSObject
+
++ (SDLCreateInteractionChoiceSet *)createInteractionChoiceSet;
++ (void)showPerformInteractionChoiceSetWithManager:(SDLManager *)manager triggerSource:(SDLTriggerSource)triggerSource;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/PerformInteractionManager.m b/SmartDeviceLink_Example/PerformInteractionManager.m
new file mode 100644
index 000000000..6e6523174
--- /dev/null
+++ b/SmartDeviceLink_Example/PerformInteractionManager.m
@@ -0,0 +1,56 @@
+//
+// PerformInteractionManager.m
+// SmartDeviceLink-Example-ObjC
+//
+// Created by Nicole on 5/15/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import "PerformInteractionManager.h"
+#import "AppConstants.h"
+#import "SmartDeviceLink.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation PerformInteractionManager
+
+static UInt32 ChoiceSetId = 100;
+
++ (SDLCreateInteractionChoiceSet *)createInteractionChoiceSet {
+ return [[SDLCreateInteractionChoiceSet alloc] initWithId:ChoiceSetId choiceSet:[self sdlex_createChoiceSet]];
+}
+
++ (void)showPerformInteractionChoiceSetWithManager:(SDLManager *)manager triggerSource:(SDLTriggerSource)triggerSource {
+ [manager sendRequest:[self sdlex_createPerformInteractionWithTriggerSource:triggerSource] withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
+ if (response.resultCode != SDLResultSuccess) {
+ SDLLogE(@"The Show Perform Interaction Choice Set request failed: %@", error.localizedDescription);
+ return;
+ }
+
+ if ([response.resultCode isEqualToEnum:SDLResultTimedOut]) {
+ SDLLogD(@"The perform interaction choice set menu timed out before the user could select an item");
+ [manager sendRequest:[[SDLSpeak alloc] initWithTTS:TTSYouMissed]];
+ } else if ([response.resultCode isEqualToEnum:SDLResultSuccess]) {
+ SDLLogD(@"The user selected an item in the perform interaction choice set menu");
+ [manager sendRequest:[[SDLSpeak alloc] initWithTTS:TTSGoodJob]];
+ }
+ }];
+}
+
++ (NSArray<SDLChoice *> *)sdlex_createChoiceSet {
+ SDLChoice *firstChoice = [[SDLChoice alloc] initWithId:1 menuName:PICSFirstChoice vrCommands:@[PICSFirstChoice]];
+ SDLChoice *secondChoice = [[SDLChoice alloc] initWithId:2 menuName:PICSSecondChoice vrCommands:@[PICSSecondChoice]];
+ SDLChoice *thirdChoice = [[SDLChoice alloc] initWithId:3 menuName:PICSThirdChoice vrCommands:@[PICSThirdChoice]];
+ return @[firstChoice, secondChoice, thirdChoice];
+}
+
++ (SDLPerformInteraction *)sdlex_createPerformInteractionWithTriggerSource:(SDLTriggerSource)triggerSource {
+ SDLInteractionMode interactionMode = [triggerSource isEqualToEnum:SDLTriggerSourceVoiceRecognition] ? SDLInteractionModeVoiceRecognitionOnly : SDLInteractionModeManualOnly;
+ SDLPerformInteraction *performInteraction = [[SDLPerformInteraction alloc] initWithInitialPrompt:PICSInitialPrompt initialText:PICSInitialText interactionChoiceSetIDList:@[@(ChoiceSetId)] helpPrompt:PICSHelpPrompt timeoutPrompt:PICSTimeoutPrompt interactionMode:interactionMode timeout:10000];
+ performInteraction.interactionLayout = SDLLayoutModeListOnly;
+ return performInteraction;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/PerformInteractionManager.swift b/SmartDeviceLink_Example/PerformInteractionManager.swift
new file mode 100644
index 000000000..021997923
--- /dev/null
+++ b/SmartDeviceLink_Example/PerformInteractionManager.swift
@@ -0,0 +1,65 @@
+//
+// PerformInteractionManager.swift
+// SmartDeviceLink-Example-Swift
+//
+// Created by Nicole on 5/15/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+import UIKit
+import SmartDeviceLink
+import SmartDeviceLinkSwift
+
+class PerformInteractionManager: NSObject {
+ /// Creates a choice set to be used in a PerformInteraction. The choice set must be sent to SDL Core and a response received before it can be used in a PerformInteraction request.
+ ///
+ /// - Returns: A SDLCreateInteractionChoiceSet request
+ class func createInteractionChoiceSet() -> SDLCreateInteractionChoiceSet {
+ return SDLCreateInteractionChoiceSet(id: UInt32(ChoiceSetId), choiceSet: createChoiceSet())
+ }
+
+ /// Shows a PICS. The handler is called when the user selects a menu item or when the menu times out after a set amount of time. A custom text-to-speech phrase is spoken when the menu is closed.
+ ///
+ /// - Parameter manager: The SDL Manager
+ class func showPerformInteractionChoiceSet(with manager: SDLManager, triggerSource: SDLTriggerSource) {
+ manager.send(request: createPerformInteraction(triggerSource: triggerSource)) { (_, response, error) in
+ guard response?.resultCode == .success else {
+ SDLLog.e("The Show Perform Interaction Choice Set request failed: \(error?.localizedDescription ?? "no error")")
+ return
+ }
+
+ if response?.resultCode == .timedOut {
+ // The menu timed out before the user could select an item
+ manager.send(SDLSpeak(tts: TTSYouMissed))
+ } else if response?.resultCode == .success {
+ // The user selected an item in the menu
+ manager.send(SDLSpeak(tts: TTSGoodJob))
+ }
+ }
+ }
+}
+
+// MARK: - PICS Menu
+
+private extension PerformInteractionManager {
+ static let ChoiceSetId = 100
+ /// The PICS menu items
+ ///
+ /// - Returns: An array of SDLChoice items
+ class func createChoiceSet() -> [SDLChoice] {
+ let firstChoice = SDLChoice(id: 1, menuName: PICSFirstChoice, vrCommands: [PICSFirstChoice])
+ let secondChoice = SDLChoice(id: 2, menuName: PICSSecondChoice, vrCommands: [PICSSecondChoice])
+ let thirdChoice = SDLChoice(id: 3, menuName: PICSThirdChoice, vrCommands: [PICSThirdChoice])
+ return [firstChoice, secondChoice, thirdChoice]
+ }
+
+ /// Creates a PICS with three menu items and customized voice commands
+ ///
+ /// - Returns: A SDLPerformInteraction request
+ class func createPerformInteraction(triggerSource: SDLTriggerSource) -> SDLPerformInteraction {
+ let interactionMode: SDLInteractionMode = triggerSource == .voiceRecognition ? .voiceRecognitionOnly : .manualOnly
+ let performInteraction = SDLPerformInteraction(initialPrompt: PICSInitialPrompt, initialText: PICSInitialText, interactionChoiceSetIDList: [ChoiceSetId as NSNumber], helpPrompt: PICSHelpPrompt, timeoutPrompt: PICSTimeoutPrompt, interactionMode: interactionMode, timeout: 10000)
+ performInteraction.interactionLayout = .listOnly
+ return performInteraction
+ }
+}
diff --git a/SmartDeviceLink_Example/Protocol+ProxyManagerDelegate.swift b/SmartDeviceLink_Example/Protocol+ProxyManagerDelegate.swift
new file mode 100644
index 000000000..ede7b7701
--- /dev/null
+++ b/SmartDeviceLink_Example/Protocol+ProxyManagerDelegate.swift
@@ -0,0 +1,13 @@
+//
+// Protocol+ProxyManagerDelegate.swift
+// SmartDeviceLink
+//
+// Created by Nicole on 4/12/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+import Foundation
+
+protocol ProxyManagerDelegate: class {
+ func didChangeProxyState(_ newState: ProxyState)
+}
diff --git a/SmartDeviceLink_Example/ProxyManager.swift b/SmartDeviceLink_Example/ProxyManager.swift
new file mode 100644
index 000000000..7ecc28679
--- /dev/null
+++ b/SmartDeviceLink_Example/ProxyManager.swift
@@ -0,0 +1,285 @@
+//
+// ProxyManager.swift
+// SmartDeviceLink-ExampleSwift
+//
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+import UIKit
+import SmartDeviceLink
+import SmartDeviceLinkSwift
+
+enum ProxyTransportType {
+ case tcp
+ case iap
+}
+
+enum ProxyState {
+ case stopped
+ case searching
+ case connected
+}
+
+class ProxyManager: NSObject {
+ fileprivate var sdlManager: SDLManager!
+ fileprivate var buttonManager: ButtonManager!
+ fileprivate var vehicleDataManager: VehicleDataManager!
+ fileprivate var firstHMILevelState: SDLHMILevel
+ weak var delegate: ProxyManagerDelegate?
+
+ // Singleton
+ static let sharedManager = ProxyManager()
+ private override init() {
+ firstHMILevelState = .none
+ super.init()
+ }
+}
+
+// MARK: - SDL Configuration
+
+extension ProxyManager {
+ /// Configures the SDL Manager that handles data transfer beween this app and the car's head unit and starts searching for a connection to a head unit. There are two possible types of transport layers to use: TCP is used to connect wirelessly to SDL Core and is only available for debugging; iAP is used to connect to MFi (Made for iPhone) hardware and is must be used for production builds.
+ ///
+ /// - Parameter connectionType: The type of transport layer to use.
+ func start(with proxyTransportType: ProxyTransportType) {
+ delegate?.didChangeProxyState(ProxyState.searching)
+ sdlManager = SDLManager(configuration: proxyTransportType == .iap ? ProxyManager.connectIAP() : ProxyManager.connectTCP(), delegate: self)
+ startManager()
+ }
+
+ /// Attempts to close the connection between the this app and the car's head unit. The `SDLManagerDelegate`'s `managerDidDisconnect()` is called when connection is actually closed.
+ func resetConnection() {
+ guard sdlManager != nil else {
+ delegate?.didChangeProxyState(ProxyState.stopped)
+ return
+ }
+
+ sdlManager.stop()
+ }
+}
+
+// MARK: - SDL Configuration Helpers
+
+private extension ProxyManager {
+ /// Configures an iAP transport layer.
+ ///
+ /// - Returns: A SDLConfiguration object
+ class func connectIAP() -> SDLConfiguration {
+ let lifecycleConfiguration = SDLLifecycleConfiguration(appName: ExampleAppName, appId: ExampleAppId)
+ return setupManagerConfiguration(with: lifecycleConfiguration)
+ }
+
+ /// Configures a TCP transport layer with the IP address and port of the remote SDL Core instance.
+ ///
+ /// - Returns: A SDLConfiguration object
+ class func connectTCP() -> SDLConfiguration {
+ let lifecycleConfiguration = SDLLifecycleConfiguration(appName: ExampleAppName, appId: ExampleAppId, ipAddress: AppUserDefaults.shared.ipAddress!, port: UInt16(AppUserDefaults.shared.port!)!)
+ return setupManagerConfiguration(with: lifecycleConfiguration)
+ }
+
+ /// Helper method for setting additional configuration parameters for both TCP and iAP transport layers.
+ ///
+ /// - Parameter lifecycleConfiguration: The transport layer configuration
+ /// - Returns: A SDLConfiguration object
+ class func setupManagerConfiguration(with lifecycleConfiguration: SDLLifecycleConfiguration) -> SDLConfiguration {
+ lifecycleConfiguration.shortAppName = ExampleAppNameShort
+ let appIcon = UIImage(named: ExampleAppLogoName)
+ lifecycleConfiguration.appIcon = appIcon != nil ? SDLArtwork(image: appIcon!, persistent: true, as: .PNG) : nil
+ lifecycleConfiguration.appType = .default
+ lifecycleConfiguration.language = .enUs
+ lifecycleConfiguration.languagesSupported = [.enUs, .esMx, .frCa]
+ lifecycleConfiguration.ttsName = [SDLTTSChunk(text: "S D L", type: .text)]
+
+ let lockScreenConfiguration = appIcon != nil ? SDLLockScreenConfiguration.enabledConfiguration(withAppIcon: appIcon!, backgroundColor: nil) : SDLLockScreenConfiguration.enabled()
+ return SDLConfiguration(lifecycle: lifecycleConfiguration, lockScreen: lockScreenConfiguration, logging: logConfiguration())
+ }
+
+ /// Sets the type of SDL debug logs that are visible and where to port the logs. There are 4 levels of log filtering, verbose, debug, warning and error. Verbose prints all SDL logs; error prints only the error logs. Adding SDLLogTargetFile to the targest will log to a text file on the iOS device. This file can be accessed via: iTunes > Your Device Name > File Sharing > Your App Name. Make sure `UIFileSharingEnabled` has been added to the application's info.plist and is set to `true`.
+ ///
+ /// - Returns: A SDLLogConfiguration object
+ class func logConfiguration() -> SDLLogConfiguration {
+ let logConfig = SDLLogConfiguration.default()
+ let exampleLogFileModule = SDLLogFileModule(name: "SDL Swift Example App", files: ["ProxyManager", "AlertManager", "AudioManager", "ButtonManager", "MenuManager", "PerformInteractionManager", "RPCPermissionsManager", "VehicleDataManager"])
+ logConfig.modules.insert(exampleLogFileModule)
+ _ = logConfig.targets.insert(SDLLogTargetFile()) // Logs to file
+ logConfig.globalLogLevel = .debug // Filters the logs
+ return logConfig
+ }
+
+ /// Searches for a connection to a SDL enabled accessory. When a connection has been established, the ready handler is called. Even though the app is connected to SDL Core, it does not mean that RPCs can be immediately sent to the accessory as there is no guarentee that SDL Core is ready to receive RPCs. Monitor the `SDLManagerDelegate`'s `hmiLevel:didChangeToLevel:` to determine when to send RPCs.
+ func startManager() {
+ sdlManager.start(readyHandler: { [unowned self] (success, error) in
+ guard success else {
+ SDLLog.e("There was an error while starting up: \(String(describing: error))")
+ self.resetConnection()
+ return
+ }
+
+ self.delegate?.didChangeProxyState(ProxyState.connected)
+
+ self.buttonManager = ButtonManager(sdlManager: self.sdlManager, updateScreenHandler: self.refreshUIHandler)
+ self.vehicleDataManager = VehicleDataManager(sdlManager: self.sdlManager, refreshUIHandler: self.refreshUIHandler)
+
+ RPCPermissionsManager.setupPermissionsCallbacks(with: self.sdlManager)
+
+ SDLLog.d("SDL file manager storage: \(self.sdlManager.fileManager.bytesAvailable / 1024 / 1024) mb")
+ })
+ }
+}
+
+// MARK: - SDLManagerDelegate
+
+extension ProxyManager: SDLManagerDelegate {
+ /// Called when the connection beween this app and SDL Core has closed.
+ func managerDidDisconnect() {
+ delegate?.didChangeProxyState(ProxyState.stopped)
+ firstHMILevelState = .none
+
+ // If desired, automatically start searching for a new connection to Core
+ if ExampleAppShouldRestartSDLManagerOnDisconnect.boolValue {
+ startManager()
+ }
+ }
+
+ /// Called when the state of the SDL app has changed. The state limits the type of RPC that can be sent. Refer to the class documentation for each RPC to determine what state(s) the RPC can be sent.
+ ///
+ /// - Parameters:
+ /// - oldLevel: The old SDL HMI Level
+ /// - newLevel: The new SDL HMI Level
+ func hmiLevel(_ oldLevel: SDLHMILevel, didChangeToLevel newLevel: SDLHMILevel) {
+ if newLevel != .none && firstHMILevelState == .none {
+ // This is our first time in a non-NONE state
+ firstHMILevelState = newLevel
+
+ // Send static menu items. Menu related RPCs can be sent at all `hmiLevel`s except `NONE`
+ createStaticMenus()
+ vehicleDataManager.subscribeToVehicleOdometer()
+ }
+
+ if newLevel == .full && firstHMILevelState != .full {
+ // This is our first time in a `FULL` state.
+ firstHMILevelState = newLevel
+ }
+
+ switch newLevel {
+ case .full: // The SDL app is in the foreground
+ // Always try to show the initial state to guard against some possible weird states. Duplicates will be ignored by Core.
+ showInitialData()
+ case .limited: break // An active NAV or MEDIA SDL app is in the background
+ case .background: break // The SDL app is not in the foreground
+ case .none: break // The SDL app is not yet running
+ default: break
+ }
+ }
+
+ func systemContext(_ oldContext: SDLSystemContext?, didChangeToContext newContext: SDLSystemContext) {
+ switch newContext {
+ case SDLSystemContext.alert: break
+ case SDLSystemContext.hmiObscured: break
+ case SDLSystemContext.main: break
+ case SDLSystemContext.menu: break
+ case SDLSystemContext.voiceRecognitionSession: break
+ default: break
+ }
+ }
+
+ /// Called when the audio state of the SDL app has changed. The audio state only needs to be monitored if the app is streaming audio.
+ ///
+ /// - Parameters:
+ /// - oldState: The old SDL audio streaming state
+ /// - newState: The new SDL audio streaming state
+ func audioStreamingState(_ oldState: SDLAudioStreamingState?, didChangeToState newState: SDLAudioStreamingState) {
+ switch newState {
+ case .audible: break // The SDL app's audio can be heard
+ case .notAudible: break // The SDL app's audio cannot be heard
+ case .attenuated: break // The SDL app's audio volume has been lowered to let the system speak over the audio. This usually happens with voice recognition commands.
+ default: break
+ }
+ }
+
+ /// Called when the car's head unit language is different from the default langage set in the SDLConfiguration AND the head unit language is supported by the app (as set in `languagesSupported` of SDLConfiguration). This method is only called when a connection to Core is first established. If desired, you can update the app's name and text-to-speech name to reflect the head unit's language.
+ ///
+ /// - Parameter language: The head unit's current language
+ /// - Returns: A SDLLifecycleConfigurationUpdate object
+ func managerShouldUpdateLifecycle(toLanguage language: SDLLanguage) -> SDLLifecycleConfigurationUpdate? {
+ var appName = ""
+ switch language {
+ case .enUs:
+ appName = ExampleAppName
+ case .esMx:
+ appName = ExampleAppNameSpanish
+ case .frCa:
+ appName = ExampleAppNameFrench
+ default:
+ return nil
+ }
+
+ return SDLLifecycleConfigurationUpdate(appName: appName, shortAppName: nil, ttsName: [SDLTTSChunk(text: appName, type: .text)], voiceRecognitionCommandNames: nil)
+ }
+}
+
+// MARK: - SDL UI
+
+private extension ProxyManager {
+ /// Handler for refreshing the UI
+ var refreshUIHandler: RefreshUIHandler? {
+ return { [unowned self] () in
+ self.updateScreen()
+ }
+ }
+
+ /// Set the template and create the UI
+ func showInitialData() {
+ guard sdlManager.hmiLevel == .full else { return }
+
+ updateScreen()
+ sdlManager.screenManager.softButtonObjects = buttonManager.allScreenSoftButtons(with: sdlManager)
+ }
+
+ /// Update the UI's textfields, images and soft buttons
+ func updateScreen() {
+ guard sdlManager.hmiLevel == .full else { return }
+
+ let screenManager = sdlManager.screenManager
+ let isTextVisible = buttonManager.textEnabled
+ let areImagesVisible = buttonManager.imagesEnabled
+
+ screenManager.beginUpdates()
+ screenManager.textAlignment = .left
+ screenManager.textField1 = isTextVisible ? SmartDeviceLinkText : nil
+ screenManager.textField2 = isTextVisible ? "Swift \(ExampleAppText)" : nil
+ screenManager.textField3 = isTextVisible ? vehicleDataManager.vehicleOdometerData : nil
+
+ if sdlManager.systemCapabilityManager.displayCapabilities?.graphicSupported.boolValue ?? false {
+ screenManager.primaryGraphic = areImagesVisible ? SDLArtwork(image: UIImage(named: ExampleAppLogoName)!, persistent: false, as: .PNG) : nil
+ }
+
+ screenManager.endUpdates(completionHandler: { (error) in
+ guard error != nil else { return }
+ SDLLog.e("Textfields, graphics and soft buttons failed to update: \(error!.localizedDescription)")
+ })
+ }
+
+ /// Send static menu data
+ func createStaticMenus() {
+ // Send the root menu items
+ let screenManager = sdlManager.screenManager
+ let menuItems = MenuManager.allMenuItems(with: sdlManager)
+ let voiceMenuItems = MenuManager.allVoiceMenuItems(with: sdlManager)
+
+ screenManager.beginUpdates()
+ if !menuItems.isEmpty { screenManager.menu = menuItems }
+ if !voiceMenuItems.isEmpty { screenManager.voiceCommands = voiceMenuItems }
+ screenManager.endUpdates { (error) in
+ guard error != nil else { return }
+ SDLLog.e("Menu items and voice commands failed to update: \(error!.localizedDescription)")
+ }
+
+ // Send the choice sets
+ sdlManager.send([PerformInteractionManager.createInteractionChoiceSet()], progressHandler: { (request, response, error, percentComplete) in
+ SDLLog.d("\(request), was sent \(response?.resultCode == .success ? "successfully" : "unsuccessfully"), error: \(error?.localizedDescription ?? "no error message")")
+ }, completionHandler: { (success) in
+ SDLLog.d("All prepare remote system requests sent \(success ? "successfully" : "unsuccessfully")")
+ })
+ }
+}
diff --git a/SmartDeviceLink_Example/RPCPermissionsManager.h b/SmartDeviceLink_Example/RPCPermissionsManager.h
new file mode 100644
index 000000000..09e321f31
--- /dev/null
+++ b/SmartDeviceLink_Example/RPCPermissionsManager.h
@@ -0,0 +1,21 @@
+//
+// RPCPermissionsManager.h
+// SmartDeviceLink-Example-ObjC
+//
+// Created by Nicole on 5/11/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "SmartDeviceLink.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RPCPermissionsManager : NSObject
+
++ (void)setupPermissionsCallbacksWithManager:(SDLManager *)manager;
++ (BOOL)isDialNumberRPCAllowedWithManager:(SDLManager *)manager;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/RPCPermissionsManager.m b/SmartDeviceLink_Example/RPCPermissionsManager.m
new file mode 100644
index 000000000..dc5cf6dfc
--- /dev/null
+++ b/SmartDeviceLink_Example/RPCPermissionsManager.m
@@ -0,0 +1,138 @@
+//
+// RPCPermissionsManager.m
+// SmartDeviceLink-Example-ObjC
+//
+// Created by Nicole on 5/11/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import "RPCPermissionsManager.h"
+#import "SDLLogMacros.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation RPCPermissionsManager
+
+/**
+ * Examples of how to check the permissions of select RPCs
+ *
+ * @param manager The SDL Manager
+ */
++ (void)setupPermissionsCallbacksWithManager:(SDLManager *)manager {
+ // Checks if the `SDLShow` RPC is allowed right at this moment
+ NSString *showRPCName = @"Show";
+ [self sdlex_checkCurrentPermissionWithManager:manager rpcName:showRPCName];
+
+ // Checks if all the RPCs need to create menus are allowed right at this moment
+ NSArray<NSString *> *menuRPCNames = @[@"AddCommand", @"CreateInteractionChoiceSet", @"PerformInteraction"];
+ [self sdlex_checkCurrentGroupPermissionsWithManager:manager rpcNames:menuRPCNames];
+
+ // Set up an observer for permissions changes to media template releated RPCs. Since the `groupType` is set to all allowed, this block is called when the group permissions changes from all allowed. This block is called immediately when created.
+ NSArray<NSString *> *mediaTemplateRPCs = @[@"SetMediaClockTimer", @"SubscribeButton"];
+ SDLPermissionObserverIdentifier allAllowedObserverId = [self sdlex_subscribeGroupPermissionsWithManager:manager rpcNames:mediaTemplateRPCs groupType:SDLPermissionGroupTypeAllAllowed];
+
+ // Stop observing permissions changes for the media template releated RPCs
+ [self sdlex_unsubscribeGroupPermissionsWithManager:manager observerId:allAllowedObserverId];
+
+ // Set up an observer for permissions changes to media template releated RPCs. Since the `groupType` is set to any, this block is called when the permission status changes for any of the RPCs being observed. This block is called immediately when created.
+ [self sdlex_subscribeGroupPermissionsWithManager:manager rpcNames:mediaTemplateRPCs groupType:SDLPermissionGroupTypeAny];
+}
+
+/**
+ * Checks if the `DialNumber` RPC is allowed
+ *
+ * @param manager The SDL Manager
+ * @return True if allowed, false if not
+ */
++ (BOOL)isDialNumberRPCAllowedWithManager:(SDLManager *)manager {
+ SDLLogD(@"Checking if app has permission to dial a number");
+ return [self sdlex_checkCurrentPermissionWithManager:manager rpcName:@"DialNumber"];
+}
+
+#pragma mark - Check Permissions
+
+#pragma mark Current Permissions
+
+/**
+ * Checks the current permissions of a single RPC
+ *
+ * @param manager The SDL Manager
+ * @param rpcName The name of the RPC
+ * @return True if the RPC can be sent to Core right now, false if not
+ */
++ (BOOL)sdlex_checkCurrentPermissionWithManager:(SDLManager *)manager rpcName:(NSString *)rpcName {
+ BOOL isRPCAllowed = [manager.permissionManager isRPCAllowed:rpcName];
+ [self sdlex_logRPCPermission:rpcName isRPCAllowed:isRPCAllowed];
+ return isRPCAllowed;
+}
+
+/**
+ * Checks the current permissions of a group of RPCs
+ *
+ * @param manager The SDL Manager
+ * @param rpcNames The names of the RPCs
+ * @return The current permission status for all the RPCs in the group
+ */
++ (SDLPermissionGroupStatus)sdlex_checkCurrentGroupPermissionsWithManager:(SDLManager *)manager rpcNames:(NSArray<NSString *> *)rpcNames {
+ SDLPermissionGroupStatus groupPermissionStatus = [manager.permissionManager groupStatusOfRPCs:rpcNames];
+ NSDictionary<NSString *, NSNumber *> *individualPermissionStatuses = [manager.permissionManager statusOfRPCs:rpcNames];
+ [self sdlex_logRPCGroupPermissions:rpcNames groupPermissionStatus:groupPermissionStatus individualPermissionStatuses:individualPermissionStatuses];
+ return groupPermissionStatus;
+}
+
+#pragma mark Subscribe Permissions
+
+/**
+ * Sets up a block for observing permission changes for a group of RPCs. This block is called immediately when created and when the permission status changes for the group of RPCs being observed.
+ *
+ * @param manager The SDL Manager
+ * @param rpcNames The names of the RPCs to be subscribed
+ * @param groupType The type of changes you want to be notified about for the group
+ * @return A unique identifier for the subscription. This can be used to later to unsubscribe from the notifications.
+ */
++ (SDLPermissionObserverIdentifier)sdlex_subscribeGroupPermissionsWithManager:(SDLManager *)manager rpcNames:(NSArray<NSString *> *)rpcNames groupType:(SDLPermissionGroupType)groupType {
+ SDLPermissionObserverIdentifier observerId = [manager.permissionManager addObserverForRPCs:rpcNames groupType:groupType withHandler:^(NSDictionary<SDLPermissionRPCName,NSNumber<SDLBool> *> * _Nonnull change, SDLPermissionGroupStatus status) {
+ [self sdlex_logRPCGroupPermissions:rpcNames groupPermissionStatus:status individualPermissionStatuses:change];
+ }];
+ return observerId;
+}
+
+/**
+ * Unsubscribe to notifications about permissions changes for a group of RPCs
+ *
+ * @param manager The SDL Manager
+ * @param observerId The unique identifier for a group of RPCs
+ */
++ (void)sdlex_unsubscribeGroupPermissionsWithManager:(SDLManager *)manager observerId:(SDLPermissionObserverIdentifier)observerId {
+ [manager.permissionManager removeObserverForIdentifier:observerId];
+}
+
+#pragma mark - Debug Logging
+
+/**
+ * Logs permissions for a single RPC
+ *
+ * @param rpcName The name of the RPC
+ * @param isRPCAllowed The permission status for the RPC
+ */
++ (void)sdlex_logRPCPermission:(NSString *)rpcName isRPCAllowed:(BOOL)isRPCAllowed {
+ SDLLogD(@"%@ RPC can be sent to SDL Core? %@", rpcName, isRPCAllowed ? @"Yes" : @"No");
+}
+
+/**
+ * Logs permissions for a group of RPCs
+ *
+ * @param rpcNames The names of the RPCs
+ * @param groupPermissionStatus The permission status for all RPCs in the group
+ * @param individualPermissionStatuses The permission status for each of the RPCs in the group
+ */
++ (void)sdlex_logRPCGroupPermissions:(NSArray<NSString *> *)rpcNames groupPermissionStatus:(SDLPermissionGroupStatus)groupPermissionStatus individualPermissionStatuses:(NSDictionary<NSString *, NSNumber *> *)individualPermissionStatuses {
+ SDLLogD(@"The group status for %@ has changed to: %lu", rpcNames, (unsigned long)groupPermissionStatus);
+ [individualPermissionStatuses enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSNumber * _Nonnull obj, BOOL * _Nonnull stop) {
+ [self sdlex_logRPCPermission:key isRPCAllowed:obj.boolValue];
+ }];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/RPCPermissionsManager.swift b/SmartDeviceLink_Example/RPCPermissionsManager.swift
new file mode 100644
index 000000000..72cdb8019
--- /dev/null
+++ b/SmartDeviceLink_Example/RPCPermissionsManager.swift
@@ -0,0 +1,119 @@
+//
+// RPCPermissionsManager.swift
+// SmartDeviceLink
+//
+// Created by Nicole on 4/13/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+import Foundation
+import SmartDeviceLink
+import SmartDeviceLinkSwift
+
+class RPCPermissionsManager {
+ /// Checks if an RPC has the required permission to be sent to SDL Core and gets notifications if those permissions change.
+ ///
+ /// - Parameter manager: The SDL Manager
+ class func setupPermissionsCallbacks(with manager: SDLManager) {
+ // Checks if the `SDLShow` RPC is allowed right at this moment
+ let showRPCName = "Show"
+ _ = checkCurrentPermission(with: manager, rpcName: showRPCName)
+
+ // Checks if all the RPCs need to create menus are allowed right at this moment
+ let menuRPCNames = ["AddCommand", "CreateInteractionChoiceSet", "PerformInteraction"]
+ _ = checkCurrentGroupPermissions(with: manager, rpcNames: menuRPCNames)
+
+ // Set up an observer for permissions changes to media template releated RPCs. Since the `groupType` is set to all allowed, this block is called when the group permissions changes from all allowed. This block is called immediately when created.
+ let mediaTemplateRPCs = ["SetMediaClockTimer", "SubscribeButton"]
+ let allAllowedObserverId = subscribeGroupPermissions(with: manager, rpcNames: mediaTemplateRPCs, groupType: .allAllowed)
+
+ // Stop observing permissions changes for the media template releated RPCs
+ unsubscribeGroupPermissions(with: manager, observerId: allAllowedObserverId)
+
+ // Sets up a block for observing permission changes for a group of RPCs. Since the `groupType` is set to any, this block is called when the permission status changes for any of the RPCs being observed. This block is called immediately when created.
+ _ = subscribeGroupPermissions(with: manager, rpcNames: mediaTemplateRPCs, groupType: .any)
+ }
+
+ /// Checks if the `DialNumber` RPC is allowed
+ ///
+ /// - Parameter manager: The SDL Manager
+ /// - Returns: True if allowed, false if not
+ class func isDialNumberRPCAllowed(with manager: SDLManager) -> Bool {
+ SDLLog.d("Checking if app has permission to dial a number")
+ return checkCurrentPermission(with: manager, rpcName: "DialNumber")
+ }
+}
+
+// MARK: - Check Permissions
+
+private extension RPCPermissionsManager {
+ /// Checks if the `Show` RPC is allowed right at this moment
+ ///
+ /// - Parameter manager: The SDL Manager
+ /// - Returns: true if allowed, false if not
+ class func checkCurrentPermission(with manager: SDLManager, rpcName: String) -> Bool {
+ let isRPCAllowed = manager.permissionManager.isRPCAllowed(rpcName)
+ logRPCPermission(rpcName: rpcName, isRPCAllowed: isRPCAllowed)
+ return isRPCAllowed
+ }
+
+ /// Checks if all the RPCs need to create menus are allowed right at this moment
+ ///
+ /// - Parameter manager: The SDL Manager
+ /// - Returns: The rpc names, the group permission status and the permission status for each rpc in the group
+ class func checkCurrentGroupPermissions(with manager: SDLManager, rpcNames: [String]) -> SDLPermissionGroupStatus {
+ let groupPermissionStatus = manager.permissionManager.groupStatus(ofRPCs: rpcNames)
+ let individualPermissionStatuses = manager.permissionManager.status(ofRPCs: rpcNames)
+ logRPCGroupPermissions(rpcNames: rpcNames, groupPermissionStatus: groupPermissionStatus, individualPermissionStatuses: individualPermissionStatuses)
+ return groupPermissionStatus
+ }
+
+ /// Sets up an observer for permissions changes to media template releated RPCs.
+ ///
+ /// - Parameters:
+ /// - manager: The SDL Manager
+ /// - groupType: The type of changes to get notified about
+ /// - Returns: A unique id assigned to observer. Use the id to unsubscribe to notifications
+ class func subscribeGroupPermissions(with manager: SDLManager, rpcNames: [String], groupType: SDLPermissionGroupType) -> UUID {
+ let permissionAllAllowedObserverId = manager.permissionManager.addObserver(forRPCs: rpcNames, groupType: groupType, withHandler: { (individualStatuses, groupStatus) in
+ self.logRPCGroupPermissions(rpcNames: rpcNames, groupPermissionStatus: groupStatus, individualPermissionStatuses: individualStatuses)
+ })
+
+ return permissionAllAllowedObserverId
+ }
+
+ /// Unsubscribe to notifications about permissions changes for a group of RPCs
+ ///
+ /// - Parameters:
+ /// - manager: The SDL Manager
+ /// - observerId: The unique identifier for a group of RPCs
+ class func unsubscribeGroupPermissions(with manager: SDLManager, observerId: UUID) {
+ manager.permissionManager.removeObserver(forIdentifier: observerId)
+ }
+}
+
+// MARK: - Debug Logging
+
+private extension RPCPermissionsManager {
+ /// Logs permissions for a single RPC
+ ///
+ /// - Parameters:
+ /// - rpcName: The name of the RPC
+ /// - isRPCAllowed: The permission status for the RPC
+ class func logRPCPermission(rpcName: String, isRPCAllowed: Bool) {
+ SDLLog.d("\(rpcName) RPC can be sent to SDL Core? \(isRPCAllowed ? "yes" : "no")")
+ }
+
+ /// Logs permissions for a group of RPCs
+ ///
+ /// - Parameters:
+ /// - rpcNames: The names of the RPCs
+ /// - groupPermissionStatus: The permission status for all RPCs in the group
+ /// - individualPermissionStatuses: The permission status for each of the RPCs in the group
+ class func logRPCGroupPermissions(rpcNames: [String], groupPermissionStatus: SDLPermissionGroupStatus, individualPermissionStatuses: [String:NSNumber]) {
+ SDLLog.d("The group status for \(rpcNames) has changed to: \(groupPermissionStatus)")
+ for (rpcName, rpcAllowed) in individualPermissionStatuses {
+ logRPCPermission(rpcName: rpcName as String, isRPCAllowed: rpcAllowed.boolValue)
+ }
+ }
+}
diff --git a/SmartDeviceLink_Example/Info.plist b/SmartDeviceLink_Example/SmartDeviceLink-Example-ObjC-Info.plist
index 87be1458a..95a3acdac 100644
--- a/SmartDeviceLink_Example/Info.plist
+++ b/SmartDeviceLink_Example/SmartDeviceLink-Example-ObjC-Info.plist
@@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>LSApplicationCategoryType</key>
+ <string></string>
+ <key>NSSpeechRecognitionUsageDescription</key>
+ <string>Requesting access to the speech recognition API</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
diff --git a/SmartDeviceLink_Example/SmartDeviceLink-Example-Swift-Bridging-Header.h b/SmartDeviceLink_Example/SmartDeviceLink-Example-Swift-Bridging-Header.h
new file mode 100644
index 000000000..70ca78854
--- /dev/null
+++ b/SmartDeviceLink_Example/SmartDeviceLink-Example-Swift-Bridging-Header.h
@@ -0,0 +1,5 @@
+//
+// Use this file to import your target's public headers that you would like to expose to Swift.
+//
+
+#import "AppConstants.h"
diff --git a/SmartDeviceLink_Example/VehicleDataManager.h b/SmartDeviceLink_Example/VehicleDataManager.h
new file mode 100644
index 000000000..65f6dd09d
--- /dev/null
+++ b/SmartDeviceLink_Example/VehicleDataManager.h
@@ -0,0 +1,33 @@
+//
+// VehicleDataManager.h
+// SmartDeviceLink-Example-ObjC
+//
+// Created by Nicole on 4/23/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@class SDLManager;
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef void(^RefreshUIHandler)(void);
+
+@interface VehicleDataManager : NSObject
+
+@property (copy, nonatomic, readonly) NSString *vehicleOdometerData;
+
+- (instancetype)init NS_UNAVAILABLE;
+- (instancetype)initWithManager:(SDLManager *)manager refreshUIHandler:(RefreshUIHandler)refreshUIHandler;
+
+- (void)subscribeToVehicleOdometer;
+- (void)unsubscribeToVehicleOdometer;
+
++ (void)getVehicleSpeedWithManager:(SDLManager *)manager;
++ (void)checkPhoneCallCapabilityWithManager:(SDLManager *)manager phoneNumber:(NSString *)phoneNumber;
+
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/VehicleDataManager.m b/SmartDeviceLink_Example/VehicleDataManager.m
new file mode 100644
index 000000000..5615dfe52
--- /dev/null
+++ b/SmartDeviceLink_Example/VehicleDataManager.m
@@ -0,0 +1,216 @@
+//
+// VehicleDataManager.m
+// SmartDeviceLink-Example-ObjC
+//
+// Created by Nicole on 4/23/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import "AlertManager.h"
+#import "VehicleDataManager.h"
+#import "AppConstants.h"
+#import "SmartDeviceLink.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+@interface VehicleDataManager ()
+
+@property (strong, nonatomic) SDLManager *sdlManager;
+@property (copy, nonatomic, readwrite) NSString *vehicleOdometerData;
+@property (copy, nonatomic, nullable) RefreshUIHandler refreshUIHandler;
+
+@end
+
+@implementation VehicleDataManager
+
+#pragma mark - Lifecycle
+
+- (instancetype)initWithManager:(SDLManager *)manager refreshUIHandler:(RefreshUIHandler)refreshUIHandler {
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+
+ _sdlManager = manager;
+ _refreshUIHandler = refreshUIHandler;
+ _vehicleOdometerData = @"";
+
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(vehicleDataNotification:) name:SDLDidReceiveVehicleDataNotification object:nil];
+ [self sdlex_resetOdometer];
+
+ return self;
+}
+
+
+#pragma mark - Subscribe Vehicle Data
+
+/**
+ * Subscribes to odometer data. You must subscribe to a notification with name `SDLDidReceiveVehicleData` to get the new data when the odometer data changes.
+ */
+- (void)subscribeToVehicleOdometer {
+ SDLLogD(@"Subscribing to odometer vehicle data");
+ SDLSubscribeVehicleData *subscribeToVehicleOdometer = [[SDLSubscribeVehicleData alloc] init];
+ subscribeToVehicleOdometer.odometer = @YES;
+ [self.sdlManager sendRequest:subscribeToVehicleOdometer withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
+ if (error || ![response isKindOfClass:SDLSubscribeVehicleDataResponse.class]) {
+ SDLLogE(@"Error sending Get Vehicle Data RPC: %@", error);
+ }
+
+ SDLGetVehicleDataResponse* getVehicleDataResponse = (SDLGetVehicleDataResponse *)response;
+ SDLResult resultCode = getVehicleDataResponse.resultCode;
+
+ NSMutableString *message = [NSMutableString stringWithFormat:@"%@: ", VehicleDataOdometerName];
+ if ([resultCode isEqualToEnum:SDLResultSuccess]) {
+ SDLLogD(@"Subscribed to vehicle odometer data");
+ [message appendString:@"Subscribed"];
+ } else if ([resultCode isEqualToEnum:SDLResultDisallowed]) {
+ SDLLogD(@"Access to vehicle data disallowed");
+ [message appendString:@"Disallowed"];
+ } else if ([resultCode isEqualToEnum:SDLResultUserDisallowed]) {
+ SDLLogD(@"Vehicle user disabled access to vehicle data");
+ [message appendString:@"Disabled"];
+ } else if ([resultCode isEqualToEnum:SDLResultIgnored]) {
+ SDLLogD(@"Already subscribed to odometer data");
+ [message appendString:@"Subscribed"];
+ } else if ([resultCode isEqualToEnum:SDLResultDataNotAvailable]) {
+ SDLLogD(@"You have permission to access to vehicle data, but the vehicle you are connected to did not provide any data");
+ [message appendString:@"Unknown"];
+ } else {
+ SDLLogE(@"Unknown reason for failure to get vehicle data: %@", error != nil ? error.localizedDescription : @"no error message");
+ [message appendString:@"Unsubscribed"];
+ }
+
+ self.vehicleOdometerData = message;
+
+ if (!self.refreshUIHandler) { return; }
+ self.refreshUIHandler();
+ }];
+}
+
+/**
+ * Unsubscribes to vehicle odometer data.
+ */
+- (void)unsubscribeToVehicleOdometer {
+ SDLUnsubscribeVehicleData *unsubscribeToVehicleOdometer = [[SDLUnsubscribeVehicleData alloc] init];
+ unsubscribeToVehicleOdometer.odometer = @YES;
+ [self.sdlManager sendRequest:unsubscribeToVehicleOdometer withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
+ if (!response.success.boolValue) { return; }
+ [self sdlex_resetOdometer];
+ }];
+}
+
+/**
+ * Notification containing the updated vehicle data.
+ *
+ * @param notification A SDLOnVehicleData notification
+ */
+- (void)vehicleDataNotification:(SDLRPCNotificationNotification *)notification {
+ if (![notification.notification isKindOfClass:SDLOnVehicleData.class]) {
+ return;
+ }
+
+ SDLOnVehicleData *onVehicleData = (SDLOnVehicleData *)notification.notification;
+ self.vehicleOdometerData = [NSString stringWithFormat:@"%@: %@ kph", VehicleDataOdometerName, onVehicleData.odometer];
+
+ if (!self.refreshUIHandler) { return; }
+ self.refreshUIHandler();
+}
+
+/**
+ * Resets the odometer data
+ */
+- (void)sdlex_resetOdometer {
+ self.vehicleOdometerData = [NSString stringWithFormat:@"%@: Unsubscribed", VehicleDataOdometerName];
+}
+
+#pragma mark - Get Vehicle Data
+
+/**
+ * Retreives the current vehicle speed
+ *
+ * @param manager The SDL manager
+ */
++ (void)getVehicleSpeedWithManager:(SDLManager *)manager {
+ SDLLogD(@"Checking if app has permission to access vehicle data...");
+ if (![manager.permissionManager isRPCAllowed:@"GetVehicleData"]) {
+ [manager sendRequest:[AlertManager alertWithMessageAndCloseButton:@"This app does not have the required permissions to access vehicle data" textField2:nil]];
+ return;
+ }
+
+ SDLLogD(@"App has permission to access vehicle data. Requesting vehicle speed data...");
+ SDLGetVehicleData *getVehicleSpeed = [[SDLGetVehicleData alloc] init];
+ getVehicleSpeed.speed = @YES;
+ [manager sendRequest:getVehicleSpeed withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
+ if (error || ![response isKindOfClass:SDLGetVehicleDataResponse.class]) {
+ [manager sendRequest:[AlertManager alertWithMessageAndCloseButton:@"Something went wrong while getting vehicle speed" textField2:nil]];
+ return;
+ }
+
+ SDLGetVehicleDataResponse* getVehicleDataResponse = (SDLGetVehicleDataResponse *)response;
+ SDLResult resultCode = getVehicleDataResponse.resultCode;
+
+ NSMutableString *alertMessage = [NSMutableString stringWithFormat:@"%@: ", VehicleDataSpeedName];
+ if ([resultCode isEqualToEnum:SDLResultRejected]) {
+ SDLLogD(@"The request for vehicle speed was rejected");
+ [alertMessage appendString:@"Rejected"];
+ } else if ([resultCode isEqualToEnum:SDLResultDisallowed]) {
+ SDLLogD(@"This app does not have the required permissions to access vehicle data.");
+ [alertMessage appendString:@"Disallowed"];
+ } else if ([resultCode isEqualToEnum:SDLResultSuccess]) {
+ NSNumber *speed = getVehicleDataResponse.speed;
+ if (speed) {
+ SDLLogD(@"Request for vehicle speed successful: %f", speed.floatValue);
+ [alertMessage appendString:[NSString stringWithFormat:@"%f kph", speed.floatValue]];
+ } else {
+ SDLLogD(@"Request for vehicle speed successful but no data returned.");
+ [alertMessage appendString:@"Unknown"];
+ }
+ }
+
+ [manager sendRequest:[AlertManager alertWithMessageAndCloseButton:alertMessage textField2:nil]];
+ }];
+}
+
+#pragma mark - Phone Calls
+
+/**
+ * Checks if the head unit has the ability and/or permissions to make a phone call. If it does, the phone number is dialed.
+ *
+ * @param manager The SDL manager
+ * @param phoneNumber A phone number to dial
+ */
++ (void)checkPhoneCallCapabilityWithManager:(SDLManager *)manager phoneNumber:(NSString *)phoneNumber {
+ SDLLogD(@"Checking phone call capability");
+ [manager.systemCapabilityManager updateCapabilityType:SDLSystemCapabilityTypePhoneCall completionHandler:^(NSError * _Nullable error, SDLSystemCapabilityManager * _Nonnull systemCapabilityManager) {
+ if (!systemCapabilityManager.phoneCapability) {
+ [manager sendRequest:[AlertManager alertWithMessageAndCloseButton:@"The head unit does not support the phone call capability" textField2:nil]];
+ return;
+ }
+
+ if (systemCapabilityManager.phoneCapability.dialNumberEnabled.boolValue) {
+ SDLLogD(@"Dialing phone number %@", phoneNumber);
+ [self sdlex_dialPhoneNumber:phoneNumber manager:manager];
+ } else {
+ [manager sendRequest:[AlertManager alertWithMessageAndCloseButton:@"The dial number feature is unavailable for this head unit" textField2:nil]];
+ }
+ }];
+}
+
+/**
+ * Dials a phone number.
+ *
+ * @param phoneNumber A phone number to dial
+ * @param manager The SDL manager
+ */
++ (void)sdlex_dialPhoneNumber:(NSString *)phoneNumber manager:(SDLManager *)manager {
+ SDLDialNumber *dialNumber = [[SDLDialNumber alloc] initWithNumber:phoneNumber];
+ [manager sendRequest:dialNumber withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
+ if (!response.resultCode) { return; }
+ SDLLogD(@"Sent dial number request: %@", response.resultCode == SDLResultSuccess ? @"successfully" : @"unsuccessfully");
+ }];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink_Example/VehicleDataManager.swift b/SmartDeviceLink_Example/VehicleDataManager.swift
new file mode 100644
index 000000000..1d8c5a52a
--- /dev/null
+++ b/SmartDeviceLink_Example/VehicleDataManager.swift
@@ -0,0 +1,184 @@
+//
+// VehicleDataManager.swift
+// SmartDeviceLink
+//
+// Created by Nicole on 4/13/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+import Foundation
+import SmartDeviceLink
+import SmartDeviceLinkSwift
+
+class VehicleDataManager: NSObject {
+ fileprivate let sdlManager: SDLManager!
+ fileprivate var refreshUIHandler: RefreshUIHandler?
+ public fileprivate(set) var vehicleOdometerData: String
+
+ init(sdlManager: SDLManager, refreshUIHandler: RefreshUIHandler? = nil) {
+ self.sdlManager = sdlManager
+ self.refreshUIHandler = refreshUIHandler
+ self.vehicleOdometerData = ""
+ super.init()
+
+ resetOdometer()
+ NotificationCenter.default.addObserver(self, selector: #selector(vehicleDataNotification(_:)), name: .SDLDidReceiveVehicleData, object: nil)
+ }
+}
+
+// MARK: - Subscribe Vehicle Data
+
+extension VehicleDataManager {
+ /// Subscribes to odometer data. You must subscribe to a notification with name `SDLDidReceiveVehicleData` to get the new data when the odometer data changes.
+ func subscribeToVehicleOdometer() {
+ let subscribeToVehicleOdometer = SDLSubscribeVehicleData()
+ subscribeToVehicleOdometer.odometer = true
+ sdlManager.send(request: subscribeToVehicleOdometer) { [unowned self] (request, response, error) in
+ guard let result = response?.resultCode else { return }
+
+ if error != nil {
+ SDLLog.e("Error sending Get Vehicle Data RPC: \(error!.localizedDescription)")
+ }
+
+ var message = "\(VehicleDataOdometerName): "
+ switch result {
+ case .success:
+ SDLLog.d("Subscribed to vehicle odometer data")
+ message += "Subscribed"
+ case .disallowed:
+ SDLLog.d("Access to vehicle data disallowed")
+ message += "Disallowed"
+ case .userDisallowed:
+ SDLLog.d("Vehicle user disabled access to vehicle data")
+ message += "Disabled"
+ case .ignored:
+ SDLLog.d("Already subscribed to odometer data")
+ message += "Subscribed"
+ case .dataNotAvailable:
+ SDLLog.d("You have permission to access to vehicle data, but the vehicle you are connected to did not provide any data")
+ message += "Unknown"
+ default:
+ SDLLog.e("Unknown reason for failure to get vehicle data: \(error != nil ? error!.localizedDescription : "no error message")")
+ message += "Unsubscribed"
+ return
+ }
+ self.vehicleOdometerData = message
+
+ guard let handler = self.refreshUIHandler else { return }
+ handler()
+ }
+ }
+
+ /// Unsubscribes to vehicle odometer data.
+ func unsubscribeToVehicleOdometer() {
+ let unsubscribeToVehicleOdometer = SDLUnsubscribeVehicleData()
+ unsubscribeToVehicleOdometer.odometer = true
+ sdlManager.send(request: unsubscribeToVehicleOdometer) { (request, response, error) in
+ guard let response = response, response.resultCode == .success else { return }
+ self.resetOdometer()
+ }
+ }
+
+ /// Notification containing the updated vehicle data.
+ ///
+ /// - Parameter notification: A SDLOnVehicleData notification
+ func vehicleDataNotification(_ notification: SDLRPCNotificationNotification) {
+ guard let handler = refreshUIHandler, let onVehicleData = notification.notification as? SDLOnVehicleData, let odometer = onVehicleData.odometer else {
+ return
+ }
+
+ vehicleOdometerData = "\(VehicleDataOdometerName): \(odometer) km"
+ handler()
+ }
+
+ /// Resets the odometer data
+ fileprivate func resetOdometer() {
+ vehicleOdometerData = "\(VehicleDataOdometerName): Unsubscribed"
+ }
+}
+
+// MARK: - Get Vehicle Data
+
+extension VehicleDataManager {
+ /// Retreives the current vehicle speed
+ ///
+ /// - Parameter manager: The SDL manager
+ class func getVehicleSpeed(with manager: SDLManager) {
+ SDLLog.d("Checking if app has permission to access vehicle data...")
+ guard manager.permissionManager.isRPCAllowed("GetVehicleData") else {
+ let alert = AlertManager.alertWithMessageAndCloseButton("This app does not have the required permissions to access vehicle data")
+ manager.send(request: alert)
+ return
+ }
+
+ SDLLog.d("App has permission to access vehicle data. Requesting vehicle speed data...")
+ let getVehicleSpeed = SDLGetVehicleData()
+ getVehicleSpeed.speed = true
+ manager.send(request: getVehicleSpeed) { (request, response, error) in
+ guard let response = response, error == nil else {
+ let alert = AlertManager.alertWithMessageAndCloseButton("Something went wrong while getting vehicle speed")
+ manager.send(request: alert)
+ return
+ }
+
+ var alertMessage = "\(VehicleDataSpeedName): "
+ switch response.resultCode {
+ case .rejected:
+ SDLLog.d("The request for vehicle speed was rejected")
+ alertMessage += "Rejected"
+ case .disallowed:
+ SDLLog.d("This app does not have the required permissions to access vehicle data")
+ alertMessage += "Disallowed"
+ case .success:
+ if let vehicleData = response as? SDLGetVehicleDataResponse, let speed = vehicleData.speed {
+ SDLLog.d("Request for vehicle speed successful: \(speed)")
+ alertMessage += "\(speed) kph"
+ } else {
+ SDLLog.e("Request for vehicle speed successful but no data returned")
+ alertMessage += "Unknown"
+ }
+ default: break
+ }
+
+ let alert = AlertManager.alertWithMessageAndCloseButton(alertMessage)
+ manager.send(request: alert)
+ }
+ }
+}
+
+// MARK: - Phone Calls
+
+extension VehicleDataManager {
+ /// Checks if the head unit has the ability and/or permissions to make a phone call. If it does, the phone number is dialed.
+ ///
+ /// - Parameter manager: The SDL manager
+ /// - phoneNumber: A phone number to dial
+ class func checkPhoneCallCapability(manager: SDLManager, phoneNumber: String) {
+ SDLLog.d("Checking phone call capability")
+ manager.systemCapabilityManager.updateCapabilityType(.phoneCall, completionHandler: { (error, systemCapabilityManager) in
+ guard let phoneCapability = systemCapabilityManager.phoneCapability else {
+ manager.send(AlertManager.alertWithMessageAndCloseButton("The head unit does not support the phone call capability"))
+ return
+ }
+ if phoneCapability.dialNumberEnabled?.boolValue ?? false {
+ SDLLog.d("Dialing phone number \(phoneNumber)...")
+ dialPhoneNumber(phoneNumber, manager: manager)
+ } else {
+ manager.send(AlertManager.alertWithMessageAndCloseButton("A phone call can not be made"))
+ }
+ })
+ }
+
+ /// Dials a phone number.
+ ///
+ /// - Parameters:
+ /// - phoneNumber: A phone number to dial
+ /// - manager: The SDL manager
+ private class func dialPhoneNumber(_ phoneNumber: String, manager: SDLManager) {
+ let dialNumber = SDLDialNumber(number: phoneNumber)
+ manager.send(request: dialNumber) { (requst, response, error) in
+ guard let success = response?.resultCode else { return }
+ SDLLog.d("Sent dial number request: \(success == .success ? "successfully" : "unsuccessfully").")
+ }
+ }
+}