From af7c5ce2233eb14a5ba57cc581948ffa9658ecc2 Mon Sep 17 00:00:00 2001 From: Dave Arter Date: Fri, 17 Jul 2015 15:51:54 +0100 Subject: Upgrade iOS version of the app to latest Cordova; remove old phonegap 2 bits --- config.xml | 15 + iPhone/CordovaLib/Classes/CDV.h | 57 - iPhone/CordovaLib/Classes/CDVAccelerometer.h | 39 - iPhone/CordovaLib/Classes/CDVAccelerometer.m | 128 - iPhone/CordovaLib/Classes/CDVAvailability.h | 90 - iPhone/CordovaLib/Classes/CDVBattery.h | 40 - iPhone/CordovaLib/Classes/CDVBattery.m | 152 - iPhone/CordovaLib/Classes/CDVCamera.h | 102 - iPhone/CordovaLib/Classes/CDVCamera.m | 730 --- iPhone/CordovaLib/Classes/CDVCapture.h | 118 - iPhone/CordovaLib/Classes/CDVCapture.m | 845 --- iPhone/CordovaLib/Classes/CDVCommandDelegate.h | 54 - iPhone/CordovaLib/Classes/CDVCommandDelegateImpl.h | 33 - iPhone/CordovaLib/Classes/CDVCommandDelegateImpl.m | 145 - iPhone/CordovaLib/Classes/CDVCommandQueue.h | 40 - iPhone/CordovaLib/Classes/CDVCommandQueue.m | 169 - iPhone/CordovaLib/Classes/CDVConfigParser.h | 31 - iPhone/CordovaLib/Classes/CDVConfigParser.m | 96 - iPhone/CordovaLib/Classes/CDVConnection.h | 34 - iPhone/CordovaLib/Classes/CDVConnection.m | 132 - iPhone/CordovaLib/Classes/CDVContact.h | 136 - iPhone/CordovaLib/Classes/CDVContact.m | 1752 ------ iPhone/CordovaLib/Classes/CDVContacts.h | 151 - iPhone/CordovaLib/Classes/CDVContacts.m | 593 -- iPhone/CordovaLib/Classes/CDVDebug.h | 25 - iPhone/CordovaLib/Classes/CDVDevice.h | 30 - iPhone/CordovaLib/Classes/CDVDevice.m | 89 - iPhone/CordovaLib/Classes/CDVEcho.h | 23 - iPhone/CordovaLib/Classes/CDVEcho.m | 61 - iPhone/CordovaLib/Classes/CDVExif.h | 43 - iPhone/CordovaLib/Classes/CDVFile.h | 107 - iPhone/CordovaLib/Classes/CDVFile.m | 1426 ----- iPhone/CordovaLib/Classes/CDVFileTransfer.h | 82 - iPhone/CordovaLib/Classes/CDVFileTransfer.m | 730 --- iPhone/CordovaLib/Classes/CDVGlobalization.h | 150 - iPhone/CordovaLib/Classes/CDVGlobalization.m | 790 --- iPhone/CordovaLib/Classes/CDVInAppBrowser.h | 89 - iPhone/CordovaLib/Classes/CDVInAppBrowser.m | 818 --- iPhone/CordovaLib/Classes/CDVInvokedUrlCommand.h | 57 - iPhone/CordovaLib/Classes/CDVInvokedUrlCommand.m | 140 - iPhone/CordovaLib/Classes/CDVJSON.h | 30 - iPhone/CordovaLib/Classes/CDVJSON.m | 77 - iPhone/CordovaLib/Classes/CDVJpegHeaderWriter.h | 62 - iPhone/CordovaLib/Classes/CDVJpegHeaderWriter.m | 547 -- iPhone/CordovaLib/Classes/CDVLocalStorage.h | 50 - iPhone/CordovaLib/Classes/CDVLocalStorage.m | 485 -- iPhone/CordovaLib/Classes/CDVLocation.h | 104 - iPhone/CordovaLib/Classes/CDVLocation.m | 623 -- iPhone/CordovaLib/Classes/CDVLogger.h | 26 - iPhone/CordovaLib/Classes/CDVLogger.m | 38 - iPhone/CordovaLib/Classes/CDVNotification.h | 37 - iPhone/CordovaLib/Classes/CDVNotification.m | 130 - iPhone/CordovaLib/Classes/CDVPlugin.h | 64 - iPhone/CordovaLib/Classes/CDVPlugin.m | 152 - iPhone/CordovaLib/Classes/CDVPluginResult.h | 68 - iPhone/CordovaLib/Classes/CDVPluginResult.m | 224 - iPhone/CordovaLib/Classes/CDVReachability.h | 85 - iPhone/CordovaLib/Classes/CDVReachability.m | 260 - .../Classes/CDVScreenOrientationDelegate.h | 28 - iPhone/CordovaLib/Classes/CDVSound.h | 116 - iPhone/CordovaLib/Classes/CDVSound.m | 702 --- iPhone/CordovaLib/Classes/CDVSplashScreen.h | 33 - iPhone/CordovaLib/Classes/CDVSplashScreen.m | 233 - iPhone/CordovaLib/Classes/CDVTimer.h | 27 - iPhone/CordovaLib/Classes/CDVTimer.m | 123 - iPhone/CordovaLib/Classes/CDVURLProtocol.h | 29 - iPhone/CordovaLib/Classes/CDVURLProtocol.m | 230 - iPhone/CordovaLib/Classes/CDVUserAgentUtil.h | 27 - iPhone/CordovaLib/Classes/CDVUserAgentUtil.m | 120 - iPhone/CordovaLib/Classes/CDVViewController.h | 73 - iPhone/CordovaLib/Classes/CDVViewController.m | 933 --- iPhone/CordovaLib/Classes/CDVWebViewDelegate.h | 39 - iPhone/CordovaLib/Classes/CDVWebViewDelegate.m | 380 -- iPhone/CordovaLib/Classes/CDVWhitelist.h | 34 - iPhone/CordovaLib/Classes/CDVWhitelist.m | 238 - iPhone/CordovaLib/Classes/NSArray+Comparisons.h | 26 - iPhone/CordovaLib/Classes/NSArray+Comparisons.m | 41 - iPhone/CordovaLib/Classes/NSData+Base64.h | 33 - iPhone/CordovaLib/Classes/NSData+Base64.m | 281 - .../CordovaLib/Classes/NSDictionary+Extensions.h | 35 - .../CordovaLib/Classes/NSDictionary+Extensions.m | 159 - .../Classes/NSMutableArray+QueueAdditions.h | 29 - .../Classes/NSMutableArray+QueueAdditions.m | 58 - iPhone/CordovaLib/Classes/UIDevice+Extensions.h | 31 - iPhone/CordovaLib/Classes/UIDevice+Extensions.m | 47 - .../CordovaLib.xcodeproj/project.pbxproj | 682 -- iPhone/CordovaLib/CordovaLib_Prefix.pch | 22 - iPhone/CordovaLib/VERSION | 1 - iPhone/CordovaLib/cordova.js | 6521 -------------------- iPhone/Default-568h@2x.png | Bin 12832 -> 0 bytes iPhone/Default.png | Bin 6002 -> 0 bytes iPhone/Default@2x.png | Bin 12206 -> 0 bytes iPhone/FixMyStreet.xcodeproj/project.pbxproj | 694 --- .../project.xcworkspace/contents.xcworkspacedata | 7 - .../xcshareddata/FixMyStreet.xccheckout | 41 - iPhone/FixMyStreet/Classes/AppDelegate.h | 42 - iPhone/FixMyStreet/Classes/AppDelegate.m | 133 - iPhone/FixMyStreet/Classes/MainViewController.h | 40 - iPhone/FixMyStreet/Classes/MainViewController.m | 174 - iPhone/FixMyStreet/Classes/MainViewController.xib | 138 - iPhone/FixMyStreet/FixMyStreet-Info.plist | 64 - iPhone/FixMyStreet/FixMyStreet-Prefix.pch | 7 - iPhone/FixMyStreet/Icon.png | Bin 1580 -> 0 bytes iPhone/FixMyStreet/Icon@2x.png | Bin 3690 -> 0 bytes iPhone/FixMyStreet/Plugins/README | 1 - .../Resources/Capture.bundle/controls_bg.png | Bin 955 -> 0 bytes .../Resources/Capture.bundle/controls_bg@2x.png | Bin 971 -> 0 bytes .../Resources/Capture.bundle/controls_bg~ipad.png | Bin 969 -> 0 bytes .../Resources/Capture.bundle/microphone.png | Bin 72226 -> 0 bytes .../Resources/Capture.bundle/microphone@2x.png | Bin 282409 -> 0 bytes .../Resources/Capture.bundle/microphone~ipad.png | Bin 393975 -> 0 bytes .../Resources/Capture.bundle/record_button.png | Bin 5852 -> 0 bytes .../Resources/Capture.bundle/record_button@2x.png | Bin 13875 -> 0 bytes .../Capture.bundle/record_button~ipad.png | Bin 7547 -> 0 bytes .../Resources/Capture.bundle/recording_bg.png | Bin 973 -> 0 bytes .../Resources/Capture.bundle/recording_bg@2x.png | Bin 990 -> 0 bytes .../Resources/Capture.bundle/recording_bg~ipad.png | Bin 996 -> 0 bytes .../Resources/Capture.bundle/stop_button.png | Bin 5514 -> 0 bytes .../Resources/Capture.bundle/stop_button@2x.png | Bin 12965 -> 0 bytes .../Resources/Capture.bundle/stop_button~ipad.png | Bin 7119 -> 0 bytes .../Resources/de.lproj/Localizable.strings | 26 - .../Resources/en.lproj/Localizable.strings | 25 - .../Resources/es.lproj/Localizable.strings | 25 - .../FixMyStreet/Resources/icons/fms-Icon-120.png | Bin 5539 -> 0 bytes iPhone/FixMyStreet/Resources/icons/fms-Icon-80.png | Bin 5420 -> 0 bytes .../Resources/icons/fms-Icon-Small-29.png | Bin 1003 -> 0 bytes .../Resources/icons/fms-Icon-Small-29@2x.png | Bin 2081 -> 0 bytes iPhone/FixMyStreet/Resources/icons/fms-Icon.png | Bin 2002 -> 0 bytes iPhone/FixMyStreet/Resources/icons/fms-Icon@2x.png | Bin 4832 -> 0 bytes .../Resources/se.lproj/Localizable.strings | 26 - iPhone/FixMyStreet/Resources/splash/Default.png | Bin 6002 -> 0 bytes iPhone/FixMyStreet/Resources/splash/Default@2x.png | Bin 12206 -> 0 bytes iPhone/FixMyStreet/config.xml | 120 - iPhone/FixMyStreet/en.lproj/InfoPlist.strings | 2 - iPhone/FixMyStreet/main.m | 35 - iPhone/Icon-120.png | Bin 5584 -> 0 bytes iPhone/Icon.png | Bin 1580 -> 0 bytes iPhone/Icon@2x.png | Bin 3690 -> 0 bytes iPhone/cordova/build | 51 - iPhone/cordova/emulate | 55 - iPhone/cordova/log | 23 - iPhone/cordova/release | 51 - iPhone/cordova/run | 58 - iPhone/fms-Icon-120.png | Bin 5539 -> 0 bytes iPhone/fms-Icon-80.png | Bin 5420 -> 0 bytes iPhone/fms-Icon-Small-29.png | Bin 1003 -> 0 bytes iPhone/fms-Icon-Small-29@2x.png | Bin 2081 -> 0 bytes iPhone/www/cordova.js | 6521 -------------------- res/ios/Default-568h@2x.png | Bin 0 -> 12832 bytes res/ios/Default.png | Bin 0 -> 6002 bytes res/ios/Default@2x.png | Bin 0 -> 12206 bytes res/ios/Icon-120.png | Bin 0 -> 5584 bytes res/ios/Icon.png | Bin 0 -> 1580 bytes res/ios/Icon@2x.png | Bin 0 -> 3690 bytes 154 files changed, 15 insertions(+), 33079 deletions(-) delete mode 100755 iPhone/CordovaLib/Classes/CDV.h delete mode 100755 iPhone/CordovaLib/Classes/CDVAccelerometer.h delete mode 100755 iPhone/CordovaLib/Classes/CDVAccelerometer.m delete mode 100755 iPhone/CordovaLib/Classes/CDVAvailability.h delete mode 100755 iPhone/CordovaLib/Classes/CDVBattery.h delete mode 100755 iPhone/CordovaLib/Classes/CDVBattery.m delete mode 100755 iPhone/CordovaLib/Classes/CDVCamera.h delete mode 100755 iPhone/CordovaLib/Classes/CDVCamera.m delete mode 100755 iPhone/CordovaLib/Classes/CDVCapture.h delete mode 100755 iPhone/CordovaLib/Classes/CDVCapture.m delete mode 100755 iPhone/CordovaLib/Classes/CDVCommandDelegate.h delete mode 100755 iPhone/CordovaLib/Classes/CDVCommandDelegateImpl.h delete mode 100755 iPhone/CordovaLib/Classes/CDVCommandDelegateImpl.m delete mode 100755 iPhone/CordovaLib/Classes/CDVCommandQueue.h delete mode 100755 iPhone/CordovaLib/Classes/CDVCommandQueue.m delete mode 100755 iPhone/CordovaLib/Classes/CDVConfigParser.h delete mode 100755 iPhone/CordovaLib/Classes/CDVConfigParser.m delete mode 100755 iPhone/CordovaLib/Classes/CDVConnection.h delete mode 100755 iPhone/CordovaLib/Classes/CDVConnection.m delete mode 100755 iPhone/CordovaLib/Classes/CDVContact.h delete mode 100755 iPhone/CordovaLib/Classes/CDVContact.m delete mode 100755 iPhone/CordovaLib/Classes/CDVContacts.h delete mode 100755 iPhone/CordovaLib/Classes/CDVContacts.m delete mode 100755 iPhone/CordovaLib/Classes/CDVDebug.h delete mode 100755 iPhone/CordovaLib/Classes/CDVDevice.h delete mode 100755 iPhone/CordovaLib/Classes/CDVDevice.m delete mode 100755 iPhone/CordovaLib/Classes/CDVEcho.h delete mode 100755 iPhone/CordovaLib/Classes/CDVEcho.m delete mode 100755 iPhone/CordovaLib/Classes/CDVExif.h delete mode 100755 iPhone/CordovaLib/Classes/CDVFile.h delete mode 100755 iPhone/CordovaLib/Classes/CDVFile.m delete mode 100755 iPhone/CordovaLib/Classes/CDVFileTransfer.h delete mode 100755 iPhone/CordovaLib/Classes/CDVFileTransfer.m delete mode 100755 iPhone/CordovaLib/Classes/CDVGlobalization.h delete mode 100755 iPhone/CordovaLib/Classes/CDVGlobalization.m delete mode 100755 iPhone/CordovaLib/Classes/CDVInAppBrowser.h delete mode 100755 iPhone/CordovaLib/Classes/CDVInAppBrowser.m delete mode 100755 iPhone/CordovaLib/Classes/CDVInvokedUrlCommand.h delete mode 100755 iPhone/CordovaLib/Classes/CDVInvokedUrlCommand.m delete mode 100755 iPhone/CordovaLib/Classes/CDVJSON.h delete mode 100755 iPhone/CordovaLib/Classes/CDVJSON.m delete mode 100755 iPhone/CordovaLib/Classes/CDVJpegHeaderWriter.h delete mode 100755 iPhone/CordovaLib/Classes/CDVJpegHeaderWriter.m delete mode 100755 iPhone/CordovaLib/Classes/CDVLocalStorage.h delete mode 100755 iPhone/CordovaLib/Classes/CDVLocalStorage.m delete mode 100755 iPhone/CordovaLib/Classes/CDVLocation.h delete mode 100755 iPhone/CordovaLib/Classes/CDVLocation.m delete mode 100755 iPhone/CordovaLib/Classes/CDVLogger.h delete mode 100755 iPhone/CordovaLib/Classes/CDVLogger.m delete mode 100755 iPhone/CordovaLib/Classes/CDVNotification.h delete mode 100755 iPhone/CordovaLib/Classes/CDVNotification.m delete mode 100755 iPhone/CordovaLib/Classes/CDVPlugin.h delete mode 100755 iPhone/CordovaLib/Classes/CDVPlugin.m delete mode 100755 iPhone/CordovaLib/Classes/CDVPluginResult.h delete mode 100755 iPhone/CordovaLib/Classes/CDVPluginResult.m delete mode 100755 iPhone/CordovaLib/Classes/CDVReachability.h delete mode 100755 iPhone/CordovaLib/Classes/CDVReachability.m delete mode 100755 iPhone/CordovaLib/Classes/CDVScreenOrientationDelegate.h delete mode 100755 iPhone/CordovaLib/Classes/CDVSound.h delete mode 100755 iPhone/CordovaLib/Classes/CDVSound.m delete mode 100755 iPhone/CordovaLib/Classes/CDVSplashScreen.h delete mode 100755 iPhone/CordovaLib/Classes/CDVSplashScreen.m delete mode 100755 iPhone/CordovaLib/Classes/CDVTimer.h delete mode 100755 iPhone/CordovaLib/Classes/CDVTimer.m delete mode 100755 iPhone/CordovaLib/Classes/CDVURLProtocol.h delete mode 100755 iPhone/CordovaLib/Classes/CDVURLProtocol.m delete mode 100755 iPhone/CordovaLib/Classes/CDVUserAgentUtil.h delete mode 100755 iPhone/CordovaLib/Classes/CDVUserAgentUtil.m delete mode 100755 iPhone/CordovaLib/Classes/CDVViewController.h delete mode 100755 iPhone/CordovaLib/Classes/CDVViewController.m delete mode 100755 iPhone/CordovaLib/Classes/CDVWebViewDelegate.h delete mode 100755 iPhone/CordovaLib/Classes/CDVWebViewDelegate.m delete mode 100755 iPhone/CordovaLib/Classes/CDVWhitelist.h delete mode 100755 iPhone/CordovaLib/Classes/CDVWhitelist.m delete mode 100755 iPhone/CordovaLib/Classes/NSArray+Comparisons.h delete mode 100755 iPhone/CordovaLib/Classes/NSArray+Comparisons.m delete mode 100755 iPhone/CordovaLib/Classes/NSData+Base64.h delete mode 100755 iPhone/CordovaLib/Classes/NSData+Base64.m delete mode 100755 iPhone/CordovaLib/Classes/NSDictionary+Extensions.h delete mode 100755 iPhone/CordovaLib/Classes/NSDictionary+Extensions.m delete mode 100755 iPhone/CordovaLib/Classes/NSMutableArray+QueueAdditions.h delete mode 100755 iPhone/CordovaLib/Classes/NSMutableArray+QueueAdditions.m delete mode 100755 iPhone/CordovaLib/Classes/UIDevice+Extensions.h delete mode 100755 iPhone/CordovaLib/Classes/UIDevice+Extensions.m delete mode 100755 iPhone/CordovaLib/CordovaLib.xcodeproj/project.pbxproj delete mode 100755 iPhone/CordovaLib/CordovaLib_Prefix.pch delete mode 100755 iPhone/CordovaLib/VERSION delete mode 100755 iPhone/CordovaLib/cordova.js delete mode 100644 iPhone/Default-568h@2x.png delete mode 100644 iPhone/Default.png delete mode 100644 iPhone/Default@2x.png delete mode 100644 iPhone/FixMyStreet.xcodeproj/project.pbxproj delete mode 100644 iPhone/FixMyStreet.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 iPhone/FixMyStreet.xcodeproj/project.xcworkspace/xcshareddata/FixMyStreet.xccheckout delete mode 100644 iPhone/FixMyStreet/Classes/AppDelegate.h delete mode 100644 iPhone/FixMyStreet/Classes/AppDelegate.m delete mode 100644 iPhone/FixMyStreet/Classes/MainViewController.h delete mode 100644 iPhone/FixMyStreet/Classes/MainViewController.m delete mode 100644 iPhone/FixMyStreet/Classes/MainViewController.xib delete mode 100644 iPhone/FixMyStreet/FixMyStreet-Info.plist delete mode 100644 iPhone/FixMyStreet/FixMyStreet-Prefix.pch delete mode 100644 iPhone/FixMyStreet/Icon.png delete mode 100644 iPhone/FixMyStreet/Icon@2x.png delete mode 100644 iPhone/FixMyStreet/Plugins/README delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/controls_bg.png delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/controls_bg@2x.png delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/controls_bg~ipad.png delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/microphone.png delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/microphone@2x.png delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/microphone~ipad.png delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/record_button.png delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/record_button@2x.png delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/record_button~ipad.png delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/recording_bg.png delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/recording_bg@2x.png delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/recording_bg~ipad.png delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/stop_button.png delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/stop_button@2x.png delete mode 100644 iPhone/FixMyStreet/Resources/Capture.bundle/stop_button~ipad.png delete mode 100644 iPhone/FixMyStreet/Resources/de.lproj/Localizable.strings delete mode 100644 iPhone/FixMyStreet/Resources/en.lproj/Localizable.strings delete mode 100644 iPhone/FixMyStreet/Resources/es.lproj/Localizable.strings delete mode 100644 iPhone/FixMyStreet/Resources/icons/fms-Icon-120.png delete mode 100644 iPhone/FixMyStreet/Resources/icons/fms-Icon-80.png delete mode 100644 iPhone/FixMyStreet/Resources/icons/fms-Icon-Small-29.png delete mode 100644 iPhone/FixMyStreet/Resources/icons/fms-Icon-Small-29@2x.png delete mode 100644 iPhone/FixMyStreet/Resources/icons/fms-Icon.png delete mode 100644 iPhone/FixMyStreet/Resources/icons/fms-Icon@2x.png delete mode 100644 iPhone/FixMyStreet/Resources/se.lproj/Localizable.strings delete mode 100644 iPhone/FixMyStreet/Resources/splash/Default.png delete mode 100644 iPhone/FixMyStreet/Resources/splash/Default@2x.png delete mode 100644 iPhone/FixMyStreet/config.xml delete mode 100644 iPhone/FixMyStreet/en.lproj/InfoPlist.strings delete mode 100644 iPhone/FixMyStreet/main.m delete mode 100644 iPhone/Icon-120.png delete mode 100644 iPhone/Icon.png delete mode 100644 iPhone/Icon@2x.png delete mode 100755 iPhone/cordova/build delete mode 100755 iPhone/cordova/emulate delete mode 100755 iPhone/cordova/log delete mode 100755 iPhone/cordova/release delete mode 100755 iPhone/cordova/run delete mode 100644 iPhone/fms-Icon-120.png delete mode 100644 iPhone/fms-Icon-80.png delete mode 100644 iPhone/fms-Icon-Small-29.png delete mode 100644 iPhone/fms-Icon-Small-29@2x.png delete mode 100755 iPhone/www/cordova.js create mode 100644 res/ios/Default-568h@2x.png create mode 100644 res/ios/Default.png create mode 100644 res/ios/Default@2x.png create mode 100644 res/ios/Icon-120.png create mode 100644 res/ios/Icon.png create mode 100644 res/ios/Icon@2x.png diff --git a/config.xml b/config.xml index 7fa3427..f0081ed 100644 --- a/config.xml +++ b/config.xml @@ -25,6 +25,8 @@ + + @@ -32,4 +34,17 @@ + + + + + + + + + + + + + diff --git a/iPhone/CordovaLib/Classes/CDV.h b/iPhone/CordovaLib/Classes/CDV.h deleted file mode 100755 index 15d9316..0000000 --- a/iPhone/CordovaLib/Classes/CDV.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVAvailability.h" - -#import "CDVPlugin.h" -#import "CDVViewController.h" -#import "CDVCommandDelegate.h" -#import "CDVURLProtocol.h" -#import "CDVInvokedUrlCommand.h" - -#import "CDVAccelerometer.h" -#import "CDVBattery.h" -#import "CDVCamera.h" -#import "CDVCapture.h" -#import "CDVConnection.h" -#import "CDVContact.h" -#import "CDVContacts.h" -#import "CDVDebug.h" -#import "CDVDevice.h" -#import "CDVFile.h" -#import "CDVFileTransfer.h" -#import "CDVLocation.h" -#import "CDVNotification.h" -#import "CDVPluginResult.h" -#import "CDVReachability.h" -#import "CDVSound.h" -#import "CDVSplashScreen.h" -#import "CDVWhitelist.h" -#import "CDVLocalStorage.h" -#import "CDVInAppBrowser.h" -#import "CDVScreenOrientationDelegate.h" -#import "CDVTimer.h" - -#import "NSArray+Comparisons.h" -#import "NSData+Base64.h" -#import "NSDictionary+Extensions.h" -#import "NSMutableArray+QueueAdditions.h" -#import "UIDevice+Extensions.h" - -#import "CDVJSON.h" diff --git a/iPhone/CordovaLib/Classes/CDVAccelerometer.h b/iPhone/CordovaLib/Classes/CDVAccelerometer.h deleted file mode 100755 index 044ca53..0000000 --- a/iPhone/CordovaLib/Classes/CDVAccelerometer.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import "CDVPlugin.h" - -@interface CDVAccelerometer : CDVPlugin -{ - double x; - double y; - double z; - NSTimeInterval timestamp; -} - -@property (readonly, assign) BOOL isRunning; -@property (nonatomic, strong) NSString* callbackId; - -- (CDVAccelerometer*)init; - -- (void)start:(CDVInvokedUrlCommand*)command; -- (void)stop:(CDVInvokedUrlCommand*)command; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVAccelerometer.m b/iPhone/CordovaLib/Classes/CDVAccelerometer.m deleted file mode 100755 index 33093d0..0000000 --- a/iPhone/CordovaLib/Classes/CDVAccelerometer.m +++ /dev/null @@ -1,128 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVAccelerometer.h" - -@interface CDVAccelerometer () {} -@property (readwrite, assign) BOOL isRunning; -@end - -@implementation CDVAccelerometer - -@synthesize callbackId, isRunning; - -// defaults to 10 msec -#define kAccelerometerInterval 40 -// g constant: -9.81 m/s^2 -#define kGravitationalConstant -9.81 - -- (CDVAccelerometer*)init -{ - self = [super init]; - if (self) { - x = 0; - y = 0; - z = 0; - timestamp = 0; - self.callbackId = nil; - self.isRunning = NO; - } - return self; -} - -- (void)dealloc -{ - [self stop:nil]; -} - -- (void)start:(CDVInvokedUrlCommand*)command -{ - NSString* cbId = command.callbackId; - NSTimeInterval desiredFrequency_num = kAccelerometerInterval; - UIAccelerometer* pAccel = [UIAccelerometer sharedAccelerometer]; - - // accelerometer expects fractional seconds, but we have msecs - pAccel.updateInterval = desiredFrequency_num / 1000; - self.callbackId = cbId; - if (!self.isRunning) { - pAccel.delegate = self; - self.isRunning = YES; - } -} - -- (void)onReset -{ - [self stop:nil]; -} - -- (void)stop:(CDVInvokedUrlCommand*)command -{ - UIAccelerometer* theAccelerometer = [UIAccelerometer sharedAccelerometer]; - - theAccelerometer.delegate = nil; - self.isRunning = NO; -} - -/** - * Picks up accel updates from device and stores them in this class - */ -- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration -{ - if (self.isRunning) { - x = acceleration.x; - y = acceleration.y; - z = acceleration.z; - timestamp = ([[NSDate date] timeIntervalSince1970] * 1000); - [self returnAccelInfo]; - } -} - -- (void)returnAccelInfo -{ - // Create an acceleration object - NSMutableDictionary* accelProps = [NSMutableDictionary dictionaryWithCapacity:4]; - - [accelProps setValue:[NSNumber numberWithDouble:x * kGravitationalConstant] forKey:@"x"]; - [accelProps setValue:[NSNumber numberWithDouble:y * kGravitationalConstant] forKey:@"y"]; - [accelProps setValue:[NSNumber numberWithDouble:z * kGravitationalConstant] forKey:@"z"]; - [accelProps setValue:[NSNumber numberWithDouble:timestamp] forKey:@"timestamp"]; - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:accelProps]; - [result setKeepCallback:[NSNumber numberWithBool:YES]]; - [self.commandDelegate sendPluginResult:result callbackId:self.callbackId]; -} - -// TODO: Consider using filtering to isolate instantaneous data vs. gravity data -jm - -/* - #define kFilteringFactor 0.1 - - // Use a basic low-pass filter to keep only the gravity component of each axis. - grav_accelX = (acceleration.x * kFilteringFactor) + ( grav_accelX * (1.0 - kFilteringFactor)); - grav_accelY = (acceleration.y * kFilteringFactor) + ( grav_accelY * (1.0 - kFilteringFactor)); - grav_accelZ = (acceleration.z * kFilteringFactor) + ( grav_accelZ * (1.0 - kFilteringFactor)); - - // Subtract the low-pass value from the current value to get a simplified high-pass filter - instant_accelX = acceleration.x - ( (acceleration.x * kFilteringFactor) + (instant_accelX * (1.0 - kFilteringFactor)) ); - instant_accelY = acceleration.y - ( (acceleration.y * kFilteringFactor) + (instant_accelY * (1.0 - kFilteringFactor)) ); - instant_accelZ = acceleration.z - ( (acceleration.z * kFilteringFactor) + (instant_accelZ * (1.0 - kFilteringFactor)) ); - - - */ -@end diff --git a/iPhone/CordovaLib/Classes/CDVAvailability.h b/iPhone/CordovaLib/Classes/CDVAvailability.h deleted file mode 100755 index 7e8157c..0000000 --- a/iPhone/CordovaLib/Classes/CDVAvailability.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#define __CORDOVA_IOS__ - -#define __CORDOVA_0_9_6 906 -#define __CORDOVA_1_0_0 10000 -#define __CORDOVA_1_1_0 10100 -#define __CORDOVA_1_2_0 10200 -#define __CORDOVA_1_3_0 10300 -#define __CORDOVA_1_4_0 10400 -#define __CORDOVA_1_4_1 10401 -#define __CORDOVA_1_5_0 10500 -#define __CORDOVA_1_6_0 10600 -#define __CORDOVA_1_6_1 10601 -#define __CORDOVA_1_7_0 10700 -#define __CORDOVA_1_8_0 10800 -#define __CORDOVA_1_8_1 10801 -#define __CORDOVA_1_9_0 10900 -#define __CORDOVA_2_0_0 20000 -#define __CORDOVA_2_1_0 20100 -#define __CORDOVA_2_2_0 20200 -#define __CORDOVA_2_3_0 20300 -#define __CORDOVA_2_4_0 20400 -#define __CORDOVA_2_5_0 20500 -#define __CORDOVA_2_6_0 20600 -#define __CORDOVA_2_7_0 20700 -#define __CORDOVA_2_8_0 20800 -#define __CORDOVA_2_9_0 20900 -#define __CORDOVA_NA 99999 /* not available */ - -/* - #if CORDOVA_VERSION_MIN_REQUIRED >= __CORDOVA_1_7_0 - // do something when its at least 1.7.0 - #else - // do something else (non 1.7.0) - #endif - */ -#ifndef CORDOVA_VERSION_MIN_REQUIRED - #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_9_0 -#endif - -/* - Returns YES if it is at least version specified as NSString(X) - Usage: - if (IsAtLeastiOSVersion(@"5.1")) { - // do something for iOS 5.1 or greater - } - */ -#define IsAtLeastiOSVersion(X) ([[[UIDevice currentDevice] systemVersion] compare:X options:NSNumericSearch] != NSOrderedAscending) - -#define CDV_IsIPad() ([[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] && ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)) - -#define CDV_IsIPhone5() ([[UIScreen mainScreen] bounds].size.height == 568 && [[UIScreen mainScreen] bounds].size.width == 320) - -/* Return the string version of the decimal version */ -#define CDV_VERSION [NSString stringWithFormat:@"%d.%d.%d", \ - (CORDOVA_VERSION_MIN_REQUIRED / 10000), \ - (CORDOVA_VERSION_MIN_REQUIRED % 10000) / 100, \ - (CORDOVA_VERSION_MIN_REQUIRED % 10000) % 100] - -#ifdef __clang__ - #define CDV_DEPRECATED(version, msg) __attribute__((deprecated("Deprecated in Cordova " #version ". " msg))) -#else - #define CDV_DEPRECATED(version, msg) __attribute__((deprecated())) -#endif - -// Enable this to log all exec() calls. -#define CDV_ENABLE_EXEC_LOGGING 0 -#if CDV_ENABLE_EXEC_LOGGING - #define CDV_EXEC_LOG NSLog -#else - #define CDV_EXEC_LOG(...) do {} while (NO) -#endif diff --git a/iPhone/CordovaLib/Classes/CDVBattery.h b/iPhone/CordovaLib/Classes/CDVBattery.h deleted file mode 100755 index ba26c3a..0000000 --- a/iPhone/CordovaLib/Classes/CDVBattery.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import "CDVPlugin.h" - -@interface CDVBattery : CDVPlugin { - UIDeviceBatteryState state; - float level; - bool isPlugged; - NSString* callbackId; -} - -@property (nonatomic) UIDeviceBatteryState state; -@property (nonatomic) float level; -@property (nonatomic) bool isPlugged; -@property (strong) NSString* callbackId; - -- (void)updateBatteryStatus:(NSNotification*)notification; -- (NSDictionary*)getBatteryStatus; -- (void)start:(CDVInvokedUrlCommand*)command; -- (void)stop:(CDVInvokedUrlCommand*)command; -- (void)dealloc; -@end diff --git a/iPhone/CordovaLib/Classes/CDVBattery.m b/iPhone/CordovaLib/Classes/CDVBattery.m deleted file mode 100755 index 681511c..0000000 --- a/iPhone/CordovaLib/Classes/CDVBattery.m +++ /dev/null @@ -1,152 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVBattery.h" - -@interface CDVBattery (PrivateMethods) -- (void)updateOnlineStatus; -@end - -@implementation CDVBattery - -@synthesize state, level, callbackId, isPlugged; - -/* determining type of event occurs on JavaScript side -- (void) updateBatteryLevel:(NSNotification*)notification -{ - // send batterylow event for less than 25% battery - // send batterycritical event for less than 10% battery - // W3c says to send batteryStatus event when batterylevel changes by more than 1% (iOS seems to notify each 5%) - // always update the navigator.device.battery info - float currentLevel = [[UIDevice currentDevice] batteryLevel]; - NSString* type = @""; - // no check for level == -1 since this api is only called when monitoring is enabled so level should be valid - if (currentLevel < 0.10){ - type = @"batterycritical"; - } else if (currentLevel < 0.25) { - type = @"batterylow"; - } else { - float onePercent = 0.1; - if (self.level >= 0 ){ - onePercent = self.level * 0.01; - } - if (fabsf(currentLevel - self.level) > onePercent){ - // issue batteryStatus event - type = @"batterystatus"; - } - } - // update the battery info and fire event - NSString* jsString = [NSString stringWithFormat:@"navigator.device.battery._status(\"%@\", %@)", type,[[self getBatteryStatus] JSONRepresentation]]; - [super writeJavascript:jsString]; -} - */ - -- (void)updateBatteryStatus:(NSNotification*)notification -{ - NSDictionary* batteryData = [self getBatteryStatus]; - - if (self.callbackId) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:batteryData]; - [result setKeepCallbackAsBool:YES]; - [self.commandDelegate sendPluginResult:result callbackId:self.callbackId]; - } -} - -/* Get the current battery status and level. Status will be unknown and level will be -1.0 if - * monitoring is turned off. - */ -- (NSDictionary*)getBatteryStatus -{ - UIDevice* currentDevice = [UIDevice currentDevice]; - UIDeviceBatteryState currentState = [currentDevice batteryState]; - - isPlugged = FALSE; // UIDeviceBatteryStateUnknown or UIDeviceBatteryStateUnplugged - if ((currentState == UIDeviceBatteryStateCharging) || (currentState == UIDeviceBatteryStateFull)) { - isPlugged = TRUE; - } - float currentLevel = [currentDevice batteryLevel]; - - if ((currentLevel != self.level) || (currentState != self.state)) { - self.level = currentLevel; - self.state = currentState; - } - - // W3C spec says level must be null if it is unknown - NSObject* w3cLevel = nil; - if ((currentState == UIDeviceBatteryStateUnknown) || (currentLevel == -1.0)) { - w3cLevel = [NSNull null]; - } else { - w3cLevel = [NSNumber numberWithFloat:(currentLevel * 100)]; - } - NSMutableDictionary* batteryData = [NSMutableDictionary dictionaryWithCapacity:2]; - [batteryData setObject:[NSNumber numberWithBool:isPlugged] forKey:@"isPlugged"]; - [batteryData setObject:w3cLevel forKey:@"level"]; - return batteryData; -} - -/* turn on battery monitoring*/ -- (void)start:(CDVInvokedUrlCommand*)command -{ - self.callbackId = command.callbackId; - - if ([UIDevice currentDevice].batteryMonitoringEnabled == NO) { - [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateBatteryStatus:) - name:UIDeviceBatteryStateDidChangeNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateBatteryStatus:) - name:UIDeviceBatteryLevelDidChangeNotification object:nil]; - } -} - -/* turn off battery monitoring */ -- (void)stop:(CDVInvokedUrlCommand*)command -{ - // callback one last time to clear the callback function on JS side - if (self.callbackId) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getBatteryStatus]]; - [result setKeepCallbackAsBool:NO]; - [self.commandDelegate sendPluginResult:result callbackId:self.callbackId]; - } - self.callbackId = nil; - [[UIDevice currentDevice] setBatteryMonitoringEnabled:NO]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceBatteryStateDidChangeNotification object:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceBatteryLevelDidChangeNotification object:nil]; -} - -- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView -{ - self = (CDVBattery*)[super initWithWebView:theWebView]; - if (self) { - self.state = UIDeviceBatteryStateUnknown; - self.level = -1.0; - } - return self; -} - -- (void)dealloc -{ - [self stop:nil]; -} - -- (void)onReset -{ - [self stop:nil]; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVCamera.h b/iPhone/CordovaLib/Classes/CDVCamera.h deleted file mode 100755 index 2932e3b..0000000 --- a/iPhone/CordovaLib/Classes/CDVCamera.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import -#import -#import "CDVPlugin.h" - -enum CDVDestinationType { - DestinationTypeDataUrl = 0, - DestinationTypeFileUri, - DestinationTypeNativeUri -}; -typedef NSUInteger CDVDestinationType; - -enum CDVEncodingType { - EncodingTypeJPEG = 0, - EncodingTypePNG -}; -typedef NSUInteger CDVEncodingType; - -enum CDVMediaType { - MediaTypePicture = 0, - MediaTypeVideo, - MediaTypeAll -}; -typedef NSUInteger CDVMediaType; - -@interface CDVCameraPicker : UIImagePickerController -{} - -@property (assign) NSInteger quality; -@property (copy) NSString* callbackId; -@property (copy) NSString* postUrl; -@property (nonatomic) enum CDVDestinationType returnType; -@property (nonatomic) enum CDVEncodingType encodingType; -@property (strong) UIPopoverController* popoverController; -@property (assign) CGSize targetSize; -@property (assign) bool correctOrientation; -@property (assign) bool saveToPhotoAlbum; -@property (assign) bool cropToSize; -@property (strong) UIWebView* webView; -@property (assign) BOOL popoverSupported; - -@end - -// ======================================================================= // - -@interface CDVCamera : CDVPlugin -{} - -@property (strong) CDVCameraPicker* pickerController; -@property (strong) NSMutableDictionary *metadata; -@property (strong, nonatomic) CLLocationManager *locationManager; -@property (strong) NSData* data; - -/* - * getPicture - * - * arguments: - * 1: this is the javascript function that will be called with the results, the first parameter passed to the - * javascript function is the picture as a Base64 encoded string - * 2: this is the javascript function to be called if there was an error - * options: - * quality: integer between 1 and 100 - */ -- (void)takePicture:(CDVInvokedUrlCommand*)command; -- (void)postImage:(UIImage*)anImage withFilename:(NSString*)filename toUrl:(NSURL*)url; -- (void)cleanup:(CDVInvokedUrlCommand*)command; -- (void)repositionPopover:(CDVInvokedUrlCommand*)command; - -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info; -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo; -- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker; -- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated; -- (UIImage*)imageByScalingAndCroppingForSize:(UIImage*)anImage toSize:(CGSize)targetSize; -- (UIImage*)imageByScalingNotCroppingForSize:(UIImage*)anImage toSize:(CGSize)frameSize; -- (UIImage*)imageCorrectedForCaptureOrientation:(UIImage*)anImage; - -- (void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*)oldLocation; -- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVCamera.m b/iPhone/CordovaLib/Classes/CDVCamera.m deleted file mode 100755 index d0a36dd..0000000 --- a/iPhone/CordovaLib/Classes/CDVCamera.m +++ /dev/null @@ -1,730 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVCamera.h" -#import "CDVJpegHeaderWriter.h" -#import "NSArray+Comparisons.h" -#import "NSData+Base64.h" -#import "NSDictionary+Extensions.h" -#import -#import -#import -#import -#import -#import - -#define CDV_PHOTO_PREFIX @"cdv_photo_" - -static NSSet* org_apache_cordova_validArrowDirections; - -@interface CDVCamera () - -@property (readwrite, assign) BOOL hasPendingOperation; - -@end - -@implementation CDVCamera - -+ (void)initialize -{ - org_apache_cordova_validArrowDirections = [[NSSet alloc] initWithObjects:[NSNumber numberWithInt:UIPopoverArrowDirectionUp], [NSNumber numberWithInt:UIPopoverArrowDirectionDown], [NSNumber numberWithInt:UIPopoverArrowDirectionLeft], [NSNumber numberWithInt:UIPopoverArrowDirectionRight], [NSNumber numberWithInt:UIPopoverArrowDirectionAny], nil]; -} - -@synthesize hasPendingOperation, pickerController, locationManager; - -- (BOOL)popoverSupported -{ - return (NSClassFromString(@"UIPopoverController") != nil) && - (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad); -} - -/* takePicture arguments: - * INDEX ARGUMENT - * 0 quality - * 1 destination type - * 2 source type - * 3 targetWidth - * 4 targetHeight - * 5 encodingType - * 6 mediaType - * 7 allowsEdit - * 8 correctOrientation - * 9 saveToPhotoAlbum - * 10 popoverOptions - * 11 cameraDirection - */ -- (void)takePicture:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSArray* arguments = command.arguments; - - self.hasPendingOperation = NO; - - NSString* sourceTypeString = [arguments objectAtIndex:2]; - UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera; // default - if (sourceTypeString != nil) { - sourceType = (UIImagePickerControllerSourceType)[sourceTypeString intValue]; - } - - bool hasCamera = [UIImagePickerController isSourceTypeAvailable:sourceType]; - if (!hasCamera) { - NSLog(@"Camera.getPicture: source type %d not available.", sourceType); - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no camera available"]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - - bool allowEdit = [[arguments objectAtIndex:7] boolValue]; - NSNumber* targetWidth = [arguments objectAtIndex:3]; - NSNumber* targetHeight = [arguments objectAtIndex:4]; - NSNumber* mediaValue = [arguments objectAtIndex:6]; - CDVMediaType mediaType = (mediaValue) ? [mediaValue intValue] : MediaTypePicture; - - CGSize targetSize = CGSizeMake(0, 0); - if ((targetWidth != nil) && (targetHeight != nil)) { - targetSize = CGSizeMake([targetWidth floatValue], [targetHeight floatValue]); - } - - // If a popover is already open, close it; we only want one at a time. - if (([[self pickerController] popoverController] != nil) && [[[self pickerController] popoverController] isPopoverVisible]) { - [[[self pickerController] popoverController] dismissPopoverAnimated:YES]; - [[[self pickerController] popoverController] setDelegate:nil]; - [[self pickerController] setPopoverController:nil]; - } - - CDVCameraPicker* cameraPicker = [[CDVCameraPicker alloc] init]; - self.pickerController = cameraPicker; - - cameraPicker.delegate = self; - cameraPicker.sourceType = sourceType; - cameraPicker.allowsEditing = allowEdit; // THIS IS ALL IT TAKES FOR CROPPING - jm - cameraPicker.callbackId = callbackId; - cameraPicker.targetSize = targetSize; - cameraPicker.cropToSize = NO; - // we need to capture this state for memory warnings that dealloc this object - cameraPicker.webView = self.webView; - cameraPicker.popoverSupported = [self popoverSupported]; - - cameraPicker.correctOrientation = [[arguments objectAtIndex:8] boolValue]; - cameraPicker.saveToPhotoAlbum = [[arguments objectAtIndex:9] boolValue]; - - cameraPicker.encodingType = ([arguments objectAtIndex:5]) ? [[arguments objectAtIndex:5] intValue] : EncodingTypeJPEG; - - cameraPicker.quality = ([arguments objectAtIndex:0]) ? [[arguments objectAtIndex:0] intValue] : 50; - cameraPicker.returnType = ([arguments objectAtIndex:1]) ? [[arguments objectAtIndex:1] intValue] : DestinationTypeFileUri; - - if (sourceType == UIImagePickerControllerSourceTypeCamera) { - // We only allow taking pictures (no video) in this API. - cameraPicker.mediaTypes = [NSArray arrayWithObjects:(NSString*)kUTTypeImage, nil]; - - // We can only set the camera device if we're actually using the camera. - NSNumber* cameraDirection = [command argumentAtIndex:11 withDefault:[NSNumber numberWithInteger:UIImagePickerControllerCameraDeviceRear]]; - cameraPicker.cameraDevice = (UIImagePickerControllerCameraDevice)[cameraDirection intValue]; - } else if (mediaType == MediaTypeAll) { - cameraPicker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:sourceType]; - } else { - NSArray* mediaArray = [NSArray arrayWithObjects:(NSString*)(mediaType == MediaTypeVideo ? kUTTypeMovie : kUTTypeImage), nil]; - cameraPicker.mediaTypes = mediaArray; - } - - if ([self popoverSupported] && (sourceType != UIImagePickerControllerSourceTypeCamera)) { - if (cameraPicker.popoverController == nil) { - cameraPicker.popoverController = [[NSClassFromString(@"UIPopoverController")alloc] initWithContentViewController:cameraPicker]; - } - NSDictionary* options = [command.arguments objectAtIndex:10 withDefault:nil]; - [self displayPopover:options]; - } else { - if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) { - [self.viewController presentViewController:cameraPicker animated:YES completion:nil]; - } else { - [self.viewController presentModalViewController:cameraPicker animated:YES]; - } - } - self.hasPendingOperation = YES; -} - -- (void)repositionPopover:(CDVInvokedUrlCommand*)command -{ - NSDictionary* options = [command.arguments objectAtIndex:0 withDefault:nil]; - - [self displayPopover:options]; -} - -- (void)displayPopover:(NSDictionary*)options -{ - int x = 0; - int y = 32; - int width = 320; - int height = 480; - UIPopoverArrowDirection arrowDirection = UIPopoverArrowDirectionAny; - - if (options) { - x = [options integerValueForKey:@"x" defaultValue:0]; - y = [options integerValueForKey:@"y" defaultValue:32]; - width = [options integerValueForKey:@"width" defaultValue:320]; - height = [options integerValueForKey:@"height" defaultValue:480]; - arrowDirection = [options integerValueForKey:@"arrowDir" defaultValue:UIPopoverArrowDirectionAny]; - if (![org_apache_cordova_validArrowDirections containsObject:[NSNumber numberWithInt:arrowDirection]]) { - arrowDirection = UIPopoverArrowDirectionAny; - } - } - - [[[self pickerController] popoverController] setDelegate:self]; - [[[self pickerController] popoverController] presentPopoverFromRect:CGRectMake(x, y, width, height) - inView:[self.webView superview] - permittedArrowDirections:arrowDirection - animated:YES]; -} - -- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated -{ - if([navigationController isKindOfClass:[UIImagePickerController class]]){ - UIImagePickerController * cameraPicker = (UIImagePickerController*)navigationController; - - if(![cameraPicker.mediaTypes containsObject:(NSString*) kUTTypeImage]){ - [viewController.navigationItem setTitle:NSLocalizedString(@"Videos title", nil)]; - } - } -} - -- (void)cleanup:(CDVInvokedUrlCommand*)command -{ - // empty the tmp directory - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - NSError* err = nil; - BOOL hasErrors = NO; - - // clear contents of NSTemporaryDirectory - NSString* tempDirectoryPath = NSTemporaryDirectory(); - NSDirectoryEnumerator* directoryEnumerator = [fileMgr enumeratorAtPath:tempDirectoryPath]; - NSString* fileName = nil; - BOOL result; - - while ((fileName = [directoryEnumerator nextObject])) { - // only delete the files we created - if (![fileName hasPrefix:CDV_PHOTO_PREFIX]) { - continue; - } - NSString* filePath = [tempDirectoryPath stringByAppendingPathComponent:fileName]; - result = [fileMgr removeItemAtPath:filePath error:&err]; - if (!result && err) { - NSLog(@"Failed to delete: %@ (error: %@)", filePath, err); - hasErrors = YES; - } - } - - CDVPluginResult* pluginResult; - if (hasErrors) { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:@"One or more files failed to be deleted."]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -- (void)popoverControllerDidDismissPopover:(id)popoverController -{ - // [ self imagePickerControllerDidCancel:self.pickerController ]; ' - UIPopoverController* pc = (UIPopoverController*)popoverController; - - [pc dismissPopoverAnimated:YES]; - pc.delegate = nil; - if (self.pickerController && self.pickerController.callbackId && self.pickerController.popoverController) { - self.pickerController.popoverController = nil; - NSString* callbackId = self.pickerController.callbackId; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no image selected"]; // error callback expects string ATM - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - self.hasPendingOperation = NO; -} - -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info -{ - CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker; - - if (cameraPicker.popoverSupported && (cameraPicker.popoverController != nil)) { - [cameraPicker.popoverController dismissPopoverAnimated:YES]; - cameraPicker.popoverController.delegate = nil; - cameraPicker.popoverController = nil; - } else { - if ([cameraPicker respondsToSelector:@selector(presentingViewController)]) { - [[cameraPicker presentingViewController] dismissModalViewControllerAnimated:YES]; - } else { - [[cameraPicker parentViewController] dismissModalViewControllerAnimated:YES]; - } - } - - CDVPluginResult* result = nil; - - NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType]; - // IMAGE TYPE - if ([mediaType isEqualToString:(NSString*)kUTTypeImage]) { - if (cameraPicker.returnType == DestinationTypeNativeUri) { - NSString* nativeUri = [(NSURL*)[info objectForKey:UIImagePickerControllerReferenceURL] absoluteString]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:nativeUri]; - } else { - // get the image - UIImage* image = nil; - if (cameraPicker.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage]) { - image = [info objectForKey:UIImagePickerControllerEditedImage]; - } else { - image = [info objectForKey:UIImagePickerControllerOriginalImage]; - } - - if (cameraPicker.correctOrientation) { - image = [self imageCorrectedForCaptureOrientation:image]; - } - - UIImage* scaledImage = nil; - - if ((cameraPicker.targetSize.width > 0) && (cameraPicker.targetSize.height > 0)) { - // if cropToSize, resize image and crop to target size, otherwise resize to fit target without cropping - if (cameraPicker.cropToSize) { - scaledImage = [self imageByScalingAndCroppingForSize:image toSize:cameraPicker.targetSize]; - } else { - scaledImage = [self imageByScalingNotCroppingForSize:image toSize:cameraPicker.targetSize]; - } - } - - NSData* data = nil; - - if (cameraPicker.encodingType == EncodingTypePNG) { - data = UIImagePNGRepresentation(scaledImage == nil ? image : scaledImage); - } else { - data = UIImageJPEGRepresentation(scaledImage == nil ? image : scaledImage, cameraPicker.quality / 100.0f); - - NSDictionary *controllerMetadata = [info objectForKey:@"UIImagePickerControllerMediaMetadata"]; - if (controllerMetadata) { - self.data = data; - self.metadata = [[NSMutableDictionary alloc] init]; - - NSMutableDictionary *EXIFDictionary = [[controllerMetadata objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy]; - if (EXIFDictionary) [self.metadata setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary]; - - [[self locationManager] startUpdatingLocation]; - return; - } - } - - if (cameraPicker.saveToPhotoAlbum) { - UIImageWriteToSavedPhotosAlbum([UIImage imageWithData:data], nil, nil, nil); - } - - if (cameraPicker.returnType == DestinationTypeFileUri) { - // write to temp directory and return URI - // get the temp directory path - NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath]; - NSError* err = nil; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; // recommended by apple (vs [NSFileManager defaultManager]) to be threadsafe - // generate unique file name - NSString* filePath; - - int i = 1; - do { - filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, cameraPicker.encodingType == EncodingTypePNG ? @"png":@"jpg"]; - } while ([fileMgr fileExistsAtPath:filePath]); - - // save file - if (![data writeToFile:filePath options:NSAtomicWrite error:&err]) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[NSURL fileURLWithPath:filePath] absoluteString]]; - } - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[data base64EncodedString]]; - } - } - } - // NOT IMAGE TYPE (MOVIE) - else { - NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] absoluteString]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:moviePath]; - } - - if (result) { - [self.commandDelegate sendPluginResult:result callbackId:cameraPicker.callbackId]; - } - - self.hasPendingOperation = NO; - self.pickerController = nil; -} - -// older api calls newer didFinishPickingMediaWithInfo -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo -{ - NSDictionary* imageInfo = [NSDictionary dictionaryWithObject:image forKey:UIImagePickerControllerOriginalImage]; - - [self imagePickerController:picker didFinishPickingMediaWithInfo:imageInfo]; -} - -- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker -{ - CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker; - - if ([cameraPicker respondsToSelector:@selector(presentingViewController)]) { - [[cameraPicker presentingViewController] dismissModalViewControllerAnimated:YES]; - } else { - [[cameraPicker parentViewController] dismissModalViewControllerAnimated:YES]; - } - // popoverControllerDidDismissPopover:(id)popoverController is called if popover is cancelled - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no image selected"]; // error callback expects string ATM - [self.commandDelegate sendPluginResult:result callbackId:cameraPicker.callbackId]; - - self.hasPendingOperation = NO; - self.pickerController = nil; -} - -- (UIImage*)imageByScalingAndCroppingForSize:(UIImage*)anImage toSize:(CGSize)targetSize -{ - UIImage* sourceImage = anImage; - UIImage* newImage = nil; - CGSize imageSize = sourceImage.size; - CGFloat width = imageSize.width; - CGFloat height = imageSize.height; - CGFloat targetWidth = targetSize.width; - CGFloat targetHeight = targetSize.height; - CGFloat scaleFactor = 0.0; - CGFloat scaledWidth = targetWidth; - CGFloat scaledHeight = targetHeight; - CGPoint thumbnailPoint = CGPointMake(0.0, 0.0); - - if (CGSizeEqualToSize(imageSize, targetSize) == NO) { - CGFloat widthFactor = targetWidth / width; - CGFloat heightFactor = targetHeight / height; - - if (widthFactor > heightFactor) { - scaleFactor = widthFactor; // scale to fit height - } else { - scaleFactor = heightFactor; // scale to fit width - } - scaledWidth = width * scaleFactor; - scaledHeight = height * scaleFactor; - - // center the image - if (widthFactor > heightFactor) { - thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; - } else if (widthFactor < heightFactor) { - thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5; - } - } - - UIGraphicsBeginImageContext(targetSize); // this will crop - - CGRect thumbnailRect = CGRectZero; - thumbnailRect.origin = thumbnailPoint; - thumbnailRect.size.width = scaledWidth; - thumbnailRect.size.height = scaledHeight; - - [sourceImage drawInRect:thumbnailRect]; - - newImage = UIGraphicsGetImageFromCurrentImageContext(); - if (newImage == nil) { - NSLog(@"could not scale image"); - } - - // pop the context to get back to the default - UIGraphicsEndImageContext(); - return newImage; -} - -- (UIImage*)imageCorrectedForCaptureOrientation:(UIImage*)anImage -{ - float rotation_radians = 0; - bool perpendicular = false; - - switch ([anImage imageOrientation]) { - case UIImageOrientationUp : - rotation_radians = 0.0; - break; - - case UIImageOrientationDown: - rotation_radians = M_PI; // don't be scared of radians, if you're reading this, you're good at math - break; - - case UIImageOrientationRight: - rotation_radians = M_PI_2; - perpendicular = true; - break; - - case UIImageOrientationLeft: - rotation_radians = -M_PI_2; - perpendicular = true; - break; - - default: - break; - } - - UIGraphicsBeginImageContext(CGSizeMake(anImage.size.width, anImage.size.height)); - CGContextRef context = UIGraphicsGetCurrentContext(); - - // Rotate around the center point - CGContextTranslateCTM(context, anImage.size.width / 2, anImage.size.height / 2); - CGContextRotateCTM(context, rotation_radians); - - CGContextScaleCTM(context, 1.0, -1.0); - float width = perpendicular ? anImage.size.height : anImage.size.width; - float height = perpendicular ? anImage.size.width : anImage.size.height; - CGContextDrawImage(context, CGRectMake(-width / 2, -height / 2, width, height), [anImage CGImage]); - - // Move the origin back since the rotation might've change it (if its 90 degrees) - if (perpendicular) { - CGContextTranslateCTM(context, -anImage.size.height / 2, -anImage.size.width / 2); - } - - UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - return newImage; -} - -- (UIImage*)imageByScalingNotCroppingForSize:(UIImage*)anImage toSize:(CGSize)frameSize -{ - UIImage* sourceImage = anImage; - UIImage* newImage = nil; - CGSize imageSize = sourceImage.size; - CGFloat width = imageSize.width; - CGFloat height = imageSize.height; - CGFloat targetWidth = frameSize.width; - CGFloat targetHeight = frameSize.height; - CGFloat scaleFactor = 0.0; - CGSize scaledSize = frameSize; - - if (CGSizeEqualToSize(imageSize, frameSize) == NO) { - CGFloat widthFactor = targetWidth / width; - CGFloat heightFactor = targetHeight / height; - - // opposite comparison to imageByScalingAndCroppingForSize in order to contain the image within the given bounds - if (widthFactor > heightFactor) { - scaleFactor = heightFactor; // scale to fit height - } else { - scaleFactor = widthFactor; // scale to fit width - } - scaledSize = CGSizeMake(MIN(width * scaleFactor, targetWidth), MIN(height * scaleFactor, targetHeight)); - } - - UIGraphicsBeginImageContext(scaledSize); // this will resize - - [sourceImage drawInRect:CGRectMake(0, 0, scaledSize.width, scaledSize.height)]; - - newImage = UIGraphicsGetImageFromCurrentImageContext(); - if (newImage == nil) { - NSLog(@"could not scale image"); - } - - // pop the context to get back to the default - UIGraphicsEndImageContext(); - return newImage; -} - -- (void)postImage:(UIImage*)anImage withFilename:(NSString*)filename toUrl:(NSURL*)url -{ - self.hasPendingOperation = YES; - - NSString* boundary = @"----BOUNDARY_IS_I"; - - NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url]; - [req setHTTPMethod:@"POST"]; - - NSString* contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; - [req setValue:contentType forHTTPHeaderField:@"Content-type"]; - - NSData* imageData = UIImagePNGRepresentation(anImage); - - // adding the body - NSMutableData* postBody = [NSMutableData data]; - - // first parameter an image - [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; - [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"upload\"; filename=\"%@\"\r\n", filename] dataUsingEncoding:NSUTF8StringEncoding]]; - [postBody appendData:[@"Content-Type: image/png\r\n\r\n" dataUsingEncoding : NSUTF8StringEncoding]]; - [postBody appendData:imageData]; - - // // second parameter information - // [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; - // [postBody appendData:[@"Content-Disposition: form-data; name=\"some_other_name\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; - // [postBody appendData:[@"some_other_value" dataUsingEncoding:NSUTF8StringEncoding]]; - // [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r \n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; - - [req setHTTPBody:postBody]; - - NSURLResponse* response; - NSError* error; - [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&error]; - - // NSData* result = [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&error]; - // NSString * resultStr = [[[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding] autorelease]; - - self.hasPendingOperation = NO; -} - - -- (CLLocationManager *)locationManager { - - if (locationManager != nil) { - return locationManager; - } - - locationManager = [[CLLocationManager alloc] init]; - [locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters]; - [locationManager setDelegate:self]; - - return locationManager; -} - -- (void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*)oldLocation -{ - if (locationManager != nil) { - [self.locationManager stopUpdatingLocation]; - self.locationManager = nil; - - NSMutableDictionary *GPSDictionary = [[NSMutableDictionary dictionary] init]; - - CLLocationDegrees latitude = newLocation.coordinate.latitude; - CLLocationDegrees longitude = newLocation.coordinate.longitude; - - // latitude - if (latitude < 0.0) { - latitude = latitude * -1.0f; - [GPSDictionary setObject:@"S" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef]; - } else { - [GPSDictionary setObject:@"N" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef]; - } - [GPSDictionary setObject:[NSNumber numberWithFloat:latitude] forKey:(NSString*)kCGImagePropertyGPSLatitude]; - - // longitude - if (longitude < 0.0) { - longitude = longitude * -1.0f; - [GPSDictionary setObject:@"W" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef]; - } - else { - [GPSDictionary setObject:@"E" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef]; - } - [GPSDictionary setObject:[NSNumber numberWithFloat:longitude] forKey:(NSString*)kCGImagePropertyGPSLongitude]; - - // altitude - CGFloat altitude = newLocation.altitude; - if (!isnan(altitude)){ - if (altitude < 0) { - altitude = -altitude; - [GPSDictionary setObject:@"1" forKey:(NSString *)kCGImagePropertyGPSAltitudeRef]; - } else { - [GPSDictionary setObject:@"0" forKey:(NSString *)kCGImagePropertyGPSAltitudeRef]; - } - [GPSDictionary setObject:[NSNumber numberWithFloat:altitude] forKey:(NSString *)kCGImagePropertyGPSAltitude]; - } - - // Time and date - NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; - [formatter setDateFormat:@"HH:mm:ss.SSSSSS"]; - [formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; - [GPSDictionary setObject:[formatter stringFromDate:newLocation.timestamp] forKey:(NSString *)kCGImagePropertyGPSTimeStamp]; - [formatter setDateFormat:@"yyyy:MM:dd"]; - [GPSDictionary setObject:[formatter stringFromDate:newLocation.timestamp] forKey:(NSString *)kCGImagePropertyGPSDateStamp]; - - [self.metadata setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary]; - [self imagePickerControllerReturnImageResult]; - } -} - -- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { - if (locationManager != nil) { - [self.locationManager stopUpdatingLocation]; - self.locationManager = nil; - - [self imagePickerControllerReturnImageResult]; - } -} - -- (void)imagePickerControllerReturnImageResult -{ - CDVPluginResult* result = nil; - - if (self.metadata) { - CGImageSourceRef sourceImage = CGImageSourceCreateWithData((__bridge_retained CFDataRef)self.data, NULL); - CFStringRef sourceType = CGImageSourceGetType(sourceImage); - - CGImageDestinationRef destinationImage = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)self.data, sourceType, 1, NULL); - CGImageDestinationAddImageFromSource(destinationImage, sourceImage, 0, (__bridge CFDictionaryRef)self.metadata); - CGImageDestinationFinalize(destinationImage); - - CFRelease(sourceImage); - CFRelease(destinationImage); - } - - if (self.pickerController.saveToPhotoAlbum) { - UIImageWriteToSavedPhotosAlbum([UIImage imageWithData:[self data]], nil, nil, nil); - } - - if (self.pickerController.returnType == DestinationTypeFileUri) { - // write to temp directory and return URI - // get the temp directory path - NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath]; - NSError* err = nil; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; // recommended by apple (vs [NSFileManager defaultManager]) to be threadsafe - // generate unique file name - NSString* filePath; - - int i = 1; - do { - filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, self.pickerController.encodingType == EncodingTypePNG ? @"png":@"jpg"]; - } while ([fileMgr fileExistsAtPath:filePath]); - - // save file - if (![self.data writeToFile:filePath options:NSAtomicWrite error:&err]) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]]; - } - else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[NSURL fileURLWithPath:filePath] absoluteString]]; - } - } - else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[self.data base64EncodedString]]; - } - if (result) { - [self.commandDelegate sendPluginResult:result callbackId:self.pickerController.callbackId]; - } - - if (result) { - [self.commandDelegate sendPluginResult:result callbackId:self.pickerController.callbackId]; - } - - self.hasPendingOperation = NO; - self.pickerController = nil; - self.data = nil; - self.metadata = nil; -} - -@end - -@implementation CDVCameraPicker - -@synthesize quality, postUrl; -@synthesize returnType; -@synthesize callbackId; -@synthesize popoverController; -@synthesize targetSize; -@synthesize correctOrientation; -@synthesize saveToPhotoAlbum; -@synthesize encodingType; -@synthesize cropToSize; -@synthesize webView; -@synthesize popoverSupported; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVCapture.h b/iPhone/CordovaLib/Classes/CDVCapture.h deleted file mode 100755 index afb82b4..0000000 --- a/iPhone/CordovaLib/Classes/CDVCapture.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import -#import -#import "CDVPlugin.h" -#import "CDVFile.h" - -enum CDVCaptureError { - CAPTURE_INTERNAL_ERR = 0, - CAPTURE_APPLICATION_BUSY = 1, - CAPTURE_INVALID_ARGUMENT = 2, - CAPTURE_NO_MEDIA_FILES = 3, - CAPTURE_NOT_SUPPORTED = 20 -}; -typedef NSUInteger CDVCaptureError; - -@interface CDVImagePicker : UIImagePickerController -{ - NSString* callbackid; - NSInteger quality; - NSString* mimeType; -} -@property (assign) NSInteger quality; -@property (copy) NSString* callbackId; -@property (copy) NSString* mimeType; - -@end - -@interface CDVCapture : CDVPlugin -{ - CDVImagePicker* pickerController; - BOOL inUse; -} -@property BOOL inUse; -- (void)captureAudio:(CDVInvokedUrlCommand*)command; -- (void)captureImage:(CDVInvokedUrlCommand*)command; -- (CDVPluginResult*)processImage:(UIImage*)image type:(NSString*)mimeType forCallbackId:(NSString*)callbackId; -- (void)captureVideo:(CDVInvokedUrlCommand*)command; -- (CDVPluginResult*)processVideo:(NSString*)moviePath forCallbackId:(NSString*)callbackId; -- (void)getMediaModes:(CDVInvokedUrlCommand*)command; -- (void)getFormatData:(CDVInvokedUrlCommand*)command; -- (NSDictionary*)getMediaDictionaryFromPath:(NSString*)fullPath ofType:(NSString*)type; -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info; -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo; -- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker; - -@end - -@interface CDVAudioNavigationController : UINavigationController - -@end - -/* AudioRecorderViewController is used to create a simple view for audio recording. - * It is created from [Capture captureAudio]. It creates a very simple interface for - * recording by presenting just a record/stop button and a Done button to close the view. - * The recording time is displayed and recording for a specified duration is supported. When duration - * is specified there is no UI to the user - recording just stops when the specified - * duration is reached. The UI has been minimized to avoid localization. - */ -@interface CDVAudioRecorderViewController : UIViewController -{ - CDVCaptureError errorCode; - NSString* callbackId; - NSNumber* duration; - CDVCapture* captureCommand; - UIBarButtonItem* doneButton; - UIView* recordingView; - UIButton* recordButton; - UIImage* recordImage; - UIImage* stopRecordImage; - UILabel* timerLabel; - AVAudioRecorder* avRecorder; - AVAudioSession* avSession; - CDVPluginResult* pluginResult; - NSTimer* timer; - BOOL isTimed; -} -@property (nonatomic) CDVCaptureError errorCode; -@property (nonatomic, copy) NSString* callbackId; -@property (nonatomic, copy) NSNumber* duration; -@property (nonatomic, strong) CDVCapture* captureCommand; -@property (nonatomic, strong) UIBarButtonItem* doneButton; -@property (nonatomic, strong) UIView* recordingView; -@property (nonatomic, strong) UIButton* recordButton; -@property (nonatomic, strong) UIImage* recordImage; -@property (nonatomic, strong) UIImage* stopRecordImage; -@property (nonatomic, strong) UILabel* timerLabel; -@property (nonatomic, strong) AVAudioRecorder* avRecorder; -@property (nonatomic, strong) AVAudioSession* avSession; -@property (nonatomic, strong) CDVPluginResult* pluginResult; -@property (nonatomic, strong) NSTimer* timer; -@property (nonatomic) BOOL isTimed; - -- (id)initWithCommand:(CDVPlugin*)theCommand duration:(NSNumber*)theDuration callbackId:(NSString*)theCallbackId; -- (void)processButton:(id)sender; -- (void)stopRecordingCleanup; -- (void)dismissAudioView:(id)sender; -- (NSString*)formatTime:(int)interval; -- (void)updateTime; -@end diff --git a/iPhone/CordovaLib/Classes/CDVCapture.m b/iPhone/CordovaLib/Classes/CDVCapture.m deleted file mode 100755 index 884702d..0000000 --- a/iPhone/CordovaLib/Classes/CDVCapture.m +++ /dev/null @@ -1,845 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVCapture.h" -#import "CDVJSON.h" -#import "CDVAvailability.h" - -#define kW3CMediaFormatHeight @"height" -#define kW3CMediaFormatWidth @"width" -#define kW3CMediaFormatCodecs @"codecs" -#define kW3CMediaFormatBitrate @"bitrate" -#define kW3CMediaFormatDuration @"duration" -#define kW3CMediaModeType @"type" - -@implementation CDVImagePicker - -@synthesize quality; -@synthesize callbackId; -@synthesize mimeType; - -- (uint64_t)accessibilityTraits -{ - NSString* systemVersion = [[UIDevice currentDevice] systemVersion]; - - if (([systemVersion compare:@"4.0" options:NSNumericSearch] != NSOrderedAscending)) { // this means system version is not less than 4.0 - return UIAccessibilityTraitStartsMediaSession; - } - - return UIAccessibilityTraitNone; -} - -@end - -@implementation CDVCapture -@synthesize inUse; - -- (id)initWithWebView:(UIWebView*)theWebView -{ - self = (CDVCapture*)[super initWithWebView:theWebView]; - if (self) { - self.inUse = NO; - } - return self; -} - -- (void)captureAudio:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* options = [command.arguments objectAtIndex:0]; - - if ([options isKindOfClass:[NSNull class]]) { - options = [NSDictionary dictionary]; - } - - NSNumber* duration = [options objectForKey:@"duration"]; - // the default value of duration is 0 so use nil (no duration) if default value - if (duration) { - duration = [duration doubleValue] == 0 ? nil : duration; - } - CDVPluginResult* result = nil; - - if (NSClassFromString(@"AVAudioRecorder") == nil) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_NOT_SUPPORTED]; - } else if (self.inUse == YES) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_APPLICATION_BUSY]; - } else { - // all the work occurs here - CDVAudioRecorderViewController* audioViewController = [[CDVAudioRecorderViewController alloc] initWithCommand:self duration:duration callbackId:callbackId]; - - // Now create a nav controller and display the view... - CDVAudioNavigationController* navController = [[CDVAudioNavigationController alloc] initWithRootViewController:audioViewController]; - - self.inUse = YES; - - if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) { - [self.viewController presentViewController:navController animated:YES completion:nil]; - } else { - [self.viewController presentModalViewController:navController animated:YES]; - } - } - - if (result) { - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } -} - -- (void)captureImage:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* options = [command.arguments objectAtIndex:0]; - - if ([options isKindOfClass:[NSNull class]]) { - options = [NSDictionary dictionary]; - } - - // options could contain limit and mode neither of which are supported at this time - // taking more than one picture (limit) is only supported if provide own controls via cameraOverlayView property - // can support mode in OS - - if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { - NSLog(@"Capture.imageCapture: camera not available."); - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_NOT_SUPPORTED]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } else { - if (pickerController == nil) { - pickerController = [[CDVImagePicker alloc] init]; - } - - pickerController.delegate = self; - pickerController.sourceType = UIImagePickerControllerSourceTypeCamera; - pickerController.allowsEditing = NO; - if ([pickerController respondsToSelector:@selector(mediaTypes)]) { - // iOS 3.0 - pickerController.mediaTypes = [NSArray arrayWithObjects:(NSString*)kUTTypeImage, nil]; - } - - /*if ([pickerController respondsToSelector:@selector(cameraCaptureMode)]){ - // iOS 4.0 - pickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto; - pickerController.cameraDevice = UIImagePickerControllerCameraDeviceRear; - pickerController.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto; - }*/ - // CDVImagePicker specific property - pickerController.callbackId = callbackId; - - if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) { - [self.viewController presentViewController:pickerController animated:YES completion:nil]; - } else { - [self.viewController presentModalViewController:pickerController animated:YES]; - } - } -} - -/* Process a still image from the camera. - * IN: - * UIImage* image - the UIImage data returned from the camera - * NSString* callbackId - */ -- (CDVPluginResult*)processImage:(UIImage*)image type:(NSString*)mimeType forCallbackId:(NSString*)callbackId -{ - CDVPluginResult* result = nil; - - // save the image to photo album - UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil); - - NSData* data = nil; - if (mimeType && [mimeType isEqualToString:@"image/png"]) { - data = UIImagePNGRepresentation(image); - } else { - data = UIImageJPEGRepresentation(image, 0.5); - } - - // write to temp directory and return URI - NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath]; // use file system temporary directory - NSError* err = nil; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - - // generate unique file name - NSString* filePath; - int i = 1; - do { - filePath = [NSString stringWithFormat:@"%@/photo_%03d.jpg", docsPath, i++]; - } while ([fileMgr fileExistsAtPath:filePath]); - - if (![data writeToFile:filePath options:NSAtomicWrite error:&err]) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageToErrorObject:CAPTURE_INTERNAL_ERR]; - if (err) { - NSLog(@"Error saving image: %@", [err localizedDescription]); - } - } else { - // create MediaFile object - - NSDictionary* fileDict = [self getMediaDictionaryFromPath:filePath ofType:mimeType]; - NSArray* fileArray = [NSArray arrayWithObject:fileDict]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:fileArray]; - } - - return result; -} - -- (void)captureVideo:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* options = [command.arguments objectAtIndex:0]; - - if ([options isKindOfClass:[NSNull class]]) { - options = [NSDictionary dictionary]; - } - - // options could contain limit, duration and mode - // taking more than one video (limit) is only supported if provide own controls via cameraOverlayView property - NSNumber* duration = [options objectForKey:@"duration"]; - NSString* mediaType = nil; - - if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { - // there is a camera, it is available, make sure it can do movies - pickerController = [[CDVImagePicker alloc] init]; - - NSArray* types = nil; - if ([UIImagePickerController respondsToSelector:@selector(availableMediaTypesForSourceType:)]) { - types = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera]; - // NSLog(@"MediaTypes: %@", [types description]); - - if ([types containsObject:(NSString*)kUTTypeMovie]) { - mediaType = (NSString*)kUTTypeMovie; - } else if ([types containsObject:(NSString*)kUTTypeVideo]) { - mediaType = (NSString*)kUTTypeVideo; - } - } - } - if (!mediaType) { - // don't have video camera return error - NSLog(@"Capture.captureVideo: video mode not available."); - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_NOT_SUPPORTED]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - pickerController = nil; - } else { - pickerController.delegate = self; - pickerController.sourceType = UIImagePickerControllerSourceTypeCamera; - pickerController.allowsEditing = NO; - // iOS 3.0 - pickerController.mediaTypes = [NSArray arrayWithObjects:mediaType, nil]; - - if ([mediaType isEqualToString:(NSString*)kUTTypeMovie]){ - if (duration) { - pickerController.videoMaximumDuration = [duration doubleValue]; - } - //NSLog(@"pickerController.videoMaximumDuration = %f", pickerController.videoMaximumDuration); - } - - // iOS 4.0 - if ([pickerController respondsToSelector:@selector(cameraCaptureMode)]) { - pickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo; - // pickerController.videoQuality = UIImagePickerControllerQualityTypeHigh; - // pickerController.cameraDevice = UIImagePickerControllerCameraDeviceRear; - // pickerController.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto; - } - // CDVImagePicker specific property - pickerController.callbackId = callbackId; - - if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) { - [self.viewController presentViewController:pickerController animated:YES completion:nil]; - } else { - [self.viewController presentModalViewController:pickerController animated:YES]; - } - } -} - -- (CDVPluginResult*)processVideo:(NSString*)moviePath forCallbackId:(NSString*)callbackId -{ - // save the movie to photo album (only avail as of iOS 3.1) - - /* don't need, it should automatically get saved - NSLog(@"can save %@: %d ?", moviePath, UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(moviePath)); - if (&UIVideoAtPathIsCompatibleWithSavedPhotosAlbum != NULL && UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(moviePath) == YES) { - NSLog(@"try to save movie"); - UISaveVideoAtPathToSavedPhotosAlbum(moviePath, nil, nil, nil); - NSLog(@"finished saving movie"); - }*/ - // create MediaFile object - NSDictionary* fileDict = [self getMediaDictionaryFromPath:moviePath ofType:nil]; - NSArray* fileArray = [NSArray arrayWithObject:fileDict]; - - return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:fileArray]; -} - -- (void)getMediaModes:(CDVInvokedUrlCommand*)command -{ - // NSString* callbackId = [arguments objectAtIndex:0]; - // NSMutableDictionary* imageModes = nil; - NSArray* imageArray = nil; - NSArray* movieArray = nil; - NSArray* audioArray = nil; - - if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { - // there is a camera, find the modes - // can get image/jpeg or image/png from camera - - /* can't find a way to get the default height and width and other info - * for images/movies taken with UIImagePickerController - */ - NSDictionary* jpg = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt:0], kW3CMediaFormatHeight, - [NSNumber numberWithInt:0], kW3CMediaFormatWidth, - @"image/jpeg", kW3CMediaModeType, - nil]; - NSDictionary* png = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt:0], kW3CMediaFormatHeight, - [NSNumber numberWithInt:0], kW3CMediaFormatWidth, - @"image/png", kW3CMediaModeType, - nil]; - imageArray = [NSArray arrayWithObjects:jpg, png, nil]; - - if ([UIImagePickerController respondsToSelector:@selector(availableMediaTypesForSourceType:)]) { - NSArray* types = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera]; - - if ([types containsObject:(NSString*)kUTTypeMovie]) { - NSDictionary* mov = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt:0], kW3CMediaFormatHeight, - [NSNumber numberWithInt:0], kW3CMediaFormatWidth, - @"video/quicktime", kW3CMediaModeType, - nil]; - movieArray = [NSArray arrayWithObject:mov]; - } - } - } - NSDictionary* modes = [NSDictionary dictionaryWithObjectsAndKeys: - imageArray ? (NSObject*) imageArray:[NSNull null], @"image", - movieArray ? (NSObject*) movieArray:[NSNull null], @"video", - audioArray ? (NSObject*) audioArray:[NSNull null], @"audio", - nil]; - NSString* jsString = [NSString stringWithFormat:@"navigator.device.capture.setSupportedModes(%@);", [modes JSONString]]; - [self.commandDelegate evalJs:jsString]; -} - -- (void)getFormatData:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - // existence of fullPath checked on JS side - NSString* fullPath = [command.arguments objectAtIndex:0]; - // mimeType could be null - NSString* mimeType = nil; - - if ([command.arguments count] > 1) { - mimeType = [command.arguments objectAtIndex:1]; - } - BOOL bError = NO; - CDVCaptureError errorCode = CAPTURE_INTERNAL_ERR; - CDVPluginResult* result = nil; - - if (!mimeType || [mimeType isKindOfClass:[NSNull class]]) { - // try to determine mime type if not provided - id command = [self.commandDelegate getCommandInstance:@"File"]; - bError = !([command isKindOfClass:[CDVFile class]]); - if (!bError) { - CDVFile* cdvFile = (CDVFile*)command; - mimeType = [cdvFile getMimeTypeFromPath:fullPath]; - if (!mimeType) { - // can't do much without mimeType, return error - bError = YES; - errorCode = CAPTURE_INVALID_ARGUMENT; - } - } - } - if (!bError) { - // create and initialize return dictionary - NSMutableDictionary* formatData = [NSMutableDictionary dictionaryWithCapacity:5]; - [formatData setObject:[NSNull null] forKey:kW3CMediaFormatCodecs]; - [formatData setObject:[NSNumber numberWithInt:0] forKey:kW3CMediaFormatBitrate]; - [formatData setObject:[NSNumber numberWithInt:0] forKey:kW3CMediaFormatHeight]; - [formatData setObject:[NSNumber numberWithInt:0] forKey:kW3CMediaFormatWidth]; - [formatData setObject:[NSNumber numberWithInt:0] forKey:kW3CMediaFormatDuration]; - - if ([mimeType rangeOfString:@"image/"].location != NSNotFound) { - UIImage* image = [UIImage imageWithContentsOfFile:fullPath]; - if (image) { - CGSize imgSize = [image size]; - [formatData setObject:[NSNumber numberWithInteger:imgSize.width] forKey:kW3CMediaFormatWidth]; - [formatData setObject:[NSNumber numberWithInteger:imgSize.height] forKey:kW3CMediaFormatHeight]; - } - } else if (([mimeType rangeOfString:@"video/"].location != NSNotFound) && (NSClassFromString(@"AVURLAsset") != nil)) { - NSURL* movieURL = [NSURL fileURLWithPath:fullPath]; - AVURLAsset* movieAsset = [[AVURLAsset alloc] initWithURL:movieURL options:nil]; - CMTime duration = [movieAsset duration]; - [formatData setObject:[NSNumber numberWithFloat:CMTimeGetSeconds(duration)] forKey:kW3CMediaFormatDuration]; - - NSArray* allVideoTracks = [movieAsset tracksWithMediaType:AVMediaTypeVideo]; - if ([allVideoTracks count] > 0) { - AVAssetTrack* track = [[movieAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; - CGSize size = [track naturalSize]; - - [formatData setObject:[NSNumber numberWithFloat:size.height] forKey:kW3CMediaFormatHeight]; - [formatData setObject:[NSNumber numberWithFloat:size.width] forKey:kW3CMediaFormatWidth]; - // not sure how to get codecs or bitrate??? - // AVMetadataItem - // AudioFile - } else { - NSLog(@"No video tracks found for %@", fullPath); - } - } else if ([mimeType rangeOfString:@"audio/"].location != NSNotFound) { - if (NSClassFromString(@"AVAudioPlayer") != nil) { - NSURL* fileURL = [NSURL fileURLWithPath:fullPath]; - NSError* err = nil; - - AVAudioPlayer* avPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&err]; - if (!err) { - // get the data - [formatData setObject:[NSNumber numberWithDouble:[avPlayer duration]] forKey:kW3CMediaFormatDuration]; - if ([avPlayer respondsToSelector:@selector(settings)]) { - NSDictionary* info = [avPlayer settings]; - NSNumber* bitRate = [info objectForKey:AVEncoderBitRateKey]; - if (bitRate) { - [formatData setObject:bitRate forKey:kW3CMediaFormatBitrate]; - } - } - } // else leave data init'ed to 0 - } - } - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:formatData]; - // NSLog(@"getFormatData: %@", [formatData description]); - } - if (bError) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errorCode]; - } - if (result) { - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } -} - -- (NSDictionary*)getMediaDictionaryFromPath:(NSString*)fullPath ofType:(NSString*)type -{ - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - NSMutableDictionary* fileDict = [NSMutableDictionary dictionaryWithCapacity:5]; - - [fileDict setObject:[fullPath lastPathComponent] forKey:@"name"]; - [fileDict setObject:fullPath forKey:@"fullPath"]; - // determine type - if (!type) { - id command = [self.commandDelegate getCommandInstance:@"File"]; - if ([command isKindOfClass:[CDVFile class]]) { - CDVFile* cdvFile = (CDVFile*)command; - NSString* mimeType = [cdvFile getMimeTypeFromPath:fullPath]; - [fileDict setObject:(mimeType != nil ? (NSObject*)mimeType : [NSNull null]) forKey:@"type"]; - } - } - NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:fullPath error:nil]; - [fileDict setObject:[NSNumber numberWithUnsignedLongLong:[fileAttrs fileSize]] forKey:@"size"]; - NSDate* modDate = [fileAttrs fileModificationDate]; - NSNumber* msDate = [NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000]; - [fileDict setObject:msDate forKey:@"lastModifiedDate"]; - - return fileDict; -} - -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo -{ - // older api calls new one - [self imagePickerController:picker didFinishPickingMediaWithInfo:editingInfo]; -} - -/* Called when image/movie is finished recording. - * Calls success or error code as appropriate - * if successful, result contains an array (with just one entry since can only get one image unless build own camera UI) of MediaFile object representing the image - * name - * fullPath - * type - * lastModifiedDate - * size - */ -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info -{ - CDVImagePicker* cameraPicker = (CDVImagePicker*)picker; - NSString* callbackId = cameraPicker.callbackId; - - if ([picker respondsToSelector:@selector(presentingViewController)]) { - [[picker presentingViewController] dismissModalViewControllerAnimated:YES]; - } else { - [[picker parentViewController] dismissModalViewControllerAnimated:YES]; - } - - CDVPluginResult* result = nil; - - UIImage* image = nil; - NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType]; - if (!mediaType || [mediaType isEqualToString:(NSString*)kUTTypeImage]) { - // mediaType is nil then only option is UIImagePickerControllerOriginalImage - if ([UIImagePickerController respondsToSelector:@selector(allowsEditing)] && - (cameraPicker.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage])) { - image = [info objectForKey:UIImagePickerControllerEditedImage]; - } else { - image = [info objectForKey:UIImagePickerControllerOriginalImage]; - } - } - if (image != nil) { - // mediaType was image - result = [self processImage:image type:cameraPicker.mimeType forCallbackId:callbackId]; - } else if ([mediaType isEqualToString:(NSString*)kUTTypeMovie]) { - // process video - NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path]; - if (moviePath) { - result = [self processVideo:moviePath forCallbackId:callbackId]; - } - } - if (!result) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_INTERNAL_ERR]; - } - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - pickerController = nil; -} - -- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker -{ - CDVImagePicker* cameraPicker = (CDVImagePicker*)picker; - NSString* callbackId = cameraPicker.callbackId; - - if ([picker respondsToSelector:@selector(presentingViewController)]) { - [[picker presentingViewController] dismissModalViewControllerAnimated:YES]; - } else { - [[picker parentViewController] dismissModalViewControllerAnimated:YES]; - } - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_NO_MEDIA_FILES]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - pickerController = nil; -} - -@end - -@implementation CDVAudioNavigationController - -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000 - - (NSUInteger)supportedInterfaceOrientations - { - // delegate to CVDAudioRecorderViewController - return [self.topViewController supportedInterfaceOrientations]; - } -#endif - -@end - -@implementation CDVAudioRecorderViewController -@synthesize errorCode, callbackId, duration, captureCommand, doneButton, recordingView, recordButton, recordImage, stopRecordImage, timerLabel, avRecorder, avSession, pluginResult, timer, isTimed; - -- (NSString*)resolveImageResource:(NSString*)resource -{ - NSString* systemVersion = [[UIDevice currentDevice] systemVersion]; - BOOL isLessThaniOS4 = ([systemVersion compare:@"4.0" options:NSNumericSearch] == NSOrderedAscending); - - // the iPad image (nor retina) differentiation code was not in 3.x, and we have to explicitly set the path - // if user wants iPhone only app to run on iPad they must remove *~ipad.* images from capture.bundle - if (isLessThaniOS4) { - NSString* iPadResource = [NSString stringWithFormat:@"%@~ipad.png", resource]; - if (CDV_IsIPad() && [UIImage imageNamed:iPadResource]) { - return iPadResource; - } else { - return [NSString stringWithFormat:@"%@.png", resource]; - } - } - - return resource; -} - -- (id)initWithCommand:(CDVCapture*)theCommand duration:(NSNumber*)theDuration callbackId:(NSString*)theCallbackId -{ - if ((self = [super init])) { - self.captureCommand = theCommand; - self.duration = theDuration; - self.callbackId = theCallbackId; - self.errorCode = CAPTURE_NO_MEDIA_FILES; - self.isTimed = self.duration != nil; - - return self; - } - - return nil; -} - -- (void)loadView -{ - // create view and display - CGRect viewRect = [[UIScreen mainScreen] applicationFrame]; - UIView* tmp = [[UIView alloc] initWithFrame:viewRect]; - - // make backgrounds - NSString* microphoneResource = @"Capture.bundle/microphone"; - - if (CDV_IsIPhone5()) { - microphoneResource = @"Capture.bundle/microphone-568h"; - } - - UIImage* microphone = [UIImage imageNamed:[self resolveImageResource:microphoneResource]]; - UIView* microphoneView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, viewRect.size.width, microphone.size.height)]; - [microphoneView setBackgroundColor:[UIColor colorWithPatternImage:microphone]]; - [microphoneView setUserInteractionEnabled:NO]; - [microphoneView setIsAccessibilityElement:NO]; - [tmp addSubview:microphoneView]; - - // add bottom bar view - UIImage* grayBkg = [UIImage imageNamed:[self resolveImageResource:@"Capture.bundle/controls_bg"]]; - UIView* controls = [[UIView alloc] initWithFrame:CGRectMake(0, microphone.size.height, viewRect.size.width, grayBkg.size.height)]; - [controls setBackgroundColor:[UIColor colorWithPatternImage:grayBkg]]; - [controls setUserInteractionEnabled:NO]; - [controls setIsAccessibilityElement:NO]; - [tmp addSubview:controls]; - - // make red recording background view - UIImage* recordingBkg = [UIImage imageNamed:[self resolveImageResource:@"Capture.bundle/recording_bg"]]; - UIColor* background = [UIColor colorWithPatternImage:recordingBkg]; - self.recordingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, viewRect.size.width, recordingBkg.size.height)]; - [self.recordingView setBackgroundColor:background]; - [self.recordingView setHidden:YES]; - [self.recordingView setUserInteractionEnabled:NO]; - [self.recordingView setIsAccessibilityElement:NO]; - [tmp addSubview:self.recordingView]; - - // add label - self.timerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, viewRect.size.width, recordingBkg.size.height)]; - // timerLabel.autoresizingMask = reSizeMask; - [self.timerLabel setBackgroundColor:[UIColor clearColor]]; - [self.timerLabel setTextColor:[UIColor whiteColor]]; - [self.timerLabel setTextAlignment:UITextAlignmentCenter]; - [self.timerLabel setText:@"0:00"]; - [self.timerLabel setAccessibilityHint:NSLocalizedString(@"recorded time in minutes and seconds", nil)]; - self.timerLabel.accessibilityTraits |= UIAccessibilityTraitUpdatesFrequently; - self.timerLabel.accessibilityTraits &= ~UIAccessibilityTraitStaticText; - [tmp addSubview:self.timerLabel]; - - // Add record button - - self.recordImage = [UIImage imageNamed:[self resolveImageResource:@"Capture.bundle/record_button"]]; - self.stopRecordImage = [UIImage imageNamed:[self resolveImageResource:@"Capture.bundle/stop_button"]]; - self.recordButton.accessibilityTraits |= [self accessibilityTraits]; - self.recordButton = [[UIButton alloc] initWithFrame:CGRectMake((viewRect.size.width - recordImage.size.width) / 2, (microphone.size.height + (grayBkg.size.height - recordImage.size.height) / 2), recordImage.size.width, recordImage.size.height)]; - [self.recordButton setAccessibilityLabel:NSLocalizedString(@"toggle audio recording", nil)]; - [self.recordButton setImage:recordImage forState:UIControlStateNormal]; - [self.recordButton addTarget:self action:@selector(processButton:) forControlEvents:UIControlEventTouchUpInside]; - [tmp addSubview:recordButton]; - - // make and add done button to navigation bar - self.doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismissAudioView:)]; - [self.doneButton setStyle:UIBarButtonItemStyleDone]; - self.navigationItem.rightBarButtonItem = self.doneButton; - - [self setView:tmp]; -} - -- (void)viewDidLoad -{ - [super viewDidLoad]; - UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); - NSError* error = nil; - - if (self.avSession == nil) { - // create audio session - self.avSession = [AVAudioSession sharedInstance]; - if (error) { - // return error if can't create recording audio session - NSLog(@"error creating audio session: %@", [[error userInfo] description]); - self.errorCode = CAPTURE_INTERNAL_ERR; - [self dismissAudioView:nil]; - } - } - - // create file to record to in temporary dir - - NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath]; // use file system temporary directory - NSError* err = nil; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - - // generate unique file name - NSString* filePath; - int i = 1; - do { - filePath = [NSString stringWithFormat:@"%@/audio_%03d.wav", docsPath, i++]; - } while ([fileMgr fileExistsAtPath:filePath]); - - NSURL* fileURL = [NSURL fileURLWithPath:filePath isDirectory:NO]; - - // create AVAudioPlayer - self.avRecorder = [[AVAudioRecorder alloc] initWithURL:fileURL settings:nil error:&err]; - if (err) { - NSLog(@"Failed to initialize AVAudioRecorder: %@\n", [err localizedDescription]); - self.avRecorder = nil; - // return error - self.errorCode = CAPTURE_INTERNAL_ERR; - [self dismissAudioView:nil]; - } else { - self.avRecorder.delegate = self; - [self.avRecorder prepareToRecord]; - self.recordButton.enabled = YES; - self.doneButton.enabled = YES; - } -} - -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000 - - (NSUInteger)supportedInterfaceOrientations - { - NSUInteger orientation = UIInterfaceOrientationMaskPortrait; // must support portrait - NSUInteger supported = [captureCommand.viewController supportedInterfaceOrientations]; - - orientation = orientation | (supported & UIInterfaceOrientationMaskPortraitUpsideDown); - return orientation; - } -#endif - -- (void)viewDidUnload -{ - [self setView:nil]; - [self.captureCommand setInUse:NO]; -} - -- (void)processButton:(id)sender -{ - if (self.avRecorder.recording) { - // stop recording - [self.avRecorder stop]; - self.isTimed = NO; // recording was stopped via button so reset isTimed - // view cleanup will occur in audioRecordingDidFinishRecording - } else { - // begin recording - [self.recordButton setImage:stopRecordImage forState:UIControlStateNormal]; - self.recordButton.accessibilityTraits &= ~[self accessibilityTraits]; - [self.recordingView setHidden:NO]; - NSError* error = nil; - [self.avSession setCategory:AVAudioSessionCategoryRecord error:&error]; - [self.avSession setActive:YES error:&error]; - if (error) { - // can't continue without active audio session - self.errorCode = CAPTURE_INTERNAL_ERR; - [self dismissAudioView:nil]; - } else { - if (self.duration) { - self.isTimed = true; - [self.avRecorder recordForDuration:[duration doubleValue]]; - } else { - [self.avRecorder record]; - } - [self.timerLabel setText:@"0.00"]; - self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:@selector(updateTime) userInfo:nil repeats:YES]; - self.doneButton.enabled = NO; - } - UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil); - } -} - -/* - * helper method to clean up when stop recording - */ -- (void)stopRecordingCleanup -{ - if (self.avRecorder.recording) { - [self.avRecorder stop]; - } - [self.recordButton setImage:recordImage forState:UIControlStateNormal]; - self.recordButton.accessibilityTraits |= [self accessibilityTraits]; - [self.recordingView setHidden:YES]; - self.doneButton.enabled = YES; - if (self.avSession) { - // deactivate session so sounds can come through - [self.avSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; - [self.avSession setActive:NO error:nil]; - } - if (self.duration && self.isTimed) { - // VoiceOver announcement so user knows timed recording has finished - BOOL isUIAccessibilityAnnouncementNotification = (&UIAccessibilityAnnouncementNotification != NULL); - if (isUIAccessibilityAnnouncementNotification) { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 500ull * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{ - UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, NSLocalizedString(@"timed recording complete", nil)); - }); - } - } else { - // issue a layout notification change so that VO will reannounce the button label when recording completes - UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil); - } -} - -- (void)dismissAudioView:(id)sender -{ - // called when done button pressed or when error condition to do cleanup and remove view - if ([self.captureCommand.viewController.modalViewController respondsToSelector:@selector(presentingViewController)]) { - [[self.captureCommand.viewController.modalViewController presentingViewController] dismissModalViewControllerAnimated:YES]; - } else { - [[self.captureCommand.viewController.modalViewController parentViewController] dismissModalViewControllerAnimated:YES]; - } - - if (!self.pluginResult) { - // return error - self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:self.errorCode]; - } - - self.avRecorder = nil; - [self.avSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; - [self.avSession setActive:NO error:nil]; - [self.captureCommand setInUse:NO]; - UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); - // return result - [self.captureCommand.commandDelegate sendPluginResult:pluginResult callbackId:callbackId]; -} - -- (void)updateTime -{ - // update the label with the elapsed time - [self.timerLabel setText:[self formatTime:self.avRecorder.currentTime]]; -} - -- (NSString*)formatTime:(int)interval -{ - // is this format universal? - int secs = interval % 60; - int min = interval / 60; - - if (interval < 60) { - return [NSString stringWithFormat:@"0:%02d", interval]; - } else { - return [NSString stringWithFormat:@"%d:%02d", min, secs]; - } -} - -- (void)audioRecorderDidFinishRecording:(AVAudioRecorder*)recorder successfully:(BOOL)flag -{ - // may be called when timed audio finishes - need to stop time and reset buttons - [self.timer invalidate]; - [self stopRecordingCleanup]; - - // generate success result - if (flag) { - NSString* filePath = [avRecorder.url path]; - // NSLog(@"filePath: %@", filePath); - NSDictionary* fileDict = [captureCommand getMediaDictionaryFromPath:filePath ofType:@"audio/wav"]; - NSArray* fileArray = [NSArray arrayWithObject:fileDict]; - - self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:fileArray]; - } else { - self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageToErrorObject:CAPTURE_INTERNAL_ERR]; - } -} - -- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder*)recorder error:(NSError*)error -{ - [self.timer invalidate]; - [self stopRecordingCleanup]; - - NSLog(@"error recording audio"); - self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageToErrorObject:CAPTURE_INTERNAL_ERR]; - [self dismissAudioView:nil]; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVCommandDelegate.h b/iPhone/CordovaLib/Classes/CDVCommandDelegate.h deleted file mode 100755 index 0401136..0000000 --- a/iPhone/CordovaLib/Classes/CDVCommandDelegate.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVAvailability.h" -#import "CDVInvokedUrlCommand.h" - -@class CDVPlugin; -@class CDVPluginResult; -@class CDVWhitelist; - -@protocol CDVCommandDelegate - -@property (nonatomic, readonly) NSDictionary* settings; - -- (NSString*)pathForResource:(NSString*)resourcepath; -- (id)getCommandInstance:(NSString*)pluginName; - -// Plugins should not be using this interface to call other plugins since it -// will result in bogus callbacks being made. -- (BOOL)execute:(CDVInvokedUrlCommand*)command CDV_DEPRECATED(2.2, "Use direct method calls instead."); - -// Sends a plugin result to the JS. This is thread-safe. -- (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId; -// Evaluates the given JS. This is thread-safe. -- (void)evalJs:(NSString*)js; -// Can be used to evaluate JS right away instead of scheduling it on the run-loop. -// This is required for dispatch resign and pause events, but should not be used -// without reason. Without the run-loop delay, alerts used in JS callbacks may result -// in dead-lock. This method must be called from the UI thread. -- (void)evalJs:(NSString*)js scheduledOnRunLoop:(BOOL)scheduledOnRunLoop; -// Runs the given block on a background thread using a shared thread-pool. -- (void)runInBackground:(void (^)())block; -// Returns the User-Agent of the associated UIWebView. -- (NSString*)userAgent; -// Returns whether the given URL passes the white-list. -- (BOOL)URLIsWhitelisted:(NSURL*)url; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVCommandDelegateImpl.h b/iPhone/CordovaLib/Classes/CDVCommandDelegateImpl.h deleted file mode 100755 index 6735136..0000000 --- a/iPhone/CordovaLib/Classes/CDVCommandDelegateImpl.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import "CDVCommandDelegate.h" - -@class CDVViewController; -@class CDVCommandQueue; - -@interface CDVCommandDelegateImpl : NSObject { - @private - __weak CDVViewController* _viewController; - @protected - __weak CDVCommandQueue* _commandQueue; -} -- (id)initWithViewController:(CDVViewController*)viewController; -@end diff --git a/iPhone/CordovaLib/Classes/CDVCommandDelegateImpl.m b/iPhone/CordovaLib/Classes/CDVCommandDelegateImpl.m deleted file mode 100755 index fa0e5e0..0000000 --- a/iPhone/CordovaLib/Classes/CDVCommandDelegateImpl.m +++ /dev/null @@ -1,145 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVCommandDelegateImpl.h" -#import "CDVJSON.h" -#import "CDVCommandQueue.h" -#import "CDVPluginResult.h" -#import "CDVViewController.h" - -@implementation CDVCommandDelegateImpl - -- (id)initWithViewController:(CDVViewController*)viewController -{ - self = [super init]; - if (self != nil) { - _viewController = viewController; - _commandQueue = _viewController.commandQueue; - } - return self; -} - -- (NSString*)pathForResource:(NSString*)resourcepath -{ - NSBundle* mainBundle = [NSBundle mainBundle]; - NSMutableArray* directoryParts = [NSMutableArray arrayWithArray:[resourcepath componentsSeparatedByString:@"/"]]; - NSString* filename = [directoryParts lastObject]; - - [directoryParts removeLastObject]; - - NSString* directoryPartsJoined = [directoryParts componentsJoinedByString:@"/"]; - NSString* directoryStr = _viewController.wwwFolderName; - - if ([directoryPartsJoined length] > 0) { - directoryStr = [NSString stringWithFormat:@"%@/%@", _viewController.wwwFolderName, [directoryParts componentsJoinedByString:@"/"]]; - } - - return [mainBundle pathForResource:filename ofType:@"" inDirectory:directoryStr]; -} - -- (void)evalJsHelper2:(NSString*)js -{ - CDV_EXEC_LOG(@"Exec: evalling: %@", [js substringToIndex:MIN([js length], 160)]); - NSString* commandsJSON = [_viewController.webView stringByEvaluatingJavaScriptFromString:js]; - if ([commandsJSON length] > 0) { - CDV_EXEC_LOG(@"Exec: Retrieved new exec messages by chaining."); - } - - [_commandQueue enqueCommandBatch:commandsJSON]; -} - -- (void)evalJsHelper:(NSString*)js -{ - // Cycle the run-loop before executing the JS. - // This works around a bug where sometimes alerts() within callbacks can cause - // dead-lock. - // If the commandQueue is currently executing, then we know that it is safe to - // execute the callback immediately. - // Using (dispatch_get_main_queue()) does *not* fix deadlocks for some reaon, - // but performSelectorOnMainThread: does. - if (![NSThread isMainThread] || !_commandQueue.currentlyExecuting) { - [self performSelectorOnMainThread:@selector(evalJsHelper2:) withObject:js waitUntilDone:NO]; - } else { - [self evalJsHelper2:js]; - } -} - -- (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId -{ - CDV_EXEC_LOG(@"Exec(%@): Sending result. Status=%@", callbackId, result.status); - // This occurs when there is are no win/fail callbacks for the call. - if ([@"INVALID" isEqualToString : callbackId]) { - return; - } - int status = [result.status intValue]; - BOOL keepCallback = [result.keepCallback boolValue]; - NSString* argumentsAsJSON = [result argumentsAsJSON]; - - NSString* js = [NSString stringWithFormat:@"cordova.require('cordova/exec').nativeCallback('%@',%d,%@,%d)", callbackId, status, argumentsAsJSON, keepCallback]; - - [self evalJsHelper:js]; -} - -- (void)evalJs:(NSString*)js -{ - [self evalJs:js scheduledOnRunLoop:YES]; -} - -- (void)evalJs:(NSString*)js scheduledOnRunLoop:(BOOL)scheduledOnRunLoop -{ - js = [NSString stringWithFormat:@"cordova.require('cordova/exec').nativeEvalAndFetch(function(){%@})", js]; - if (scheduledOnRunLoop) { - [self evalJsHelper:js]; - } else { - [self evalJsHelper2:js]; - } -} - -- (BOOL)execute:(CDVInvokedUrlCommand*)command -{ - return [_commandQueue execute:command]; -} - -- (id)getCommandInstance:(NSString*)pluginName -{ - return [_viewController getCommandInstance:pluginName]; -} - -- (void)runInBackground:(void (^)())block -{ - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block); -} - -- (NSString*)userAgent -{ - return [_viewController userAgent]; -} - -- (BOOL)URLIsWhitelisted:(NSURL*)url -{ - return ![_viewController.whitelist schemeIsAllowed:[url scheme]] || - [_viewController.whitelist URLIsAllowed:url]; -} - -- (NSDictionary*)settings -{ - return _viewController.settings; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVCommandQueue.h b/iPhone/CordovaLib/Classes/CDVCommandQueue.h deleted file mode 100755 index 27c47b5..0000000 --- a/iPhone/CordovaLib/Classes/CDVCommandQueue.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import - -@class CDVInvokedUrlCommand; -@class CDVViewController; - -@interface CDVCommandQueue : NSObject - -@property (nonatomic, readonly) BOOL currentlyExecuting; - -- (id)initWithViewController:(CDVViewController*)viewController; -- (void)dispose; - -- (void)resetRequestId; -- (void)enqueCommandBatch:(NSString*)batchJSON; - -- (void)maybeFetchCommandsFromJs:(NSNumber*)requestId; -- (void)fetchCommandsFromJs; -- (void)executePending; -- (BOOL)execute:(CDVInvokedUrlCommand*)command; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVCommandQueue.m b/iPhone/CordovaLib/Classes/CDVCommandQueue.m deleted file mode 100755 index 1a0dfa0..0000000 --- a/iPhone/CordovaLib/Classes/CDVCommandQueue.m +++ /dev/null @@ -1,169 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#include -#import "CDV.h" -#import "CDVCommandQueue.h" -#import "CDVViewController.h" -#import "CDVCommandDelegateImpl.h" - -@interface CDVCommandQueue () { - NSInteger _lastCommandQueueFlushRequestId; - __weak CDVViewController* _viewController; - NSMutableArray* _queue; - BOOL _currentlyExecuting; -} -@end - -@implementation CDVCommandQueue - -@synthesize currentlyExecuting = _currentlyExecuting; - -- (id)initWithViewController:(CDVViewController*)viewController -{ - self = [super init]; - if (self != nil) { - _viewController = viewController; - _queue = [[NSMutableArray alloc] init]; - } - return self; -} - -- (void)dispose -{ - // TODO(agrieve): Make this a zeroing weak ref once we drop support for 4.3. - _viewController = nil; -} - -- (void)resetRequestId -{ - _lastCommandQueueFlushRequestId = 0; -} - -- (void)enqueCommandBatch:(NSString*)batchJSON -{ - if ([batchJSON length] > 0) { - [_queue addObject:batchJSON]; - [self executePending]; - } -} - -- (void)maybeFetchCommandsFromJs:(NSNumber*)requestId -{ - // Use the request ID to determine if we've already flushed for this request. - // This is required only because the NSURLProtocol enqueues the same request - // multiple times. - if ([requestId integerValue] > _lastCommandQueueFlushRequestId) { - _lastCommandQueueFlushRequestId = [requestId integerValue]; - [self fetchCommandsFromJs]; - } -} - -- (void)fetchCommandsFromJs -{ - // Grab all the queued commands from the JS side. - NSString* queuedCommandsJSON = [_viewController.webView stringByEvaluatingJavaScriptFromString: - @"cordova.require('cordova/exec').nativeFetchMessages()"]; - - [self enqueCommandBatch:queuedCommandsJSON]; - if ([queuedCommandsJSON length] > 0) { - CDV_EXEC_LOG(@"Exec: Retrieved new exec messages by request."); - } -} - -- (void)executePending -{ - // Make us re-entrant-safe. - if (_currentlyExecuting) { - return; - } - @try { - _currentlyExecuting = YES; - - for (NSUInteger i = 0; i < [_queue count]; ++i) { - // Parse the returned JSON array. - NSArray* commandBatch = [[_queue objectAtIndex:i] JSONObject]; - - // Iterate over and execute all of the commands. - for (NSArray* jsonEntry in commandBatch) { - CDVInvokedUrlCommand* command = [CDVInvokedUrlCommand commandFromJson:jsonEntry]; - CDV_EXEC_LOG(@"Exec(%@): Calling %@.%@", command.callbackId, command.className, command.methodName); - - if (![self execute:command]) { -#ifdef DEBUG - NSString* commandJson = [jsonEntry JSONString]; - static NSUInteger maxLogLength = 1024; - NSString* commandString = ([commandJson length] > maxLogLength) ? - [NSString stringWithFormat:@"%@[...]", [commandJson substringToIndex:maxLogLength]] : - commandJson; - - DLog(@"FAILED pluginJSON = %@", commandString); -#endif - } - } - } - - [_queue removeAllObjects]; - } @finally - { - _currentlyExecuting = NO; - } -} - -- (BOOL)execute:(CDVInvokedUrlCommand*)command -{ - if ((command.className == nil) || (command.methodName == nil)) { - NSLog(@"ERROR: Classname and/or methodName not found for command."); - return NO; - } - - // Fetch an instance of this class - CDVPlugin* obj = [_viewController.commandDelegate getCommandInstance:command.className]; - - if (!([obj isKindOfClass:[CDVPlugin class]])) { - NSLog(@"ERROR: Plugin '%@' not found, or is not a CDVPlugin. Check your plugin mapping in config.xml.", command.className); - return NO; - } - BOOL retVal = YES; - - // Find the proper selector to call. - NSString* methodName = [NSString stringWithFormat:@"%@:", command.methodName]; - NSString* methodNameWithDict = [NSString stringWithFormat:@"%@:withDict:", command.methodName]; - SEL normalSelector = NSSelectorFromString(methodName); - SEL legacySelector = NSSelectorFromString(methodNameWithDict); - // Test for the legacy selector first in case they both exist. - if ([obj respondsToSelector:legacySelector]) { - NSMutableArray* arguments = nil; - NSMutableDictionary* dict = nil; - [command legacyArguments:&arguments andDict:&dict]; - // [obj performSelector:legacySelector withObject:arguments withObject:dict]; - objc_msgSend(obj, legacySelector, arguments, dict); - } else if ([obj respondsToSelector:normalSelector]) { - // [obj performSelector:normalSelector withObject:command]; - objc_msgSend(obj, normalSelector, command); - } else { - // There's no method to call, so throw an error. - NSLog(@"ERROR: Method '%@' not defined in Plugin '%@'", methodName, command.className); - retVal = NO; - } - - return retVal; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVConfigParser.h b/iPhone/CordovaLib/Classes/CDVConfigParser.h deleted file mode 100755 index 2e06c88..0000000 --- a/iPhone/CordovaLib/Classes/CDVConfigParser.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -@interface CDVConfigParser : NSObject -{ - NSString* featureName; -} - -@property (nonatomic, readonly, strong) NSMutableDictionary* pluginsDict; -@property (nonatomic, readonly, strong) NSMutableDictionary* settings; -@property (nonatomic, readonly, strong) NSMutableArray* whitelistHosts; -@property (nonatomic, readonly, strong) NSMutableArray* startupPluginNames; -@property (nonatomic, readonly, strong) NSString* startPage; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVConfigParser.m b/iPhone/CordovaLib/Classes/CDVConfigParser.m deleted file mode 100755 index 55b25e6..0000000 --- a/iPhone/CordovaLib/Classes/CDVConfigParser.m +++ /dev/null @@ -1,96 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVConfigParser.h" - -@interface CDVConfigParser () - -@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginsDict; -@property (nonatomic, readwrite, strong) NSMutableDictionary* settings; -@property (nonatomic, readwrite, strong) NSMutableArray* whitelistHosts; -@property (nonatomic, readwrite, strong) NSMutableArray* startupPluginNames; -@property (nonatomic, readwrite, strong) NSString* startPage; - -@end - -@implementation CDVConfigParser - -@synthesize pluginsDict, settings, whitelistHosts, startPage, startupPluginNames; - -- (id)init -{ - self = [super init]; - if (self != nil) { - self.pluginsDict = [[NSMutableDictionary alloc] initWithCapacity:30]; - self.settings = [[NSMutableDictionary alloc] initWithCapacity:30]; - self.whitelistHosts = [[NSMutableArray alloc] initWithCapacity:30]; - self.startupPluginNames = [[NSMutableArray alloc] initWithCapacity:8]; - featureName = nil; - } - return self; -} - -- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributeDict -{ - if ([elementName isEqualToString:@"preference"]) { - settings[attributeDict[@"name"]] = attributeDict[@"value"]; - } else if ([elementName isEqualToString:@"plugin"]) { - NSString* name = [attributeDict[@"name"] lowercaseString]; - pluginsDict[name] = attributeDict[@"value"]; - if ([@"true" isEqualToString : attributeDict[@"onload"]]) { - [self.startupPluginNames addObject:name]; - } - NSLog(@"\nUse of the tag has been deprecated. Use a tag instead. Change:\n" - @" \n" - @"To:\n" - @" \n" - @" \n" - @" \n" - , attributeDict[@"name"], attributeDict[@"value"], attributeDict[@"name"], attributeDict[@"value"]); - } else if ([elementName isEqualToString:@"feature"]) { // store feature name to use with correct parameter set - featureName = [attributeDict[@"name"] lowercaseString]; - } else if ((featureName != nil) && [elementName isEqualToString:@"param"]) { - NSString* paramName = [attributeDict[@"name"] lowercaseString]; - id value = attributeDict[@"value"]; - if ([paramName isEqualToString:@"ios-package"]) { - pluginsDict[featureName] = value; - } - if ([paramName isEqualToString:@"onload"] && [@"true" isEqualToString : value]) { - [self.startupPluginNames addObject:featureName]; - } - } else if ([elementName isEqualToString:@"access"]) { - [whitelistHosts addObject:attributeDict[@"origin"]]; - } else if ([elementName isEqualToString:@"content"]) { - self.startPage = attributeDict[@"src"]; - } -} - -- (void)parser:(NSXMLParser*)parser didEndElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName -{ - if ([elementName isEqualToString:@"feature"]) { // no longer handling a feature so release - featureName = nil; - } -} - -- (void)parser:(NSXMLParser*)parser parseErrorOccurred:(NSError*)parseError -{ - NSAssert(NO, @"config.xml parse error line %d col %d", [parser lineNumber], [parser columnNumber]); -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVConnection.h b/iPhone/CordovaLib/Classes/CDVConnection.h deleted file mode 100755 index d3e8c5d..0000000 --- a/iPhone/CordovaLib/Classes/CDVConnection.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import "CDVPlugin.h" -#import "CDVReachability.h" - -@interface CDVConnection : CDVPlugin { - NSString* type; - NSString* _callbackId; - - CDVReachability* internetReach; -} - -@property (copy) NSString* connectionType; -@property (strong) CDVReachability* internetReach; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVConnection.m b/iPhone/CordovaLib/Classes/CDVConnection.m deleted file mode 100755 index b3f5cab..0000000 --- a/iPhone/CordovaLib/Classes/CDVConnection.m +++ /dev/null @@ -1,132 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVConnection.h" -#import "CDVReachability.h" - -@interface CDVConnection (PrivateMethods) -- (void)updateOnlineStatus; -- (void)sendPluginResult; -@end - -@implementation CDVConnection - -@synthesize connectionType, internetReach; - -- (void)getConnectionInfo:(CDVInvokedUrlCommand*)command -{ - _callbackId = command.callbackId; - [self sendPluginResult]; -} - -- (void)sendPluginResult -{ - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:self.connectionType]; - - [result setKeepCallbackAsBool:YES]; - [self.commandDelegate sendPluginResult:result callbackId:_callbackId]; -} - -- (NSString*)w3cConnectionTypeFor:(CDVReachability*)reachability -{ - NetworkStatus networkStatus = [reachability currentReachabilityStatus]; - - switch (networkStatus) { - case NotReachable: - return @"none"; - - case ReachableViaWWAN: - // Return value of '2g' is deprecated as of 2.6.0 and will be replaced with 'cellular' in 3.0.0 - return @"2g"; - - case ReachableViaWiFi: - return @"wifi"; - - default: - return @"unknown"; - } -} - -- (BOOL)isCellularConnection:(NSString*)theConnectionType -{ - return [theConnectionType isEqualToString:@"2g"] || - [theConnectionType isEqualToString:@"3g"] || - [theConnectionType isEqualToString:@"4g"] || - [theConnectionType isEqualToString:@"cellular"]; -} - -- (void)updateReachability:(CDVReachability*)reachability -{ - if (reachability) { - // check whether the connection type has changed - NSString* newConnectionType = [self w3cConnectionTypeFor:reachability]; - if ([newConnectionType isEqualToString:self.connectionType]) { // the same as before, remove dupes - return; - } else { - self.connectionType = [self w3cConnectionTypeFor:reachability]; - } - } - [self sendPluginResult]; -} - -- (void)updateConnectionType:(NSNotification*)note -{ - CDVReachability* curReach = [note object]; - - if ((curReach != nil) && [curReach isKindOfClass:[CDVReachability class]]) { - [self updateReachability:curReach]; - } -} - -- (void)onPause -{ - [self.internetReach stopNotifier]; -} - -- (void)onResume -{ - [self.internetReach startNotifier]; - [self updateReachability:self.internetReach]; -} - -- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView -{ - self = [super initWithWebView:theWebView]; - if (self) { - self.connectionType = @"none"; - self.internetReach = [CDVReachability reachabilityForInternetConnection]; - self.connectionType = [self w3cConnectionTypeFor:self.internetReach]; - [self.internetReach startNotifier]; - [self printDeprecationNotice]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateConnectionType:) - name:kReachabilityChangedNotification object:nil]; - if (&UIApplicationDidEnterBackgroundNotification && &UIApplicationWillEnterForegroundNotification) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPause) name:UIApplicationDidEnterBackgroundNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume) name:UIApplicationWillEnterForegroundNotification object:nil]; - } - } - return self; -} - -- (void)printDeprecationNotice -{ - NSLog(@"DEPRECATION NOTICE: The Connection ReachableViaWWAN return value of '2g' is deprecated as of Cordova version 2.6.0 and will be changed to 'cellular' in a future release. "); -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVContact.h b/iPhone/CordovaLib/Classes/CDVContact.h deleted file mode 100755 index 5187efc..0000000 --- a/iPhone/CordovaLib/Classes/CDVContact.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import -#import - -enum CDVContactError { - UNKNOWN_ERROR = 0, - INVALID_ARGUMENT_ERROR = 1, - TIMEOUT_ERROR = 2, - PENDING_OPERATION_ERROR = 3, - IO_ERROR = 4, - NOT_SUPPORTED_ERROR = 5, - PERMISSION_DENIED_ERROR = 20 -}; -typedef NSUInteger CDVContactError; - -@interface CDVContact : NSObject { - ABRecordRef record; // the ABRecord associated with this contact - NSDictionary* returnFields; // dictionary of fields to return when performing search -} - -@property (nonatomic, assign) ABRecordRef record; -@property (nonatomic, strong) NSDictionary* returnFields; - -+ (NSDictionary*)defaultABtoW3C; -+ (NSDictionary*)defaultW3CtoAB; -+ (NSSet*)defaultW3CtoNull; -+ (NSDictionary*)defaultObjectAndProperties; -+ (NSDictionary*)defaultFields; - -+ (NSDictionary*)calcReturnFields:(NSArray*)fields; -- (id)init; -- (id)initFromABRecord:(ABRecordRef)aRecord; -- (bool)setFromContactDict:(NSDictionary*)aContact asUpdate:(BOOL)bUpdate; - -+ (BOOL)needsConversion:(NSString*)W3Label; -+ (CFStringRef)convertContactTypeToPropertyLabel:(NSString*)label; -+ (NSString*)convertPropertyLabelToContactType:(NSString*)label; -+ (BOOL)isValidW3ContactType:(NSString*)label; -- (bool)setValue:(id)aValue forProperty:(ABPropertyID)aProperty inRecord:(ABRecordRef)aRecord asUpdate:(BOOL)bUpdate; - -- (NSDictionary*)toDictionary:(NSDictionary*)withFields; -- (NSNumber*)getDateAsNumber:(ABPropertyID)datePropId; -- (NSObject*)extractName; -- (NSObject*)extractMultiValue:(NSString*)propertyId; -- (NSObject*)extractAddresses; -- (NSObject*)extractIms; -- (NSObject*)extractOrganizations; -- (NSObject*)extractPhotos; - -- (NSMutableDictionary*)translateW3Dict:(NSDictionary*)dict forProperty:(ABPropertyID)prop; -- (bool)setMultiValueStrings:(NSArray*)fieldArray forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person asUpdate:(BOOL)bUpdate; -- (bool)setMultiValueDictionary:(NSArray*)array forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person asUpdate:(BOOL)bUpdate; -- (ABMultiValueRef)allocStringMultiValueFromArray:array; -- (ABMultiValueRef)allocDictMultiValueFromArray:array forProperty:(ABPropertyID)prop; -- (BOOL)foundValue:(NSString*)testValue inFields:(NSDictionary*)searchFields; -- (BOOL)testStringValue:(NSString*)testValue forW3CProperty:(NSString*)property; -- (BOOL)testDateValue:(NSString*)testValue forW3CProperty:(NSString*)property; -- (BOOL)searchContactFields:(NSArray*)fields forMVStringProperty:(ABPropertyID)propId withValue:testValue; -- (BOOL)testMultiValueStrings:(NSString*)testValue forProperty:(ABPropertyID)propId ofType:(NSString*)type; -- (NSArray*)valuesForProperty:(ABPropertyID)propId inRecord:(ABRecordRef)aRecord; -- (NSArray*)labelsForProperty:(ABPropertyID)propId inRecord:(ABRecordRef)aRecord; -- (BOOL)searchContactFields:(NSArray*)fields forMVDictionaryProperty:(ABPropertyID)propId withValue:(NSString*)testValue; - -@end - -// generic ContactField types -#define kW3ContactFieldType @"type" -#define kW3ContactFieldValue @"value" -#define kW3ContactFieldPrimary @"pref" -// Various labels for ContactField types -#define kW3ContactWorkLabel @"work" -#define kW3ContactHomeLabel @"home" -#define kW3ContactOtherLabel @"other" -#define kW3ContactPhoneFaxLabel @"fax" -#define kW3ContactPhoneMobileLabel @"mobile" -#define kW3ContactPhonePagerLabel @"pager" -#define kW3ContactUrlBlog @"blog" -#define kW3ContactUrlProfile @"profile" -#define kW3ContactImAIMLabel @"aim" -#define kW3ContactImICQLabel @"icq" -#define kW3ContactImMSNLabel @"msn" -#define kW3ContactImYahooLabel @"yahoo" -#define kW3ContactFieldId @"id" -// special translation for IM field value and type -#define kW3ContactImType @"type" -#define kW3ContactImValue @"value" - -// Contact object -#define kW3ContactId @"id" -#define kW3ContactName @"name" -#define kW3ContactFormattedName @"formatted" -#define kW3ContactGivenName @"givenName" -#define kW3ContactFamilyName @"familyName" -#define kW3ContactMiddleName @"middleName" -#define kW3ContactHonorificPrefix @"honorificPrefix" -#define kW3ContactHonorificSuffix @"honorificSuffix" -#define kW3ContactDisplayName @"displayName" -#define kW3ContactNickname @"nickname" -#define kW3ContactPhoneNumbers @"phoneNumbers" -#define kW3ContactAddresses @"addresses" -#define kW3ContactAddressFormatted @"formatted" -#define kW3ContactStreetAddress @"streetAddress" -#define kW3ContactLocality @"locality" -#define kW3ContactRegion @"region" -#define kW3ContactPostalCode @"postalCode" -#define kW3ContactCountry @"country" -#define kW3ContactEmails @"emails" -#define kW3ContactIms @"ims" -#define kW3ContactOrganizations @"organizations" -#define kW3ContactOrganizationName @"name" -#define kW3ContactTitle @"title" -#define kW3ContactDepartment @"department" -#define kW3ContactBirthday @"birthday" -#define kW3ContactNote @"note" -#define kW3ContactPhotos @"photos" -#define kW3ContactCategories @"categories" -#define kW3ContactUrls @"urls" diff --git a/iPhone/CordovaLib/Classes/CDVContact.m b/iPhone/CordovaLib/Classes/CDVContact.m deleted file mode 100755 index 3844525..0000000 --- a/iPhone/CordovaLib/Classes/CDVContact.m +++ /dev/null @@ -1,1752 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVContact.h" -#import "NSDictionary+Extensions.h" - -#define DATE_OR_NULL(dateObj) ((aDate != nil) ? (id)([aDate descriptionWithLocale:[NSLocale currentLocale]]) : (id)([NSNull null])) -#define IS_VALID_VALUE(value) ((value != nil) && (![value isKindOfClass:[NSNull class]])) - -static NSDictionary* org_apache_cordova_contacts_W3CtoAB = nil; -static NSDictionary* org_apache_cordova_contacts_ABtoW3C = nil; -static NSSet* org_apache_cordova_contacts_W3CtoNull = nil; -static NSDictionary* org_apache_cordova_contacts_objectAndProperties = nil; -static NSDictionary* org_apache_cordova_contacts_defaultFields = nil; - -@implementation CDVContact : NSObject - - @synthesize returnFields; - -- (id)init -{ - if ((self = [super init]) != nil) { - ABRecordRef rec = ABPersonCreate(); - self.record = rec; - if (rec) { - CFRelease(rec); - } - } - return self; -} - -- (id)initFromABRecord:(ABRecordRef)aRecord -{ - if ((self = [super init]) != nil) { - self.record = aRecord; - } - return self; -} - -/* synthesize 'record' ourselves to have retain properties for CF types */ - -- (void)setRecord:(ABRecordRef)aRecord -{ - if (record != NULL) { - CFRelease(record); - } - if (aRecord != NULL) { - record = CFRetain(aRecord); - } -} - -- (ABRecordRef)record -{ - return record; -} - -/* Rather than creating getters and setters for each AddressBook (AB) Property, generic methods are used to deal with - * simple properties, MultiValue properties( phone numbers and emails) and MultiValueDictionary properties (Ims and addresses). - * The dictionaries below are used to translate between the W3C identifiers and the AB properties. Using the dictionaries, - * allows looping through sets of properties to extract from or set into the W3C dictionary to/from the ABRecord. - */ - -/* The two following dictionaries translate between W3C properties and AB properties. It currently mixes both - * Properties (kABPersonAddressProperty for example) and Strings (kABPersonAddressStreetKey) so users should be aware of - * what types of values are expected. - * a bit. -*/ -+ (NSDictionary*)defaultABtoW3C -{ - if (org_apache_cordova_contacts_ABtoW3C == nil) { - org_apache_cordova_contacts_ABtoW3C = [NSDictionary dictionaryWithObjectsAndKeys: - kW3ContactNickname, [NSNumber numberWithInt:kABPersonNicknameProperty], - kW3ContactGivenName, [NSNumber numberWithInt:kABPersonFirstNameProperty], - kW3ContactFamilyName, [NSNumber numberWithInt:kABPersonLastNameProperty], - kW3ContactMiddleName, [NSNumber numberWithInt:kABPersonMiddleNameProperty], - kW3ContactHonorificPrefix, [NSNumber numberWithInt:kABPersonPrefixProperty], - kW3ContactHonorificSuffix, [NSNumber numberWithInt:kABPersonSuffixProperty], - kW3ContactPhoneNumbers, [NSNumber numberWithInt:kABPersonPhoneProperty], - kW3ContactAddresses, [NSNumber numberWithInt:kABPersonAddressProperty], - kW3ContactStreetAddress, kABPersonAddressStreetKey, - kW3ContactLocality, kABPersonAddressCityKey, - kW3ContactRegion, kABPersonAddressStateKey, - kW3ContactPostalCode, kABPersonAddressZIPKey, - kW3ContactCountry, kABPersonAddressCountryKey, - kW3ContactEmails, [NSNumber numberWithInt:kABPersonEmailProperty], - kW3ContactIms, [NSNumber numberWithInt:kABPersonInstantMessageProperty], - kW3ContactOrganizations, [NSNumber numberWithInt:kABPersonOrganizationProperty], - kW3ContactOrganizationName, [NSNumber numberWithInt:kABPersonOrganizationProperty], - kW3ContactTitle, [NSNumber numberWithInt:kABPersonJobTitleProperty], - kW3ContactDepartment, [NSNumber numberWithInt:kABPersonDepartmentProperty], - kW3ContactBirthday, [NSNumber numberWithInt:kABPersonBirthdayProperty], - kW3ContactUrls, [NSNumber numberWithInt:kABPersonURLProperty], - kW3ContactNote, [NSNumber numberWithInt:kABPersonNoteProperty], - nil]; - } - - return org_apache_cordova_contacts_ABtoW3C; -} - -+ (NSDictionary*)defaultW3CtoAB -{ - if (org_apache_cordova_contacts_W3CtoAB == nil) { - org_apache_cordova_contacts_W3CtoAB = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt:kABPersonNicknameProperty], kW3ContactNickname, - [NSNumber numberWithInt:kABPersonFirstNameProperty], kW3ContactGivenName, - [NSNumber numberWithInt:kABPersonLastNameProperty], kW3ContactFamilyName, - [NSNumber numberWithInt:kABPersonMiddleNameProperty], kW3ContactMiddleName, - [NSNumber numberWithInt:kABPersonPrefixProperty], kW3ContactHonorificPrefix, - [NSNumber numberWithInt:kABPersonSuffixProperty], kW3ContactHonorificSuffix, - [NSNumber numberWithInt:kABPersonPhoneProperty], kW3ContactPhoneNumbers, - [NSNumber numberWithInt:kABPersonAddressProperty], kW3ContactAddresses, - kABPersonAddressStreetKey, kW3ContactStreetAddress, - kABPersonAddressCityKey, kW3ContactLocality, - kABPersonAddressStateKey, kW3ContactRegion, - kABPersonAddressZIPKey, kW3ContactPostalCode, - kABPersonAddressCountryKey, kW3ContactCountry, - [NSNumber numberWithInt:kABPersonEmailProperty], kW3ContactEmails, - [NSNumber numberWithInt:kABPersonInstantMessageProperty], kW3ContactIms, - [NSNumber numberWithInt:kABPersonOrganizationProperty], kW3ContactOrganizations, - [NSNumber numberWithInt:kABPersonJobTitleProperty], kW3ContactTitle, - [NSNumber numberWithInt:kABPersonDepartmentProperty], kW3ContactDepartment, - [NSNumber numberWithInt:kABPersonBirthdayProperty], kW3ContactBirthday, - [NSNumber numberWithInt:kABPersonNoteProperty], kW3ContactNote, - [NSNumber numberWithInt:kABPersonURLProperty], kW3ContactUrls, - kABPersonInstantMessageUsernameKey, kW3ContactImValue, - kABPersonInstantMessageServiceKey, kW3ContactImType, - [NSNull null], kW3ContactFieldType, /* include entries in dictionary to indicate ContactField properties */ - [NSNull null], kW3ContactFieldValue, - [NSNull null], kW3ContactFieldPrimary, - [NSNull null], kW3ContactFieldId, - [NSNumber numberWithInt:kABPersonOrganizationProperty], kW3ContactOrganizationName, /* careful, name is used multiple times*/ - nil]; - } - return org_apache_cordova_contacts_W3CtoAB; -} - -+ (NSSet*)defaultW3CtoNull -{ - // these are values that have no AddressBook Equivalent OR have not been implemented yet - if (org_apache_cordova_contacts_W3CtoNull == nil) { - org_apache_cordova_contacts_W3CtoNull = [NSSet setWithObjects:kW3ContactDisplayName, - kW3ContactCategories, kW3ContactFormattedName, nil]; - } - return org_apache_cordova_contacts_W3CtoNull; -} - -/* - * The objectAndProperties dictionary contains the all of the properties of the W3C Contact Objects specified by the key - * Used in calcReturnFields, and various extract methods - */ -+ (NSDictionary*)defaultObjectAndProperties -{ - if (org_apache_cordova_contacts_objectAndProperties == nil) { - org_apache_cordova_contacts_objectAndProperties = [NSDictionary dictionaryWithObjectsAndKeys: - [NSArray arrayWithObjects:kW3ContactGivenName, kW3ContactFamilyName, - kW3ContactMiddleName, kW3ContactHonorificPrefix, kW3ContactHonorificSuffix, kW3ContactFormattedName, nil], kW3ContactName, - [NSArray arrayWithObjects:kW3ContactStreetAddress, kW3ContactLocality, kW3ContactRegion, - kW3ContactPostalCode, kW3ContactCountry, /*kW3ContactAddressFormatted,*/ nil], kW3ContactAddresses, - [NSArray arrayWithObjects:kW3ContactOrganizationName, kW3ContactTitle, kW3ContactDepartment, nil], kW3ContactOrganizations, - [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary, nil], kW3ContactPhoneNumbers, - [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary, nil], kW3ContactEmails, - [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary, nil], kW3ContactPhotos, - [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary, nil], kW3ContactUrls, - [NSArray arrayWithObjects:kW3ContactImValue, kW3ContactImType, nil], kW3ContactIms, - nil]; - } - return org_apache_cordova_contacts_objectAndProperties; -} - -+ (NSDictionary*)defaultFields -{ - if (org_apache_cordova_contacts_defaultFields == nil) { - org_apache_cordova_contacts_defaultFields = [NSDictionary dictionaryWithObjectsAndKeys: - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactName], kW3ContactName, - [NSNull null], kW3ContactNickname, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactAddresses], kW3ContactAddresses, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactOrganizations], kW3ContactOrganizations, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactPhoneNumbers], kW3ContactPhoneNumbers, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactEmails], kW3ContactEmails, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactIms], kW3ContactIms, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactPhotos], kW3ContactPhotos, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactUrls], kW3ContactUrls, - [NSNull null], kW3ContactBirthday, - [NSNull null], kW3ContactNote, - nil]; - } - return org_apache_cordova_contacts_defaultFields; -} - -/* Translate W3C Contact data into ABRecordRef - * - * New contact information comes in as a NSMutableDictionary. All Null entries in Contact object are set - * as [NSNull null] in the dictionary when translating from the JSON input string of Contact data. However, if - * user did not set a value within a Contact object or sub-object (by not using the object constructor) some data - * may not exist. - * bUpdate = YES indicates this is a save of an existing record - */ -- (bool)setFromContactDict:(NSDictionary*)aContact asUpdate:(BOOL)bUpdate -{ - if (![aContact isKindOfClass:[NSDictionary class]]) { - return FALSE; // can't do anything if no dictionary! - } - - ABRecordRef person = self.record; - bool bSuccess = TRUE; - CFErrorRef error; - - // set name info - // iOS doesn't have displayName - might have to pull parts from it to create name - bool bName = false; - NSDictionary* dict = [aContact valueForKey:kW3ContactName]; - if ([dict isKindOfClass:[NSDictionary class]]) { - bName = true; - NSArray* propArray = [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactName]; - - for (id i in propArray) { - if (![(NSString*)i isEqualToString : kW3ContactFormattedName]) { // kW3ContactFormattedName is generated from ABRecordCopyCompositeName() and can't be set - [self setValue:[dict valueForKey:i] forProperty:(ABPropertyID)[(NSNumber*)[[CDVContact defaultW3CtoAB] objectForKey:i] intValue] - inRecord:person asUpdate:bUpdate]; - } - } - } - - id nn = [aContact valueForKey:kW3ContactNickname]; - if (![nn isKindOfClass:[NSNull class]]) { - bName = true; - [self setValue:nn forProperty:kABPersonNicknameProperty inRecord:person asUpdate:bUpdate]; - } - if (!bName) { - // if no name or nickname - try and use displayName as W3Contact must have displayName or ContactName - [self setValue:[aContact valueForKey:kW3ContactDisplayName] forProperty:kABPersonNicknameProperty - inRecord:person asUpdate:bUpdate]; - } - - // set phoneNumbers - // NSLog(@"setting phoneNumbers"); - NSArray* array = [aContact valueForKey:kW3ContactPhoneNumbers]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueStrings:array forProperty:kABPersonPhoneProperty inRecord:person asUpdate:bUpdate]; - } - // set Emails - // NSLog(@"setting emails"); - array = [aContact valueForKey:kW3ContactEmails]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueStrings:array forProperty:kABPersonEmailProperty inRecord:person asUpdate:bUpdate]; - } - // set Urls - // NSLog(@"setting urls"); - array = [aContact valueForKey:kW3ContactUrls]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueStrings:array forProperty:kABPersonURLProperty inRecord:person asUpdate:bUpdate]; - } - - // set multivalue dictionary properties - // set addresses: streetAddress, locality, region, postalCode, country - // set ims: value = username, type = servicetype - // iOS addresses and im are a MultiValue Properties with label, value=dictionary of info, and id - // NSLog(@"setting addresses"); - error = nil; - array = [aContact valueForKey:kW3ContactAddresses]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueDictionary:array forProperty:kABPersonAddressProperty inRecord:person asUpdate:bUpdate]; - } - // ims - // NSLog(@"setting ims"); - array = [aContact valueForKey:kW3ContactIms]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueDictionary:array forProperty:kABPersonInstantMessageProperty inRecord:person asUpdate:bUpdate]; - } - - // organizations - // W3C ContactOrganization has pref, type, name, title, department - // iOS only supports name, title, department - // NSLog(@"setting organizations"); - // TODO this may need work - should Organization information be removed when array is empty?? - array = [aContact valueForKey:kW3ContactOrganizations]; // iOS only supports one organization - use first one - if ([array isKindOfClass:[NSArray class]]) { - BOOL bRemove = NO; - NSDictionary* dict = nil; - if ([array count] > 0) { - dict = [array objectAtIndex:0]; - } else { - // remove the organization info entirely - bRemove = YES; - } - if ([dict isKindOfClass:[NSDictionary class]] || (bRemove == YES)) { - [self setValue:(bRemove ? @"" : [dict valueForKey:@"name"]) forProperty:kABPersonOrganizationProperty inRecord:person asUpdate:bUpdate]; - [self setValue:(bRemove ? @"" : [dict valueForKey:kW3ContactTitle]) forProperty:kABPersonJobTitleProperty inRecord:person asUpdate:bUpdate]; - [self setValue:(bRemove ? @"" : [dict valueForKey:kW3ContactDepartment]) forProperty:kABPersonDepartmentProperty inRecord:person asUpdate:bUpdate]; - } - } - // add dates - // Dates come in as milliseconds in NSNumber Object - id ms = [aContact valueForKey:kW3ContactBirthday]; - NSDate* aDate = nil; - if (ms && [ms isKindOfClass:[NSNumber class]]) { - double msValue = [ms doubleValue]; - msValue = msValue / 1000; - aDate = [NSDate dateWithTimeIntervalSince1970:msValue]; - } - if ((aDate != nil) || [ms isKindOfClass:[NSString class]]) { - [self setValue:aDate != nil ? aDate:ms forProperty:kABPersonBirthdayProperty inRecord:person asUpdate:bUpdate]; - } - // don't update creation date - // modification date will get updated when save - // anniversary is removed from W3C Contact api Dec 9, 2010 spec - don't waste time on it yet - - // kABPersonDateProperty - - // kABPersonAnniversaryLabel - - // iOS doesn't have gender - ignore - // note - [self setValue:[aContact valueForKey:kW3ContactNote] forProperty:kABPersonNoteProperty inRecord:person asUpdate:bUpdate]; - - // iOS doesn't have preferredName- ignore - - // photo - array = [aContact valueForKey:kW3ContactPhotos]; - if ([array isKindOfClass:[NSArray class]]) { - if (bUpdate && ([array count] == 0)) { - // remove photo - bSuccess = ABPersonRemoveImageData(person, &error); - } else if ([array count] > 0) { - NSDictionary* dict = [array objectAtIndex:0]; // currently only support one photo - if ([dict isKindOfClass:[NSDictionary class]]) { - id value = [dict objectForKey:kW3ContactFieldValue]; - if ([value isKindOfClass:[NSString class]]) { - if (bUpdate && ([value length] == 0)) { - // remove the current image - bSuccess = ABPersonRemoveImageData(person, &error); - } else { - // use this image - // don't know if string is encoded or not so first unencode it then encode it again - NSString* cleanPath = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSURL* photoUrl = [NSURL URLWithString:[cleanPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; - // caller is responsible for checking for a connection, if no connection this will fail - NSError* err = nil; - NSData* data = nil; - if (photoUrl) { - data = [NSData dataWithContentsOfURL:photoUrl options:NSDataReadingUncached error:&err]; - } - if (data && ([data length] > 0)) { - bSuccess = ABPersonSetImageData(person, (__bridge CFDataRef)data, &error); - } - if (!data || !bSuccess) { - NSLog(@"error setting contact image: %@", (err != nil ? [err localizedDescription] : @"")); - } - } - } - } - } - } - - // TODO WebURLs - - // TODO timezone - - return bSuccess; -} - -/* Set item into an AddressBook Record for the specified property. - * aValue - the value to set into the address book (code checks for null or [NSNull null] - * aProperty - AddressBook property ID - * aRecord - the record to update - * bUpdate - whether this is a possible update vs a new entry - * RETURN - * true - property was set (or input value as null) - * false - property was not set - */ -- (bool)setValue:(id)aValue forProperty:(ABPropertyID)aProperty inRecord:(ABRecordRef)aRecord asUpdate:(BOOL)bUpdate -{ - bool bSuccess = true; // if property was null, just ignore and return success - CFErrorRef error; - - if (aValue && ![aValue isKindOfClass:[NSNull class]]) { - if (bUpdate && ([aValue isKindOfClass:[NSString class]] && ([aValue length] == 0))) { // if updating, empty string means to delete - aValue = NULL; - } // really only need to set if different - more efficient to just update value or compare and only set if necessary??? - bSuccess = ABRecordSetValue(aRecord, aProperty, (__bridge CFTypeRef)aValue, &error); - if (!bSuccess) { - NSLog(@"error setting %d property", aProperty); - } - } - - return bSuccess; -} - -- (bool)removeProperty:(ABPropertyID)aProperty inRecord:(ABRecordRef)aRecord -{ - CFErrorRef err; - bool bSuccess = ABRecordRemoveValue(aRecord, aProperty, &err); - - if (!bSuccess) { - CFStringRef errDescription = CFErrorCopyDescription(err); - NSLog(@"Unable to remove property %d: %@", aProperty, errDescription); - CFRelease(errDescription); - } - return bSuccess; -} - -- (bool)addToMultiValue:(ABMultiValueRef)multi fromDictionary:dict -{ - bool bSuccess = FALSE; - id value = [dict valueForKey:kW3ContactFieldValue]; - - if (IS_VALID_VALUE(value)) { - CFStringRef label = [CDVContact convertContactTypeToPropertyLabel:[dict valueForKey:kW3ContactFieldType]]; - bSuccess = ABMultiValueAddValueAndLabel(multi, (__bridge CFTypeRef)value, label, NULL); - if (!bSuccess) { - NSLog(@"Error setting Value: %@ and label: %@", value, label); - } - } - return bSuccess; -} - -- (ABMultiValueRef)allocStringMultiValueFromArray:array -{ - ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABMultiStringPropertyType); - - for (NSDictionary* dict in array) { - [self addToMultiValue:multi fromDictionary:dict]; - } - - return multi; // caller is responsible for releasing multi -} - -- (bool)setValue:(CFTypeRef)value forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person -{ - CFErrorRef error; - bool bSuccess = ABRecordSetValue(person, prop, value, &error); - - if (!bSuccess) { - NSLog(@"Error setting value for property: %d", prop); - } - return bSuccess; -} - -/* Set MultiValue string properties into Address Book Record. - * NSArray* fieldArray - array of dictionaries containing W3C properties to be set into record - * ABPropertyID prop - the property to be set (generally used for phones and emails) - * ABRecordRef person - the record to set values into - * BOOL bUpdate - whether or not to update date or set as new. - * When updating: - * empty array indicates to remove entire property - * empty string indicates to remove - * [NSNull null] do not modify (keep existing record value) - * RETURNS - * bool false indicates error - * - * used for phones and emails - */ -- (bool)setMultiValueStrings:(NSArray*)fieldArray forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person asUpdate:(BOOL)bUpdate -{ - bool bSuccess = TRUE; - ABMutableMultiValueRef multi = nil; - - if (!bUpdate) { - multi = [self allocStringMultiValueFromArray:fieldArray]; - bSuccess = [self setValue:multi forProperty:prop inRecord:person]; - } else if (bUpdate && ([fieldArray count] == 0)) { - // remove entire property - bSuccess = [self removeProperty:prop inRecord:person]; - } else { // check for and apply changes - ABMultiValueRef copy = ABRecordCopyValue(person, prop); - if (copy != nil) { - multi = ABMultiValueCreateMutableCopy(copy); - CFRelease(copy); - - for (NSDictionary* dict in fieldArray) { - id val; - NSString* label = nil; - val = [dict valueForKey:kW3ContactFieldValue]; - label = (__bridge NSString*)[CDVContact convertContactTypeToPropertyLabel:[dict valueForKey:kW3ContactFieldType]]; - if (IS_VALID_VALUE(val)) { - // is an update, find index of entry with matching id, if values are different, update. - id idValue = [dict valueForKey:kW3ContactFieldId]; - int identifier = [idValue isKindOfClass:[NSNumber class]] ? [idValue intValue] : -1; - CFIndex i = identifier >= 0 ? ABMultiValueGetIndexForIdentifier(multi, identifier) : kCFNotFound; - if (i != kCFNotFound) { - if ([val length] == 0) { - // remove both value and label - ABMultiValueRemoveValueAndLabelAtIndex(multi, i); - } else { - NSString* valueAB = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(multi, i); - NSString* labelAB = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(multi, i); - if ((valueAB == nil) || ![val isEqualToString:valueAB]) { - ABMultiValueReplaceValueAtIndex(multi, (__bridge CFTypeRef)val, i); - } - if ((labelAB == nil) || ![label isEqualToString:labelAB]) { - ABMultiValueReplaceLabelAtIndex(multi, (__bridge CFStringRef)label, i); - } - } - } else { - // is a new value - insert - [self addToMultiValue:multi fromDictionary:dict]; - } - } // end of if value - } // end of for - } else { // adding all new value(s) - multi = [self allocStringMultiValueFromArray:fieldArray]; - } - // set the (updated) copy as the new value - bSuccess = [self setValue:multi forProperty:prop inRecord:person]; - } - - if (multi) { - CFRelease(multi); - } - - return bSuccess; -} - -// used for ims and addresses -- (ABMultiValueRef)allocDictMultiValueFromArray:array forProperty:(ABPropertyID)prop -{ - ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType); - NSMutableDictionary* newDict; - NSMutableDictionary* addDict; - - for (NSDictionary* dict in array) { - newDict = [self translateW3Dict:dict forProperty:prop]; - addDict = [NSMutableDictionary dictionaryWithCapacity:2]; - if (newDict) { // create a new dictionary with a Label and Value, value is the dictionary previously created - // June, 2011 W3C Contact spec adds type into ContactAddress book - // get the type out of the original dictionary for address - NSString* addrType = (NSString*)[dict valueForKey:kW3ContactFieldType]; - if (!addrType) { - addrType = (NSString*)kABOtherLabel; - } - NSObject* typeValue = ((prop == kABPersonInstantMessageProperty) ? (NSObject*)kABOtherLabel : addrType); - // NSLog(@"typeValue: %@", typeValue); - [addDict setObject:typeValue forKey:kW3ContactFieldType]; // im labels will be set as Other and address labels as type from dictionary - [addDict setObject:newDict forKey:kW3ContactFieldValue]; - [self addToMultiValue:multi fromDictionary:addDict]; - } - } - - return multi; // caller is responsible for releasing -} - -// used for ims and addresses to convert W3 dictionary of values to AB Dictionary -// got messier when June, 2011 W3C Contact spec added type field into ContactAddress -- (NSMutableDictionary*)translateW3Dict:(NSDictionary*)dict forProperty:(ABPropertyID)prop -{ - NSArray* propArray = [[CDVContact defaultObjectAndProperties] valueForKey:[[CDVContact defaultABtoW3C] objectForKey:[NSNumber numberWithInt:prop]]]; - - NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:1]; - id value; - - for (NSString* key in propArray) { // for each W3 Contact key get the value - if (((value = [dict valueForKey:key]) != nil) && ![value isKindOfClass:[NSNull class]]) { - // if necessary convert the W3 value to AB Property label - NSString* setValue = value; - if ([CDVContact needsConversion:key]) { // IM types must be converted - setValue = (NSString*)[CDVContact convertContactTypeToPropertyLabel:value]; - // IMs must have a valid AB value! - if ((prop == kABPersonInstantMessageProperty) && [setValue isEqualToString:(NSString*)kABOtherLabel]) { - setValue = @""; // try empty string - } - } - // set the AB value into the dictionary - [newDict setObject:setValue forKey:(NSString*)[[CDVContact defaultW3CtoAB] valueForKey:(NSString*)key]]; - } - } - - if ([newDict count] == 0) { - newDict = nil; // no items added - } - return newDict; -} - -/* set multivalue dictionary properties into an AddressBook Record - * NSArray* array - array of dictionaries containing the W3C properties to set into the record - * ABPropertyID prop - the property id for the multivalue dictionary (addresses and ims) - * ABRecordRef person - the record to set the values into - * BOOL bUpdate - YES if this is an update to an existing record - * When updating: - * empty array indicates to remove entire property - * value/label == "" indicates to remove - * value/label == [NSNull null] do not modify (keep existing record value) - * RETURN - * bool false indicates fatal error - * - * iOS addresses and im are a MultiValue Properties with label, value=dictionary of info, and id - * set addresses: streetAddress, locality, region, postalCode, country - * set ims: value = username, type = servicetype - * there are some special cases in here for ims - needs cleanup / simplification - * - */ -- (bool)setMultiValueDictionary:(NSArray*)array forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person asUpdate:(BOOL)bUpdate -{ - bool bSuccess = FALSE; - ABMutableMultiValueRef multi = nil; - - if (!bUpdate) { - multi = [self allocDictMultiValueFromArray:array forProperty:prop]; - bSuccess = [self setValue:multi forProperty:prop inRecord:person]; - } else if (bUpdate && ([array count] == 0)) { - // remove property - bSuccess = [self removeProperty:prop inRecord:person]; - } else { // check for and apply changes - ABMultiValueRef copy = ABRecordCopyValue(person, prop); - if (copy) { - multi = ABMultiValueCreateMutableCopy(copy); - CFRelease(copy); - // get the W3C values for this property - NSArray* propArray = [[CDVContact defaultObjectAndProperties] valueForKey:[[CDVContact defaultABtoW3C] objectForKey:[NSNumber numberWithInt:prop]]]; - id value; - id valueAB; - - for (NSDictionary* field in array) { - NSMutableDictionary* dict; - // find the index for the current property - id idValue = [field valueForKey:kW3ContactFieldId]; - int identifier = [idValue isKindOfClass:[NSNumber class]] ? [idValue intValue] : -1; - CFIndex idx = identifier >= 0 ? ABMultiValueGetIndexForIdentifier(multi, identifier) : kCFNotFound; - BOOL bUpdateLabel = NO; - if (idx != kCFNotFound) { - dict = [NSMutableDictionary dictionaryWithCapacity:1]; - // NSDictionary* existingDictionary = (NSDictionary*)ABMultiValueCopyValueAtIndex(multi, idx); - CFTypeRef existingDictionary = ABMultiValueCopyValueAtIndex(multi, idx); - NSString* existingABLabel = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(multi, idx); - NSString* testLabel = [field valueForKey:kW3ContactFieldType]; - // fixes cb-143 where setting empty label could cause address to not be removed - // (because empty label would become 'other' in convertContactTypeToPropertyLabel - // which may not have matched existing label thus resulting in an incorrect updating of the label - // and the address not getting removed at the end of the for loop) - if (testLabel && [testLabel isKindOfClass:[NSString class]] && ([testLabel length] > 0)) { - CFStringRef w3cLabel = [CDVContact convertContactTypeToPropertyLabel:testLabel]; - if (w3cLabel && ![existingABLabel isEqualToString:(__bridge NSString*)w3cLabel]) { - // replace the label - ABMultiValueReplaceLabelAtIndex(multi, w3cLabel, idx); - bUpdateLabel = YES; - } - } // else was invalid or empty label string so do not update - - for (id k in propArray) { - value = [field valueForKey:k]; - bool bSet = (value != nil && ![value isKindOfClass:[NSNull class]] && ([value isKindOfClass:[NSString class]] && [value length] > 0)); - // if there is a contact value, put it into dictionary - if (bSet) { - NSString* setValue = [CDVContact needsConversion:(NSString*)k] ? (NSString*)[CDVContact convertContactTypeToPropertyLabel:value] : value; - [dict setObject:setValue forKey:(NSString*)[[CDVContact defaultW3CtoAB] valueForKey:(NSString*)k]]; - } else if ((value == nil) || ([value isKindOfClass:[NSString class]] && ([value length] != 0))) { - // value not provided in contact dictionary - if prop exists in AB dictionary, preserve it - valueAB = [(__bridge NSDictionary*)existingDictionary valueForKey : [[CDVContact defaultW3CtoAB] valueForKey:k]]; - if (valueAB != nil) { - [dict setValue:valueAB forKey:[[CDVContact defaultW3CtoAB] valueForKey:k]]; - } - } // else if value == "" it will not be added into updated dict and thus removed - } // end of for loop (moving here fixes cb-143, need to end for loop before replacing or removing multivalue) - - if ([dict count] > 0) { - // something was added into new dict, - ABMultiValueReplaceValueAtIndex(multi, (__bridge CFTypeRef)dict, idx); - } else if (!bUpdateLabel) { - // nothing added into new dict and no label change so remove this property entry - ABMultiValueRemoveValueAndLabelAtIndex(multi, idx); - } - - CFRelease(existingDictionary); - } else { - // not found in multivalue so add it - dict = [self translateW3Dict:field forProperty:prop]; - if (dict) { - NSMutableDictionary* addDict = [NSMutableDictionary dictionaryWithCapacity:2]; - // get the type out of the original dictionary for address - NSObject* typeValue = ((prop == kABPersonInstantMessageProperty) ? (NSObject*)kABOtherLabel : (NSString*)[field valueForKey:kW3ContactFieldType]); - // NSLog(@"typeValue: %@", typeValue); - [addDict setObject:typeValue forKey:kW3ContactFieldType]; // im labels will be set as Other and address labels as type from dictionary - [addDict setObject:dict forKey:kW3ContactFieldValue]; - [self addToMultiValue:multi fromDictionary:addDict]; - } - } - } // end of looping through dictionaries - - // set the (updated) copy as the new value - bSuccess = [self setValue:multi forProperty:prop inRecord:person]; - } - } // end of copy and apply changes - if (multi) { - CFRelease(multi); - } - - return bSuccess; -} - -/* Determine which W3C labels need to be converted - */ -+ (BOOL)needsConversion:(NSString*)W3Label -{ - BOOL bConvert = NO; - - if ([W3Label isEqualToString:kW3ContactFieldType] || [W3Label isEqualToString:kW3ContactImType]) { - bConvert = YES; - } - return bConvert; -} - -/* Translation of property type labels contact API ---> iPhone - * - * phone: work, home, other, mobile, fax, pager --> - * kABWorkLabel, kABHomeLabel, kABOtherLabel, kABPersonPhoneMobileLabel, kABPersonHomeFAXLabel || kABPersonHomeFAXLabel, kABPersonPhonePagerLabel - * emails: work, home, other ---> kABWorkLabel, kABHomeLabel, kABOtherLabel - * ims: aim, gtalk, icq, xmpp, msn, skype, qq, yahoo --> kABPersonInstantMessageService + (AIM, ICG, MSN, Yahoo). No support for gtalk, xmpp, skype, qq - * addresses: work, home, other --> kABWorkLabel, kABHomeLabel, kABOtherLabel - * - * - */ -+ (CFStringRef)convertContactTypeToPropertyLabel:(NSString*)label -{ - CFStringRef type; - - if ([label isKindOfClass:[NSNull class]] || ![label isKindOfClass:[NSString class]]) { - type = NULL; // no label - } else if ([label caseInsensitiveCompare:kW3ContactWorkLabel] == NSOrderedSame) { - type = kABWorkLabel; - } else if ([label caseInsensitiveCompare:kW3ContactHomeLabel] == NSOrderedSame) { - type = kABHomeLabel; - } else if ([label caseInsensitiveCompare:kW3ContactOtherLabel] == NSOrderedSame) { - type = kABOtherLabel; - } else if ([label caseInsensitiveCompare:kW3ContactPhoneMobileLabel] == NSOrderedSame) { - type = kABPersonPhoneMobileLabel; - } else if ([label caseInsensitiveCompare:kW3ContactPhonePagerLabel] == NSOrderedSame) { - type = kABPersonPhonePagerLabel; - } else if ([label caseInsensitiveCompare:kW3ContactImAIMLabel] == NSOrderedSame) { - type = kABPersonInstantMessageServiceAIM; - } else if ([label caseInsensitiveCompare:kW3ContactImICQLabel] == NSOrderedSame) { - type = kABPersonInstantMessageServiceICQ; - } else if ([label caseInsensitiveCompare:kW3ContactImMSNLabel] == NSOrderedSame) { - type = kABPersonInstantMessageServiceMSN; - } else if ([label caseInsensitiveCompare:kW3ContactImYahooLabel] == NSOrderedSame) { - type = kABPersonInstantMessageServiceYahoo; - } else if ([label caseInsensitiveCompare:kW3ContactUrlProfile] == NSOrderedSame) { - type = kABPersonHomePageLabel; - } else { - type = kABOtherLabel; - } - - return type; -} - -+ (NSString*)convertPropertyLabelToContactType:(NSString*)label -{ - NSString* type = nil; - - if (label != nil) { // improve efficiency...... - if ([label isEqualToString:(NSString*)kABPersonPhoneMobileLabel]) { - type = kW3ContactPhoneMobileLabel; - } else if ([label isEqualToString:(NSString*)kABPersonPhoneHomeFAXLabel] || - [label isEqualToString:(NSString*)kABPersonPhoneWorkFAXLabel]) { - type = kW3ContactPhoneFaxLabel; - } else if ([label isEqualToString:(NSString*)kABPersonPhonePagerLabel]) { - type = kW3ContactPhonePagerLabel; - } else if ([label isEqualToString:(NSString*)kABHomeLabel]) { - type = kW3ContactHomeLabel; - } else if ([label isEqualToString:(NSString*)kABWorkLabel]) { - type = kW3ContactWorkLabel; - } else if ([label isEqualToString:(NSString*)kABOtherLabel]) { - type = kW3ContactOtherLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceAIM]) { - type = kW3ContactImAIMLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceICQ]) { - type = kW3ContactImICQLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceJabber]) { - type = kW3ContactOtherLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceMSN]) { - type = kW3ContactImMSNLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceYahoo]) { - type = kW3ContactImYahooLabel; - } else if ([label isEqualToString:(NSString*)kABPersonHomePageLabel]) { - type = kW3ContactUrlProfile; - } else { - type = kW3ContactOtherLabel; - } - } - return type; -} - -/* Check if the input label is a valid W3C ContactField.type. This is used when searching, - * only search field types if the search string is a valid type. If we converted any search - * string to a ABPropertyLabel it could convert to kABOtherLabel which is probably not want - * the user wanted to search for and could skew the results. - */ -+ (BOOL)isValidW3ContactType:(NSString*)label -{ - BOOL isValid = NO; - - if ([label isKindOfClass:[NSNull class]] || ![label isKindOfClass:[NSString class]]) { - isValid = NO; // no label - } else if ([label caseInsensitiveCompare:kW3ContactWorkLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactHomeLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactOtherLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactPhoneMobileLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactPhonePagerLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactImAIMLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactImICQLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactImMSNLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactImYahooLabel] == NSOrderedSame) { - isValid = YES; - } else { - isValid = NO; - } - - return isValid; -} - -/* Create a new Contact Dictionary object from an ABRecordRef that contains information in a format such that - * it can be returned to JavaScript callback as JSON object string. - * Uses: - * ABRecordRef set into Contact Object - * NSDictionary withFields indicates which fields to return from the AddressBook Record - * - * JavaScript Contact: - * @param {DOMString} id unique identifier - * @param {DOMString} displayName - * @param {ContactName} name - * @param {DOMString} nickname - * @param {ContactField[]} phoneNumbers array of phone numbers - * @param {ContactField[]} emails array of email addresses - * @param {ContactAddress[]} addresses array of addresses - * @param {ContactField[]} ims instant messaging user ids - * @param {ContactOrganization[]} organizations - * @param {DOMString} published date contact was first created - * @param {DOMString} updated date contact was last updated - * @param {DOMString} birthday contact's birthday - * @param (DOMString} anniversary contact's anniversary - * @param {DOMString} gender contact's gender - * @param {DOMString} note user notes about contact - * @param {DOMString} preferredUsername - * @param {ContactField[]} photos - * @param {ContactField[]} tags - * @param {ContactField[]} relationships - * @param {ContactField[]} urls contact's web sites - * @param {ContactAccounts[]} accounts contact's online accounts - * @param {DOMString} timezone UTC time zone offset - * @param {DOMString} connected - */ - -- (NSDictionary*)toDictionary:(NSDictionary*)withFields -{ - // if not a person type record bail out for now - if (ABRecordGetRecordType(self.record) != kABPersonType) { - return NULL; - } - id value = nil; - self.returnFields = withFields; - - NSMutableDictionary* nc = [NSMutableDictionary dictionaryWithCapacity:1]; // new contact dictionary to fill in from ABRecordRef - // id - [nc setObject:[NSNumber numberWithInt:ABRecordGetRecordID(self.record)] forKey:kW3ContactId]; - if (self.returnFields == nil) { - // if no returnFields specified, W3C says to return empty contact (but Cordova will at least return id) - return nc; - } - if ([self.returnFields objectForKey:kW3ContactDisplayName]) { - // displayname requested - iOS doesn't have so return null - [nc setObject:[NSNull null] forKey:kW3ContactDisplayName]; - // may overwrite below if requested ContactName and there are no values - } - // nickname - if ([self.returnFields valueForKey:kW3ContactNickname]) { - value = (__bridge_transfer NSString*)ABRecordCopyValue(self.record, kABPersonNicknameProperty); - [nc setObject:(value != nil) ? value:[NSNull null] forKey:kW3ContactNickname]; - } - - // name dictionary - // NSLog(@"getting name info"); - NSObject* data = [self extractName]; - if (data != nil) { - [nc setObject:data forKey:kW3ContactName]; - } - if ([self.returnFields objectForKey:kW3ContactDisplayName] && ((data == nil) || ([(NSDictionary*)data objectForKey : kW3ContactFormattedName] == [NSNull null]))) { - // user asked for displayName which iOS doesn't support but there is no other name data being returned - // try and use Composite Name so some name is returned - id tryName = (__bridge_transfer NSString*)ABRecordCopyCompositeName(self.record); - if (tryName != nil) { - [nc setObject:tryName forKey:kW3ContactDisplayName]; - } else { - // use nickname or empty string - value = (__bridge_transfer NSString*)ABRecordCopyValue(self.record, kABPersonNicknameProperty); - [nc setObject:(value != nil) ? value:@"" forKey:kW3ContactDisplayName]; - } - } - // phoneNumbers array - // NSLog(@"getting phoneNumbers"); - value = [self extractMultiValue:kW3ContactPhoneNumbers]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactPhoneNumbers]; - } - // emails array - // NSLog(@"getting emails"); - value = [self extractMultiValue:kW3ContactEmails]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactEmails]; - } - // urls array - value = [self extractMultiValue:kW3ContactUrls]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactUrls]; - } - // addresses array - // NSLog(@"getting addresses"); - value = [self extractAddresses]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactAddresses]; - } - // im array - // NSLog(@"getting ims"); - value = [self extractIms]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactIms]; - } - // organization array (only info for one organization in iOS) - // NSLog(@"getting organizations"); - value = [self extractOrganizations]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactOrganizations]; - } - - // for simple properties, could make this a bit more efficient by storing all simple properties in a single - // array in the returnFields dictionary and setting them via a for loop through the array - - // add dates - // NSLog(@"getting dates"); - NSNumber* ms; - - /** Contact Revision field removed from June 16, 2011 version of specification - - if ([self.returnFields valueForKey:kW3ContactUpdated]){ - ms = [self getDateAsNumber: kABPersonModificationDateProperty]; - if (!ms){ - // try and get published date - ms = [self getDateAsNumber: kABPersonCreationDateProperty]; - } - if (ms){ - [nc setObject: ms forKey:kW3ContactUpdated]; - } - - } - */ - - if ([self.returnFields valueForKey:kW3ContactBirthday]) { - ms = [self getDateAsNumber:kABPersonBirthdayProperty]; - if (ms) { - [nc setObject:ms forKey:kW3ContactBirthday]; - } - } - - /* Anniversary removed from 12-09-2010 W3C Contacts api spec - if ([self.returnFields valueForKey:kW3ContactAnniversary]){ - // Anniversary date is stored in a multivalue property - ABMultiValueRef multi = ABRecordCopyValue(self.record, kABPersonDateProperty); - if (multi){ - CFStringRef label = nil; - CFIndex count = ABMultiValueGetCount(multi); - // see if contains an Anniversary date - for(CFIndex i=0; i 0) { // ?? this will always be true since we set id,label,primary field?? - [(NSMutableArray*)addresses addObject : newAddress]; - } - CFRelease(dict); - } // end of loop through addresses - } else { - addresses = [NSNull null]; - } - if (multi) { - CFRelease(multi); - } - - return addresses; -} - -/* Create array of Dictionaries to match JavaScript ContactField object for ims - * type one of [aim, gtalk, icq, xmpp, msn, skype, qq, yahoo] needs other as well - * value - * (bool) primary - * id - * - * iOS IMs are a MultiValue Properties with label, value=dictionary of IM details (service, username), and id - */ -- (NSObject*)extractIms -{ - NSArray* fields = [self.returnFields objectForKey:kW3ContactIms]; - - if (fields == nil) { // no name fields requested - return nil; - } - NSObject* imArray; - ABMultiValueRef multi = ABRecordCopyValue(self.record, kABPersonInstantMessageProperty); - CFIndex count = multi ? ABMultiValueGetCount(multi) : 0; - if (count) { - imArray = [NSMutableArray arrayWithCapacity:count]; - - for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) { - NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:3]; - // iOS has label property (work, home, other) for each IM but W3C contact API doesn't use - CFDictionaryRef dict = (CFDictionaryRef)ABMultiValueCopyValueAtIndex(multi, i); - CFStringRef value; // all values should be CFStringRefs / NSString* - bool bFound; - if ([fields containsObject:kW3ContactFieldValue]) { - // value = user name - bFound = CFDictionaryGetValueIfPresent(dict, kABPersonInstantMessageUsernameKey, (void*)&value); - if (bFound && (value != NULL)) { - CFRetain(value); - [newDict setObject:(__bridge id)value forKey:kW3ContactFieldValue]; - CFRelease(value); - } else { - [newDict setObject:[NSNull null] forKey:kW3ContactFieldValue]; - } - } - if ([fields containsObject:kW3ContactFieldType]) { - bFound = CFDictionaryGetValueIfPresent(dict, kABPersonInstantMessageServiceKey, (void*)&value); - if (bFound && (value != NULL)) { - CFRetain(value); - [newDict setObject:(id)[[CDVContact class] convertPropertyLabelToContactType : (__bridge NSString*)value] forKey:kW3ContactFieldType]; - CFRelease(value); - } else { - [newDict setObject:[NSNull null] forKey:kW3ContactFieldType]; - } - } - // always set ID - id identifier = [NSNumber numberWithUnsignedInt:ABMultiValueGetIdentifierAtIndex(multi, i)]; - [newDict setObject:(identifier != nil) ? identifier:[NSNull null] forKey:kW3ContactFieldId]; - - [(NSMutableArray*)imArray addObject : newDict]; - CFRelease(dict); - } - } else { - imArray = [NSNull null]; - } - - if (multi) { - CFRelease(multi); - } - return imArray; -} - -/* Create array of Dictionaries to match JavaScript ContactOrganization object - * pref - not supported in iOS - * type - not supported in iOS - * name - * department - * title - */ - -- (NSObject*)extractOrganizations -{ - NSArray* fields = [self.returnFields objectForKey:kW3ContactOrganizations]; - - if (fields == nil) { // no name fields requested - return nil; - } - NSObject* array = nil; - NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:5]; - id value; - int validValueCount = 0; - - for (id i in fields) { - id key = [[CDVContact defaultW3CtoAB] valueForKey:i]; - if (key && [key isKindOfClass:[NSNumber class]]) { - value = (__bridge_transfer NSString*)ABRecordCopyValue(self.record, (ABPropertyID)[[[CDVContact defaultW3CtoAB] valueForKey:i] intValue]); - if (value != nil) { - // if there are no organization values we should return null for organization - // this counter keeps indicates if any organization values have been set - validValueCount++; - } - [newDict setObject:(value != nil) ? value:[NSNull null] forKey:i]; - } else { // not a key iOS supports, set to null - [newDict setObject:[NSNull null] forKey:i]; - } - } - - if (([newDict count] > 0) && (validValueCount > 0)) { - // add pref and type - // they are not supported by iOS and thus these values never change - [newDict setObject:@"false" forKey:kW3ContactFieldPrimary]; - [newDict setObject:[NSNull null] forKey:kW3ContactFieldType]; - array = [NSMutableArray arrayWithCapacity:1]; - [(NSMutableArray*)array addObject : newDict]; - } else { - array = [NSNull null]; - } - return array; -} - -// W3C Contacts expects an array of photos. Can return photos in more than one format, currently -// just returning the default format -// Save the photo data into tmp directory and return FileURI - temp directory is deleted upon application exit -- (NSObject*)extractPhotos -{ - NSMutableArray* photos = nil; - - if (ABPersonHasImageData(self.record)) { - CFDataRef photoData = ABPersonCopyImageData(self.record); - NSData* data = (__bridge NSData*)photoData; - // write to temp directory and store URI in photos array - // get the temp directory path - NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath]; - NSError* err = nil; - NSString* filePath = [NSString stringWithFormat:@"%@/photo_XXXXX", docsPath]; - char template[filePath.length + 1]; - strcpy(template, [filePath cStringUsingEncoding:NSASCIIStringEncoding]); - mkstemp(template); - filePath = [[NSFileManager defaultManager] - stringWithFileSystemRepresentation:template - length:strlen(template)]; - - // save file - if ([data writeToFile:filePath options:NSAtomicWrite error:&err]) { - photos = [NSMutableArray arrayWithCapacity:1]; - NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:2]; - [newDict setObject:filePath forKey:kW3ContactFieldValue]; - [newDict setObject:@"url" forKey:kW3ContactFieldType]; - [newDict setObject:@"false" forKey:kW3ContactFieldPrimary]; - [photos addObject:newDict]; - } - - CFRelease(photoData); - } - return photos; -} - -/** - * given an array of W3C Contact field names, create a dictionary of field names to extract - * if field name represents an object, return all properties for that object: "name" - returns all properties in ContactName - * if field name is an explicit property, return only those properties: "name.givenName - returns a ContactName with only ContactName.givenName - * if field contains ONLY ["*"] return all fields - * dictionary format: - * key is W3Contact #define - * value is NSMutableArray* for complex keys: name,addresses,organizations, phone, emails, ims - * value is [NSNull null] for simple keys -*/ -+ (NSDictionary*)calcReturnFields:(NSArray*)fieldsArray // NSLog(@"getting self.returnFields"); -{ - NSMutableDictionary* d = [NSMutableDictionary dictionaryWithCapacity:1]; - - if ((fieldsArray != nil) && [fieldsArray isKindOfClass:[NSArray class]]) { - if (([fieldsArray count] == 1) && [[fieldsArray objectAtIndex:0] isEqualToString:@"*"]) { - return [CDVContact defaultFields]; // return all fields - } - - for (id i in fieldsArray) { - NSMutableArray* keys = nil; - NSString* fieldStr = nil; - if ([i isKindOfClass:[NSNumber class]]) { - fieldStr = [i stringValue]; - } else { - fieldStr = i; - } - - // see if this is specific property request in object - object.property - NSArray* parts = [fieldStr componentsSeparatedByString:@"."]; // returns original string if no separator found - NSString* name = [parts objectAtIndex:0]; - NSString* property = nil; - if ([parts count] > 1) { - property = [parts objectAtIndex:1]; - } - // see if this is a complex field by looking for its array of properties in objectAndProperties dictionary - id fields = [[CDVContact defaultObjectAndProperties] objectForKey:name]; - - // if find complex name (name,addresses,organizations, phone, emails, ims) in fields, add name as key - // with array of associated properties as the value - if ((fields != nil) && (property == nil)) { // request was for full object - keys = [NSMutableArray arrayWithArray:fields]; - if (keys != nil) { - [d setObject:keys forKey:name]; // will replace if prop array already exists - } - } else if ((fields != nil) && (property != nil)) { - // found an individual property request in form of name.property - // verify is real property name by using it as key in W3CtoAB - id abEquiv = [[CDVContact defaultW3CtoAB] objectForKey:property]; - if (abEquiv || [[CDVContact defaultW3CtoNull] containsObject:property]) { - // if existing array add to it - if ((keys = [d objectForKey:name]) != nil) { - [keys addObject:property]; - } else { - keys = [NSMutableArray arrayWithObject:property]; - [d setObject:keys forKey:name]; - } - } else { - NSLog(@"Contacts.find -- request for invalid property ignored: %@.%@", name, property); - } - } else { // is an individual property, verify is real property name by using it as key in W3CtoAB - id valid = [[CDVContact defaultW3CtoAB] objectForKey:name]; - if (valid || [[CDVContact defaultW3CtoNull] containsObject:name]) { - [d setObject:[NSNull null] forKey:name]; - } - } - } - } - if ([d count] == 0) { - // no array or nothing in the array. W3C spec says to return nothing - return nil; // [Contact defaultFields]; - } - return d; -} - -/* - * Search for the specified value in each of the fields specified in the searchFields dictionary. - * NSString* value - the string value to search for (need clarification from W3C on how to search for dates) - * NSDictionary* searchFields - a dictionary created via calcReturnFields where the key is the top level W3C - * object and the object is the array of specific fields within that object or null if it is a single property - * RETURNS - * YES as soon as a match is found in any of the fields - * NO - the specified value does not exist in any of the fields in this contact - * - * Note: I'm not a fan of returning in the middle of methods but have done it some in this method in order to - * keep the code simpler. bgibson - */ -- (BOOL)foundValue:(NSString*)testValue inFields:(NSDictionary*)searchFields -{ - BOOL bFound = NO; - - if ((testValue == nil) || ![testValue isKindOfClass:[NSString class]] || ([testValue length] == 0)) { - // nothing to find so return NO - return NO; - } - NSInteger valueAsInt = [testValue integerValue]; - - // per W3C spec, always include id in search - int recordId = ABRecordGetRecordID(self.record); - if (valueAsInt && (recordId == valueAsInt)) { - return YES; - } - - if (searchFields == nil) { - // no fields to search - return NO; - } - - if ([searchFields valueForKey:kW3ContactNickname]) { - bFound = [self testStringValue:testValue forW3CProperty:kW3ContactNickname]; - if (bFound == YES) { - return bFound; - } - } - - if ([searchFields valueForKeyIsArray:kW3ContactName]) { - // test name fields. All are string properties obtained via ABRecordCopyValue except kW3ContactFormattedName - NSArray* fields = [searchFields valueForKey:kW3ContactName]; - - for (NSString* testItem in fields) { - if ([testItem isEqualToString:kW3ContactFormattedName]) { - NSString* propValue = (__bridge_transfer NSString*)ABRecordCopyCompositeName(self.record); - if ((propValue != nil) && ([propValue length] > 0)) { - NSRange range = [propValue rangeOfString:testValue options:NSCaseInsensitiveSearch]; - bFound = (range.location != NSNotFound); - propValue = nil; - } - } else { - bFound = [self testStringValue:testValue forW3CProperty:testItem]; - } - - if (bFound) { - break; - } - } - } - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactPhoneNumbers]) { - bFound = [self searchContactFields:(NSArray*)[searchFields valueForKey:kW3ContactPhoneNumbers] - forMVStringProperty:kABPersonPhoneProperty withValue:testValue]; - } - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactEmails]) { - bFound = [self searchContactFields:(NSArray*)[searchFields valueForKey:kW3ContactEmails] - forMVStringProperty:kABPersonEmailProperty withValue:testValue]; - } - - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactAddresses]) { - bFound = [self searchContactFields:[searchFields valueForKey:kW3ContactAddresses] - forMVDictionaryProperty:kABPersonAddressProperty withValue:testValue]; - } - - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactIms]) { - bFound = [self searchContactFields:[searchFields valueForKey:kW3ContactIms] - forMVDictionaryProperty:kABPersonInstantMessageProperty withValue:testValue]; - } - - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactOrganizations]) { - NSArray* fields = [searchFields valueForKey:kW3ContactOrganizations]; - - for (NSString* testItem in fields) { - bFound = [self testStringValue:testValue forW3CProperty:testItem]; - if (bFound == YES) { - break; - } - } - } - if (!bFound && [searchFields valueForKey:kW3ContactNote]) { - bFound = [self testStringValue:testValue forW3CProperty:kW3ContactNote]; - } - - // if searching for a date field is requested, get the date field as a localized string then look for match against testValue in date string - // searching for photos is not supported - if (!bFound && [searchFields valueForKey:kW3ContactBirthday]) { - bFound = [self testDateValue:testValue forW3CProperty:kW3ContactBirthday]; - } - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactUrls]) { - bFound = [self searchContactFields:(NSArray*)[searchFields valueForKey:kW3ContactUrls] - forMVStringProperty:kABPersonURLProperty withValue:testValue]; - } - - return bFound; -} - -/* - * Test for the existence of a given string within the value of a ABPersonRecord string property based on the W3c property name. - * - * IN: - * NSString* testValue - the value to find - search is case insensitive - * NSString* property - the W3c property string - * OUT: - * BOOL YES if the given string was found within the property value - * NO if the testValue was not found, W3C property string was invalid or the AddressBook property was not a string - */ -- (BOOL)testStringValue:(NSString*)testValue forW3CProperty:(NSString*)property -{ - BOOL bFound = NO; - - if ([[CDVContact defaultW3CtoAB] valueForKeyIsNumber:property]) { - ABPropertyID propId = [[[CDVContact defaultW3CtoAB] objectForKey:property] intValue]; - if (ABPersonGetTypeOfProperty(propId) == kABStringPropertyType) { - NSString* propValue = (__bridge_transfer NSString*)ABRecordCopyValue(self.record, propId); - if ((propValue != nil) && ([propValue length] > 0)) { - NSPredicate* containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testValue]; - bFound = [containPred evaluateWithObject:propValue]; - // NSRange range = [propValue rangeOfString:testValue options: NSCaseInsensitiveSearch]; - // bFound = (range.location != NSNotFound); - } - } - } - return bFound; -} - -/* - * Test for the existence of a given Date string within the value of a ABPersonRecord datetime property based on the W3c property name. - * - * IN: - * NSString* testValue - the value to find - search is case insensitive - * NSString* property - the W3c property string - * OUT: - * BOOL YES if the given string was found within the localized date string value - * NO if the testValue was not found, W3C property string was invalid or the AddressBook property was not a DateTime - */ -- (BOOL)testDateValue:(NSString*)testValue forW3CProperty:(NSString*)property -{ - BOOL bFound = NO; - - if ([[CDVContact defaultW3CtoAB] valueForKeyIsNumber:property]) { - ABPropertyID propId = [[[CDVContact defaultW3CtoAB] objectForKey:property] intValue]; - if (ABPersonGetTypeOfProperty(propId) == kABDateTimePropertyType) { - NSDate* date = (__bridge_transfer NSDate*)ABRecordCopyValue(self.record, propId); - if (date != nil) { - NSString* dateString = [date descriptionWithLocale:[NSLocale currentLocale]]; - NSPredicate* containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testValue]; - bFound = [containPred evaluateWithObject:dateString]; - } - } - } - return bFound; -} - -/* - * Search the specified fields within an AddressBook multivalue string property for the specified test value. - * Used for phoneNumbers, emails and urls. - * IN: - * NSArray* fields - the fields to search for within the multistring property (value and/or type) - * ABPropertyID - the property to search - * NSString* testValue - the value to search for. Will convert between W3C types and AB types. Will only - * search for types if the testValue is a valid ContactField type. - * OUT: - * YES if the test value was found in one of the specified fields - * NO if the test value was not found - */ -- (BOOL)searchContactFields:(NSArray*)fields forMVStringProperty:(ABPropertyID)propId withValue:testValue -{ - BOOL bFound = NO; - - for (NSString* type in fields) { - NSString* testString = nil; - if ([type isEqualToString:kW3ContactFieldType]) { - if ([CDVContact isValidW3ContactType:testValue]) { - // only search types if the filter string is a valid ContactField.type - testString = (NSString*)[CDVContact convertContactTypeToPropertyLabel:testValue]; - } - } else { - testString = testValue; - } - - if (testString != nil) { - bFound = [self testMultiValueStrings:testString forProperty:propId ofType:type]; - } - if (bFound == YES) { - break; - } - } - - return bFound; -} - -/* - * Searches a multiString value of the specified type for the specified test value. - * - * IN: - * NSString* testValue - the value to test for - * ABPropertyID propId - the property id of the multivalue property to search - * NSString* type - the W3C contact type to search for (value or type) - * OUT: - * YES is the test value was found - * NO if the test value was not found - */ -- (BOOL)testMultiValueStrings:(NSString*)testValue forProperty:(ABPropertyID)propId ofType:(NSString*)type -{ - BOOL bFound = NO; - - if (ABPersonGetTypeOfProperty(propId) == kABMultiStringPropertyType) { - NSArray* valueArray = nil; - if ([type isEqualToString:kW3ContactFieldType]) { - valueArray = [self labelsForProperty:propId inRecord:self.record]; - } else if ([type isEqualToString:kW3ContactFieldValue]) { - valueArray = [self valuesForProperty:propId inRecord:self.record]; - } - if (valueArray) { - NSString* valuesAsString = [valueArray componentsJoinedByString:@" "]; - NSPredicate* containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testValue]; - bFound = [containPred evaluateWithObject:valuesAsString]; - } - } - return bFound; -} - -/* - * Returns the array of values for a multivalue string property of the specified property id - */ -- (__autoreleasing NSArray*)valuesForProperty:(ABPropertyID)propId inRecord:(ABRecordRef)aRecord -{ - ABMultiValueRef multi = ABRecordCopyValue(aRecord, propId); - NSArray* values = (__bridge_transfer NSArray*)ABMultiValueCopyArrayOfAllValues(multi); - - CFRelease(multi); - return values; -} - -/* - * Returns the array of labels for a multivalue string property of the specified property id - */ -- (NSArray*)labelsForProperty:(ABPropertyID)propId inRecord:(ABRecordRef)aRecord -{ - ABMultiValueRef multi = ABRecordCopyValue(aRecord, propId); - CFIndex count = ABMultiValueGetCount(multi); - NSMutableArray* labels = [NSMutableArray arrayWithCapacity:count]; - - for (int i = 0; i < count; i++) { - NSString* label = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(multi, i); - if (label) { - [labels addObject:label]; - } - } - - CFRelease(multi); - return labels; -} - -/* search for values within MultiValue Dictionary properties Address or IM property - * IN: - * (NSArray*) fields - the array of W3C field names to search within - * (ABPropertyID) propId - the AddressBook property that returns a multivalue dictionary - * (NSString*) testValue - the string to search for within the specified fields - * - */ -- (BOOL)searchContactFields:(NSArray*)fields forMVDictionaryProperty:(ABPropertyID)propId withValue:(NSString*)testValue -{ - BOOL bFound = NO; - - NSArray* values = [self valuesForProperty:propId inRecord:self.record]; // array of dictionaries (as CFDictionaryRef) - int dictCount = [values count]; - - // for ims dictionary contains with service (w3C type) and username (W3c value) - // for addresses dictionary contains street, city, state, zip, country - for (int i = 0; i < dictCount; i++) { - CFDictionaryRef dict = (__bridge CFDictionaryRef)[values objectAtIndex:i]; - - for (NSString* member in fields) { - NSString* abKey = [[CDVContact defaultW3CtoAB] valueForKey:member]; // im and address fields are all strings - CFStringRef abValue = nil; - if (abKey) { - NSString* testString = nil; - if ([member isEqualToString:kW3ContactImType]) { - if ([CDVContact isValidW3ContactType:testValue]) { - // only search service/types if the filter string is a valid ContactField.type - testString = (NSString*)[CDVContact convertContactTypeToPropertyLabel:testValue]; - } - } else { - testString = testValue; - } - if (testString != nil) { - BOOL bExists = CFDictionaryGetValueIfPresent(dict, (__bridge const void*)abKey, (void*)&abValue); - if (bExists) { - CFRetain(abValue); - NSPredicate* containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testString]; - bFound = [containPred evaluateWithObject:(__bridge id)abValue]; - CFRelease(abValue); - } - } - } - if (bFound == YES) { - break; - } - } // end of for each member in fields - - if (bFound == YES) { - break; - } - } // end of for each dictionary - - return bFound; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVContacts.h b/iPhone/CordovaLib/Classes/CDVContacts.h deleted file mode 100755 index 0342f5b..0000000 --- a/iPhone/CordovaLib/Classes/CDVContacts.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import -#import -#import "CDVPlugin.h" -#import "CDVContact.h" - -@interface CDVContacts : CDVPlugin -{ - ABAddressBookRef addressBook; -} - -/* - * newContact - create a new contact via the GUI - * - * arguments: - * 1: successCallback: this is the javascript function that will be called with the newly created contactId - */ -- (void)newContact:(CDVInvokedUrlCommand*)command; - -/* - * displayContact - IN PROGRESS - * - * arguments: - * 1: recordID of the contact to display in the iPhone contact display - * 2: successCallback - currently not used - * 3: error callback - * options: - * allowsEditing: set to true to allow the user to edit the contact - currently not supported - */ -- (void)displayContact:(CDVInvokedUrlCommand*)command; - -/* - * chooseContact - * - * arguments: - * 1: this is the javascript function that will be called with the contact data as a JSON object (as the first param) - * options: - * allowsEditing: set to true to not choose the contact, but to edit it in the iPhone contact editor - */ -- (void)chooseContact:(CDVInvokedUrlCommand*)command; - -- (void)newPersonViewController:(ABNewPersonViewController*)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person; -- (BOOL)personViewController:(ABPersonViewController*)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person - property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue; - -/* - * search - searches for contacts. Only person records are currently supported. - * - * arguments: - * 1: successcallback - this is the javascript function that will be called with the array of found contacts - * 2: errorCallback - optional javascript function to be called in the event of an error with an error code. - * options: dictionary containing ContactFields and ContactFindOptions - * fields - ContactFields array - * findOptions - ContactFindOptions object as dictionary - * - */ -- (void)search:(CDVInvokedUrlCommand*)command; - -/* - * save - saves a new contact or updates and existing contact - * - * arguments: - * 1: success callback - this is the javascript function that will be called with the JSON representation of the saved contact - * search calls a fixed navigator.service.contacts._findCallback which then calls the success callback stored before making the call into obj-c - */ -- (void)save:(CDVInvokedUrlCommand*)command; - -/* - * remove - removes a contact from the address book - * - * arguments: - * 1: 1: successcallback - this is the javascript function that will be called with a (now) empty contact object - * - * options: dictionary containing Contact object to remove - * contact - Contact object as dictionary - */ -- (void)remove:(CDVInvokedUrlCommand*)command; - -// - (void) dealloc; - -@end - -@interface CDVContactsPicker : ABPeoplePickerNavigationController -{ - BOOL allowsEditing; - NSString* callbackId; - NSDictionary* options; - NSDictionary* pickedContactDictionary; -} - -@property BOOL allowsEditing; -@property (copy) NSString* callbackId; -@property (nonatomic, strong) NSDictionary* options; -@property (nonatomic, strong) NSDictionary* pickedContactDictionary; - -@end - -@interface CDVNewContactsController : ABNewPersonViewController -{ - NSString* callbackId; -} -@property (copy) NSString* callbackId; -@end - -/* ABPersonViewController does not have any UI to dismiss. Adding navigationItems to it does not work properly, the navigationItems are lost when the app goes into the background. - The solution was to create an empty NavController in front of the ABPersonViewController. This - causes the ABPersonViewController to have a back button. By subclassing the ABPersonViewController, - we can override viewWillDisappear and take down the entire NavigationController at that time. - */ -@interface CDVDisplayContactViewController : ABPersonViewController -{} -@property (nonatomic, strong) CDVPlugin* contactsPlugin; - -@end -@interface CDVAddressBookAccessError : NSObject -{} -@property (assign) CDVContactError errorCode; -- (CDVAddressBookAccessError*)initWithCode:(CDVContactError)code; -@end - -typedef void (^ CDVAddressBookWorkerBlock)( - ABAddressBookRef addressBook, - CDVAddressBookAccessError* error - ); -@interface CDVAddressBookHelper : NSObject -{} - -- (void)createAddressBook:(CDVAddressBookWorkerBlock)workerBlock; -@end diff --git a/iPhone/CordovaLib/Classes/CDVContacts.m b/iPhone/CordovaLib/Classes/CDVContacts.m deleted file mode 100755 index 6cb9f08..0000000 --- a/iPhone/CordovaLib/Classes/CDVContacts.m +++ /dev/null @@ -1,593 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVContacts.h" -#import -#import "NSArray+Comparisons.h" -#import "NSDictionary+Extensions.h" -#import "CDVNotification.h" - -@implementation CDVContactsPicker - -@synthesize allowsEditing; -@synthesize callbackId; -@synthesize options; -@synthesize pickedContactDictionary; - -@end -@implementation CDVNewContactsController - -@synthesize callbackId; - -@end - -@implementation CDVContacts - -// no longer used since code gets AddressBook for each operation. -// If address book changes during save or remove operation, may get error but not much we can do about it -// If address book changes during UI creation, display or edit, we don't control any saves so no need for callback - -/*void addressBookChanged(ABAddressBookRef addressBook, CFDictionaryRef info, void* context) -{ - // note that this function is only called when another AddressBook instance modifies - // the address book, not the current one. For example, through an OTA MobileMe sync - Contacts* contacts = (Contacts*)context; - [contacts addressBookDirty]; -}*/ - -- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView -{ - self = (CDVContacts*)[super initWithWebView:(UIWebView*)theWebView]; - - /*if (self) { - addressBook = ABAddressBookCreate(); - ABAddressBookRegisterExternalChangeCallback(addressBook, addressBookChanged, self); - }*/ - - return self; -} - -// overridden to clean up Contact statics -- (void)onAppTerminate -{ - // NSLog(@"Contacts::onAppTerminate"); -} - -// iPhone only method to create a new contact through the GUI -- (void)newContact:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - - CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles - - [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errCode) { - if (addrBook == NULL) { - // permission was denied or other error just return (no error callback) - return; - } - CDVNewContactsController* npController = [[CDVNewContactsController alloc] init]; - npController.addressBook = addrBook; // a CF retaining assign - CFRelease(addrBook); - - npController.newPersonViewDelegate = self; - npController.callbackId = callbackId; - - UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:npController]; - - if ([weakSelf.viewController respondsToSelector:@selector(presentViewController:::)]) { - [weakSelf.viewController presentViewController:navController animated:YES completion:nil]; - } else { - [weakSelf.viewController presentModalViewController:navController animated:YES]; - } - }]; -} - -- (void)newPersonViewController:(ABNewPersonViewController*)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person -{ - ABRecordID recordId = kABRecordInvalidID; - CDVNewContactsController* newCP = (CDVNewContactsController*)newPersonViewController; - NSString* callbackId = newCP.callbackId; - - if (person != NULL) { - // return the contact id - recordId = ABRecordGetRecordID(person); - } - - if ([newPersonViewController respondsToSelector:@selector(presentingViewController)]) { - [[newPersonViewController presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[newPersonViewController parentViewController] dismissModalViewControllerAnimated:YES]; - } - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:recordId]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; -} - -- (void)displayContact:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - ABRecordID recordID = [[command.arguments objectAtIndex:0] intValue]; - NSDictionary* options = [command.arguments objectAtIndex:1 withDefault:[NSNull null]]; - bool bEdit = [options isKindOfClass:[NSNull class]] ? false : [options existsValue:@"true" forKey:@"allowsEditing"]; - - CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles - - [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errCode) { - if (addrBook == NULL) { - // permission was denied or other error - return error - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errCode ? errCode.errorCode:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - ABRecordRef rec = ABAddressBookGetPersonWithRecordID(addrBook, recordID); - - if (rec) { - CDVDisplayContactViewController* personController = [[CDVDisplayContactViewController alloc] init]; - personController.displayedPerson = rec; - personController.personViewDelegate = self; - personController.allowsEditing = NO; - - // create this so DisplayContactViewController will have a "back" button. - UIViewController* parentController = [[UIViewController alloc] init]; - UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:parentController]; - - [navController pushViewController:personController animated:YES]; - - if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) { - [self.viewController presentViewController:navController animated:YES completion:nil]; - } else { - [self.viewController presentModalViewController:navController animated:YES]; - } - - if (bEdit) { - // create the editing controller and push it onto the stack - ABPersonViewController* editPersonController = [[ABPersonViewController alloc] init]; - editPersonController.displayedPerson = rec; - editPersonController.personViewDelegate = self; - editPersonController.allowsEditing = YES; - [navController pushViewController:editPersonController animated:YES]; - } - } else { - // no record, return error - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - CFRelease(addrBook); - }]; -} - -- (BOOL)personViewController:(ABPersonViewController*)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person - property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue -{ - return YES; -} - -- (void)chooseContact:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* options = [command.arguments objectAtIndex:0 withDefault:[NSNull null]]; - - CDVContactsPicker* pickerController = [[CDVContactsPicker alloc] init]; - - pickerController.peoplePickerDelegate = self; - pickerController.callbackId = callbackId; - pickerController.options = options; - pickerController.pickedContactDictionary = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:kABRecordInvalidID], kW3ContactId, nil]; - pickerController.allowsEditing = (BOOL)[options existsValue : @"true" forKey : @"allowsEditing"]; - - if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) { - [self.viewController presentViewController:pickerController animated:YES completion:nil]; - } else { - [self.viewController presentModalViewController:pickerController animated:YES]; - } -} - -- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker - shouldContinueAfterSelectingPerson:(ABRecordRef)person -{ - CDVContactsPicker* picker = (CDVContactsPicker*)peoplePicker; - NSNumber* pickedId = [NSNumber numberWithInt:ABRecordGetRecordID(person)]; - - if (picker.allowsEditing) { - ABPersonViewController* personController = [[ABPersonViewController alloc] init]; - personController.displayedPerson = person; - personController.personViewDelegate = self; - personController.allowsEditing = picker.allowsEditing; - // store id so can get info in peoplePickerNavigationControllerDidCancel - picker.pickedContactDictionary = [NSDictionary dictionaryWithObjectsAndKeys:pickedId, kW3ContactId, nil]; - - [peoplePicker pushViewController:personController animated:YES]; - } else { - // Retrieve and return pickedContact information - CDVContact* pickedContact = [[CDVContact alloc] initFromABRecord:(ABRecordRef)person]; - NSArray* fields = [picker.options objectForKey:@"fields"]; - NSDictionary* returnFields = [[CDVContact class] calcReturnFields:fields]; - picker.pickedContactDictionary = [pickedContact toDictionary:returnFields]; - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:picker.pickedContactDictionary]; - [self.commandDelegate sendPluginResult:result callbackId:picker.callbackId]; - - if ([picker respondsToSelector:@selector(presentingViewController)]) { - [[picker presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[picker parentViewController] dismissModalViewControllerAnimated:YES]; - } - } - return NO; -} - -- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker - shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier -{ - return YES; -} - -- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController*)peoplePicker -{ - // return contactId or invalid if none picked - CDVContactsPicker* picker = (CDVContactsPicker*)peoplePicker; - - if (picker.allowsEditing) { - // get the info after possible edit - // if we got this far, user has already approved/ disapproved addressBook access - ABAddressBookRef addrBook = nil; -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000 - if (&ABAddressBookCreateWithOptions != NULL) { - addrBook = ABAddressBookCreateWithOptions(NULL, NULL); - } else -#endif - { - // iOS 4 & 5 - addrBook = ABAddressBookCreate(); - } - ABRecordRef person = ABAddressBookGetPersonWithRecordID(addrBook, [[picker.pickedContactDictionary objectForKey:kW3ContactId] integerValue]); - if (person) { - CDVContact* pickedContact = [[CDVContact alloc] initFromABRecord:(ABRecordRef)person]; - NSArray* fields = [picker.options objectForKey:@"fields"]; - NSDictionary* returnFields = [[CDVContact class] calcReturnFields:fields]; - picker.pickedContactDictionary = [pickedContact toDictionary:returnFields]; - } - CFRelease(addrBook); - } - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:picker.pickedContactDictionary]; - [self.commandDelegate sendPluginResult:result callbackId:picker.callbackId]; - - if ([peoplePicker respondsToSelector:@selector(presentingViewController)]) { - [[peoplePicker presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[peoplePicker parentViewController] dismissModalViewControllerAnimated:YES]; - } -} - -- (void)search:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSArray* fields = [command.arguments objectAtIndex:0]; - NSDictionary* findOptions = [command.arguments objectAtIndex:1 withDefault:[NSNull null]]; - - [self.commandDelegate runInBackground:^{ - // from Apple: Important You must ensure that an instance of ABAddressBookRef is used by only one thread. - // which is why address book is created within the dispatch queue. - // more details here: http: //blog.byadrian.net/2012/05/05/ios-addressbook-framework-and-gcd/ - CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles - // it gets uglier, block within block..... - [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errCode) { - if (addrBook == NULL) { - // permission was denied or other error - return error - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errCode ? errCode.errorCode:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - - NSArray* foundRecords = nil; - // get the findOptions values - BOOL multiple = NO; // default is false - NSString* filter = nil; - if (![findOptions isKindOfClass:[NSNull class]]) { - id value = nil; - filter = (NSString*)[findOptions objectForKey:@"filter"]; - value = [findOptions objectForKey:@"multiple"]; - if ([value isKindOfClass:[NSNumber class]]) { - // multiple is a boolean that will come through as an NSNumber - multiple = [(NSNumber*)value boolValue]; - // NSLog(@"multiple is: %d", multiple); - } - } - - NSDictionary* returnFields = [[CDVContact class] calcReturnFields:fields]; - - NSMutableArray* matches = nil; - if (!filter || [filter isEqualToString:@""]) { - // get all records - foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook); - if (foundRecords && ([foundRecords count] > 0)) { - // create Contacts and put into matches array - // doesn't make sense to ask for all records when multiple == NO but better check - int xferCount = multiple == YES ? [foundRecords count] : 1; - matches = [NSMutableArray arrayWithCapacity:xferCount]; - - for (int k = 0; k < xferCount; k++) { - CDVContact* xferContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:k]]; - [matches addObject:xferContact]; - xferContact = nil; - } - } - } else { - foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook); - matches = [NSMutableArray arrayWithCapacity:1]; - BOOL bFound = NO; - int testCount = [foundRecords count]; - - for (int j = 0; j < testCount; j++) { - CDVContact* testContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:j]]; - if (testContact) { - bFound = [testContact foundValue:filter inFields:returnFields]; - if (bFound) { - [matches addObject:testContact]; - } - testContact = nil; - } - } - } - NSMutableArray* returnContacts = [NSMutableArray arrayWithCapacity:1]; - - if ((matches != nil) && ([matches count] > 0)) { - // convert to JS Contacts format and return in callback - // - returnFields determines what properties to return - @autoreleasepool { - int count = multiple == YES ? [matches count] : 1; - - for (int i = 0; i < count; i++) { - CDVContact* newContact = [matches objectAtIndex:i]; - NSDictionary* aContact = [newContact toDictionary:returnFields]; - [returnContacts addObject:aContact]; - } - } - } - // return found contacts (array is empty if no contacts found) - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:returnContacts]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - // NSLog(@"findCallback string: %@", jsString); - - if (addrBook) { - CFRelease(addrBook); - } - }]; - }]; // end of workQueue block - - return; -} - -- (void)save:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* contactDict = [command.arguments objectAtIndex:0]; - - [self.commandDelegate runInBackground:^{ - CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles - - [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errorCode) { - CDVPluginResult* result = nil; - if (addrBook == NULL) { - // permission was denied or other error - return error - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode ? errorCode.errorCode:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - - bool bIsError = FALSE, bSuccess = FALSE; - BOOL bUpdate = NO; - CDVContactError errCode = UNKNOWN_ERROR; - CFErrorRef error; - NSNumber* cId = [contactDict valueForKey:kW3ContactId]; - CDVContact* aContact = nil; - ABRecordRef rec = nil; - if (cId && ![cId isKindOfClass:[NSNull class]]) { - rec = ABAddressBookGetPersonWithRecordID(addrBook, [cId intValue]); - if (rec) { - aContact = [[CDVContact alloc] initFromABRecord:rec]; - bUpdate = YES; - } - } - if (!aContact) { - aContact = [[CDVContact alloc] init]; - } - - bSuccess = [aContact setFromContactDict:contactDict asUpdate:bUpdate]; - if (bSuccess) { - if (!bUpdate) { - bSuccess = ABAddressBookAddRecord(addrBook, [aContact record], &error); - } - if (bSuccess) { - bSuccess = ABAddressBookSave(addrBook, &error); - } - if (!bSuccess) { // need to provide error codes - bIsError = TRUE; - errCode = IO_ERROR; - } else { - // give original dictionary back? If generate dictionary from saved contact, have no returnFields specified - // so would give back all fields (which W3C spec. indicates is not desired) - // for now (while testing) give back saved, full contact - NSDictionary* newContact = [aContact toDictionary:[CDVContact defaultFields]]; - // NSString* contactStr = [newContact JSONRepresentation]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newContact]; - } - } else { - bIsError = TRUE; - errCode = IO_ERROR; - } - CFRelease(addrBook); - - if (bIsError) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode]; - } - - if (result) { - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - }]; - }]; // end of queue -} - -- (void)remove:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSNumber* cId = [command.arguments objectAtIndex:0]; - - CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles - - [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errorCode) { - CDVPluginResult* result = nil; - if (addrBook == NULL) { - // permission was denied or other error - return error - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode ? errorCode.errorCode:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - - bool bIsError = FALSE, bSuccess = FALSE; - CDVContactError errCode = UNKNOWN_ERROR; - CFErrorRef error; - ABRecordRef rec = nil; - if (cId && ![cId isKindOfClass:[NSNull class]] && ([cId intValue] != kABRecordInvalidID)) { - rec = ABAddressBookGetPersonWithRecordID(addrBook, [cId intValue]); - if (rec) { - bSuccess = ABAddressBookRemoveRecord(addrBook, rec, &error); - if (!bSuccess) { - bIsError = TRUE; - errCode = IO_ERROR; - } else { - bSuccess = ABAddressBookSave(addrBook, &error); - if (!bSuccess) { - bIsError = TRUE; - errCode = IO_ERROR; - } else { - // set id to null - // [contactDict setObject:[NSNull null] forKey:kW3ContactId]; - // result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary: contactDict]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - // NSString* contactStr = [contactDict JSONRepresentation]; - } - } - } else { - // no record found return error - bIsError = TRUE; - errCode = UNKNOWN_ERROR; - } - } else { - // invalid contact id provided - bIsError = TRUE; - errCode = INVALID_ARGUMENT_ERROR; - } - - if (addrBook) { - CFRelease(addrBook); - } - if (bIsError) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode]; - } - if (result) { - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - }]; - return; -} - -@end - -/* ABPersonViewController does not have any UI to dismiss. Adding navigationItems to it does not work properly - * The navigationItems are lost when the app goes into the background. The solution was to create an empty - * NavController in front of the ABPersonViewController. This will cause the ABPersonViewController to have a back button. By subclassing the ABPersonViewController, we can override viewDidDisappear and take down the entire NavigationController. - */ -@implementation CDVDisplayContactViewController -@synthesize contactsPlugin; - -- (void)viewWillDisappear:(BOOL)animated -{ - [super viewWillDisappear:animated]; - - if ([self respondsToSelector:@selector(presentingViewController)]) { - [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[self parentViewController] dismissModalViewControllerAnimated:YES]; - } -} - -@end -@implementation CDVAddressBookAccessError - -@synthesize errorCode; - -- (CDVAddressBookAccessError*)initWithCode:(CDVContactError)code -{ - self = [super init]; - if (self) { - self.errorCode = code; - } - return self; -} - -@end - -@implementation CDVAddressBookHelper - -/** - * NOTE: workerBlock is responsible for releasing the addressBook that is passed to it - */ -- (void)createAddressBook:(CDVAddressBookWorkerBlock)workerBlock -{ - // TODO: this probably should be reworked - seems like the workerBlock can just create and release its own AddressBook, - // and also this important warning from (http://developer.apple.com/library/ios/#documentation/ContactData/Conceptual/AddressBookProgrammingGuideforiPhone/Chapters/BasicObjects.html): - // "Important: Instances of ABAddressBookRef cannot be used by multiple threads. Each thread must make its own instance." - ABAddressBookRef addressBook; - -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000 - if (&ABAddressBookCreateWithOptions != NULL) { - CFErrorRef error = nil; - // CFIndex status = ABAddressBookGetAuthorizationStatus(); - addressBook = ABAddressBookCreateWithOptions(NULL, &error); - // NSLog(@"addressBook access: %lu", status); - ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { - // callback can occur in background, address book must be accessed on thread it was created on - dispatch_sync(dispatch_get_main_queue(), ^{ - if (error) { - workerBlock(NULL, [[CDVAddressBookAccessError alloc] initWithCode:UNKNOWN_ERROR]); - } else if (!granted) { - workerBlock(NULL, [[CDVAddressBookAccessError alloc] initWithCode:PERMISSION_DENIED_ERROR]); - } else { - // access granted - workerBlock(addressBook, [[CDVAddressBookAccessError alloc] initWithCode:UNKNOWN_ERROR]); - } - }); - }); - } else -#endif - { - // iOS 4 or 5 no checks needed - addressBook = ABAddressBookCreate(); - workerBlock(addressBook, NULL); - } -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVDebug.h b/iPhone/CordovaLib/Classes/CDVDebug.h deleted file mode 100755 index 4a0d9f9..0000000 --- a/iPhone/CordovaLib/Classes/CDVDebug.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#ifdef DEBUG - #define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) -#else - #define DLog(...) -#endif -#define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) diff --git a/iPhone/CordovaLib/Classes/CDVDevice.h b/iPhone/CordovaLib/Classes/CDVDevice.h deleted file mode 100755 index fd6ea12..0000000 --- a/iPhone/CordovaLib/Classes/CDVDevice.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import "CDVPlugin.h" - -@interface CDVDevice : CDVPlugin -{} - -+ (NSString*)cordovaVersion; - -- (void)getDeviceInfo:(CDVInvokedUrlCommand*)command; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVDevice.m b/iPhone/CordovaLib/Classes/CDVDevice.m deleted file mode 100755 index a331b81..0000000 --- a/iPhone/CordovaLib/Classes/CDVDevice.m +++ /dev/null @@ -1,89 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#include -#include - -#import "CDV.h" - -@implementation UIDevice (ModelVersion) - -- (NSString*)modelVersion -{ - size_t size; - - sysctlbyname("hw.machine", NULL, &size, NULL, 0); - char* machine = malloc(size); - sysctlbyname("hw.machine", machine, &size, NULL, 0); - NSString* platform = [NSString stringWithUTF8String:machine]; - free(machine); - - return platform; -} - -@end - -@interface CDVDevice () {} -@end - -@implementation CDVDevice - -- (void)getDeviceInfo:(CDVInvokedUrlCommand*)command -{ - NSDictionary* deviceProperties = [self deviceProperties]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:deviceProperties]; - - /* Settings.plist - * Read the optional Settings.plist file and push these user-defined settings down into the web application. - * This can be useful for supplying build-time configuration variables down to the app to change its behavior, - * such as specifying Full / Lite version, or localization (English vs German, for instance). - */ - // TODO: turn this into an iOS only plugin - NSDictionary* temp = [CDVViewController getBundlePlist:@"Settings"]; - - if ([temp respondsToSelector:@selector(JSONString)]) { - NSLog(@"Deprecation warning: window.Setting will be removed Aug 2013. Refer to https://issues.apache.org/jira/browse/CB-2433"); - NSString* js = [NSString stringWithFormat:@"window.Settings = %@;", [temp JSONString]]; - [self.commandDelegate evalJs:js]; - } - - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -- (NSDictionary*)deviceProperties -{ - UIDevice* device = [UIDevice currentDevice]; - NSMutableDictionary* devProps = [NSMutableDictionary dictionaryWithCapacity:4]; - - [devProps setObject:[device modelVersion] forKey:@"model"]; - [devProps setObject:@"iOS" forKey:@"platform"]; - [devProps setObject:[device systemVersion] forKey:@"version"]; - [devProps setObject:[device uniqueAppInstanceIdentifier] forKey:@"uuid"]; - [devProps setObject:[[self class] cordovaVersion] forKey:@"cordova"]; - - NSDictionary* devReturn = [NSDictionary dictionaryWithDictionary:devProps]; - return devReturn; -} - -+ (NSString*)cordovaVersion -{ - return CDV_VERSION; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVEcho.h b/iPhone/CordovaLib/Classes/CDVEcho.h deleted file mode 100755 index 76a4a96..0000000 --- a/iPhone/CordovaLib/Classes/CDVEcho.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVPlugin.h" - -@interface CDVEcho : CDVPlugin -@end diff --git a/iPhone/CordovaLib/Classes/CDVEcho.m b/iPhone/CordovaLib/Classes/CDVEcho.m deleted file mode 100755 index c74990d..0000000 --- a/iPhone/CordovaLib/Classes/CDVEcho.m +++ /dev/null @@ -1,61 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVEcho.h" -#import "CDV.h" - -@implementation CDVEcho - -- (void)echo:(CDVInvokedUrlCommand*)command -{ - id message = [command.arguments objectAtIndex:0]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:message]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -- (void)echoAsyncHelper:(NSArray*)args -{ - [self.commandDelegate sendPluginResult:[args objectAtIndex:0] callbackId:[args objectAtIndex:1]]; -} - -- (void)echoAsync:(CDVInvokedUrlCommand*)command -{ - id message = [command.arguments objectAtIndex:0]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:message]; - - [self performSelector:@selector(echoAsyncHelper:) withObject:[NSArray arrayWithObjects:pluginResult, command.callbackId, nil] afterDelay:0]; -} - -- (void)echoArrayBuffer:(CDVInvokedUrlCommand*)command -{ - id message = [command.arguments objectAtIndex:0]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:message]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -- (void)echoMultiPart:(CDVInvokedUrlCommand*)command -{ - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsMultipart:command.arguments]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVExif.h b/iPhone/CordovaLib/Classes/CDVExif.h deleted file mode 100755 index 3e8adbd..0000000 --- a/iPhone/CordovaLib/Classes/CDVExif.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#ifndef CordovaLib_ExifData_h -#define CordovaLib_ExifData_h - -// exif data types -typedef enum exifDataTypes { - EDT_UBYTE = 1, // 8 bit unsigned integer - EDT_ASCII_STRING, // 8 bits containing 7 bit ASCII code, null terminated - EDT_USHORT, // 16 bit unsigned integer - EDT_ULONG, // 32 bit unsigned integer - EDT_URATIONAL, // 2 longs, first is numerator and second is denominator - EDT_SBYTE, - EDT_UNDEFINED, // 8 bits - EDT_SSHORT, - EDT_SLONG, // 32bit signed integer (2's complement) - EDT_SRATIONAL, // 2 SLONGS, first long is numerator, second is denominator - EDT_SINGLEFLOAT, - EDT_DOUBLEFLOAT -} ExifDataTypes; - -// maps integer code for exif data types to width in bytes -static const int DataTypeToWidth[] = {1,1,2,4,8,1,1,2,4,8,4,8}; - -static const int RECURSE_HORIZON = 8; -#endif diff --git a/iPhone/CordovaLib/Classes/CDVFile.h b/iPhone/CordovaLib/Classes/CDVFile.h deleted file mode 100755 index 017b066..0000000 --- a/iPhone/CordovaLib/Classes/CDVFile.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import "CDVPlugin.h" - -enum CDVFileError { - NO_ERROR = 0, - NOT_FOUND_ERR = 1, - SECURITY_ERR = 2, - ABORT_ERR = 3, - NOT_READABLE_ERR = 4, - ENCODING_ERR = 5, - NO_MODIFICATION_ALLOWED_ERR = 6, - INVALID_STATE_ERR = 7, - SYNTAX_ERR = 8, - INVALID_MODIFICATION_ERR = 9, - QUOTA_EXCEEDED_ERR = 10, - TYPE_MISMATCH_ERR = 11, - PATH_EXISTS_ERR = 12 -}; -typedef int CDVFileError; - -enum CDVFileSystemType { - TEMPORARY = 0, - PERSISTENT = 1 -}; -typedef int CDVFileSystemType; - -extern NSString* const kCDVAssetsLibraryPrefix; - -@interface CDVFile : CDVPlugin { - NSString* appDocsPath; - NSString* appLibraryPath; - NSString* appTempPath; - NSString* persistentPath; - NSString* temporaryPath; - - BOOL userHasAllowed; -} -- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath; -- (NSString*)getAppPath:(NSString*)pathFragment; -// -(NSString*) getFullPath: (NSString*)pathFragment; -- (void)requestFileSystem:(CDVInvokedUrlCommand*)command; -- (NSDictionary*)getDirectoryEntry:(NSString*)fullPath isDirectory:(BOOL)isDir; -- (void)resolveLocalFileSystemURI:(CDVInvokedUrlCommand*)command; -- (void)getDirectory:(CDVInvokedUrlCommand*)command; -- (void)getFile:(CDVInvokedUrlCommand*)command; -- (void)getParent:(CDVInvokedUrlCommand*)command; -- (void)getMetadata:(CDVInvokedUrlCommand*)command; -- (void)removeRecursively:(CDVInvokedUrlCommand*)command; -- (void)remove:(CDVInvokedUrlCommand*)command; -- (CDVPluginResult*)doRemove:(NSString*)fullPath; -- (void)copyTo:(CDVInvokedUrlCommand*)command; -- (void)moveTo:(CDVInvokedUrlCommand*)command; -- (BOOL)canCopyMoveSrc:(NSString*)src ToDestination:(NSString*)dest; -- (void)doCopyMove:(CDVInvokedUrlCommand*)command isCopy:(BOOL)bCopy; -// - (void) toURI:(CDVInvokedUrlCommand*)command; -- (void)getFileMetadata:(CDVInvokedUrlCommand*)command; -- (void)readEntries:(CDVInvokedUrlCommand*)command; - -- (void)readAsText:(CDVInvokedUrlCommand*)command; -- (void)readAsDataURL:(CDVInvokedUrlCommand*)command; -- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command; -- (NSString*)getMimeTypeFromPath:(NSString*)fullPath; -- (void)write:(CDVInvokedUrlCommand*)command; -- (void)testFileExists:(CDVInvokedUrlCommand*)command; -- (void)testDirectoryExists:(CDVInvokedUrlCommand*)command; -// - (void) createDirectory:(CDVInvokedUrlCommand*)command; -// - (void) deleteDirectory:(CDVInvokedUrlCommand*)command; -// - (void) deleteFile:(CDVInvokedUrlCommand*)command; -- (void)getFreeDiskSpace:(CDVInvokedUrlCommand*)command; -- (void)truncate:(CDVInvokedUrlCommand*)command; - -// - (BOOL) fileExists:(NSString*)fileName; -// - (BOOL) directoryExists:(NSString*)dirName; -- (void)writeToFile:(NSString*)fileName withData:(NSData*)data append:(BOOL)shouldAppend callback:(NSString*)callbackId; -- (void)writeToFile:(NSString*)fileName withString:(NSString*)data encoding:(NSStringEncoding)encoding append:(BOOL)shouldAppend callback:(NSString*)callbackId; -- (unsigned long long)truncateFile:(NSString*)filePath atPosition:(unsigned long long)pos; - -@property (nonatomic, strong) NSString* appDocsPath; -@property (nonatomic, strong) NSString* appLibraryPath; -@property (nonatomic, strong) NSString* appTempPath; -@property (nonatomic, strong) NSString* persistentPath; -@property (nonatomic, strong) NSString* temporaryPath; -@property BOOL userHasAllowed; - -@end - -#define kW3FileTemporary @"temporary" -#define kW3FilePersistent @"persistent" diff --git a/iPhone/CordovaLib/Classes/CDVFile.m b/iPhone/CordovaLib/Classes/CDVFile.m deleted file mode 100755 index 9487dd4..0000000 --- a/iPhone/CordovaLib/Classes/CDVFile.m +++ /dev/null @@ -1,1426 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVFile.h" -#import "NSArray+Comparisons.h" -#import "NSDictionary+Extensions.h" -#import "CDVJSON.h" -#import "NSData+Base64.h" -#import -#import -#import -#import -#import "CDVAvailability.h" -#import "sys/xattr.h" - -extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import)); - -#ifndef __IPHONE_5_1 - NSString* const NSURLIsExcludedFromBackupKey = @"NSURLIsExcludedFromBackupKey"; -#endif - -NSString* const kCDVAssetsLibraryPrefix = @"assets-library://"; - -@implementation CDVFile - -@synthesize appDocsPath, appLibraryPath, appTempPath, persistentPath, temporaryPath, userHasAllowed; - -- (id)initWithWebView:(UIWebView*)theWebView -{ - self = (CDVFile*)[super initWithWebView:theWebView]; - if (self) { - // get the documents directory path - NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - self.appDocsPath = [paths objectAtIndex:0]; - - paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); - self.appLibraryPath = [paths objectAtIndex:0]; - - self.appTempPath = [NSTemporaryDirectory()stringByStandardizingPath]; // remove trailing slash from NSTemporaryDirectory() - - self.persistentPath = [NSString stringWithFormat:@"/%@", [self.appDocsPath lastPathComponent]]; - self.temporaryPath = [NSString stringWithFormat:@"/%@", [self.appTempPath lastPathComponent]]; - // NSLog(@"docs: %@ - temp: %@", self.appDocsPath, self.appTempPath); - } - - return self; -} - -- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath -{ - NSFileManager* fMgr = [[NSFileManager alloc] init]; - - NSError* __autoreleasing pError = nil; - - NSDictionary* pDict = [fMgr attributesOfFileSystemForPath:appPath error:&pError]; - NSNumber* pNumAvail = (NSNumber*)[pDict objectForKey:NSFileSystemFreeSize]; - - return pNumAvail; -} - -// figure out if the pathFragment represents a persistent of temporary directory and return the full application path. -// returns nil if path is not persistent or temporary -- (NSString*)getAppPath:(NSString*)pathFragment -{ - NSString* appPath = nil; - NSRange rangeP = [pathFragment rangeOfString:self.persistentPath]; - NSRange rangeT = [pathFragment rangeOfString:self.temporaryPath]; - - if ((rangeP.location != NSNotFound) && (rangeT.location != NSNotFound)) { - // we found both in the path, return whichever one is first - if (rangeP.length < rangeT.length) { - appPath = self.appDocsPath; - } else { - appPath = self.appTempPath; - } - } else if (rangeP.location != NSNotFound) { - appPath = self.appDocsPath; - } else if (rangeT.location != NSNotFound) { - appPath = self.appTempPath; - } - return appPath; -} - -/* get the full path to this resource - * IN - * NSString* pathFragment - full Path from File or Entry object (includes system path info) - * OUT - * NSString* fullPath - full iOS path to this resource, nil if not found - */ - -/* Was here in order to NOT have to return full path, but W3C synchronous DirectoryEntry.toURI() killed that idea since I can't call into iOS to - * resolve full URI. Leaving this code here in case W3C spec changes. --(NSString*) getFullPath: (NSString*)pathFragment -{ - return pathFragment; - NSString* fullPath = nil; - NSString *appPath = [ self getAppPath: pathFragment]; - if (appPath){ - - // remove last component from appPath - NSRange range = [appPath rangeOfString:@"/" options: NSBackwardsSearch]; - NSString* newPath = [appPath substringToIndex:range.location]; - // add pathFragment to get test Path - fullPath = [newPath stringByAppendingPathComponent:pathFragment]; - } - return fullPath; -} */ - -/* Request the File System info - * - * IN: - * arguments[0] - type (number as string) - * TEMPORARY = 0, PERSISTENT = 1; - * arguments[1] - size - * - * OUT: - * Dictionary representing FileSystem object - * name - the human readable directory name - * root = DirectoryEntry object - * bool isDirectory - * bool isFile - * string name - * string fullPath - * fileSystem = FileSystem object - !! ignored because creates circular reference !! - */ - -- (void)requestFileSystem:(CDVInvokedUrlCommand*)command -{ - NSArray* arguments = command.arguments; - - // arguments - NSString* strType = [arguments objectAtIndex:0]; - unsigned long long size = [[arguments objectAtIndex:1] longLongValue]; - - int type = [strType intValue]; - CDVPluginResult* result = nil; - - if (type > 1) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:NOT_FOUND_ERR]; - NSLog(@"iOS only supports TEMPORARY and PERSISTENT file systems"); - } else { - // NSString* fullPath = [NSString stringWithFormat:@"/%@", (type == 0 ? [self.appTempPath lastPathComponent] : [self.appDocsPath lastPathComponent])]; - NSString* fullPath = (type == 0 ? self.appTempPath : self.appDocsPath); - // check for avail space for size request - NSNumber* pNumAvail = [self checkFreeDiskSpace:fullPath]; - // NSLog(@"Free space: %@", [NSString stringWithFormat:@"%qu", [ pNumAvail unsignedLongLongValue ]]); - if (pNumAvail && ([pNumAvail unsignedLongLongValue] < size)) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:QUOTA_EXCEEDED_ERR]; - } else { - NSMutableDictionary* fileSystem = [NSMutableDictionary dictionaryWithCapacity:2]; - [fileSystem setObject:(type == TEMPORARY ? kW3FileTemporary : kW3FilePersistent) forKey:@"name"]; - NSDictionary* dirEntry = [self getDirectoryEntry:fullPath isDirectory:YES]; - [fileSystem setObject:dirEntry forKey:@"root"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem]; - } - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* Creates a dictionary representing an Entry Object - * - * IN: - * NSString* fullPath of the entry - * FileSystem type - * BOOL isDirectory - YES if this is a directory, NO if is a file - * OUT: - * NSDictionary* - Entry object - * bool as NSNumber isDirectory - * bool as NSNumber isFile - * NSString* name - last part of path - * NSString* fullPath - * fileSystem = FileSystem object - !! ignored because creates circular reference FileSystem contains DirectoryEntry which contains FileSystem.....!! - */ -- (NSDictionary*)getDirectoryEntry:(NSString*)fullPath isDirectory:(BOOL)isDir -{ - NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:4]; - NSString* lastPart = [fullPath lastPathComponent]; - - [dirEntry setObject:[NSNumber numberWithBool:!isDir] forKey:@"isFile"]; - [dirEntry setObject:[NSNumber numberWithBool:isDir] forKey:@"isDirectory"]; - // NSURL* fileUrl = [NSURL fileURLWithPath:fullPath]; - // [dirEntry setObject: [fileUrl absoluteString] forKey: @"fullPath"]; - [dirEntry setObject:fullPath forKey:@"fullPath"]; - [dirEntry setObject:lastPart forKey:@"name"]; - - return dirEntry; -} - -/* - * Given a URI determine the File System information associated with it and return an appropriate W3C entry object - * IN - * NSString* fileURI - currently requires full file URI - * OUT - * Entry object - * bool isDirectory - * bool isFile - * string name - * string fullPath - * fileSystem = FileSystem object - !! ignored because creates circular reference FileSystem contains DirectoryEntry which contains FileSystem.....!! - */ -- (void)resolveLocalFileSystemURI:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* inputUri = [command.arguments objectAtIndex:0]; - - // don't know if string is encoded or not so unescape - NSString* cleanUri = [inputUri stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - // now escape in order to create URL - NSString* strUri = [cleanUri stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSURL* testUri = [NSURL URLWithString:strUri]; - CDVPluginResult* result = nil; - - if (!testUri) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR]; - } else if ([testUri isFileURL]) { - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - NSString* path = [testUri path]; - // NSLog(@"url path: %@", path); - BOOL isDir = NO; - // see if exists and is file or dir - BOOL bExists = [fileMgr fileExistsAtPath:path isDirectory:&isDir]; - if (bExists) { - // see if it contains docs path - NSRange range = [path rangeOfString:self.appDocsPath]; - NSString* foundFullPath = nil; - // there's probably an api or easier way to figure out the path type but I can't find it! - if ((range.location != NSNotFound) && (range.length == [self.appDocsPath length])) { - foundFullPath = self.appDocsPath; - } else { - // see if it contains the temp path - range = [path rangeOfString:self.appTempPath]; - if ((range.location != NSNotFound) && (range.length == [self.appTempPath length])) { - foundFullPath = self.appTempPath; - } - } - if (foundFullPath == nil) { - // error SECURITY_ERR - not one of the two paths types supported - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:SECURITY_ERR]; - } else { - NSDictionary* fileSystem = [self getDirectoryEntry:path isDirectory:isDir]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem]; - } - } else { - // return NOT_FOUND_ERR - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - } - } else if ([strUri hasPrefix:@"assets-library://"]) { - NSDictionary* fileSystem = [self getDirectoryEntry:strUri isDirectory:NO]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR]; - } - - if (result != nil) { - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } -} - -/* Part of DirectoryEntry interface, creates or returns the specified directory - * IN: - * NSString* fullPath - full path for this directory - * NSString* path - directory to be created/returned; may be full path or relative path - * NSDictionary* - Flags object - * boolean as NSNumber create - - * if create is true and directory does not exist, create dir and return directory entry - * if create is true and exclusive is true and directory does exist, return error - * if create is false and directory does not exist, return error - * if create is false and the path represents a file, return error - * boolean as NSNumber exclusive - used in conjunction with create - * if exclusive is true and create is true - specifies failure if directory already exists - * - * - */ -- (void)getDirectory:(CDVInvokedUrlCommand*)command -{ - NSMutableArray* arguments = [NSMutableArray arrayWithArray:command.arguments]; - NSMutableDictionary* options = nil; - - if ([arguments count] >= 3) { - options = [arguments objectAtIndex:2 withDefault:nil]; - } - // add getDir to options and call getFile() - if (options != nil) { - options = [NSMutableDictionary dictionaryWithDictionary:options]; - } else { - options = [NSMutableDictionary dictionaryWithCapacity:1]; - } - [options setObject:[NSNumber numberWithInt:1] forKey:@"getDir"]; - if ([arguments count] >= 3) { - [arguments replaceObjectAtIndex:2 withObject:options]; - } else { - [arguments addObject:options]; - } - CDVInvokedUrlCommand* subCommand = - [[CDVInvokedUrlCommand alloc] initWithArguments:arguments - callbackId:command.callbackId - className:command.className - methodName:command.methodName]; - - [self getFile:subCommand]; -} - -/* Part of DirectoryEntry interface, creates or returns the specified file - * IN: - * NSString* fullPath - full path for this file - * NSString* path - file to be created/returned; may be full path or relative path - * NSDictionary* - Flags object - * boolean as NSNumber create - - * if create is true and file does not exist, create file and return File entry - * if create is true and exclusive is true and file does exist, return error - * if create is false and file does not exist, return error - * if create is false and the path represents a directory, return error - * boolean as NSNumber exclusive - used in conjunction with create - * if exclusive is true and create is true - specifies failure if file already exists - * - * - */ -- (void)getFile:(CDVInvokedUrlCommand*)command -{ - // arguments are URL encoded - NSString* fullPath = [command.arguments objectAtIndex:0]; - NSString* requestedPath = [command.arguments objectAtIndex:1]; - NSDictionary* options = [command.arguments objectAtIndex:2 withDefault:nil]; - - // return unsupported result for assets-library URLs - if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"getFile not supported for assets-library URLs."]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - CDVPluginResult* result = nil; - BOOL bDirRequest = NO; - BOOL create = NO; - BOOL exclusive = NO; - int errorCode = 0; // !!! risky - no error code currently defined for 0 - - if ([options valueForKeyIsNumber:@"create"]) { - create = [(NSNumber*)[options valueForKey:@"create"] boolValue]; - } - if ([options valueForKeyIsNumber:@"exclusive"]) { - exclusive = [(NSNumber*)[options valueForKey:@"exclusive"] boolValue]; - } - - if ([options valueForKeyIsNumber:@"getDir"]) { - // this will not exist for calls directly to getFile but will have been set by getDirectory before calling this method - bDirRequest = [(NSNumber*)[options valueForKey:@"getDir"] boolValue]; - } - // see if the requested path has invalid characters - should we be checking for more than just ":"? - if ([requestedPath rangeOfString:@":"].location != NSNotFound) { - errorCode = ENCODING_ERR; - } else { - // was full or relative path provided? - NSRange range = [requestedPath rangeOfString:fullPath]; - BOOL bIsFullPath = range.location != NSNotFound; - - NSString* reqFullPath = nil; - - if (!bIsFullPath) { - reqFullPath = [fullPath stringByAppendingPathComponent:requestedPath]; - } else { - reqFullPath = requestedPath; - } - - // NSLog(@"reqFullPath = %@", reqFullPath); - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - BOOL bIsDir; - BOOL bExists = [fileMgr fileExistsAtPath:reqFullPath isDirectory:&bIsDir]; - if (bExists && (create == NO) && (bIsDir == !bDirRequest)) { - // path exists and is of requested type - return TYPE_MISMATCH_ERR - errorCode = TYPE_MISMATCH_ERR; - } else if (!bExists && (create == NO)) { - // path does not exist and create is false - return NOT_FOUND_ERR - errorCode = NOT_FOUND_ERR; - } else if (bExists && (create == YES) && (exclusive == YES)) { - // file/dir already exists and exclusive and create are both true - return PATH_EXISTS_ERR - errorCode = PATH_EXISTS_ERR; - } else { - // if bExists and create == YES - just return data - // if bExists and create == NO - just return data - // if !bExists and create == YES - create and return data - BOOL bSuccess = YES; - NSError __autoreleasing* pError = nil; - if (!bExists && (create == YES)) { - if (bDirRequest) { - // create the dir - bSuccess = [fileMgr createDirectoryAtPath:reqFullPath withIntermediateDirectories:NO attributes:nil error:&pError]; - } else { - // create the empty file - bSuccess = [fileMgr createFileAtPath:reqFullPath contents:nil attributes:nil]; - } - } - if (!bSuccess) { - errorCode = ABORT_ERR; - if (pError) { - NSLog(@"error creating directory: %@", [pError localizedDescription]); - } - } else { - // NSLog(@"newly created file/dir (%@) exists: %d", reqFullPath, [fileMgr fileExistsAtPath:reqFullPath]); - // file existed or was created - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getDirectoryEntry:reqFullPath isDirectory:bDirRequest]]; - } - } // are all possible conditions met? - } - - if (errorCode > 0) { - // create error callback - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* - * Look up the parent Entry containing this Entry. - * If this Entry is the root of its filesystem, its parent is itself. - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * NSMutableDictionary* options - * empty - */ -- (void)getParent:(CDVInvokedUrlCommand*)command -{ - // arguments are URL encoded - NSString* fullPath = [command.arguments objectAtIndex:0]; - - // we don't (yet?) support getting the parent of an asset - if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_READABLE_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - CDVPluginResult* result = nil; - NSString* newPath = nil; - - if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]) { - // return self - newPath = fullPath; - } else { - // since this call is made from an existing Entry object - the parent should already exist so no additional error checking - // remove last component and return Entry - NSRange range = [fullPath rangeOfString:@"/" options:NSBackwardsSearch]; - newPath = [fullPath substringToIndex:range.location]; - } - - if (newPath) { - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - BOOL bIsDir; - BOOL bExists = [fileMgr fileExistsAtPath:newPath isDirectory:&bIsDir]; - if (bExists) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getDirectoryEntry:newPath isDirectory:bIsDir]]; - } - } - if (!result) { - // invalid path or file does not exist - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* - * get MetaData of entry - * Currently MetaData only includes modificationTime. - */ -- (void)getMetadata:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* argPath = [command.arguments objectAtIndex:0]; - __block CDVPluginResult* result = nil; - - if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) { - // In this case, we need to use an asynchronous method to retrieve the file. - // Because of this, we can't just assign to `result` and send it at the end of the method. - // Instead, we return after calling the asynchronous method and send `result` in each of the blocks. - ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { - if (asset) { - // We have the asset! Retrieve the metadata and send it off. - NSDate* date = [asset valueForProperty:ALAssetPropertyDate]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:[date timeIntervalSince1970] * 1000]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } else { - // We couldn't find the asset. Send the appropriate error. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } - }; - // TODO(maxw): Consider making this a class variable since it's the same every time. - ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) { - // Retrieving the asset failed for some reason. Send the appropriate error. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }; - - ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; - [assetsLibrary assetForURL:[NSURL URLWithString:argPath] resultBlock:resultBlock failureBlock:failureBlock]; - return; - } - - NSString* testPath = argPath; // [self getFullPath: argPath]; - - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - NSError* __autoreleasing error = nil; - - NSDictionary* fileAttribs = [fileMgr attributesOfItemAtPath:testPath error:&error]; - - if (fileAttribs) { - NSDate* modDate = [fileAttribs fileModificationDate]; - if (modDate) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:[modDate timeIntervalSince1970] * 1000]; - } - } else { - // didn't get fileAttribs - CDVFileError errorCode = ABORT_ERR; - NSLog(@"error getting metadata: %@", [error localizedDescription]); - if ([error code] == NSFileNoSuchFileError) { - errorCode = NOT_FOUND_ERR; - } - // log [NSNumber numberWithDouble: theMessage] objCtype to see what it returns - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode]; - } - if (!result) { - // invalid path or file does not exist - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* - * set MetaData of entry - * Currently we only support "com.apple.MobileBackup" (boolean) - */ -- (void)setMetadata:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* filePath = [command.arguments objectAtIndex:0]; - NSDictionary* options = [command.arguments objectAtIndex:1 withDefault:nil]; - CDVPluginResult* result = nil; - BOOL ok = NO; - - // setMetadata doesn't make sense for asset library files - if (![filePath hasPrefix:kCDVAssetsLibraryPrefix]) { - // we only care about this iCloud key for now. - // set to 1/true to skip backup, set to 0/false to back it up (effectively removing the attribute) - NSString* iCloudBackupExtendedAttributeKey = @"com.apple.MobileBackup"; - id iCloudBackupExtendedAttributeValue = [options objectForKey:iCloudBackupExtendedAttributeKey]; - - if ((iCloudBackupExtendedAttributeValue != nil) && [iCloudBackupExtendedAttributeValue isKindOfClass:[NSNumber class]]) { - if (IsAtLeastiOSVersion(@"5.1")) { - NSURL* url = [NSURL fileURLWithPath:filePath]; - NSError* __autoreleasing error = nil; - - ok = [url setResourceValue:[NSNumber numberWithBool:[iCloudBackupExtendedAttributeValue boolValue]] forKey:NSURLIsExcludedFromBackupKey error:&error]; - } else { // below 5.1 (deprecated - only really supported in 5.01) - u_int8_t value = [iCloudBackupExtendedAttributeValue intValue]; - if (value == 0) { // remove the attribute (allow backup, the default) - ok = (removexattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], 0) == 0); - } else { // set the attribute (skip backup) - ok = (setxattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], &value, sizeof(value), 0, 0) == 0); - } - } - } - } - - if (ok) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* removes the directory or file entry - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * - * returns NO_MODIFICATION_ALLOWED_ERR if is top level directory or no permission to delete dir - * returns INVALID_MODIFICATION_ERR if is non-empty dir or asset library file - * returns NOT_FOUND_ERR if file or dir is not found -*/ -- (void)remove:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* fullPath = [command.arguments objectAtIndex:0]; - CDVPluginResult* result = nil; - CDVFileError errorCode = 0; // !! 0 not currently defined - - // return error for assets-library URLs - if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { - errorCode = INVALID_MODIFICATION_ERR; - } else if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]) { - // error if try to remove top level (documents or tmp) dir - errorCode = NO_MODIFICATION_ALLOWED_ERR; - } else { - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - BOOL bIsDir = NO; - BOOL bExists = [fileMgr fileExistsAtPath:fullPath isDirectory:&bIsDir]; - if (!bExists) { - errorCode = NOT_FOUND_ERR; - } - if (bIsDir && ([[fileMgr contentsOfDirectoryAtPath:fullPath error:nil] count] != 0)) { - // dir is not empty - errorCode = INVALID_MODIFICATION_ERR; - } - } - if (errorCode > 0) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } else { - // perform actual remove - result = [self doRemove:fullPath]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* recursively removes the directory - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * - * returns NO_MODIFICATION_ALLOWED_ERR if is top level directory or no permission to delete dir - * returns NOT_FOUND_ERR if file or dir is not found - */ -- (void)removeRecursively:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* fullPath = [command.arguments objectAtIndex:0]; - - // return unsupported result for assets-library URLs - if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"removeRecursively not supported for assets-library URLs."]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - CDVPluginResult* result = nil; - - // error if try to remove top level (documents or tmp) dir - if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR]; - } else { - result = [self doRemove:fullPath]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* remove the file or directory (recursively) - * IN: - * NSString* fullPath - the full path to the file or directory to be removed - * NSString* callbackId - * called from remove and removeRecursively - check all pubic api specific error conditions (dir not empty, etc) before calling - */ - -- (CDVPluginResult*)doRemove:(NSString*)fullPath -{ - CDVPluginResult* result = nil; - BOOL bSuccess = NO; - NSError* __autoreleasing pError = nil; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - - @try { - bSuccess = [fileMgr removeItemAtPath:fullPath error:&pError]; - if (bSuccess) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - // see if we can give a useful error - CDVFileError errorCode = ABORT_ERR; - NSLog(@"error getting metadata: %@", [pError localizedDescription]); - if ([pError code] == NSFileNoSuchFileError) { - errorCode = NOT_FOUND_ERR; - } else if ([pError code] == NSFileWriteNoPermissionError) { - errorCode = NO_MODIFICATION_ALLOWED_ERR; - } - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - } @catch(NSException* e) { // NSInvalidArgumentException if path is . or .. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:SYNTAX_ERR]; - } - - return result; -} - -- (void)copyTo:(CDVInvokedUrlCommand*)command -{ - [self doCopyMove:command isCopy:YES]; -} - -- (void)moveTo:(CDVInvokedUrlCommand*)command -{ - [self doCopyMove:command isCopy:NO]; -} - -/** - * Helper function to check to see if the user attempted to copy an entry into its parent without changing its name, - * or attempted to copy a directory into a directory that it contains directly or indirectly. - * - * IN: - * NSString* srcDir - * NSString* destinationDir - * OUT: - * YES copy/ move is allows - * NO move is onto itself - */ -- (BOOL)canCopyMoveSrc:(NSString*)src ToDestination:(NSString*)dest -{ - // This weird test is to determine if we are copying or moving a directory into itself. - // Copy /Documents/myDir to /Documents/myDir-backup is okay but - // Copy /Documents/myDir to /Documents/myDir/backup not okay - BOOL copyOK = YES; - NSRange range = [dest rangeOfString:src]; - - if (range.location != NSNotFound) { - NSRange testRange = {range.length - 1, ([dest length] - range.length)}; - NSRange resultRange = [dest rangeOfString:@"/" options:0 range:testRange]; - if (resultRange.location != NSNotFound) { - copyOK = NO; - } - } - return copyOK; -} - -/* Copy/move a file or directory to a new location - * IN: - * NSArray* arguments - * 0 - NSString* fullPath of entry - * 1 - NSString* newName the new name of the entry, defaults to the current name - * NSMutableDictionary* options - DirectoryEntry to which to copy the entry - * BOOL - bCopy YES if copy, NO if move - * - */ -- (void)doCopyMove:(CDVInvokedUrlCommand*)command isCopy:(BOOL)bCopy -{ - NSArray* arguments = command.arguments; - - // arguments - NSString* srcFullPath = [arguments objectAtIndex:0]; - NSString* destRootPath = [arguments objectAtIndex:1]; - // optional argument - NSString* newName = ([arguments count] > 2) ? [arguments objectAtIndex:2] : [srcFullPath lastPathComponent]; // use last component from appPath if new name not provided - - __block CDVPluginResult* result = nil; - CDVFileError errCode = 0; // !! Currently 0 is not defined, use this to signal error !! - - /*NSString* destRootPath = nil; - NSString* key = @"fullPath"; - if([options valueForKeyIsString:key]){ - destRootPath = [options objectForKey:@"fullPath"]; - }*/ - - if (!destRootPath) { - // no destination provided - errCode = NOT_FOUND_ERR; - } else if ([newName rangeOfString:@":"].location != NSNotFound) { - // invalid chars in new name - errCode = ENCODING_ERR; - } else { - NSString* newFullPath = [destRootPath stringByAppendingPathComponent:newName]; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - if ([newFullPath isEqualToString:srcFullPath]) { - // source and destination can not be the same - errCode = INVALID_MODIFICATION_ERR; - } else if ([srcFullPath hasPrefix:kCDVAssetsLibraryPrefix]) { - if (bCopy) { - // Copying (as opposed to moving) an assets library file is okay. - // In this case, we need to use an asynchronous method to retrieve the file. - // Because of this, we can't just assign to `result` and send it at the end of the method. - // Instead, we return after calling the asynchronous method and send `result` in each of the blocks. - ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { - if (asset) { - // We have the asset! Get the data and try to copy it over. - if (![fileMgr fileExistsAtPath:destRootPath]) { - // The destination directory doesn't exist. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } else if ([fileMgr fileExistsAtPath:newFullPath]) { - // A file already exists at the destination path. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:PATH_EXISTS_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - // We're good to go! Write the file to the new destination. - ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; - Byte* buffer = (Byte*)malloc([assetRepresentation size]); - NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil]; - NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES]; - [data writeToFile:newFullPath atomically:YES]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getDirectoryEntry:newFullPath isDirectory:NO]]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } else { - // We couldn't find the asset. Send the appropriate error. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } - }; - ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) { - // Retrieving the asset failed for some reason. Send the appropriate error. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }; - - ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; - [assetsLibrary assetForURL:[NSURL URLWithString:srcFullPath] resultBlock:resultBlock failureBlock:failureBlock]; - return; - } else { - // Moving an assets library file is not doable, since we can't remove it. - errCode = INVALID_MODIFICATION_ERR; - } - } else { - BOOL bSrcIsDir = NO; - BOOL bDestIsDir = NO; - BOOL bNewIsDir = NO; - BOOL bSrcExists = [fileMgr fileExistsAtPath:srcFullPath isDirectory:&bSrcIsDir]; - BOOL bDestExists = [fileMgr fileExistsAtPath:destRootPath isDirectory:&bDestIsDir]; - BOOL bNewExists = [fileMgr fileExistsAtPath:newFullPath isDirectory:&bNewIsDir]; - if (!bSrcExists || !bDestExists) { - // the source or the destination root does not exist - errCode = NOT_FOUND_ERR; - } else if (bSrcIsDir && (bNewExists && !bNewIsDir)) { - // can't copy/move dir to file - errCode = INVALID_MODIFICATION_ERR; - } else { // no errors yet - NSError* __autoreleasing error = nil; - BOOL bSuccess = NO; - if (bCopy) { - if (bSrcIsDir && ![self canCopyMoveSrc:srcFullPath ToDestination:newFullPath] /*[newFullPath hasPrefix:srcFullPath]*/) { - // can't copy dir into self - errCode = INVALID_MODIFICATION_ERR; - } else if (bNewExists) { - // the full destination should NOT already exist if a copy - errCode = PATH_EXISTS_ERR; - } else { - bSuccess = [fileMgr copyItemAtPath:srcFullPath toPath:newFullPath error:&error]; - } - } else { // move - // iOS requires that destination must not exist before calling moveTo - // is W3C INVALID_MODIFICATION_ERR error if destination dir exists and has contents - // - if (!bSrcIsDir && (bNewExists && bNewIsDir)) { - // can't move a file to directory - errCode = INVALID_MODIFICATION_ERR; - } else if (bSrcIsDir && ![self canCopyMoveSrc:srcFullPath ToDestination:newFullPath]) { // [newFullPath hasPrefix:srcFullPath]){ - // can't move a dir into itself - errCode = INVALID_MODIFICATION_ERR; - } else if (bNewExists) { - if (bNewIsDir && ([[fileMgr contentsOfDirectoryAtPath:newFullPath error:NULL] count] != 0)) { - // can't move dir to a dir that is not empty - errCode = INVALID_MODIFICATION_ERR; - newFullPath = nil; // so we won't try to move - } else { - // remove destination so can perform the moveItemAtPath - bSuccess = [fileMgr removeItemAtPath:newFullPath error:NULL]; - if (!bSuccess) { - errCode = INVALID_MODIFICATION_ERR; // is this the correct error? - newFullPath = nil; - } - } - } else if (bNewIsDir && [newFullPath hasPrefix:srcFullPath]) { - // can't move a directory inside itself or to any child at any depth; - errCode = INVALID_MODIFICATION_ERR; - newFullPath = nil; - } - - if (newFullPath != nil) { - bSuccess = [fileMgr moveItemAtPath:srcFullPath toPath:newFullPath error:&error]; - } - } - if (bSuccess) { - // should verify it is there and of the correct type??? - NSDictionary* newEntry = [self getDirectoryEntry:newFullPath isDirectory:bSrcIsDir]; // should be the same type as source - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newEntry]; - } else { - errCode = INVALID_MODIFICATION_ERR; // catch all - if (error) { - if (([error code] == NSFileReadUnknownError) || ([error code] == NSFileReadTooLargeError)) { - errCode = NOT_READABLE_ERR; - } else if ([error code] == NSFileWriteOutOfSpaceError) { - errCode = QUOTA_EXCEEDED_ERR; - } else if ([error code] == NSFileWriteNoPermissionError) { - errCode = NO_MODIFICATION_ALLOWED_ERR; - } - } - } - } - } - } - if (errCode > 0) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errCode]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* return the URI to the entry - * IN: - * NSArray* arguments - * 0 - NSString* fullPath of entry - * 1 - desired mime type of entry - ignored - always returns file:// - */ - -/* Not needed since W3C toURI is synchronous. Leaving code here for now in case W3C spec changes..... -- (void) toURI:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSString* argPath = [command.arguments objectAtIndex:0]; - PluginResult* result = nil; - NSString* jsString = nil; - - NSString* fullPath = [self getFullPath: argPath]; - if (fullPath) { - // do we need to make sure the file actually exists? - // create file uri - NSString* strUri = [fullPath stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; - NSURL* fileUrl = [NSURL fileURLWithPath:strUri]; - if (fileUrl) { - result = [PluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: [fileUrl absoluteString]]; - jsString = [result toSuccessCallbackString:callbackId]; - } // else NOT_FOUND_ERR - } - if(!jsString) { - // was error - result = [PluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: NOT_FOUND_ERR cast: @"window.localFileSystem._castError"]; - jsString = [result toErrorCallbackString:callbackId]; - } - - [self writeJavascript:jsString]; -}*/ -- (void)getFileMetadata:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* argPath = [command.arguments objectAtIndex:0]; - - __block CDVPluginResult* result = nil; - - NSString* fullPath = argPath; // [self getFullPath: argPath]; - - if (fullPath) { - if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { - // In this case, we need to use an asynchronous method to retrieve the file. - // Because of this, we can't just assign to `result` and send it at the end of the method. - // Instead, we return after calling the asynchronous method and send `result` in each of the blocks. - ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { - if (asset) { - // We have the asset! Populate the dictionary and send it off. - NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5]; - ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; - [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[assetRepresentation size]] forKey:@"size"]; - [fileInfo setObject:argPath forKey:@"fullPath"]; - NSString* filename = [assetRepresentation filename]; - [fileInfo setObject:filename forKey:@"name"]; - [fileInfo setObject:[self getMimeTypeFromPath:filename] forKey:@"type"]; - NSDate* creationDate = [asset valueForProperty:ALAssetPropertyDate]; - NSNumber* msDate = [NSNumber numberWithDouble:[creationDate timeIntervalSince1970] * 1000]; - [fileInfo setObject:msDate forKey:@"lastModifiedDate"]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } else { - // We couldn't find the asset. Send the appropriate error. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } - }; - ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) { - // Retrieving the asset failed for some reason. Send the appropriate error. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }; - - ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; - [assetsLibrary assetForURL:[NSURL URLWithString:argPath] resultBlock:resultBlock failureBlock:failureBlock]; - return; - } else { - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - BOOL bIsDir = NO; - // make sure it exists and is not a directory - BOOL bExists = [fileMgr fileExistsAtPath:fullPath isDirectory:&bIsDir]; - if (!bExists || bIsDir) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - } else { - // create dictionary of file info - NSError* __autoreleasing error = nil; - NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:fullPath error:&error]; - NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5]; - [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[fileAttrs fileSize]] forKey:@"size"]; - [fileInfo setObject:argPath forKey:@"fullPath"]; - [fileInfo setObject:@"" forKey:@"type"]; // can't easily get the mimetype unless create URL, send request and read response so skipping - [fileInfo setObject:[argPath lastPathComponent] forKey:@"name"]; - NSDate* modDate = [fileAttrs fileModificationDate]; - NSNumber* msDate = [NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000]; - [fileInfo setObject:msDate forKey:@"lastModifiedDate"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]; - } - } - } - if (!result) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_INSTANTIATION_EXCEPTION]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -- (void)readEntries:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* fullPath = [command.arguments objectAtIndex:0]; - - // return unsupported result for assets-library URLs - if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"readEntries not supported for assets-library URLs."]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - CDVPluginResult* result = nil; - - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - NSError* __autoreleasing error = nil; - NSArray* contents = [fileMgr contentsOfDirectoryAtPath:fullPath error:&error]; - - if (contents) { - NSMutableArray* entries = [NSMutableArray arrayWithCapacity:1]; - if ([contents count] > 0) { - // create an Entry (as JSON) for each file/dir - for (NSString* name in contents) { - // see if is dir or file - NSString* entryPath = [fullPath stringByAppendingPathComponent:name]; - BOOL bIsDir = NO; - [fileMgr fileExistsAtPath:entryPath isDirectory:&bIsDir]; - NSDictionary* entryDict = [self getDirectoryEntry:entryPath isDirectory:bIsDir]; - [entries addObject:entryDict]; - } - } - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:entries]; - } else { - // assume not found but could check error for more specific error conditions - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -- (void)readFileWithPath:(NSString*)path start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback -{ - if (path == nil) { - callback(nil, nil, SYNTAX_ERR); - } else { - [self.commandDelegate runInBackground:^ { - if ([path hasPrefix:kCDVAssetsLibraryPrefix]) { - // In this case, we need to use an asynchronous method to retrieve the file. - // Because of this, we can't just assign to `result` and send it at the end of the method. - // Instead, we return after calling the asynchronous method and send `result` in each of the blocks. - ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { - if (asset) { - // We have the asset! Get the data and send it off. - ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; - Byte* buffer = (Byte*)malloc([assetRepresentation size]); - NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil]; - NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES]; - NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType); - - callback(data, MIMEType, NO_ERROR); - } else { - callback(nil, nil, NOT_FOUND_ERR); - } - }; - ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) { - // Retrieving the asset failed for some reason. Send the appropriate error. - NSLog(@"Error: %@", error); - callback(nil, nil, SECURITY_ERR); - }; - - ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; - [assetsLibrary assetForURL:[NSURL URLWithString:path] resultBlock:resultBlock failureBlock:failureBlock]; - } else { - NSString* mimeType = [self getMimeTypeFromPath:path]; - if (mimeType == nil) { - mimeType = @"*/*"; - } - NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:path]; - if (start > 0) { - [file seekToFileOffset:start]; - } - - NSData* readData; - if (end < 0) { - readData = [file readDataToEndOfFile]; - } else { - readData = [file readDataOfLength:(end - start)]; - } - - [file closeFile]; - - callback(readData, mimeType, readData != nil ? NO_ERROR : NOT_FOUND_ERR); - } - }]; - } -} - -/* read and return file data - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * 1 - NSString* encoding - * 2 - NSString* start - * 3 - NSString* end - */ -- (void)readAsText:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* path = [command argumentAtIndex:0]; - NSString* encoding = [command argumentAtIndex:1]; - NSInteger start = [[command argumentAtIndex:2] integerValue]; - NSInteger end = [[command argumentAtIndex:3] integerValue]; - - // TODO: implement - if (![@"UTF-8" isEqualToString : encoding]) { - NSLog(@"Only UTF-8 encodings are currently supported by readAsText"); - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ENCODING_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { - CDVPluginResult* result = nil; - if (data != nil) { - NSString* str = [[NSString alloc] initWithBytesNoCopy:(void*)[data bytes] length:[data length] encoding:NSUTF8StringEncoding freeWhenDone:NO]; - // Check that UTF8 conversion did not fail. - if (str != nil) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:str]; - result.associatedObject = data; - } else { - errorCode = ENCODING_ERR; - } - } - if (result == nil) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }]; -} - -/* Read content of text file and return as base64 encoded data url. - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * 1 - NSString* start - * 2 - NSString* end - * - * Determines the mime type from the file extension, returns ENCODING_ERR if mimetype can not be determined. - */ - -- (void)readAsDataURL:(CDVInvokedUrlCommand*)command -{ - NSString* path = [command argumentAtIndex:0]; - NSInteger start = [[command argumentAtIndex:1] integerValue]; - NSInteger end = [[command argumentAtIndex:2] integerValue]; - - [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { - CDVPluginResult* result = nil; - if (data != nil) { - // TODO: Would be faster to base64 encode directly to the final string. - NSString* output = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, [data base64EncodedString]]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:output]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }]; -} - -/* Read content of text file and return as an arraybuffer - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * 1 - NSString* start - * 2 - NSString* end - */ - -- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command -{ - NSString* path = [command argumentAtIndex:0]; - NSInteger start = [[command argumentAtIndex:1] integerValue]; - NSInteger end = [[command argumentAtIndex:2] integerValue]; - - [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { - CDVPluginResult* result = nil; - if (data != nil) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:data]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }]; -} - -- (void)readAsBinaryString:(CDVInvokedUrlCommand*)command -{ - NSString* path = [command argumentAtIndex:0]; - NSInteger start = [[command argumentAtIndex:1] integerValue]; - NSInteger end = [[command argumentAtIndex:2] integerValue]; - - [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { - CDVPluginResult* result = nil; - if (data != nil) { - NSString* payload = [[NSString alloc] initWithBytesNoCopy:(void*)[data bytes] length:[data length] encoding:NSASCIIStringEncoding freeWhenDone:NO]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:payload]; - result.associatedObject = data; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }]; -} - -/* helper function to get the mimeType from the file extension - * IN: - * NSString* fullPath - filename (may include path) - * OUT: - * NSString* the mime type as type/subtype. nil if not able to determine - */ -- (NSString*)getMimeTypeFromPath:(NSString*)fullPath -{ - NSString* mimeType = nil; - - if (fullPath) { - CFStringRef typeId = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[fullPath pathExtension], NULL); - if (typeId) { - mimeType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass(typeId, kUTTagClassMIMEType); - if (!mimeType) { - // special case for m4a - if ([(__bridge NSString*)typeId rangeOfString : @"m4a-audio"].location != NSNotFound) { - mimeType = @"audio/mp4"; - } else if ([[fullPath pathExtension] rangeOfString:@"wav"].location != NSNotFound) { - mimeType = @"audio/wav"; - } - } - CFRelease(typeId); - } - } - return mimeType; -} - -- (void)truncate:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* argPath = [command.arguments objectAtIndex:0]; - unsigned long long pos = (unsigned long long)[[command.arguments objectAtIndex:1] longLongValue]; - - // assets-library files can't be truncated - if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - NSString* appFile = argPath; // [self getFullPath:argPath]; - - unsigned long long newPos = [self truncateFile:appFile atPosition:pos]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:newPos]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -- (unsigned long long)truncateFile:(NSString*)filePath atPosition:(unsigned long long)pos -{ - unsigned long long newPos = 0UL; - - NSFileHandle* file = [NSFileHandle fileHandleForWritingAtPath:filePath]; - - if (file) { - [file truncateFileAtOffset:(unsigned long long)pos]; - newPos = [file offsetInFile]; - [file synchronizeFile]; - [file closeFile]; - } - return newPos; -} - -/* write - * IN: - * NSArray* arguments - * 0 - NSString* file path to write to - * 1 - NSString* or NSData* data to write - * 2 - NSNumber* position to begin writing - */ -- (void)write:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSArray* arguments = command.arguments; - - // arguments - NSString* argPath = [arguments objectAtIndex:0]; - id argData = [arguments objectAtIndex:1]; - unsigned long long pos = (unsigned long long)[[arguments objectAtIndex:2] longLongValue]; - - // text can't be written into assets-library files - if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - NSString* fullPath = argPath; // [self getFullPath:argPath]; - - [self truncateFile:fullPath atPosition:pos]; - - if ([argData isKindOfClass:[NSString class]]) { - [self writeToFile:fullPath withString:argData encoding:NSUTF8StringEncoding append:YES callback:callbackId]; - } else if ([argData isKindOfClass:[NSData class]]) { - [self writeToFile:fullPath withData:argData append:YES callback:callbackId]; - } else { - CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Invalid parameter type"]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - -} - -- (void)writeToFile:(NSString*)filePath withData:(NSData*)encData append:(BOOL)shouldAppend callback:(NSString*)callbackId -{ - CDVPluginResult* result = nil; - CDVFileError errCode = INVALID_MODIFICATION_ERR; - int bytesWritten = 0; - - if (filePath) { - NSOutputStream* fileStream = [NSOutputStream outputStreamToFileAtPath:filePath append:shouldAppend]; - if (fileStream) { - NSUInteger len = [encData length]; - [fileStream open]; - - bytesWritten = [fileStream write:[encData bytes] maxLength:len]; - - [fileStream close]; - if (bytesWritten > 0) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:bytesWritten]; - // } else { - // can probably get more detailed error info via [fileStream streamError] - // errCode already set to INVALID_MODIFICATION_ERR; - // bytesWritten = 0; // may be set to -1 on error - } - } // else fileStream not created return INVALID_MODIFICATION_ERR - } else { - // invalid filePath - errCode = NOT_FOUND_ERR; - } - if (!result) { - // was an error - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode]; - } - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; -} - -- (void)writeToFile:(NSString*)filePath withString:(NSString*)stringData encoding:(NSStringEncoding)encoding append:(BOOL)shouldAppend callback:(NSString*)callbackId -{ - [self writeToFile:filePath withData:[stringData dataUsingEncoding:encoding allowLossyConversion:YES] append:shouldAppend callback:callbackId]; -} - -- (void)testFileExists:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* argPath = [command.arguments objectAtIndex:0]; - - // Get the file manager - NSFileManager* fMgr = [NSFileManager defaultManager]; - NSString* appFile = argPath; // [ self getFullPath: argPath]; - - BOOL bExists = [fMgr fileExistsAtPath:appFile]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(bExists ? 1 : 0)]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -- (void)testDirectoryExists:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* argPath = [command.arguments objectAtIndex:0]; - - // Get the file manager - NSFileManager* fMgr = [[NSFileManager alloc] init]; - NSString* appFile = argPath; // [self getFullPath: argPath]; - BOOL bIsDir = NO; - BOOL bExists = [fMgr fileExistsAtPath:appFile isDirectory:&bIsDir]; - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:((bExists && bIsDir) ? 1 : 0)]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -// Returns number of bytes available via callback -- (void)getFreeDiskSpace:(CDVInvokedUrlCommand*)command -{ - // no arguments - - NSNumber* pNumAvail = [self checkFreeDiskSpace:self.appDocsPath]; - - NSString* strFreeSpace = [NSString stringWithFormat:@"%qu", [pNumAvail unsignedLongLongValue]]; - // NSLog(@"Free space is %@", strFreeSpace ); - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:strFreeSpace]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVFileTransfer.h b/iPhone/CordovaLib/Classes/CDVFileTransfer.h deleted file mode 100755 index 35e3fdd..0000000 --- a/iPhone/CordovaLib/Classes/CDVFileTransfer.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import "CDVPlugin.h" - -enum CDVFileTransferError { - FILE_NOT_FOUND_ERR = 1, - INVALID_URL_ERR = 2, - CONNECTION_ERR = 3, - CONNECTION_ABORTED = 4 -}; -typedef int CDVFileTransferError; - -enum CDVFileTransferDirection { - CDV_TRANSFER_UPLOAD = 1, - CDV_TRANSFER_DOWNLOAD = 2, -}; -typedef int CDVFileTransferDirection; - -// Magic value within the options dict used to set a cookie. -extern NSString* const kOptionsKeyCookie; - -@interface CDVFileTransfer : CDVPlugin {} - -- (void)upload:(CDVInvokedUrlCommand*)command; -- (void)download:(CDVInvokedUrlCommand*)command; -- (NSString*)escapePathComponentForUrlString:(NSString*)urlString; - -// Visible for testing. -- (NSURLRequest*)requestForUploadCommand:(CDVInvokedUrlCommand*)command fileData:(NSData*)fileData; -- (NSMutableDictionary*)createFileTransferError:(int)code AndSource:(NSString*)source AndTarget:(NSString*)target; - -- (NSMutableDictionary*)createFileTransferError:(int)code - AndSource:(NSString*)source - AndTarget:(NSString*)target - AndHttpStatus:(int)httpStatus - AndBody:(NSString*)body; -@property (readonly) NSMutableDictionary* activeTransfers; -@property (nonatomic, assign) UIBackgroundTaskIdentifier backgroundTaskID; -@end - -@class CDVFileTransferEntityLengthRequest; - -@interface CDVFileTransferDelegate : NSObject {} - -- (void)updateBytesExpected:(NSInteger)newBytesExpected; -- (void)cancelTransfer:(NSURLConnection*)connection; - -@property (strong) NSMutableData* responseData; // atomic -@property (nonatomic, strong) CDVFileTransfer* command; -@property (nonatomic, assign) CDVFileTransferDirection direction; -@property (nonatomic, strong) NSURLConnection* connection; -@property (nonatomic, copy) NSString* callbackId; -@property (nonatomic, copy) NSString* objectId; -@property (nonatomic, copy) NSString* source; -@property (nonatomic, copy) NSString* target; -@property (nonatomic, copy) NSString* mimeType; -@property (assign) int responseCode; // atomic -@property (nonatomic, assign) NSInteger bytesTransfered; -@property (nonatomic, assign) NSInteger bytesExpected; -@property (nonatomic, assign) BOOL trustAllHosts; -@property (strong) NSFileHandle* targetFileHandle; -@property (nonatomic, strong) CDVFileTransferEntityLengthRequest* entityLengthRequest; - -@end; diff --git a/iPhone/CordovaLib/Classes/CDVFileTransfer.m b/iPhone/CordovaLib/Classes/CDVFileTransfer.m deleted file mode 100755 index 0f6b174..0000000 --- a/iPhone/CordovaLib/Classes/CDVFileTransfer.m +++ /dev/null @@ -1,730 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDV.h" - -#import -#import -#import -#import - -@interface CDVFileTransfer () -// Sets the requests headers for the request. -- (void)applyRequestHeaders:(NSDictionary*)headers toRequest:(NSMutableURLRequest*)req; -// Creates a delegate to handle an upload. -- (CDVFileTransferDelegate*)delegateForUploadCommand:(CDVInvokedUrlCommand*)command; -// Creates an NSData* for the file for the given upload arguments. -- (void)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command; -@end - -// Buffer size to use for streaming uploads. -static const NSUInteger kStreamBufferSize = 32768; -// Magic value within the options dict used to set a cookie. -NSString* const kOptionsKeyCookie = @"__cookie"; -// Form boundary for multi-part requests. -NSString* const kFormBoundary = @"+++++org.apache.cordova.formBoundary"; - -// Writes the given data to the stream in a blocking way. -// If successful, returns bytesToWrite. -// If the stream was closed on the other end, returns 0. -// If there was an error, returns -1. -static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream) -{ - UInt8* bytes = (UInt8*)[data bytes]; - NSUInteger bytesToWrite = [data length]; - NSUInteger totalBytesWritten = 0; - - while (totalBytesWritten < bytesToWrite) { - CFIndex result = CFWriteStreamWrite(stream, - bytes + totalBytesWritten, - bytesToWrite - totalBytesWritten); - if (result < 0) { - CFStreamError error = CFWriteStreamGetError(stream); - NSLog(@"WriteStreamError domain: %ld error: %ld", error.domain, error.error); - return result; - } else if (result == 0) { - return result; - } - totalBytesWritten += result; - } - - return totalBytesWritten; -} - -@implementation CDVFileTransfer -@synthesize activeTransfers; - -- (NSString*)escapePathComponentForUrlString:(NSString*)urlString -{ - NSRange schemeAndHostRange = [urlString rangeOfString:@"://.*?/" options:NSRegularExpressionSearch]; - - if (schemeAndHostRange.length == 0) { - return urlString; - } - - NSInteger schemeAndHostEndIndex = NSMaxRange(schemeAndHostRange); - NSString* schemeAndHost = [urlString substringToIndex:schemeAndHostEndIndex]; - NSString* pathComponent = [urlString substringFromIndex:schemeAndHostEndIndex]; - pathComponent = [pathComponent stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - - return [schemeAndHost stringByAppendingString:pathComponent]; -} - -- (void)applyRequestHeaders:(NSDictionary*)headers toRequest:(NSMutableURLRequest*)req -{ - [req setValue:@"XMLHttpRequest" forHTTPHeaderField:@"X-Requested-With"]; - - NSString* userAgent = [self.commandDelegate userAgent]; - if (userAgent) { - [req setValue:userAgent forHTTPHeaderField:@"User-Agent"]; - } - - for (NSString* headerName in headers) { - id value = [headers objectForKey:headerName]; - if (!value || (value == [NSNull null])) { - value = @"null"; - } - - // First, remove an existing header if one exists. - [req setValue:nil forHTTPHeaderField:headerName]; - - if (![value isKindOfClass:[NSArray class]]) { - value = [NSArray arrayWithObject:value]; - } - - // Then, append all header values. - for (id __strong subValue in value) { - // Convert from an NSNumber -> NSString. - if ([subValue respondsToSelector:@selector(stringValue)]) { - subValue = [subValue stringValue]; - } - if ([subValue isKindOfClass:[NSString class]]) { - [req addValue:subValue forHTTPHeaderField:headerName]; - } - } - } -} - -- (NSURLRequest*)requestForUploadCommand:(CDVInvokedUrlCommand*)command fileData:(NSData*)fileData -{ - // arguments order from js: [filePath, server, fileKey, fileName, mimeType, params, debug, chunkedMode] - // however, params is a JavaScript object and during marshalling is put into the options dict, - // thus debug and chunkedMode are the 6th and 7th arguments - NSString* target = [command argumentAtIndex:0]; - NSString* server = [command argumentAtIndex:1]; - NSString* fileKey = [command argumentAtIndex:2 withDefault:@"file"]; - NSString* fileName = [command argumentAtIndex:3 withDefault:@"no-filename"]; - NSString* mimeType = [command argumentAtIndex:4 withDefault:nil]; - NSDictionary* options = [command argumentAtIndex:5 withDefault:nil]; - // BOOL trustAllHosts = [[arguments objectAtIndex:6 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs - BOOL chunkedMode = [[command argumentAtIndex:7 withDefault:[NSNumber numberWithBool:YES]] boolValue]; - NSDictionary* headers = [command argumentAtIndex:8 withDefault:nil]; - // Allow alternative http method, default to POST. JS side checks - // for allowed methods, currently PUT or POST (forces POST for - // unrecognised values) - NSString* httpMethod = [command argumentAtIndex:10 withDefault:@"POST"]; - CDVPluginResult* result = nil; - CDVFileTransferError errorCode = 0; - - // NSURL does not accepts URLs with spaces in the path. We escape the path in order - // to be more lenient. - NSURL* url = [NSURL URLWithString:server]; - - if (!url) { - errorCode = INVALID_URL_ERR; - NSLog(@"File Transfer Error: Invalid server URL %@", server); - } else if (!fileData) { - errorCode = FILE_NOT_FOUND_ERR; - } - - if (errorCode > 0) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:errorCode AndSource:target AndTarget:server]]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return nil; - } - - NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url]; - - [req setHTTPMethod:httpMethod]; - - // Magic value to set a cookie - if ([options objectForKey:kOptionsKeyCookie]) { - [req setValue:[options objectForKey:kOptionsKeyCookie] forHTTPHeaderField:@"Cookie"]; - [req setHTTPShouldHandleCookies:NO]; - } - - NSString* contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", kFormBoundary]; - [req setValue:contentType forHTTPHeaderField:@"Content-Type"]; - [self applyRequestHeaders:headers toRequest:req]; - - NSData* formBoundaryData = [[NSString stringWithFormat:@"--%@\r\n", kFormBoundary] dataUsingEncoding:NSUTF8StringEncoding]; - NSMutableData* postBodyBeforeFile = [NSMutableData data]; - - for (NSString* key in options) { - id val = [options objectForKey:key]; - if (!val || (val == [NSNull null]) || [key isEqualToString:kOptionsKeyCookie]) { - continue; - } - // if it responds to stringValue selector (eg NSNumber) get the NSString - if ([val respondsToSelector:@selector(stringValue)]) { - val = [val stringValue]; - } - // finally, check whether it is a NSString (for dataUsingEncoding selector below) - if (![val isKindOfClass:[NSString class]]) { - continue; - } - - [postBodyBeforeFile appendData:formBoundaryData]; - [postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]]; - [postBodyBeforeFile appendData:[val dataUsingEncoding:NSUTF8StringEncoding]]; - [postBodyBeforeFile appendData:[@"\r\n" dataUsingEncoding : NSUTF8StringEncoding]]; - } - - [postBodyBeforeFile appendData:formBoundaryData]; - [postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fileKey, fileName] dataUsingEncoding:NSUTF8StringEncoding]]; - if (mimeType != nil) { - [postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n", mimeType] dataUsingEncoding:NSUTF8StringEncoding]]; - } - [postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Length: %d\r\n\r\n", [fileData length]] dataUsingEncoding:NSUTF8StringEncoding]]; - - DLog(@"fileData length: %d", [fileData length]); - NSData* postBodyAfterFile = [[NSString stringWithFormat:@"\r\n--%@--\r\n", kFormBoundary] dataUsingEncoding:NSUTF8StringEncoding]; - - NSUInteger totalPayloadLength = [postBodyBeforeFile length] + [fileData length] + [postBodyAfterFile length]; - [req setValue:[[NSNumber numberWithInteger:totalPayloadLength] stringValue] forHTTPHeaderField:@"Content-Length"]; - - if (chunkedMode) { - CFReadStreamRef readStream = NULL; - CFWriteStreamRef writeStream = NULL; - CFStreamCreateBoundPair(NULL, &readStream, &writeStream, kStreamBufferSize); - [req setHTTPBodyStream:CFBridgingRelease(readStream)]; - - self.backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ - [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskID]; - self.backgroundTaskID = UIBackgroundTaskInvalid; - NSLog(@"Background task to upload media finished."); - }]; - - [self.commandDelegate runInBackground:^{ - if (CFWriteStreamOpen(writeStream)) { - NSData* chunks[] = {postBodyBeforeFile, fileData, postBodyAfterFile}; - int numChunks = sizeof(chunks) / sizeof(chunks[0]); - - for (int i = 0; i < numChunks; ++i) { - CFIndex result = WriteDataToStream(chunks[i], writeStream); - if (result <= 0) { - break; - } - } - } else { - NSLog(@"FileTransfer: Failed to open writeStream"); - } - CFWriteStreamClose(writeStream); - CFRelease(writeStream); - }]; - } else { - [postBodyBeforeFile appendData:fileData]; - [postBodyBeforeFile appendData:postBodyAfterFile]; - [req setHTTPBody:postBodyBeforeFile]; - } - return req; -} - -- (CDVFileTransferDelegate*)delegateForUploadCommand:(CDVInvokedUrlCommand*)command -{ - NSString* source = [command.arguments objectAtIndex:0]; - NSString* server = [command.arguments objectAtIndex:1]; - BOOL trustAllHosts = [[command.arguments objectAtIndex:6 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs - NSString* objectId = [command.arguments objectAtIndex:9]; - - CDVFileTransferDelegate* delegate = [[CDVFileTransferDelegate alloc] init]; - - delegate.command = self; - delegate.callbackId = command.callbackId; - delegate.direction = CDV_TRANSFER_UPLOAD; - delegate.objectId = objectId; - delegate.source = source; - delegate.target = server; - delegate.trustAllHosts = trustAllHosts; - - return delegate; -} - -- (void)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command -{ - NSString* target = (NSString*)[command.arguments objectAtIndex:0]; - NSError* __autoreleasing err = nil; - - // return unsupported result for assets-library URLs - if ([target hasPrefix:kCDVAssetsLibraryPrefix]) { - // Instead, we return after calling the asynchronous method and send `result` in each of the blocks. - ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { - if (asset) { - // We have the asset! Get the data and send it off. - ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; - Byte* buffer = (Byte*)malloc([assetRepresentation size]); - NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil]; - NSData* fileData = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES]; - [self uploadData:fileData command:command]; - } else { - // We couldn't find the asset. Send the appropriate error. - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } - }; - ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) { - // Retrieving the asset failed for some reason. Send the appropriate error. - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }; - - ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; - [assetsLibrary assetForURL:[NSURL URLWithString:target] resultBlock:resultBlock failureBlock:failureBlock]; - return; - } else { - // Extract the path part out of a file: URL. - NSString* filePath = [target hasPrefix:@"/"] ? [target copy] : [[NSURL URLWithString:target] path]; - if (filePath == nil) { - // We couldn't find the asset. Send the appropriate error. - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - // Memory map the file so that it can be read efficiently even if it is large. - NSData* fileData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&err]; - - if (err != nil) { - NSLog(@"Error opening file %@: %@", target, err); - } - [self uploadData:fileData command:command]; - } -} - -- (void)upload:(CDVInvokedUrlCommand*)command -{ - // fileData and req are split into helper functions to ease the unit testing of delegateForUpload. - // First, get the file data. This method will call `uploadData:command`. - [self fileDataForUploadCommand:command]; -} - -- (void)uploadData:(NSData*)fileData command:(CDVInvokedUrlCommand*)command -{ - NSURLRequest* req = [self requestForUploadCommand:command fileData:fileData]; - - if (req == nil) { - return; - } - CDVFileTransferDelegate* delegate = [self delegateForUploadCommand:command]; - [NSURLConnection connectionWithRequest:req delegate:delegate]; - - if (activeTransfers == nil) { - activeTransfers = [[NSMutableDictionary alloc] init]; - } - - [activeTransfers setObject:delegate forKey:delegate.objectId]; -} - -- (void)abort:(CDVInvokedUrlCommand*)command -{ - NSString* objectId = [command.arguments objectAtIndex:0]; - - CDVFileTransferDelegate* delegate = [activeTransfers objectForKey:objectId]; - - if (delegate != nil) { - [delegate cancelTransfer:delegate.connection]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:CONNECTION_ABORTED AndSource:delegate.source AndTarget:delegate.target]]; - [self.commandDelegate sendPluginResult:result callbackId:delegate.callbackId]; - } -} - -- (void)download:(CDVInvokedUrlCommand*)command -{ - DLog(@"File Transfer downloading file..."); - NSString* sourceUrl = [command.arguments objectAtIndex:0]; - NSString* filePath = [command.arguments objectAtIndex:1]; - BOOL trustAllHosts = [[command.arguments objectAtIndex:2 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs - NSString* objectId = [command.arguments objectAtIndex:3]; - NSDictionary* headers = [command.arguments objectAtIndex:4 withDefault:nil]; - - // return unsupported result for assets-library URLs - if ([filePath hasPrefix:kCDVAssetsLibraryPrefix]) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"download not supported for assets-library URLs."]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - CDVPluginResult* result = nil; - CDVFileTransferError errorCode = 0; - - NSURL* file; - - if ([filePath hasPrefix:@"/"]) { - file = [NSURL fileURLWithPath:filePath]; - } else { - file = [NSURL URLWithString:filePath]; - } - - NSURL* url = [NSURL URLWithString:sourceUrl]; - - if (!url) { - errorCode = INVALID_URL_ERR; - NSLog(@"File Transfer Error: Invalid server URL %@", sourceUrl); - } else if (![file isFileURL]) { - errorCode = FILE_NOT_FOUND_ERR; - NSLog(@"File Transfer Error: Invalid file path or URL %@", filePath); - } - - if (errorCode > 0) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:errorCode AndSource:sourceUrl AndTarget:filePath]]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url]; - [self applyRequestHeaders:headers toRequest:req]; - - CDVFileTransferDelegate* delegate = [[CDVFileTransferDelegate alloc] init]; - delegate.command = self; - delegate.direction = CDV_TRANSFER_DOWNLOAD; - delegate.callbackId = command.callbackId; - delegate.objectId = objectId; - delegate.source = sourceUrl; - delegate.target = filePath; - delegate.trustAllHosts = trustAllHosts; - - delegate.connection = [NSURLConnection connectionWithRequest:req delegate:delegate]; - - if (activeTransfers == nil) { - activeTransfers = [[NSMutableDictionary alloc] init]; - } - - [activeTransfers setObject:delegate forKey:delegate.objectId]; -} - -- (NSMutableDictionary*)createFileTransferError:(int)code AndSource:(NSString*)source AndTarget:(NSString*)target -{ - NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity:3]; - - [result setObject:[NSNumber numberWithInt:code] forKey:@"code"]; - if (source != nil) { - [result setObject:source forKey:@"source"]; - } - if (target != nil) { - [result setObject:target forKey:@"target"]; - } - NSLog(@"FileTransferError %@", result); - - return result; -} - -- (NSMutableDictionary*)createFileTransferError:(int)code - AndSource:(NSString*)source - AndTarget:(NSString*)target - AndHttpStatus:(int)httpStatus - AndBody:(NSString*)body -{ - NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity:5]; - - [result setObject:[NSNumber numberWithInt:code] forKey:@"code"]; - if (source != nil) { - [result setObject:source forKey:@"source"]; - } - if (target != nil) { - [result setObject:target forKey:@"target"]; - } - [result setObject:[NSNumber numberWithInt:httpStatus] forKey:@"http_status"]; - if (body != nil) { - [result setObject:body forKey:@"body"]; - } - NSLog(@"FileTransferError %@", result); - - return result; -} - -- (void)onReset -{ - for (CDVFileTransferDelegate* delegate in [activeTransfers allValues]) { - [delegate.connection cancel]; - } - - [activeTransfers removeAllObjects]; -} - -@end - -@interface CDVFileTransferEntityLengthRequest : NSObject { - NSURLConnection* _connection; - CDVFileTransferDelegate* __weak _originalDelegate; -} - -- (CDVFileTransferEntityLengthRequest*)initWithOriginalRequest:(NSURLRequest*)originalRequest andDelegate:(CDVFileTransferDelegate*)originalDelegate; - -@end; - -@implementation CDVFileTransferEntityLengthRequest; - -- (CDVFileTransferEntityLengthRequest*)initWithOriginalRequest:(NSURLRequest*)originalRequest andDelegate:(CDVFileTransferDelegate*)originalDelegate -{ - if (self) { - DLog(@"Requesting entity length for GZIPped content..."); - - NSMutableURLRequest* req = [originalRequest mutableCopy]; - [req setHTTPMethod:@"HEAD"]; - [req setValue:@"identity" forHTTPHeaderField:@"Accept-Encoding"]; - - _originalDelegate = originalDelegate; - _connection = [NSURLConnection connectionWithRequest:req delegate:self]; - } - return self; -} - -- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response -{ - DLog(@"HEAD request returned; content-length is %lld", [response expectedContentLength]); - [_originalDelegate updateBytesExpected:[response expectedContentLength]]; -} - -- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data -{} - -- (void)connectionDidFinishLoading:(NSURLConnection*)connection -{} - -@end - -@implementation CDVFileTransferDelegate - -@synthesize callbackId, connection = _connection, source, target, responseData, command, bytesTransfered, bytesExpected, direction, responseCode, objectId, targetFileHandle; - -- (void)connectionDidFinishLoading:(NSURLConnection*)connection -{ - NSString* uploadResponse = nil; - NSString* downloadResponse = nil; - NSMutableDictionary* uploadResult; - CDVPluginResult* result = nil; - BOOL bDirRequest = NO; - CDVFile* file; - - NSLog(@"File Transfer Finished with response code %d", self.responseCode); - - if (self.direction == CDV_TRANSFER_UPLOAD) { - uploadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding]; - - if ((self.responseCode >= 200) && (self.responseCode < 300)) { - // create dictionary to return FileUploadResult object - uploadResult = [NSMutableDictionary dictionaryWithCapacity:3]; - if (uploadResponse != nil) { - [uploadResult setObject:uploadResponse forKey:@"response"]; - } - [uploadResult setObject:[NSNumber numberWithInt:self.bytesTransfered] forKey:@"bytesSent"]; - [uploadResult setObject:[NSNumber numberWithInt:self.responseCode] forKey:@"responseCode"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:uploadResult]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:uploadResponse]]; - } - } - if (self.direction == CDV_TRANSFER_DOWNLOAD) { - if (self.targetFileHandle) { - [self.targetFileHandle closeFile]; - self.targetFileHandle = nil; - DLog(@"File Transfer Download success"); - - file = [[CDVFile alloc] init]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[file getDirectoryEntry:target isDirectory:bDirRequest]]; - } else { - downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]]; - } - } - - [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; - - // remove connection for activeTransfers - [command.activeTransfers removeObjectForKey:objectId]; - - // remove background id task in case our upload was done in the background - [[UIApplication sharedApplication] endBackgroundTask:self.command.backgroundTaskID]; - self.command.backgroundTaskID = UIBackgroundTaskInvalid; -} - -- (void)removeTargetFile -{ - NSFileManager* fileMgr = [NSFileManager defaultManager]; - - [fileMgr removeItemAtPath:self.target error:nil]; -} - -- (void)cancelTransfer:(NSURLConnection*)connection -{ - [connection cancel]; - [self.command.activeTransfers removeObjectForKey:self.objectId]; - [self removeTargetFile]; -} - -- (void)cancelTransferWithError:(NSURLConnection*)connection errorMessage:(NSString*)errorMessage -{ - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsDictionary:[self.command createFileTransferError:FILE_NOT_FOUND_ERR AndSource:self.source AndTarget:self.target AndHttpStatus:self.responseCode AndBody:errorMessage]]; - - NSLog(@"File Transfer Error: %@", errorMessage); - [self cancelTransfer:connection]; - [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; -} - -- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response -{ - NSError* __autoreleasing error = nil; - - self.mimeType = [response MIMEType]; - self.targetFileHandle = nil; - - // required for iOS 4.3, for some reason; response is - // a plain NSURLResponse, not the HTTP subclass - if ([response isKindOfClass:[NSHTTPURLResponse class]]) { - NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; - - self.responseCode = [httpResponse statusCode]; - self.bytesExpected = [response expectedContentLength]; - if ((self.direction == CDV_TRANSFER_DOWNLOAD) && (self.responseCode == 200) && (self.bytesExpected == NSURLResponseUnknownLength)) { - // Kick off HEAD request to server to get real length - // bytesExpected will be updated when that response is returned - self.entityLengthRequest = [[CDVFileTransferEntityLengthRequest alloc] initWithOriginalRequest:connection.currentRequest andDelegate:self]; - } - } else if ([response.URL isFileURL]) { - NSDictionary* attr = [[NSFileManager defaultManager] attributesOfItemAtPath:[response.URL path] error:nil]; - self.responseCode = 200; - self.bytesExpected = [attr[NSFileSize] longLongValue]; - } else { - self.responseCode = 200; - self.bytesExpected = NSURLResponseUnknownLength; - } - if ((self.direction == CDV_TRANSFER_DOWNLOAD) && (self.responseCode >= 200) && (self.responseCode < 300)) { - // Download response is okay; begin streaming output to file - NSString* parentPath = [self.target stringByDeletingLastPathComponent]; - - // create parent directories if needed - if ([[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:&error] == NO) { - if (error) { - [self cancelTransferWithError:connection errorMessage:[NSString stringWithFormat:@"Could not create path to save downloaded file: %@", [error localizedDescription]]]; - } else { - [self cancelTransferWithError:connection errorMessage:@"Could not create path to save downloaded file"]; - } - return; - } - // create target file - if ([[NSFileManager defaultManager] createFileAtPath:self.target contents:nil attributes:nil] == NO) { - [self cancelTransferWithError:connection errorMessage:@"Could not create target file"]; - return; - } - // open target file for writing - self.targetFileHandle = [NSFileHandle fileHandleForWritingAtPath:self.target]; - if (self.targetFileHandle == nil) { - [self cancelTransferWithError:connection errorMessage:@"Could not open target file for writing"]; - } - DLog(@"Streaming to file %@", target); - } -} - -- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error -{ - NSString* body = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:body]]; - - NSLog(@"File Transfer Error: %@", [error localizedDescription]); - - [self cancelTransfer:connection]; - [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; -} - -- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data -{ - self.bytesTransfered += data.length; - if (self.targetFileHandle) { - [self.targetFileHandle writeData:data]; - } else { - [self.responseData appendData:data]; - } - [self updateProgress]; -} - -- (void)updateBytesExpected:(NSInteger)newBytesExpected -{ - DLog(@"Updating bytesExpected to %d", newBytesExpected); - self.bytesExpected = newBytesExpected; - [self updateProgress]; -} - -- (void)updateProgress -{ - if (self.direction == CDV_TRANSFER_DOWNLOAD) { - BOOL lengthComputable = (self.bytesExpected != NSURLResponseUnknownLength); - // If the response is GZipped, and we have an outstanding HEAD request to get - // the length, then hold off on sending progress events. - if (!lengthComputable && (self.entityLengthRequest != nil)) { - return; - } - NSMutableDictionary* downloadProgress = [NSMutableDictionary dictionaryWithCapacity:3]; - [downloadProgress setObject:[NSNumber numberWithBool:lengthComputable] forKey:@"lengthComputable"]; - [downloadProgress setObject:[NSNumber numberWithInt:self.bytesTransfered] forKey:@"loaded"]; - [downloadProgress setObject:[NSNumber numberWithInt:self.bytesExpected] forKey:@"total"]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:downloadProgress]; - [result setKeepCallbackAsBool:true]; - [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; - } -} - -- (void)connection:(NSURLConnection*)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite -{ - if (self.direction == CDV_TRANSFER_UPLOAD) { - NSMutableDictionary* uploadProgress = [NSMutableDictionary dictionaryWithCapacity:3]; - - [uploadProgress setObject:[NSNumber numberWithBool:true] forKey:@"lengthComputable"]; - [uploadProgress setObject:[NSNumber numberWithInt:totalBytesWritten] forKey:@"loaded"]; - [uploadProgress setObject:[NSNumber numberWithInt:totalBytesExpectedToWrite] forKey:@"total"]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:uploadProgress]; - [result setKeepCallbackAsBool:true]; - [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - self.bytesTransfered = totalBytesWritten; -} - -// for self signed certificates -- (void)connection:(NSURLConnection*)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge -{ - if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { - if (self.trustAllHosts) { - NSURLCredential* credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; - [challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; - } - [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; - } else { - [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; - } -} - -- (id)init -{ - if ((self = [super init])) { - self.responseData = [NSMutableData data]; - self.targetFileHandle = nil; - } - return self; -} - -@end; diff --git a/iPhone/CordovaLib/Classes/CDVGlobalization.h b/iPhone/CordovaLib/Classes/CDVGlobalization.h deleted file mode 100755 index 0384656..0000000 --- a/iPhone/CordovaLib/Classes/CDVGlobalization.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import "CDVPlugin.h" - -#define CDV_FORMAT_SHORT 0 -#define CDV_FORMAT_MEDIUM 1 -#define CDV_FORMAT_LONG 2 -#define CDV_FORMAT_FULL 3 -#define CDV_SELECTOR_MONTHS 0 -#define CDV_SELECTOR_DAYS 1 - -enum CDVGlobalizationError { - CDV_UNKNOWN_ERROR = 0, - CDV_FORMATTING_ERROR = 1, - CDV_PARSING_ERROR = 2, - CDV_PATTERN_ERROR = 3, -}; -typedef NSUInteger CDVGlobalizationError; - -@interface CDVGlobalization : CDVPlugin { - CFLocaleRef currentLocale; -} - -- (void)getPreferredLanguage:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns the string identifier for the clients current locale setting. - * It returns the locale identifier string to the successCB callback with a - * properties object as a parameter. If there is an error getting the locale, - * then the errorCB callback is invoked. - */ -- (void)getLocaleName:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns a date formatted as a string according to the clients user preferences and - * calendar using the time zone of the client. It returns the formatted date string to the - * successCB callback with a properties object as a parameter. If there is an error - * formatting the date, then the errorCB callback is invoked. - * - * options: "date" contains the number of milliseconds that represents the JavaScript date - */ -- (void)dateToString:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Parses a date formatted as a string according to the clients user - * preferences and calendar using the time zone of the client and returns - * the corresponding date object. It returns the date to the successCB - * callback with a properties object as a parameter. If there is an error - * parsing the date string, then the errorCB callback is invoked. - * - * options: "dateString" contains the JavaScript string to parse for a date - */ -- (void)stringToDate:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns a pattern string for formatting and parsing dates according to the clients - * user preferences. It returns the pattern to the successCB callback with a - * properties object as a parameter. If there is an error obtaining the pattern, - * then the errorCB callback is invoked. - * - */ -- (void)getDatePattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns an array of either the names of the months or days of the week - * according to the clients user preferences and calendar. It returns the array of names to the - * successCB callback with a properties object as a parameter. If there is an error obtaining the - * names, then the errorCB callback is invoked. - * - */ -- (void)getDateNames:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns whether daylight savings time is in effect for a given date using the clients - * time zone and calendar. It returns whether or not daylight savings time is in effect - * to the successCB callback with a properties object as a parameter. If there is an error - * reading the date, then the errorCB callback is invoked. - * - * options: "date" contains the number of milliseconds that represents the JavaScript date - * - */ -- (void)isDayLightSavingsTime:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns the first day of the week according to the clients user preferences and calendar. - * The days of the week are numbered starting from 1 where 1 is considered to be Sunday. - * It returns the day to the successCB callback with a properties object as a parameter. - * If there is an error obtaining the pattern, then the errorCB callback is invoked. - * - */ -- (void)getFirstDayOfWeek:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns a number formatted as a string according to the clients user preferences. - * It returns the formatted number string to the successCB callback with a properties object as a - * parameter. If there is an error formatting the number, then the errorCB callback is invoked. - * - * options: "number" contains the JavaScript number to format - * - */ -- (void)numberToString:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Parses a number formatted as a string according to the clients user preferences and - * returns the corresponding number. It returns the number to the successCB callback with a - * properties object as a parameter. If there is an error parsing the number string, then - * the errorCB callback is invoked. - * - * options: "numberString" contains the JavaScript string to parse for a number - * - */ -- (void)stringToNumber:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns a pattern string for formatting and parsing numbers according to the clients user - * preferences. It returns the pattern to the successCB callback with a properties object as a - * parameter. If there is an error obtaining the pattern, then the errorCB callback is invoked. - * - */ -- (void)getNumberPattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns a pattern string for formatting and parsing currency values according to the clients - * user preferences and ISO 4217 currency code. It returns the pattern to the successCB callback with a - * properties object as a parameter. If there is an error obtaining the pattern, then the errorCB - * callback is invoked. - * - * options: "currencyCode" contains the ISO currency code from JavaScript - */ -- (void)getCurrencyPattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVGlobalization.m b/iPhone/CordovaLib/Classes/CDVGlobalization.m deleted file mode 100755 index 9eb9721..0000000 --- a/iPhone/CordovaLib/Classes/CDVGlobalization.m +++ /dev/null @@ -1,790 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVGlobalization.h" - -@implementation CDVGlobalization - -- (id)initWithWebView:(UIWebView*)theWebView -{ - self = (CDVGlobalization*)[super initWithWebView:theWebView]; - if (self) { - currentLocale = CFLocaleCopyCurrent(); - } - return self; -} - -- (void)getPreferredLanguage:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - NSString* callbackId = [arguments objectAtIndex:0]; - CDVPluginResult* result = nil; - - NSLog(@"log1"); - // Source: http://stackoverflow.com/questions/3910244/getting-current-device-language-in-ios - // (should be OK) - NSString* language = [[NSLocale preferredLanguages] objectAtIndex:0]; - - if (language) { - NSDictionary* dictionary = [NSDictionary dictionaryWithObject:language forKey:@"value"]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:dictionary]; - } else { - // TBD is this ever expected to happen? - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unknown error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; -} - -- (void)getLocaleName:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CDVPluginResult* result = nil; - NSString* callbackId = [arguments objectAtIndex:0]; - NSDictionary* dictionary = nil; - - NSLocale* locale = [NSLocale currentLocale]; - - if (locale) { - dictionary = [NSDictionary dictionaryWithObject:[locale localeIdentifier] forKey:@"value"]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } else { - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unknown error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; -} - -- (void)dateToString:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CFDateFormatterStyle style = kCFDateFormatterShortStyle; - CFDateFormatterStyle dateStyle = kCFDateFormatterShortStyle; - CFDateFormatterStyle timeStyle = kCFDateFormatterShortStyle; - NSDate* date = nil; - NSString* dateString = nil; - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - - id milliseconds = [options valueForKey:@"date"]; - - if (milliseconds && [milliseconds isKindOfClass:[NSNumber class]]) { - // get the number of seconds since 1970 and create the date object - date = [NSDate dateWithTimeIntervalSince1970:[milliseconds doubleValue] / 1000]; - } - - // see if any options have been specified - id items = [options valueForKey:@"options"]; - if (items && [items isKindOfClass:[NSMutableDictionary class]]) { - NSEnumerator* enumerator = [items keyEnumerator]; - id key; - - // iterate through all the options - while ((key = [enumerator nextObject])) { - id item = [items valueForKey:key]; - - // make sure that only string values are present - if ([item isKindOfClass:[NSString class]]) { - // get the desired format length - if ([key isEqualToString:@"formatLength"]) { - if ([item isEqualToString:@"short"]) { - style = kCFDateFormatterShortStyle; - } else if ([item isEqualToString:@"medium"]) { - style = kCFDateFormatterMediumStyle; - } else if ([item isEqualToString:@"long"]) { - style = kCFDateFormatterLongStyle; - } else if ([item isEqualToString:@"full"]) { - style = kCFDateFormatterFullStyle; - } - } - // get the type of date and time to generate - else if ([key isEqualToString:@"selector"]) { - if ([item isEqualToString:@"date"]) { - dateStyle = style; - timeStyle = kCFDateFormatterNoStyle; - } else if ([item isEqualToString:@"time"]) { - dateStyle = kCFDateFormatterNoStyle; - timeStyle = style; - } else if ([item isEqualToString:@"date and time"]) { - dateStyle = style; - timeStyle = style; - } - } - } - } - } - - // create the formatter using the user's current default locale and formats for dates and times - CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault, - currentLocale, - dateStyle, - timeStyle); - // if we have a valid date object then call the formatter - if (date) { - dateString = (__bridge_transfer NSString*)CFDateFormatterCreateStringWithDate(kCFAllocatorDefault, - formatter, - (__bridge CFDateRef)date); - } - - // if the date was converted to a string successfully then return the result - if (dateString) { - NSDictionary* dictionary = [NSDictionary dictionaryWithObject:dateString forKey:@"value"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - // DLog(@"GlobalizationCommand dateToString unable to format %@", [date description]); - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_FORMATTING_ERROR] forKey:@"code"]; - [dictionary setValue:@"Formatting error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; - - CFRelease(formatter); -} - -- (void)stringToDate:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CFDateFormatterStyle style = kCFDateFormatterShortStyle; - CFDateFormatterStyle dateStyle = kCFDateFormatterShortStyle; - CFDateFormatterStyle timeStyle = kCFDateFormatterShortStyle; - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - NSString* dateString = nil; - NSDateComponents* comps = nil; - - // get the string that is to be parsed for a date - id ms = [options valueForKey:@"dateString"]; - - if (ms && [ms isKindOfClass:[NSString class]]) { - dateString = ms; - } - - // see if any options have been specified - id items = [options valueForKey:@"options"]; - if (items && [items isKindOfClass:[NSMutableDictionary class]]) { - NSEnumerator* enumerator = [items keyEnumerator]; - id key; - - // iterate through all the options - while ((key = [enumerator nextObject])) { - id item = [items valueForKey:key]; - - // make sure that only string values are present - if ([item isKindOfClass:[NSString class]]) { - // get the desired format length - if ([key isEqualToString:@"formatLength"]) { - if ([item isEqualToString:@"short"]) { - style = kCFDateFormatterShortStyle; - } else if ([item isEqualToString:@"medium"]) { - style = kCFDateFormatterMediumStyle; - } else if ([item isEqualToString:@"long"]) { - style = kCFDateFormatterLongStyle; - } else if ([item isEqualToString:@"full"]) { - style = kCFDateFormatterFullStyle; - } - } - // get the type of date and time to generate - else if ([key isEqualToString:@"selector"]) { - if ([item isEqualToString:@"date"]) { - dateStyle = style; - timeStyle = kCFDateFormatterNoStyle; - } else if ([item isEqualToString:@"time"]) { - dateStyle = kCFDateFormatterNoStyle; - timeStyle = style; - } else if ([item isEqualToString:@"date and time"]) { - dateStyle = style; - timeStyle = style; - } - } - } - } - } - - // get the user's default settings for date and time formats - CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault, - currentLocale, - dateStyle, - timeStyle); - - // set the parsing to be more lenient - CFDateFormatterSetProperty(formatter, kCFDateFormatterIsLenient, kCFBooleanTrue); - - // parse tha date and time string - CFDateRef date = CFDateFormatterCreateDateFromString(kCFAllocatorDefault, - formatter, - (__bridge CFStringRef)dateString, - NULL); - - // if we were able to parse the date then get the date and time components - if (date != NULL) { - NSCalendar* calendar = [NSCalendar currentCalendar]; - - unsigned unitFlags = NSYearCalendarUnit | - NSMonthCalendarUnit | - NSDayCalendarUnit | - NSHourCalendarUnit | - NSMinuteCalendarUnit | - NSSecondCalendarUnit; - - comps = [calendar components:unitFlags fromDate:(__bridge NSDate*)date]; - CFRelease(date); - } - - // put the various elements of the date and time into a dictionary - if (comps != nil) { - NSArray* keys = [NSArray arrayWithObjects:@"year", @"month", @"day", @"hour", @"minute", @"second", @"millisecond", nil]; - NSArray* values = [NSArray arrayWithObjects:[NSNumber numberWithInt:[comps year]], - [NSNumber numberWithInt:[comps month] - 1], - [NSNumber numberWithInt:[comps day]], - [NSNumber numberWithInt:[comps hour]], - [NSNumber numberWithInt:[comps minute]], - [NSNumber numberWithInt:[comps second]], - [NSNumber numberWithInt:0], /* iOS does not provide milliseconds */ - nil]; - - NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - // Dlog(@"GlobalizationCommand stringToDate unable to parse %@", dateString); - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_PARSING_ERROR] forKey:@"code"]; - [dictionary setValue:@"unable to parse" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; - - CFRelease(formatter); -} - -- (void)getDatePattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CFDateFormatterStyle style = kCFDateFormatterShortStyle; - CFDateFormatterStyle dateStyle = kCFDateFormatterShortStyle; - CFDateFormatterStyle timeStyle = kCFDateFormatterShortStyle; - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - - // see if any options have been specified - id items = [options valueForKey:@"options"]; - - if (items && [items isKindOfClass:[NSMutableDictionary class]]) { - NSEnumerator* enumerator = [items keyEnumerator]; - id key; - - // iterate through all the options - while ((key = [enumerator nextObject])) { - id item = [items valueForKey:key]; - - // make sure that only string values are present - if ([item isKindOfClass:[NSString class]]) { - // get the desired format length - if ([key isEqualToString:@"formatLength"]) { - if ([item isEqualToString:@"short"]) { - style = kCFDateFormatterShortStyle; - } else if ([item isEqualToString:@"medium"]) { - style = kCFDateFormatterMediumStyle; - } else if ([item isEqualToString:@"long"]) { - style = kCFDateFormatterLongStyle; - } else if ([item isEqualToString:@"full"]) { - style = kCFDateFormatterFullStyle; - } - } - // get the type of date and time to generate - else if ([key isEqualToString:@"selector"]) { - if ([item isEqualToString:@"date"]) { - dateStyle = style; - timeStyle = kCFDateFormatterNoStyle; - } else if ([item isEqualToString:@"time"]) { - dateStyle = kCFDateFormatterNoStyle; - timeStyle = style; - } else if ([item isEqualToString:@"date and time"]) { - dateStyle = style; - timeStyle = style; - } - } - } - } - } - - // get the user's default settings for date and time formats - CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault, - currentLocale, - dateStyle, - timeStyle); - - // get the date pattern to apply when formatting and parsing - CFStringRef datePattern = CFDateFormatterGetFormat(formatter); - // get the user's current time zone information - CFTimeZoneRef timezone = (CFTimeZoneRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterTimeZone); - - // put the pattern and time zone information into the dictionary - if ((datePattern != nil) && (timezone != nil)) { - NSArray* keys = [NSArray arrayWithObjects:@"pattern", @"timezone", @"utc_offset", @"dst_offset", nil]; - NSArray* values = [NSArray arrayWithObjects:((__bridge NSString*)datePattern), - [((__bridge NSTimeZone*)timezone)abbreviation], - [NSNumber numberWithLong:[((__bridge NSTimeZone*)timezone)secondsFromGMT]], - [NSNumber numberWithDouble:[((__bridge NSTimeZone*)timezone)daylightSavingTimeOffset]], - nil]; - - NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_PATTERN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Pattern error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; - - if (timezone) { - CFRelease(timezone); - } - CFRelease(formatter); -} - -- (void)getDateNames:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - int style = CDV_FORMAT_LONG; - int selector = CDV_SELECTOR_MONTHS; - CFStringRef dataStyle = kCFDateFormatterMonthSymbols; - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - - // see if any options have been specified - id items = [options valueForKey:@"options"]; - - if (items && [items isKindOfClass:[NSMutableDictionary class]]) { - NSEnumerator* enumerator = [items keyEnumerator]; - id key; - - // iterate through all the options - while ((key = [enumerator nextObject])) { - id item = [items valueForKey:key]; - - // make sure that only string values are present - if ([item isKindOfClass:[NSString class]]) { - // get the desired type of name - if ([key isEqualToString:@"type"]) { - if ([item isEqualToString:@"narrow"]) { - style = CDV_FORMAT_SHORT; - } else if ([item isEqualToString:@"wide"]) { - style = CDV_FORMAT_LONG; - } - } - // determine if months or days are needed - else if ([key isEqualToString:@"item"]) { - if ([item isEqualToString:@"months"]) { - selector = CDV_SELECTOR_MONTHS; - } else if ([item isEqualToString:@"days"]) { - selector = CDV_SELECTOR_DAYS; - } - } - } - } - } - - CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault, - currentLocale, - kCFDateFormatterFullStyle, - kCFDateFormatterFullStyle); - - if ((selector == CDV_SELECTOR_MONTHS) && (style == CDV_FORMAT_LONG)) { - dataStyle = kCFDateFormatterMonthSymbols; - } else if ((selector == CDV_SELECTOR_MONTHS) && (style == CDV_FORMAT_SHORT)) { - dataStyle = kCFDateFormatterShortMonthSymbols; - } else if ((selector == CDV_SELECTOR_DAYS) && (style == CDV_FORMAT_LONG)) { - dataStyle = kCFDateFormatterWeekdaySymbols; - } else if ((selector == CDV_SELECTOR_DAYS) && (style == CDV_FORMAT_SHORT)) { - dataStyle = kCFDateFormatterShortWeekdaySymbols; - } - - CFArrayRef names = (CFArrayRef)CFDateFormatterCopyProperty(formatter, dataStyle); - - if (names) { - NSDictionary* dictionary = [NSDictionary dictionaryWithObject:((__bridge NSArray*)names) forKey:@"value"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - CFRelease(names); - } - // error - else { - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unknown error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; - - CFRelease(formatter); -} - -- (void)isDayLightSavingsTime:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - NSDate* date = nil; - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - - id milliseconds = [options valueForKey:@"date"]; - - if (milliseconds && [milliseconds isKindOfClass:[NSNumber class]]) { - // get the number of seconds since 1970 and create the date object - date = [NSDate dateWithTimeIntervalSince1970:[milliseconds doubleValue] / 1000]; - } - - if (date) { - // get the current calendar for the user and check if the date is using DST - NSCalendar* calendar = [NSCalendar currentCalendar]; - NSTimeZone* timezone = [calendar timeZone]; - NSNumber* dst = [NSNumber numberWithBool:[timezone isDaylightSavingTimeForDate:date]]; - - NSDictionary* dictionary = [NSDictionary dictionaryWithObject:dst forKey:@"dst"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unknown error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; -} - -- (void)getFirstDayOfWeek:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - - NSCalendar* calendar = [NSCalendar autoupdatingCurrentCalendar]; - - NSNumber* day = [NSNumber numberWithInt:[calendar firstWeekday]]; - - if (day) { - NSDictionary* dictionary = [NSDictionary dictionaryWithObject:day forKey:@"value"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unknown error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; -} - -- (void)numberToString:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - CFNumberFormatterStyle style = kCFNumberFormatterDecimalStyle; - NSNumber* number = nil; - - id value = [options valueForKey:@"number"]; - - if (value && [value isKindOfClass:[NSNumber class]]) { - number = (NSNumber*)value; - } - - // see if any options have been specified - id items = [options valueForKey:@"options"]; - if (items && [items isKindOfClass:[NSMutableDictionary class]]) { - NSEnumerator* enumerator = [items keyEnumerator]; - id key; - - // iterate through all the options - while ((key = [enumerator nextObject])) { - id item = [items valueForKey:key]; - - // make sure that only string values are present - if ([item isKindOfClass:[NSString class]]) { - // get the desired style of formatting - if ([key isEqualToString:@"type"]) { - if ([item isEqualToString:@"percent"]) { - style = kCFNumberFormatterPercentStyle; - } else if ([item isEqualToString:@"currency"]) { - style = kCFNumberFormatterCurrencyStyle; - } else if ([item isEqualToString:@"decimal"]) { - style = kCFNumberFormatterDecimalStyle; - } - } - } - } - } - - CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault, - currentLocale, - style); - - // get the localized string based upon the locale and user preferences - NSString* numberString = (__bridge_transfer NSString*)CFNumberFormatterCreateStringWithNumber(kCFAllocatorDefault, - formatter, - (__bridge CFNumberRef)number); - - if (numberString) { - NSDictionary* dictionary = [NSDictionary dictionaryWithObject:numberString forKey:@"value"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - // DLog(@"GlobalizationCommand numberToString unable to format %@", [number stringValue]); - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_FORMATTING_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unable to format" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; - - CFRelease(formatter); -} - -- (void)stringToNumber:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - CFNumberFormatterStyle style = kCFNumberFormatterDecimalStyle; - NSString* numberString = nil; - double doubleValue; - - id value = [options valueForKey:@"numberString"]; - - if (value && [value isKindOfClass:[NSString class]]) { - numberString = (NSString*)value; - } - - // see if any options have been specified - id items = [options valueForKey:@"options"]; - if (items && [items isKindOfClass:[NSMutableDictionary class]]) { - NSEnumerator* enumerator = [items keyEnumerator]; - id key; - - // iterate through all the options - while ((key = [enumerator nextObject])) { - id item = [items valueForKey:key]; - - // make sure that only string values are present - if ([item isKindOfClass:[NSString class]]) { - // get the desired style of formatting - if ([key isEqualToString:@"type"]) { - if ([item isEqualToString:@"percent"]) { - style = kCFNumberFormatterPercentStyle; - } else if ([item isEqualToString:@"currency"]) { - style = kCFNumberFormatterCurrencyStyle; - } else if ([item isEqualToString:@"decimal"]) { - style = kCFNumberFormatterDecimalStyle; - } - } - } - } - } - - CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault, - currentLocale, - style); - - // we need to make this lenient so as to avoid problems with parsing currencies that have non-breaking space characters - if (style == kCFNumberFormatterCurrencyStyle) { - CFNumberFormatterSetProperty(formatter, kCFNumberFormatterIsLenient, kCFBooleanTrue); - } - - // parse againist the largest type to avoid data loss - Boolean rc = CFNumberFormatterGetValueFromString(formatter, - (__bridge CFStringRef)numberString, - NULL, - kCFNumberDoubleType, - &doubleValue); - - if (rc) { - NSDictionary* dictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithDouble:doubleValue] forKey:@"value"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - // DLog(@"GlobalizationCommand stringToNumber unable to parse %@", numberString); - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_PARSING_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unable to parse" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; - - CFRelease(formatter); -} - -- (void)getNumberPattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - CFNumberFormatterStyle style = kCFNumberFormatterDecimalStyle; - CFStringRef symbolType = NULL; - NSString* symbol = @""; - - // see if any options have been specified - id items = [options valueForKey:@"options"]; - - if (items && [items isKindOfClass:[NSMutableDictionary class]]) { - NSEnumerator* enumerator = [items keyEnumerator]; - id key; - - // iterate through all the options - while ((key = [enumerator nextObject])) { - id item = [items valueForKey:key]; - - // make sure that only string values are present - if ([item isKindOfClass:[NSString class]]) { - // get the desired style of formatting - if ([key isEqualToString:@"type"]) { - if ([item isEqualToString:@"percent"]) { - style = kCFNumberFormatterPercentStyle; - } else if ([item isEqualToString:@"currency"]) { - style = kCFNumberFormatterCurrencyStyle; - } else if ([item isEqualToString:@"decimal"]) { - style = kCFNumberFormatterDecimalStyle; - } - } - } - } - } - - CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault, - currentLocale, - style); - - NSString* numberPattern = (__bridge NSString*)CFNumberFormatterGetFormat(formatter); - - if (style == kCFNumberFormatterCurrencyStyle) { - symbolType = kCFNumberFormatterCurrencySymbol; - } else if (style == kCFNumberFormatterPercentStyle) { - symbolType = kCFNumberFormatterPercentSymbol; - } - - if (symbolType) { - symbol = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, symbolType); - } - - NSString* decimal = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterDecimalSeparator); - NSString* grouping = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterGroupingSeparator); - NSString* posSign = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterPlusSign); - NSString* negSign = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterMinusSign); - NSNumber* fracDigits = (__bridge_transfer NSNumber*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterMinFractionDigits); - NSNumber* roundingDigits = (__bridge_transfer NSNumber*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterRoundingIncrement); - - // put the pattern information into the dictionary - if (numberPattern != nil) { - NSArray* keys = [NSArray arrayWithObjects:@"pattern", @"symbol", @"fraction", @"rounding", - @"positive", @"negative", @"decimal", @"grouping", nil]; - NSArray* values = [NSArray arrayWithObjects:numberPattern, symbol, fracDigits, roundingDigits, - posSign, negSign, decimal, grouping, nil]; - NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_PATTERN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Pattern error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; - - CFRelease(formatter); -} - -- (void)getCurrencyPattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - NSString* currencyCode = nil; - NSString* numberPattern = nil; - NSString* decimal = nil; - NSString* grouping = nil; - int32_t defaultFractionDigits; - double roundingIncrement; - Boolean rc; - - id value = [options valueForKey:@"currencyCode"]; - - if (value && [value isKindOfClass:[NSString class]]) { - currencyCode = (NSString*)value; - } - - // first see if there is base currency info available and fill in the currency_info structure - rc = CFNumberFormatterGetDecimalInfoForCurrencyCode((__bridge CFStringRef)currencyCode, &defaultFractionDigits, &roundingIncrement); - - // now set the currency code in the formatter - if (rc) { - CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault, - currentLocale, - kCFNumberFormatterCurrencyStyle); - - CFNumberFormatterSetProperty(formatter, kCFNumberFormatterCurrencyCode, (__bridge CFStringRef)currencyCode); - CFNumberFormatterSetProperty(formatter, kCFNumberFormatterInternationalCurrencySymbol, (__bridge CFStringRef)currencyCode); - - numberPattern = (__bridge NSString*)CFNumberFormatterGetFormat(formatter); - decimal = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterCurrencyDecimalSeparator); - grouping = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterCurrencyGroupingSeparator); - - NSArray* keys = [NSArray arrayWithObjects:@"pattern", @"code", @"fraction", @"rounding", - @"decimal", @"grouping", nil]; - NSArray* values = [NSArray arrayWithObjects:numberPattern, currencyCode, [NSNumber numberWithInt:defaultFractionDigits], - [NSNumber numberWithDouble:roundingIncrement], decimal, grouping, nil]; - NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - CFRelease(formatter); - } - // error - else { - // DLog(@"GlobalizationCommand getCurrencyPattern unable to get pattern for %@", currencyCode); - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_PATTERN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unable to get pattern" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; -} - -- (void)dealloc -{ - if (currentLocale) { - CFRelease(currentLocale); - currentLocale = nil; - } -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVInAppBrowser.h b/iPhone/CordovaLib/Classes/CDVInAppBrowser.h deleted file mode 100755 index 248274a..0000000 --- a/iPhone/CordovaLib/Classes/CDVInAppBrowser.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVPlugin.h" -#import "CDVInvokedUrlCommand.h" -#import "CDVScreenOrientationDelegate.h" -#import "CDVWebViewDelegate.h" - -@class CDVInAppBrowserViewController; - -@interface CDVInAppBrowser : CDVPlugin { - BOOL _injectedIframeBridge; -} - -@property (nonatomic, retain) CDVInAppBrowserViewController* inAppBrowserViewController; -@property (nonatomic, copy) NSString* callbackId; - -- (void)open:(CDVInvokedUrlCommand*)command; -- (void)close:(CDVInvokedUrlCommand*)command; -- (void)injectScriptCode:(CDVInvokedUrlCommand*)command; -- (void)show:(CDVInvokedUrlCommand*)command; - -@end - -@interface CDVInAppBrowserViewController : UIViewController { - @private - NSString* _userAgent; - NSString* _prevUserAgent; - NSInteger _userAgentLockToken; - CDVWebViewDelegate* _webViewDelegate; -} - -@property (nonatomic, strong) IBOutlet UIWebView* webView; -@property (nonatomic, strong) IBOutlet UIBarButtonItem* closeButton; -@property (nonatomic, strong) IBOutlet UILabel* addressLabel; -@property (nonatomic, strong) IBOutlet UIBarButtonItem* backButton; -@property (nonatomic, strong) IBOutlet UIBarButtonItem* forwardButton; -@property (nonatomic, strong) IBOutlet UIActivityIndicatorView* spinner; -@property (nonatomic, strong) IBOutlet UIToolbar* toolbar; - -@property (nonatomic, weak) id orientationDelegate; -@property (nonatomic, weak) CDVInAppBrowser* navigationDelegate; -@property (nonatomic) NSURL* currentURL; - -- (void)close; -- (void)navigateTo:(NSURL*)url; -- (void)showLocationBar:(BOOL)show; -- (void)showToolBar:(BOOL)show; -- (void)setCloseButtonTitle:(NSString*)title; - -- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent; - -@end - -@interface CDVInAppBrowserOptions : NSObject {} - -@property (nonatomic, assign) BOOL location; -@property (nonatomic, assign) BOOL toolbar; -@property (nonatomic, copy) NSString* closebuttoncaption; - -@property (nonatomic, copy) NSString* presentationstyle; -@property (nonatomic, copy) NSString* transitionstyle; - -@property (nonatomic, assign) BOOL enableviewportscale; -@property (nonatomic, assign) BOOL mediaplaybackrequiresuseraction; -@property (nonatomic, assign) BOOL allowinlinemediaplayback; -@property (nonatomic, assign) BOOL keyboarddisplayrequiresuseraction; -@property (nonatomic, assign) BOOL suppressesincrementalrendering; -@property (nonatomic, assign) BOOL hidden; - -+ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVInAppBrowser.m b/iPhone/CordovaLib/Classes/CDVInAppBrowser.m deleted file mode 100755 index b832e23..0000000 --- a/iPhone/CordovaLib/Classes/CDVInAppBrowser.m +++ /dev/null @@ -1,818 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVInAppBrowser.h" -#import "CDVPluginResult.h" -#import "CDVUserAgentUtil.h" -#import "CDVJSON.h" - -#define kInAppBrowserTargetSelf @"_self" -#define kInAppBrowserTargetSystem @"_system" -#define kInAppBrowserTargetBlank @"_blank" - -#define TOOLBAR_HEIGHT 44.0 -#define LOCATIONBAR_HEIGHT 21.0 -#define FOOTER_HEIGHT ((TOOLBAR_HEIGHT) + (LOCATIONBAR_HEIGHT)) - -#pragma mark CDVInAppBrowser - -@implementation CDVInAppBrowser - -- (CDVInAppBrowser*)initWithWebView:(UIWebView*)theWebView -{ - self = [super initWithWebView:theWebView]; - if (self != nil) { - // your initialization here - } - - return self; -} - -- (void)onReset -{ - [self close:nil]; -} - -- (void)close:(CDVInvokedUrlCommand*)command -{ - if (self.inAppBrowserViewController != nil) { - [self.inAppBrowserViewController close]; - self.inAppBrowserViewController = nil; - } - - self.callbackId = nil; -} - -- (void)open:(CDVInvokedUrlCommand*)command -{ - CDVPluginResult* pluginResult; - - NSString* url = [command argumentAtIndex:0]; - NSString* target = [command argumentAtIndex:1 withDefault:kInAppBrowserTargetSelf]; - NSString* options = [command argumentAtIndex:2 withDefault:@"" andClass:[NSString class]]; - - self.callbackId = command.callbackId; - - if (url != nil) { - NSURL* baseUrl = [self.webView.request URL]; - NSURL* absoluteUrl = [[NSURL URLWithString:url relativeToURL:baseUrl] absoluteURL]; - if ([target isEqualToString:kInAppBrowserTargetSelf]) { - [self openInCordovaWebView:absoluteUrl withOptions:options]; - } else if ([target isEqualToString:kInAppBrowserTargetSystem]) { - [self openInSystem:absoluteUrl]; - } else { // _blank or anything else - [self openInInAppBrowser:absoluteUrl withOptions:options]; - } - - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"incorrect number of arguments"]; - } - - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -- (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options -{ - if (self.inAppBrowserViewController == nil) { - NSString* originalUA = [CDVUserAgentUtil originalUserAgent]; - self.inAppBrowserViewController = [[CDVInAppBrowserViewController alloc] initWithUserAgent:originalUA prevUserAgent:[self.commandDelegate userAgent]]; - self.inAppBrowserViewController.navigationDelegate = self; - - if ([self.viewController conformsToProtocol:@protocol(CDVScreenOrientationDelegate)]) { - self.inAppBrowserViewController.orientationDelegate = (UIViewController *)self.viewController; - } - } - - - CDVInAppBrowserOptions* browserOptions = [CDVInAppBrowserOptions parseOptions:options]; - [self.inAppBrowserViewController showLocationBar:browserOptions.location]; - [self.inAppBrowserViewController showToolBar:browserOptions.toolbar]; - if (browserOptions.closebuttoncaption != nil) { - [self.inAppBrowserViewController setCloseButtonTitle:browserOptions.closebuttoncaption]; - } - // Set Presentation Style - UIModalPresentationStyle presentationStyle = UIModalPresentationFullScreen; // default - if (browserOptions.presentationstyle != nil) { - if ([[browserOptions.presentationstyle lowercaseString] isEqualToString:@"pagesheet"]) { - presentationStyle = UIModalPresentationPageSheet; - } else if ([[browserOptions.presentationstyle lowercaseString] isEqualToString:@"formsheet"]) { - presentationStyle = UIModalPresentationFormSheet; - } - } - self.inAppBrowserViewController.modalPresentationStyle = presentationStyle; - - // Set Transition Style - UIModalTransitionStyle transitionStyle = UIModalTransitionStyleCoverVertical; // default - if (browserOptions.transitionstyle != nil) { - if ([[browserOptions.transitionstyle lowercaseString] isEqualToString:@"fliphorizontal"]) { - transitionStyle = UIModalTransitionStyleFlipHorizontal; - } else if ([[browserOptions.transitionstyle lowercaseString] isEqualToString:@"crossdissolve"]) { - transitionStyle = UIModalTransitionStyleCrossDissolve; - } - } - self.inAppBrowserViewController.modalTransitionStyle = transitionStyle; - - - // UIWebView options - self.inAppBrowserViewController.webView.scalesPageToFit = browserOptions.enableviewportscale; - self.inAppBrowserViewController.webView.mediaPlaybackRequiresUserAction = browserOptions.mediaplaybackrequiresuseraction; - self.inAppBrowserViewController.webView.allowsInlineMediaPlayback = browserOptions.allowinlinemediaplayback; - if (IsAtLeastiOSVersion(@"6.0")) { - self.inAppBrowserViewController.webView.keyboardDisplayRequiresUserAction = browserOptions.keyboarddisplayrequiresuseraction; - self.inAppBrowserViewController.webView.suppressesIncrementalRendering = browserOptions.suppressesincrementalrendering; - } - - if (! browserOptions.hidden) { - if (self.viewController.modalViewController != self.inAppBrowserViewController) { - [self.viewController presentModalViewController:self.inAppBrowserViewController animated:YES]; - } - } - [self.inAppBrowserViewController navigateTo:url]; -} - -- (void)show:(CDVInvokedUrlCommand*)command -{ - [self.viewController presentModalViewController:self.inAppBrowserViewController animated:YES]; -} - -- (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options -{ - if ([self.commandDelegate URLIsWhitelisted:url]) { - NSURLRequest* request = [NSURLRequest requestWithURL:url]; - [self.webView loadRequest:request]; - } else { // this assumes the InAppBrowser can be excepted from the white-list - [self openInInAppBrowser:url withOptions:options]; - } -} - -- (void)openInSystem:(NSURL*)url -{ - if ([[UIApplication sharedApplication] canOpenURL:url]) { - [[UIApplication sharedApplication] openURL:url]; - } else { // handle any custom schemes to plugins - [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]]; - } -} - -// This is a helper method for the inject{Script|Style}{Code|File} API calls, which -// provides a consistent method for injecting JavaScript code into the document. -// -// If a wrapper string is supplied, then the source string will be JSON-encoded (adding -// quotes) and wrapped using string formatting. (The wrapper string should have a single -// '%@' marker). -// -// If no wrapper is supplied, then the source string is executed directly. - -- (void)injectDeferredObject:(NSString*)source withWrapper:(NSString*)jsWrapper -{ - if (!_injectedIframeBridge) { - _injectedIframeBridge = YES; - // Create an iframe bridge in the new document to communicate with the CDVInAppBrowserViewController - [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:@"(function(d){var e = _cdvIframeBridge = d.createElement('iframe');e.style.display='none';d.body.appendChild(e);})(document)"]; - } - - if (jsWrapper != nil) { - NSString* sourceArrayString = [@[source] JSONString]; - if (sourceArrayString) { - NSString* sourceString = [sourceArrayString substringWithRange:NSMakeRange(1, [sourceArrayString length] - 2)]; - NSString* jsToInject = [NSString stringWithFormat:jsWrapper, sourceString]; - [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:jsToInject]; - } - } else { - [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:source]; - } -} - -- (void)injectScriptCode:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper = nil; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"_cdvIframeBridge.src='gap-iab://%@/'+window.escape(JSON.stringify([eval(%%@)]));", command.callbackId]; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -- (void)injectScriptFile:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('script'); c.src = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; - } else { - jsWrapper = @"(function(d) { var c = d.createElement('script'); c.src = %@; d.body.appendChild(c); })(document)"; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -- (void)injectStyleCode:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('style'); c.innerHTML = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; - } else { - jsWrapper = @"(function(d) { var c = d.createElement('style'); c.innerHTML = %@; d.body.appendChild(c); })(document)"; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -- (void)injectStyleFile:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; - } else { - jsWrapper = @"(function(d) { var c = d.createElement('link'); c.rel='stylesheet', c.type='text/css'; c.href = %@; d.body.appendChild(c); })(document)"; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -/** - * The iframe bridge provided for the InAppBrowser is capable of executing any oustanding callback belonging - * to the InAppBrowser plugin. Care has been taken that other callbacks cannot be triggered, and that no - * other code execution is possible. - * - * To trigger the bridge, the iframe (or any other resource) should attempt to load a url of the form: - * - * gap-iab:/// - * - * where is the string id of the callback to trigger (something like "InAppBrowser0123456789") - * - * If present, the path component of the special gap-iab:// url is expected to be a URL-escaped JSON-encoded - * value to pass to the callback. [NSURL path] should take care of the URL-unescaping, and a JSON_EXCEPTION - * is returned if the JSON is invalid. - */ -- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType -{ - NSURL* url = request.URL; - BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]]; - - // See if the url uses the 'gap-iab' protocol. If so, the host should be the id of a callback to execute, - // and the path, if present, should be a JSON-encoded value to pass to the callback. - if ([[url scheme] isEqualToString:@"gap-iab"]) { - NSString* scriptCallbackId = [url host]; - CDVPluginResult* pluginResult = nil; - - if ([scriptCallbackId hasPrefix:@"InAppBrowser"]) { - NSString* scriptResult = [url path]; - NSError* __autoreleasing error = nil; - - // The message should be a JSON-encoded array of the result of the script which executed. - if ((scriptResult != nil) && ([scriptResult length] > 1)) { - scriptResult = [scriptResult substringFromIndex:1]; - NSData* decodedResult = [NSJSONSerialization JSONObjectWithData:[scriptResult dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; - if ((error == nil) && [decodedResult isKindOfClass:[NSArray class]]) { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:(NSArray*)decodedResult]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_JSON_EXCEPTION]; - } - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:@[]]; - } - [self.commandDelegate sendPluginResult:pluginResult callbackId:scriptCallbackId]; - return NO; - } - } else if ((self.callbackId != nil) && isTopLevelNavigation) { - // Send a loadstart event for each top-level navigation (includes redirects). - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:@{@"type":@"loadstart", @"url":[url absoluteString]}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } - - return YES; -} - -- (void)webViewDidStartLoad:(UIWebView*)theWebView -{ - _injectedIframeBridge = NO; -} - -- (void)webViewDidFinishLoad:(UIWebView*)theWebView -{ - if (self.callbackId != nil) { - // TODO: It would be more useful to return the URL the page is actually on (e.g. if it's been redirected). - NSString* url = [self.inAppBrowserViewController.currentURL absoluteString]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:@{@"type":@"loadstop", @"url":url}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } -} - -- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error -{ - if (self.callbackId != nil) { - NSString* url = [self.inAppBrowserViewController.currentURL absoluteString]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR - messageAsDictionary:@{@"type":@"loaderror", @"url":url, @"code": [NSNumber numberWithInt:error.code], @"message": error.localizedDescription}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } -} - -- (void)browserExit -{ - if (self.callbackId != nil) { - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:@{@"type":@"exit"}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } - // Don't recycle the ViewController since it may be consuming a lot of memory. - // Also - this is required for the PDF/User-Agent bug work-around. - self.inAppBrowserViewController = nil; -} - -@end - -#pragma mark CDVInAppBrowserViewController - -@implementation CDVInAppBrowserViewController - -@synthesize currentURL; - -- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent -{ - self = [super init]; - if (self != nil) { - _userAgent = userAgent; - _prevUserAgent = prevUserAgent; - _webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self]; - [self createViews]; - } - - return self; -} - -- (void)createViews -{ - // We create the views in code for primarily for ease of upgrades and not requiring an external .xib to be included - - CGRect webViewBounds = self.view.bounds; - - webViewBounds.size.height -= FOOTER_HEIGHT; - - self.webView = [[UIWebView alloc] initWithFrame:webViewBounds]; - self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); - - [self.view addSubview:self.webView]; - [self.view sendSubviewToBack:self.webView]; - - self.webView.delegate = _webViewDelegate; - self.webView.backgroundColor = [UIColor whiteColor]; - - self.webView.clearsContextBeforeDrawing = YES; - self.webView.clipsToBounds = YES; - self.webView.contentMode = UIViewContentModeScaleToFill; - self.webView.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); - self.webView.multipleTouchEnabled = YES; - self.webView.opaque = YES; - self.webView.scalesPageToFit = NO; - self.webView.userInteractionEnabled = YES; - - self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; - self.spinner.alpha = 1.000; - self.spinner.autoresizesSubviews = YES; - self.spinner.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin; - self.spinner.clearsContextBeforeDrawing = NO; - self.spinner.clipsToBounds = NO; - self.spinner.contentMode = UIViewContentModeScaleToFill; - self.spinner.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); - self.spinner.frame = CGRectMake(454.0, 231.0, 20.0, 20.0); - self.spinner.hidden = YES; - self.spinner.hidesWhenStopped = YES; - self.spinner.multipleTouchEnabled = NO; - self.spinner.opaque = NO; - self.spinner.userInteractionEnabled = NO; - [self.spinner stopAnimating]; - - self.closeButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(close)]; - self.closeButton.enabled = YES; - - UIBarButtonItem* flexibleSpaceButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; - - UIBarButtonItem* fixedSpaceButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; - fixedSpaceButton.width = 20; - - self.toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, (self.view.bounds.size.height - TOOLBAR_HEIGHT), self.view.bounds.size.width, TOOLBAR_HEIGHT)]; - self.toolbar.alpha = 1.000; - self.toolbar.autoresizesSubviews = YES; - self.toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; - self.toolbar.barStyle = UIBarStyleBlackOpaque; - self.toolbar.clearsContextBeforeDrawing = NO; - self.toolbar.clipsToBounds = NO; - self.toolbar.contentMode = UIViewContentModeScaleToFill; - self.toolbar.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); - self.toolbar.hidden = NO; - self.toolbar.multipleTouchEnabled = NO; - self.toolbar.opaque = NO; - self.toolbar.userInteractionEnabled = YES; - - CGFloat labelInset = 5.0; - self.addressLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelInset, (self.view.bounds.size.height - FOOTER_HEIGHT), self.view.bounds.size.width - labelInset, LOCATIONBAR_HEIGHT)]; - self.addressLabel.adjustsFontSizeToFitWidth = NO; - self.addressLabel.alpha = 1.000; - self.addressLabel.autoresizesSubviews = YES; - self.addressLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin; - self.addressLabel.backgroundColor = [UIColor clearColor]; - self.addressLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters; - self.addressLabel.clearsContextBeforeDrawing = YES; - self.addressLabel.clipsToBounds = YES; - self.addressLabel.contentMode = UIViewContentModeScaleToFill; - self.addressLabel.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); - self.addressLabel.enabled = YES; - self.addressLabel.hidden = NO; - self.addressLabel.lineBreakMode = UILineBreakModeTailTruncation; - self.addressLabel.minimumFontSize = 10.000; - self.addressLabel.multipleTouchEnabled = NO; - self.addressLabel.numberOfLines = 1; - self.addressLabel.opaque = NO; - self.addressLabel.shadowOffset = CGSizeMake(0.0, -1.0); - self.addressLabel.text = @"Loading..."; - self.addressLabel.textAlignment = UITextAlignmentLeft; - self.addressLabel.textColor = [UIColor colorWithWhite:1.000 alpha:1.000]; - self.addressLabel.userInteractionEnabled = NO; - - NSString* frontArrowString = @"â–º"; // create arrow from Unicode char - self.forwardButton = [[UIBarButtonItem alloc] initWithTitle:frontArrowString style:UIBarButtonItemStylePlain target:self action:@selector(goForward:)]; - self.forwardButton.enabled = YES; - self.forwardButton.imageInsets = UIEdgeInsetsZero; - - NSString* backArrowString = @"â—„"; // create arrow from Unicode char - self.backButton = [[UIBarButtonItem alloc] initWithTitle:backArrowString style:UIBarButtonItemStylePlain target:self action:@selector(goBack:)]; - self.backButton.enabled = YES; - self.backButton.imageInsets = UIEdgeInsetsZero; - - [self.toolbar setItems:@[self.closeButton, flexibleSpaceButton, self.backButton, fixedSpaceButton, self.forwardButton]]; - - self.view.backgroundColor = [UIColor grayColor]; - [self.view addSubview:self.toolbar]; - [self.view addSubview:self.addressLabel]; - [self.view addSubview:self.spinner]; -} - -- (void)setCloseButtonTitle:(NSString*)title -{ - // the advantage of using UIBarButtonSystemItemDone is the system will localize it for you automatically - // but, if you want to set this yourself, knock yourself out (we can't set the title for a system Done button, so we have to create a new one) - self.closeButton = nil; - self.closeButton = [[UIBarButtonItem alloc] initWithTitle:title style:UIBarButtonItemStyleBordered target:self action:@selector(close)]; - self.closeButton.enabled = YES; - self.closeButton.tintColor = [UIColor colorWithRed:60.0 / 255.0 green:136.0 / 255.0 blue:230.0 / 255.0 alpha:1]; - - NSMutableArray* items = [self.toolbar.items mutableCopy]; - [items replaceObjectAtIndex:0 withObject:self.closeButton]; - [self.toolbar setItems:items]; -} - -- (void)showLocationBar:(BOOL)show -{ - CGRect locationbarFrame = self.addressLabel.frame; - - BOOL toolbarVisible = !self.toolbar.hidden; - - // prevent double show/hide - if (show == !(self.addressLabel.hidden)) { - return; - } - - if (show) { - self.addressLabel.hidden = NO; - - if (toolbarVisible) { - // toolBar at the bottom, leave as is - // put locationBar on top of the toolBar - - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= FOOTER_HEIGHT; - self.webView.frame = webViewBounds; - - locationbarFrame.origin.y = webViewBounds.size.height; - self.addressLabel.frame = locationbarFrame; - } else { - // no toolBar, so put locationBar at the bottom - - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= LOCATIONBAR_HEIGHT; - self.webView.frame = webViewBounds; - - locationbarFrame.origin.y = webViewBounds.size.height; - self.addressLabel.frame = locationbarFrame; - } - } else { - self.addressLabel.hidden = YES; - - if (toolbarVisible) { - // locationBar is on top of toolBar, hide locationBar - - // webView take up whole height less toolBar height - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= TOOLBAR_HEIGHT; - self.webView.frame = webViewBounds; - } else { - // no toolBar, expand webView to screen dimensions - - CGRect webViewBounds = self.view.bounds; - self.webView.frame = webViewBounds; - } - } -} - -- (void)showToolBar:(BOOL)show -{ - CGRect toolbarFrame = self.toolbar.frame; - CGRect locationbarFrame = self.addressLabel.frame; - - BOOL locationbarVisible = !self.addressLabel.hidden; - - // prevent double show/hide - if (show == !(self.toolbar.hidden)) { - return; - } - - if (show) { - self.toolbar.hidden = NO; - - if (locationbarVisible) { - // locationBar at the bottom, move locationBar up - // put toolBar at the bottom - - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= FOOTER_HEIGHT; - self.webView.frame = webViewBounds; - - locationbarFrame.origin.y = webViewBounds.size.height; - self.addressLabel.frame = locationbarFrame; - - toolbarFrame.origin.y = (webViewBounds.size.height + LOCATIONBAR_HEIGHT); - self.toolbar.frame = toolbarFrame; - } else { - // no locationBar, so put toolBar at the bottom - - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= TOOLBAR_HEIGHT; - self.webView.frame = webViewBounds; - - toolbarFrame.origin.y = webViewBounds.size.height; - self.toolbar.frame = toolbarFrame; - } - } else { - self.toolbar.hidden = YES; - - if (locationbarVisible) { - // locationBar is on top of toolBar, hide toolBar - // put locationBar at the bottom - - // webView take up whole height less locationBar height - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= LOCATIONBAR_HEIGHT; - self.webView.frame = webViewBounds; - - // move locationBar down - locationbarFrame.origin.y = webViewBounds.size.height; - self.addressLabel.frame = locationbarFrame; - } else { - // no locationBar, expand webView to screen dimensions - - CGRect webViewBounds = self.view.bounds; - self.webView.frame = webViewBounds; - } - } -} - -- (void)viewDidLoad -{ - [super viewDidLoad]; -} - -- (void)viewDidUnload -{ - [self.webView loadHTMLString:nil baseURL:nil]; - [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; - [super viewDidUnload]; -} - -- (void)close -{ - [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; - - if ([self respondsToSelector:@selector(presentingViewController)]) { - [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[self parentViewController] dismissModalViewControllerAnimated:YES]; - } - - self.currentURL = nil; - - if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserExit)]) { - [self.navigationDelegate browserExit]; - } -} - -- (void)navigateTo:(NSURL*)url -{ - NSURLRequest* request = [NSURLRequest requestWithURL:url]; - - if (_userAgentLockToken != 0) { - [self.webView loadRequest:request]; - } else { - [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) { - _userAgentLockToken = lockToken; - [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken]; - [self.webView loadRequest:request]; - }]; - } -} - -- (void)goBack:(id)sender -{ - [self.webView goBack]; -} - -- (void)goForward:(id)sender -{ - [self.webView goForward]; -} - -#pragma mark UIWebViewDelegate - -- (void)webViewDidStartLoad:(UIWebView*)theWebView -{ - // loading url, start spinner, update back/forward - - self.addressLabel.text = @"Loading..."; - self.backButton.enabled = theWebView.canGoBack; - self.forwardButton.enabled = theWebView.canGoForward; - - [self.spinner startAnimating]; - - return [self.navigationDelegate webViewDidStartLoad:theWebView]; -} - -- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType -{ - BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]]; - - if (isTopLevelNavigation) { - self.currentURL = request.URL; - } - return [self.navigationDelegate webView:theWebView shouldStartLoadWithRequest:request navigationType:navigationType]; -} - -- (void)webViewDidFinishLoad:(UIWebView*)theWebView -{ - // update url, stop spinner, update back/forward - - self.addressLabel.text = [self.currentURL absoluteString]; - self.backButton.enabled = theWebView.canGoBack; - self.forwardButton.enabled = theWebView.canGoForward; - - [self.spinner stopAnimating]; - - // Work around a bug where the first time a PDF is opened, all UIWebViews - // reload their User-Agent from NSUserDefaults. - // This work-around makes the following assumptions: - // 1. The app has only a single Cordova Webview. If not, then the app should - // take it upon themselves to load a PDF in the background as a part of - // their start-up flow. - // 2. That the PDF does not require any additional network requests. We change - // the user-agent here back to that of the CDVViewController, so requests - // from it must pass through its white-list. This *does* break PDFs that - // contain links to other remote PDF/websites. - // More info at https://issues.apache.org/jira/browse/CB-2225 - BOOL isPDF = [@"true" isEqualToString :[theWebView stringByEvaluatingJavaScriptFromString:@"document.body==null"]]; - if (isPDF) { - [CDVUserAgentUtil setUserAgent:_prevUserAgent lockToken:_userAgentLockToken]; - } - - [self.navigationDelegate webViewDidFinishLoad:theWebView]; -} - -- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error -{ - // log fail message, stop spinner, update back/forward - NSLog(@"webView:didFailLoadWithError - %@", [error localizedDescription]); - - self.backButton.enabled = theWebView.canGoBack; - self.forwardButton.enabled = theWebView.canGoForward; - [self.spinner stopAnimating]; - - self.addressLabel.text = @"Load Error"; - - [self.navigationDelegate webView:theWebView didFailLoadWithError:error]; -} - -#pragma mark CDVScreenOrientationDelegate - -- (BOOL)shouldAutorotate -{ - if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotate)]) { - return [self.orientationDelegate shouldAutorotate]; - } - return YES; -} - -- (NSUInteger)supportedInterfaceOrientations -{ - if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(supportedInterfaceOrientations)]) { - return [self.orientationDelegate supportedInterfaceOrientations]; - } - - return 1 << UIInterfaceOrientationPortrait; -} - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) { - return [self.orientationDelegate shouldAutorotateToInterfaceOrientation:interfaceOrientation]; - } - - return YES; -} - -@end - -@implementation CDVInAppBrowserOptions - -- (id)init -{ - if (self = [super init]) { - // default values - self.location = YES; - self.toolbar = YES; - self.closebuttoncaption = nil; - - self.enableviewportscale = NO; - self.mediaplaybackrequiresuseraction = NO; - self.allowinlinemediaplayback = NO; - self.keyboarddisplayrequiresuseraction = YES; - self.suppressesincrementalrendering = NO; - self.hidden = NO; - } - - return self; -} - -+ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options -{ - CDVInAppBrowserOptions* obj = [[CDVInAppBrowserOptions alloc] init]; - - // NOTE: this parsing does not handle quotes within values - NSArray* pairs = [options componentsSeparatedByString:@","]; - - // parse keys and values, set the properties - for (NSString* pair in pairs) { - NSArray* keyvalue = [pair componentsSeparatedByString:@"="]; - - if ([keyvalue count] == 2) { - NSString* key = [[keyvalue objectAtIndex:0] lowercaseString]; - NSString* value = [keyvalue objectAtIndex:1]; - NSString* value_lc = [value lowercaseString]; - - BOOL isBoolean = [value_lc isEqualToString:@"yes"] || [value_lc isEqualToString:@"no"]; - NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init]; - [numberFormatter setAllowsFloats:YES]; - BOOL isNumber = [numberFormatter numberFromString:value_lc] != nil; - - // set the property according to the key name - if ([obj respondsToSelector:NSSelectorFromString(key)]) { - if (isNumber) { - [obj setValue:[numberFormatter numberFromString:value_lc] forKey:key]; - } else if (isBoolean) { - [obj setValue:[NSNumber numberWithBool:[value_lc isEqualToString:@"yes"]] forKey:key]; - } else { - [obj setValue:value forKey:key]; - } - } - } - } - - return obj; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVInvokedUrlCommand.h b/iPhone/CordovaLib/Classes/CDVInvokedUrlCommand.h deleted file mode 100755 index 7be8884..0000000 --- a/iPhone/CordovaLib/Classes/CDVInvokedUrlCommand.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import - -@interface CDVInvokedUrlCommand : NSObject { - NSString* _callbackId; - NSString* _className; - NSString* _methodName; - NSArray* _arguments; -} - -@property (nonatomic, readonly) NSArray* arguments; -@property (nonatomic, readonly) NSString* callbackId; -@property (nonatomic, readonly) NSString* className; -@property (nonatomic, readonly) NSString* methodName; - -+ (CDVInvokedUrlCommand*)commandFromJson:(NSArray*)jsonEntry; - -- (id)initWithArguments:(NSArray*)arguments - callbackId:(NSString*)callbackId - className:(NSString*)className - methodName:(NSString*)methodName; - -- (id)initFromJson:(NSArray*)jsonEntry; - -// The first NSDictionary found in the arguments will be returned in legacyDict. -// The arguments array with be prepended with the callbackId and have the first -// dict removed from it. -- (void)legacyArguments:(NSMutableArray**)legacyArguments andDict:(NSMutableDictionary**)legacyDict; - -// Returns the argument at the given index. -// If index >= the number of arguments, returns nil. -// If the argument at the given index is NSNull, returns nil. -- (id)argumentAtIndex:(NSUInteger)index; -// Same as above, but returns defaultValue instead of nil. -- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue; -// Same as above, but returns defaultValue instead of nil, and if the argument is not of the expected class, returns defaultValue -- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue andClass:(Class)aClass; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVInvokedUrlCommand.m b/iPhone/CordovaLib/Classes/CDVInvokedUrlCommand.m deleted file mode 100755 index 6c7a856..0000000 --- a/iPhone/CordovaLib/Classes/CDVInvokedUrlCommand.m +++ /dev/null @@ -1,140 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVInvokedUrlCommand.h" -#import "CDVJSON.h" -#import "NSData+Base64.h" - -@implementation CDVInvokedUrlCommand - -@synthesize arguments = _arguments; -@synthesize callbackId = _callbackId; -@synthesize className = _className; -@synthesize methodName = _methodName; - -+ (CDVInvokedUrlCommand*)commandFromJson:(NSArray*)jsonEntry -{ - return [[CDVInvokedUrlCommand alloc] initFromJson:jsonEntry]; -} - -- (id)initFromJson:(NSArray*)jsonEntry -{ - id tmp = [jsonEntry objectAtIndex:0]; - NSString* callbackId = tmp == [NSNull null] ? nil : tmp; - NSString* className = [jsonEntry objectAtIndex:1]; - NSString* methodName = [jsonEntry objectAtIndex:2]; - NSMutableArray* arguments = [jsonEntry objectAtIndex:3]; - - return [self initWithArguments:arguments - callbackId:callbackId - className:className - methodName:methodName]; -} - -- (id)initWithArguments:(NSArray*)arguments - callbackId:(NSString*)callbackId - className:(NSString*)className - methodName:(NSString*)methodName -{ - self = [super init]; - if (self != nil) { - _arguments = arguments; - _callbackId = callbackId; - _className = className; - _methodName = methodName; - } - [self massageArguments]; - return self; -} - -- (void)massageArguments -{ - NSMutableArray* newArgs = nil; - - for (NSUInteger i = 0, count = [_arguments count]; i < count; ++i) { - id arg = [_arguments objectAtIndex:i]; - if (![arg isKindOfClass:[NSDictionary class]]) { - continue; - } - NSDictionary* dict = arg; - NSString* type = [dict objectForKey:@"CDVType"]; - if (!type || ![type isEqualToString:@"ArrayBuffer"]) { - continue; - } - NSString* data = [dict objectForKey:@"data"]; - if (!data) { - continue; - } - if (newArgs == nil) { - newArgs = [NSMutableArray arrayWithArray:_arguments]; - _arguments = newArgs; - } - [newArgs replaceObjectAtIndex:i withObject:[NSData dataFromBase64String:data]]; - } -} - -- (void)legacyArguments:(NSMutableArray**)legacyArguments andDict:(NSMutableDictionary**)legacyDict -{ - NSMutableArray* newArguments = [NSMutableArray arrayWithArray:_arguments]; - - for (NSUInteger i = 0; i < [newArguments count]; ++i) { - if ([[newArguments objectAtIndex:i] isKindOfClass:[NSDictionary class]]) { - if (legacyDict != NULL) { - *legacyDict = [newArguments objectAtIndex:i]; - } - [newArguments removeObjectAtIndex:i]; - break; - } - } - - // Legacy (two versions back) has no callbackId. - if (_callbackId != nil) { - [newArguments insertObject:_callbackId atIndex:0]; - } - if (legacyArguments != NULL) { - *legacyArguments = newArguments; - } -} - -- (id)argumentAtIndex:(NSUInteger)index -{ - return [self argumentAtIndex:index withDefault:nil]; -} - -- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue -{ - return [self argumentAtIndex:index withDefault:defaultValue andClass:nil]; -} - -- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue andClass:(Class)aClass -{ - if (index >= [_arguments count]) { - return defaultValue; - } - id ret = [_arguments objectAtIndex:index]; - if (ret == [NSNull null]) { - ret = defaultValue; - } - if ((aClass != nil) && ![ret isKindOfClass:aClass]) { - ret = defaultValue; - } - return ret; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVJSON.h b/iPhone/CordovaLib/Classes/CDVJSON.h deleted file mode 100755 index eaa895e..0000000 --- a/iPhone/CordovaLib/Classes/CDVJSON.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -@interface NSArray (CDVJSONSerializing) -- (NSString*)JSONString; -@end - -@interface NSDictionary (CDVJSONSerializing) -- (NSString*)JSONString; -@end - -@interface NSString (CDVJSONSerializing) -- (id)JSONObject; -@end diff --git a/iPhone/CordovaLib/Classes/CDVJSON.m b/iPhone/CordovaLib/Classes/CDVJSON.m deleted file mode 100755 index 78267e5..0000000 --- a/iPhone/CordovaLib/Classes/CDVJSON.m +++ /dev/null @@ -1,77 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVJSON.h" -#import - -@implementation NSArray (CDVJSONSerializing) - -- (NSString*)JSONString -{ - NSError* error = nil; - NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self - options:NSJSONWritingPrettyPrinted - error:&error]; - - if (error != nil) { - NSLog(@"NSArray JSONString error: %@", [error localizedDescription]); - return nil; - } else { - return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; - } -} - -@end - -@implementation NSDictionary (CDVJSONSerializing) - -- (NSString*)JSONString -{ - NSError* error = nil; - NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self - options:NSJSONWritingPrettyPrinted - error:&error]; - - if (error != nil) { - NSLog(@"NSDictionary JSONString error: %@", [error localizedDescription]); - return nil; - } else { - return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; - } -} - -@end - -@implementation NSString (CDVJSONSerializing) - -- (id)JSONObject -{ - NSError* error = nil; - id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding] - options:kNilOptions - error:&error]; - - if (error != nil) { - NSLog(@"NSString JSONObject error: %@", [error localizedDescription]); - } - - return object; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVJpegHeaderWriter.h b/iPhone/CordovaLib/Classes/CDVJpegHeaderWriter.h deleted file mode 100755 index 3b43ef0..0000000 --- a/iPhone/CordovaLib/Classes/CDVJpegHeaderWriter.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import - -@interface CDVJpegHeaderWriter : NSObject { - NSDictionary * SubIFDTagFormatDict; - NSDictionary * IFD0TagFormatDict; -} - -- (NSData*) spliceExifBlockIntoJpeg: (NSData*) jpegdata - withExifBlock: (NSString*) exifstr; -- (NSString*) createExifAPP1 : (NSDictionary*) datadict; -- (NSString*) formattedHexStringFromDecimalNumber: (NSNumber*) numb - withPlaces: (NSNumber*) width; -- (NSString*) formatNumberWithLeadingZeroes: (NSNumber*) numb - withPlaces: (NSNumber*) places; -- (NSString*) decimalToUnsignedRational: (NSNumber*) numb - withResultNumerator: (NSNumber**) numerator - withResultDenominator: (NSNumber**) denominator; -- (void) continuedFraction: (double) val - withFractionList: (NSMutableArray*) fractionlist - withHorizon: (int) horizon; -//- (void) expandContinuedFraction: (NSArray*) fractionlist; -- (void) splitDouble: (double) val - withIntComponent: (int*) rightside - withFloatRemainder: (double*) leftside; -- (NSString*) formatRationalWithNumerator: (NSNumber*) numerator - withDenominator: (NSNumber*) denominator - asSigned: (Boolean) signedFlag; -- (NSString*) hexStringFromData : (NSData*) data; -- (NSNumber*) numericFromHexString : (NSString *) hexstring; - -/* -- (void) readExifMetaData : (NSData*) imgdata; -- (void) spliceImageData : (NSData*) imgdata withExifData: (NSDictionary*) exifdata; -- (void) locateExifMetaData : (NSData*) imgdata; -- (NSString*) createExifAPP1 : (NSDictionary*) datadict; -- (void) createExifDataString : (NSDictionary*) datadict; -- (NSString*) createDataElement : (NSString*) element - withElementData: (NSString*) data - withExternalDataBlock: (NSDictionary*) memblock; -- (NSString*) hexStringFromData : (NSData*) data; -- (NSNumber*) numericFromHexString : (NSString *) hexstring; -*/ -@end diff --git a/iPhone/CordovaLib/Classes/CDVJpegHeaderWriter.m b/iPhone/CordovaLib/Classes/CDVJpegHeaderWriter.m deleted file mode 100755 index 93cafb8..0000000 --- a/iPhone/CordovaLib/Classes/CDVJpegHeaderWriter.m +++ /dev/null @@ -1,547 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVJpegHeaderWriter.h" -#include "CDVExif.h" - -/* macros for tag info shorthand: - tagno : tag number - typecode : data type - components : number of components - appendString (TAGINF_W_APPEND only) : string to append to data - Exif date data format include an extra 0x00 to the end of the data - */ -#define TAGINF(tagno, typecode, components) [NSArray arrayWithObjects: tagno, typecode, components, nil] -#define TAGINF_W_APPEND(tagno, typecode, components, appendString) [NSArray arrayWithObjects: tagno, typecode, components, appendString, nil] - -const uint mJpegId = 0xffd8; // JPEG format marker -const uint mExifMarker = 0xffe1; // APP1 jpeg header marker -const uint mExif = 0x45786966; // ASCII 'Exif', first characters of valid exif header after size -const uint mMotorallaByteAlign = 0x4d4d; // 'MM', motorola byte align, msb first or 'sane' -const uint mIntelByteAlgin = 0x4949; // 'II', Intel byte align, lsb first or 'batshit crazy reverso world' -const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a(MM) or 0x2a00(II), tiff version number - - -@implementation CDVJpegHeaderWriter - -- (id) init { - self = [super init]; - // supported tags for exif IFD - IFD0TagFormatDict = [[NSDictionary alloc] initWithObjectsAndKeys: - // TAGINF(@"010e", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"ImageDescription", - TAGINF_W_APPEND(@"0132", [NSNumber numberWithInt:EDT_ASCII_STRING], @20, @"00"), @"DateTime", - TAGINF(@"010f", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Make", - TAGINF(@"0110", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Model", - TAGINF(@"0131", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Software", - TAGINF(@"011a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"XResolution", - TAGINF(@"011b", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"YResolution", - // currently supplied outside of Exif data block by UIImagePickerControllerMediaMetadata, this is set manually in CDVCamera.m - /* TAGINF(@"0112", [NSNumber numberWithInt:EDT_USHORT], @1), @"Orientation", - - // rest of the tags are supported by exif spec, but are not specified by UIImagePickerControllerMediaMedadata - // should camera hardware supply these values in future versions, or if they can be derived, ImageHeaderWriter will include them gracefully - TAGINF(@"0128", [NSNumber numberWithInt:EDT_USHORT], @1), @"ResolutionUnit", - TAGINF(@"013e", [NSNumber numberWithInt:EDT_URATIONAL], @2), @"WhitePoint", - TAGINF(@"013f", [NSNumber numberWithInt:EDT_URATIONAL], @6), @"PrimaryChromaticities", - TAGINF(@"0211", [NSNumber numberWithInt:EDT_URATIONAL], @3), @"YCbCrCoefficients", - TAGINF(@"0213", [NSNumber numberWithInt:EDT_USHORT], @1), @"YCbCrPositioning", - TAGINF(@"0214", [NSNumber numberWithInt:EDT_URATIONAL], @6), @"ReferenceBlackWhite", - TAGINF(@"8298", [NSNumber numberWithInt:EDT_URATIONAL], @0), @"Copyright", - - // offset to exif subifd, we determine this dynamically based on the size of the main exif IFD - TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1), @"ExifOffset",*/ - nil]; - - - // supported tages for exif subIFD - SubIFDTagFormatDict = [[NSDictionary alloc] initWithObjectsAndKeys: - //TAGINF(@"9000", [NSNumber numberWithInt:], @), @"ExifVersion", - //TAGINF(@"9202",[NSNumber numberWithInt:EDT_URATIONAL],@1), @"ApertureValue", - //TAGINF(@"9203",[NSNumber numberWithInt:EDT_SRATIONAL],@1), @"BrightnessValue", - TAGINF(@"a001",[NSNumber numberWithInt:EDT_USHORT],@1), @"ColorSpace", - TAGINF_W_APPEND(@"9004",[NSNumber numberWithInt:EDT_ASCII_STRING],@20,@"00"), @"DateTimeDigitized", - TAGINF_W_APPEND(@"9003",[NSNumber numberWithInt:EDT_ASCII_STRING],@20,@"00"), @"DateTimeOriginal", - TAGINF(@"a402", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureMode", - TAGINF(@"8822", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureProgram", - //TAGINF(@"829a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"ExposureTime", - //TAGINF(@"829d", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FNumber", - TAGINF(@"9209", [NSNumber numberWithInt:EDT_USHORT], @1), @"Flash", - // FocalLengthIn35mmFilm - TAGINF(@"a405", [NSNumber numberWithInt:EDT_USHORT], @1), @"FocalLenIn35mmFilm", - //TAGINF(@"920a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FocalLength", - //TAGINF(@"8827", [NSNumber numberWithInt:EDT_USHORT], @2), @"ISOSpeedRatings", - TAGINF(@"9207", [NSNumber numberWithInt:EDT_USHORT],@1), @"MeteringMode", - // specific to compressed data - TAGINF(@"a002", [NSNumber numberWithInt:EDT_ULONG],@1), @"PixelXDimension", - TAGINF(@"a003", [NSNumber numberWithInt:EDT_ULONG],@1), @"PixelYDimension", - // data type undefined, but this is a DSC camera, so value is always 1, treat as ushort - TAGINF(@"a301", [NSNumber numberWithInt:EDT_USHORT],@1), @"SceneType", - TAGINF(@"a217",[NSNumber numberWithInt:EDT_USHORT],@1), @"SensingMethod", - //TAGINF(@"9201", [NSNumber numberWithInt:EDT_SRATIONAL], @1), @"ShutterSpeedValue", - // specifies location of main subject in scene (x,y,wdith,height) expressed before rotation processing - //TAGINF(@"9214", [NSNumber numberWithInt:EDT_USHORT], @4), @"SubjectArea", - TAGINF(@"a403", [NSNumber numberWithInt:EDT_USHORT], @1), @"WhiteBalance", - nil]; - return self; -} - -- (NSData*) spliceExifBlockIntoJpeg: (NSData*) jpegdata withExifBlock: (NSString*) exifstr { - - CDVJpegHeaderWriter * exifWriter = [[CDVJpegHeaderWriter alloc] init]; - - NSMutableData * exifdata = [NSMutableData dataWithCapacity: [exifstr length]/2]; - int idx; - for (idx = 0; idx+1 < [exifstr length]; idx+=2) { - NSRange range = NSMakeRange(idx, 2); - NSString* hexStr = [exifstr substringWithRange:range]; - NSScanner* scanner = [NSScanner scannerWithString:hexStr]; - unsigned int intValue; - [scanner scanHexInt:&intValue]; - [exifdata appendBytes:&intValue length:1]; - } - - NSMutableData * ddata = [NSMutableData dataWithCapacity: [jpegdata length]]; - NSMakeRange(0,4); - int loc = 0; - bool done = false; - // read the jpeg data until we encounter the app1==0xFFE1 marker - while (loc+1 < [jpegdata length]) { - NSData * blag = [jpegdata subdataWithRange: NSMakeRange(loc,2)]; - if( [[blag description] isEqualToString : @""]) { - // read the APP1 block size bits - NSString * the = [exifWriter hexStringFromData:[jpegdata subdataWithRange: NSMakeRange(loc+2,2)]]; - NSNumber * app1width = [exifWriter numericFromHexString:the]; - //consume the original app1 block - [ddata appendData:exifdata]; - // advance our loc marker past app1 - loc += [app1width intValue] + 2; - done = true; - } else { - if(!done) { - [ddata appendData:blag]; - loc += 2; - } else { - break; - } - } - } - // copy the remaining data - [ddata appendData:[jpegdata subdataWithRange: NSMakeRange(loc,[jpegdata length]-loc)]]; - return ddata; -} - - - -/** - * Create the Exif data block as a hex string - * jpeg uses Application Markers (APP's) as markers for application data - * APP1 is the application marker reserved for exif data - * - * (NSDictionary*) datadict - with subdictionaries marked '{TIFF}' and '{EXIF}' as returned by imagePickerController with a valid - * didFinishPickingMediaWithInfo data dict, under key @"UIImagePickerControllerMediaMetadata" - * - * the following constructs a hex string to Exif specifications, and is therefore brittle - * altering the order of arguments to the string constructors, modifying field sizes or formats, - * and any other minor change will likely prevent the exif data from being read - */ -- (NSString*) createExifAPP1 : (NSDictionary*) datadict { - NSMutableString * app1; // holds finalized product - NSString * exifIFD; // exif information file directory - NSString * subExifIFD; // subexif information file directory - - // FFE1 is the hex APP1 marker code, and will allow client apps to read the data - NSString * app1marker = @"ffe1"; - // SSSS size, to be determined - // EXIF ascii characters followed by 2bytes of zeros - NSString * exifmarker = @"457869660000"; - // Tiff header: 4d4d is motorolla byte align (big endian), 002a is hex for 42 - NSString * tiffheader = @"4d4d002a"; - //first IFD offset from the Tiff header to IFD0. Since we are writing it, we know it's address 0x08 - NSString * ifd0offset = @"00000008"; - // current offset to next data area - int currentDataOffset = 0; - - //data labeled as TIFF in UIImagePickerControllerMediaMetaData is part of the EXIF IFD0 portion of APP1 - exifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{TIFF}"] withFormatDict: IFD0TagFormatDict isIFD0:YES currentDataOffset:¤tDataOffset]; - - //data labeled as EXIF in UIImagePickerControllerMediaMetaData is part of the EXIF Sub IFD portion of APP1 - subExifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{Exif}"] withFormatDict: SubIFDTagFormatDict isIFD0:NO currentDataOffset:¤tDataOffset]; - /* - NSLog(@"SUB EXIF IFD %@ WITH SIZE: %d",exifIFD,[exifIFD length]); - - NSLog(@"SUB EXIF IFD %@ WITH SIZE: %d",subExifIFD,[subExifIFD length]); - */ - // construct the complete app1 data block - app1 = [[NSMutableString alloc] initWithFormat: @"%@%04x%@%@%@%@%@", - app1marker, - 16 + ([exifIFD length]/2) + ([subExifIFD length]/2) /*16+[exifIFD length]/2*/, - exifmarker, - tiffheader, - ifd0offset, - exifIFD, - subExifIFD]; - - return app1; -} - -// returns hex string representing a valid exif information file directory constructed from the datadict and formatdict -- (NSString*) createExifIFDFromDict : (NSDictionary*) datadict - withFormatDict : (NSDictionary*) formatdict - isIFD0 : (BOOL) ifd0flag - currentDataOffset : (int*) dataoffset { - NSArray * datakeys = [datadict allKeys]; // all known data keys - NSArray * knownkeys = [formatdict allKeys]; // only keys in knowkeys are considered for entry in this IFD - NSMutableArray * ifdblock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // all ifd entries - NSMutableArray * ifddatablock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // data block entries - // ifd0flag = NO; // ifd0 requires a special flag and has offset to next ifd appended to end - - // iterate through known provided data keys - for (int i = 0; i < [datakeys count]; i++) { - NSString * key = [datakeys objectAtIndex:i]; - // don't muck about with unknown keys - if ([knownkeys indexOfObject: key] != NSNotFound) { - // create new IFD entry - NSString * entry = [self createIFDElement: key - withFormat: [formatdict objectForKey:key] - withElementData: [datadict objectForKey:key]]; - // create the IFD entry's data block - NSString * data = [self createIFDElementDataWithFormat: [formatdict objectForKey:key] - withData: [datadict objectForKey:key]]; - if (entry) { - [ifdblock addObject:entry]; - if(!data) { - [ifdblock addObject:@""]; - } else { - [ifddatablock addObject:data]; - } - } - } - } - - NSMutableString * exifstr = [[NSMutableString alloc] initWithCapacity: [ifdblock count] * 24]; - NSMutableString * dbstr = [[NSMutableString alloc] initWithCapacity: 100]; - - int addr=*dataoffset; // current offset/address in datablock - if (ifd0flag) { - // calculate offset to datablock based on ifd file entry count - addr += 14+(12*([ifddatablock count]+1)); // +1 for tag 0x8769, exifsubifd offset - } else { - // current offset + numSubIFDs (2-bytes) + 12*numSubIFDs + endMarker (4-bytes) - addr += 2+(12*[ifddatablock count])+4; - } - - for (int i = 0; i < [ifdblock count]; i++) { - NSString * entry = [ifdblock objectAtIndex:i]; - NSString * data = [ifddatablock objectAtIndex:i]; - - // check if the data fits into 4 bytes - if( [data length] <= 8) { - // concatenate the entry and the (4byte) data entry into the final IFD entry and append to exif ifd string - [exifstr appendFormat : @"%@%@", entry, data]; - } else { - [exifstr appendFormat : @"%@%08x", entry, addr]; - [dbstr appendFormat: @"%@", data]; - addr+= [data length] / 2; - /* - NSLog(@"=====data-length[%i]=======",[data length]); - NSLog(@"addr-offset[%i]",addr); - NSLog(@"entry[%@]",entry); - NSLog(@"data[%@]",data); - */ - } - } - - // calculate IFD0 terminal offset tags, currently ExifSubIFD - int entrycount = [ifdblock count]; - if (ifd0flag) { - // 18 accounts for 8769's width + offset to next ifd, 8 accounts for start of header - NSNumber * offset = [NSNumber numberWithInt:[exifstr length] / 2 + [dbstr length] / 2 + 18+8]; - - [self appendExifOffsetTagTo: exifstr - withOffset : offset]; - entrycount++; - } - *dataoffset = addr; - return [[NSString alloc] initWithFormat: @"%04x%@%@%@", - entrycount, - exifstr, - @"00000000", // offset to next IFD, 0 since there is none - dbstr]; // lastly, the datablock -} - -// Creates an exif formatted exif information file directory entry -- (NSString*) createIFDElement: (NSString*) elementName withFormat: (NSArray*) formtemplate withElementData: (NSString*) data { - //NSArray * fielddata = [formatdict objectForKey: elementName];// format data of desired field - if (formtemplate) { - // format string @"%@%@%@%@", tag number, data format, components, value - NSNumber * dataformat = [formtemplate objectAtIndex:1]; - NSNumber * components = [formtemplate objectAtIndex:2]; - if([components intValue] == 0) { - components = [NSNumber numberWithInt: [data length] * DataTypeToWidth[[dataformat intValue]-1]]; - } - - return [[NSString alloc] initWithFormat: @"%@%@%08x", - [formtemplate objectAtIndex:0], // the field code - [self formatNumberWithLeadingZeroes: dataformat withPlaces: @4], // the data type code - [components intValue]]; // number of components - } - return NULL; -} - -/** - * appends exif IFD0 tag 8769 "ExifOffset" to the string provided - * (NSMutableString*) str - string you wish to append the 8769 tag to: APP1 or IFD0 hex data string - * // TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1), @"ExifOffset", - */ -- (void) appendExifOffsetTagTo: (NSMutableString*) str withOffset : (NSNumber*) offset { - NSArray * format = TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1); - - NSString * entry = [self createIFDElement: @"ExifOffset" - withFormat: format - withElementData: [offset stringValue]]; - - NSString * data = [self createIFDElementDataWithFormat: format - withData: [offset stringValue]]; - [str appendFormat:@"%@%@", entry, data]; -} - -// formats the Information File Directory Data to exif format -- (NSString*) createIFDElementDataWithFormat: (NSArray*) dataformat withData: (NSString*) data { - NSMutableString * datastr = nil; - NSNumber * tmp = nil; - NSNumber * formatcode = [dataformat objectAtIndex:1]; - NSUInteger formatItemsCount = [dataformat count]; - NSNumber * num = @0; - NSNumber * denom = @0; - - switch ([formatcode intValue]) { - case EDT_UBYTE: - break; - case EDT_ASCII_STRING: - datastr = [[NSMutableString alloc] init]; - for (int i = 0; i < [data length]; i++) { - [datastr appendFormat:@"%02x",[data characterAtIndex:i]]; - } - if (formatItemsCount > 3) { - // We have additional data to append. - // currently used by Date format to append final 0x00 but can be used by other data types as well in the future - [datastr appendString:[dataformat objectAtIndex:3]]; - } - if ([datastr length] < 8) { - NSString * format = [NSString stringWithFormat:@"%%0%dd", 8 - [datastr length]]; - [datastr appendFormat:format,0]; - } - return datastr; - case EDT_USHORT: - return [[NSString alloc] initWithFormat : @"%@%@", - [self formattedHexStringFromDecimalNumber: [NSNumber numberWithInt: [data intValue]] withPlaces: @4], - @"0000"]; - case EDT_ULONG: - tmp = [NSNumber numberWithUnsignedLong:[data intValue]]; - return [NSString stringWithFormat : @"%@", - [self formattedHexStringFromDecimalNumber: tmp withPlaces: @8]]; - case EDT_URATIONAL: - return [self decimalToUnsignedRational: [NSNumber numberWithDouble:[data doubleValue]] - withResultNumerator: &num - withResultDenominator: &denom]; - case EDT_SBYTE: - - break; - case EDT_UNDEFINED: - break; // 8 bits - case EDT_SSHORT: - break; - case EDT_SLONG: - break; // 32bit signed integer (2's complement) - case EDT_SRATIONAL: - break; // 2 SLONGS, first long is numerator, second is denominator - case EDT_SINGLEFLOAT: - break; - case EDT_DOUBLEFLOAT: - break; - } - return datastr; -} - -//====================================================================================================================== -// Utility Methods -//====================================================================================================================== - -// creates a formatted little endian hex string from a number and width specifier -- (NSString*) formattedHexStringFromDecimalNumber: (NSNumber*) numb withPlaces: (NSNumber*) width { - NSMutableString * str = [[NSMutableString alloc] initWithCapacity:[width intValue]]; - NSString * formatstr = [[NSString alloc] initWithFormat: @"%%%@%dx", @"0", [width intValue]]; - [str appendFormat:formatstr, [numb intValue]]; - return str; -} - -// format number as string with leading 0's -- (NSString*) formatNumberWithLeadingZeroes: (NSNumber *) numb withPlaces: (NSNumber *) places { - NSNumberFormatter * formatter = [[NSNumberFormatter alloc] init]; - NSString *formatstr = [@"" stringByPaddingToLength:[places unsignedIntegerValue] withString:@"0" startingAtIndex:0]; - [formatter setPositiveFormat:formatstr]; - return [formatter stringFromNumber:numb]; -} - -// approximate a decimal with a rational by method of continued fraction -// can be collasped into decimalToUnsignedRational after testing -- (void) decimalToRational: (NSNumber *) numb - withResultNumerator: (NSNumber**) numerator - withResultDenominator: (NSNumber**) denominator { - NSMutableArray * fractionlist = [[NSMutableArray alloc] initWithCapacity:8]; - - [self continuedFraction: [numb doubleValue] - withFractionList: fractionlist - withHorizon: 8]; - - // simplify complex fraction represented by partial fraction list - [self expandContinuedFraction: fractionlist - withResultNumerator: numerator - withResultDenominator: denominator]; - -} - -// approximate a decimal with an unsigned rational by method of continued fraction -- (NSString*) decimalToUnsignedRational: (NSNumber *) numb - withResultNumerator: (NSNumber**) numerator - withResultDenominator: (NSNumber**) denominator { - NSMutableArray * fractionlist = [[NSMutableArray alloc] initWithCapacity:8]; - - // generate partial fraction list - [self continuedFraction: [numb doubleValue] - withFractionList: fractionlist - withHorizon: 8]; - - // simplify complex fraction represented by partial fraction list - [self expandContinuedFraction: fractionlist - withResultNumerator: numerator - withResultDenominator: denominator]; - - return [self formatFractionList: fractionlist]; -} - -// recursive implementation of decimal approximation by continued fraction -- (void) continuedFraction: (double) val - withFractionList: (NSMutableArray*) fractionlist - withHorizon: (int) horizon { - int whole; - double remainder; - // 1. split term - [self splitDouble: val withIntComponent: &whole withFloatRemainder: &remainder]; - [fractionlist addObject: [NSNumber numberWithInt:whole]]; - - // 2. calculate reciprocal of remainder - if (!remainder) return; // early exit, exact fraction found, avoids recip/0 - double recip = 1 / remainder; - - // 3. exit condition - if ([fractionlist count] > horizon) { - return; - } - - // 4. recurse - [self continuedFraction:recip withFractionList: fractionlist withHorizon: horizon]; - -} - -// expand continued fraction list, creating a single level rational approximation --(void) expandContinuedFraction: (NSArray*) fractionlist - withResultNumerator: (NSNumber**) numerator - withResultDenominator: (NSNumber**) denominator { - int i = 0; - int den = 0; - int num = 0; - if ([fractionlist count] == 1) { - *numerator = [NSNumber numberWithInt:[[fractionlist objectAtIndex:0] intValue]]; - *denominator = @1; - return; - } - - //begin at the end of the list - i = [fractionlist count] - 1; - num = 1; - den = [[fractionlist objectAtIndex:i] intValue]; - - while (i > 0) { - int t = [[fractionlist objectAtIndex: i-1] intValue]; - num = t * den + num; - if (i==1) { - break; - } else { - t = num; - num = den; - den = t; - } - i--; - } - // set result parameters values - *numerator = [NSNumber numberWithInt: num]; - *denominator = [NSNumber numberWithInt: den]; -} - -// formats expanded fraction list to string matching exif specification -- (NSString*) formatFractionList: (NSArray *) fractionlist { - NSMutableString * str = [[NSMutableString alloc] initWithCapacity:16]; - - if ([fractionlist count] == 1){ - [str appendFormat: @"%08x00000001", [[fractionlist objectAtIndex:0] intValue]]; - } - return str; -} - -// format rational as -- (NSString*) formatRationalWithNumerator: (NSNumber*) numerator withDenominator: (NSNumber*) denominator asSigned: (Boolean) signedFlag { - NSMutableString * str = [[NSMutableString alloc] initWithCapacity:16]; - if (signedFlag) { - long num = [numerator longValue]; - long den = [denominator longValue]; - [str appendFormat: @"%08lx%08lx", num >= 0 ? num : ~ABS(num) + 1, num >= 0 ? den : ~ABS(den) + 1]; - } else { - [str appendFormat: @"%08lx%08lx", [numerator unsignedLongValue], [denominator unsignedLongValue]]; - } - return str; -} - -// split a floating point number into two integer values representing the left and right side of the decimal -- (void) splitDouble: (double) val withIntComponent: (int*) rightside withFloatRemainder: (double*) leftside { - *rightside = val; // convert numb to int representation, which truncates the decimal portion - *leftside = val - *rightside; -} - - -// -- (NSString*) hexStringFromData : (NSData*) data { - //overflow detection - const unsigned char *dataBuffer = [data bytes]; - return [[NSString alloc] initWithFormat: @"%02x%02x", - (unsigned char)dataBuffer[0], - (unsigned char)dataBuffer[1]]; -} - -// convert a hex string to a number -- (NSNumber*) numericFromHexString : (NSString *) hexstring { - NSScanner * scan = NULL; - unsigned int numbuf= 0; - - scan = [NSScanner scannerWithString:hexstring]; - [scan scanHexInt:&numbuf]; - return [NSNumber numberWithInt:numbuf]; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVLocalStorage.h b/iPhone/CordovaLib/Classes/CDVLocalStorage.h deleted file mode 100755 index dec6ab3..0000000 --- a/iPhone/CordovaLib/Classes/CDVLocalStorage.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVPlugin.h" - -#define kCDVLocalStorageErrorDomain @"kCDVLocalStorageErrorDomain" -#define kCDVLocalStorageFileOperationError 1 - -@interface CDVLocalStorage : CDVPlugin - -@property (nonatomic, readonly, strong) NSMutableArray* backupInfo; - -- (BOOL)shouldBackup; -- (BOOL)shouldRestore; -- (void)backup:(CDVInvokedUrlCommand*)command; -- (void)restore:(CDVInvokedUrlCommand*)command; - -+ (void)__fixupDatabaseLocationsWithBackupType:(NSString*)backupType; -// Visible for testing. -+ (BOOL)__verifyAndFixDatabaseLocationsWithAppPlistDict:(NSMutableDictionary*)appPlistDict - bundlePath:(NSString*)bundlePath - fileManager:(NSFileManager*)fileManager; -@end - -@interface CDVBackupInfo : NSObject - -@property (nonatomic, copy) NSString* original; -@property (nonatomic, copy) NSString* backup; -@property (nonatomic, copy) NSString* label; - -- (BOOL)shouldBackup; -- (BOOL)shouldRestore; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVLocalStorage.m b/iPhone/CordovaLib/Classes/CDVLocalStorage.m deleted file mode 100755 index 238d680..0000000 --- a/iPhone/CordovaLib/Classes/CDVLocalStorage.m +++ /dev/null @@ -1,485 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVLocalStorage.h" -#import "CDV.h" - -@interface CDVLocalStorage () - -@property (nonatomic, readwrite, strong) NSMutableArray* backupInfo; // array of CDVBackupInfo objects -@property (nonatomic, readwrite, weak) id webviewDelegate; - -@end - -@implementation CDVLocalStorage - -@synthesize backupInfo, webviewDelegate; - -- (void)pluginInitialize -{ - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResignActive) - name:UIApplicationWillResignActiveNotification object:nil]; - BOOL cloudBackup = [@"cloud" isEqualToString : self.commandDelegate.settings[@"BackupWebStorage"]]; - - self.backupInfo = [[self class] createBackupInfoWithCloudBackup:cloudBackup]; -} - -#pragma mark - -#pragma mark Plugin interface methods - -+ (NSMutableArray*)createBackupInfoWithTargetDir:(NSString*)targetDir backupDir:(NSString*)backupDir targetDirNests:(BOOL)targetDirNests backupDirNests:(BOOL)backupDirNests rename:(BOOL)rename -{ - /* - This "helper" does so much work and has so many options it would probably be clearer to refactor the whole thing. - Basically, there are three database locations: - - 1. "Normal" dir -- LIB// - 2. "Caches" dir -- LIB/Caches/ - 3. "Backup" dir -- DOC/Backups/ - - And between these three, there are various migration paths, most of which only consider 2 of the 3, which is why this helper is based on 2 locations and has a notion of "direction". - */ - NSMutableArray* backupInfo = [NSMutableArray arrayWithCapacity:3]; - - NSString* original; - NSString* backup; - CDVBackupInfo* backupItem; - - // ////////// LOCALSTORAGE - - original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/file__0.localstorage":@"file__0.localstorage"]; - backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")]; - backup = [backup stringByAppendingPathComponent:(rename ? @"localstorage.appdata.db" : @"file__0.localstorage")]; - - backupItem = [[CDVBackupInfo alloc] init]; - backupItem.backup = backup; - backupItem.original = original; - backupItem.label = @"localStorage database"; - - [backupInfo addObject:backupItem]; - - // ////////// WEBSQL MAIN DB - - original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/Databases.db":@"Databases.db"]; - backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")]; - backup = [backup stringByAppendingPathComponent:(rename ? @"websqlmain.appdata.db" : @"Databases.db")]; - - backupItem = [[CDVBackupInfo alloc] init]; - backupItem.backup = backup; - backupItem.original = original; - backupItem.label = @"websql main database"; - - [backupInfo addObject:backupItem]; - - // ////////// WEBSQL DATABASES - - original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/file__0":@"file__0"]; - backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")]; - backup = [backup stringByAppendingPathComponent:(rename ? @"websqldbs.appdata.db" : @"file__0")]; - - backupItem = [[CDVBackupInfo alloc] init]; - backupItem.backup = backup; - backupItem.original = original; - backupItem.label = @"websql databases"; - - [backupInfo addObject:backupItem]; - - return backupInfo; -} - -+ (NSMutableArray*)createBackupInfoWithCloudBackup:(BOOL)cloudBackup -{ - // create backup info from backup folder to caches folder - NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - NSString* cacheFolder = [appLibraryFolder stringByAppendingPathComponent:@"Caches"]; - NSString* backupsFolder = [appDocumentsFolder stringByAppendingPathComponent:@"Backups"]; - - // create the backups folder, if needed - [[NSFileManager defaultManager] createDirectoryAtPath:backupsFolder withIntermediateDirectories:YES attributes:nil error:nil]; - - [self addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:backupsFolder] skip:!cloudBackup]; - - return [self createBackupInfoWithTargetDir:cacheFolder backupDir:backupsFolder targetDirNests:NO backupDirNests:NO rename:YES]; -} - -+ (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL*)URL skip:(BOOL)skip -{ - NSAssert(IsAtLeastiOSVersion(@"5.1"), @"Cannot mark files for NSURLIsExcludedFromBackupKey on iOS less than 5.1"); - - NSError* error = nil; - BOOL success = [URL setResourceValue:[NSNumber numberWithBool:skip] forKey:NSURLIsExcludedFromBackupKey error:&error]; - if (!success) { - NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error); - } - return success; -} - -+ (BOOL)copyFrom:(NSString*)src to:(NSString*)dest error:(NSError* __autoreleasing*)error -{ - NSFileManager* fileManager = [NSFileManager defaultManager]; - - if (![fileManager fileExistsAtPath:src]) { - NSString* errorString = [NSString stringWithFormat:@"%@ file does not exist.", src]; - if (error != NULL) { - (*error) = [NSError errorWithDomain:kCDVLocalStorageErrorDomain - code:kCDVLocalStorageFileOperationError - userInfo:[NSDictionary dictionaryWithObject:errorString - forKey:NSLocalizedDescriptionKey]]; - } - return NO; - } - - // generate unique filepath in temp directory - CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault); - CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef); - NSString* tempBackup = [[NSTemporaryDirectory() stringByAppendingPathComponent:(__bridge NSString*)uuidString] stringByAppendingPathExtension:@"bak"]; - CFRelease(uuidString); - CFRelease(uuidRef); - - BOOL destExists = [fileManager fileExistsAtPath:dest]; - - // backup the dest - if (destExists && ![fileManager copyItemAtPath:dest toPath:tempBackup error:error]) { - return NO; - } - - // remove the dest - if (destExists && ![fileManager removeItemAtPath:dest error:error]) { - return NO; - } - - // create path to dest - if (!destExists && ![fileManager createDirectoryAtPath:[dest stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:error]) { - return NO; - } - - // copy src to dest - if ([fileManager copyItemAtPath:src toPath:dest error:error]) { - // success - cleanup - delete the backup to the dest - if ([fileManager fileExistsAtPath:tempBackup]) { - [fileManager removeItemAtPath:tempBackup error:error]; - } - return YES; - } else { - // failure - we restore the temp backup file to dest - [fileManager copyItemAtPath:tempBackup toPath:dest error:error]; - // cleanup - delete the backup to the dest - if ([fileManager fileExistsAtPath:tempBackup]) { - [fileManager removeItemAtPath:tempBackup error:error]; - } - return NO; - } -} - -- (BOOL)shouldBackup -{ - for (CDVBackupInfo* info in self.backupInfo) { - if ([info shouldBackup]) { - return YES; - } - } - - return NO; -} - -- (BOOL)shouldRestore -{ - for (CDVBackupInfo* info in self.backupInfo) { - if ([info shouldRestore]) { - return YES; - } - } - - return NO; -} - -/* copy from webkitDbLocation to persistentDbLocation */ -- (void)backup:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - - NSError* __autoreleasing error = nil; - CDVPluginResult* result = nil; - NSString* message = nil; - - for (CDVBackupInfo* info in self.backupInfo) { - if ([info shouldBackup]) { - [[self class] copyFrom:info.original to:info.backup error:&error]; - - if (callbackId) { - if (error == nil) { - message = [NSString stringWithFormat:@"Backed up: %@", info.label]; - NSLog(@"%@", message); - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:message]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } else { - message = [NSString stringWithFormat:@"Error in CDVLocalStorage (%@) backup: %@", info.label, [error localizedDescription]]; - NSLog(@"%@", message); - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:message]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - } - } - } -} - -/* copy from persistentDbLocation to webkitDbLocation */ -- (void)restore:(CDVInvokedUrlCommand*)command -{ - NSError* __autoreleasing error = nil; - CDVPluginResult* result = nil; - NSString* message = nil; - - for (CDVBackupInfo* info in self.backupInfo) { - if ([info shouldRestore]) { - [[self class] copyFrom:info.backup to:info.original error:&error]; - - if (error == nil) { - message = [NSString stringWithFormat:@"Restored: %@", info.label]; - NSLog(@"%@", message); - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:message]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } else { - message = [NSString stringWithFormat:@"Error in CDVLocalStorage (%@) restore: %@", info.label, [error localizedDescription]]; - NSLog(@"%@", message); - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:message]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } - } - } -} - -+ (void)__fixupDatabaseLocationsWithBackupType:(NSString*)backupType -{ - [self __verifyAndFixDatabaseLocations]; - [self __restoreLegacyDatabaseLocationsWithBackupType:backupType]; -} - -+ (void)__verifyAndFixDatabaseLocations -{ - NSBundle* mainBundle = [NSBundle mainBundle]; - NSString* bundlePath = [[mainBundle bundlePath] stringByDeletingLastPathComponent]; - NSString* bundleIdentifier = [[mainBundle infoDictionary] objectForKey:@"CFBundleIdentifier"]; - NSString* appPlistPath = [bundlePath stringByAppendingPathComponent:[NSString stringWithFormat:@"Library/Preferences/%@.plist", bundleIdentifier]]; - - NSMutableDictionary* appPlistDict = [NSMutableDictionary dictionaryWithContentsOfFile:appPlistPath]; - BOOL modified = [[self class] __verifyAndFixDatabaseLocationsWithAppPlistDict:appPlistDict - bundlePath:bundlePath - fileManager:[NSFileManager defaultManager]]; - - if (modified) { - BOOL ok = [appPlistDict writeToFile:appPlistPath atomically:YES]; - [[NSUserDefaults standardUserDefaults] synchronize]; - NSLog(@"Fix applied for database locations?: %@", ok ? @"YES" : @"NO"); - } -} - -+ (BOOL)__verifyAndFixDatabaseLocationsWithAppPlistDict:(NSMutableDictionary*)appPlistDict - bundlePath:(NSString*)bundlePath - fileManager:(NSFileManager*)fileManager -{ - NSString* libraryCaches = @"Library/Caches"; - NSString* libraryWebKit = @"Library/WebKit"; - - NSArray* keysToCheck = [NSArray arrayWithObjects: - @"WebKitLocalStorageDatabasePathPreferenceKey", - @"WebDatabaseDirectory", - nil]; - - BOOL dirty = NO; - - for (NSString* key in keysToCheck) { - NSString* value = [appPlistDict objectForKey:key]; - // verify key exists, and path is in app bundle, if not - fix - if ((value != nil) && ![value hasPrefix:bundlePath]) { - // the pathSuffix to use may be wrong - OTA upgrades from < 5.1 to 5.1 do keep the old path Library/WebKit, - // while Xcode synced ones do change the storage location to Library/Caches - NSString* newBundlePath = [bundlePath stringByAppendingPathComponent:libraryCaches]; - if (![fileManager fileExistsAtPath:newBundlePath]) { - newBundlePath = [bundlePath stringByAppendingPathComponent:libraryWebKit]; - } - [appPlistDict setValue:newBundlePath forKey:key]; - dirty = YES; - } - } - - return dirty; -} - -+ (void)__restoreLegacyDatabaseLocationsWithBackupType:(NSString*)backupType -{ - // on iOS 6, if you toggle between cloud/local backup, you must move database locations. Default upgrade from iOS5.1 to iOS6 is like a toggle from local to cloud. - if (!IsAtLeastiOSVersion(@"6.0")) { - return; - } - - NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - - NSMutableArray* backupInfo = [NSMutableArray arrayWithCapacity:0]; - - if ([backupType isEqualToString:@"cloud"]) { - // We would like to restore old backups/caches databases to the new destination (nested in lib folder) - [backupInfo addObjectsFromArray:[self createBackupInfoWithTargetDir:appLibraryFolder backupDir:[appDocumentsFolder stringByAppendingPathComponent:@"Backups"] targetDirNests:YES backupDirNests:NO rename:YES]]; - [backupInfo addObjectsFromArray:[self createBackupInfoWithTargetDir:appLibraryFolder backupDir:[appLibraryFolder stringByAppendingPathComponent:@"Caches"] targetDirNests:YES backupDirNests:NO rename:NO]]; - } else { - // For ios6 local backups we also want to restore from Backups dir -- but we don't need to do that here, since the plugin will do that itself. - [backupInfo addObjectsFromArray:[self createBackupInfoWithTargetDir:[appLibraryFolder stringByAppendingPathComponent:@"Caches"] backupDir:appLibraryFolder targetDirNests:NO backupDirNests:YES rename:NO]]; - } - - NSFileManager* manager = [NSFileManager defaultManager]; - - for (CDVBackupInfo* info in backupInfo) { - if ([manager fileExistsAtPath:info.backup]) { - if ([info shouldRestore]) { - NSLog(@"Restoring old webstorage backup. From: '%@' To: '%@'.", info.backup, info.original); - [self copyFrom:info.backup to:info.original error:nil]; - } - NSLog(@"Removing old webstorage backup: '%@'.", info.backup); - [manager removeItemAtPath:info.backup error:nil]; - } - } - - [[NSUserDefaults standardUserDefaults] setBool:[backupType isEqualToString:@"cloud"] forKey:@"WebKitStoreWebDataForBackup"]; -} - -#pragma mark - -#pragma mark Notification handlers - -- (void)onResignActive -{ - UIDevice* device = [UIDevice currentDevice]; - NSNumber* exitsOnSuspend = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIApplicationExitsOnSuspend"]; - - BOOL isMultitaskingSupported = [device respondsToSelector:@selector(isMultitaskingSupported)] && [device isMultitaskingSupported]; - - if (exitsOnSuspend == nil) { // if it's missing, it should be NO (i.e. multi-tasking on by default) - exitsOnSuspend = [NSNumber numberWithBool:NO]; - } - - if (exitsOnSuspend) { - [self backup:nil]; - } else if (isMultitaskingSupported) { - __block UIBackgroundTaskIdentifier backgroundTaskID = UIBackgroundTaskInvalid; - - backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ - [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID]; - backgroundTaskID = UIBackgroundTaskInvalid; - NSLog(@"Background task to backup WebSQL/LocalStorage expired."); - }]; - CDVLocalStorage __weak* weakSelf = self; - [self.commandDelegate runInBackground:^{ - [weakSelf backup:nil]; - - [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID]; - backgroundTaskID = UIBackgroundTaskInvalid; - }]; - } -} - -- (void)onAppTerminate -{ - [self onResignActive]; -} - -- (void)onReset -{ - [self restore:nil]; -} - -@end - -#pragma mark - -#pragma mark CDVBackupInfo implementation - -@implementation CDVBackupInfo - -@synthesize original, backup, label; - -- (BOOL)file:(NSString*)aPath isNewerThanFile:(NSString*)bPath -{ - NSFileManager* fileManager = [NSFileManager defaultManager]; - NSError* __autoreleasing error = nil; - - NSDictionary* aPathAttribs = [fileManager attributesOfItemAtPath:aPath error:&error]; - NSDictionary* bPathAttribs = [fileManager attributesOfItemAtPath:bPath error:&error]; - - NSDate* aPathModDate = [aPathAttribs objectForKey:NSFileModificationDate]; - NSDate* bPathModDate = [bPathAttribs objectForKey:NSFileModificationDate]; - - if ((nil == aPathModDate) && (nil == bPathModDate)) { - return NO; - } - - return [aPathModDate compare:bPathModDate] == NSOrderedDescending || bPathModDate == nil; -} - -- (BOOL)item:(NSString*)aPath isNewerThanItem:(NSString*)bPath -{ - NSFileManager* fileManager = [NSFileManager defaultManager]; - - BOOL aPathIsDir = NO, bPathIsDir = NO; - BOOL aPathExists = [fileManager fileExistsAtPath:aPath isDirectory:&aPathIsDir]; - - [fileManager fileExistsAtPath:bPath isDirectory:&bPathIsDir]; - - if (!aPathExists) { - return NO; - } - - if (!(aPathIsDir && bPathIsDir)) { // just a file - return [self file:aPath isNewerThanFile:bPath]; - } - - // essentially we want rsync here, but have to settle for our poor man's implementation - // we get the files in aPath, and see if it is newer than the file in bPath - // (it is newer if it doesn't exist in bPath) if we encounter the FIRST file that is newer, - // we return YES - NSDirectoryEnumerator* directoryEnumerator = [fileManager enumeratorAtPath:aPath]; - NSString* path; - - while ((path = [directoryEnumerator nextObject])) { - NSString* aPathFile = [aPath stringByAppendingPathComponent:path]; - NSString* bPathFile = [bPath stringByAppendingPathComponent:path]; - - BOOL isNewer = [self file:aPathFile isNewerThanFile:bPathFile]; - if (isNewer) { - return YES; - } - } - - return NO; -} - -- (BOOL)shouldBackup -{ - return [self item:self.original isNewerThanItem:self.backup]; -} - -- (BOOL)shouldRestore -{ - return [self item:self.backup isNewerThanItem:self.original]; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVLocation.h b/iPhone/CordovaLib/Classes/CDVLocation.h deleted file mode 100755 index caf0798..0000000 --- a/iPhone/CordovaLib/Classes/CDVLocation.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import -#import "CDVPlugin.h" - -enum CDVHeadingStatus { - HEADINGSTOPPED = 0, - HEADINGSTARTING, - HEADINGRUNNING, - HEADINGERROR -}; -typedef NSUInteger CDVHeadingStatus; - -enum CDVLocationStatus { - PERMISSIONDENIED = 1, - POSITIONUNAVAILABLE, - TIMEOUT -}; -typedef NSUInteger CDVLocationStatus; - -// simple object to keep track of heading information -@interface CDVHeadingData : NSObject {} - -@property (nonatomic, assign) CDVHeadingStatus headingStatus; -@property (nonatomic, strong) CLHeading* headingInfo; -@property (nonatomic, strong) NSMutableArray* headingCallbacks; -@property (nonatomic, copy) NSString* headingFilter; -@property (nonatomic, strong) NSDate* headingTimestamp; -@property (assign) NSInteger timeout; - -@end - -// simple object to keep track of location information -@interface CDVLocationData : NSObject { - CDVLocationStatus locationStatus; - NSMutableArray* locationCallbacks; - NSMutableDictionary* watchCallbacks; - CLLocation* locationInfo; -} - -@property (nonatomic, assign) CDVLocationStatus locationStatus; -@property (nonatomic, strong) CLLocation* locationInfo; -@property (nonatomic, strong) NSMutableArray* locationCallbacks; -@property (nonatomic, strong) NSMutableDictionary* watchCallbacks; - -@end - -@interface CDVLocation : CDVPlugin { - @private BOOL __locationStarted; - @private BOOL __highAccuracyEnabled; - CDVHeadingData* headingData; - CDVLocationData* locationData; -} - -@property (nonatomic, strong) CLLocationManager* locationManager; -@property (strong) CDVHeadingData* headingData; -@property (nonatomic, strong) CDVLocationData* locationData; - -- (BOOL)hasHeadingSupport; -- (void)getLocation:(CDVInvokedUrlCommand*)command; -- (void)addWatch:(CDVInvokedUrlCommand*)command; -- (void)clearWatch:(CDVInvokedUrlCommand*)command; -- (void)returnLocationInfo:(NSString*)callbackId andKeepCallback:(BOOL)keepCallback; -- (void)returnLocationError:(NSUInteger)errorCode withMessage:(NSString*)message; -- (void)startLocation:(BOOL)enableHighAccuracy; - -- (void)locationManager:(CLLocationManager*)manager - didUpdateToLocation:(CLLocation*)newLocation - fromLocation:(CLLocation*)oldLocation; - -- (void)locationManager:(CLLocationManager*)manager - didFailWithError:(NSError*)error; - -- (BOOL)isLocationServicesEnabled; - -- (void)getHeading:(CDVInvokedUrlCommand*)command; -- (void)returnHeadingInfo:(NSString*)callbackId keepCallback:(BOOL)bRetain; -- (void)watchHeadingFilter:(CDVInvokedUrlCommand*)command; -- (void)stopHeading:(CDVInvokedUrlCommand*)command; -- (void)startHeadingWithFilter:(CLLocationDegrees)filter; -- (void)locationManager:(CLLocationManager*)manager - didUpdateHeading:(CLHeading*)heading; - -- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager*)manager; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVLocation.m b/iPhone/CordovaLib/Classes/CDVLocation.m deleted file mode 100755 index ed9ec26..0000000 --- a/iPhone/CordovaLib/Classes/CDVLocation.m +++ /dev/null @@ -1,623 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVLocation.h" -#import "NSArray+Comparisons.h" - -#pragma mark Constants - -#define kPGLocationErrorDomain @"kPGLocationErrorDomain" -#define kPGLocationDesiredAccuracyKey @"desiredAccuracy" -#define kPGLocationForcePromptKey @"forcePrompt" -#define kPGLocationDistanceFilterKey @"distanceFilter" -#define kPGLocationFrequencyKey @"frequency" - -#pragma mark - -#pragma mark Categories - -@interface NSError (JSONMethods) - -- (NSString*)JSONRepresentation; - -@end - -@interface CLLocation (JSONMethods) - -- (NSString*)JSONRepresentation; - -@end - -@interface CLHeading (JSONMethods) - -- (NSString*)JSONRepresentation; - -@end - -#pragma mark - -#pragma mark CDVHeadingData - -@implementation CDVHeadingData - -@synthesize headingStatus, headingInfo, headingCallbacks, headingFilter, headingTimestamp, timeout; -- (CDVHeadingData*)init -{ - self = (CDVHeadingData*)[super init]; - if (self) { - self.headingStatus = HEADINGSTOPPED; - self.headingInfo = nil; - self.headingCallbacks = nil; - self.headingFilter = nil; - self.headingTimestamp = nil; - self.timeout = 10; - } - return self; -} - -@end - -@implementation CDVLocationData - -@synthesize locationStatus, locationInfo, locationCallbacks, watchCallbacks; -- (CDVLocationData*)init -{ - self = (CDVLocationData*)[super init]; - if (self) { - self.locationInfo = nil; - self.locationCallbacks = nil; - self.watchCallbacks = nil; - } - return self; -} - -@end - -#pragma mark - -#pragma mark CDVLocation - -@implementation CDVLocation - -@synthesize locationManager, headingData, locationData; - -- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView -{ - self = (CDVLocation*)[super initWithWebView:(UIWebView*)theWebView]; - if (self) { - self.locationManager = [[CLLocationManager alloc] init]; - self.locationManager.delegate = self; // Tells the location manager to send updates to this object - __locationStarted = NO; - __highAccuracyEnabled = NO; - self.headingData = nil; - self.locationData = nil; - } - return self; -} - -- (BOOL)hasHeadingSupport -{ - BOOL headingInstancePropertyAvailable = [self.locationManager respondsToSelector:@selector(headingAvailable)]; // iOS 3.x - BOOL headingClassPropertyAvailable = [CLLocationManager respondsToSelector:@selector(headingAvailable)]; // iOS 4.x - - if (headingInstancePropertyAvailable) { // iOS 3.x - return [(id)self.locationManager headingAvailable]; - } else if (headingClassPropertyAvailable) { // iOS 4.x - return [CLLocationManager headingAvailable]; - } else { // iOS 2.x - return NO; - } -} - -- (BOOL)isAuthorized -{ - BOOL authorizationStatusClassPropertyAvailable = [CLLocationManager respondsToSelector:@selector(authorizationStatus)]; // iOS 4.2+ - - if (authorizationStatusClassPropertyAvailable) { - NSUInteger authStatus = [CLLocationManager authorizationStatus]; - return (authStatus == kCLAuthorizationStatusAuthorized) || (authStatus == kCLAuthorizationStatusNotDetermined); - } - - // by default, assume YES (for iOS < 4.2) - return YES; -} - -- (BOOL)isLocationServicesEnabled -{ - BOOL locationServicesEnabledInstancePropertyAvailable = [self.locationManager respondsToSelector:@selector(locationServicesEnabled)]; // iOS 3.x - BOOL locationServicesEnabledClassPropertyAvailable = [CLLocationManager respondsToSelector:@selector(locationServicesEnabled)]; // iOS 4.x - - if (locationServicesEnabledClassPropertyAvailable) { // iOS 4.x - return [CLLocationManager locationServicesEnabled]; - } else if (locationServicesEnabledInstancePropertyAvailable) { // iOS 2.x, iOS 3.x - return [(id)self.locationManager locationServicesEnabled]; - } else { - return NO; - } -} - -- (void)startLocation:(BOOL)enableHighAccuracy -{ - if (![self isLocationServicesEnabled]) { - [self returnLocationError:PERMISSIONDENIED withMessage:@"Location services are not enabled."]; - return; - } - if (![self isAuthorized]) { - NSString* message = nil; - BOOL authStatusAvailable = [CLLocationManager respondsToSelector:@selector(authorizationStatus)]; // iOS 4.2+ - if (authStatusAvailable) { - NSUInteger code = [CLLocationManager authorizationStatus]; - if (code == kCLAuthorizationStatusNotDetermined) { - // could return POSITION_UNAVAILABLE but need to coordinate with other platforms - message = @"User undecided on application's use of location services."; - } else if (code == kCLAuthorizationStatusRestricted) { - message = @"Application's use of location services is restricted."; - } - } - // PERMISSIONDENIED is only PositionError that makes sense when authorization denied - [self returnLocationError:PERMISSIONDENIED withMessage:message]; - - return; - } - - // Tell the location manager to start notifying us of location updates. We - // first stop, and then start the updating to ensure we get at least one - // update, even if our location did not change. - [self.locationManager stopUpdatingLocation]; - [self.locationManager startUpdatingLocation]; - __locationStarted = YES; - if (enableHighAccuracy) { - __highAccuracyEnabled = YES; - // Set to distance filter to "none" - which should be the minimum for best results. - self.locationManager.distanceFilter = kCLDistanceFilterNone; - // Set desired accuracy to Best. - self.locationManager.desiredAccuracy = kCLLocationAccuracyBest; - } else { - __highAccuracyEnabled = NO; - // TODO: Set distance filter to 10 meters? and desired accuracy to nearest ten meters? arbitrary. - self.locationManager.distanceFilter = 10; - self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; - } -} - -- (void)_stopLocation -{ - if (__locationStarted) { - if (![self isLocationServicesEnabled]) { - return; - } - - [self.locationManager stopUpdatingLocation]; - __locationStarted = NO; - __highAccuracyEnabled = NO; - } -} - -- (void)locationManager:(CLLocationManager*)manager - didUpdateToLocation:(CLLocation*)newLocation - fromLocation:(CLLocation*)oldLocation -{ - CDVLocationData* cData = self.locationData; - - cData.locationInfo = newLocation; - if (self.locationData.locationCallbacks.count > 0) { - for (NSString* callbackId in self.locationData.locationCallbacks) { - [self returnLocationInfo:callbackId andKeepCallback:NO]; - } - - [self.locationData.locationCallbacks removeAllObjects]; - } - if (self.locationData.watchCallbacks.count > 0) { - for (NSString* timerId in self.locationData.watchCallbacks) { - [self returnLocationInfo:[self.locationData.watchCallbacks objectForKey:timerId] andKeepCallback:YES]; - } - } else { - // No callbacks waiting on us anymore, turn off listening. - [self _stopLocation]; - } -} - -- (void)getLocation:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - BOOL enableHighAccuracy = [[command.arguments objectAtIndex:0] boolValue]; - - if ([self isLocationServicesEnabled] == NO) { - NSMutableDictionary* posError = [NSMutableDictionary dictionaryWithCapacity:2]; - [posError setObject:[NSNumber numberWithInt:PERMISSIONDENIED] forKey:@"code"]; - [posError setObject:@"Location services are disabled." forKey:@"message"]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:posError]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } else { - if (!self.locationData) { - self.locationData = [[CDVLocationData alloc] init]; - } - CDVLocationData* lData = self.locationData; - if (!lData.locationCallbacks) { - lData.locationCallbacks = [NSMutableArray arrayWithCapacity:1]; - } - - if (!__locationStarted || (__highAccuracyEnabled != enableHighAccuracy)) { - // add the callbackId into the array so we can call back when get data - if (callbackId != nil) { - [lData.locationCallbacks addObject:callbackId]; - } - // Tell the location manager to start notifying us of heading updates - [self startLocation:enableHighAccuracy]; - } else { - [self returnLocationInfo:callbackId andKeepCallback:NO]; - } - } -} - -- (void)addWatch:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSString* timerId = [command.arguments objectAtIndex:0]; - BOOL enableHighAccuracy = [[command.arguments objectAtIndex:1] boolValue]; - - if (!self.locationData) { - self.locationData = [[CDVLocationData alloc] init]; - } - CDVLocationData* lData = self.locationData; - - if (!lData.watchCallbacks) { - lData.watchCallbacks = [NSMutableDictionary dictionaryWithCapacity:1]; - } - - // add the callbackId into the dictionary so we can call back whenever get data - [lData.watchCallbacks setObject:callbackId forKey:timerId]; - - if ([self isLocationServicesEnabled] == NO) { - NSMutableDictionary* posError = [NSMutableDictionary dictionaryWithCapacity:2]; - [posError setObject:[NSNumber numberWithInt:PERMISSIONDENIED] forKey:@"code"]; - [posError setObject:@"Location services are disabled." forKey:@"message"]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:posError]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } else { - if (!__locationStarted || (__highAccuracyEnabled != enableHighAccuracy)) { - // Tell the location manager to start notifying us of location updates - [self startLocation:enableHighAccuracy]; - } - } -} - -- (void)clearWatch:(CDVInvokedUrlCommand*)command -{ - NSString* timerId = [command.arguments objectAtIndex:0]; - - if (self.locationData && self.locationData.watchCallbacks && [self.locationData.watchCallbacks objectForKey:timerId]) { - [self.locationData.watchCallbacks removeObjectForKey:timerId]; - } -} - -- (void)stopLocation:(CDVInvokedUrlCommand*)command -{ - [self _stopLocation]; -} - -- (void)returnLocationInfo:(NSString*)callbackId andKeepCallback:(BOOL)keepCallback -{ - CDVPluginResult* result = nil; - CDVLocationData* lData = self.locationData; - - if (lData && !lData.locationInfo) { - // return error - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:POSITIONUNAVAILABLE]; - } else if (lData && lData.locationInfo) { - CLLocation* lInfo = lData.locationInfo; - NSMutableDictionary* returnInfo = [NSMutableDictionary dictionaryWithCapacity:8]; - NSNumber* timestamp = [NSNumber numberWithDouble:([lInfo.timestamp timeIntervalSince1970] * 1000)]; - [returnInfo setObject:timestamp forKey:@"timestamp"]; - [returnInfo setObject:[NSNumber numberWithDouble:lInfo.speed] forKey:@"velocity"]; - [returnInfo setObject:[NSNumber numberWithDouble:lInfo.verticalAccuracy] forKey:@"altitudeAccuracy"]; - [returnInfo setObject:[NSNumber numberWithDouble:lInfo.horizontalAccuracy] forKey:@"accuracy"]; - [returnInfo setObject:[NSNumber numberWithDouble:lInfo.course] forKey:@"heading"]; - [returnInfo setObject:[NSNumber numberWithDouble:lInfo.altitude] forKey:@"altitude"]; - [returnInfo setObject:[NSNumber numberWithDouble:lInfo.coordinate.latitude] forKey:@"latitude"]; - [returnInfo setObject:[NSNumber numberWithDouble:lInfo.coordinate.longitude] forKey:@"longitude"]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:returnInfo]; - [result setKeepCallbackAsBool:keepCallback]; - } - if (result) { - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } -} - -- (void)returnLocationError:(NSUInteger)errorCode withMessage:(NSString*)message -{ - NSMutableDictionary* posError = [NSMutableDictionary dictionaryWithCapacity:2]; - - [posError setObject:[NSNumber numberWithInt:errorCode] forKey:@"code"]; - [posError setObject:message ? message:@"" forKey:@"message"]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:posError]; - - for (NSString* callbackId in self.locationData.locationCallbacks) { - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - - [self.locationData.locationCallbacks removeAllObjects]; - - for (NSString* callbackId in self.locationData.watchCallbacks) { - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } -} - -// called to get the current heading -// Will call location manager to startUpdatingHeading if necessary - -- (void)getHeading:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* options = [command.arguments objectAtIndex:0 withDefault:nil]; - NSNumber* filter = [options valueForKey:@"filter"]; - - if (filter) { - [self watchHeadingFilter:command]; - return; - } - if ([self hasHeadingSupport] == NO) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:20]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } else { - // heading retrieval does is not affected by disabling locationServices and authorization of app for location services - if (!self.headingData) { - self.headingData = [[CDVHeadingData alloc] init]; - } - CDVHeadingData* hData = self.headingData; - - if (!hData.headingCallbacks) { - hData.headingCallbacks = [NSMutableArray arrayWithCapacity:1]; - } - // add the callbackId into the array so we can call back when get data - [hData.headingCallbacks addObject:callbackId]; - - if ((hData.headingStatus != HEADINGRUNNING) && (hData.headingStatus != HEADINGERROR)) { - // Tell the location manager to start notifying us of heading updates - [self startHeadingWithFilter:0.2]; - } else { - [self returnHeadingInfo:callbackId keepCallback:NO]; - } - } -} - -// called to request heading updates when heading changes by a certain amount (filter) -- (void)watchHeadingFilter:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* options = [command.arguments objectAtIndex:0 withDefault:nil]; - NSNumber* filter = [options valueForKey:@"filter"]; - CDVHeadingData* hData = self.headingData; - - if ([self hasHeadingSupport] == NO) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:20]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } else { - if (!hData) { - self.headingData = [[CDVHeadingData alloc] init]; - hData = self.headingData; - } - if (hData.headingStatus != HEADINGRUNNING) { - // Tell the location manager to start notifying us of heading updates - [self startHeadingWithFilter:[filter doubleValue]]; - } else { - // if already running check to see if due to existing watch filter - if (hData.headingFilter && ![hData.headingFilter isEqualToString:callbackId]) { - // new watch filter being specified - // send heading data one last time to clear old successCallback - [self returnHeadingInfo:hData.headingFilter keepCallback:NO]; - } - } - // save the new filter callback and update the headingFilter setting - hData.headingFilter = callbackId; - // check if need to stop and restart in order to change value??? - self.locationManager.headingFilter = [filter doubleValue]; - } -} - -- (void)returnHeadingInfo:(NSString*)callbackId keepCallback:(BOOL)bRetain -{ - CDVPluginResult* result = nil; - CDVHeadingData* hData = self.headingData; - - self.headingData.headingTimestamp = [NSDate date]; - - if (hData && (hData.headingStatus == HEADINGERROR)) { - // return error - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:0]; - } else if (hData && (hData.headingStatus == HEADINGRUNNING) && hData.headingInfo) { - // if there is heading info, return it - CLHeading* hInfo = hData.headingInfo; - NSMutableDictionary* returnInfo = [NSMutableDictionary dictionaryWithCapacity:4]; - NSNumber* timestamp = [NSNumber numberWithDouble:([hInfo.timestamp timeIntervalSince1970] * 1000)]; - [returnInfo setObject:timestamp forKey:@"timestamp"]; - [returnInfo setObject:[NSNumber numberWithDouble:hInfo.magneticHeading] forKey:@"magneticHeading"]; - id trueHeading = __locationStarted ? (id)[NSNumber numberWithDouble : hInfo.trueHeading] : (id)[NSNull null]; - [returnInfo setObject:trueHeading forKey:@"trueHeading"]; - [returnInfo setObject:[NSNumber numberWithDouble:hInfo.headingAccuracy] forKey:@"headingAccuracy"]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:returnInfo]; - [result setKeepCallbackAsBool:bRetain]; - } - if (result) { - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } -} - -- (void)stopHeading:(CDVInvokedUrlCommand*)command -{ - // CDVHeadingData* hData = self.headingData; - if (self.headingData && (self.headingData.headingStatus != HEADINGSTOPPED)) { - if (self.headingData.headingFilter) { - // callback one last time to clear callback - [self returnHeadingInfo:self.headingData.headingFilter keepCallback:NO]; - self.headingData.headingFilter = nil; - } - [self.locationManager stopUpdatingHeading]; - NSLog(@"heading STOPPED"); - self.headingData = nil; - } -} - -// helper method to check the orientation and start updating headings -- (void)startHeadingWithFilter:(CLLocationDegrees)filter -{ - // FYI UIDeviceOrientation and CLDeviceOrientation enums are currently the same - self.locationManager.headingOrientation = (CLDeviceOrientation)self.viewController.interfaceOrientation; - self.locationManager.headingFilter = filter; - [self.locationManager startUpdatingHeading]; - self.headingData.headingStatus = HEADINGSTARTING; -} - -- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager*)manager -{ - return YES; -} - -- (void)locationManager:(CLLocationManager*)manager - didUpdateHeading:(CLHeading*)heading -{ - CDVHeadingData* hData = self.headingData; - - // normally we would clear the delegate to stop getting these notifications, but - // we are sharing a CLLocationManager to get location data as well, so we do a nil check here - // ideally heading and location should use their own CLLocationManager instances - if (hData == nil) { - return; - } - - // save the data for next call into getHeadingData - hData.headingInfo = heading; - BOOL bTimeout = NO; - if (!hData.headingFilter && hData.headingTimestamp) { - bTimeout = fabs([hData.headingTimestamp timeIntervalSinceNow]) > hData.timeout; - } - - if (hData.headingStatus == HEADINGSTARTING) { - hData.headingStatus = HEADINGRUNNING; // so returnHeading info will work - - // this is the first update - for (NSString* callbackId in hData.headingCallbacks) { - [self returnHeadingInfo:callbackId keepCallback:NO]; - } - - [hData.headingCallbacks removeAllObjects]; - } - if (hData.headingFilter) { - [self returnHeadingInfo:hData.headingFilter keepCallback:YES]; - } else if (bTimeout) { - [self stopHeading:nil]; - } - hData.headingStatus = HEADINGRUNNING; // to clear any error -} - -- (void)locationManager:(CLLocationManager*)manager didFailWithError:(NSError*)error -{ - NSLog(@"locationManager::didFailWithError %@", [error localizedFailureReason]); - - // Compass Error - if ([error code] == kCLErrorHeadingFailure) { - CDVHeadingData* hData = self.headingData; - if (hData) { - if (hData.headingStatus == HEADINGSTARTING) { - // heading error during startup - report error - for (NSString* callbackId in hData.headingCallbacks) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:0]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - - [hData.headingCallbacks removeAllObjects]; - } // else for frequency watches next call to getCurrentHeading will report error - if (hData.headingFilter) { - CDVPluginResult* resultFilter = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:0]; - [self.commandDelegate sendPluginResult:resultFilter callbackId:hData.headingFilter]; - } - hData.headingStatus = HEADINGERROR; - } - } - // Location Error - else { - CDVLocationData* lData = self.locationData; - if (lData && __locationStarted) { - // TODO: probably have to once over the various error codes and return one of: - // PositionError.PERMISSION_DENIED = 1; - // PositionError.POSITION_UNAVAILABLE = 2; - // PositionError.TIMEOUT = 3; - NSUInteger positionError = POSITIONUNAVAILABLE; - if (error.code == kCLErrorDenied) { - positionError = PERMISSIONDENIED; - } - [self returnLocationError:positionError withMessage:[error localizedDescription]]; - } - } - - [self.locationManager stopUpdatingLocation]; - __locationStarted = NO; -} - -- (void)dealloc -{ - self.locationManager.delegate = nil; -} - -- (void)onReset -{ - [self _stopLocation]; - [self.locationManager stopUpdatingHeading]; - self.headingData = nil; -} - -@end - -#pragma mark - -#pragma mark CLLocation(JSONMethods) - -@implementation CLLocation (JSONMethods) - -- (NSString*)JSONRepresentation -{ - return [NSString stringWithFormat: - @"{ timestamp: %.00f, \ - coords: { latitude: %f, longitude: %f, altitude: %.02f, heading: %.02f, speed: %.02f, accuracy: %.02f, altitudeAccuracy: %.02f } \ - }", - [self.timestamp timeIntervalSince1970] * 1000.0, - self.coordinate.latitude, - self.coordinate.longitude, - self.altitude, - self.course, - self.speed, - self.horizontalAccuracy, - self.verticalAccuracy - ]; -} - -@end - -#pragma mark NSError(JSONMethods) - -@implementation NSError (JSONMethods) - -- (NSString*)JSONRepresentation -{ - return [NSString stringWithFormat: - @"{ code: %d, message: '%@'}", - self.code, - [self localizedDescription] - ]; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVLogger.h b/iPhone/CordovaLib/Classes/CDVLogger.h deleted file mode 100755 index eeba63c..0000000 --- a/iPhone/CordovaLib/Classes/CDVLogger.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVPlugin.h" - -@interface CDVLogger : CDVPlugin - -- (void)logLevel:(CDVInvokedUrlCommand*)command; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVLogger.m b/iPhone/CordovaLib/Classes/CDVLogger.m deleted file mode 100755 index a37cf8a..0000000 --- a/iPhone/CordovaLib/Classes/CDVLogger.m +++ /dev/null @@ -1,38 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVLogger.h" -#import "CDV.h" - -@implementation CDVLogger - -/* log a message */ -- (void)logLevel:(CDVInvokedUrlCommand*)command -{ - id level = [command.arguments objectAtIndex:0]; - id message = [command.arguments objectAtIndex:1]; - - if ([level isEqualToString:@"LOG"]) { - NSLog(@"%@", message); - } else { - NSLog(@"%@: %@", level, message); - } -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVNotification.h b/iPhone/CordovaLib/Classes/CDVNotification.h deleted file mode 100755 index 5b5b89f..0000000 --- a/iPhone/CordovaLib/Classes/CDVNotification.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import -#import -#import "CDVPlugin.h" - -@interface CDVNotification : CDVPlugin {} - -- (void)alert:(CDVInvokedUrlCommand*)command; -- (void)confirm:(CDVInvokedUrlCommand*)command; -- (void)prompt:(CDVInvokedUrlCommand*)command; -- (void)vibrate:(CDVInvokedUrlCommand*)command; - -@end - -@interface CDVAlertView : UIAlertView {} -@property (nonatomic, copy) NSString* callbackId; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVNotification.m b/iPhone/CordovaLib/Classes/CDVNotification.m deleted file mode 100755 index 464eb1f..0000000 --- a/iPhone/CordovaLib/Classes/CDVNotification.m +++ /dev/null @@ -1,130 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVNotification.h" -#import "NSDictionary+Extensions.h" - -#define DIALOG_TYPE_ALERT @"alert" -#define DIALOG_TYPE_PROMPT @"prompt" - -@implementation CDVNotification - -/* - * showDialogWithMessage - Common method to instantiate the alert view for alert, confirm, and prompt notifications. - * Parameters: - * message The alert view message. - * title The alert view title. - * buttons The array of customized strings for the buttons. - * defaultText The input text for the textbox (if textbox exists). - * callbackId The commmand callback id. - * dialogType The type of alert view [alert | prompt]. - */ -- (void)showDialogWithMessage:(NSString*)message title:(NSString*)title buttons:(NSArray*)buttons defaultText:(NSString*)defaultText callbackId:(NSString*)callbackId dialogType:(NSString*)dialogType -{ - CDVAlertView* alertView = [[CDVAlertView alloc] - initWithTitle:title - message:message - delegate:self - cancelButtonTitle:nil - otherButtonTitles:nil]; - - alertView.callbackId = callbackId; - - int count = [buttons count]; - - for (int n = 0; n < count; n++) { - [alertView addButtonWithTitle:[buttons objectAtIndex:n]]; - } - - if ([dialogType isEqualToString:DIALOG_TYPE_PROMPT]) { - alertView.alertViewStyle = UIAlertViewStylePlainTextInput; - UITextField* textField = [alertView textFieldAtIndex:0]; - textField.text = defaultText; - } - - [alertView show]; -} - -- (void)alert:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSString* message = [command argumentAtIndex:0]; - NSString* title = [command argumentAtIndex:1]; - NSString* buttons = [command argumentAtIndex:2]; - - [self showDialogWithMessage:message title:title buttons:@[buttons] defaultText:nil callbackId:callbackId dialogType:DIALOG_TYPE_ALERT]; -} - -- (void)confirm:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSString* message = [command argumentAtIndex:0]; - NSString* title = [command argumentAtIndex:1]; - NSArray* buttons = [command argumentAtIndex:2]; - - [self showDialogWithMessage:message title:title buttons:buttons defaultText:nil callbackId:callbackId dialogType:DIALOG_TYPE_ALERT]; -} - -- (void)prompt:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSString* message = [command argumentAtIndex:0]; - NSString* title = [command argumentAtIndex:1]; - NSArray* buttons = [command argumentAtIndex:2]; - NSString* defaultText = [command argumentAtIndex:3]; - - [self showDialogWithMessage:message title:title buttons:buttons defaultText:defaultText callbackId:callbackId dialogType:DIALOG_TYPE_PROMPT]; -} - -/** - * Callback invoked when an alert dialog's buttons are clicked. - */ -- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex -{ - CDVAlertView* cdvAlertView = (CDVAlertView*)alertView; - CDVPluginResult* result; - - // Determine what gets returned to JS based on the alert view type. - if (alertView.alertViewStyle == UIAlertViewStyleDefault) { - // For alert and confirm, return button index as int back to JS. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:buttonIndex + 1]; - } else { - // For prompt, return button index and input text back to JS. - NSString* value0 = [[alertView textFieldAtIndex:0] text]; - NSDictionary* info = @{ - @"buttonIndex":@(buttonIndex + 1), - @"input1":(value0 ? value0 : [NSNull null]) - }; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:info]; - } - [self.commandDelegate sendPluginResult:result callbackId:cdvAlertView.callbackId]; -} - -- (void)vibrate:(CDVInvokedUrlCommand*)command -{ - AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); -} - -@end - -@implementation CDVAlertView - -@synthesize callbackId; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVPlugin.h b/iPhone/CordovaLib/Classes/CDVPlugin.h deleted file mode 100755 index 33ba1c4..0000000 --- a/iPhone/CordovaLib/Classes/CDVPlugin.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import -#import "CDVPluginResult.h" -#import "NSMutableArray+QueueAdditions.h" -#import "CDVCommandDelegate.h" - -extern NSString* const CDVPageDidLoadNotification; -extern NSString* const CDVPluginHandleOpenURLNotification; -extern NSString* const CDVPluginResetNotification; -extern NSString* const CDVLocalNotification; - -@interface CDVPlugin : NSObject {} - -@property (nonatomic, weak) UIWebView* webView; -@property (nonatomic, weak) UIViewController* viewController; -@property (nonatomic, weak) id commandDelegate; - -@property (readonly, assign) BOOL hasPendingOperation; - -- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView; -- (void)pluginInitialize; - -- (void)handleOpenURL:(NSNotification*)notification; -- (void)onAppTerminate; -- (void)onMemoryWarning; -- (void)onReset; -- (void)dispose; - -/* - // see initWithWebView implementation - - (void) onPause {} - - (void) onResume {} - - (void) onOrientationWillChange {} - - (void) onOrientationDidChange {} - - (void)didReceiveLocalNotification:(NSNotification *)notification; - */ - -- (id)appDelegate; - -// TODO(agrieve): Deprecate these in favour of using CDVCommandDelegate directly. -- (NSString*)writeJavascript:(NSString*)javascript; -- (NSString*)success:(CDVPluginResult*)pluginResult callbackId:(NSString*)callbackId; -- (NSString*)error:(CDVPluginResult*)pluginResult callbackId:(NSString*)callbackId; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVPlugin.m b/iPhone/CordovaLib/Classes/CDVPlugin.m deleted file mode 100755 index 8c932a0..0000000 --- a/iPhone/CordovaLib/Classes/CDVPlugin.m +++ /dev/null @@ -1,152 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVPlugin.h" - -NSString* const CDVPageDidLoadNotification = @"CDVPageDidLoadNotification"; -NSString* const CDVPluginHandleOpenURLNotification = @"CDVPluginHandleOpenURLNotification"; -NSString* const CDVPluginResetNotification = @"CDVPluginResetNotification"; -NSString* const CDVLocalNotification = @"CDVLocalNotification"; - -@interface CDVPlugin () - -@property (readwrite, assign) BOOL hasPendingOperation; - -@end - -@implementation CDVPlugin -@synthesize webView, viewController, commandDelegate, hasPendingOperation; - -// Do not override these methods. Use pluginInitialize instead. -- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView settings:(NSDictionary*)classSettings -{ - return [self initWithWebView:theWebView]; -} - -- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView -{ - self = [super init]; - if (self) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppTerminate) name:UIApplicationWillTerminateNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleOpenURL:) name:CDVPluginHandleOpenURLNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onReset) name:CDVPluginResetNotification object:theWebView]; - - self.webView = theWebView; - } - return self; -} - -- (void)pluginInitialize -{ - // You can listen to more app notifications, see: - // http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006728-CH3-DontLinkElementID_4 - - // NOTE: if you want to use these, make sure you uncomment the corresponding notification handler - - // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPause) name:UIApplicationDidEnterBackgroundNotification object:nil]; - // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume) name:UIApplicationWillEnterForegroundNotification object:nil]; - // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationWillChange) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil]; - // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationDidChange) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; - - // Added in 2.3.0 - // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveLocalNotification:) name:CDVLocalNotification object:nil]; - - // Added in 2.5.0 - // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad:) name:CDVPageDidLoadNotification object:self.webView]; -} - -- (void)dispose -{ - viewController = nil; - commandDelegate = nil; - webView = nil; -} - -/* -// NOTE: for onPause and onResume, calls into JavaScript must not call or trigger any blocking UI, like alerts -- (void) onPause {} -- (void) onResume {} -- (void) onOrientationWillChange {} -- (void) onOrientationDidChange {} -*/ - -/* NOTE: calls into JavaScript must not call or trigger any blocking UI, like alerts */ -- (void)handleOpenURL:(NSNotification*)notification -{ - // override to handle urls sent to your app - // register your url schemes in your App-Info.plist - - NSURL* url = [notification object]; - - if ([url isKindOfClass:[NSURL class]]) { - /* Do your thing! */ - } -} - -/* NOTE: calls into JavaScript must not call or trigger any blocking UI, like alerts */ -- (void)onAppTerminate -{ - // override this if you need to do any cleanup on app exit -} - -- (void)onMemoryWarning -{ - // override to remove caches, etc -} - -- (void)onReset -{ - // Override to cancel any long-running requests when the WebView navigates or refreshes. -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; // this will remove all notification unless added using addObserverForName:object:queue:usingBlock: -} - -- (id)appDelegate -{ - return [[UIApplication sharedApplication] delegate]; -} - -- (NSString*)writeJavascript:(NSString*)javascript -{ - return [self.webView stringByEvaluatingJavaScriptFromString:javascript]; -} - -- (NSString*)success:(CDVPluginResult*)pluginResult callbackId:(NSString*)callbackId -{ - [self.commandDelegate evalJs:[pluginResult toSuccessCallbackString:callbackId]]; - return @""; -} - -- (NSString*)error:(CDVPluginResult*)pluginResult callbackId:(NSString*)callbackId -{ - [self.commandDelegate evalJs:[pluginResult toErrorCallbackString:callbackId]]; - return @""; -} - -// default implementation does nothing, ideally, we are not registered for notification if we aren't going to do anything. -// - (void)didReceiveLocalNotification:(NSNotification *)notification -// { -// // UILocalNotification* localNotification = [notification object]; // get the payload as a LocalNotification -// } - -@end diff --git a/iPhone/CordovaLib/Classes/CDVPluginResult.h b/iPhone/CordovaLib/Classes/CDVPluginResult.h deleted file mode 100755 index 11b5377..0000000 --- a/iPhone/CordovaLib/Classes/CDVPluginResult.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import - -typedef enum { - CDVCommandStatus_NO_RESULT = 0, - CDVCommandStatus_OK, - CDVCommandStatus_CLASS_NOT_FOUND_EXCEPTION, - CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION, - CDVCommandStatus_INSTANTIATION_EXCEPTION, - CDVCommandStatus_MALFORMED_URL_EXCEPTION, - CDVCommandStatus_IO_EXCEPTION, - CDVCommandStatus_INVALID_ACTION, - CDVCommandStatus_JSON_EXCEPTION, - CDVCommandStatus_ERROR -} CDVCommandStatus; - -@interface CDVPluginResult : NSObject {} - -@property (nonatomic, strong, readonly) NSNumber* status; -@property (nonatomic, strong, readonly) id message; -@property (nonatomic, strong) NSNumber* keepCallback; -// This property can be used to scope the lifetime of another object. For example, -// Use it to store the associated NSData when `message` is created using initWithBytesNoCopy. -@property (nonatomic, strong) id associatedObject; - -- (CDVPluginResult*)init; -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal; -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsString:(NSString*)theMessage; -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArray:(NSArray*)theMessage; -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsInt:(int)theMessage; -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDouble:(double)theMessage; -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsBool:(BOOL)theMessage; -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDictionary:(NSDictionary*)theMessage; -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArrayBuffer:(NSData*)theMessage; -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsMultipart:(NSArray*)theMessages; -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageToErrorObject:(int)errorCode; - -+ (void)setVerbose:(BOOL)verbose; -+ (BOOL)isVerbose; - -- (void)setKeepCallbackAsBool:(BOOL)bKeepCallback; - -- (NSString*)argumentsAsJSON; - -// These methods are used by the legacy plugin return result method -- (NSString*)toJSONString; -- (NSString*)toSuccessCallbackString:(NSString*)callbackId; -- (NSString*)toErrorCallbackString:(NSString*)callbackId; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVPluginResult.m b/iPhone/CordovaLib/Classes/CDVPluginResult.m deleted file mode 100755 index af7c528..0000000 --- a/iPhone/CordovaLib/Classes/CDVPluginResult.m +++ /dev/null @@ -1,224 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVPluginResult.h" -#import "CDVJSON.h" -#import "CDVDebug.h" -#import "NSData+Base64.h" - -@interface CDVPluginResult () - -- (CDVPluginResult*)initWithStatus:(CDVCommandStatus)statusOrdinal message:(id)theMessage; - -@end - -@implementation CDVPluginResult -@synthesize status, message, keepCallback, associatedObject; - -static NSArray* org_apache_cordova_CommandStatusMsgs; - -id messageFromArrayBuffer(NSData* data) -{ - return @{ - @"CDVType" : @"ArrayBuffer", - @"data" :[data base64EncodedString] - }; -} - -id massageMessage(id message) -{ - if ([message isKindOfClass:[NSData class]]) { - return messageFromArrayBuffer(message); - } - return message; -} - -id messageFromMultipart(NSArray* theMessages) -{ - NSMutableArray* messages = [NSMutableArray arrayWithArray:theMessages]; - - for (NSUInteger i = 0; i < messages.count; ++i) { - [messages replaceObjectAtIndex:i withObject:massageMessage([messages objectAtIndex:i])]; - } - - return @{ - @"CDVType" : @"MultiPart", - @"messages" : messages - }; -} - -+ (void)initialize -{ - org_apache_cordova_CommandStatusMsgs = [[NSArray alloc] initWithObjects:@"No result", - @"OK", - @"Class not found", - @"Illegal access", - @"Instantiation error", - @"Malformed url", - @"IO error", - @"Invalid action", - @"JSON error", - @"Error", - nil]; -} - -- (CDVPluginResult*)init -{ - return [self initWithStatus:CDVCommandStatus_NO_RESULT message:nil]; -} - -- (CDVPluginResult*)initWithStatus:(CDVCommandStatus)statusOrdinal message:(id)theMessage -{ - self = [super init]; - if (self) { - status = [NSNumber numberWithInt:statusOrdinal]; - message = theMessage; - keepCallback = [NSNumber numberWithBool:NO]; - } - return self; -} - -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal -{ - return [[self alloc] initWithStatus:statusOrdinal message:[org_apache_cordova_CommandStatusMsgs objectAtIndex:statusOrdinal]]; -} - -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsString:(NSString*)theMessage -{ - return [[self alloc] initWithStatus:statusOrdinal message:theMessage]; -} - -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArray:(NSArray*)theMessage -{ - return [[self alloc] initWithStatus:statusOrdinal message:theMessage]; -} - -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsInt:(int)theMessage -{ - return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithInt:theMessage]]; -} - -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDouble:(double)theMessage -{ - return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithDouble:theMessage]]; -} - -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsBool:(BOOL)theMessage -{ - return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithBool:theMessage]]; -} - -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDictionary:(NSDictionary*)theMessage -{ - return [[self alloc] initWithStatus:statusOrdinal message:theMessage]; -} - -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArrayBuffer:(NSData*)theMessage -{ - return [[self alloc] initWithStatus:statusOrdinal message:messageFromArrayBuffer(theMessage)]; -} - -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsMultipart:(NSArray*)theMessages -{ - return [[self alloc] initWithStatus:statusOrdinal message:messageFromMultipart(theMessages)]; -} - -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageToErrorObject:(int)errorCode -{ - NSDictionary* errDict = @{@"code" :[NSNumber numberWithInt:errorCode]}; - - return [[self alloc] initWithStatus:statusOrdinal message:errDict]; -} - -- (void)setKeepCallbackAsBool:(BOOL)bKeepCallback -{ - [self setKeepCallback:[NSNumber numberWithBool:bKeepCallback]]; -} - -- (NSString*)argumentsAsJSON -{ - id arguments = (self.message == nil ? [NSNull null] : self.message); - NSArray* argumentsWrappedInArray = [NSArray arrayWithObject:arguments]; - - NSString* argumentsJSON = [argumentsWrappedInArray JSONString]; - - argumentsJSON = [argumentsJSON substringWithRange:NSMakeRange(1, [argumentsJSON length] - 2)]; - - return argumentsJSON; -} - -// These methods are used by the legacy plugin return result method -- (NSString*)toJSONString -{ - NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: - self.status, @"status", - self.message ? self. message:[NSNull null], @"message", - self.keepCallback, @"keepCallback", - nil]; - - NSError* error = nil; - NSData* jsonData = [NSJSONSerialization dataWithJSONObject:dict - options:NSJSONWritingPrettyPrinted - error:&error]; - NSString* resultString = nil; - - if (error != nil) { - NSLog(@"toJSONString error: %@", [error localizedDescription]); - } else { - resultString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; - } - - if ([[self class] isVerbose]) { - NSLog(@"PluginResult:toJSONString - %@", resultString); - } - return resultString; -} - -- (NSString*)toSuccessCallbackString:(NSString*)callbackId -{ - NSString* successCB = [NSString stringWithFormat:@"cordova.callbackSuccess('%@',%@);", callbackId, [self toJSONString]]; - - if ([[self class] isVerbose]) { - NSLog(@"PluginResult toSuccessCallbackString: %@", successCB); - } - return successCB; -} - -- (NSString*)toErrorCallbackString:(NSString*)callbackId -{ - NSString* errorCB = [NSString stringWithFormat:@"cordova.callbackError('%@',%@);", callbackId, [self toJSONString]]; - - if ([[self class] isVerbose]) { - NSLog(@"PluginResult toErrorCallbackString: %@", errorCB); - } - return errorCB; -} - -static BOOL gIsVerbose = NO; -+ (void)setVerbose:(BOOL)verbose -{ - gIsVerbose = verbose; -} - -+ (BOOL)isVerbose -{ - return gIsVerbose; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVReachability.h b/iPhone/CordovaLib/Classes/CDVReachability.h deleted file mode 100755 index 01a95c3..0000000 --- a/iPhone/CordovaLib/Classes/CDVReachability.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - - File: Reachability.h - Abstract: Basic demonstration of how to use the SystemConfiguration Reachability APIs. - Version: 2.2 - - Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. - ("Apple") in consideration of your agreement to the following terms, and your - use, installation, modification or redistribution of this Apple software - constitutes acceptance of these terms. If you do not agree with these terms, - please do not use, install, modify or redistribute this Apple software. - - In consideration of your agreement to abide by the following terms, and subject - to these terms, Apple grants you a personal, non-exclusive license, under - Apple's copyrights in this original Apple software (the "Apple Software"), to - use, reproduce, modify and redistribute the Apple Software, with or without - modifications, in source and/or binary forms; provided that if you redistribute - the Apple Software in its entirety and without modifications, you must retain - this notice and the following text and disclaimers in all such redistributions - of the Apple Software. - Neither the name, trademarks, service marks or logos of Apple Inc. may be used - to endorse or promote products derived from the Apple Software without specific - prior written permission from Apple. Except as expressly stated in this notice, - no other rights or licenses, express or implied, are granted by Apple herein, - including but not limited to any patent rights that may be infringed by your - derivative works or by other works in which the Apple Software may be - incorporated. - - The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO - WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED - WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN - COMBINATION WITH YOUR PRODUCTS. - - IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR - DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF - CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF - APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Copyright (C) 2010 Apple Inc. All Rights Reserved. - -*/ - -#import -#import -#import - -typedef enum { - NotReachable = 0, - ReachableViaWWAN, // this value has been swapped with ReachableViaWiFi for Cordova backwards compat. reasons - ReachableViaWiFi // this value has been swapped with ReachableViaWWAN for Cordova backwards compat. reasons -} NetworkStatus; -#define kReachabilityChangedNotification @"kNetworkReachabilityChangedNotification" - -@interface CDVReachability : NSObject -{ - BOOL localWiFiRef; - SCNetworkReachabilityRef reachabilityRef; -} - -// reachabilityWithHostName- Use to check the reachability of a particular host name. -+ (CDVReachability*)reachabilityWithHostName:(NSString*)hostName; - -// reachabilityWithAddress- Use to check the reachability of a particular IP address. -+ (CDVReachability*)reachabilityWithAddress:(const struct sockaddr_in*)hostAddress; - -// reachabilityForInternetConnection- checks whether the default route is available. -// Should be used by applications that do not connect to a particular host -+ (CDVReachability*)reachabilityForInternetConnection; - -// reachabilityForLocalWiFi- checks whether a local wifi connection is available. -+ (CDVReachability*)reachabilityForLocalWiFi; - -// Start listening for reachability notifications on the current run loop -- (BOOL)startNotifier; -- (void)stopNotifier; - -- (NetworkStatus)currentReachabilityStatus; -// WWAN may be available, but not active until a connection has been established. -// WiFi may require a connection for VPN on Demand. -- (BOOL)connectionRequired; -@end diff --git a/iPhone/CordovaLib/Classes/CDVReachability.m b/iPhone/CordovaLib/Classes/CDVReachability.m deleted file mode 100755 index 89f4ec9..0000000 --- a/iPhone/CordovaLib/Classes/CDVReachability.m +++ /dev/null @@ -1,260 +0,0 @@ -/* - - File: Reachability.m - Abstract: Basic demonstration of how to use the SystemConfiguration Reachability APIs. - Version: 2.2 - - Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. - ("Apple") in consideration of your agreement to the following terms, and your - use, installation, modification or redistribution of this Apple software - constitutes acceptance of these terms. If you do not agree with these terms, - please do not use, install, modify or redistribute this Apple software. - - In consideration of your agreement to abide by the following terms, and subject - to these terms, Apple grants you a personal, non-exclusive license, under - Apple's copyrights in this original Apple software (the "Apple Software"), to - use, reproduce, modify and redistribute the Apple Software, with or without - modifications, in source and/or binary forms; provided that if you redistribute - the Apple Software in its entirety and without modifications, you must retain - this notice and the following text and disclaimers in all such redistributions - of the Apple Software. - Neither the name, trademarks, service marks or logos of Apple Inc. may be used - to endorse or promote products derived from the Apple Software without specific - prior written permission from Apple. Except as expressly stated in this notice, - no other rights or licenses, express or implied, are granted by Apple herein, - including but not limited to any patent rights that may be infringed by your - derivative works or by other works in which the Apple Software may be - incorporated. - - The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO - WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED - WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN - COMBINATION WITH YOUR PRODUCTS. - - IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR - DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF - CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF - APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Copyright (C) 2010 Apple Inc. All Rights Reserved. - -*/ - -#import -#import -#import -#import -#import -#import - -#import - -#import "CDVReachability.h" - -#define kShouldPrintReachabilityFlags 0 - -static void CDVPrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment) -{ -#if kShouldPrintReachabilityFlags - NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n", - (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', - (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', - - (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', - (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', - (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', - (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', - (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', - (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', - (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-', - comment - ); -#endif -} - -@implementation CDVReachability - -static void CDVReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) -{ -#pragma unused (target, flags) - // NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback"); - // NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback"); - - // Converted the asserts above to conditionals, with safe return from the function - if (info == NULL) { - NSLog(@"info was NULL in ReachabilityCallback"); - return; - } - - if (![(__bridge NSObject*)info isKindOfClass :[CDVReachability class]]) { - NSLog(@"info was wrong class in ReachabilityCallback"); - return; - } - - // We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively - // in case someon uses the Reachability object in a different thread. - @autoreleasepool { - CDVReachability* noteObject = (__bridge CDVReachability*)info; - // Post a notification to notify the client that the network reachability changed. - [[NSNotificationCenter defaultCenter] postNotificationName:kReachabilityChangedNotification object:noteObject]; - } -} - -- (BOOL)startNotifier -{ - BOOL retVal = NO; - SCNetworkReachabilityContext context = {0, (__bridge void*)(self), NULL, NULL, NULL}; - - if (SCNetworkReachabilitySetCallback(reachabilityRef, CDVReachabilityCallback, &context)) { - if (SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) { - retVal = YES; - } - } - return retVal; -} - -- (void)stopNotifier -{ - if (reachabilityRef != NULL) { - SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - } -} - -- (void)dealloc -{ - [self stopNotifier]; - if (reachabilityRef != NULL) { - CFRelease(reachabilityRef); - } -} - -+ (CDVReachability*)reachabilityWithHostName:(NSString*)hostName; -{ - CDVReachability* retVal = NULL; - SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]); - if (reachability != NULL) { - retVal = [[self alloc] init]; - if (retVal != NULL) { - retVal->reachabilityRef = reachability; - retVal->localWiFiRef = NO; - } - } - return retVal; -} - -+ (CDVReachability*)reachabilityWithAddress:(const struct sockaddr_in*)hostAddress; -{ - SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress); - CDVReachability* retVal = NULL; - if (reachability != NULL) { - retVal = [[self alloc] init]; - if (retVal != NULL) { - retVal->reachabilityRef = reachability; - retVal->localWiFiRef = NO; - } - } - return retVal; -} - -+ (CDVReachability*)reachabilityForInternetConnection; -{ - struct sockaddr_in zeroAddress; - bzero(&zeroAddress, sizeof(zeroAddress)); - zeroAddress.sin_len = sizeof(zeroAddress); - zeroAddress.sin_family = AF_INET; - return [self reachabilityWithAddress:&zeroAddress]; -} - -+ (CDVReachability*)reachabilityForLocalWiFi; -{ - struct sockaddr_in localWifiAddress; - bzero(&localWifiAddress, sizeof(localWifiAddress)); - localWifiAddress.sin_len = sizeof(localWifiAddress); - localWifiAddress.sin_family = AF_INET; - // IN_LINKLOCALNETNUM is defined in as 169.254.0.0 - localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); - CDVReachability* retVal = [self reachabilityWithAddress:&localWifiAddress]; - if (retVal != NULL) { - retVal->localWiFiRef = YES; - } - return retVal; -} - -#pragma mark Network Flag Handling - -- (NetworkStatus)localWiFiStatusForFlags:(SCNetworkReachabilityFlags)flags -{ - CDVPrintReachabilityFlags(flags, "localWiFiStatusForFlags"); - - BOOL retVal = NotReachable; - if ((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect)) { - retVal = ReachableViaWiFi; - } - return retVal; -} - -- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags -{ - CDVPrintReachabilityFlags(flags, "networkStatusForFlags"); - if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) { - // if target host is not reachable - return NotReachable; - } - - BOOL retVal = NotReachable; - - if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) { - // if target host is reachable and no connection is required - // then we'll assume (for now) that your on Wi-Fi - retVal = ReachableViaWiFi; - } - - if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand) != 0) || - ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))) { - // ... and the connection is on-demand (or on-traffic) if the - // calling application is using the CFSocketStream or higher APIs - - if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) { - // ... and no [user] intervention is needed - retVal = ReachableViaWiFi; - } - } - - if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) { - // ... but WWAN connections are OK if the calling application - // is using the CFNetwork (CFSocketStream?) APIs. - retVal = ReachableViaWWAN; - } - return retVal; -} - -- (BOOL)connectionRequired; -{ - NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef"); - SCNetworkReachabilityFlags flags; - if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { - return flags & kSCNetworkReachabilityFlagsConnectionRequired; - } - return NO; -} - -- (NetworkStatus)currentReachabilityStatus -{ - NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef"); - NetworkStatus retVal = NotReachable; - SCNetworkReachabilityFlags flags; - if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { - if (localWiFiRef) { - retVal = [self localWiFiStatusForFlags:flags]; - } else { - retVal = [self networkStatusForFlags:flags]; - } - } - return retVal; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVScreenOrientationDelegate.h b/iPhone/CordovaLib/Classes/CDVScreenOrientationDelegate.h deleted file mode 100755 index 7226205..0000000 --- a/iPhone/CordovaLib/Classes/CDVScreenOrientationDelegate.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import - -@protocol CDVScreenOrientationDelegate - -- (NSUInteger)supportedInterfaceOrientations; -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; -- (BOOL)shouldAutorotate; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVSound.h b/iPhone/CordovaLib/Classes/CDVSound.h deleted file mode 100755 index 8dcf98e..0000000 --- a/iPhone/CordovaLib/Classes/CDVSound.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import -#import - -#import "CDVPlugin.h" - -enum CDVMediaError { - MEDIA_ERR_ABORTED = 1, - MEDIA_ERR_NETWORK = 2, - MEDIA_ERR_DECODE = 3, - MEDIA_ERR_NONE_SUPPORTED = 4 -}; -typedef NSUInteger CDVMediaError; - -enum CDVMediaStates { - MEDIA_NONE = 0, - MEDIA_STARTING = 1, - MEDIA_RUNNING = 2, - MEDIA_PAUSED = 3, - MEDIA_STOPPED = 4 -}; -typedef NSUInteger CDVMediaStates; - -enum CDVMediaMsg { - MEDIA_STATE = 1, - MEDIA_DURATION = 2, - MEDIA_POSITION = 3, - MEDIA_ERROR = 9 -}; -typedef NSUInteger CDVMediaMsg; - -@interface CDVAudioPlayer : AVAudioPlayer -{ - NSString* mediaId; -} -@property (nonatomic, copy) NSString* mediaId; -@end - -@interface CDVAudioRecorder : AVAudioRecorder -{ - NSString* mediaId; -} -@property (nonatomic, copy) NSString* mediaId; -@end - -@interface CDVAudioFile : NSObject -{ - NSString* resourcePath; - NSURL* resourceURL; - CDVAudioPlayer* player; - CDVAudioRecorder* recorder; - NSNumber* volume; -} - -@property (nonatomic, strong) NSString* resourcePath; -@property (nonatomic, strong) NSURL* resourceURL; -@property (nonatomic, strong) CDVAudioPlayer* player; -@property (nonatomic, strong) NSNumber* volume; - -@property (nonatomic, strong) CDVAudioRecorder* recorder; - -@end - -@interface CDVSound : CDVPlugin -{ - NSMutableDictionary* soundCache; - AVAudioSession* avSession; -} -@property (nonatomic, strong) NSMutableDictionary* soundCache; -@property (nonatomic, strong) AVAudioSession* avSession; - -- (void)startPlayingAudio:(CDVInvokedUrlCommand*)command; -- (void)pausePlayingAudio:(CDVInvokedUrlCommand*)command; -- (void)stopPlayingAudio:(CDVInvokedUrlCommand*)command; -- (void)seekToAudio:(CDVInvokedUrlCommand*)command; -- (void)release:(CDVInvokedUrlCommand*)command; -- (void)getCurrentPositionAudio:(CDVInvokedUrlCommand*)command; - -- (BOOL)hasAudioSession; - -// helper methods -- (NSURL*)urlForRecording:(NSString*)resourcePath; -- (NSURL*)urlForPlaying:(NSString*)resourcePath; -- (NSURL*)urlForResource:(NSString*)resourcePath CDV_DEPRECATED(2.5, "Use specific api for playing or recording"); - -- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId CDV_DEPRECATED(2.5, "Use updated audioFileForResource api"); - -- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId doValidation:(BOOL)bValidate forRecording:(BOOL)bRecord; -- (BOOL)prepareToPlay:(CDVAudioFile*)audioFile withId:(NSString*)mediaId; -- (NSString*)createMediaErrorWithCode:(CDVMediaError)code message:(NSString*)message; - -- (void)startRecordingAudio:(CDVInvokedUrlCommand*)command; -- (void)stopRecordingAudio:(CDVInvokedUrlCommand*)command; - -- (void)setVolume:(CDVInvokedUrlCommand*)command; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVSound.m b/iPhone/CordovaLib/Classes/CDVSound.m deleted file mode 100755 index 71eab59..0000000 --- a/iPhone/CordovaLib/Classes/CDVSound.m +++ /dev/null @@ -1,702 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVSound.h" -#import "NSArray+Comparisons.h" -#import "CDVJSON.h" - -#define DOCUMENTS_SCHEME_PREFIX @"documents://" -#define HTTP_SCHEME_PREFIX @"http://" -#define HTTPS_SCHEME_PREFIX @"https://" -#define RECORDING_WAV @"wav" - -@implementation CDVSound - -@synthesize soundCache, avSession; - -- (NSURL*)urlForResource:(NSString*)resourcePath -{ - NSURL* resourceURL = nil; - NSString* filePath = nil; - - // first try to find HTTP:// or Documents:// resources - - if ([resourcePath hasPrefix:HTTP_SCHEME_PREFIX] || [resourcePath hasPrefix:HTTPS_SCHEME_PREFIX]) { - // if it is a http url, use it - NSLog(@"Will use resource '%@' from the Internet.", resourcePath); - resourceURL = [NSURL URLWithString:resourcePath]; - } else if ([resourcePath hasPrefix:DOCUMENTS_SCHEME_PREFIX]) { - NSString* docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; - filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", docsPath]]; - NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath); - } else { - // attempt to find file path in www directory - filePath = [self.commandDelegate pathForResource:resourcePath]; - if (filePath != nil) { - NSLog(@"Found resource '%@' in the web folder.", filePath); - } else { - filePath = resourcePath; - NSLog(@"Will attempt to use file resource '%@'", filePath); - } - } - // check that file exists for all but HTTP_SHEME_PREFIX - if (filePath != nil) { - // try to access file - NSFileManager* fMgr = [[NSFileManager alloc] init]; - if (![fMgr fileExistsAtPath:filePath]) { - resourceURL = nil; - NSLog(@"Unknown resource '%@'", resourcePath); - } else { - // it's a valid file url, use it - resourceURL = [NSURL fileURLWithPath:filePath]; - } - } - return resourceURL; -} - -// Maps a url for a resource path for recording -- (NSURL*)urlForRecording:(NSString*)resourcePath -{ - NSURL* resourceURL = nil; - NSString* filePath = nil; - NSString* docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; - - // first check for correct extension - if ([[resourcePath pathExtension] caseInsensitiveCompare:RECORDING_WAV] != NSOrderedSame) { - resourceURL = nil; - NSLog(@"Resource for recording must have %@ extension", RECORDING_WAV); - } else if ([resourcePath hasPrefix:DOCUMENTS_SCHEME_PREFIX]) { - // try to find Documents:// resources - filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", docsPath]]; - NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath); - } else { - // if resourcePath is not from FileSystem put in tmp dir, else attempt to use provided resource path - NSString* tmpPath = [NSTemporaryDirectory()stringByStandardizingPath]; - BOOL isTmp = [resourcePath rangeOfString:tmpPath].location != NSNotFound; - BOOL isDoc = [resourcePath rangeOfString:docsPath].location != NSNotFound; - if (!isTmp && !isDoc) { - // put in temp dir - filePath = [NSString stringWithFormat:@"%@/%@", tmpPath, resourcePath]; - } else { - filePath = resourcePath; - } - } - - if (filePath != nil) { - // create resourceURL - resourceURL = [NSURL fileURLWithPath:filePath]; - } - return resourceURL; -} - -// Maps a url for a resource path for playing -// "Naked" resource paths are assumed to be from the www folder as its base -- (NSURL*)urlForPlaying:(NSString*)resourcePath -{ - NSURL* resourceURL = nil; - NSString* filePath = nil; - - // first try to find HTTP:// or Documents:// resources - - if ([resourcePath hasPrefix:HTTP_SCHEME_PREFIX] || [resourcePath hasPrefix:HTTPS_SCHEME_PREFIX]) { - // if it is a http url, use it - NSLog(@"Will use resource '%@' from the Internet.", resourcePath); - resourceURL = [NSURL URLWithString:resourcePath]; - } else if ([resourcePath hasPrefix:DOCUMENTS_SCHEME_PREFIX]) { - NSString* docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; - filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", docsPath]]; - NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath); - } else { - // attempt to find file path in www directory or LocalFileSystem.TEMPORARY directory - filePath = [self.commandDelegate pathForResource:resourcePath]; - if (filePath == nil) { - // see if this exists in the documents/temp directory from a previous recording - NSString* testPath = [NSString stringWithFormat:@"%@/%@", [NSTemporaryDirectory()stringByStandardizingPath], resourcePath]; - if ([[NSFileManager defaultManager] fileExistsAtPath:testPath]) { - // inefficient as existence will be checked again below but only way to determine if file exists from previous recording - filePath = testPath; - NSLog(@"Will attempt to use file resource from LocalFileSystem.TEMPORARY directory"); - } else { - // attempt to use path provided - filePath = resourcePath; - NSLog(@"Will attempt to use file resource '%@'", filePath); - } - } else { - NSLog(@"Found resource '%@' in the web folder.", filePath); - } - } - // check that file exists for all but HTTP_SHEME_PREFIX - if (filePath != nil) { - // create resourceURL - resourceURL = [NSURL fileURLWithPath:filePath]; - // try to access file - NSFileManager* fMgr = [NSFileManager defaultManager]; - if (![fMgr fileExistsAtPath:filePath]) { - resourceURL = nil; - NSLog(@"Unknown resource '%@'", resourcePath); - } - } - - return resourceURL; -} - -- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId -{ - // will maintain backwards compatibility with original implementation - return [self audioFileForResource:resourcePath withId:mediaId doValidation:YES forRecording:NO]; -} - -// Creates or gets the cached audio file resource object -- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId doValidation:(BOOL)bValidate forRecording:(BOOL)bRecord -{ - BOOL bError = NO; - CDVMediaError errcode = MEDIA_ERR_NONE_SUPPORTED; - NSString* errMsg = @""; - NSString* jsString = nil; - CDVAudioFile* audioFile = nil; - NSURL* resourceURL = nil; - - if ([self soundCache] == nil) { - [self setSoundCache:[NSMutableDictionary dictionaryWithCapacity:1]]; - } else { - audioFile = [[self soundCache] objectForKey:mediaId]; - } - if (audioFile == nil) { - // validate resourcePath and create - if ((resourcePath == nil) || ![resourcePath isKindOfClass:[NSString class]] || [resourcePath isEqualToString:@""]) { - bError = YES; - errcode = MEDIA_ERR_ABORTED; - errMsg = @"invalid media src argument"; - } else { - audioFile = [[CDVAudioFile alloc] init]; - audioFile.resourcePath = resourcePath; - audioFile.resourceURL = nil; // validate resourceURL when actually play or record - [[self soundCache] setObject:audioFile forKey:mediaId]; - } - } - if (bValidate && (audioFile.resourceURL == nil)) { - if (bRecord) { - resourceURL = [self urlForRecording:resourcePath]; - } else { - resourceURL = [self urlForPlaying:resourcePath]; - } - if (resourceURL == nil) { - bError = YES; - errcode = MEDIA_ERR_ABORTED; - errMsg = [NSString stringWithFormat:@"Cannot use audio file from resource '%@'", resourcePath]; - } else { - audioFile.resourceURL = resourceURL; - } - } - - if (bError) { - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:errcode message:errMsg]]; - [self.commandDelegate evalJs:jsString]; - } - - return audioFile; -} - -// returns whether or not audioSession is available - creates it if necessary -- (BOOL)hasAudioSession -{ - BOOL bSession = YES; - - if (!self.avSession) { - NSError* error = nil; - - self.avSession = [AVAudioSession sharedInstance]; - if (error) { - // is not fatal if can't get AVAudioSession , just log the error - NSLog(@"error creating audio session: %@", [[error userInfo] description]); - self.avSession = nil; - bSession = NO; - } - } - return bSession; -} - -// helper function to create a error object string -- (NSString*)createMediaErrorWithCode:(CDVMediaError)code message:(NSString*)message -{ - NSMutableDictionary* errorDict = [NSMutableDictionary dictionaryWithCapacity:2]; - - [errorDict setObject:[NSNumber numberWithUnsignedInt:code] forKey:@"code"]; - [errorDict setObject:message ? message:@"" forKey:@"message"]; - return [errorDict JSONString]; -} - -- (void)create:(CDVInvokedUrlCommand*)command -{ - NSString* mediaId = [command.arguments objectAtIndex:0]; - NSString* resourcePath = [command.arguments objectAtIndex:1]; - - CDVAudioFile* audioFile = [self audioFileForResource:resourcePath withId:mediaId doValidation:NO forRecording:NO]; - - if (audioFile == nil) { - NSString* errorMessage = [NSString stringWithFormat:@"Failed to initialize Media file with path %@", resourcePath]; - NSString* jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMessage]]; - [self.commandDelegate evalJs:jsString]; - } else { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } -} - -- (void)setVolume:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - -#pragma unused(callbackId) - NSString* mediaId = [command.arguments objectAtIndex:0]; - NSNumber* volume = [command.arguments objectAtIndex:1 withDefault:[NSNumber numberWithFloat:1.0]]; - - CDVAudioFile* audioFile; - if ([self soundCache] == nil) { - [self setSoundCache:[NSMutableDictionary dictionaryWithCapacity:1]]; - } else { - audioFile = [[self soundCache] objectForKey:mediaId]; - audioFile.volume = volume; - if (audioFile.player) { - audioFile.player.volume = [volume floatValue]; - } - [[self soundCache] setObject:audioFile forKey:mediaId]; - } - - // don't care for any callbacks -} - -- (void)startPlayingAudio:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - -#pragma unused(callbackId) - NSString* mediaId = [command.arguments objectAtIndex:0]; - NSString* resourcePath = [command.arguments objectAtIndex:1]; - NSDictionary* options = [command.arguments objectAtIndex:2 withDefault:nil]; - - BOOL bError = NO; - NSString* jsString = nil; - - CDVAudioFile* audioFile = [self audioFileForResource:resourcePath withId:mediaId doValidation:YES forRecording:NO]; - if ((audioFile != nil) && (audioFile.resourceURL != nil)) { - if (audioFile.player == nil) { - bError = [self prepareToPlay:audioFile withId:mediaId]; - } - if (!bError) { - // audioFile.player != nil or player was successfully created - // get the audioSession and set the category to allow Playing when device is locked or ring/silent switch engaged - if ([self hasAudioSession]) { - NSError* __autoreleasing err = nil; - NSNumber* playAudioWhenScreenIsLocked = [options objectForKey:@"playAudioWhenScreenIsLocked"]; - BOOL bPlayAudioWhenScreenIsLocked = YES; - if (playAudioWhenScreenIsLocked != nil) { - bPlayAudioWhenScreenIsLocked = [playAudioWhenScreenIsLocked boolValue]; - } - - NSString* sessionCategory = bPlayAudioWhenScreenIsLocked ? AVAudioSessionCategoryPlayback : AVAudioSessionCategorySoloAmbient; - [self.avSession setCategory:sessionCategory error:&err]; - if (![self.avSession setActive:YES error:&err]) { - // other audio with higher priority that does not allow mixing could cause this to fail - NSLog(@"Unable to play audio: %@", [err localizedFailureReason]); - bError = YES; - } - } - if (!bError) { - NSLog(@"Playing audio sample '%@'", audioFile.resourcePath); - NSNumber* loopOption = [options objectForKey:@"numberOfLoops"]; - NSInteger numberOfLoops = 0; - if (loopOption != nil) { - numberOfLoops = [loopOption intValue] - 1; - } - audioFile.player.numberOfLoops = numberOfLoops; - if (audioFile.player.isPlaying) { - [audioFile.player stop]; - audioFile.player.currentTime = 0; - } - if (audioFile.volume != nil) { - audioFile.player.volume = [audioFile.volume floatValue]; - } - - [audioFile.player play]; - double position = round(audioFile.player.duration * 1000) / 1000; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%.3f);\n%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_DURATION, position, @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_RUNNING]; - [self.commandDelegate evalJs:jsString]; - } - } - if (bError) { - /* I don't see a problem playing previously recorded audio so removing this section - BG - NSError* error; - // try loading it one more time, in case the file was recorded previously - audioFile.player = [[ AVAudioPlayer alloc ] initWithContentsOfURL:audioFile.resourceURL error:&error]; - if (error != nil) { - NSLog(@"Failed to initialize AVAudioPlayer: %@\n", error); - audioFile.player = nil; - } else { - NSLog(@"Playing audio sample '%@'", audioFile.resourcePath); - audioFile.player.numberOfLoops = numberOfLoops; - [audioFile.player play]; - } */ - // error creating the session or player - // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, MEDIA_ERR_NONE_SUPPORTED]; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_NONE_SUPPORTED message:nil]]; - [self.commandDelegate evalJs:jsString]; - } - } - // else audioFile was nil - error already returned from audioFile for resource - return; -} - -- (BOOL)prepareToPlay:(CDVAudioFile*)audioFile withId:(NSString*)mediaId -{ - BOOL bError = NO; - NSError* __autoreleasing playerError = nil; - - // create the player - NSURL* resourceURL = audioFile.resourceURL; - - if ([resourceURL isFileURL]) { - audioFile.player = [[CDVAudioPlayer alloc] initWithContentsOfURL:resourceURL error:&playerError]; - } else { - NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:resourceURL]; - NSString* userAgent = [self.commandDelegate userAgent]; - if (userAgent) { - [request setValue:userAgent forHTTPHeaderField:@"User-Agent"]; - } - - NSURLResponse* __autoreleasing response = nil; - NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&playerError]; - if (playerError) { - NSLog(@"Unable to download audio from: %@", [resourceURL absoluteString]); - } else { - // bug in AVAudioPlayer when playing downloaded data in NSData - we have to download the file and play from disk - CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault); - CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef); - NSString* filePath = [NSString stringWithFormat:@"%@/%@", [NSTemporaryDirectory()stringByStandardizingPath], uuidString]; - CFRelease(uuidString); - CFRelease(uuidRef); - - [data writeToFile:filePath atomically:YES]; - NSURL* fileURL = [NSURL fileURLWithPath:filePath]; - audioFile.player = [[CDVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&playerError]; - } - } - - if (playerError != nil) { - NSLog(@"Failed to initialize AVAudioPlayer: %@\n", [playerError localizedDescription]); - audioFile.player = nil; - if (self.avSession) { - [self.avSession setActive:NO error:nil]; - } - bError = YES; - } else { - audioFile.player.mediaId = mediaId; - audioFile.player.delegate = self; - bError = ![audioFile.player prepareToPlay]; - } - return bError; -} - -- (void)stopPlayingAudio:(CDVInvokedUrlCommand*)command -{ - NSString* mediaId = [command.arguments objectAtIndex:0]; - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - NSString* jsString = nil; - - if ((audioFile != nil) && (audioFile.player != nil)) { - NSLog(@"Stopped playing audio sample '%@'", audioFile.resourcePath); - [audioFile.player stop]; - audioFile.player.currentTime = 0; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_STOPPED]; - } // ignore if no media playing - if (jsString) { - [self.commandDelegate evalJs:jsString]; - } -} - -- (void)pausePlayingAudio:(CDVInvokedUrlCommand*)command -{ - NSString* mediaId = [command.arguments objectAtIndex:0]; - NSString* jsString = nil; - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - - if ((audioFile != nil) && (audioFile.player != nil)) { - NSLog(@"Paused playing audio sample '%@'", audioFile.resourcePath); - [audioFile.player pause]; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_PAUSED]; - } - // ignore if no media playing - - if (jsString) { - [self.commandDelegate evalJs:jsString]; - } -} - -- (void)seekToAudio:(CDVInvokedUrlCommand*)command -{ - // args: - // 0 = Media id - // 1 = path to resource - // 2 = seek to location in milliseconds - - NSString* mediaId = [command.arguments objectAtIndex:0]; - - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - double position = [[command.arguments objectAtIndex:1] doubleValue]; - - if ((audioFile != nil) && (audioFile.player != nil)) { - NSString* jsString; - double posInSeconds = position / 1000; - if (posInSeconds >= audioFile.player.duration) { - // The seek is past the end of file. Stop media and reset to beginning instead of seeking past the end. - [audioFile.player stop]; - audioFile.player.currentTime = 0; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%.3f);\n%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_POSITION, 0.0, @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_STOPPED]; - // NSLog(@"seekToEndJsString=%@",jsString); - } else { - audioFile.player.currentTime = posInSeconds; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%f);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_POSITION, posInSeconds]; - // NSLog(@"seekJsString=%@",jsString); - } - - [self.commandDelegate evalJs:jsString]; - } -} - -- (void)release:(CDVInvokedUrlCommand*)command -{ - NSString* mediaId = [command.arguments objectAtIndex:0]; - - if (mediaId != nil) { - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - if (audioFile != nil) { - if (audioFile.player && [audioFile.player isPlaying]) { - [audioFile.player stop]; - } - if (audioFile.recorder && [audioFile.recorder isRecording]) { - [audioFile.recorder stop]; - } - if (self.avSession) { - [self.avSession setActive:NO error:nil]; - self.avSession = nil; - } - [[self soundCache] removeObjectForKey:mediaId]; - NSLog(@"Media with id %@ released", mediaId); - } - } -} - -- (void)getCurrentPositionAudio:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSString* mediaId = [command.arguments objectAtIndex:0]; - -#pragma unused(mediaId) - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - double position = -1; - - if ((audioFile != nil) && (audioFile.player != nil) && [audioFile.player isPlaying]) { - position = round(audioFile.player.currentTime * 1000) / 1000; - } - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:position]; - NSString* jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%.3f);\n%@", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_POSITION, position, [result toSuccessCallbackString:callbackId]]; - [self.commandDelegate evalJs:jsString]; -} - -- (void)startRecordingAudio:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - -#pragma unused(callbackId) - - NSString* mediaId = [command.arguments objectAtIndex:0]; - CDVAudioFile* audioFile = [self audioFileForResource:[command.arguments objectAtIndex:1] withId:mediaId doValidation:YES forRecording:YES]; - NSString* jsString = nil; - NSString* errorMsg = @""; - - if ((audioFile != nil) && (audioFile.resourceURL != nil)) { - NSError* __autoreleasing error = nil; - - if (audioFile.recorder != nil) { - [audioFile.recorder stop]; - audioFile.recorder = nil; - } - // get the audioSession and set the category to allow recording when device is locked or ring/silent switch engaged - if ([self hasAudioSession]) { - [self.avSession setCategory:AVAudioSessionCategoryRecord error:nil]; - if (![self.avSession setActive:YES error:&error]) { - // other audio with higher priority that does not allow mixing could cause this to fail - errorMsg = [NSString stringWithFormat:@"Unable to record audio: %@", [error localizedFailureReason]]; - // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, MEDIA_ERR_ABORTED]; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]]; - [self.commandDelegate evalJs:jsString]; - return; - } - } - - // create a new recorder for each start record - audioFile.recorder = [[CDVAudioRecorder alloc] initWithURL:audioFile.resourceURL settings:nil error:&error]; - - bool recordingSuccess = NO; - if (error == nil) { - audioFile.recorder.delegate = self; - audioFile.recorder.mediaId = mediaId; - recordingSuccess = [audioFile.recorder record]; - if (recordingSuccess) { - NSLog(@"Started recording audio sample '%@'", audioFile.resourcePath); - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_RUNNING]; - } - } - - if ((error != nil) || (recordingSuccess == NO)) { - if (error != nil) { - errorMsg = [NSString stringWithFormat:@"Failed to initialize AVAudioRecorder: %@\n", [error localizedFailureReason]]; - } else { - errorMsg = @"Failed to start recording using AVAudioRecorder"; - } - audioFile.recorder = nil; - if (self.avSession) { - [self.avSession setActive:NO error:nil]; - } - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]]; - } - } else { - // file did not validate - NSString* errorMsg = [NSString stringWithFormat:@"Could not record audio at '%@'", audioFile.resourcePath]; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]]; - } - if (jsString) { - [self.commandDelegate evalJs:jsString]; - } - return; -} - -- (void)stopRecordingAudio:(CDVInvokedUrlCommand*)command -{ - NSString* mediaId = [command.arguments objectAtIndex:0]; - - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - NSString* jsString = nil; - - if ((audioFile != nil) && (audioFile.recorder != nil)) { - NSLog(@"Stopped recording audio sample '%@'", audioFile.resourcePath); - [audioFile.recorder stop]; - // no callback - that will happen in audioRecorderDidFinishRecording - } - // ignore if no media recording - if (jsString) { - [self.commandDelegate evalJs:jsString]; - } -} - -- (void)audioRecorderDidFinishRecording:(AVAudioRecorder*)recorder successfully:(BOOL)flag -{ - CDVAudioRecorder* aRecorder = (CDVAudioRecorder*)recorder; - NSString* mediaId = aRecorder.mediaId; - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - NSString* jsString = nil; - - if (audioFile != nil) { - NSLog(@"Finished recording audio sample '%@'", audioFile.resourcePath); - } - if (flag) { - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_STOPPED]; - } else { - // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, MEDIA_ERR_DECODE]; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_DECODE message:nil]]; - } - if (self.avSession) { - [self.avSession setActive:NO error:nil]; - } - [self.commandDelegate evalJs:jsString]; -} - -- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer*)player successfully:(BOOL)flag -{ - CDVAudioPlayer* aPlayer = (CDVAudioPlayer*)player; - NSString* mediaId = aPlayer.mediaId; - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - NSString* jsString = nil; - - if (audioFile != nil) { - NSLog(@"Finished playing audio sample '%@'", audioFile.resourcePath); - } - if (flag) { - audioFile.player.currentTime = 0; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_STOPPED]; - } else { - // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, MEDIA_ERR_DECODE]; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_DECODE message:nil]]; - } - if (self.avSession) { - [self.avSession setActive:NO error:nil]; - } - [self.commandDelegate evalJs:jsString]; -} - -- (void)onMemoryWarning -{ - [[self soundCache] removeAllObjects]; - [self setSoundCache:nil]; - [self setAvSession:nil]; - - [super onMemoryWarning]; -} - -- (void)dealloc -{ - [[self soundCache] removeAllObjects]; -} - -- (void)onReset -{ - for (CDVAudioFile* audioFile in [[self soundCache] allValues]) { - if (audioFile != nil) { - if (audioFile.player != nil) { - [audioFile.player stop]; - audioFile.player.currentTime = 0; - } - if (audioFile.recorder != nil) { - [audioFile.recorder stop]; - } - } - } - - [[self soundCache] removeAllObjects]; -} - -@end - -@implementation CDVAudioFile - -@synthesize resourcePath; -@synthesize resourceURL; -@synthesize player, volume; -@synthesize recorder; - -@end -@implementation CDVAudioPlayer -@synthesize mediaId; - -@end - -@implementation CDVAudioRecorder -@synthesize mediaId; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVSplashScreen.h b/iPhone/CordovaLib/Classes/CDVSplashScreen.h deleted file mode 100755 index 704ab43..0000000 --- a/iPhone/CordovaLib/Classes/CDVSplashScreen.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import "CDVPlugin.h" - -@interface CDVSplashScreen : CDVPlugin { - UIActivityIndicatorView* _activityView; - UIImageView* _imageView; - NSString* _curImageName; - BOOL _visible; -} - -- (void)show:(CDVInvokedUrlCommand*)command; -- (void)hide:(CDVInvokedUrlCommand*)command; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVSplashScreen.m b/iPhone/CordovaLib/Classes/CDVSplashScreen.m deleted file mode 100755 index 8ce1191..0000000 --- a/iPhone/CordovaLib/Classes/CDVSplashScreen.m +++ /dev/null @@ -1,233 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVSplashScreen.h" - -#define kSplashScreenDurationDefault 0.25f - -@implementation CDVSplashScreen - -- (void)pluginInitialize -{ - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad) name:CDVPageDidLoadNotification object:self.webView]; - - [self setVisible:YES]; -} - -- (void)show:(CDVInvokedUrlCommand*)command -{ - [self setVisible:YES]; -} - -- (void)hide:(CDVInvokedUrlCommand*)command -{ - [self setVisible:NO]; -} - -- (void)pageDidLoad -{ - id autoHideSplashScreenValue = [self.commandDelegate.settings objectForKey:@"AutoHideSplashScreen"]; - - // if value is missing, default to yes - if ((autoHideSplashScreenValue == nil) || [autoHideSplashScreenValue boolValue]) { - [self setVisible:NO]; - } -} - -- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context -{ - [self updateImage]; -} - -- (void)createViews -{ - /* - * The Activity View is the top spinning throbber in the status/battery bar. We init it with the default Grey Style. - * - * whiteLarge = UIActivityIndicatorViewStyleWhiteLarge - * white = UIActivityIndicatorViewStyleWhite - * gray = UIActivityIndicatorViewStyleGray - * - */ - NSString* topActivityIndicator = [self.commandDelegate.settings objectForKey:@"TopActivityIndicator"]; - UIActivityIndicatorViewStyle topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray; - - if ([topActivityIndicator isEqualToString:@"whiteLarge"]) { - topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhiteLarge; - } else if ([topActivityIndicator isEqualToString:@"white"]) { - topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhite; - } else if ([topActivityIndicator isEqualToString:@"gray"]) { - topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray; - } - - UIView* parentView = self.viewController.view; - parentView.userInteractionEnabled = NO; // disable user interaction while splashscreen is shown - _activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:topActivityIndicatorStyle]; - _activityView.center = CGPointMake(parentView.bounds.size.width / 2, parentView.bounds.size.height / 2); - _activityView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin - | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin; - [_activityView startAnimating]; - - // Set the frame & image later. - _imageView = [[UIImageView alloc] init]; - [parentView addSubview:_imageView]; - - id showSplashScreenSpinnerValue = [self.commandDelegate.settings objectForKey:@"ShowSplashScreenSpinner"]; - // backwards compatibility - if key is missing, default to true - if ((showSplashScreenSpinnerValue == nil) || [showSplashScreenSpinnerValue boolValue]) { - [parentView addSubview:_activityView]; - } - - // Frame is required when launching in portrait mode. - // Bounds for landscape since it captures the rotation. - [parentView addObserver:self forKeyPath:@"frame" options:0 context:nil]; - [parentView addObserver:self forKeyPath:@"bounds" options:0 context:nil]; - - [self updateImage]; -} - -- (void)destroyViews -{ - [_imageView removeFromSuperview]; - [_activityView removeFromSuperview]; - _imageView = nil; - _activityView = nil; - _curImageName = nil; - - self.viewController.view.userInteractionEnabled = YES; // re-enable user interaction upon completion - [self.viewController.view removeObserver:self forKeyPath:@"frame"]; - [self.viewController.view removeObserver:self forKeyPath:@"bounds"]; -} - -// Sets the view's frame and image. -- (void)updateImage -{ - UIInterfaceOrientation orientation = self.viewController.interfaceOrientation; - - // Use UILaunchImageFile if specified in plist. Otherwise, use Default. - NSString* imageName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchImageFile"]; - - if (imageName) { - imageName = [imageName stringByDeletingPathExtension]; - } else { - imageName = @"Default"; - } - - if (CDV_IsIPhone5()) { - imageName = [imageName stringByAppendingString:@"-568h"]; - } else if (CDV_IsIPad()) { - switch (orientation) { - case UIInterfaceOrientationLandscapeLeft: - case UIInterfaceOrientationLandscapeRight: - imageName = [imageName stringByAppendingString:@"-Landscape"]; - break; - - case UIInterfaceOrientationPortrait: - case UIInterfaceOrientationPortraitUpsideDown: - default: - imageName = [imageName stringByAppendingString:@"-Portrait"]; - break; - } - } - - if (![imageName isEqualToString:_curImageName]) { - UIImage* img = [UIImage imageNamed:imageName]; - _imageView.image = img; - _curImageName = imageName; - } - - // Check that splash screen's image exists before updating bounds - if (_imageView.image) { - [self updateBounds]; - } else { - NSLog(@"WARNING: The splashscreen image named %@ was not found", imageName); - } -} - -- (void)updateBounds -{ - UIImage* img = _imageView.image; - CGRect imgBounds = CGRectMake(0, 0, img.size.width, img.size.height); - - CGSize screenSize = [self.viewController.view convertRect:[UIScreen mainScreen].bounds fromView:nil].size; - - // There's a special case when the image is the size of the screen. - if (CGSizeEqualToSize(screenSize, imgBounds.size)) { - CGRect statusFrame = [self.viewController.view convertRect:[UIApplication sharedApplication].statusBarFrame fromView:nil]; - // fix for splash screen bounce from http://stackoverflow.com/questions/18927141/ios7-startup-screen-splash-screen-leave-a-space-on-the-bottom - if (!(IsAtLeastiOSVersion(@"7.0"))) { - imgBounds.origin.y -= statusFrame.size.height; - } - } else { - CGRect viewBounds = self.viewController.view.bounds; - CGFloat imgAspect = imgBounds.size.width / imgBounds.size.height; - CGFloat viewAspect = viewBounds.size.width / viewBounds.size.height; - // This matches the behaviour of the native splash screen. - CGFloat ratio; - if (viewAspect > imgAspect) { - ratio = viewBounds.size.width / imgBounds.size.width; - } else { - ratio = viewBounds.size.height / imgBounds.size.height; - } - imgBounds.size.height *= ratio; - imgBounds.size.width *= ratio; - } - - _imageView.frame = imgBounds; -} - -- (void)setVisible:(BOOL)visible -{ - if (visible == _visible) { - return; - } - _visible = visible; - - id fadeSplashScreenValue = [self.commandDelegate.settings objectForKey:@"FadeSplashScreen"]; - id fadeSplashScreenDuration = [self.commandDelegate.settings objectForKey:@"FadeSplashScreenDuration"]; - - float fadeDuration = fadeSplashScreenDuration == nil ? kSplashScreenDurationDefault : [fadeSplashScreenDuration floatValue]; - - if ((fadeSplashScreenValue == nil) || ![fadeSplashScreenValue boolValue]) { - fadeDuration = 0; - } - - // Never animate the showing of the splash screen. - if (visible) { - if (_imageView == nil) { - [self createViews]; - } - } else if (fadeDuration == 0) { - [self destroyViews]; - } else { - [UIView transitionWithView:self.viewController.view - duration:fadeDuration - options:UIViewAnimationOptionTransitionNone - animations:^(void) { - [_imageView setAlpha:0]; - [_activityView setAlpha:0]; - } - - completion:^(BOOL finished) { - [self destroyViews]; - }]; - } -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVTimer.h b/iPhone/CordovaLib/Classes/CDVTimer.h deleted file mode 100755 index 6d31593..0000000 --- a/iPhone/CordovaLib/Classes/CDVTimer.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import - -@interface CDVTimer : NSObject - -+ (void)start:(NSString*)name; -+ (void)stop:(NSString*)name; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVTimer.m b/iPhone/CordovaLib/Classes/CDVTimer.m deleted file mode 100755 index 784e94d..0000000 --- a/iPhone/CordovaLib/Classes/CDVTimer.m +++ /dev/null @@ -1,123 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVTimer.h" - -#pragma mark CDVTimerItem - -@interface CDVTimerItem : NSObject - -@property (nonatomic, strong) NSString* name; -@property (nonatomic, strong) NSDate* started; -@property (nonatomic, strong) NSDate* ended; - -- (void)log; - -@end - -@implementation CDVTimerItem - -- (void)log -{ - NSLog(@"[CDVTimer][%@] %fms", self.name, [self.ended timeIntervalSinceDate:self.started] * 1000.0); -} - -@end - -#pragma mark CDVTimer - -@interface CDVTimer () - -@property (nonatomic, strong) NSMutableDictionary* items; - -@end - -@implementation CDVTimer - -#pragma mark object methods - -- (id)init -{ - if (self = [super init]) { - self.items = [NSMutableDictionary dictionaryWithCapacity:6]; - } - - return self; -} - -- (void)add:(NSString*)name -{ - if ([self.items objectForKey:[name lowercaseString]] == nil) { - CDVTimerItem* item = [CDVTimerItem new]; - item.name = name; - item.started = [NSDate new]; - [self.items setObject:item forKey:[name lowercaseString]]; - } else { - NSLog(@"Timer called '%@' already exists.", name); - } -} - -- (void)remove:(NSString*)name -{ - CDVTimerItem* item = [self.items objectForKey:[name lowercaseString]]; - - if (item != nil) { - item.ended = [NSDate new]; - [item log]; - [self.items removeObjectForKey:[name lowercaseString]]; - } else { - NSLog(@"Timer called '%@' does not exist.", name); - } -} - -- (void)removeAll -{ - [self.items removeAllObjects]; -} - -#pragma mark class methods - -+ (void)start:(NSString*)name -{ - [[CDVTimer sharedInstance] add:name]; -} - -+ (void)stop:(NSString*)name -{ - [[CDVTimer sharedInstance] remove:name]; -} - -+ (void)clearAll -{ - [[CDVTimer sharedInstance] removeAll]; -} - -+ (CDVTimer*)sharedInstance -{ - static dispatch_once_t pred = 0; - __strong static CDVTimer* _sharedObject = nil; - - dispatch_once(&pred, ^{ - _sharedObject = [[self alloc] init]; - }); - - return _sharedObject; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVURLProtocol.h b/iPhone/CordovaLib/Classes/CDVURLProtocol.h deleted file mode 100755 index 5444f6d..0000000 --- a/iPhone/CordovaLib/Classes/CDVURLProtocol.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import "CDVAvailability.h" - -@class CDVViewController; - -@interface CDVURLProtocol : NSURLProtocol {} - -+ (void)registerViewController:(CDVViewController*)viewController; -+ (void)unregisterViewController:(CDVViewController*)viewController; -@end diff --git a/iPhone/CordovaLib/Classes/CDVURLProtocol.m b/iPhone/CordovaLib/Classes/CDVURLProtocol.m deleted file mode 100755 index afc10de..0000000 --- a/iPhone/CordovaLib/Classes/CDVURLProtocol.m +++ /dev/null @@ -1,230 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import -#import -#import -#import "CDVURLProtocol.h" -#import "CDVCommandQueue.h" -#import "CDVWhitelist.h" -#import "CDVViewController.h" -#import "CDVFile.h" - -@interface CDVHTTPURLResponse : NSHTTPURLResponse -@property (nonatomic) NSInteger statusCode; -@end - -static CDVWhitelist* gWhitelist = nil; -// Contains a set of NSNumbers of addresses of controllers. It doesn't store -// the actual pointer to avoid retaining. -static NSMutableSet* gRegisteredControllers = nil; - -// Returns the registered view controller that sent the given request. -// If the user-agent is not from a UIWebView, or if it's from an unregistered one, -// then nil is returned. -static CDVViewController *viewControllerForRequest(NSURLRequest* request) -{ - // The exec bridge explicitly sets the VC address in a header. - // This works around the User-Agent not being set for file: URLs. - NSString* addrString = [request valueForHTTPHeaderField:@"vc"]; - - if (addrString == nil) { - NSString* userAgent = [request valueForHTTPHeaderField:@"User-Agent"]; - if (userAgent == nil) { - return nil; - } - NSUInteger bracketLocation = [userAgent rangeOfString:@"(" options:NSBackwardsSearch].location; - if (bracketLocation == NSNotFound) { - return nil; - } - addrString = [userAgent substringFromIndex:bracketLocation + 1]; - } - - long long viewControllerAddress = [addrString longLongValue]; - @synchronized(gRegisteredControllers) { - if (![gRegisteredControllers containsObject:[NSNumber numberWithLongLong:viewControllerAddress]]) { - return nil; - } - } - - return (__bridge CDVViewController*)(void*)viewControllerAddress; -} - -@implementation CDVURLProtocol - -+ (void)registerPGHttpURLProtocol {} - -+ (void)registerURLProtocol {} - -// Called to register the URLProtocol, and to make it away of an instance of -// a ViewController. -+ (void)registerViewController:(CDVViewController*)viewController -{ - if (gRegisteredControllers == nil) { - [NSURLProtocol registerClass:[CDVURLProtocol class]]; - gRegisteredControllers = [[NSMutableSet alloc] initWithCapacity:8]; - // The whitelist doesn't change, so grab the first one and store it. - gWhitelist = viewController.whitelist; - - // Note that we grab the whitelist from the first viewcontroller for now - but this will change - // when we allow a registered viewcontroller to have its own whitelist (e.g InAppBrowser) - // Differentiating the requests will be through the 'vc' http header below as used for the js->objc bridge. - // The 'vc' value is generated by casting the viewcontroller object to a (long long) value (see CDVViewController::webViewDidFinishLoad) - if (gWhitelist == nil) { - NSLog(@"WARNING: NO whitelist has been set in CDVURLProtocol."); - } - } - - @synchronized(gRegisteredControllers) { - [gRegisteredControllers addObject:[NSNumber numberWithLongLong:(long long)viewController]]; - } -} - -+ (void)unregisterViewController:(CDVViewController*)viewController -{ - @synchronized(gRegisteredControllers) { - [gRegisteredControllers removeObject:[NSNumber numberWithLongLong:(long long)viewController]]; - } -} - -+ (BOOL)canInitWithRequest:(NSURLRequest*)theRequest -{ - NSURL* theUrl = [theRequest URL]; - CDVViewController* viewController = viewControllerForRequest(theRequest); - - if ([[theUrl absoluteString] hasPrefix:kCDVAssetsLibraryPrefix]) { - return YES; - } else if (viewController != nil) { - if ([[theUrl path] isEqualToString:@"/!gap_exec"]) { - NSString* queuedCommandsJSON = [theRequest valueForHTTPHeaderField:@"cmds"]; - NSString* requestId = [theRequest valueForHTTPHeaderField:@"rc"]; - if (requestId == nil) { - NSLog(@"!cordova request missing rc header"); - return NO; - } - BOOL hasCmds = [queuedCommandsJSON length] > 0; - if (hasCmds) { - SEL sel = @selector(enqueCommandBatch:); - [viewController.commandQueue performSelectorOnMainThread:sel withObject:queuedCommandsJSON waitUntilDone:NO]; - } else { - SEL sel = @selector(maybeFetchCommandsFromJs:); - [viewController.commandQueue performSelectorOnMainThread:sel withObject:[NSNumber numberWithInteger:[requestId integerValue]] waitUntilDone:NO]; - } - // Returning NO here would be 20% faster, but it spams WebInspector's console with failure messages. - // If JS->Native bridge speed is really important for an app, they should use the iframe bridge. - // Returning YES here causes the request to come through canInitWithRequest two more times. - // For this reason, we return NO when cmds exist. - return !hasCmds; - } - // we only care about http and https connections. - // CORS takes care of http: trying to access file: URLs. - if ([gWhitelist schemeIsAllowed:[theUrl scheme]]) { - // if it FAILS the whitelist, we return TRUE, so we can fail the connection later - return ![gWhitelist URLIsAllowed:theUrl]; - } - } - - return NO; -} - -+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)request -{ - // NSLog(@"%@ received %@", self, NSStringFromSelector(_cmd)); - return request; -} - -- (void)startLoading -{ - // NSLog(@"%@ received %@ - start", self, NSStringFromSelector(_cmd)); - NSURL* url = [[self request] URL]; - - if ([[url path] isEqualToString:@"/!gap_exec"]) { - [self sendResponseWithResponseCode:200 data:nil mimeType:nil]; - return; - } else if ([[url absoluteString] hasPrefix:kCDVAssetsLibraryPrefix]) { - ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { - if (asset) { - // We have the asset! Get the data and send it along. - ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; - NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType); - Byte* buffer = (Byte*)malloc([assetRepresentation size]); - NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil]; - NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES]; - [self sendResponseWithResponseCode:200 data:data mimeType:MIMEType]; - } else { - // Retrieving the asset failed for some reason. Send an error. - [self sendResponseWithResponseCode:404 data:nil mimeType:nil]; - } - }; - ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) { - // Retrieving the asset failed for some reason. Send an error. - [self sendResponseWithResponseCode:401 data:nil mimeType:nil]; - }; - - ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; - [assetsLibrary assetForURL:url resultBlock:resultBlock failureBlock:failureBlock]; - return; - } - - NSString* body = [gWhitelist errorStringForURL:url]; - [self sendResponseWithResponseCode:401 data:[body dataUsingEncoding:NSASCIIStringEncoding] mimeType:nil]; -} - -- (void)stopLoading -{ - // do any cleanup here -} - -+ (BOOL)requestIsCacheEquivalent:(NSURLRequest*)requestA toRequest:(NSURLRequest*)requestB -{ - return NO; -} - -- (void)sendResponseWithResponseCode:(NSInteger)statusCode data:(NSData*)data mimeType:(NSString*)mimeType -{ - if (mimeType == nil) { - mimeType = @"text/plain"; - } - NSString* encodingName = [@"text/plain" isEqualToString : mimeType] ? @"UTF-8" : nil; - CDVHTTPURLResponse* response = - [[CDVHTTPURLResponse alloc] initWithURL:[[self request] URL] - MIMEType:mimeType - expectedContentLength:[data length] - textEncodingName:encodingName]; - response.statusCode = statusCode; - - [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; - if (data != nil) { - [[self client] URLProtocol:self didLoadData:data]; - } - [[self client] URLProtocolDidFinishLoading:self]; -} - -@end - -@implementation CDVHTTPURLResponse -@synthesize statusCode; - -- (NSDictionary*)allHeaderFields -{ - return nil; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVUserAgentUtil.h b/iPhone/CordovaLib/Classes/CDVUserAgentUtil.h deleted file mode 100755 index 4de382f..0000000 --- a/iPhone/CordovaLib/Classes/CDVUserAgentUtil.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import - -@interface CDVUserAgentUtil : NSObject -+ (NSString*)originalUserAgent; -+ (void)acquireLock:(void (^)(NSInteger lockToken))block; -+ (void)releaseLock:(NSInteger*)lockToken; -+ (void)setUserAgent:(NSString*)value lockToken:(NSInteger)lockToken; -@end diff --git a/iPhone/CordovaLib/Classes/CDVUserAgentUtil.m b/iPhone/CordovaLib/Classes/CDVUserAgentUtil.m deleted file mode 100755 index 9923d47..0000000 --- a/iPhone/CordovaLib/Classes/CDVUserAgentUtil.m +++ /dev/null @@ -1,120 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVUserAgentUtil.h" - -#import - -// #define VerboseLog NSLog -#define VerboseLog(...) do {} while (0) - -static NSString* const kCdvUserAgentKey = @"Cordova-User-Agent"; -static NSString* const kCdvUserAgentVersionKey = @"Cordova-User-Agent-Version"; - -static NSString* gOriginalUserAgent = nil; -static NSInteger gNextLockToken = 0; -static NSInteger gCurrentLockToken = 0; -static NSMutableArray* gPendingSetUserAgentBlocks = nil; - -@implementation CDVUserAgentUtil - -+ (NSString*)originalUserAgent -{ - if (gOriginalUserAgent == nil) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppLocaleDidChange:) - name:NSCurrentLocaleDidChangeNotification object:nil]; - - NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; - NSString* systemVersion = [[UIDevice currentDevice] systemVersion]; - NSString* localeStr = [[NSLocale currentLocale] localeIdentifier]; - NSString* systemAndLocale = [NSString stringWithFormat:@"%@ %@", systemVersion, localeStr]; - - NSString* cordovaUserAgentVersion = [userDefaults stringForKey:kCdvUserAgentVersionKey]; - gOriginalUserAgent = [userDefaults stringForKey:kCdvUserAgentKey]; - BOOL cachedValueIsOld = ![systemAndLocale isEqualToString:cordovaUserAgentVersion]; - - if ((gOriginalUserAgent == nil) || cachedValueIsOld) { - UIWebView* sampleWebView = [[UIWebView alloc] initWithFrame:CGRectZero]; - gOriginalUserAgent = [sampleWebView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"]; - - [userDefaults setObject:gOriginalUserAgent forKey:kCdvUserAgentKey]; - [userDefaults setObject:systemAndLocale forKey:kCdvUserAgentVersionKey]; - - [userDefaults synchronize]; - } - } - return gOriginalUserAgent; -} - -+ (void)onAppLocaleDidChange:(NSNotification*)notification -{ - // TODO: We should figure out how to update the user-agent of existing UIWebViews when this happens. - // Maybe use the PDF bug (noted in setUserAgent:). - gOriginalUserAgent = nil; -} - -+ (void)acquireLock:(void (^)(NSInteger lockToken))block -{ - if (gCurrentLockToken == 0) { - gCurrentLockToken = ++gNextLockToken; - VerboseLog(@"Gave lock %d", gCurrentLockToken); - block(gCurrentLockToken); - } else { - if (gPendingSetUserAgentBlocks == nil) { - gPendingSetUserAgentBlocks = [[NSMutableArray alloc] initWithCapacity:4]; - } - VerboseLog(@"Waiting for lock"); - [gPendingSetUserAgentBlocks addObject:block]; - } -} - -+ (void)releaseLock:(NSInteger*)lockToken -{ - if (*lockToken == 0) { - return; - } - NSAssert(gCurrentLockToken == *lockToken, @"Got token %d, expected %d", *lockToken, gCurrentLockToken); - - VerboseLog(@"Released lock %d", *lockToken); - if ([gPendingSetUserAgentBlocks count] > 0) { - void (^block)() = [gPendingSetUserAgentBlocks objectAtIndex:0]; - [gPendingSetUserAgentBlocks removeObjectAtIndex:0]; - gCurrentLockToken = ++gNextLockToken; - NSLog(@"Gave lock %d", gCurrentLockToken); - block(gCurrentLockToken); - } else { - gCurrentLockToken = 0; - } - *lockToken = 0; -} - -+ (void)setUserAgent:(NSString*)value lockToken:(NSInteger)lockToken -{ - NSAssert(gCurrentLockToken == lockToken, @"Got token %d, expected %d", lockToken, gCurrentLockToken); - VerboseLog(@"User-Agent set to: %@", value); - - // Setting the UserAgent must occur before a UIWebView is instantiated. - // It is read per instantiation, so it does not affect previously created views. - // Except! When a PDF is loaded, all currently active UIWebViews reload their - // User-Agent from the NSUserDefaults some time after the DidFinishLoad of the PDF bah! - NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:value, @"UserAgent", nil]; - [[NSUserDefaults standardUserDefaults] registerDefaults:dict]; -} - -@end diff --git a/iPhone/CordovaLib/Classes/CDVViewController.h b/iPhone/CordovaLib/Classes/CDVViewController.h deleted file mode 100755 index 2338baf..0000000 --- a/iPhone/CordovaLib/Classes/CDVViewController.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import -#import "CDVAvailability.h" -#import "CDVInvokedUrlCommand.h" -#import "CDVCommandDelegate.h" -#import "CDVCommandQueue.h" -#import "CDVWhitelist.h" -#import "CDVScreenOrientationDelegate.h" -#import "CDVPlugin.h" - -@interface CDVViewController : UIViewController { - @protected - id _commandDelegate; - @protected - CDVCommandQueue* _commandQueue; - NSString* _userAgent; -} - -@property (nonatomic, strong) IBOutlet UIWebView* webView; - -@property (nonatomic, readonly, strong) NSMutableDictionary* pluginObjects; -@property (nonatomic, readonly, strong) NSDictionary* pluginsMap; -@property (nonatomic, readonly, strong) NSMutableDictionary* settings; -@property (nonatomic, readonly, strong) NSXMLParser* configParser; -@property (nonatomic, readonly, strong) CDVWhitelist* whitelist; // readonly for public -@property (nonatomic, readonly, assign) BOOL loadFromString; -@property (nonatomic, readwrite, assign) BOOL useSplashScreen CDV_DEPRECATED(2.5, "Add/Remove the SplashScreen plugin instead of setting this property."); - -@property (nonatomic, readwrite, copy) NSString* wwwFolderName; -@property (nonatomic, readwrite, copy) NSString* startPage; -@property (nonatomic, readonly, strong) CDVCommandQueue* commandQueue; -@property (nonatomic, readonly, strong) id commandDelegate; -@property (nonatomic, readonly) NSString* userAgent; - -+ (NSDictionary*)getBundlePlist:(NSString*)plistName; -+ (NSString*)applicationDocumentsDirectory; - -- (void)printMultitaskingInfo; -- (void)createGapView; -- (UIWebView*)newCordovaViewWithFrame:(CGRect)bounds; - -- (void)javascriptAlert:(NSString*)text; -- (NSString*)appURLScheme; - -- (NSArray*)parseInterfaceOrientations:(NSArray*)orientations; -- (BOOL)supportsOrientation:(UIInterfaceOrientation)orientation; - -- (id)getCommandInstance:(NSString*)pluginName; -- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className; -- (void)registerPlugin:(CDVPlugin*)plugin withPluginName:(NSString*)pluginName; - -- (BOOL)URLisAllowed:(NSURL*)url; - -@end diff --git a/iPhone/CordovaLib/Classes/CDVViewController.m b/iPhone/CordovaLib/Classes/CDVViewController.m deleted file mode 100755 index 94f4552..0000000 --- a/iPhone/CordovaLib/Classes/CDVViewController.m +++ /dev/null @@ -1,933 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import "CDV.h" -#import "CDVCommandDelegateImpl.h" -#import "CDVConfigParser.h" -#import "CDVUserAgentUtil.h" -#import "CDVWebViewDelegate.h" - -#define degreesToRadian(x) (M_PI * (x) / 180.0) - -@interface CDVViewController () { - NSInteger _userAgentLockToken; - CDVWebViewDelegate* _webViewDelegate; -} - -@property (nonatomic, readwrite, strong) NSXMLParser* configParser; -@property (nonatomic, readwrite, strong) NSMutableDictionary* settings; -@property (nonatomic, readwrite, strong) CDVWhitelist* whitelist; -@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginObjects; -@property (nonatomic, readwrite, strong) NSArray* startupPluginNames; -@property (nonatomic, readwrite, strong) NSDictionary* pluginsMap; -@property (nonatomic, readwrite, strong) NSArray* supportedOrientations; -@property (nonatomic, readwrite, assign) BOOL loadFromString; - -@property (readwrite, assign) BOOL initialized; - -@property (atomic, strong) NSURL* openURL; - -@end - -@implementation CDVViewController - -@synthesize webView, supportedOrientations; -@synthesize pluginObjects, pluginsMap, whitelist, startupPluginNames; -@synthesize configParser, settings, loadFromString; -@synthesize useSplashScreen; -@synthesize wwwFolderName, startPage, initialized, openURL; -@synthesize commandDelegate = _commandDelegate; -@synthesize commandQueue = _commandQueue; - -- (void)__init -{ - if ((self != nil) && !self.initialized) { - _commandQueue = [[CDVCommandQueue alloc] initWithViewController:self]; - _commandDelegate = [[CDVCommandDelegateImpl alloc] initWithViewController:self]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillTerminate:) - name:UIApplicationWillTerminateNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillResignActive:) - name:UIApplicationWillResignActiveNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidBecomeActive:) - name:UIApplicationDidBecomeActiveNotification object:nil]; - - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillEnterForeground:) - name:UIApplicationWillEnterForegroundNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidEnterBackground:) - name:UIApplicationDidEnterBackgroundNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleOpenURL:) name:CDVPluginHandleOpenURLNotification object:nil]; - - // read from UISupportedInterfaceOrientations (or UISupportedInterfaceOrientations~iPad, if its iPad) from -Info.plist - self.supportedOrientations = [self parseInterfaceOrientations: - [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UISupportedInterfaceOrientations"]]; - - [self printMultitaskingInfo]; - [self printDeprecationNotice]; - self.initialized = YES; - - // load config.xml settings - [self loadSettings]; - useSplashScreen = YES; - } -} - -- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil -{ - self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - [self __init]; - return self; -} - -- (id)init -{ - self = [super init]; - [self __init]; - return self; -} - -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; - - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; - [nc addObserver:self - selector:@selector(keyboardWillShowOrHide:) - name:UIKeyboardWillShowNotification - object:nil]; - [nc addObserver:self - selector:@selector(keyboardWillShowOrHide:) - name:UIKeyboardWillHideNotification - object:nil]; -} - -- (void)viewWillDisappear:(BOOL)animated -{ - [super viewWillDisappear:animated]; - - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; - [nc removeObserver:self name:UIKeyboardWillShowNotification object:nil]; - [nc removeObserver:self name:UIKeyboardWillHideNotification object:nil]; -} - -- (void)keyboardWillShowOrHide:(NSNotification*)notif -{ - if (![@"true" isEqualToString : self.settings[@"KeyboardShrinksView"]]) { - return; - } - BOOL showEvent = [notif.name isEqualToString:UIKeyboardWillShowNotification]; - - CGRect keyboardFrame = [notif.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; - keyboardFrame = [self.view convertRect:keyboardFrame fromView:nil]; - - CGRect newFrame = self.view.bounds; - if (showEvent) { - newFrame.size.height -= keyboardFrame.size.height; - } - self.webView.frame = newFrame; - self.webView.scrollView.contentInset = UIEdgeInsetsMake(0, 0, -keyboardFrame.size.height, 0); -} - -- (void)printDeprecationNotice -{ - if (!IsAtLeastiOSVersion(@"5.0")) { - NSLog(@"CRITICAL: For Cordova 2.0, you will need to upgrade to at least iOS 5.0 or greater. Your current version of iOS is %@.", - [[UIDevice currentDevice] systemVersion] - ); - } -} - -- (void)printMultitaskingInfo -{ - UIDevice* device = [UIDevice currentDevice]; - BOOL backgroundSupported = NO; - - if ([device respondsToSelector:@selector(isMultitaskingSupported)]) { - backgroundSupported = device.multitaskingSupported; - } - - NSNumber* exitsOnSuspend = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIApplicationExitsOnSuspend"]; - if (exitsOnSuspend == nil) { // if it's missing, it should be NO (i.e. multi-tasking on by default) - exitsOnSuspend = [NSNumber numberWithBool:NO]; - } - - NSLog(@"Multi-tasking -> Device: %@, App: %@", (backgroundSupported ? @"YES" : @"NO"), (![exitsOnSuspend intValue]) ? @"YES" : @"NO"); -} - -- (BOOL)URLisAllowed:(NSURL*)url -{ - if (self.whitelist == nil) { - return YES; - } - - return [self.whitelist URLIsAllowed:url]; -} - -- (void)loadSettings -{ - CDVConfigParser* delegate = [[CDVConfigParser alloc] init]; - - // read from config.xml in the app bundle - NSString* path = [[NSBundle mainBundle] pathForResource:@"config" ofType:@"xml"]; - - if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { - NSAssert(NO, @"ERROR: config.xml does not exist. Please run cordova-ios/bin/cordova_plist_to_config_xml path/to/project."); - return; - } - - NSURL* url = [NSURL fileURLWithPath:path]; - - configParser = [[NSXMLParser alloc] initWithContentsOfURL:url]; - if (configParser == nil) { - NSLog(@"Failed to initialize XML parser."); - return; - } - [configParser setDelegate:((id < NSXMLParserDelegate >)delegate)]; - [configParser parse]; - - // Get the plugin dictionary, whitelist and settings from the delegate. - self.pluginsMap = delegate.pluginsDict; - self.startupPluginNames = delegate.startupPluginNames; - self.whitelist = [[CDVWhitelist alloc] initWithArray:delegate.whitelistHosts]; - self.settings = delegate.settings; - - // And the start folder/page. - self.wwwFolderName = @"www"; - self.startPage = delegate.startPage; - if (self.startPage == nil) { - self.startPage = @"index.html"; - } - - // Initialize the plugin objects dict. - self.pluginObjects = [[NSMutableDictionary alloc] initWithCapacity:20]; -} - -// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. -- (void)viewDidLoad -{ - [super viewDidLoad]; - - NSURL* appURL = nil; - NSString* loadErr = nil; - - if ([self.startPage rangeOfString:@"://"].location != NSNotFound) { - appURL = [NSURL URLWithString:self.startPage]; - } else if ([self.wwwFolderName rangeOfString:@"://"].location != NSNotFound) { - appURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%@", self.wwwFolderName, self.startPage]]; - } else { - NSString* startFilePath = [self.commandDelegate pathForResource:self.startPage]; - if (startFilePath == nil) { - loadErr = [NSString stringWithFormat:@"ERROR: Start Page at '%@/%@' was not found.", self.wwwFolderName, self.startPage]; - NSLog(@"%@", loadErr); - self.loadFromString = YES; - appURL = nil; - } else { - appURL = [NSURL fileURLWithPath:startFilePath]; - } - } - - // // Fix the iOS 5.1 SECURITY_ERR bug (CB-347), this must be before the webView is instantiated //// - - NSString* backupWebStorageType = @"cloud"; // default value - - id backupWebStorage = self.settings[@"BackupWebStorage"]; - if ([backupWebStorage isKindOfClass:[NSString class]]) { - backupWebStorageType = backupWebStorage; - } - self.settings[@"BackupWebStorage"] = backupWebStorageType; - - if (IsAtLeastiOSVersion(@"5.1")) { - [CDVLocalStorage __fixupDatabaseLocationsWithBackupType:backupWebStorageType]; - } - - // // Instantiate the WebView /////////////// - - [self createGapView]; - - // ///////////////// - - NSNumber* enableLocation = [self.settings objectForKey:@"EnableLocation"]; - NSString* enableViewportScale = [self.settings objectForKey:@"EnableViewportScale"]; - NSNumber* allowInlineMediaPlayback = [self.settings objectForKey:@"AllowInlineMediaPlayback"]; - BOOL mediaPlaybackRequiresUserAction = YES; // default value - if ([self.settings objectForKey:@"MediaPlaybackRequiresUserAction"]) { - mediaPlaybackRequiresUserAction = [(NSNumber*)[settings objectForKey:@"MediaPlaybackRequiresUserAction"] boolValue]; - } - BOOL hideKeyboardFormAccessoryBar = NO; // default value - if ([self.settings objectForKey:@"HideKeyboardFormAccessoryBar"]) { - hideKeyboardFormAccessoryBar = [(NSNumber*)[settings objectForKey:@"HideKeyboardFormAccessoryBar"] boolValue]; - } - - self.webView.scalesPageToFit = [enableViewportScale boolValue]; - - /* - * Fire up the GPS Service right away as it takes a moment for data to come back. - */ - - if ([enableLocation boolValue]) { - NSLog(@"Deprecated: The 'EnableLocation' boolean property is deprecated in 2.5.0, and will be removed in 3.0.0. Use the 'onload' boolean attribute (of the CDVLocation plugin."); - [[self.commandDelegate getCommandInstance:@"Geolocation"] getLocation:[CDVInvokedUrlCommand new]]; - } - - if (hideKeyboardFormAccessoryBar) { - __weak CDVViewController* weakSelf = self; - [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification - object:nil - queue:[NSOperationQueue mainQueue] - usingBlock:^(NSNotification* notification) { - // we can't hide it here because the accessory bar hasn't been created yet, so we delay on the queue - [weakSelf performSelector:@selector(hideKeyboardFormAccessoryBar) withObject:nil afterDelay:0]; - }]; - } - - /* - * Fire up CDVLocalStorage to work-around WebKit storage limitations: on all iOS 5.1+ versions for local-only backups, but only needed on iOS 5.1 for cloud backup. - */ - if (IsAtLeastiOSVersion(@"5.1") && (([backupWebStorageType isEqualToString:@"local"]) || - ([backupWebStorageType isEqualToString:@"cloud"] && !IsAtLeastiOSVersion(@"6.0")))) { - [self registerPlugin:[[CDVLocalStorage alloc] initWithWebView:self.webView] withClassName:NSStringFromClass([CDVLocalStorage class])]; - } - - /* - * This is for iOS 4.x, where you can allow inline