You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2013/03/25 22:53:24 UTC

[1/6] 2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.

Updated Branches:
  refs/heads/2.6.x [created] 37b92ff47


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLibTests/CDVLocalStorageTests.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CDVLocalStorageTests.m b/lib/cordova-ios/CordovaLibTests/CDVLocalStorageTests.m
index 64a1435..675f5ea 100644
--- a/lib/cordova-ios/CordovaLibTests/CDVLocalStorageTests.m
+++ b/lib/cordova-ios/CordovaLibTests/CDVLocalStorageTests.m
@@ -71,9 +71,9 @@
     CDVLocalStorage* localStorage = [self localStorage];
 
     [self waitForConditionName:@"shouldBackup" block:^{
-            [self evalJs:@"localStorage.setItem('foo', 'bar')"];
-            return [localStorage shouldBackup];
-        }];
+        [self evalJs:@"localStorage.setItem('foo', 'bar')"];
+        return [localStorage shouldBackup];
+    }];
     [localStorage backup:[CDVInvokedUrlCommand new]];
     STAssertFalse([localStorage shouldBackup], @"Should have backed up.");
 
@@ -92,8 +92,8 @@
 - (void)testVerifyAndFixDatabaseLocations_noChangeRequired
 {
     NSString* const kBundlePath = @"/bpath";
-    id fakeFileManager = [CDVFakeFileManager managerWithFileExistsBlock:^(NSString * path) {
-            STFail (@"fileExists called.");
+    id fakeFileManager = [CDVFakeFileManager managerWithFileExistsBlock:^(NSString* path) {
+            STFail(@"fileExists called.");
             return NO;
         }];
     NSMutableDictionary* appPlistDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@@ -104,13 +104,13 @@
                                                                           bundlePath:kBundlePath
                                                                          fileManager:fakeFileManager];
 
-    STAssertFalse (modified, @"Should not have applied fix.");
+    STAssertFalse(modified, @"Should not have applied fix.");
 }
 
 - (void)testVerifyAndFixDatabaseLocations_changeRequired1
 {
     NSString* const kBundlePath = @"/bpath";
-    id fakeFileManager = [CDVFakeFileManager managerWithFileExistsBlock:^(NSString * path) {
+    id fakeFileManager = [CDVFakeFileManager managerWithFileExistsBlock:^(NSString* path) {
             return YES;
         }];
     NSMutableDictionary* appPlistDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@@ -120,15 +120,15 @@
                                                                           bundlePath:kBundlePath
                                                                          fileManager:fakeFileManager];
 
-    STAssertTrue (modified, @"Should have applied fix.");
+    STAssertTrue(modified, @"Should have applied fix.");
     NSString* newPath = [appPlistDict objectForKey:@"WebKitLocalStorageDatabasePathPreferenceKey"];
-    STAssertTrue ([@"/bpath/Library/Caches" isEqualToString:newPath], nil);
+    STAssertTrue([@"/bpath/Library/Caches" isEqualToString: newPath], nil);
 }
 
 - (void)testVerifyAndFixDatabaseLocations_changeRequired2
 {
     NSString* const kBundlePath = @"/bpath";
-    id fakeFileManager = [CDVFakeFileManager managerWithFileExistsBlock:^(NSString * path) {
+    id fakeFileManager = [CDVFakeFileManager managerWithFileExistsBlock:^(NSString* path) {
             return NO;
         }];
     NSMutableDictionary* appPlistDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@@ -138,9 +138,9 @@
                                                                           bundlePath:kBundlePath
                                                                          fileManager:fakeFileManager];
 
-    STAssertTrue (modified, @"Should have applied fix.");
+    STAssertTrue(modified, @"Should have applied fix.");
     NSString* newPath = [appPlistDict objectForKey:@"WebDatabaseDirectory"];
-    STAssertTrue ([@"/bpath/Library/WebKit" isEqualToString:newPath], nil);
+    STAssertTrue([@"/bpath/Library/WebKit" isEqualToString: newPath], nil);
 }
 
 @end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLibTests/CDVUserAgentTest.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CDVUserAgentTest.m b/lib/cordova-ios/CordovaLibTests/CDVUserAgentTest.m
index dcbf30a..98659f8 100644
--- a/lib/cordova-ios/CordovaLibTests/CDVUserAgentTest.m
+++ b/lib/cordova-ios/CordovaLibTests/CDVUserAgentTest.m
@@ -82,8 +82,8 @@
 
     NSString* getUserAgentCode = @"navigator.userAgent";
     [self waitForConditionName:@"getting user-agents" block:^{
-            return (BOOL)(rootVc.vc1.webView.request != nil && rootVc.vc2.webView.request != nil);
-        }];
+        return (BOOL)(rootVc.vc1.webView.request != nil && rootVc.vc2.webView.request != nil);
+    }];
     NSString* ua1 = [rootVc.vc1.webView stringByEvaluatingJavaScriptFromString:getUserAgentCode];
     NSString* ua2 = [rootVc.vc2.webView stringByEvaluatingJavaScriptFromString:getUserAgentCode];
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLibTests/CDVWebViewTest.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CDVWebViewTest.m b/lib/cordova-ios/CordovaLibTests/CDVWebViewTest.m
index c0cb173..e22992a 100644
--- a/lib/cordova-ios/CordovaLibTests/CDVWebViewTest.m
+++ b/lib/cordova-ios/CordovaLibTests/CDVWebViewTest.m
@@ -110,8 +110,8 @@
 - (void)waitForPageLoad
 {
     [self waitForConditionName:@"PageLoad" block:^{
-            return [@"true" isEqualToString:[self evalJs:@"window.pageIsLoaded"]];
-        }];
+        return [@"true" isEqualToString :[self evalJs:@"window.pageIsLoaded"]];
+    }];
 }
 
 - (NSString*)evalJs:(NSString*)code

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml b/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
index 512bd1f..5610e5e 100644
--- a/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
+++ b/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
@@ -2,9 +2,9 @@
 <widget>
     <preference name="KeyboardDisplayRequiresUserAction" value="true" />
     <preference name="SuppressesIncrementalRendering" value="false" />
-    <preference name="UIWebViewBounce" value="true" />
+    <preference name="DisallowOverscroll" value="false" />
     <preference name="TopActivityIndicator" value="gray" />
-    <preference name="EnableLocation" value="false" />
+    <preference name="EnableLocation" value="false" /><!-- DEPRECATED -->
     <preference name="EnableViewportScale" value="false" />
     <preference name="AutoHideSplashScreen" value="true" />
     <preference name="ShowSplashScreenSpinner" value="true" />
@@ -13,6 +13,8 @@
     <preference name="MediaPlaybackRequiresUserAction" value="false" />
     <preference name="AllowInlineMediaPlayback" value="false" />
     <preference name="BackupWebStorage" value="cloud" />
+    <preference name="HideKeyboardFormAccessoryBar" value="false" />
+    <preference name="KeyboardShrinksView" value="false" />
 
     <plugins>
         <plugin name="LocalStorage" value="CDVLocalStorage" />

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj b/lib/cordova-ios/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
index f29ac11..219eb53 100644
--- a/lib/cordova-ios/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
+++ b/lib/cordova-ios/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
@@ -41,6 +41,8 @@
 		68A32D7D141030E4006B237C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 686357AE141002F100DF4CF2 /* CoreGraphics.framework */; };
 		68A32D7E141030EB006B237C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 686357AA141002F100DF4CF2 /* UIKit.framework */; };
 		68A32D7F141030F3006B237C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 686357AC141002F100DF4CF2 /* Foundation.framework */; };
+		8220B5C216D541BD00EC3921 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8220B5C116D541BD00EC3921 /* AssetsLibrary.framework */; };
+		8220B5C616D542F500EC3921 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8220B5C116D541BD00EC3921 /* AssetsLibrary.framework */; };
 		EB3B34E9161B5532003DBE7D /* libCordova.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EB3B34E6161B5454003DBE7D /* libCordova.a */; };
 		EB89634A15FE66EA00E12277 /* CDVInvokedUrlCommandTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB89634915FE66EA00E12277 /* CDVInvokedUrlCommandTests.m */; };
 		EB96677216ADBCF500D86CDF /* CDVUserAgentTest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB96677116ADBCF500D86CDF /* CDVUserAgentTest.m */; };
@@ -104,6 +106,7 @@
 		686357D414100AF200DF4CF2 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
 		686357DC14100B1600DF4CF2 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
 		68A32D7414103017006B237C /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; };
+		8220B5C116D541BD00EC3921 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
 		EB37018115D18B2D00BEBC43 /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CordovaLib.xcodeproj; path = ../CordovaLib/CordovaLib.xcodeproj; sourceTree = "<group>"; };
 		EB89634915FE66EA00E12277 /* CDVInvokedUrlCommandTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVInvokedUrlCommandTests.m; sourceTree = "<group>"; };
 		EB96677116ADBCF500D86CDF /* CDVUserAgentTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVUserAgentTest.m; sourceTree = "<group>"; };
@@ -120,6 +123,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				EB3B34E9161B5532003DBE7D /* libCordova.a in Frameworks */,
+				8220B5C216D541BD00EC3921 /* AssetsLibrary.framework in Frameworks */,
 				30F8AE0C152125B6006625B3 /* MobileCoreServices.framework in Frameworks */,
 				30F8AE0515212587006625B3 /* AddressBook.framework in Frameworks */,
 				30F8AE0615212587006625B3 /* AddressBookUI.framework in Frameworks */,
@@ -139,6 +143,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				68A32D7514103017006B237C /* AddressBook.framework in Frameworks */,
+				8220B5C616D542F500EC3921 /* AssetsLibrary.framework in Frameworks */,
 				68A32D7614103078006B237C /* CoreMedia.framework in Frameworks */,
 				68A32D7714103082006B237C /* AudioToolbox.framework in Frameworks */,
 				68A32D781410308B006B237C /* AVFoundation.framework in Frameworks */,
@@ -181,6 +186,7 @@
 			isa = PBXGroup;
 			children = (
 				68A32D7414103017006B237C /* AddressBook.framework */,
+				8220B5C116D541BD00EC3921 /* AssetsLibrary.framework */,
 				686357DC14100B1600DF4CF2 /* CoreMedia.framework */,
 				686357CE14100ADA00DF4CF2 /* AudioToolbox.framework */,
 				686357CF14100ADB00DF4CF2 /* AVFoundation.framework */,

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLibTests/ExifTests.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/ExifTests.h b/lib/cordova-ios/CordovaLibTests/ExifTests.h
new file mode 100644
index 0000000..b46241b
--- /dev/null
+++ b/lib/cordova-ios/CordovaLibTests/ExifTests.h
@@ -0,0 +1,27 @@
+//
+//  ExifTestTests.h
+//  ExifTestTests
+//
+//  Created by Lorin Beer on 2013-03-18.
+//
+//
+
+#import <SenTestingKit/SenTestingKit.h>
+
+#import "../ExifTest/CDVJpegHeaderWriter.h"
+
+#define ARC4RANDOM_MAX 0x100000000
+
+@interface ExifTestTests : SenTestCase {
+    CDVJpegHeaderWriter * testHeaderWriter;
+    NSNumber * testErrorThreshhold;
+}
+
+- (void) testContinuedFractionWithUInt;
+- (void) testContinuedFractionWithUFloat;
+- (void) testContinuedFractionsWorstCase;
+- (void) testFormatHexFromDecimal;
+- (void) testFormatNumberWithLeadingZeroes;
+- (void) testUnsignedRationalToString;
+- (void) testSignedRationalToString;
+@end
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLibTests/ExifTests.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/ExifTests.m b/lib/cordova-ios/CordovaLibTests/ExifTests.m
new file mode 100644
index 0000000..960ac95
--- /dev/null
+++ b/lib/cordova-ios/CordovaLibTests/ExifTests.m
@@ -0,0 +1,155 @@
+//
+//  ExifTestTests.m
+//  ExifTestTests
+//
+//  Created by Lorin Beer on 2013-03-18.
+//
+//
+
+#import <SenTestingKit/SenTestingKit.h>
+
+#import "ExifTestTests.h"
+#import "../ExifTest/CDVJpegHeaderWriter.m"
+
+
+@implementation ExifTestTests
+
+- (void)setUp
+{
+    [super setUp];
+    testHeaderWriter = [[CDVJpegHeaderWriter alloc] init];
+    testErrorThreshhold = [NSNumber numberWithDouble: 0.000001];
+    NSLog(@"%x", ~10+1);
+    
+    
+}
+
+- (void)tearDown
+{
+    // Tear-down code here.
+    
+    [super tearDown];
+}
+
+//==================================================================================================
+// rational approximation of decimal by continued fraction tests
+//==================================================================================================
+
+// tests continued fraction with random int
+- (void)testContinuedFractionWithUInt {
+    NSLog(@"Continued Fraction Test with random int value, numerator should be generated value, denominator should be 1");
+    NSNumber * numerator = @0;
+    NSNumber * denominator = @0;
+    NSNumber * testValue = [NSNumber numberWithInt: abs(arc4random())];
+    [testHeaderWriter decimalToUnsignedRational: testValue
+                  withResultNumerator: &numerator
+                withResultDenominator: &denominator];
+    STAssertEquals([numerator intValue],
+                   [testValue intValue],
+                   @"Numerator did not match");
+    STAssertEquals([denominator intValue],
+                   1,
+                   @"denominator was not one");
+}
+
+// tests continued fraction with random float
+- (void)testContinuedFractionWithUFloat {
+    NSLog(@"Continued Fraction Test with random double value, resulting fraction should be within acceptable error threshhold");
+    NSNumber * threshhold = @0.1;
+    NSNumber * numerator = @0;
+    NSNumber * denominator = @0;
+    NSLog(@"%f",((double)arc4random() / ARC4RANDOM_MAX) * 100.0f);
+    NSNumber * testValue = [NSNumber numberWithDouble:
+                                ((double)arc4random() / ARC4RANDOM_MAX) * 100.0f];
+
+    [testHeaderWriter decimalToUnsignedRational: testValue
+                            withResultNumerator: &numerator
+                          withResultDenominator: &denominator];
+    NSLog(@"%lf, %lf",[testValue doubleValue], [numerator doubleValue]/[denominator doubleValue]);
+
+    STAssertEqualsWithAccuracy([testValue doubleValue],
+                               [numerator doubleValue]/[denominator doubleValue],
+                               [threshhold doubleValue],
+                               @"rational approximation did not meet acceptable error threshhold");
+    
+}
+
+// tests continued fraction in sqrt(2) worst case
+- (void)testContinuedFractionsWorstCase {
+    NSLog(@"Continued Fraction Test with provable worst case ~sqrt(2), resulting fraction should be within acceptable error threshhold");
+    NSNumber * threshhold = @0.1;
+    NSNumber * numerator = @0;
+    NSNumber * denominator = @0;
+    NSNumber * testValue = [NSNumber numberWithDouble: sqrt(2)];
+    [testHeaderWriter decimalToUnsignedRational: testValue
+                            withResultNumerator: &numerator
+                          withResultDenominator: &denominator];
+    STAssertEqualsWithAccuracy([testValue doubleValue],
+                               [numerator doubleValue]/[denominator doubleValue],
+                               [threshhold doubleValue],
+                               @"rational approximation did not meet acceptable error threshhold");
+}
+
+// tests format hex from a decimal
+- (void) testFormatHexFromDecimal {
+    NSNumber * testValue = @1;
+    NSNumber * testPlaces = @8;
+    NSString * result = nil;
+    result = [testHeaderWriter formattedHexStringFromDecimalNumber: testValue
+                                                        withPlaces: testPlaces];
+    // assert not nil
+    STAssertNotNil(result, @"nil renturned from formattedHexStringFromDecimalNumber");
+    // assert correct number of places
+    STAssertEquals([result length], [testPlaces unsignedIntegerValue],
+                   @"returned string to wrong number of places. Should be = %i Was = %i",
+                   [testPlaces intValue],
+                   [result length]);
+    // assert correct hex representation
+    STAssertTrueNoThrow([result isEqualToString:@"00000001"], @"result should be equal to @00000001");
+
+}
+
+// tests format number string with leading zeroes
+- (void) testFormatNumberWithLeadingZeroes {
+    NSString * result = nil;
+    NSNumber * testValue = @8769; // Exif SubIFD Offset Tag
+    NSNumber * testPlaces = @6;
+    result = [testHeaderWriter formatNumberWithLeadingZeroes: testValue
+                                                  withPlaces: testPlaces];
+    STAssertNotNil(result, @"nil renturned from formattedHexStringFromDecimalNumber");
+    STAssertEquals([result length],
+                   [testPlaces unsignedIntegerValue],
+                   @"returned string to wrong number of places. Should be = %i Was = %i",
+                   [testPlaces intValue],
+                   [result length]);
+    // assert correct hex representation
+    STAssertTrueNoThrow([result isEqualToString:@"008769"], @"result was = %@ should be = @008769", result);
+}
+
+- (void) testUnsignedRationalToString {
+    NSString * result = nil;
+    NSNumber * numerator = @1;
+    NSNumber * denominator = @10;
+    result = [testHeaderWriter formatRationalWithNumerator: numerator
+                                           withDenominator: denominator
+                                                  asSigned: FALSE];
+    NSLog(result);
+    STAssertNotNil(result, @"nil returned from testUnsignedRationalToString");
+    STAssertTrueNoThrow([result length]==16, @"returned string with wrong length. Exif rationals are 8 bytes, string has %ld bytes",[result length]/2);
+    STAssertTrueNoThrow([result isEqualToString:@"000000010000000a"], @"result was = %@ should be = @0000000100000010", result);
+}
+
+- (void) testSignedRationalToString {
+    NSString * result = nil;
+    NSNumber * numerator = @-1;
+    NSNumber * denominator = @-10;
+    result = [testHeaderWriter formatRationalWithNumerator: numerator
+                                           withDenominator: denominator
+                                                  asSigned: TRUE];
+    NSLog(result);
+    STAssertNotNil(result, @"nil returned from testSignedRationalToString");
+    STAssertTrueNoThrow([result length]==16, @"returned string with wrong length. Exif rationals are 8 bytes, string has %ld bytes",[result length]/2);
+    STAssertTrueNoThrow([result isEqualToString:@"fffffffffffffff6"], @"result was = %@ should be = @000000FF000000F6", result);
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/RELEASENOTES.md
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/RELEASENOTES.md b/lib/cordova-ios/RELEASENOTES.md
index 843493e..e83c647 100644
--- a/lib/cordova-ios/RELEASENOTES.md
+++ b/lib/cordova-ios/RELEASENOTES.md
@@ -22,7 +22,65 @@
  
  Cordova is a static library that enables developers to include the Cordova API in their iOS application projects easily, and also create new Cordova-based iOS application projects through the command-line.
 
- ### 2.5.0 (20130301) ###
+### 2.6.0 (20130401) ###
+
+* [CB-1547] Scope notifications to WebViews
+* [CB-2461] Distinguish sub-frame from top-level loads in InAppBrowser.
+* [CB-2523] Add setting to shrink webview when keyboard pops up
+* [CB-2220] Fix splashscreen origin when status bar is present
+* [CB-2220] Size the splash screen in the same way as the launch image
+* [CB-2389] Fix page load detection for late-loaded iframes
+* [CB-2220] Fix splash screen positioning when image is the size of device
+* [CB-2631] Fix crash when bad url given to FT.upload
+* [CB-2652] Make FileReader.readAs*() functions run on a background thread
+* [CB-2633] Add FileReader.readAsBinaryString()
+* [CB-2308] Correctly delegate to CDVInAppBrowser webView:didFailLoadWithError
+* [CB-2308] [ios] Report errors when InAppBrowser fails to load page
+* [CB-2527] Update iPad splash images to correct sizes
+* [CB-1452] Media position incorrect after being set beyond duration
+* [CB-2436] Wrong splashscreen is displayed when UILaunchImageFile is set
+* [CB-2634] Copy www fails w spaces in filenames
+* [CB-2618] xcode build from Network Drive Fails
+* [CB-2638] Fix iOS project warnings on Retina imgs
+* [CB-2491] Deprecate current Connection cell setting
+* [CB-2674] Add prompt to Notification API for iOS
+* [CB-2691] Splashscreen should block user interaction
+* [CB-2502] Fixing CDVViewController.commandDelegate property declaration
+* [CB-1933] Changed button labels to an array.
+* [CB-1688] Added a camera direction option.
+* [CB-2732] Only set camera device when allowed.
+* [CB-2530] [CB-2239] Multipart plugin result
+* [CB-2605] icon-72@2x.png not included in xcode project template
+* [CB-2545] Deprecate "EnableLocation" Project Setting - use the "onload" attribute of the <plugin> element
+* [CB-2384] Add new iOS Project Setting to suppress the form accessory bar above the keyboard
+* [CB-2195] Remove deprecated - iOS - BackupWebStorage Cordova.plist property change from boolean to string
+* [CB-2194] Remove deprecated - iOS - CDVCommandDelegate registerPlugin method
+* [CB-2699] Bug in dynamic loading of a plugin at CDVViewController's registerPlugin method
+* [CB-2384] Re-fix - Add new iOS Project Setting to suppress the form accessory bar above the keyboard
+* [CB-2759] Update www/ Application for iOS
+* [CB-2672] InAppBrowserBug fixed (not reporting actual URL after redirect)
+* [CB-861] Header support for FileTransfer download
+* Add a define that turns on logging of exec() bridge
+* Sort preferences in project template.
+* Add KeyboardShrinksView preference to project template
+* Revert accidentaly change in PluginResult that broke threading.
+* Remove NSLogs accidentally checked in.
+* Use noCopy versions of NSString init in Base64 code.
+* Add an associatedObject field to CDVPluginResult.
+* Uncrustified with v0.60 of the tool (up from 0.59).
+* Make sure version of uncrustify is correct in the pre-commit hook
+* Remove some unnecessary argument checks in CDVNotification
+* Implement readAsArrayBuffer
+* Changed UIWebViewBounce to DisallowOverscroll.
+* Retain cycle fix
+* Fixed static analyzer issues.
+* Interim .js for [CB-52] FileTransfer Basic Auth
+* Added KeyboardShrinksView preference to CordovaLibTest config.xml
+* Added \__CORDOVA_IOS\__ macro
+
+< br />
+
+### 2.5.0 (20130301) ###
 
 * [CB-2395] Fix CDVViewController UserAgent lock
 * [CB-2207] Use a custom script for www/ copying.
@@ -76,7 +134,7 @@
 
 <br />
 
- ### 2.4.0 (20130205) ###
+### 2.4.0 (20130205) ###
 
 * Make cordova_plist_to_config_xml able to handle binary plist files
 * Ran splashscreen images through ImageOptim.
@@ -129,7 +187,7 @@
 
 <br />
 
- ### 2.3.0 (20130107) ###
+### 2.3.0 (20130107) ###
 
 * [CB-1550] iOS build, debug, emulate scripts should check xcode version
 * [CB-1669] Issue an error when media.startRecord() is failing.
@@ -191,7 +249,7 @@
 
 <br />
 
- ### 2.2.0 (20121031) ###
+### 2.2.0 (20121031) ###
 
 * [CB-622] FileTransfer interface should provide progress monitoring
 * [CB-622] Progress events for downloads

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj b/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj
index 1d9c170..f5ed342 100755
--- a/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj
+++ b/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj
@@ -40,6 +40,7 @@
 		30A0434814DC770100060A13 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30A0434314DC770100060A13 /* Localizable.strings */; };
 		30A0434914DC770100060A13 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30A0434614DC770100060A13 /* Localizable.strings */; };
 		30E5649213A7FCAF007403D8 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30E5649113A7FCAF007403D8 /* CoreMedia.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+		30FC414916E50CA1004E6F35 /* icon-72@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 30FC414816E50CA1004E6F35 /* icon-72@2x.png */; };
 		5B1594DD16A7569C00FEF299 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B1594DC16A7569C00FEF299 /* AssetsLibrary.framework */; };
 		D4A0D8761607E02300AEF8BB /* Default-568h@2x~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = D4A0D8751607E02300AEF8BB /* Default-568h@2x~iphone.png */; };
 		F840E1F1165FE0F500CFE078 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = F840E1F0165FE0F500CFE078 /* config.xml */; };
@@ -100,6 +101,7 @@
 		30A0434414DC770100060A13 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Localizable.strings; sourceTree = "<group>"; };
 		30A0434714DC770100060A13 /* se */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = se; path = Localizable.strings; sourceTree = "<group>"; };
 		30E5649113A7FCAF007403D8 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
+		30FC414816E50CA1004E6F35 /* icon-72@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-72@2x.png"; sourceTree = "<group>"; };
 		32CA4F630368D1EE00C91783 /* __TESTING__-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "__TESTING__-Prefix.pch"; sourceTree = "<group>"; };
 		5B1594DC16A7569C00FEF299 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
 		8D1107310486CEB800E47090 /* __TESTING__-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "__TESTING__-Info.plist"; path = "../__TESTING__-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = "<group>"; };
@@ -254,6 +256,7 @@
 		308D052D1370CCF300D202BF /* icons */ = {
 			isa = PBXGroup;
 			children = (
+				30FC414816E50CA1004E6F35 /* icon-72@2x.png */,
 				308D052E1370CCF300D202BF /* icon-72.png */,
 				308D052F1370CCF300D202BF /* icon.png */,
 				308D05301370CCF300D202BF /* icon@2x.png */,
@@ -382,6 +385,7 @@
 				3088BBC1154F3926009F9C59 /* Default@2x~iphone.png in Resources */,
 				3088BBC2154F3926009F9C59 /* Default~iphone.png in Resources */,
 				D4A0D8761607E02300AEF8BB /* Default-568h@2x~iphone.png in Resources */,
+				30FC414916E50CA1004E6F35 /* icon-72@2x.png in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -400,7 +404,7 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "SRC_DIR=\"www\"\nDST_DIR=\"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/www\"\nCOPY_HIDDEN=\n\nif [[ ! -e \"$SRC_DIR\" ]]; then\n  echo \"Path does not exist: $SRC_DIR\"\n  exit 1\nfi\n\nif [[ -n $COPY_HIDDEN ]]; then\n  alias do_find='find \"$SRC_DIR\"'\nelse\n  alias do_find='find \"$SRC_DIR\" -name \".*\" -prune -o'\nfi\n\ntime (\n# Code signing files must be removed or else there are\n# resource signing errors.\nrm -rf \"$DST_DIR\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/_CodeSignature\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/PkgInfo\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/embedded.mobileprovision\"\n\n# Directories\nfor p in $(do_find -type d -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  mkdir \"$DST_DIR$subpath\" || exit 1\ndone\n\n# Symlinks\nfor p in $(do_find -type l -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  cp -a \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" || exit 2\ndone\n\n# Files\nfor p in $(do_find -type f -print); do\n 
  subpath=\"${p#$SRC_DIR}\"\n  if ! ln \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\"; then\n    cp -a \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" || exit 3\n  fi\ndone\n\n)";
+			shellScript = "SRC_DIR=\"www\"\nDST_DIR=\"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/www\"\nCOPY_HIDDEN=\nORIG_IFS=$IFS\nIFS=$(echo -en \"\\n\\b\")\n\nif [[ ! -e \"$SRC_DIR\" ]]; then\n  echo \"Path does not exist: $SRC_DIR\"\n  exit 1\nfi\n\nif [[ -n $COPY_HIDDEN ]]; then\n  alias do_find='find \"$SRC_DIR\"'\nelse\n  alias do_find='find \"$SRC_DIR\" -name \".*\" -prune -o'\nfi\n\ntime (\n# Code signing files must be removed or else there are\n# resource signing errors.\nrm -rf \"$DST_DIR\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/_CodeSignature\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/PkgInfo\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/embedded.mobileprovision\"\n\n# Directories\nfor p in $(do_find -type d -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  mkdir \"$DST_DIR$subpath\" || exit 1\ndone\n\n# Symlinks\nfor p in $(do_find -type l -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  rsync -a \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" || exit 2\ndone\n\n# Fi
 les\nfor p in $(do_find -type f -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  if ! ln \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" 2>/dev/null; then\n    rsync -a \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" || exit 3\n  fi\ndone\n\n)\nIFS=$ORIG_IFS";
 		};
 /* End PBXShellScriptBuildPhase section */
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m b/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
index 318f793..623ad8e 100644
--- a/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
+++ b/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
@@ -45,7 +45,7 @@
 
     int cacheSizeMemory = 8 * 1024 * 1024; // 8MB
     int cacheSizeDisk = 32 * 1024 * 1024; // 32MB
-    NSURLCache* sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"];
+    NSURLCache* sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
     [NSURLCache setSharedURLCache:sharedCache];
 
     self = [super init];
@@ -99,8 +99,8 @@
 }
 
 // repost the localnotification using the default NSNotificationCenter so multiple plugins may respond
-- (void)           application:(UIApplication*)application
-   didReceiveLocalNotification:(UILocalNotification*)notification
+- (void)            application:(UIApplication*)application
+    didReceiveLocalNotification:(UILocalNotification*)notification
 {
     // re-post ( broadcast )
     [[NSNotificationCenter defaultCenter] postNotificationName:CDVLocalNotification object:notification];

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-568h@2x~iphone.png
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-568h@2x~iphone.png b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-568h@2x~iphone.png
index d14b55b..10ed683 100644
Binary files a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-568h@2x~iphone.png and b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-568h@2x~iphone.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape@2x~ipad.png
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape@2x~ipad.png b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape@2x~ipad.png
index 72eb605..9f1e14f 100644
Binary files a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape@2x~ipad.png and b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape@2x~ipad.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape~ipad.png
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape~ipad.png b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape~ipad.png
index 30e8587..93a8d74 100644
Binary files a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape~ipad.png and b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape~ipad.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait@2x~ipad.png
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait@2x~ipad.png b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait@2x~ipad.png
index 435bbec..6d1c5d3 100644
Binary files a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait@2x~ipad.png and b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait@2x~ipad.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait~ipad.png
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait~ipad.png b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait~ipad.png
index 5e9786a..30e0a3d 100644
Binary files a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait~ipad.png and b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait~ipad.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml b/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
index 64e7163..8889726 100644
--- a/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
+++ b/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
@@ -20,19 +20,21 @@
 #
 -->
 <widget>
-    <preference name="KeyboardDisplayRequiresUserAction" value="true" />
-    <preference name="SuppressesIncrementalRendering" value="false" />
-    <preference name="UIWebViewBounce" value="true" />
-    <preference name="TopActivityIndicator" value="gray" />
-    <preference name="EnableLocation" value="false" />
-    <preference name="EnableViewportScale" value="false" />
+    <preference name="AllowInlineMediaPlayback" value="false" />
     <preference name="AutoHideSplashScreen" value="true" />
-    <preference name="ShowSplashScreenSpinner" value="true" />
+    <preference name="BackupWebStorage" value="cloud" />
+    <preference name="DisallowOverscroll" value="false" />
+    <preference name="EnableLocation" value="false" /><!-- DEPRECATED -->
+    <preference name="EnableViewportScale" value="false" />
     <preference name="FadeSplashScreen" value="true" />
     <preference name="FadeSplashScreenDuration" value=".25" />
+    <preference name="HideKeyboardFormAccessoryBar" value="false" />
+    <preference name="KeyboardDisplayRequiresUserAction" value="true" />
+    <preference name="KeyboardShrinksView" value="false" />
     <preference name="MediaPlaybackRequiresUserAction" value="false" />
-    <preference name="AllowInlineMediaPlayback" value="false" />
-    <preference name="BackupWebStorage" value="cloud" />
+    <preference name="ShowSplashScreenSpinner" value="true" />
+    <preference name="SuppressesIncrementalRendering" value="false" />
+    <preference name="TopActivityIndicator" value="gray" />
 
     <content src="index.html" />
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/bin/templates/project/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/www/index.html b/lib/cordova-ios/bin/templates/project/www/index.html
index 6374050..8bc9055 100644
--- a/lib/cordova-ios/bin/templates/project/www/index.html
+++ b/lib/cordova-ios/bin/templates/project/www/index.html
@@ -19,7 +19,7 @@
 -->
 <html>
     <head>
-        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+        <meta charset="utf-8" />
         <meta name="format-detection" content="telephone=no" />
         <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
         <link rel="stylesheet" type="text/css" href="css/index.css" />

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/guides/Cordova Plugin Upgrade Guide.md
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/guides/Cordova Plugin Upgrade Guide.md b/lib/cordova-ios/guides/Cordova Plugin Upgrade Guide.md
index 869e4f4..7a03bc4 100644
--- a/lib/cordova-ios/guides/Cordova Plugin Upgrade Guide.md	
+++ b/lib/cordova-ios/guides/Cordova Plugin Upgrade Guide.md	
@@ -22,6 +22,12 @@
 
 This document is for developers who need to upgrade their Cordova  plugins to a newer Cordova version. Starting with Cordova 1.5.0, some classes have been renamed, which will require the plugin to be upgraded. Make sure your project itself has been upgraded using the [Cordova iOS Upgrading Guide](http://cordova.apache.org/docs/en/edge/guide_upgrading_ios_index.md.html#Upgrading%20Cordova%20iOS) document.
 
+## Upgrading older Cordova plugins to 2.6.0 ##
+
+1. **Install** Cordova 2.6.0
+2. Follow the **"Upgrading older Cordova plugins to 2.5.0"** section, if necessary
+3. The **registerPlugin** method of the **commandDelegate** property of plugin, which was deprecated, has been **removed**. Use the **registerPlugin** method directly from the **viewController** property of the plugin.
+
 ## Upgrading older Cordova plugins to 2.5.0 ##
 
 1. **Install** Cordova 2.5.0

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/hooks/pre-commit
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/hooks/pre-commit b/lib/cordova-ios/hooks/pre-commit
index 7a420c9..80550f1 100755
--- a/lib/cordova-ios/hooks/pre-commit
+++ b/lib/cordova-ios/hooks/pre-commit
@@ -20,6 +20,12 @@
 
 # Redirect output to stderr.
 exec 1>&2
+test $SKIP_UNCRUSTIFY && exit 0
+
+if [[ "$(uncrustify --version | cut -d' ' -f2)" != 0.60 ]]; then
+  echo "Please install version 0.60 of uncrustify."
+  exit 1
+fi
 
 RET=0
 files=$(bin/uncrustify.sh --filter $(git diff --cached --name-only))

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index d7bfb17..a749826 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cordova",
-  "version": "2.5.5",
+  "version": "2.6.0",
   "preferGlobal": "true",
   "description": "Cordova command line interface tool",
   "main": "cordova",


[6/6] git commit: 2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.

Posted by fi...@apache.org.
2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.


Project: http://git-wip-us.apache.org/repos/asf/cordova-cli/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-cli/commit/37b92ff4
Tree: http://git-wip-us.apache.org/repos/asf/cordova-cli/tree/37b92ff4
Diff: http://git-wip-us.apache.org/repos/asf/cordova-cli/diff/37b92ff4

Branch: refs/heads/2.6.x
Commit: 37b92ff47d532490f67a635e0f3b011c03be8eb1
Parents: 50e8e4e
Author: Fil Maj <ma...@gmail.com>
Authored: Mon Mar 25 14:52:11 2013 -0700
Committer: Fil Maj <ma...@gmail.com>
Committed: Mon Mar 25 14:52:11 2013 -0700

----------------------------------------------------------------------
 .gitignore                                         |    2 +-
 lib/cordova-android/VERSION                        |    2 +-
 lib/cordova-android/bin/create                     |   16 +-
 .../bin/templates/cordova/appinfo.jar              |  Bin 1574 -> 1574 bytes
 .../bin/templates/project/assets/www/index.html    |    2 +-
 lib/cordova-android/bin/update                     |  139 ++++
 lib/cordova-android/bin/update.bat                 |   32 +
 lib/cordova-android/bin/update.js                  |  193 ++++++
 .../framework/assets/js/cordova.android.js         |  474 +++++++++++---
 .../framework/assets/www/index.html                |    2 +-
 .../src/org/apache/cordova/AudioHandler.java       |    6 +-
 .../src/org/apache/cordova/AudioPlayer.java        |   15 +-
 .../src/org/apache/cordova/CameraLauncher.java     |   16 +-
 .../framework/src/org/apache/cordova/Capture.java  |   14 +-
 .../framework/src/org/apache/cordova/Config.java   |   10 +
 .../src/org/apache/cordova/CordovaArgs.java        |    5 +-
 .../org/apache/cordova/CordovaChromeClient.java    |    2 +-
 .../src/org/apache/cordova/CordovaWebView.java     |  124 +---
 .../org/apache/cordova/CordovaWebViewClient.java   |  103 ++--
 .../framework/src/org/apache/cordova/Device.java   |    2 +-
 .../framework/src/org/apache/cordova/DroidGap.java |   13 +-
 .../src/org/apache/cordova/FileHelper.java         |  142 ++++
 .../src/org/apache/cordova/FileTransfer.java       |   81 ++-
 .../src/org/apache/cordova/FileUtils.java          |  350 ++++-------
 .../src/org/apache/cordova/GeoBroker.java          |    2 +-
 .../cordova/IceCreamCordovaWebViewClient.java      |   16 +-
 .../src/org/apache/cordova/InAppBrowser.java       |  135 ++++-
 .../src/org/apache/cordova/JSONUtils.java          |   24 +
 .../org/apache/cordova/NativeToJsMessageQueue.java |   13 +-
 .../src/org/apache/cordova/Notification.java       |  167 ++++-
 .../org/apache/cordova/api/CallbackContext.java    |    9 +
 .../src/org/apache/cordova/api/CordovaPlugin.java  |   18 +-
 .../src/org/apache/cordova/api/PluginManager.java  |   23 +-
 .../src/org/apache/cordova/api/PluginResult.java   |   11 +-
 lib/cordova-blackberry/bin/create                  |   21 +-
 .../bin/templates/project/www/index.html           |    4 +-
 .../ext/src/org/apache/cordova/util/FileUtils.java |   33 +-
 .../javascript/cordova.blackberry.js               |  365 +++++++++--
 .../CordovaLib/Classes/CDVAvailability.h           |   19 +-
 lib/cordova-ios/CordovaLib/Classes/CDVCamera.h     |    4 +-
 lib/cordova-ios/CordovaLib/Classes/CDVCamera.m     |   53 ++
 lib/cordova-ios/CordovaLib/Classes/CDVCapture.m    |   10 +-
 .../CordovaLib/Classes/CDVCommandDelegate.h        |    1 -
 .../CordovaLib/Classes/CDVCommandDelegateImpl.m    |   22 +-
 .../CordovaLib/Classes/CDVCommandQueue.h           |    8 +-
 .../CordovaLib/Classes/CDVCommandQueue.m           |   17 +-
 .../CordovaLib/Classes/CDVConfigParser.m           |    2 +-
 lib/cordova-ios/CordovaLib/Classes/CDVConnection.m |   12 +-
 lib/cordova-ios/CordovaLib/Classes/CDVContact.m    |   32 +-
 lib/cordova-ios/CordovaLib/Classes/CDVContacts.h   |   14 +-
 lib/cordova-ios/CordovaLib/Classes/CDVContacts.m   |  490 +++++++-------
 lib/cordova-ios/CordovaLib/Classes/CDVEcho.m       |    7 +
 lib/cordova-ios/CordovaLib/Classes/CDVExif.h       |   43 ++
 lib/cordova-ios/CordovaLib/Classes/CDVFile.h       |    2 +
 lib/cordova-ios/CordovaLib/Classes/CDVFile.m       |  285 +++++----
 .../CordovaLib/Classes/CDVFileTransfer.h           |    8 +-
 .../CordovaLib/Classes/CDVFileTransfer.m           |   51 +-
 .../CordovaLib/Classes/CDVGlobalization.m          |   62 +-
 .../CordovaLib/Classes/CDVInAppBrowser.h           |    3 +
 .../CordovaLib/Classes/CDVInAppBrowser.m           |   41 +-
 .../CordovaLib/Classes/CDVInvokedUrlCommand.h      |    6 +-
 .../CordovaLib/Classes/CDVJpegHeaderWriter.h       |   60 ++
 .../CordovaLib/Classes/CDVJpegHeaderWriter.m       |  472 +++++++++++++
 .../CordovaLib/Classes/CDVLocalStorage.h           |    4 +-
 .../CordovaLib/Classes/CDVLocalStorage.m           |   36 +-
 lib/cordova-ios/CordovaLib/Classes/CDVLocation.h   |    8 +-
 lib/cordova-ios/CordovaLib/Classes/CDVLocation.m   |   24 +-
 .../CordovaLib/Classes/CDVNotification.h           |    1 +
 .../CordovaLib/Classes/CDVNotification.m           |   89 ++-
 lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h     |    8 +-
 lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m     |    9 +-
 .../CordovaLib/Classes/CDVPluginResult.h           |    7 +
 .../CordovaLib/Classes/CDVPluginResult.m           |   57 ++-
 .../CordovaLib/Classes/CDVReachability.m           |   28 +-
 lib/cordova-ios/CordovaLib/Classes/CDVSound.m      |   21 +-
 .../CordovaLib/Classes/CDVSplashScreen.h           |    3 +-
 .../CordovaLib/Classes/CDVSplashScreen.m           |  176 +++--
 .../CordovaLib/Classes/CDVURLProtocol.m            |   12 +-
 .../CordovaLib/Classes/CDVUserAgentUtil.m          |    2 +-
 .../CordovaLib/Classes/CDVViewController.h         |   10 +-
 .../CordovaLib/Classes/CDVViewController.m         |  140 ++++-
 .../CordovaLib/Classes/CDVWebViewDelegate.m        |   30 +-
 lib/cordova-ios/CordovaLib/Classes/NSData+Base64.m |   19 +-
 .../CordovaLib/Classes/NSDictionary+Extensions.m   |    2 +-
 .../CordovaLib.xcodeproj/project.pbxproj           |   14 +
 lib/cordova-ios/CordovaLib/VERSION                 |    2 +-
 lib/cordova-ios/CordovaLib/cordova.ios.js          |  521 ++++++++++++---
 .../CordovaLibTests/CDVFakeFileManager.h           |    2 +-
 .../CordovaLibTests/CDVFileTransferTests.m         |   12 +-
 .../CordovaLibTests/CDVLocalStorageTests.m         |   24 +-
 lib/cordova-ios/CordovaLibTests/CDVUserAgentTest.m |    4 +-
 lib/cordova-ios/CordovaLibTests/CDVWebViewTest.m   |    4 +-
 .../CordovaLibTests/CordovaLibApp/config.xml       |    6 +-
 .../CordovaTests.xcodeproj/project.pbxproj         |    6 +
 lib/cordova-ios/CordovaLibTests/ExifTests.h        |   27 +
 lib/cordova-ios/CordovaLibTests/ExifTests.m        |  155 +++++
 lib/cordova-ios/RELEASENOTES.md                    |   66 ++-
 .../project/__TESTING__.xcodeproj/project.pbxproj  |    6 +-
 .../project/__TESTING__/Classes/AppDelegate.m      |    6 +-
 .../Resources/splash/Default-568h@2x~iphone.png    |  Bin 29944 -> 34225 bytes
 .../Resources/splash/Default-Landscape@2x~ipad.png |  Bin 75573 -> 77300 bytes
 .../Resources/splash/Default-Landscape~ipad.png    |  Bin 33147 -> 34935 bytes
 .../Resources/splash/Default-Portrait@2x~ipad.png  |  Bin 74097 -> 76546 bytes
 .../Resources/splash/Default-Portrait~ipad.png     |  Bin 32666 -> 34278 bytes
 .../bin/templates/project/__TESTING__/config.xml   |   20 +-
 .../bin/templates/project/www/index.html           |    2 +-
 .../guides/Cordova Plugin Upgrade Guide.md         |    6 +
 lib/cordova-ios/hooks/pre-commit                   |    6 +
 package.json                                       |    2 +-
 109 files changed, 4423 insertions(+), 1464 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 3abe651..b31c8bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,8 +6,8 @@ spec/fixtures/projects/native
 spec/fixtures/projects/cordova
 lib/cordova-android/framework/bin
 lib/cordova-android/framework/gen
+lib/cordova-android/framework/local.properties
 .idea/*
 spec/fixtures/*
 .gitcore
 *.jar
-lib/*

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-android/VERSION b/lib/cordova-android/VERSION
index 437459c..f47de85 100644
--- a/lib/cordova-android/VERSION
+++ b/lib/cordova-android/VERSION
@@ -1 +1 @@
-2.5.0
+2.6.0rc1

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/bin/create
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/create b/lib/cordova-android/bin/create
index ea214ac..2eae82b 100755
--- a/lib/cordova-android/bin/create
+++ b/lib/cordova-android/bin/create
@@ -59,10 +59,10 @@ function on_exit {
 }
 
 function createAppInfoJar {
-    (cd "$BUILD_PATH"/bin/templates/cordova/ApplicationInfo &&
-     javac ApplicationInfo.java &&
-     jar -cfe ../appinfo.jar ApplicationInfo ApplicationInfo.class
-    )
+    pushd "$BUILD_PATH"/bin/templates/cordova/ApplicationInfo > /dev/null
+    javac ApplicationInfo.java
+    jar -cfe ../appinfo.jar ApplicationInfo ApplicationInfo.class
+    popd > /dev/null
 }
 
 function on_error {
@@ -108,7 +108,7 @@ fi
 # if this a distribution release no need to build a jar
 if [ ! -e "$BUILD_PATH"/cordova-$VERSION.jar ] && [ -d "$BUILD_PATH"/framework ]
 then
-# update the cordova-android framework for the desired target
+    # update the cordova-android framework for the desired target
     "$ANDROID_BIN" update project --target $TARGET --path "$BUILD_PATH"/framework &> /dev/null
 
     if [ ! -e "$BUILD_PATH"/framework/libs/commons-codec-1.7.jar ]; then
@@ -121,8 +121,10 @@ then
         rm commons-codec-1.7-bin.zip && rm -rf commons-codec-1.7
     fi
 
-# compile cordova.js and cordova.jar
-    (cd "$BUILD_PATH"/framework && ant jar &> /dev/null )
+    # compile cordova.js and cordova.jar
+    pushd "$BUILD_PATH"/framework > /dev/null
+    ant jar > /dev/null
+    popd > /dev/null
 fi
 
 # create new android project

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/bin/templates/cordova/appinfo.jar
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/appinfo.jar b/lib/cordova-android/bin/templates/cordova/appinfo.jar
index fff4d0f..7f8ac60 100644
Binary files a/lib/cordova-android/bin/templates/cordova/appinfo.jar and b/lib/cordova-android/bin/templates/cordova/appinfo.jar differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/bin/templates/project/assets/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/project/assets/www/index.html b/lib/cordova-android/bin/templates/project/assets/www/index.html
index b8c0535..5596f62 100644
--- a/lib/cordova-android/bin/templates/project/assets/www/index.html
+++ b/lib/cordova-android/bin/templates/project/assets/www/index.html
@@ -33,7 +33,7 @@
                 <p class="event received">Device is Ready</p>
             </div>
         </div>
-        <script type="text/javascript" src="cordova-2.5.0.js"></script>
+        <script type="text/javascript" src="cordova-2.6.0rc1.js"></script>
         <script type="text/javascript" src="js/index.js"></script>
         <script type="text/javascript">
             app.initialize();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/bin/update
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/update b/lib/cordova-android/bin/update
new file mode 100755
index 0000000..0e86886
--- /dev/null
+++ b/lib/cordova-android/bin/update
@@ -0,0 +1,139 @@
+#! /bin/bash
+#       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.
+#
+# update a cordova/android project's command line tools
+# 
+# USAGE
+#   ./update [path]
+#
+
+set -e
+
+if [ -z "$1" ] || [ "$1" == "-h" ]
+then
+    echo 'usage: update path'
+    echo "Make sure the Android SDK tools folder is in your PATH!"
+    exit 0
+fi
+
+BUILD_PATH="$( cd "$( dirname "$0" )/.." && pwd )"
+VERSION=$(cat "$BUILD_PATH"/VERSION)
+
+PROJECT_PATH="${1:-'./example'}"
+
+if [ ! -d "$PROJECT_PATH" ]
+then
+    echo "The project path has to exist for it to be updated"
+    exit 0
+fi
+
+
+# cleanup after exit and/or on error
+function on_exit {
+    if [ -f "$BUILD_PATH"/framework/assets/www/cordova-$VERSION.js ]
+    then
+        rm "$BUILD_PATH"/framework/assets/www/cordova-$VERSION.js
+    fi
+    if [ -f "$BUILD_PATH"/framework/cordova-$VERSION.jar ]
+    then
+        rm "$BUILD_PATH"/framework/cordova-$VERSION.jar
+    fi
+}
+
+function createAppInfoJar {
+    (cd "$BUILD_PATH"/bin/templates/cordova/ApplicationInfo &&
+     javac ApplicationInfo.java &&
+     jar -cfe ../appinfo.jar ApplicationInfo ApplicationInfo.class
+    )
+}
+
+function on_error {
+    echo "An unexpected error occurred: $previous_command exited with $?"
+    echo "Deleting project..."
+    [ -d "$PROJECT_PATH" ] && rm -rf "$PROJECT_PATH"
+    exit 1
+}
+
+function replace {
+    local pattern=$1
+    local filename=$2
+    # Mac OS X requires -i argument
+    if [[ "$OSTYPE" =~ "darwin" ]]
+    then
+        /usr/bin/sed -i '' -e $pattern "$filename"
+    elif [[ "$OSTYPE" =~ "linux" ]]
+    then
+        /bin/sed -i -e $pattern "$filename"
+    fi
+}
+
+# we do not want the script to silently fail
+trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG
+trap on_error ERR
+trap on_exit EXIT
+
+ANDROID_BIN="${ANDROID_BIN:=$( which android )}"
+
+TARGET=$("$ANDROID_BIN" list targets | grep id: | tail -1 | cut -f 2 -d ' ' )
+API_LEVEL=$("$ANDROID_BIN" list target | grep "API level:" | tail -n 1 | cut -f 2 -d ':' | tr -d ' ')
+
+# check that build targets exist
+if [ -z "$TARGET" ] || [ -z "$API_LEVEL" ]
+then
+    echo "No Android Targets are installed. Please install at least one via the android SDK"
+    exit 1
+fi
+
+# if this a distribution release no need to build a jar
+if [ ! -e "$BUILD_PATH"/cordova-$VERSION.jar ] && [ -d "$BUILD_PATH"/framework ]
+then
+# update the cordova-android framework for the desired target
+    "$ANDROID_BIN" update project --target $TARGET --path "$BUILD_PATH"/framework &> /dev/null
+
+    if [ ! -e "$BUILD_PATH"/framework/libs/commons-codec-1.7.jar ]; then
+        # Use curl to get the jar (TODO: Support Apache Mirrors)
+        curl -OL http://archive.apache.org/dist/commons/codec/binaries/commons-codec-1.7-bin.zip &> /dev/null
+        unzip commons-codec-1.7-bin.zip &> /dev/null
+        mkdir -p "$BUILD_PATH"/framework/libs
+        cp commons-codec-1.7/commons-codec-1.7.jar "$BUILD_PATH"/framework/libs
+        # cleanup yo
+        rm commons-codec-1.7-bin.zip && rm -rf commons-codec-1.7
+    fi
+
+# compile cordova.js and cordova.jar
+    (cd "$BUILD_PATH"/framework && ant jar &> /dev/null )
+fi
+
+# copy cordova.js, cordova.jar and res/xml
+if [ -d "$BUILD_PATH"/framework ]
+then
+    cp "$BUILD_PATH"/framework/assets/www/cordova-$VERSION.js "$PROJECT_PATH"/assets/www/cordova-$VERSION.js
+    cp "$BUILD_PATH"/framework/cordova-$VERSION.jar "$PROJECT_PATH"/libs/cordova-$VERSION.jar
+else
+    cp "$BUILD_PATH"/cordova-$VERSION.js "$PROJECT_PATH"/assets/www/cordova-$VERSION.js
+    cp "$BUILD_PATH"/cordova-$VERSION.jar "$PROJECT_PATH"/libs/cordova-$VERSION.jar
+fi
+
+# creating cordova folder and copying run/build/log/launch scripts
+cp "$BUILD_PATH"/bin/templates/cordova/appinfo.jar "$PROJECT_PATH"/cordova/appinfo.jar
+cp "$BUILD_PATH"/bin/templates/cordova/cordova "$PROJECT_PATH"/cordova/cordova
+cp "$BUILD_PATH"/bin/templates/cordova/build "$PROJECT_PATH"/cordova/build
+cp "$BUILD_PATH"/bin/templates/cordova/release "$PROJECT_PATH"/cordova/release
+cp "$BUILD_PATH"/bin/templates/cordova/clean "$PROJECT_PATH"/cordova/clean
+cp "$BUILD_PATH"/bin/templates/cordova/log "$PROJECT_PATH"/cordova/log
+cp "$BUILD_PATH"/bin/templates/cordova/run "$PROJECT_PATH"/cordova/run

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/bin/update.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/update.bat b/lib/cordova-android/bin/update.bat
new file mode 100644
index 0000000..a61fd26
--- /dev/null
+++ b/lib/cordova-android/bin/update.bat
@@ -0,0 +1,32 @@
+:: 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.
+
+@ECHO OFF
+IF NOT DEFINED JAVA_HOME GOTO MISSING
+FOR %%X in (java.exe javac.exe ant.bat android.bat) do (
+    SET FOUND=%%~$PATH:X
+    IF NOT DEFINED FOUND GOTO MISSING
+)
+cscript "%~dp0\update.js" %*
+GOTO END
+:MISSING
+ECHO Missing one of the following:
+ECHO JDK: http://java.oracle.com
+ECHO Android SDK: http://developer.android.com
+ECHO Apache ant: http://ant.apache.org
+EXIT /B 1
+:END

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/bin/update.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/update.js b/lib/cordova-android/bin/update.js
new file mode 100644
index 0000000..244dcc1
--- /dev/null
+++ b/lib/cordova-android/bin/update.js
@@ -0,0 +1,193 @@
+/*
+       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.
+*/
+
+/*
+ * create a cordova/android project
+ *
+ * USAGE
+ *  ./update [path]
+ */
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject');
+
+function read(filename) {
+    var fso=WScript.CreateObject("Scripting.FileSystemObject");
+    var f=fso.OpenTextFile(filename, 1);
+    var s=f.ReadAll();
+    f.Close();
+    return s;
+}
+
+function checkTargets(targets) {
+    if(!targets) {
+        WScript.Echo("You do not have any android targets setup. Please create at least one target with the `android` command");
+        WScript.Quit(69);
+    }
+}
+
+function setTarget() {
+    var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/id:\s\d+/g);
+    checkTargets(targets);
+    return targets[targets.length - 1].replace(/id: /, ""); // TODO: give users the option to set their target 
+}
+
+function setApiLevel() {
+    var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/API level:\s\d+/g);
+    checkTargets(targets);
+    return targets[targets.length - 1].replace(/API level: /, "");
+}
+
+function write(filename, contents) {
+    var fso=WScript.CreateObject("Scripting.FileSystemObject");
+    var f=fso.OpenTextFile(filename, 2, true);
+    f.Write(contents);
+    f.Close();
+}
+
+function replaceInFile(filename, regexp, replacement) {
+    write(filename, read(filename).replace(regexp, replacement));
+}
+
+function exec(command) {
+    var oShell=shell.Exec(command);
+    while (oShell.Status == 0) {
+        if(!oShell.StdOut.AtEndOfStream) {
+            var line = oShell.StdOut.ReadLine();
+            // XXX: Change to verbose mode 
+            // WScript.StdOut.WriteLine(line);
+        }
+        WScript.sleep(100);
+    }
+}
+
+function createAppInfoJar() {
+    if(!fso.FileExists(ROOT+"\\bin\\templates\\cordova\\appinfo.jar")) {
+        WScript.Echo("Creating appinfo.jar...");
+        var cur = shell.CurrentDirectory;
+        shell.CurrentDirectory = ROOT+"\\bin\\templates\\cordova\\ApplicationInfo";
+        exec("javac ApplicationInfo.java");
+        exec("jar -cfe ..\\appinfo.jar ApplicationInfo ApplicationInfo.class");
+        shell.CurrentDirectory = cur;
+    }
+}
+
+function cleanup() {
+    if(fso.FileExists(ROOT + '\\framework\\cordova-'+VERSION+'.jar')) {
+        fso.DeleteFile(ROOT + '\\framework\\cordova-'+VERSION+'.jar');
+    }
+    if(fso.FileExists(ROOT + '\\framework\\assets\\www\\cordova-'+VERSION+'.js')) {
+        fso.DeleteFile(ROOT + '\\framework\\assets\\www\\cordova-'+VERSION+'.js');
+    }
+}
+
+function downloadCommonsCodec() {
+    if (!fso.FileExists(ROOT + '\\framework\\libs\\commons-codec-1.7.jar')) {
+      // We need the .jar
+      var url = 'http://archive.apache.org/dist/commons/codec/binaries/commons-codec-1.7-bin.zip';
+      var libsPath = ROOT + '\\framework\\libs';
+      var savePath = libsPath + '\\commons-codec-1.7-bin.zip';
+      if (!fso.FileExists(savePath)) {
+        if(!fso.FolderExists(ROOT + '\\framework\\libs')) {
+            fso.CreateFolder(libsPath);
+        }
+        // We need the zip to get the jar
+        var xhr = WScript.CreateObject('MSXML2.XMLHTTP');
+        xhr.open('GET', url, false);
+        xhr.send();
+        if (xhr.status == 200) {
+          var stream = WScript.CreateObject('ADODB.Stream');
+          stream.Open();
+          stream.Type = 1;
+          stream.Write(xhr.ResponseBody);
+          stream.Position = 0;
+          stream.SaveToFile(savePath);
+          stream.Close();
+        } else {
+          WScript.Echo('Could not retrieve the commons-codec. Please download it yourself and put into the framework/libs directory. This process may fail now. Sorry.');
+        }
+      }
+      var app = WScript.CreateObject('Shell.Application');
+      var source = app.NameSpace(savePath).Items();
+      var target = app.NameSpace(ROOT + '\\framework\\libs');
+      target.CopyHere(source, 256);
+      
+      // Move the jar into libs
+      fso.MoveFile(ROOT + '\\framework\\libs\\commons-codec-1.7\\commons-codec-1.7.jar', ROOT + '\\framework\\libs\\commons-codec-1.7.jar');
+      
+      // Clean up
+      fso.DeleteFile(ROOT + '\\framework\\libs\\commons-codec-1.7-bin.zip');
+      fso.DeleteFolder(ROOT + '\\framework\\libs\\commons-codec-1.7', true);
+    }
+}
+
+var args = WScript.Arguments, PROJECT_PATH="example", 
+    shell=WScript.CreateObject("WScript.Shell");
+    
+// working dir
+var ROOT = WScript.ScriptFullName.split('\\bin\\update.js').join('');
+
+if (args.Count() == 1) {
+    PROJECT_PATH=args(0);
+}
+
+if(!fso.FolderExists(PROJECT_PATH)) {
+    WScript.Echo("Project doesn't exist!");
+    WScript.Quit(1);
+}
+
+var TARGET=setTarget();
+var API_LEVEL=setApiLevel();
+var VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,'');
+
+// build from source. distro should have these files
+if (!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.jar') &&
+    !fso.FileExists(ROOT+'\\cordova-'+VERSION+'.js')) {
+    WScript.Echo("Building jar and js files...");
+    // update the cordova framework project to a target that exists on this machine
+    exec('android.bat update project --target '+TARGET+' --path '+ROOT+'\\framework');
+    // pull down commons codec if necessary
+    downloadCommonsCodec();
+    exec('ant.bat -f \"'+ ROOT +'\\framework\\build.xml\" jar');
+}
+
+// check if we have the source or the distro files
+WScript.Echo("Copying js, jar & config.xml files...");
+if(fso.FolderExists(ROOT + '\\framework')) {
+    exec('%comspec% /c copy "'+ROOT+'"\\framework\\assets\\www\\cordova-'+VERSION+'.js '+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js /Y');
+    exec('%comspec% /c copy "'+ROOT+'"\\framework\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar /Y');
+} else {
+    // copy in cordova.js
+    exec('%comspec% /c copy "'+ROOT+'"\\cordova-'+VERSION+'.js '+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js /Y');
+    // copy in cordova.jar
+    exec('%comspec% /c copy "'+ROOT+'"\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar /Y');
+    // copy in xml
+}
+
+// update cordova scripts
+createAppInfoJar();
+WScript.Echo("Copying cordova command tools...");
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\appinfo.jar ' + PROJECT_PATH + '\\cordova\\appinfo.jar /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.js ' + PROJECT_PATH + '\\cordova\\cordova.js /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.bat ' + PROJECT_PATH + '\\cordova\\cordova.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\clean.bat ' + PROJECT_PATH + '\\cordova\\clean.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\build.bat ' + PROJECT_PATH + '\\cordova\\build.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\log.bat ' + PROJECT_PATH + '\\cordova\\log.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\run.bat ' + PROJECT_PATH + '\\cordova\\run.bat /Y');
+
+cleanup();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/assets/js/cordova.android.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/assets/js/cordova.android.js b/lib/cordova-android/framework/assets/js/cordova.android.js
index bfd6545..a0c3278 100644
--- a/lib/cordova-android/framework/assets/js/cordova.android.js
+++ b/lib/cordova-android/framework/assets/js/cordova.android.js
@@ -1,8 +1,8 @@
 // Platform: android
 
-// commit f50d20a87431c79a54572263729461883f611a53
+// commit 47593b2bc1dba9bf46545b1da24577f937966e12
 
-// File generated at :: Tue Feb 26 2013 13:37:51 GMT-0800 (PST)
+// File generated at :: Thu Mar 21 2013 10:49:00 GMT-0700 (PDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -262,7 +262,7 @@ var cordova = {
      */
     callbackSuccess: function(callbackId, args) {
         try {
-            cordova.callbackFromNative(callbackId, true, args.status, args.message, args.keepCallback);
+            cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
         } catch (e) {
             console.log("Error in error callback: " + callbackId + " = "+e);
         }
@@ -275,7 +275,7 @@ var cordova = {
         // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
         // Derive success from status.
         try {
-            cordova.callbackFromNative(callbackId, false, args.status, args.message, args.keepCallback);
+            cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
         } catch (e) {
             console.log("Error in error callback: " + callbackId + " = "+e);
         }
@@ -284,13 +284,13 @@ var cordova = {
     /**
      * Called by native code when returning the result from an action.
      */
-    callbackFromNative: function(callbackId, success, status, message, keepCallback) {
+    callbackFromNative: function(callbackId, success, status, args, keepCallback) {
         var callback = cordova.callbacks[callbackId];
         if (callback) {
             if (success && status == cordova.callbackStatus.OK) {
-                callback.success && callback.success(message);
+                callback.success && callback.success.apply(null, args);
             } else if (!success) {
-                callback.fail && callback.fail(message);
+                callback.fail && callback.fail.apply(null, args);
             }
 
             // Clear callback if not expecting any more results
@@ -724,6 +724,9 @@ channel.createSticky('onCordovaInfoReady');
 // Event to indicate that the connection property has been set.
 channel.createSticky('onCordovaConnectionReady');
 
+// Event to indicate that all automatically loaded JS plugins are loaded and ready.
+channel.createSticky('onPluginsReady');
+
 // Event to indicate that Cordova is ready
 channel.createSticky('onDeviceReady');
 
@@ -900,7 +903,7 @@ androidExec.nativeToJsModes = nativeToJsModes;
 
 androidExec.setJsToNativeBridgeMode = function(mode) {
     if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
-        console.log('Falling back on PROMPT mode since _cordovaNative is missing.');
+        console.log('Falling back on PROMPT mode since _cordovaNative is missing. Expected for Android 3.2 and lower only.');
         mode = jsToNativeModes.PROMPT;
     }
     nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
@@ -958,10 +961,12 @@ function processMessage(message) {
                     arraybuffer[i] = bytes.charCodeAt(i);
                 }
                 payload = arraybuffer.buffer;
+            } else if (payloadKind == 'S') {
+                payload = window.atob(message.slice(nextSpaceIdx + 2));
             } else {
                 payload = JSON.parse(message.slice(nextSpaceIdx + 1));
             }
-            cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);
+            cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
         } else {
             console.log("processMessage failed: invalid message:" + message);
         }
@@ -1203,9 +1208,10 @@ cameraExport.getPicture = function(successCallback, errorCallback, options) {
     var correctOrientation = !!options.correctOrientation;
     var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
     var popoverOptions = getValue(options.popoverOptions, null);
+    var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
 
     var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
-                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions];
+                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
 
     exec(successCallback, errorCallback, "Camera", "takePicture", args);
     return new CameraPopoverHandle();
@@ -1248,6 +1254,10 @@ module.exports = {
       ARROW_LEFT : 4,
       ARROW_RIGHT : 8,
       ARROW_ANY : 15
+  },
+  Direction:{
+      BACK: 0,
+      FRONT: 1
   }
 };
 
@@ -2439,14 +2449,7 @@ FileReader.prototype.readAsText = function(file, encoding) {
     // Default encoding is UTF-8
     var enc = encoding ? encoding : "UTF-8";
     var me = this;
-    var execArgs = [this._fileName, enc];
-
-    // Maybe add slice parameters.
-    if (file.end < file.size) {
-        execArgs.push(file.start, file.end);
-    } else if (file.start > 0) {
-        execArgs.push(file.start);
-    }
+    var execArgs = [this._fileName, enc, file.start, file.end];
 
     // Read file
     exec(
@@ -2515,14 +2518,7 @@ FileReader.prototype.readAsDataURL = function(file) {
     }
 
     var me = this;
-    var execArgs = [this._fileName];
-
-    // Maybe add slice parameters.
-    if (file.end < file.size) {
-        execArgs.push(file.start, file.end);
-    } else if (file.start > 0) {
-        execArgs.push(file.start);
-    }
+    var execArgs = [this._fileName, file.start, file.end];
 
     // Read file
     exec(
@@ -2585,9 +2581,59 @@ FileReader.prototype.readAsBinaryString = function(file) {
     if (initRead(this, file)) {
         return this._realReader.readAsBinaryString(file);
     }
-    // TODO - Can't return binary data to browser.
-    console.log('method "readAsBinaryString" is not supported at this time.');
-    this.abort();
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsBinaryString", execArgs);
 };
 
 /**
@@ -2599,9 +2645,59 @@ FileReader.prototype.readAsArrayBuffer = function(file) {
     if (initRead(this, file)) {
         return this._realReader.readAsArrayBuffer(file);
     }
-    // TODO - Can't return binary data to browser.
-    console.log('This method is not supported at this time.');
-    this.abort();
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsArrayBuffer", execArgs);
 };
 
 module.exports = FileReader;
@@ -2647,6 +2743,38 @@ function newProgressEvent(result) {
     return pe;
 }
 
+function getBasicAuthHeader(urlString) {
+    var header =  null;
+
+    if (window.btoa) {
+        // parse the url using the Location object
+        var url = document.createElement('a');
+        url.href = urlString;
+
+        var credentials = null;
+        var protocol = url.protocol + "//";
+        var origin = protocol + url.host;
+
+        // check whether there are the username:password credentials in the url
+        if (url.href.indexOf(origin) != 0) { // credentials found
+            var atIndex = url.href.indexOf("@");
+            credentials = url.href.substring(protocol.length, atIndex);
+        }
+
+        if (credentials) {
+            var authHeader = "Authorization";
+            var authHeaderValue = "Basic " + window.btoa(credentials);
+
+            header = {
+                name : authHeader,
+                value : authHeaderValue
+            };
+        }
+    }
+
+    return header;
+}
+
 var idCounter = 0;
 
 /**
@@ -2677,6 +2805,18 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
     var params = null;
     var chunkedMode = true;
     var headers = null;
+
+    var basicAuthHeader = getBasicAuthHeader(server);
+    if (basicAuthHeader) {
+        if (!options) {
+            options = new FileUploadOptions();
+        }
+        if (!options.headers) {
+            options.headers = {};
+        }
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
     if (options) {
         fileKey = options.fileKey;
         fileName = options.fileName;
@@ -2694,7 +2834,7 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
     }
 
     var fail = errorCallback && function(e) {
-        var error = new FileTransferError(e.code, e.source, e.target, e.http_status);
+        var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
         errorCallback(error);
     };
 
@@ -2718,10 +2858,28 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
  * @param successCallback (Function}  Callback to be invoked when upload has completed
  * @param errorCallback {Function}    Callback to be invoked upon error
  * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+ * @param options {FileDownloadOptions} Optional parameters such as headers
  */
-FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts) {
+FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts, options) {
     argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
     var self = this;
+
+    var basicAuthHeader = getBasicAuthHeader(source);
+    if (basicAuthHeader) {
+        if (!options) {
+            options = {};
+        }
+        if (!options.headers) {
+            options.headers = {};
+        }
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
+    var headers = null;
+    if (options) {
+        headers = options.headers || null;
+    }
+
     var win = function(result) {
         if (typeof result.lengthComputable != "undefined") {
             if (self.onprogress) {
@@ -2744,11 +2902,11 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
     };
 
     var fail = errorCallback && function(e) {
-        var error = new FileTransferError(e.code, e.source, e.target, e.http_status);
+        var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
         errorCallback(error);
     };
 
-    exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id]);
+    exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id, headers]);
 };
 
 /**
@@ -3146,6 +3304,7 @@ function InAppBrowser() {
    this.channels = {
         'loadstart': channel.create('loadstart'),
         'loadstop' : channel.create('loadstop'),
+        'loaderror' : channel.create('loaderror'),
         'exit' : channel.create('exit')
    };
 }
@@ -3176,7 +3335,7 @@ module.exports = function(strUrl, strWindowName, strWindowFeatures) {
     var cb = function(eventname) {
        iab._eventHandler(eventname);
     };
-    exec(cb, null, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
+    exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
     return iab;
 };
 
@@ -4940,7 +5099,8 @@ modulemapper.merges('cordova/plugin/android/device', 'device');
 // file: lib/common/plugin/echo.js
 define("cordova/plugin/echo", function(require, exports, module) {
 
-var exec = require('cordova/exec');
+var exec = require('cordova/exec'),
+    utils = require('cordova/utils');
 
 /**
  * Sends the given message through exec() to the Echo plugin, which sends it back to the successCallback.
@@ -4950,11 +5110,25 @@ var exec = require('cordova/exec');
  * @param forceAsync  Whether to force an async return value (for testing native->js bridge).
  */
 module.exports = function(successCallback, errorCallback, message, forceAsync) {
-    var action = forceAsync ? 'echoAsync' : 'echo';
-    if (!forceAsync && message.constructor == ArrayBuffer) {
-        action = 'echoArrayBuffer';
+    var action = 'echo';
+    var messageIsMultipart = (utils.typeName(message) == "Array");
+    var args = messageIsMultipart ? message : [message];
+
+    if (utils.typeName(message) == 'ArrayBuffer') {
+        if (forceAsync) {
+            console.warn('Cannot echo ArrayBuffer with forced async, falling back to sync.');
+        }
+        action += 'ArrayBuffer';
+    } else if (messageIsMultipart) {
+        if (forceAsync) {
+            console.warn('Cannot echo MultiPart Array with forced async, falling back to sync.');
+        }
+        action += 'MultiPart';
+    } else if (forceAsync) {
+        action += 'Async';
     }
-    exec(successCallback, errorCallback, "Echo", action, [message]);
+
+    exec(successCallback, errorCallback, "Echo", action, args);
 };
 
 
@@ -5950,6 +6124,7 @@ modulemapper.defaults('cordova/plugin/Connection', 'Connection');
 define("cordova/plugin/notification", function(require, exports, module) {
 
 var exec = require('cordova/exec');
+var platform = require('cordova/platform');
 
 /**
  * Provides access to notifications on the device.
@@ -5978,15 +6153,53 @@ module.exports = {
      * @param {String} message              Message to print in the body of the alert
      * @param {Function} resultCallback     The callback that is called when user clicks on a button.
      * @param {String} title                Title of the alert dialog (default: Confirm)
-     * @param {String} buttonLabels         Comma separated list of the labels of the buttons (default: 'OK,Cancel')
+     * @param {Array} buttonLabels          Array of the labels of the buttons (default: ['OK', 'Cancel'])
      */
     confirm: function(message, resultCallback, title, buttonLabels) {
         var _title = (title || "Confirm");
-        var _buttonLabels = (buttonLabels || "OK,Cancel");
+        var _buttonLabels = (buttonLabels || ["OK", "Cancel"]);
+
+        // Strings are deprecated!
+        if (typeof _buttonLabels === 'string') {
+            console.log("Notification.confirm(string, function, string, string) is deprecated.  Use Notification.confirm(string, function, string, array).");
+        }
+
+        // Android and iOS take an array of button label names.
+        // Other platforms take a comma separated list.
+        // For compatibility, we convert to the desired type based on the platform.
+        if (platform.id == "android" || platform.id == "ios") {
+            if (typeof _buttonLabels === 'string') {
+                var buttonLabelString = _buttonLabels;
+                _buttonLabels = buttonLabelString.split(",");
+            }
+        } else {
+            if (Array.isArray(_buttonLabels)) {
+                var buttonLabelArray = _buttonLabels;
+                _buttonLabels = buttonLabelArray.toString();
+            }
+        }
         exec(resultCallback, null, "Notification", "confirm", [message, _title, _buttonLabels]);
     },
 
     /**
+     * Open a native prompt dialog, with a customizable title and button text.
+     * The following results are returned to the result callback:
+     *  buttonIndex     Index number of the button selected.
+     *  input1          The text entered in the prompt dialog box.
+     *
+     * @param {String} message              Dialog message to display (default: "Prompt message")
+     * @param {Function} resultCallback     The callback that is called when user clicks on a button.
+     * @param {String} title                Title of the dialog (default: "Prompt")
+     * @param {Array} buttonLabels          Array of strings for the button labels (default: ["OK","Cancel"])
+     */
+    prompt: function(message, resultCallback, title, buttonLabels) {
+        var _message = (message || "Prompt message");
+        var _title = (title || "Prompt");
+        var _buttonLabels = (buttonLabels || ["OK","Cancel"]);
+        exec(resultCallback, null, "Notification", "prompt", [_message, _title, _buttonLabels]);
+    },
+
+    /**
      * Causes the device to vibrate.
      *
      * @param {Integer} mills       The number of milliseconds to vibrate for.
@@ -6409,53 +6622,160 @@ window.cordova = require('cordova');
 (function (context) {
     // Replace navigator before any modules are required(), to ensure it happens as soon as possible.
     // We replace it so that properties that can't be clobbered can instead be overridden.
-    if (context.navigator) {
+    function replaceNavigator(origNavigator) {
         var CordovaNavigator = function() {};
-        CordovaNavigator.prototype = context.navigator;
-        context.navigator = new CordovaNavigator();
+        CordovaNavigator.prototype = origNavigator;
+        var newNavigator = new CordovaNavigator();
+        // This work-around really only applies to new APIs that are newer than Function.bind.
+        // Without it, APIs such as getGamepads() break.
+        if (CordovaNavigator.bind) {
+            for (var key in origNavigator) {
+                if (typeof origNavigator[key] == 'function') {
+                    newNavigator[key] = origNavigator[key].bind(origNavigator);
+                }
+            }
+        }
+        return newNavigator;
     }
+    if (context.navigator) {
+        context.navigator = replaceNavigator(context.navigator);
+    }
+
+    var channel = require("cordova/channel");
+
+    // _nativeReady is global variable that the native side can set
+    // to signify that the native code is ready. It is a global since
+    // it may be called before any cordova JS is ready.
+    if (window._nativeReady) {
+        channel.onNativeReady.fire();
+    }
+
+    /**
+     * Create all cordova objects once page has fully loaded and native side is ready.
+     */
+    channel.join(function() {
+        var builder = require('cordova/builder'),
+            platform = require('cordova/platform');
+
+        builder.buildIntoButDoNotClobber(platform.defaults, context);
+        builder.buildIntoAndClobber(platform.clobbers, context);
+        builder.buildIntoAndMerge(platform.merges, context);
+
+        // Call the platform-specific initialization
+        platform.initialize();
+
+        // Fire event to notify that all objects are created
+        channel.onCordovaReady.fire();
+
+        // Fire onDeviceReady event once all constructors have run and
+        // cordova info has been received from native side.
+        channel.join(function() {
+            require('cordova').fireDocumentEvent('deviceready');
+        }, channel.deviceReadyChannelsArray);
+
+    }, [ channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady ]);
 
-    var channel = require("cordova/channel"),
-        _self = {
-            boot: function () {
-                /**
-                 * Create all cordova objects once page has fully loaded and native side is ready.
-                 */
-                channel.join(function() {
-                    var builder = require('cordova/builder'),
-                        platform = require('cordova/platform');
+}(window));
 
-                    builder.buildIntoButDoNotClobber(platform.defaults, context);
-                    builder.buildIntoAndClobber(platform.clobbers, context);
-                    builder.buildIntoAndMerge(platform.merges, context);
+// file: lib/scripts/plugin_loader.js
 
-                    // Call the platform-specific initialization
-                    platform.initialize();
+// Tries to load all plugins' js-modules.
+// This is an async process, but onDeviceReady is blocked on onPluginsReady.
+// onPluginsReady is fired when there are no plugins to load, or they are all done.
+(function (context) {
+    // To be populated with the handler by handlePluginsObject.
+    var onScriptLoadingComplete;
+
+    var scriptCounter = 0;
+    function scriptLoadedCallback() {
+        scriptCounter--;
+        if (scriptCounter === 0) {
+            onScriptLoadingComplete && onScriptLoadingComplete();
+        }
+    }
 
-                    // Fire event to notify that all objects are created
-                    channel.onCordovaReady.fire();
+    // Helper function to inject a <script> tag.
+    function injectScript(path) {
+        scriptCounter++;
+        var script = document.createElement("script");
+        script.onload = scriptLoadedCallback;
+        script.src = path;
+        document.head.appendChild(script);
+    }
+
+    // Called when:
+    // * There are plugins defined and all plugins are finished loading.
+    // * There are no plugins to load.
+    function finishPluginLoading() {
+        context.cordova.require('cordova/channel').onPluginsReady.fire();
+    }
+
+    // Handler for the cordova_plugins.json content.
+    // See plugman's plugin_loader.js for the details of this object.
+    // This function is only called if the really is a plugins array that isn't empty.
+    // Otherwise the XHR response handler will just call finishPluginLoading().
+    function handlePluginsObject(modules) {
+        // First create the callback for when all plugins are loaded.
+        var mapper = context.cordova.require('cordova/modulemapper');
+        onScriptLoadingComplete = function() {
+            // Loop through all the plugins and then through their clobbers and merges.
+            for (var i = 0; i < modules.length; i++) {
+                var module = modules[i];
+                if (!module) continue;
+
+                if (module.clobbers && module.clobbers.length) {
+                    for (var j = 0; j < module.clobbers.length; j++) {
+                        mapper.clobbers(module.id, module.clobbers[j]);
+                    }
+                }
 
-                    // Fire onDeviceReady event once all constructors have run and
-                    // cordova info has been received from native side.
-                    channel.join(function() {
-                        require('cordova').fireDocumentEvent('deviceready');
-                    }, channel.deviceReadyChannelsArray);
+                if (module.merges && module.merges.length) {
+                    for (var k = 0; k < module.merges.length; k++) {
+                        mapper.merges(module.id, module.merges[k]);
+                    }
+                }
 
-                }, [ channel.onDOMContentLoaded, channel.onNativeReady ]);
+                // Finally, if runs is truthy we want to simply require() the module.
+                // This can be skipped if it had any merges or clobbers, though,
+                // since the mapper will already have required the module.
+                if (module.runs && !(module.clobbers && module.clobbers.length) && !(module.merges && module.merges.length)) {
+                    context.cordova.require(module.id);
+                }
             }
-        };
 
-    // boot up once native side is ready
-    channel.onNativeReady.subscribe(_self.boot);
+            finishPluginLoading();
+        };
 
-    // _nativeReady is global variable that the native side can set
-    // to signify that the native code is ready. It is a global since
-    // it may be called before any cordova JS is ready.
-    if (window._nativeReady) {
-        channel.onNativeReady.fire();
+        // Now inject the scripts.
+        for (var i = 0; i < modules.length; i++) {
+            injectScript(modules[i].file);
+        }
     }
 
+    // Try to XHR the cordova_plugins.json file asynchronously.
+    var xhr = new context.XMLHttpRequest();
+    xhr.onreadystatechange = function() {
+        if (this.readyState != 4) { // not DONE
+            return;
+        }
+
+        // If the response is a JSON string which composes an array, call handlePluginsObject.
+        // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
+        if (this.status == 200) {
+            var obj = JSON.parse(this.responseText);
+            if (obj && obj instanceof Array && obj.length > 0) {
+                handlePluginsObject(obj);
+            } else {
+                finishPluginLoading();
+            }
+        } else {
+            finishPluginLoading();
+        }
+    };
+    xhr.open('GET', 'cordova_plugins.json', true); // Async
+    xhr.send();
 }(window));
 
 
+
 })();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/assets/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/assets/www/index.html b/lib/cordova-android/framework/assets/www/index.html
index a10905d..3b15a4e 100644
--- a/lib/cordova-android/framework/assets/www/index.html
+++ b/lib/cordova-android/framework/assets/www/index.html
@@ -19,7 +19,7 @@
 <html>
   <head>
     <title></title>
-    <script src="cordova-2.5.0.js"></script>
+    <script src="cordova-2.6.0rc1.js"></script>
   </head>
   <body>
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/AudioHandler.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/AudioHandler.java b/lib/cordova-android/framework/src/org/apache/cordova/AudioHandler.java
index ed5757f..fd8c9df 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/AudioHandler.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/AudioHandler.java
@@ -68,13 +68,13 @@ public class AudioHandler extends CordovaPlugin {
         String result = "";
 
         if (action.equals("startRecordingAudio")) {
-            this.startRecordingAudio(args.getString(0), FileUtils.stripFileProtocol(args.getString(1)));
+            this.startRecordingAudio(args.getString(0), FileHelper.stripFileProtocol(args.getString(1)));
         }
         else if (action.equals("stopRecordingAudio")) {
             this.stopRecordingAudio(args.getString(0));
         }
         else if (action.equals("startPlayingAudio")) {
-            this.startPlayingAudio(args.getString(0), FileUtils.stripFileProtocol(args.getString(1)));
+            this.startPlayingAudio(args.getString(0), FileHelper.stripFileProtocol(args.getString(1)));
         }
         else if (action.equals("seekToAudio")) {
             this.seekToAudio(args.getString(0), args.getInt(1));
@@ -102,7 +102,7 @@ public class AudioHandler extends CordovaPlugin {
         }
         else if (action.equals("create")) {
             String id = args.getString(0);
-            String src = FileUtils.stripFileProtocol(args.getString(1));
+            String src = FileHelper.stripFileProtocol(args.getString(1));
             AudioPlayer audio = new AudioPlayer(this, id, src);
             this.players.put(id, audio);
         }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/AudioPlayer.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/AudioPlayer.java b/lib/cordova-android/framework/src/org/apache/cordova/AudioPlayer.java
index 99dbb3d..0170728 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/AudioPlayer.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/AudioPlayer.java
@@ -167,13 +167,18 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
     public void moveFile(String file) {
         /* this is a hack to save the file as the specified name */
         File f = new File(this.tempFile);
-        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
-            f.renameTo(new File(Environment.getExternalStorageDirectory().getAbsolutePath()
-                    + File.separator + file));
-        } else {
-            f.renameTo(new File("/data/data/" + handler.cordova.getActivity().getPackageName() + "/cache/" + file));
+
+        if (!file.startsWith("/")) {
+            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+                file = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + file;
+            } else {
+                file = "/data/data/" + handler.cordova.getActivity().getPackageName() + "/cache/" + file;
+            }
         }
 
+        String logMsg = "renaming " + this.tempFile + " to " + file;
+        Log.d(LOG_TAG, logMsg);
+        if (!f.renameTo(new File(file))) Log.e(LOG_TAG, "FAILED " + logMsg);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java b/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
index aec0def..9473828 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
@@ -289,7 +289,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
 
                     // If sending base64 image back
                     if (destType == DATA_URL) {
-                        bitmap = getScaledBitmap(FileUtils.stripFileProtocol(imageUri.toString()));
+                        bitmap = getScaledBitmap(FileHelper.stripFileProtocol(imageUri.toString()));
                         if (bitmap == null) {
                             // Try to get the bitmap from intent.
                             bitmap = (Bitmap)intent.getExtras().get("data");
@@ -329,7 +329,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
 
                             this.callbackContext.success(uri.toString());
                         } else {
-                            bitmap = getScaledBitmap(FileUtils.stripFileProtocol(imageUri.toString()));
+                            bitmap = getScaledBitmap(FileHelper.stripFileProtocol(imageUri.toString()));
 
                             if (rotate != 0 && this.correctOrientation) {
                                 bitmap = getRotatedBitmap(rotate, bitmap, exif);
@@ -344,7 +344,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                             if (this.encodingType == JPEG) {
                                 String exifPath;
                                 if (this.saveToPhotoAlbum) {
-                                    exifPath = FileUtils.getRealPathFromURI(uri, this.cordova);
+                                    exifPath = FileHelper.getRealPath(uri, this.cordova);
                                 } else {
                                     exifPath = uri.getPath();
                                 }
@@ -395,8 +395,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                         this.callbackContext.success(uri.toString());
                     } else {
                         // Get the path to the image. Makes loading so much easier.
-                        String imagePath = FileUtils.getRealPathFromURI(uri, this.cordova);
-                        String mimeType = FileUtils.getMimeType(imagePath);
+                        String imagePath = FileHelper.getRealPath(uri, this.cordova);
+                        String mimeType = FileHelper.getMimeType(imagePath, this.cordova);
                         // Log.d(LOG_TAG, "Real path = " + imagePath);
                         // Log.d(LOG_TAG, "mime type = " + mimeType);
                         // If we don't have a valid image so quit.
@@ -458,7 +458,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
 
                                     // Restore exif data to file
                                     if (this.encodingType == JPEG) {
-                                        exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.cordova));
+                                        exif.createOutFile(FileHelper.getRealPath(uri, this.cordova));
                                         exif.writeExifData();
                                     }
 
@@ -521,7 +521,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
      */
     private void writeUncompressedImage(Uri uri) throws FileNotFoundException,
             IOException {
-        FileInputStream fis = new FileInputStream(FileUtils.stripFileProtocol(imageUri.toString()));
+        FileInputStream fis = new FileInputStream(FileHelper.stripFileProtocol(imageUri.toString()));
         OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
         byte[] buffer = new byte[4096];
         int len;
@@ -685,7 +685,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
         }
 
         // Clean up initial camera-written image file.
-        (new File(FileUtils.stripFileProtocol(oldImage.toString()))).delete();
+        (new File(FileHelper.stripFileProtocol(oldImage.toString()))).delete();
 
         checkForDuplicateImage(imageType);
         // Scan for the gallery to update pic refs in gallery

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/Capture.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Capture.java b/lib/cordova-android/framework/src/org/apache/cordova/Capture.java
index 3eecf37..5f737ca 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/Capture.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Capture.java
@@ -23,6 +23,7 @@ import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 
+import android.os.Build;
 import org.apache.cordova.api.CallbackContext;
 import org.apache.cordova.api.CordovaPlugin;
 import org.apache.cordova.api.LOG;
@@ -128,7 +129,7 @@ public class Capture extends CordovaPlugin {
         // If the mimeType isn't set the rest will fail
         // so let's see if we can determine it.
         if (mimeType == null || mimeType.equals("") || "null".equals(mimeType)) {
-            mimeType = FileUtils.getMimeType(filePath);
+            mimeType = FileHelper.getMimeType(filePath, cordova);
         }
         Log.d(LOG_TAG, "Mime type = " + mimeType);
 
@@ -155,7 +156,7 @@ public class Capture extends CordovaPlugin {
     private JSONObject getImageData(String filePath, JSONObject obj) throws JSONException {
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inJustDecodeBounds = true;
-        BitmapFactory.decodeFile(FileUtils.stripFileProtocol(filePath), options);
+        BitmapFactory.decodeFile(FileHelper.stripFileProtocol(filePath), options);
         obj.put("height", options.outHeight);
         obj.put("width", options.outWidth);
         return obj;
@@ -216,9 +217,10 @@ public class Capture extends CordovaPlugin {
      */
     private void captureVideo(double duration) {
         Intent intent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE);
-        // Introduced in API 8
-        //intent.putExtra(android.provider.MediaStore.EXTRA_DURATION_LIMIT, duration);
 
+        if(Build.VERSION.SDK_INT > 8){
+            intent.putExtra("android.intent.extra.durationLimit", duration);
+        }
         this.cordova.startActivityForResult((CordovaPlugin) this, intent, CAPTURE_VIDEO);
     }
 
@@ -346,7 +348,7 @@ public class Capture extends CordovaPlugin {
      * @throws IOException
      */
     private JSONObject createMediaFile(Uri data) {
-        File fp = new File(FileUtils.getRealPathFromURI(data, this.cordova));
+        File fp = new File(FileHelper.getRealPath(data, this.cordova));
         JSONObject obj = new JSONObject();
 
         try {
@@ -363,7 +365,7 @@ public class Capture extends CordovaPlugin {
                     obj.put("type", VIDEO_3GPP);
                 }
             } else {
-                obj.put("type", FileUtils.getMimeType(fp.getAbsolutePath()));
+                obj.put("type", FileHelper.getMimeType(fp.getAbsolutePath(), cordova));
             }
 
             obj.put("lastModifiedDate", fp.lastModified());

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/Config.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Config.java b/lib/cordova-android/framework/src/org/apache/cordova/Config.java
index 01eb2bb..f5de38d 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/Config.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Config.java
@@ -143,6 +143,16 @@ public class Config {
                         boolean value = xml.getAttributeValue(null, "value").equals("true");
                         action.getIntent().putExtra(name, value);
                     }
+                    else if(name.equals("InAppBrowserStorageEnabled"))
+                    {
+                        boolean value = xml.getAttributeValue(null, "value").equals("true");
+                        action.getIntent().putExtra(name, value);
+                    }
+                    else if(name.equals("disallowOverscroll"))
+                    {
+                        boolean value = xml.getAttributeValue(null, "value").equals("true");
+                        action.getIntent().putExtra(name, value);
+                    }
                     else
                     {
                         String value = xml.getAttributeValue(null, "value");

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/CordovaArgs.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CordovaArgs.java b/lib/cordova-android/framework/src/org/apache/cordova/CordovaArgs.java
index 3a8b7c0..d40d26e 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/CordovaArgs.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CordovaArgs.java
@@ -20,6 +20,7 @@ package org.apache.cordova;
 
 import org.json.JSONArray;
 import org.json.JSONException;
+import org.json.JSONObject;
 
 import android.util.Base64;
 
@@ -52,7 +53,7 @@ public class CordovaArgs {
         return baseArgs.getJSONArray(index);
     }
 
-    public Object getJSONObject(int index) throws JSONException {
+    public JSONObject getJSONObject(int index) throws JSONException {
         return baseArgs.getJSONObject(index);
     }
 
@@ -85,7 +86,7 @@ public class CordovaArgs {
         return baseArgs.optJSONArray(index);
     }
 
-    public Object optJSONObject(int index) {
+    public JSONObject optJSONObject(int index) {
         return baseArgs.optJSONObject(index);
     }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/CordovaChromeClient.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CordovaChromeClient.java b/lib/cordova-android/framework/src/org/apache/cordova/CordovaChromeClient.java
index e650781..fb6d45f 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CordovaChromeClient.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CordovaChromeClient.java
@@ -205,7 +205,7 @@ public class CordovaChromeClient extends WebChromeClient {
         // Security check to make sure any requests are coming from the page initially
         // loaded in webview and not another loaded in an iframe.
         boolean reqOk = false;
-        if (url.startsWith("file://") || url.indexOf(this.appView.baseUrl) == 0 || Config.isUrlWhiteListed(url)) {
+        if (url.startsWith("file://") || Config.isUrlWhiteListed(url)) {
             reqOk = true;
         }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java b/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java
index 4731adb..e653a95 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java
@@ -47,6 +47,7 @@ import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
 import android.webkit.WebBackForwardList;
 import android.webkit.WebHistoryItem;
 import android.webkit.WebChromeClient;
@@ -74,12 +75,7 @@ public class CordovaWebView extends WebView {
     @SuppressWarnings("unused")
     private CordovaChromeClient chromeClient;
 
-    //This is for the polyfill history
     private String url;
-    String baseUrl;
-    private Stack<String> urls = new Stack<String>();
-
-    boolean useBrowserHistory = true;
 
     // Flag to track that a loadUrl timeout occurred
     int loadUrlTimeout = 0;
@@ -211,7 +207,8 @@ public class CordovaWebView extends WebView {
 
 
     private void initWebViewClient(CordovaInterface cordova) {
-        if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
+        if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB ||
+                android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.JELLY_BEAN_MR1)
         {
             this.setWebViewClient(new CordovaWebViewClient(this.cordova, this));
         }
@@ -254,14 +251,23 @@ public class CordovaWebView extends WebView {
             Log.d(TAG, "This should never happen: InvocationTargetException means this isn't Android anymore.");
         }
 
+        //We don't save any form data in the application
+        settings.setSaveFormData(false);
+        settings.setSavePassword(false);
+        
         // Jellybean rightfully tried to lock this down. Too bad they didn't give us a whitelist
         // while we do this
         if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
             Level16Apis.enableUniversalAccess(settings);
         // Enable database
-        settings.setDatabaseEnabled(true);
+        // We keep this disabled because we use or shim to get around DOM_EXCEPTION_ERROR_16
         String databasePath = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
-        settings.setDatabasePath(databasePath);
+        if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
+        {
+            settings.setDatabaseEnabled(true);
+            settings.setDatabasePath(databasePath);
+        }
+        
         settings.setGeolocationDatabasePath(databasePath);
 
         // Enable DOM storage
@@ -360,7 +366,7 @@ public class CordovaWebView extends WebView {
             String initUrl = this.getProperty("url", null);
 
             // If first page of app, then set URL to load to be the one passed in
-            if (initUrl == null || (this.urls.size() > 0)) {
+            if (initUrl == null) {
                 this.loadUrlIntoView(url);
             }
             // Otherwise use the URL specified in the activity's extras bundle
@@ -381,7 +387,7 @@ public class CordovaWebView extends WebView {
         String initUrl = this.getProperty("url", null);
 
         // If first page of app, then set URL to load to be the one passed in
-        if (initUrl == null || (this.urls.size() > 0)) {
+        if (initUrl == null) {
             this.loadUrlIntoView(url, time);
         }
         // Otherwise use the URL specified in the activity's extras bundle
@@ -399,21 +405,8 @@ public class CordovaWebView extends WebView {
         LOG.d(TAG, ">>> loadUrl(" + url + ")");
 
         this.url = url;
-        if (this.baseUrl == null) {
-            int i = url.lastIndexOf('/');
-            if (i > 0) {
-                this.baseUrl = url.substring(0, i + 1);
-            }
-            else {
-                this.baseUrl = this.url + "/";
-            }
-
-            this.pluginManager.init();
+        this.pluginManager.init();
 
-            if (!this.useBrowserHistory) {
-                this.urls.push(url);
-            }
-        }
 
         // Create a timeout timer for loadUrl
         final CordovaWebView me = this;
@@ -468,7 +461,7 @@ public class CordovaWebView extends WebView {
         if (LOG.isLoggable(LOG.DEBUG) && !url.startsWith("javascript:")) {
             LOG.d(TAG, ">>> loadUrlNow()");
         }
-        if (url.startsWith("file://") || url.indexOf(this.baseUrl) == 0 || url.startsWith("javascript:") || Config.isUrlWhiteListed(url)) {
+        if (url.startsWith("file://") || url.startsWith("javascript:") || Config.isUrlWhiteListed(url)) {
             super.loadUrl(url);
         }
     }
@@ -484,7 +477,7 @@ public class CordovaWebView extends WebView {
 
         // If not first page of app, then load immediately
         // Add support for browser history if we use it.
-        if ((url.startsWith("javascript:")) || this.urls.size() > 0 || this.canGoBack()) {
+        if ((url.startsWith("javascript:")) || this.canGoBack()) {
         }
 
         // If first page, then show splashscreen
@@ -532,25 +525,6 @@ public class CordovaWebView extends WebView {
         }
     }
 
-    /**
-     * Returns the top url on the stack without removing it from
-     * the stack.
-     */
-    public String peekAtUrlStack() {
-        if (this.urls.size() > 0) {
-            return this.urls.peek();
-        }
-        return "";
-    }
-
-    /**
-     * Add a url to the stack
-     *
-     * @param url
-     */
-    public void pushUrl(String url) {
-        this.urls.push(url);
-    }
 
     /**
      * Go to previous page in history.  (We manage our own history)
@@ -561,37 +535,15 @@ public class CordovaWebView extends WebView {
 
         // Check webview first to see if there is a history
         // This is needed to support curPage#diffLink, since they are added to appView's history, but not our history url array (JQMobile behavior)
-        if (super.canGoBack() && this.useBrowserHistory) {
+        if (super.canGoBack()) {
             printBackForwardList();
             super.goBack();
             
             return true;
         }
-        // If our managed history has prev url
-        else if (this.urls.size() > 1 && !this.useBrowserHistory) {
-            this.urls.pop();                // Pop current url
-            String url = this.urls.pop();   // Pop prev url that we want to load, since it will be added back by loadUrl()
-            this.loadUrl(url);
-            return true;
-        }
-
         return false;
     }
 
-    /**
-     * Return true if there is a history item.
-     *
-     * @return
-     */
-    public boolean canGoBack() {
-        if (super.canGoBack() && this.useBrowserHistory) {
-            return true;
-        }
-        else if (this.urls.size() > 1) {
-            return true;
-        }
-        return false;
-    }
 
     /**
      * Load the specified URL in the Cordova webview or a new browser instance.
@@ -615,14 +567,8 @@ public class CordovaWebView extends WebView {
         if (!openExternal) {
 
             // Make sure url is in whitelist
-            if (url.startsWith("file://") || url.indexOf(this.baseUrl) == 0 || Config.isUrlWhiteListed(url)) {
+            if (url.startsWith("file://") || Config.isUrlWhiteListed(url)) {
                 // TODO: What about params?
-
-                // Clear out current url from history, since it will be replacing it
-                if (clearHistory) {
-                    this.urls.clear();
-                }
-
                 // Load new URL
                 this.loadUrl(url);
             }
@@ -659,13 +605,6 @@ public class CordovaWebView extends WebView {
      *      <log level="DEBUG" />
      */
     private void loadConfiguration() {
-        // Config has already been loaded, and it stores these preferences on the Intent.
-        if("false".equals(this.getProperty("useBrowserHistory", "true")))
-        {
-            //Switch back to the old browser history and state the six month policy
-            this.useBrowserHistory = false;
-            Log.w(TAG, "useBrowserHistory=false is deprecated as of Cordova 2.2.0 and will be removed six months after the 2.2.0 release.  Please use the browser history and use history.back().");
-        }
  
         if ("true".equals(this.getProperty("fullscreen", "false"))) {
             this.cordova.getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
@@ -719,13 +658,20 @@ public class CordovaWebView extends WebView {
         }
         else if(keyCode == KeyEvent.KEYCODE_BACK)
         {
-            //Because exit is fired on the keyDown and not the key up on Android 4.x
-            //we need to check for this.
-            //Also, I really wished "canGoBack" worked!
-            if(this.useBrowserHistory)
-                return !(this.startOfHistory()) || this.bound;
-            else
-                return this.urls.size() > 1 || this.bound;
+            return !(this.startOfHistory()) || this.bound;
+        }
+        else if(keyCode == KeyEvent.KEYCODE_MENU)
+        {
+            //How did we get here?  Is there a childView?
+            View childView = this.getFocusedChild();
+            if(childView != null)
+            {
+                //Make sure we close the keyboard if it's present
+                InputMethodManager imm = (InputMethodManager) cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+                imm.hideSoftInputFromWindow(childView.getWindowToken(), 0);
+                cordova.getActivity().openOptionsMenu();
+            }
+            return true;
         }
         
         return super.onKeyDown(keyCode, event);


[4/6] 2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.

Posted by fi...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/FileUtils.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/FileUtils.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/FileUtils.java
index 2655ef6..20ef492 100644
--- a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/FileUtils.java
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/FileUtils.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.Enumeration;
+import java.util.Random;
 
 import javax.microedition.io.Connector;
 import javax.microedition.io.file.FileConnection;
@@ -35,6 +36,7 @@ import net.rim.device.api.io.FileNotFoundException;
 import net.rim.device.api.io.IOUtilities;
 import net.rim.device.api.io.MIMETypeAssociations;
 import net.rim.device.api.system.Application;
+import net.rim.device.api.system.ControlledAccessException;
 
 /**
  * Contains file utility methods.
@@ -45,7 +47,13 @@ public class FileUtils {
     public static final String LOCAL_PROTOCOL = "local://";
     public static final String FILE_PROTOCOL = "file://";
 
-    private static final String APP_TMP_DIR    = "tmp" + CordovaExtension.getAppID();
+    private static final String APP_TMP_DIR;
+    
+    // init APP_TMP_DIR with a random value
+    static {
+        Random gen = new Random();
+        APP_TMP_DIR = "tmp" + Math.abs(gen.nextInt());
+    }
 
     /**
      * Reads file as byte array.
@@ -226,6 +234,9 @@ public class FileUtils {
                 return;
             }
             fconn.mkdir();
+        } catch (ControlledAccessException e) {
+            Logger.log("ControlledAccessException on dir " + dirPath + ", either directory conflict after reinstall of app, or device is connected via usb, see Cordova Docs File Blackberry Quirks");
+            Logger.log(e.toString());
         }
         finally {
             try {
@@ -237,6 +248,26 @@ public class FileUtils {
     }
 
     /**
+     * Determines the size of a file on the file system. Size always represents number of bytes contained in the file; never pre-allocated but empty space
+     * @return size in bytes of the selected file, or -1 if the file does not exist or is inaccessible
+     */
+    public static long fileSize(String path) throws IOException {
+        FileConnection fconn = null;
+        long fsize = -1;
+        try {
+            fconn = (FileConnection)Connector.open(path);
+            fsize = fconn.fileSize();
+        } catch (IOException e) {
+            Logger.log(FileUtils.class.getName() + " fileSize:  " + path + "not found or inaccessible");
+        } finally {
+            try {
+                if (fconn != null) fconn.close();
+            } catch (IOException ignored) {}
+        }
+       return fsize;
+    }
+
+    /**
      * Copies a file or directory to a new location. If copying a directory, the
      * entire contents of the directory are copied recursively.
      *

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-blackberry/javascript/cordova.blackberry.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/javascript/cordova.blackberry.js b/lib/cordova-blackberry/javascript/cordova.blackberry.js
index 988dd43..fbe61f5 100644
--- a/lib/cordova-blackberry/javascript/cordova.blackberry.js
+++ b/lib/cordova-blackberry/javascript/cordova.blackberry.js
@@ -1,8 +1,8 @@
 // Platform: blackberry
 
-// commit c5437f050947a65045222c6ac9fa70cf71ba334e
+// commit bbf1562d4934b1331ffb263424b6ae054cedeb71
 
-// File generated at :: Wed Feb 27 2013 13:16:46 GMT-0800 (PST)
+// File generated at :: Fri Mar 22 2013 14:49:45 GMT-0700 (PDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -725,7 +725,6 @@ channel.createSticky('onCordovaInfoReady');
 channel.createSticky('onCordovaConnectionReady');
 
 // Event to indicate that all automatically loaded JS plugins are loaded and ready.
-// This is used in conjunction with the automatic plugin JS loading CLI prototype.
 channel.createSticky('onPluginsReady');
 
 // Event to indicate that Cordova is ready
@@ -1033,9 +1032,10 @@ cameraExport.getPicture = function(successCallback, errorCallback, options) {
     var correctOrientation = !!options.correctOrientation;
     var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
     var popoverOptions = getValue(options.popoverOptions, null);
+    var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
 
     var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
-                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions];
+                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
 
     exec(successCallback, errorCallback, "Camera", "takePicture", args);
     return new CameraPopoverHandle();
@@ -1078,6 +1078,10 @@ module.exports = {
       ARROW_LEFT : 4,
       ARROW_RIGHT : 8,
       ARROW_ANY : 15
+  },
+  Direction:{
+      BACK: 0,
+      FRONT: 1
   }
 };
 
@@ -2269,14 +2273,7 @@ FileReader.prototype.readAsText = function(file, encoding) {
     // Default encoding is UTF-8
     var enc = encoding ? encoding : "UTF-8";
     var me = this;
-    var execArgs = [this._fileName, enc];
-
-    // Maybe add slice parameters.
-    if (file.end < file.size) {
-        execArgs.push(file.start, file.end);
-    } else if (file.start > 0) {
-        execArgs.push(file.start);
-    }
+    var execArgs = [this._fileName, enc, file.start, file.end];
 
     // Read file
     exec(
@@ -2345,14 +2342,7 @@ FileReader.prototype.readAsDataURL = function(file) {
     }
 
     var me = this;
-    var execArgs = [this._fileName];
-
-    // Maybe add slice parameters.
-    if (file.end < file.size) {
-        execArgs.push(file.start, file.end);
-    } else if (file.start > 0) {
-        execArgs.push(file.start);
-    }
+    var execArgs = [this._fileName, file.start, file.end];
 
     // Read file
     exec(
@@ -2415,9 +2405,59 @@ FileReader.prototype.readAsBinaryString = function(file) {
     if (initRead(this, file)) {
         return this._realReader.readAsBinaryString(file);
     }
-    // TODO - Can't return binary data to browser.
-    console.log('method "readAsBinaryString" is not supported at this time.');
-    this.abort();
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsBinaryString", execArgs);
 };
 
 /**
@@ -2429,9 +2469,59 @@ FileReader.prototype.readAsArrayBuffer = function(file) {
     if (initRead(this, file)) {
         return this._realReader.readAsArrayBuffer(file);
     }
-    // TODO - Can't return binary data to browser.
-    console.log('This method is not supported at this time.');
-    this.abort();
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsArrayBuffer", execArgs);
 };
 
 module.exports = FileReader;
@@ -2477,6 +2567,38 @@ function newProgressEvent(result) {
     return pe;
 }
 
+function getBasicAuthHeader(urlString) {
+    var header =  null;
+
+    if (window.btoa) {
+        // parse the url using the Location object
+        var url = document.createElement('a');
+        url.href = urlString;
+
+        var credentials = null;
+        var protocol = url.protocol + "//";
+        var origin = protocol + url.host;
+
+        // check whether there are the username:password credentials in the url
+        if (url.href.indexOf(origin) != 0) { // credentials found
+            var atIndex = url.href.indexOf("@");
+            credentials = url.href.substring(protocol.length, atIndex);
+        }
+
+        if (credentials) {
+            var authHeader = "Authorization";
+            var authHeaderValue = "Basic " + window.btoa(credentials);
+
+            header = {
+                name : authHeader,
+                value : authHeaderValue
+            };
+        }
+    }
+
+    return header;
+}
+
 var idCounter = 0;
 
 /**
@@ -2507,6 +2629,18 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
     var params = null;
     var chunkedMode = true;
     var headers = null;
+
+    var basicAuthHeader = getBasicAuthHeader(server);
+    if (basicAuthHeader) {
+        if (!options) {
+            options = new FileUploadOptions();
+        }
+        if (!options.headers) {
+            options.headers = {};
+        }
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
     if (options) {
         fileKey = options.fileKey;
         fileName = options.fileName;
@@ -2548,10 +2682,28 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
  * @param successCallback (Function}  Callback to be invoked when upload has completed
  * @param errorCallback {Function}    Callback to be invoked upon error
  * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+ * @param options {FileDownloadOptions} Optional parameters such as headers
  */
-FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts) {
+FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts, options) {
     argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
     var self = this;
+
+    var basicAuthHeader = getBasicAuthHeader(source);
+    if (basicAuthHeader) {
+        if (!options) {
+            options = {};
+        }
+        if (!options.headers) {
+            options.headers = {};
+        }
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
+    var headers = null;
+    if (options) {
+        headers = options.headers || null;
+    }
+
     var win = function(result) {
         if (typeof result.lengthComputable != "undefined") {
             if (self.onprogress) {
@@ -2578,7 +2730,7 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
         errorCallback(error);
     };
 
-    exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id]);
+    exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id, headers]);
 };
 
 /**
@@ -2976,6 +3128,7 @@ function InAppBrowser() {
    this.channels = {
         'loadstart': channel.create('loadstart'),
         'loadstop' : channel.create('loadstop'),
+        'loaderror' : channel.create('loaderror'),
         'exit' : channel.create('exit')
    };
 }
@@ -3006,7 +3159,7 @@ module.exports = function(strUrl, strWindowName, strWindowFeatures) {
     var cb = function(eventname) {
        iab._eventHandler(eventname);
     };
-    exec(cb, null, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
+    exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
     return iab;
 };
 
@@ -8682,6 +8835,7 @@ modulemapper.defaults('cordova/plugin/Connection', 'Connection');
 define("cordova/plugin/notification", function(require, exports, module) {
 
 var exec = require('cordova/exec');
+var platform = require('cordova/platform');
 
 /**
  * Provides access to notifications on the device.
@@ -8710,15 +8864,53 @@ module.exports = {
      * @param {String} message              Message to print in the body of the alert
      * @param {Function} resultCallback     The callback that is called when user clicks on a button.
      * @param {String} title                Title of the alert dialog (default: Confirm)
-     * @param {String} buttonLabels         Comma separated list of the labels of the buttons (default: 'OK,Cancel')
+     * @param {Array} buttonLabels          Array of the labels of the buttons (default: ['OK', 'Cancel'])
      */
     confirm: function(message, resultCallback, title, buttonLabels) {
         var _title = (title || "Confirm");
-        var _buttonLabels = (buttonLabels || "OK,Cancel");
+        var _buttonLabels = (buttonLabels || ["OK", "Cancel"]);
+
+        // Strings are deprecated!
+        if (typeof _buttonLabels === 'string') {
+            console.log("Notification.confirm(string, function, string, string) is deprecated.  Use Notification.confirm(string, function, string, array).");
+        }
+
+        // Android and iOS take an array of button label names.
+        // Other platforms take a comma separated list.
+        // For compatibility, we convert to the desired type based on the platform.
+        if (platform.id == "android" || platform.id == "ios") {
+            if (typeof _buttonLabels === 'string') {
+                var buttonLabelString = _buttonLabels;
+                _buttonLabels = buttonLabelString.split(",");
+            }
+        } else {
+            if (Array.isArray(_buttonLabels)) {
+                var buttonLabelArray = _buttonLabels;
+                _buttonLabels = buttonLabelArray.toString();
+            }
+        }
         exec(resultCallback, null, "Notification", "confirm", [message, _title, _buttonLabels]);
     },
 
     /**
+     * Open a native prompt dialog, with a customizable title and button text.
+     * The following results are returned to the result callback:
+     *  buttonIndex     Index number of the button selected.
+     *  input1          The text entered in the prompt dialog box.
+     *
+     * @param {String} message              Dialog message to display (default: "Prompt message")
+     * @param {Function} resultCallback     The callback that is called when user clicks on a button.
+     * @param {String} title                Title of the dialog (default: "Prompt")
+     * @param {Array} buttonLabels          Array of strings for the button labels (default: ["OK","Cancel"])
+     */
+    prompt: function(message, resultCallback, title, buttonLabels) {
+        var _message = (message || "Prompt message");
+        var _title = (title || "Prompt");
+        var _buttonLabels = (buttonLabels || ["OK","Cancel"]);
+        exec(resultCallback, null, "Notification", "prompt", [_message, _title, _buttonLabels]);
+    },
+
+    /**
      * Causes the device to vibrate.
      *
      * @param {Integer} mills       The number of milliseconds to vibrate for.
@@ -10506,15 +10698,6 @@ window.cordova = require('cordova');
     /**
      * Create all cordova objects once page has fully loaded and native side is ready.
      */
-    var joinEvents = [ channel.onDOMContentLoaded, channel.onNativeReady ];
-
-    // If this property is set to something truthy, join on onPluginsReady too.
-    // This property is set by the automatic JS installation prototype in cordova-cli,
-    // and will be removed when the prototype either becomes mainline or is dropped.
-    if (window.__onPluginsLoadedHack) {
-        joinEvents.push(channel.onPluginsReady);
-    }
-
     channel.join(function() {
         var builder = require('cordova/builder'),
             platform = require('cordova/platform');
@@ -10535,7 +10718,7 @@ window.cordova = require('cordova');
             require('cordova').fireDocumentEvent('deviceready');
         }, channel.deviceReadyChannelsArray);
 
-    }, joinEvents);
+    }, [ channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady ]);
 
 }(window));
 
@@ -10565,5 +10748,105 @@ document.addEventListener("DOMContentLoaded", function () {
     }
 });
 
+// file: lib/scripts/plugin_loader.js
+
+// Tries to load all plugins' js-modules.
+// This is an async process, but onDeviceReady is blocked on onPluginsReady.
+// onPluginsReady is fired when there are no plugins to load, or they are all done.
+(function (context) {
+    // To be populated with the handler by handlePluginsObject.
+    var onScriptLoadingComplete;
+
+    var scriptCounter = 0;
+    function scriptLoadedCallback() {
+        scriptCounter--;
+        if (scriptCounter === 0) {
+            onScriptLoadingComplete && onScriptLoadingComplete();
+        }
+    }
+
+    // Helper function to inject a <script> tag.
+    function injectScript(path) {
+        scriptCounter++;
+        var script = document.createElement("script");
+        script.onload = scriptLoadedCallback;
+        script.src = path;
+        document.head.appendChild(script);
+    }
+
+    // Called when:
+    // * There are plugins defined and all plugins are finished loading.
+    // * There are no plugins to load.
+    function finishPluginLoading() {
+        context.cordova.require('cordova/channel').onPluginsReady.fire();
+    }
+
+    // Handler for the cordova_plugins.json content.
+    // See plugman's plugin_loader.js for the details of this object.
+    // This function is only called if the really is a plugins array that isn't empty.
+    // Otherwise the XHR response handler will just call finishPluginLoading().
+    function handlePluginsObject(modules) {
+        // First create the callback for when all plugins are loaded.
+        var mapper = context.cordova.require('cordova/modulemapper');
+        onScriptLoadingComplete = function() {
+            // Loop through all the plugins and then through their clobbers and merges.
+            for (var i = 0; i < modules.length; i++) {
+                var module = modules[i];
+                if (!module) continue;
+
+                if (module.clobbers && module.clobbers.length) {
+                    for (var j = 0; j < module.clobbers.length; j++) {
+                        mapper.clobbers(module.id, module.clobbers[j]);
+                    }
+                }
+
+                if (module.merges && module.merges.length) {
+                    for (var k = 0; k < module.merges.length; k++) {
+                        mapper.merges(module.id, module.merges[k]);
+                    }
+                }
+
+                // Finally, if runs is truthy we want to simply require() the module.
+                // This can be skipped if it had any merges or clobbers, though,
+                // since the mapper will already have required the module.
+                if (module.runs && !(module.clobbers && module.clobbers.length) && !(module.merges && module.merges.length)) {
+                    context.cordova.require(module.id);
+                }
+            }
+
+            finishPluginLoading();
+        };
+
+        // Now inject the scripts.
+        for (var i = 0; i < modules.length; i++) {
+            injectScript(modules[i].file);
+        }
+    }
+
+    // Try to XHR the cordova_plugins.json file asynchronously.
+    var xhr = new context.XMLHttpRequest();
+    xhr.onreadystatechange = function() {
+        if (this.readyState != 4) { // not DONE
+            return;
+        }
+
+        // If the response is a JSON string which composes an array, call handlePluginsObject.
+        // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
+        if (this.status == 200) {
+            var obj = JSON.parse(this.responseText);
+            if (obj && obj instanceof Array && obj.length > 0) {
+                handlePluginsObject(obj);
+            } else {
+                finishPluginLoading();
+            }
+        } else {
+            finishPluginLoading();
+        }
+    };
+    xhr.open('GET', 'cordova_plugins.json', true); // Async
+    xhr.send();
+}(window));
+
+
 
 })();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h b/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
index 33c6799..947ae2d 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
@@ -17,6 +17,8 @@
  under the License.
  */
 
+#define __CORDOVA_IOS__
+
 #define __CORDOVA_0_9_6 906
 #define __CORDOVA_1_0_0 10000
 #define __CORDOVA_1_1_0 10100
@@ -37,6 +39,7 @@
 #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_NA 99999      /* not available */
 
 /*
@@ -47,7 +50,7 @@
  #endif
  */
 #ifndef CORDOVA_VERSION_MIN_REQUIRED
-    #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_5_0
+    #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_6_0
 #endif
 
 /*
@@ -65,12 +68,20 @@
 
 /* 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]
+    (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

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVCamera.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCamera.h b/lib/cordova-ios/CordovaLib/Classes/CDVCamera.h
index 204d25f..65eac77 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCamera.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCamera.h
@@ -61,8 +61,8 @@ typedef NSUInteger CDVMediaType;
 // ======================================================================= //
 
 @interface CDVCamera : CDVPlugin <UIImagePickerControllerDelegate,
-    UINavigationControllerDelegate,
-    UIPopoverControllerDelegate>
+                       UINavigationControllerDelegate,
+                       UIPopoverControllerDelegate>
 {}
 
 @property (strong) CDVCameraPicker* pickerController;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m b/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
index aabe844..ab1154e 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
@@ -18,6 +18,7 @@
  */
 
 #import "CDVCamera.h"
+#import "CDVJpegHeaderWriter.h"
 #import "NSArray+Comparisons.h"
 #import "NSData+Base64.h"
 #import "NSDictionary+Extensions.h"
@@ -60,6 +61,8 @@ static NSSet* org_apache_cordova_validArrowDirections;
  *  7       allowsEdit
  *  8       correctOrientation
  *  9       saveToPhotoAlbum
+ *  10      popoverOptions
+ *  11      cameraDirection
  */
 - (void)takePicture:(CDVInvokedUrlCommand*)command
 {
@@ -82,6 +85,12 @@ static NSSet* org_apache_cordova_validArrowDirections;
         return;
     }
 
+    NSNumber* cameraDirection = [arguments objectAtIndex:11];
+    UIImagePickerControllerCameraDevice cameraDevice = UIImagePickerControllerCameraDeviceRear; // default
+    if (cameraDirection != nil) {
+        cameraDevice = (UIImagePickerControllerSourceType)[cameraDirection intValue];
+    }
+
     bool allowEdit = [[arguments objectAtIndex:7] boolValue];
     NSNumber* targetWidth = [arguments objectAtIndex:3];
     NSNumber* targetHeight = [arguments objectAtIndex:4];
@@ -105,6 +114,7 @@ static NSSet* org_apache_cordova_validArrowDirections;
 
     cameraPicker.delegate = self;
     cameraPicker.sourceType = sourceType;
+    cameraPicker.cameraDevice = cameraDevice;
     cameraPicker.allowsEditing = allowEdit; // THIS IS ALL IT TAKES FOR CROPPING - jm
     cameraPicker.callbackId = callbackId;
     cameraPicker.targetSize = targetSize;
@@ -289,6 +299,49 @@ static NSSet* org_apache_cordova_validArrowDirections;
                 data = UIImagePNGRepresentation(scaledImage == nil ? image : scaledImage);
             } else {
                 data = UIImageJPEGRepresentation(scaledImage == nil ? image : scaledImage, cameraPicker.quality / 100.0f);
+                
+                CDVJpegHeaderWriter * exifWriter = [[CDVJpegHeaderWriter alloc] init];
+                
+                NSString * headerstring = [exifWriter createExifAPP1: [info objectForKey:@"UIImagePickerControllerMediaMetadata"]];
+                NSMutableData * exifdata = [NSMutableData dataWithCapacity: [headerstring length]/2];
+                int idx;
+                for (idx = 0; idx+1 < [headerstring length]; idx+=2) {
+                    NSRange range = NSMakeRange(idx, 2);
+                    NSString* hexStr = [headerstring substringWithRange:range];
+                    NSScanner* scanner = [NSScanner scannerWithString:hexStr];
+                    unsigned int intValue;
+                    [scanner scanHexInt:&intValue];
+                    [exifdata appendBytes:&intValue length:1];
+                }
+               
+                NSMutableData * ddata = [NSMutableData dataWithCapacity: [data length]];
+                NSMakeRange(0,4);
+                int loc = 0;
+                bool done = false;
+                // read the jpeg data until we encounter the app1==0xFFE1 marker
+                while (loc+1 < [data length]) {
+                    NSData * blag = [data subdataWithRange: NSMakeRange(loc,2)];
+                    if( [[blag description] isEqualToString : @"<ffe1>"]) {
+                        // read the APP1 block size bits
+                        NSString * the = [exifWriter hexStringFromData:[data 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:[data subdataWithRange: NSMakeRange(loc,[data length]-loc)]];
+                data = ddata;
             }
 
             if (cameraPicker.returnType == DestinationTypeFileUri) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m b/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m
index ed9f664..d89e3d3 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m
@@ -169,7 +169,7 @@
     }
 
     // write to temp directory and return URI
-    NSString* docsPath = [NSTemporaryDirectory ()stringByStandardizingPath];  // use file system temporary directory
+    NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath];   // use file system temporary directory
     NSError* err = nil;
     NSFileManager* fileMgr = [[NSFileManager alloc] init];
 
@@ -439,7 +439,7 @@
         if ([command isKindOfClass:[CDVFile class]]) {
             CDVFile* cdvFile = (CDVFile*)command;
             NSString* mimeType = [cdvFile getMimeTypeFromPath:fullPath];
-            [fileDict setObject:(mimeType != nil ? (NSObject*)mimeType:[NSNull null]) forKey:@"type"];
+            [fileDict setObject:(mimeType != nil ? (NSObject*)mimeType : [NSNull null]) forKey:@"type"];
         }
     }
     NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:fullPath error:nil];
@@ -533,7 +533,6 @@
         // delegate to CVDAudioRecorderViewController
         return [self.topViewController supportedInterfaceOrientations];
     }
-
 #endif
 
 @end
@@ -663,7 +662,7 @@
 
     // create file to record to in temporary dir
 
-    NSString* docsPath = [NSTemporaryDirectory ()stringByStandardizingPath];  // use file system temporary directory
+    NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath];   // use file system temporary directory
     NSError* err = nil;
     NSFileManager* fileMgr = [[NSFileManager alloc] init];
 
@@ -701,7 +700,6 @@
         orientation = orientation | (supported & UIInterfaceOrientationMaskPortraitUpsideDown);
         return orientation;
     }
-
 #endif
 
 - (void)viewDidUnload
@@ -766,7 +764,7 @@
         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));
+                    UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, NSLocalizedString(@"timed recording complete", nil));
                 });
         }
     } else {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegate.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegate.h b/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegate.h
index e177c63..0401136 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegate.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegate.h
@@ -30,7 +30,6 @@
 
 - (NSString*)pathForResource:(NSString*)resourcepath;
 - (id)getCommandInstance:(NSString*)pluginName;
-- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className CDV_DEPRECATED(2.2, "Use CDVViewController to register plugins, or use config.xml.");
 
 // Plugins should not be using this interface to call other plugins since it
 // will result in bogus callbacks being made.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegateImpl.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegateImpl.m b/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegateImpl.m
index e399289..fa0e5e0 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegateImpl.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegateImpl.m
@@ -55,7 +55,11 @@
 
 - (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];
 }
@@ -78,21 +82,16 @@
 
 - (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]) {
+    if ([@"INVALID" isEqualToString : callbackId]) {
         return;
     }
     int status = [result.status intValue];
     BOOL keepCallback = [result.keepCallback boolValue];
-    id message = result.message == nil ? [NSNull null] : result.message;
+    NSString* argumentsAsJSON = [result argumentsAsJSON];
 
-    // Use an array to encode the message as JSON.
-    message = [NSArray arrayWithObject:message];
-    NSString* encodedMessage = [message JSONString];
-    // And then strip off the outer []s.
-    encodedMessage = [encodedMessage substringWithRange:NSMakeRange(1, [encodedMessage length] - 2)];
-    NSString* js = [NSString stringWithFormat:@"cordova.require('cordova/exec').nativeCallback('%@',%d,%@,%d)",
-        callbackId, status, encodedMessage, keepCallback];
+    NSString* js = [NSString stringWithFormat:@"cordova.require('cordova/exec').nativeCallback('%@',%d,%@,%d)", callbackId, status, argumentsAsJSON, keepCallback];
 
     [self evalJsHelper:js];
 }
@@ -122,11 +121,6 @@
     return [_viewController getCommandInstance:pluginName];
 }
 
-- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className
-{
-    [_viewController registerPlugin:plugin withClassName:className];
-}
-
 - (void)runInBackground:(void (^)())block
 {
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.h b/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.h
index ebdf844..27c47b5 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.h
@@ -22,13 +22,7 @@
 @class CDVInvokedUrlCommand;
 @class CDVViewController;
 
-@interface CDVCommandQueue : NSObject {
-    @private
-    NSInteger _lastCommandQueueFlushRequestId;
-    __weak CDVViewController* _viewController;
-    NSMutableArray* _queue;
-    BOOL _currentlyExecuting;
-}
+@interface CDVCommandQueue : NSObject
 
 @property (nonatomic, readonly) BOOL currentlyExecuting;
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.m b/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.m
index a8a58b7..1a0dfa0 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.m
@@ -23,6 +23,14 @@
 #import "CDVViewController.h"
 #import "CDVCommandDelegateImpl.h"
 
+@interface CDVCommandQueue () {
+    NSInteger _lastCommandQueueFlushRequestId;
+    __weak CDVViewController* _viewController;
+    NSMutableArray* _queue;
+    BOOL _currentlyExecuting;
+}
+@end
+
 @implementation CDVCommandQueue
 
 @synthesize currentlyExecuting = _currentlyExecuting;
@@ -74,6 +82,9 @@
         @"cordova.require('cordova/exec').nativeFetchMessages()"];
 
     [self enqueCommandBatch:queuedCommandsJSON];
+    if ([queuedCommandsJSON length] > 0) {
+        CDV_EXEC_LOG(@"Exec: Retrieved new exec messages by request.");
+    }
 }
 
 - (void)executePending
@@ -92,13 +103,15 @@
             // 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;
+                            [NSString stringWithFormat:@"%@[...]", [commandJson substringToIndex:maxLogLength]] :
+                            commandJson;
 
                         DLog(@"FAILED pluginJSON = %@", commandString);
 #endif

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.m b/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.m
index 6fd5913..ffc8ede 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.m
@@ -52,7 +52,7 @@
     } else if ([elementName isEqualToString:@"plugin"]) {
         NSString* name = [attributeDict[@"name"] lowercaseString];
         pluginsDict[name] = attributeDict[@"value"];
-        if ([@"true" isEqualToString:attributeDict[@"onload"]]) {
+        if ([@"true" isEqualToString : attributeDict[@"onload"]]) {
             [self.startupPluginNames addObject:name];
         }
     } else if ([elementName isEqualToString:@"access"]) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVConnection.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVConnection.m b/lib/cordova-ios/CordovaLib/Classes/CDVConnection.m
index 3030711..b3f5cab 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVConnection.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVConnection.m
@@ -52,7 +52,8 @@
             return @"none";
 
         case ReachableViaWWAN:
-            return @"2g"; // no generic default, so we use the lowest common denominator
+            // 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";
@@ -66,7 +67,8 @@
 {
     return [theConnectionType isEqualToString:@"2g"] ||
            [theConnectionType isEqualToString:@"3g"] ||
-           [theConnectionType isEqualToString:@"4g"];
+           [theConnectionType isEqualToString:@"4g"] ||
+           [theConnectionType isEqualToString:@"cellular"];
 }
 
 - (void)updateReachability:(CDVReachability*)reachability
@@ -111,6 +113,7 @@
         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) {
@@ -121,4 +124,9 @@
     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

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVContact.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVContact.m b/lib/cordova-ios/CordovaLib/Classes/CDVContact.m
index 9efaf10..3844525 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVContact.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVContact.m
@@ -38,7 +38,9 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
     if ((self = [super init]) != nil) {
         ABRecordRef rec = ABPersonCreate();
         self.record = rec;
-        CFRelease(rec);
+        if (rec) {
+            CFRelease(rec);
+        }
     }
     return self;
 }
@@ -167,9 +169,9 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
     if (org_apache_cordova_contacts_objectAndProperties == nil) {
         org_apache_cordova_contacts_objectAndProperties = [NSDictionary dictionaryWithObjectsAndKeys:
             [NSArray arrayWithObjects:kW3ContactGivenName, kW3ContactFamilyName,
-                kW3ContactMiddleName, kW3ContactHonorificPrefix, kW3ContactHonorificSuffix, kW3ContactFormattedName, nil], kW3ContactName,
+            kW3ContactMiddleName, kW3ContactHonorificPrefix, kW3ContactHonorificSuffix, kW3ContactFormattedName, nil], kW3ContactName,
             [NSArray arrayWithObjects:kW3ContactStreetAddress, kW3ContactLocality, kW3ContactRegion,
-                kW3ContactPostalCode, kW3ContactCountry, /*kW3ContactAddressFormatted,*/ nil], kW3ContactAddresses,
+            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,
@@ -228,7 +230,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
         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
+            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];
             }
@@ -298,9 +300,9 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
             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];
+            [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
@@ -658,7 +660,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
                             [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]];
+                            valueAB = [(__bridge NSDictionary*)existingDictionary valueForKey : [[CDVContact defaultW3CtoAB] valueForKey:k]];
                             if (valueAB != nil) {
                                 [dict setValue:valueAB forKey:[[CDVContact defaultW3CtoAB] valueForKey:k]];
                             }
@@ -893,7 +895,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
     if (data != nil) {
         [nc setObject:data forKey:kW3ContactName];
     }
-    if ([self.returnFields objectForKey:kW3ContactDisplayName] && ((data == nil) || ([(NSDictionary*) data objectForKey:kW3ContactFormattedName] == [NSNull null]))) {
+    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);
@@ -1114,7 +1116,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
             // always set id
             value = [NSNumber numberWithUnsignedInt:ABMultiValueGetIdentifierAtIndex(multi, i)];
             [newDict setObject:(value != nil) ? value:[NSNull null] forKey:kW3ContactFieldId];
-            [(NSMutableArray*) valuesArray addObject:newDict];
+            [(NSMutableArray*)valuesArray addObject : newDict];
         }
     } else {
         valuesArray = [NSNull null];
@@ -1188,7 +1190,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
             }
 
             if ([newAddress count] > 0) { // ?? this will always be true since we set id,label,primary field??
-                [(NSMutableArray*) addresses addObject:newAddress];
+                [(NSMutableArray*)addresses addObject : newAddress];
             }
             CFRelease(dict);
         } // end of loop through addresses
@@ -1244,7 +1246,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
                 bFound = CFDictionaryGetValueIfPresent(dict, kABPersonInstantMessageServiceKey, (void*)&value);
                 if (bFound && (value != NULL)) {
                     CFRetain(value);
-                    [newDict setObject:(id)[[CDVContact class] convertPropertyLabelToContactType:(__bridge NSString*)value] forKey:kW3ContactFieldType];
+                    [newDict setObject:(id)[[CDVContact class] convertPropertyLabelToContactType : (__bridge NSString*)value] forKey:kW3ContactFieldType];
                     CFRelease(value);
                 } else {
                     [newDict setObject:[NSNull null] forKey:kW3ContactFieldType];
@@ -1254,7 +1256,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
             id identifier = [NSNumber numberWithUnsignedInt:ABMultiValueGetIdentifierAtIndex(multi, i)];
             [newDict setObject:(identifier != nil) ? identifier:[NSNull null] forKey:kW3ContactFieldId];
 
-            [(NSMutableArray*) imArray addObject:newDict];
+            [(NSMutableArray*)imArray addObject : newDict];
             CFRelease(dict);
         }
     } else {
@@ -1308,7 +1310,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
         [newDict setObject:@"false" forKey:kW3ContactFieldPrimary];
         [newDict setObject:[NSNull null] forKey:kW3ContactFieldType];
         array = [NSMutableArray arrayWithCapacity:1];
-        [(NSMutableArray*) array addObject:newDict];
+        [(NSMutableArray*)array addObject : newDict];
     } else {
         array = [NSNull null];
     }
@@ -1327,7 +1329,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
         NSData* data = (__bridge NSData*)photoData;
         // write to temp directory and store URI in photos array
         // get the temp directory path
-        NSString* docsPath = [NSTemporaryDirectory ()stringByStandardizingPath];
+        NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath];
         NSError* err = nil;
         NSString* filePath = [NSString stringWithFormat:@"%@/photo_XXXXX", docsPath];
         char template[filePath.length + 1];

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVContacts.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVContacts.h b/lib/cordova-ios/CordovaLib/Classes/CDVContacts.h
index 17470c0..0342f5b 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVContacts.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVContacts.h
@@ -24,9 +24,9 @@
 #import "CDVContact.h"
 
 @interface CDVContacts : CDVPlugin <ABNewPersonViewControllerDelegate,
-    ABPersonViewControllerDelegate,
-    ABPeoplePickerNavigationControllerDelegate
-    >
+                         ABPersonViewControllerDelegate,
+                         ABPeoplePickerNavigationControllerDelegate
+                         >
 {
     ABAddressBookRef addressBook;
 }
@@ -63,7 +63,7 @@
 
 - (void)newPersonViewController:(ABNewPersonViewController*)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person;
 - (BOOL)personViewController:(ABPersonViewController*)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person
-   property                 :(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue;
+                    property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue;
 
 /*
  * search - searches for contacts.  Only person records are currently supported.
@@ -140,9 +140,9 @@
 - (CDVAddressBookAccessError*)initWithCode:(CDVContactError)code;
 @end
 
-typedef void (^CDVAddressBookWorkerBlock)(
-    ABAddressBookRef addressBook,
-    CDVAddressBookAccessError * error
+typedef void (^ CDVAddressBookWorkerBlock)(
+    ABAddressBookRef         addressBook,
+    CDVAddressBookAccessError* error
     );
 @interface CDVAddressBookHelper : NSObject
 {}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVContacts.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVContacts.m b/lib/cordova-ios/CordovaLib/Classes/CDVContacts.m
index 3faf6ba..6cb9f08 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVContacts.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVContacts.m
@@ -77,26 +77,26 @@
     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);
+    [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;
+        npController.newPersonViewDelegate = self;
+        npController.callbackId = callbackId;
 
-            UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:npController];
+        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];
-            }
-        }];
+        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
@@ -130,48 +130,48 @@
     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;
+    [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);
 
-                // create this so DisplayContactViewController will have a "back" button.
-                UIViewController* parentController = [[UIViewController alloc] init];
-                UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:parentController];
+        if (rec) {
+            CDVDisplayContactViewController* personController = [[CDVDisplayContactViewController alloc] init];
+            personController.displayedPerson = rec;
+            personController.personViewDelegate = self;
+            personController.allowsEditing = NO;
 
-                [navController pushViewController:personController animated:YES];
+            // create this so DisplayContactViewController will have a "back" button.
+            UIViewController* parentController = [[UIViewController alloc] init];
+            UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:parentController];
 
-                if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
-                    [self.viewController presentViewController:navController animated:YES completion:nil];
-                } else {
-                    [self.viewController presentModalViewController:navController animated:YES];
-                }
+            [navController pushViewController:personController 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];
-                }
+            if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
+                [self.viewController presentViewController:navController animated:YES completion:nil];
             } else {
-                // no record, return error
-                CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:UNKNOWN_ERROR];
-                [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
+                [self.viewController presentModalViewController:navController animated:YES];
             }
-            CFRelease (addrBook);
-        }];
+
+            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
@@ -284,95 +284,95 @@
     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;
-                    }
+        // 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);
-                        }
-                    }
+            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;
-                            }
-                        }
+            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;
                     }
-                    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];
-                            }
+                }
+            } 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;
                     }
-                    // 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);
+                }
+            }
+            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];
                     }
-                }];
-        }]; // end of workQueue block
+                }
+            }
+            // 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;
 }
@@ -383,81 +383,10 @@
     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
+        CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init];
+        CDVContacts* __weak weakSelf = self;     // play it safe to avoid retain cycles
 
-    [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError * errorCode) {
+        [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errorCode) {
             CDVPluginResult* result = nil;
             if (addrBook == NULL) {
                 // permission was denied or other error - return error
@@ -467,50 +396,121 @@
             }
 
             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]] && ([cId intValue] != kABRecordInvalidID)) {
-                rec = ABAddressBookGetPersonWithRecordID (addrBook, [cId intValue]);
+            if (cId && ![cId isKindOfClass:[NSNull class]]) {
+                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
+                    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 = UNKNOWN_ERROR;
+                    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 {
-                // invalid contact id provided
                 bIsError = TRUE;
-                errCode = INVALID_ARGUMENT_ERROR;
+                errCode = IO_ERROR;
             }
+            CFRelease(addrBook);
 
-            if (addrBook) {
-                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;
 }
 
@@ -569,24 +569,24 @@
             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 (), ^{
+                    // 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]);
+                            workerBlock(NULL, [[CDVAddressBookAccessError alloc] initWithCode:UNKNOWN_ERROR]);
                         } else if (!granted) {
-                            workerBlock (NULL, [[CDVAddressBookAccessError alloc] initWithCode:PERMISSION_DENIED_ERROR]);
+                            workerBlock(NULL, [[CDVAddressBookAccessError alloc] initWithCode:PERMISSION_DENIED_ERROR]);
                         } else {
                             // access granted
-                            workerBlock (addressBook, [[CDVAddressBookAccessError alloc] initWithCode:UNKNOWN_ERROR]);
+                            workerBlock(addressBook, [[CDVAddressBookAccessError alloc] initWithCode:UNKNOWN_ERROR]);
                         }
                     });
-            });
+                });
         } else
 #endif
     {
         // iOS 4 or 5 no checks needed
-        addressBook = ABAddressBookCreate ();
-        workerBlock (addressBook, NULL);
+        addressBook = ABAddressBookCreate();
+        workerBlock(addressBook, NULL);
     }
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVEcho.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVEcho.m b/lib/cordova-ios/CordovaLib/Classes/CDVEcho.m
index 916e315..c74990d 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVEcho.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVEcho.m
@@ -51,4 +51,11 @@
     [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

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVExif.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVExif.h b/lib/cordova-ios/CordovaLib/Classes/CDVExif.h
new file mode 100644
index 0000000..3e8adbd
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVExif.h
@@ -0,0 +1,43 @@
+/*
+ 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

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVFile.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFile.h b/lib/cordova-ios/CordovaLib/Classes/CDVFile.h
index 4862921..eaf8cbe 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFile.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFile.h
@@ -21,6 +21,7 @@
 #import "CDVPlugin.h"
 
 enum CDVFileError {
+    NO_ERROR = 0,
     NOT_FOUND_ERR = 1,
     SECURITY_ERR = 2,
     ABORT_ERR = 3,
@@ -76,6 +77,7 @@ extern NSString* const kCDVAssetsLibraryPrefix;
 
 - (void)readAsText:(CDVInvokedUrlCommand*)command;
 - (void)readAsDataURL:(CDVInvokedUrlCommand*)command;
+- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command;
 - (NSString*)getMimeTypeFromPath:(NSString*)fullPath;
 - (void)write:(CDVInvokedUrlCommand*)command;
 - (void)testFileExists:(CDVInvokedUrlCommand*)command;


[2/6] 2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.

Posted by fi...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h b/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
index f5b50eb..6e25a27 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
@@ -23,10 +23,10 @@
 #import "NSMutableArray+QueueAdditions.h"
 #import "CDVCommandDelegate.h"
 
-#define CDVPageDidLoadNotification @"CDVPageDidLoadNotification"
-#define CDVPluginHandleOpenURLNotification @"CDVPluginHandleOpenURLNotification"
-#define CDVPluginResetNotification @"CDVPluginResetNotification"
-#define CDVLocalNotification @"CDVLocalNotification"
+NSString* const CDVPageDidLoadNotification;
+NSString* const CDVPluginHandleOpenURLNotification;
+NSString* const CDVPluginResetNotification;
+NSString* const CDVLocalNotification;
 
 @interface CDVPlugin : NSObject {}
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m b/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m
index a42d241..8c932a0 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m
@@ -19,6 +19,11 @@
 
 #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;
@@ -41,7 +46,7 @@
         [[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:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onReset) name:CDVPluginResetNotification object:theWebView];
 
         self.webView = theWebView;
     }
@@ -64,7 +69,7 @@
     // [[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:nil];
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad:) name:CDVPageDidLoadNotification object:self.webView];
 }
 
 - (void)dispose

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.h b/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.h
index 8683205..11b5377 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.h
@@ -37,6 +37,9 @@ typedef enum {
 @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;
@@ -47,6 +50,7 @@ typedef enum {
 + (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;
@@ -54,6 +58,9 @@ typedef enum {
 
 - (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;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.m b/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.m
index d9ba08f..af7c528 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.m
@@ -29,10 +29,40 @@
 @end
 
 @implementation CDVPluginResult
-@synthesize status, message, keepCallback;
+@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",
@@ -101,17 +131,17 @@ static NSArray* org_apache_cordova_CommandStatusMsgs;
 
 + (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArrayBuffer:(NSData*)theMessage
 {
-    NSDictionary* arrDict = [NSDictionary dictionaryWithObjectsAndKeys:
-        @"ArrayBuffer", @"CDVType",
-        [theMessage base64EncodedString], @"data",
-        nil];
+    return [[self alloc] initWithStatus:statusOrdinal message:messageFromArrayBuffer(theMessage)];
+}
 
-    return [[self alloc] initWithStatus:statusOrdinal message:arrDict];
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsMultipart:(NSArray*)theMessages
+{
+    return [[self alloc] initWithStatus:statusOrdinal message:messageFromMultipart(theMessages)];
 }
 
 + (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageToErrorObject:(int)errorCode
 {
-    NSDictionary* errDict = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:errorCode] forKey:@"code"];
+    NSDictionary* errDict = @{@"code" :[NSNumber numberWithInt:errorCode]};
 
     return [[self alloc] initWithStatus:statusOrdinal message:errDict];
 }
@@ -121,6 +151,19 @@ static NSArray* org_apache_cordova_CommandStatusMsgs;
     [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:

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVReachability.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVReachability.m b/lib/cordova-ios/CordovaLib/Classes/CDVReachability.m
index 3c5a48b..89f4ec9 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVReachability.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVReachability.m
@@ -61,18 +61,18 @@ static void CDVPrintReachabilityFlags(SCNetworkReachabilityFlags flags, const ch
 {
 #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
-        );
+            (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
 }
 
@@ -90,7 +90,7 @@ static void CDVReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRe
         return;
     }
 
-    if (![(__bridge NSObject*) info isKindOfClass:[CDVReachability class]]) {
+    if (![(__bridge NSObject*)info isKindOfClass :[CDVReachability class]]) {
         NSLog(@"info was wrong class in ReachabilityCallback");
         return;
     }
@@ -214,7 +214,7 @@ static void CDVReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRe
     }
 
     if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand) != 0) ||
-            ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))) {
+        ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))) {
         // ... and the connection is on-demand (or on-traffic) if the
         //     calling application is using the CFSocketStream or higher APIs
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVSound.m b/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
index 99515d7..88fbbd6 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
@@ -87,7 +87,7 @@
         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];
+        NSString* tmpPath = [NSTemporaryDirectory()stringByStandardizingPath];
         BOOL isTmp = [resourcePath rangeOfString:tmpPath].location != NSNotFound;
         BOOL isDoc = [resourcePath rangeOfString:docsPath].location != NSNotFound;
         if (!isTmp && !isDoc) {
@@ -127,7 +127,7 @@
         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];
+            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;
@@ -385,7 +385,7 @@
             // 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];
+            NSString* filePath = [NSString stringWithFormat:@"%@/%@", [NSTemporaryDirectory()stringByStandardizingPath], uuidString];
             CFRelease(uuidString);
             CFRelease(uuidRef);
 
@@ -458,9 +458,19 @@
     double position = [[command.arguments objectAtIndex:1] doubleValue];
 
     if ((audioFile != nil) && (audioFile.player != nil)) {
+        NSString* jsString;
         double posInSeconds = position / 1000;
-        audioFile.player.currentTime = posInSeconds;
-        NSString* jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%f);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_POSITION, posInSeconds];
+        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];
     }
@@ -625,6 +635,7 @@
         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];

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h
index a0868a0..704ab43 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h
@@ -23,7 +23,8 @@
 @interface CDVSplashScreen : CDVPlugin {
     UIActivityIndicatorView* _activityView;
     UIImageView* _imageView;
-    UIView* _parentView;
+    NSString* _curImageName;
+    BOOL _visible;
 }
 
 - (void)show:(CDVInvokedUrlCommand*)command;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
index cba1b53..efe3eaa 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
@@ -19,29 +19,25 @@
 
 #import "CDVSplashScreen.h"
 
-#define kSplashScreenStateShow 0
-#define kSplashScreenStateHide 1
-
 #define kSplashScreenDurationDefault 0.25f
 
 @implementation CDVSplashScreen
 
 - (void)pluginInitialize
 {
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad) name:CDVPageDidLoadNotification object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationWillChange:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad) name:CDVPageDidLoadNotification object:self.webView];
 
-    [self show:nil];
+    [self setVisible:YES];
 }
 
 - (void)show:(CDVInvokedUrlCommand*)command
 {
-    [self updateSplashScreenWithState:kSplashScreenStateShow];
+    [self setVisible:YES];
 }
 
 - (void)hide:(CDVInvokedUrlCommand*)command
 {
-    [self updateSplashScreenWithState:kSplashScreenStateHide];
+    [self setVisible:NO];
 }
 
 - (void)pageDidLoad
@@ -50,16 +46,13 @@
 
     // if value is missing, default to yes
     if ((autoHideSplashScreenValue == nil) || [autoHideSplashScreenValue boolValue]) {
-        [self hide:nil];
+        [self setVisible:NO];
     }
 }
 
-- (void)onOrientationWillChange:(NSNotification*)notification
+- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
 {
-    if (_imageView != nil) {
-        UIInterfaceOrientation orientation = [notification.userInfo[UIApplicationStatusBarOrientationUserInfoKey] intValue];
-        [self updateSplashImageForOrientation:orientation];
-    }
+    [self updateImage];
 }
 
 - (void)createViews
@@ -83,43 +76,115 @@
         topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;
     }
 
+    UIView* parentView = self.viewController.view;
+    parentView.userInteractionEnabled = NO;  // disable user interaction while splashscreen is shown
     _activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:topActivityIndicatorStyle];
-    _activityView.tag = 2;
-    _activityView.center = self.viewController.view.center;
+    _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];
-    [self.viewController.view addSubview:_imageView];
-    [self.viewController.view.superview addSubview:_activityView];
-    [self.viewController.view.superview layoutSubviews];
+    [parentView addSubview:_imageView];
+    [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)updateSplashImageForOrientation:(UIInterfaceOrientation)orientation
+- (void)destroyViews
 {
-    // IPHONE (default)
-    NSString* imageName = @"Default";
+    [_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()) {
-        // set default to portrait upside down
-        imageName = @"Default-Portrait"; // @"Default-PortraitUpsideDown.png";
+        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;
+    }
+
+    [self updateBounds];
+}
 
-        if (orientation == UIInterfaceOrientationLandscapeLeft) {
-            imageName = @"Default-Landscape.png"; // @"Default-LandscapeLeft.png";
-        } else if (orientation == UIInterfaceOrientationLandscapeRight) {
-            imageName = @"Default-Landscape.png"; // @"Default-LandscapeRight.png";
+- (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];
+        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.image = [UIImage imageNamed:imageName];
-    _imageView.frame = CGRectMake(0, 0, _imageView.image.size.width, _imageView.image.size.height);
+    _imageView.frame = imgBounds;
 }
 
-- (void)updateSplashScreenWithState:(int)state
+- (void)setVisible:(BOOL)visible
 {
-    float toAlpha = state == kSplashScreenStateShow ? 1.0f : 0.0f;
-    BOOL hidden = state == kSplashScreenStateShow ? NO : YES;
+    if (visible == _visible) {
+        return;
+    }
+    _visible = visible;
 
     id fadeSplashScreenValue = [self.commandDelegate.settings objectForKey:@"FadeSplashScreen"];
     id fadeSplashScreenDuration = [self.commandDelegate.settings objectForKey:@"FadeSplashScreenDuration"];
@@ -129,45 +194,26 @@
     if ((fadeSplashScreenValue == nil) || ![fadeSplashScreenValue boolValue]) {
         fadeDuration = 0;
     }
-    if (hidden && (_imageView == nil)) {
-        return;
-    } else if (_imageView == nil) {
-        [self createViews];
-        fadeDuration = 0;
-    }
-
-    if (!hidden) {
-        [self updateSplashImageForOrientation:self.viewController.interfaceOrientation];
-    }
 
-    if (fadeDuration == 0) {
-        [_imageView setHidden:hidden];
-        [_activityView setHidden:hidden];
-    } else {
-        if (state == kSplashScreenStateShow) {
-            // reset states
-            [_imageView setHidden:NO];
-            [_activityView setHidden:NO];
-            [_imageView setAlpha:0.0f];
-            [_activityView setAlpha:0.0f];
+    // 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:toAlpha];
-                [_activityView setAlpha:toAlpha];
-            }
+            [_imageView setAlpha:0];
+            [_activityView setAlpha:0];
+        }
+
                         completion:^(BOOL finished) {
-                if (state == kSplashScreenStateHide) {
-                    // Clean-up resources.
-                    [_imageView removeFromSuperview];
-                    [_activityView removeFromSuperview];
-                    _imageView = nil;
-                    _activityView = nil;
-                }
-            }];
+            [self destroyViews];
+        }];
     }
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m b/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m
index 1959c77..afc10de 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m
@@ -31,7 +31,7 @@
 @property (nonatomic) NSInteger statusCode;
 @end
 
-static CDVWhitelist * gWhitelist = nil;
+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;
@@ -159,12 +159,12 @@ static CDVViewController *viewControllerForRequest(NSURLRequest* request)
         [self sendResponseWithResponseCode:200 data:nil mimeType:nil];
         return;
     } else if ([[url absoluteString] hasPrefix:kCDVAssetsLibraryPrefix]) {
-        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset * asset) {
+        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]);
+                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];
@@ -173,7 +173,7 @@ static CDVViewController *viewControllerForRequest(NSURLRequest* request)
                 [self sendResponseWithResponseCode:404 data:nil mimeType:nil];
             }
         };
-        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
             // Retrieving the asset failed for some reason.  Send an error.
             [self sendResponseWithResponseCode:401 data:nil mimeType:nil];
         };
@@ -202,7 +202,7 @@ static CDVViewController *viewControllerForRequest(NSURLRequest* request)
     if (mimeType == nil) {
         mimeType = @"text/plain";
     }
-    NSString* encodingName = [@"text/plain" isEqualToString:mimeType] ? @"UTF-8" : nil;
+    NSString* encodingName = [@"text/plain" isEqualToString : mimeType] ? @"UTF-8" : nil;
     CDVHTTPURLResponse* response =
         [[CDVHTTPURLResponse alloc] initWithURL:[[self request] URL]
                                        MIMEType:mimeType

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m b/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m
index 5c43c51..9923d47 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m
@@ -96,7 +96,7 @@ static NSMutableArray* gPendingSetUserAgentBlocks = nil;
         void (^block)() = [gPendingSetUserAgentBlocks objectAtIndex:0];
         [gPendingSetUserAgentBlocks removeObjectAtIndex:0];
         gCurrentLockToken = ++gNextLockToken;
-        NSLog (@"Gave lock %d", gCurrentLockToken);
+        NSLog(@"Gave lock %d", gCurrentLockToken);
         block(gCurrentLockToken);
     } else {
         gCurrentLockToken = 0;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h
index 82e22f6..2338baf 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h
@@ -22,15 +22,14 @@
 #import "CDVAvailability.h"
 #import "CDVInvokedUrlCommand.h"
 #import "CDVCommandDelegate.h"
+#import "CDVCommandQueue.h"
 #import "CDVWhitelist.h"
 #import "CDVScreenOrientationDelegate.h"
-
-@class CDVCommandQueue;
-@class CDVCommandDelegateImpl;
+#import "CDVPlugin.h"
 
 @interface CDVViewController : UIViewController <UIWebViewDelegate, CDVScreenOrientationDelegate>{
     @protected
-    CDVCommandDelegateImpl* _commandDelegate;
+    id <CDVCommandDelegate> _commandDelegate;
     @protected
     CDVCommandQueue* _commandQueue;
     NSString* _userAgent;
@@ -49,7 +48,7 @@
 @property (nonatomic, readwrite, copy) NSString* wwwFolderName;
 @property (nonatomic, readwrite, copy) NSString* startPage;
 @property (nonatomic, readonly, strong) CDVCommandQueue* commandQueue;
-@property (nonatomic, readonly, strong) CDVCommandDelegateImpl* commandDelegate;
+@property (nonatomic, readonly, strong) id <CDVCommandDelegate> commandDelegate;
 @property (nonatomic, readonly) NSString* userAgent;
 
 + (NSDictionary*)getBundlePlist:(NSString*)plistName;
@@ -67,6 +66,7 @@
 
 - (id)getCommandInstance:(NSString*)pluginName;
 - (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className;
+- (void)registerPlugin:(CDVPlugin*)plugin withPluginName:(NSString*)pluginName;
 
 - (BOOL)URLisAllowed:(NSURL*)url;
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
index bec716d..c7ad01b 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
@@ -19,7 +19,6 @@
 
 #import <objc/message.h>
 #import "CDV.h"
-#import "CDVCommandQueue.h"
 #import "CDVCommandDelegateImpl.h"
 #import "CDVConfigParser.h"
 #import "CDVUserAgentUtil.h"
@@ -103,6 +102,48 @@
     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")) {
@@ -208,9 +249,6 @@
     id backupWebStorage = self.settings[@"BackupWebStorage"];
     if ([backupWebStorage isKindOfClass:[NSString class]]) {
         backupWebStorageType = backupWebStorage;
-    } else if ([backupWebStorage isKindOfClass:[NSNumber class]]) {
-        NSLog(@"Deprecated: BackupWebStorage boolean property is a string property now (none, local, cloud). A boolean value of 'true' will be mapped to 'cloud'. Consult the docs: http://docs.cordova.io/en/edge/guide_project-settings_ios_index.md.html#Project%%20Settings%%20for%%20iOS");
-        backupWebStorageType = [(NSNumber*) backupWebStorage boolValue] ? @"cloud" : @"none";
     }
     self.settings[@"BackupWebStorage"] = backupWebStorageType;
 
@@ -231,6 +269,10 @@
     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];
 
@@ -239,15 +281,27 @@
      */
 
     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])];
+    if (IsAtLeastiOSVersion (@"5.1") && (([backupWebStorageType isEqualToString:@"local"]) ||
+            ([backupWebStorageType isEqualToString:@"cloud"] && !IsAtLeastiOSVersion (@"6.0")))) {
+        [self registerPlugin:[[CDVLocalStorage alloc] initWithWebView:self.webView] withClassName:NSStringFromClass ([CDVLocalStorage class])];
     }
 
     /*
@@ -260,12 +314,19 @@
         self.webView.mediaPlaybackRequiresUserAction = NO;
     }
 
-    // UIWebViewBounce property - defaults to true
-    NSNumber* bouncePreference = [self.settings objectForKey:@"UIWebViewBounce"];
-    BOOL bounceAllowed = (bouncePreference == nil || [bouncePreference boolValue]);
+    // By default, overscroll bouncing is allowed.
+    // UIWebViewBounce has been renamed to DisallowOverscroll, but both are checked.
+    BOOL bounceAllowed = YES;
+    NSNumber* disallowOverscroll = [self.settings objectForKey:@"DisallowOverscroll"];
+    if (disallowOverscroll == nil) {
+        NSNumber* bouncePreference = [self.settings objectForKey:@"UIWebViewBounce"];
+        bounceAllowed = (bouncePreference == nil || [bouncePreference boolValue]);
+    } else {
+        bounceAllowed = ![disallowOverscroll boolValue];
+    }
 
     // prevent webView from bouncing
-    // based on UIWebViewBounce key in config.xml
+    // based on the DisallowOverscroll/UIWebViewBounce key in config.xml
     if (!bounceAllowed) {
         if ([self.webView respondsToSelector:@selector(scrollView)]) {
             ((UIScrollView*)[self.webView scrollView]).bounces = NO;
@@ -281,7 +342,7 @@
     /*
      * iOS 6.0 UIWebView properties
      */
-    if (IsAtLeastiOSVersion(@"6.0")) {
+    if (IsAtLeastiOSVersion (@"6.0")) {
         BOOL keyboardDisplayRequiresUserAction = YES; // KeyboardDisplayRequiresUserAction - defaults to YES
         if ([self.settings objectForKey:@"KeyboardDisplayRequiresUserAction"] != nil) {
             if ([self.settings objectForKey:@"KeyboardDisplayRequiresUserAction"]) {
@@ -330,6 +391,34 @@
         }];
 }
 
+- (void)hideKeyboardFormAccessoryBar
+{
+    NSArray* windows = [[UIApplication sharedApplication] windows];
+
+    for (UIWindow* window in windows) {
+        for (UIView* view in window.subviews) {
+            if ([[view description] hasPrefix:@"<UIPeripheralHostView"]) {
+                for (UIView* peripheralView in view.subviews) {
+                    // hides the accessory bar
+                    if ([[peripheralView description] hasPrefix:@"<UIWebFormAccessory"]) {
+                        // remove the extra scroll space for the form accessory bar
+                        CGRect newFrame = self.webView.scrollView.frame;
+                        newFrame.size.height += peripheralView.frame.size.height;
+                        self.webView.scrollView.frame = newFrame;
+
+                        // remove the form accessory bar
+                        [peripheralView removeFromSuperview];
+                    }
+                    // hides the thin grey line used to adorn the bar (iOS 6)
+                    if ([[peripheralView description] hasPrefix:@"<UIImageView"]) {
+                        [[peripheralView layer] setOpacity:0.0];
+                    }
+                }
+            }
+        }
+    }
+}
+
 - (NSArray*)parseInterfaceOrientations:(NSArray*)orientations
 {
     NSMutableArray* result = [[NSMutableArray alloc] init];
@@ -531,7 +620,7 @@
 
     [self processOpenUrl];
 
-    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:nil]];
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:self.webView]];
 }
 
 - (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
@@ -660,6 +749,22 @@
     [plugin pluginInitialize];
 }
 
+- (void)registerPlugin:(CDVPlugin*)plugin withPluginName:(NSString*)pluginName
+{
+    if ([plugin respondsToSelector:@selector(setViewController:)]) {
+        [plugin setViewController:self];
+    }
+
+    if ([plugin respondsToSelector:@selector(setCommandDelegate:)]) {
+        [plugin setCommandDelegate:_commandDelegate];
+    }
+
+    NSString* className = NSStringFromClass([plugin class]);
+    [self.pluginObjects setObject:plugin forKey:className];
+    [self.pluginsMap setValue:className forKey:[pluginName lowercaseString]];
+    [plugin pluginInitialize];
+}
+
 /**
  Returns an instance of a CordovaCommand object, based on its name.  If one exists already, it is returned.
  */
@@ -814,13 +919,8 @@
 - (void)dealloc
 {
     [CDVURLProtocol unregisterViewController:self];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillTerminateNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSCurrentLocaleDidChangeNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:CDVPluginHandleOpenURLNotification object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+
     self.webView.delegate = nil;
     self.webView = nil;
     [CDVUserAgentUtil releaseLock:&_userAgentLockToken];

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m b/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m
index 9ee8186..a72bfb9 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m
@@ -68,7 +68,9 @@ typedef enum {
     if (![self isJsLoadTokenSet:webView]) {
         _state = STATE_WAITING_FOR_FINISH;
         [self setLoadToken:webView];
-        [_delegate webViewDidStartLoad:webView];
+        if ([_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
+            [_delegate webViewDidStartLoad:webView];
+        }
         [self pollForPageLoadFinish:webView];
     }
 }
@@ -80,7 +82,9 @@ typedef enum {
     }
     if ([self isPageLoaded:webView]) {
         _state = STATE_SHOULD_LOAD_MISSING;
-        [_delegate webViewDidFinishLoad:webView];
+        if ([_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
+            [_delegate webViewDidFinishLoad:webView];
+        }
     } else {
         [self performSelector:@selector(pollForPageLoaded) withObject:webView afterDelay:50];
     }
@@ -88,7 +92,11 @@ typedef enum {
 
 - (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
 {
-    BOOL shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
+    BOOL shouldLoad = YES;
+
+    if ([_delegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) {
+        shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
+    }
 
     if (shouldLoad) {
         BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]];
@@ -104,7 +112,9 @@ typedef enum {
 {
     if (_state == STATE_NORMAL) {
         if (_loadCount == 0) {
-            [_delegate webViewDidStartLoad:webView];
+            if ([_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
+                [_delegate webViewDidStartLoad:webView];
+            }
             _loadCount += 1;
         } else if (_loadCount > 0) {
             _loadCount += 1;
@@ -128,8 +138,10 @@ typedef enum {
 {
     if (_state == STATE_NORMAL) {
         if (_loadCount == 1) {
-            [_delegate webViewDidFinishLoad:webView];
-            _loadCount -= 1;
+            if ([_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
+                [_delegate webViewDidFinishLoad:webView];
+            }
+            _loadCount = -1;
         } else if (_loadCount > 1) {
             _loadCount -= 1;
         }
@@ -143,8 +155,10 @@ typedef enum {
 {
     if (_state == STATE_NORMAL) {
         if (_loadCount == 1) {
-            [_delegate webView:webView didFailLoadWithError:error];
-            _loadCount -= 1;
+            if ([_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
+                [_delegate webView:webView didFailLoadWithError:error];
+            }
+            _loadCount = -1;
         } else if (_loadCount > 1) {
             _loadCount -= 1;
         }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/NSData+Base64.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/NSData+Base64.m b/lib/cordova-ios/CordovaLib/Classes/NSData+Base64.m
index 08c801b..d0f2189 100644
--- a/lib/cordova-ios/CordovaLib/Classes/NSData+Base64.m
+++ b/lib/cordova-ios/CordovaLib/Classes/NSData+Base64.m
@@ -249,13 +249,10 @@ char *CDVNewBase64Encode(
 //
 + (NSData*)dataFromBase64String:(NSString*)aString
 {
-    NSData* data = [aString dataUsingEncoding:NSASCIIStringEncoding];
-    size_t outputLength;
-    void* outputBuffer = CDVNewBase64Decode([data bytes], [data length], &outputLength);
-    NSData* result = [NSData dataWithBytes:outputBuffer length:outputLength];
+    size_t outputLength = 0;
+    void* outputBuffer = CDVNewBase64Decode([aString UTF8String], [aString length], &outputLength);
 
-    free(outputBuffer);
-    return result;
+    return [NSData dataWithBytesNoCopy:outputBuffer length:outputLength freeWhenDone:YES];
 }
 
 //
@@ -273,13 +270,11 @@ char *CDVNewBase64Encode(
     char* outputBuffer =
         CDVNewBase64Encode([self bytes], [self length], true, &outputLength);
 
-    NSString* result =
-        [[NSString alloc]
-        initWithBytes:outputBuffer
-               length:outputLength
-             encoding:NSASCIIStringEncoding];
+    NSString* result = [[NSString alloc] initWithBytesNoCopy:outputBuffer
+                                                      length:outputLength
+                                                    encoding:NSASCIIStringEncoding
+                                                freeWhenDone:YES];
 
-    free(outputBuffer);
     return result;
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/NSDictionary+Extensions.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/NSDictionary+Extensions.m b/lib/cordova-ios/CordovaLib/Classes/NSDictionary+Extensions.m
index 80e9ac1..0361ff9 100644
--- a/lib/cordova-ios/CordovaLib/Classes/NSDictionary+Extensions.m
+++ b/lib/cordova-ios/CordovaLib/Classes/NSDictionary+Extensions.m
@@ -28,7 +28,7 @@
     bool exists = false;
 
     if (val != nil) {
-        exists = [(NSString*) val compare:expectedValue options:NSCaseInsensitiveSearch] == 0;
+        exists = [(NSString*)val compare : expectedValue options : NSCaseInsensitiveSearch] == 0;
     }
 
     return exists;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj b/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
index 4868020..e14f1f6 100644
--- a/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
+++ b/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
@@ -44,6 +44,9 @@
 		30F5EBAB14CA26E700987760 /* CDVCommandDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 30F5EBA914CA26E700987760 /* CDVCommandDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		3E76876D156A90EE00EB6FA3 /* CDVLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E76876B156A90EE00EB6FA3 /* CDVLogger.m */; };
 		3E76876F156A90EE00EB6FA3 /* CDVLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 3E76876C156A90EE00EB6FA3 /* CDVLogger.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		68B7516E16FD18190076A8B4 /* CDVJpegHeaderWriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B7516B16FD18190076A8B4 /* CDVJpegHeaderWriter.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		68B7516F16FD18190076A8B4 /* CDVJpegHeaderWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 68B7516C16FD18190076A8B4 /* CDVJpegHeaderWriter.m */; };
+		68B7517016FD19F80076A8B4 /* CDVExif.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B7516A16FD18190076A8B4 /* CDVExif.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		8852C43A14B65FD800F0E735 /* CDVViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8852C43614B65FD800F0E735 /* CDVViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		8852C43C14B65FD800F0E735 /* CDVViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8852C43714B65FD800F0E735 /* CDVViewController.m */; };
 		8887FD661090FBE7009987E8 /* CDVCamera.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD261090FBE7009987E8 /* CDVCamera.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -141,6 +144,10 @@
 		686357DC14100B1600DF4CF2 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
 		68A32D7114102E1C006B237C /* libCordova.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCordova.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		68A32D7414103017006B237C /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; };
+		68B7516A16FD18190076A8B4 /* CDVExif.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVExif.h; path = Classes/CDVExif.h; sourceTree = "<group>"; };
+		68B7516B16FD18190076A8B4 /* CDVJpegHeaderWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVJpegHeaderWriter.h; path = Classes/CDVJpegHeaderWriter.h; sourceTree = "<group>"; };
+		68B7516C16FD18190076A8B4 /* CDVJpegHeaderWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVJpegHeaderWriter.m; path = Classes/CDVJpegHeaderWriter.m; sourceTree = "<group>"; };
+		8220B5C316D5427E00EC3921 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
 		8852C43614B65FD800F0E735 /* CDVViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVViewController.h; path = Classes/CDVViewController.h; sourceTree = "<group>"; };
 		8852C43714B65FD800F0E735 /* CDVViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVViewController.m; path = Classes/CDVViewController.m; sourceTree = "<group>"; };
 		8887FD261090FBE7009987E8 /* CDVCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVCamera.h; path = Classes/CDVCamera.h; sourceTree = "<group>"; };
@@ -223,6 +230,7 @@
 			isa = PBXGroup;
 			children = (
 				68A32D7414103017006B237C /* AddressBook.framework */,
+				8220B5C316D5427E00EC3921 /* AssetsLibrary.framework */,
 				686357DC14100B1600DF4CF2 /* CoreMedia.framework */,
 				686357CE14100ADA00DF4CF2 /* AudioToolbox.framework */,
 				686357CF14100ADB00DF4CF2 /* AVFoundation.framework */,
@@ -292,6 +300,9 @@
 				8887FD271090FBE7009987E8 /* CDVCamera.m */,
 				1F584B991385A28900ED25E8 /* CDVCapture.h */,
 				1F584B9A1385A28900ED25E8 /* CDVCapture.m */,
+				68B7516A16FD18190076A8B4 /* CDVExif.h */,
+				68B7516B16FD18190076A8B4 /* CDVJpegHeaderWriter.h */,
+				68B7516C16FD18190076A8B4 /* CDVJpegHeaderWriter.m */,
 				1F3C04CC12BC247D004F9E10 /* CDVContact.h */,
 				1F3C04CD12BC247D004F9E10 /* CDVContact.m */,
 				8887FD2A1090FBE7009987E8 /* CDVContacts.h */,
@@ -364,6 +375,8 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				68B7517016FD19F80076A8B4 /* CDVExif.h in Headers */,
+				68B7516E16FD18190076A8B4 /* CDVJpegHeaderWriter.h in Headers */,
 				8887FD661090FBE7009987E8 /* CDVCamera.h in Headers */,
 				8887FD681090FBE7009987E8 /* NSDictionary+Extensions.h in Headers */,
 				8887FD6A1090FBE7009987E8 /* CDVContacts.h in Headers */,
@@ -502,6 +515,7 @@
 				30F3930C169F839700B22307 /* CDVJSON.m in Sources */,
 				EB96673C16A8970A00D86CDF /* CDVUserAgentUtil.m in Sources */,
 				EBFF4DBC16D3FE2E008F452B /* CDVWebViewDelegate.m in Sources */,
+				68B7516F16FD18190076A8B4 /* CDVJpegHeaderWriter.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/VERSION b/lib/cordova-ios/CordovaLib/VERSION
index 437459c..f47de85 100644
--- a/lib/cordova-ios/CordovaLib/VERSION
+++ b/lib/cordova-ios/CordovaLib/VERSION
@@ -1 +1 @@
-2.5.0
+2.6.0rc1

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/cordova.ios.js
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/cordova.ios.js b/lib/cordova-ios/CordovaLib/cordova.ios.js
index 3d83df3..8ed1706 100644
--- a/lib/cordova-ios/CordovaLib/cordova.ios.js
+++ b/lib/cordova-ios/CordovaLib/cordova.ios.js
@@ -1,8 +1,8 @@
 // Platform: ios
 
-// commit f50d20a87431c79a54572263729461883f611a53
+// commit 47593b2bc1dba9bf46545b1da24577f937966e12
 
-// File generated at :: Tue Feb 26 2013 14:26:19 GMT-0800 (PST)
+// File generated at :: Thu Mar 21 2013 15:44:06 GMT-0700 (PDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -262,7 +262,7 @@ var cordova = {
      */
     callbackSuccess: function(callbackId, args) {
         try {
-            cordova.callbackFromNative(callbackId, true, args.status, args.message, args.keepCallback);
+            cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
         } catch (e) {
             console.log("Error in error callback: " + callbackId + " = "+e);
         }
@@ -275,7 +275,7 @@ var cordova = {
         // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
         // Derive success from status.
         try {
-            cordova.callbackFromNative(callbackId, false, args.status, args.message, args.keepCallback);
+            cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
         } catch (e) {
             console.log("Error in error callback: " + callbackId + " = "+e);
         }
@@ -284,13 +284,13 @@ var cordova = {
     /**
      * Called by native code when returning the result from an action.
      */
-    callbackFromNative: function(callbackId, success, status, message, keepCallback) {
+    callbackFromNative: function(callbackId, success, status, args, keepCallback) {
         var callback = cordova.callbacks[callbackId];
         if (callback) {
             if (success && status == cordova.callbackStatus.OK) {
-                callback.success && callback.success(message);
+                callback.success && callback.success.apply(null, args);
             } else if (!success) {
-                callback.fail && callback.fail(message);
+                callback.fail && callback.fail.apply(null, args);
             }
 
             // Clear callback if not expecting any more results
@@ -724,6 +724,9 @@ channel.createSticky('onCordovaInfoReady');
 // Event to indicate that the connection property has been set.
 channel.createSticky('onCordovaConnectionReady');
 
+// Event to indicate that all automatically loaded JS plugins are loaded and ready.
+channel.createSticky('onPluginsReady');
+
 // Event to indicate that Cordova is ready
 channel.createSticky('onDeviceReady');
 
@@ -826,6 +829,7 @@ function massageArgsJsToNative(args) {
     if (!args || utils.typeName(args) != 'Array') {
        return args;
     }
+    var ret = [];
     var encodeArrayBufferAs8bitString = function(ab) {
         return String.fromCharCode.apply(null, new Uint8Array(ab));
     };
@@ -834,17 +838,19 @@ function massageArgsJsToNative(args) {
     };
     args.forEach(function(arg, i) {
         if (utils.typeName(arg) == 'ArrayBuffer') {
-            args[i] = {
+            ret.push({
                 'CDVType': 'ArrayBuffer',
                 'data': encodeArrayBufferAsBase64(arg)
-            };
+            });
+        } else {
+            ret.push(arg);
         }
     });
-    return args;
+    return ret;
 }
 
-function massagePayloadNativeToJs(payload) {
-    if (payload && payload.hasOwnProperty('CDVType') && payload.CDVType == 'ArrayBuffer') {
+function massageMessageNativeToJs(message) {
+    if (message.CDVType == 'ArrayBuffer') {
         var stringToArrayBuffer = function(str) {
             var ret = new Uint8Array(str.length);
             for (var i = 0; i < str.length; i++) {
@@ -855,9 +861,23 @@ function massagePayloadNativeToJs(payload) {
         var base64ToArrayBuffer = function(b64) {
             return stringToArrayBuffer(atob(b64));
         };
-        payload = base64ToArrayBuffer(payload.data);
+        message = base64ToArrayBuffer(message.data);
+    }
+    return message;
+}
+
+function convertMessageToArgsNativeToJs(message) {
+    var args = [];
+    if (!message || !message.hasOwnProperty('CDVType')) {
+        args.push(message);
+    } else if (message.CDVType == 'MultiPart') {
+        message.messages.forEach(function(e) {
+            args.push(massageMessageNativeToJs(e));
+        });
+    } else {
+        args.push(massageMessageNativeToJs(message));
     }
-    return payload;
+    return args;
 }
 
 function iOSExec() {
@@ -964,11 +984,11 @@ iOSExec.nativeFetchMessages = function() {
     return json;
 };
 
-iOSExec.nativeCallback = function(callbackId, status, payload, keepCallback) {
+iOSExec.nativeCallback = function(callbackId, status, message, keepCallback) {
     return iOSExec.nativeEvalAndFetch(function() {
         var success = status === 0 || status === 1;
-        payload = massagePayloadNativeToJs(payload);
-        cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);
+        var args = convertMessageToArgsNativeToJs(message);
+        cordova.callbackFromNative(callbackId, success, status, args, keepCallback);
     });
 };
 
@@ -1161,9 +1181,10 @@ cameraExport.getPicture = function(successCallback, errorCallback, options) {
     var correctOrientation = !!options.correctOrientation;
     var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
     var popoverOptions = getValue(options.popoverOptions, null);
+    var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
 
     var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
-                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions];
+                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
 
     exec(successCallback, errorCallback, "Camera", "takePicture", args);
     return new CameraPopoverHandle();
@@ -1206,6 +1227,10 @@ module.exports = {
       ARROW_LEFT : 4,
       ARROW_RIGHT : 8,
       ARROW_ANY : 15
+  },
+  Direction:{
+      BACK: 0,
+      FRONT: 1
   }
 };
 
@@ -2398,14 +2423,7 @@ FileReader.prototype.readAsText = function(file, encoding) {
     // Default encoding is UTF-8
     var enc = encoding ? encoding : "UTF-8";
     var me = this;
-    var execArgs = [this._fileName, enc];
-
-    // Maybe add slice parameters.
-    if (file.end < file.size) {
-        execArgs.push(file.start, file.end);
-    } else if (file.start > 0) {
-        execArgs.push(file.start);
-    }
+    var execArgs = [this._fileName, enc, file.start, file.end];
 
     // Read file
     exec(
@@ -2474,14 +2492,7 @@ FileReader.prototype.readAsDataURL = function(file) {
     }
 
     var me = this;
-    var execArgs = [this._fileName];
-
-    // Maybe add slice parameters.
-    if (file.end < file.size) {
-        execArgs.push(file.start, file.end);
-    } else if (file.start > 0) {
-        execArgs.push(file.start);
-    }
+    var execArgs = [this._fileName, file.start, file.end];
 
     // Read file
     exec(
@@ -2544,9 +2555,59 @@ FileReader.prototype.readAsBinaryString = function(file) {
     if (initRead(this, file)) {
         return this._realReader.readAsBinaryString(file);
     }
-    // TODO - Can't return binary data to browser.
-    console.log('method "readAsBinaryString" is not supported at this time.');
-    this.abort();
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsBinaryString", execArgs);
 };
 
 /**
@@ -2558,9 +2619,59 @@ FileReader.prototype.readAsArrayBuffer = function(file) {
     if (initRead(this, file)) {
         return this._realReader.readAsArrayBuffer(file);
     }
-    // TODO - Can't return binary data to browser.
-    console.log('This method is not supported at this time.');
-    this.abort();
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsArrayBuffer", execArgs);
 };
 
 module.exports = FileReader;
@@ -2606,6 +2717,38 @@ function newProgressEvent(result) {
     return pe;
 }
 
+function getBasicAuthHeader(urlString) {
+    var header =  null;
+
+    if (window.btoa) {
+        // parse the url using the Location object
+        var url = document.createElement('a');
+        url.href = urlString;
+
+        var credentials = null;
+        var protocol = url.protocol + "//";
+        var origin = protocol + url.host;
+
+        // check whether there are the username:password credentials in the url
+        if (url.href.indexOf(origin) != 0) { // credentials found
+            var atIndex = url.href.indexOf("@");
+            credentials = url.href.substring(protocol.length, atIndex);
+        }
+
+        if (credentials) {
+            var authHeader = "Authorization";
+            var authHeaderValue = "Basic " + window.btoa(credentials);
+
+            header = {
+                name : authHeader,
+                value : authHeaderValue
+            };
+        }
+    }
+
+    return header;
+}
+
 var idCounter = 0;
 
 /**
@@ -2636,6 +2779,18 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
     var params = null;
     var chunkedMode = true;
     var headers = null;
+
+    var basicAuthHeader = getBasicAuthHeader(server);
+    if (basicAuthHeader) {
+        if (!options) {
+            options = new FileUploadOptions();
+        }
+        if (!options.headers) {
+            options.headers = {};
+        }
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
     if (options) {
         fileKey = options.fileKey;
         fileName = options.fileName;
@@ -2653,7 +2808,7 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
     }
 
     var fail = errorCallback && function(e) {
-        var error = new FileTransferError(e.code, e.source, e.target, e.http_status);
+        var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
         errorCallback(error);
     };
 
@@ -2677,10 +2832,28 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
  * @param successCallback (Function}  Callback to be invoked when upload has completed
  * @param errorCallback {Function}    Callback to be invoked upon error
  * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+ * @param options {FileDownloadOptions} Optional parameters such as headers
  */
-FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts) {
+FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts, options) {
     argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
     var self = this;
+
+    var basicAuthHeader = getBasicAuthHeader(source);
+    if (basicAuthHeader) {
+        if (!options) {
+            options = {};
+        }
+        if (!options.headers) {
+            options.headers = {};
+        }
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
+    var headers = null;
+    if (options) {
+        headers = options.headers || null;
+    }
+
     var win = function(result) {
         if (typeof result.lengthComputable != "undefined") {
             if (self.onprogress) {
@@ -2703,11 +2876,11 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
     };
 
     var fail = errorCallback && function(e) {
-        var error = new FileTransferError(e.code, e.source, e.target, e.http_status);
+        var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
         errorCallback(error);
     };
 
-    exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id]);
+    exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id, headers]);
 };
 
 /**
@@ -3105,6 +3278,7 @@ function InAppBrowser() {
    this.channels = {
         'loadstart': channel.create('loadstart'),
         'loadstop' : channel.create('loadstop'),
+        'loaderror' : channel.create('loaderror'),
         'exit' : channel.create('exit')
    };
 }
@@ -3135,7 +3309,7 @@ module.exports = function(strUrl, strWindowName, strWindowFeatures) {
     var cb = function(eventname) {
        iab._eventHandler(eventname);
     };
-    exec(cb, null, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
+    exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
     return iab;
 };
 
@@ -4341,7 +4515,8 @@ modulemapper.clobbers('cordova/plugin/device', 'device');
 // file: lib/common/plugin/echo.js
 define("cordova/plugin/echo", function(require, exports, module) {
 
-var exec = require('cordova/exec');
+var exec = require('cordova/exec'),
+    utils = require('cordova/utils');
 
 /**
  * Sends the given message through exec() to the Echo plugin, which sends it back to the successCallback.
@@ -4351,11 +4526,25 @@ var exec = require('cordova/exec');
  * @param forceAsync  Whether to force an async return value (for testing native->js bridge).
  */
 module.exports = function(successCallback, errorCallback, message, forceAsync) {
-    var action = forceAsync ? 'echoAsync' : 'echo';
-    if (!forceAsync && message.constructor == ArrayBuffer) {
-        action = 'echoArrayBuffer';
+    var action = 'echo';
+    var messageIsMultipart = (utils.typeName(message) == "Array");
+    var args = messageIsMultipart ? message : [message];
+
+    if (utils.typeName(message) == 'ArrayBuffer') {
+        if (forceAsync) {
+            console.warn('Cannot echo ArrayBuffer with forced async, falling back to sync.');
+        }
+        action += 'ArrayBuffer';
+    } else if (messageIsMultipart) {
+        if (forceAsync) {
+            console.warn('Cannot echo MultiPart Array with forced async, falling back to sync.');
+        }
+        action += 'MultiPart';
+    } else if (forceAsync) {
+        action += 'Async';
     }
-    exec(successCallback, errorCallback, "Echo", action, [message]);
+
+    exec(successCallback, errorCallback, "Echo", action, args);
 };
 
 
@@ -5086,7 +5275,7 @@ function stringify(message) {
                 return "error JSON.stringify()ing argument: " + e;
             }
         } else {
-            return message.toString();
+            return (typeof message === "undefined") ? "undefined" : message.toString();
         }
     } catch (e) {
         return e.toString();
@@ -5100,10 +5289,20 @@ function stringify(message) {
 function wrappedMethod(console, method) {
     var origMethod = console[method];
 
-    return function(message) {
+    return function() {
+
+        var args = [].slice.call(arguments),
+            len = args.length,
+            i = 0,
+            res = [];
+
+        for ( ; i < len; i++) {
+            res.push(stringify(args[i]));
+        }
+
         exec(null, null,
             'Debug Console', 'log',
-            [ stringify(message), { logLevel: method.toUpperCase() } ]
+            [ res.join(' '), { logLevel: method.toUpperCase() } ]
         );
 
         if (!origMethod) return;
@@ -5572,6 +5771,7 @@ modulemapper.defaults('cordova/plugin/Connection', 'Connection');
 define("cordova/plugin/notification", function(require, exports, module) {
 
 var exec = require('cordova/exec');
+var platform = require('cordova/platform');
 
 /**
  * Provides access to notifications on the device.
@@ -5600,15 +5800,53 @@ module.exports = {
      * @param {String} message              Message to print in the body of the alert
      * @param {Function} resultCallback     The callback that is called when user clicks on a button.
      * @param {String} title                Title of the alert dialog (default: Confirm)
-     * @param {String} buttonLabels         Comma separated list of the labels of the buttons (default: 'OK,Cancel')
+     * @param {Array} buttonLabels          Array of the labels of the buttons (default: ['OK', 'Cancel'])
      */
     confirm: function(message, resultCallback, title, buttonLabels) {
         var _title = (title || "Confirm");
-        var _buttonLabels = (buttonLabels || "OK,Cancel");
+        var _buttonLabels = (buttonLabels || ["OK", "Cancel"]);
+
+        // Strings are deprecated!
+        if (typeof _buttonLabels === 'string') {
+            console.log("Notification.confirm(string, function, string, string) is deprecated.  Use Notification.confirm(string, function, string, array).");
+        }
+
+        // Android and iOS take an array of button label names.
+        // Other platforms take a comma separated list.
+        // For compatibility, we convert to the desired type based on the platform.
+        if (platform.id == "android" || platform.id == "ios") {
+            if (typeof _buttonLabels === 'string') {
+                var buttonLabelString = _buttonLabels;
+                _buttonLabels = buttonLabelString.split(",");
+            }
+        } else {
+            if (Array.isArray(_buttonLabels)) {
+                var buttonLabelArray = _buttonLabels;
+                _buttonLabels = buttonLabelArray.toString();
+            }
+        }
         exec(resultCallback, null, "Notification", "confirm", [message, _title, _buttonLabels]);
     },
 
     /**
+     * Open a native prompt dialog, with a customizable title and button text.
+     * The following results are returned to the result callback:
+     *  buttonIndex     Index number of the button selected.
+     *  input1          The text entered in the prompt dialog box.
+     *
+     * @param {String} message              Dialog message to display (default: "Prompt message")
+     * @param {Function} resultCallback     The callback that is called when user clicks on a button.
+     * @param {String} title                Title of the dialog (default: "Prompt")
+     * @param {Array} buttonLabels          Array of strings for the button labels (default: ["OK","Cancel"])
+     */
+    prompt: function(message, resultCallback, title, buttonLabels) {
+        var _message = (message || "Prompt message");
+        var _title = (title || "Prompt");
+        var _buttonLabels = (buttonLabels || ["OK","Cancel"]);
+        exec(resultCallback, null, "Notification", "prompt", [_message, _title, _buttonLabels]);
+    },
+
+    /**
      * Causes the device to vibrate.
      *
      * @param {Integer} mills       The number of milliseconds to vibrate for.
@@ -6031,53 +6269,160 @@ window.cordova = require('cordova');
 (function (context) {
     // Replace navigator before any modules are required(), to ensure it happens as soon as possible.
     // We replace it so that properties that can't be clobbered can instead be overridden.
-    if (context.navigator) {
+    function replaceNavigator(origNavigator) {
         var CordovaNavigator = function() {};
-        CordovaNavigator.prototype = context.navigator;
-        context.navigator = new CordovaNavigator();
+        CordovaNavigator.prototype = origNavigator;
+        var newNavigator = new CordovaNavigator();
+        // This work-around really only applies to new APIs that are newer than Function.bind.
+        // Without it, APIs such as getGamepads() break.
+        if (CordovaNavigator.bind) {
+            for (var key in origNavigator) {
+                if (typeof origNavigator[key] == 'function') {
+                    newNavigator[key] = origNavigator[key].bind(origNavigator);
+                }
+            }
+        }
+        return newNavigator;
+    }
+    if (context.navigator) {
+        context.navigator = replaceNavigator(context.navigator);
     }
 
-    var channel = require("cordova/channel"),
-        _self = {
-            boot: function () {
-                /**
-                 * Create all cordova objects once page has fully loaded and native side is ready.
-                 */
-                channel.join(function() {
-                    var builder = require('cordova/builder'),
-                        platform = require('cordova/platform');
+    var channel = require("cordova/channel");
+
+    // _nativeReady is global variable that the native side can set
+    // to signify that the native code is ready. It is a global since
+    // it may be called before any cordova JS is ready.
+    if (window._nativeReady) {
+        channel.onNativeReady.fire();
+    }
+
+    /**
+     * Create all cordova objects once page has fully loaded and native side is ready.
+     */
+    channel.join(function() {
+        var builder = require('cordova/builder'),
+            platform = require('cordova/platform');
+
+        builder.buildIntoButDoNotClobber(platform.defaults, context);
+        builder.buildIntoAndClobber(platform.clobbers, context);
+        builder.buildIntoAndMerge(platform.merges, context);
+
+        // Call the platform-specific initialization
+        platform.initialize();
+
+        // Fire event to notify that all objects are created
+        channel.onCordovaReady.fire();
+
+        // Fire onDeviceReady event once all constructors have run and
+        // cordova info has been received from native side.
+        channel.join(function() {
+            require('cordova').fireDocumentEvent('deviceready');
+        }, channel.deviceReadyChannelsArray);
+
+    }, [ channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady ]);
+
+}(window));
+
+// file: lib/scripts/plugin_loader.js
 
-                    builder.buildIntoButDoNotClobber(platform.defaults, context);
-                    builder.buildIntoAndClobber(platform.clobbers, context);
-                    builder.buildIntoAndMerge(platform.merges, context);
+// Tries to load all plugins' js-modules.
+// This is an async process, but onDeviceReady is blocked on onPluginsReady.
+// onPluginsReady is fired when there are no plugins to load, or they are all done.
+(function (context) {
+    // To be populated with the handler by handlePluginsObject.
+    var onScriptLoadingComplete;
+
+    var scriptCounter = 0;
+    function scriptLoadedCallback() {
+        scriptCounter--;
+        if (scriptCounter === 0) {
+            onScriptLoadingComplete && onScriptLoadingComplete();
+        }
+    }
+
+    // Helper function to inject a <script> tag.
+    function injectScript(path) {
+        scriptCounter++;
+        var script = document.createElement("script");
+        script.onload = scriptLoadedCallback;
+        script.src = path;
+        document.head.appendChild(script);
+    }
 
-                    // Call the platform-specific initialization
-                    platform.initialize();
+    // Called when:
+    // * There are plugins defined and all plugins are finished loading.
+    // * There are no plugins to load.
+    function finishPluginLoading() {
+        context.cordova.require('cordova/channel').onPluginsReady.fire();
+    }
 
-                    // Fire event to notify that all objects are created
-                    channel.onCordovaReady.fire();
+    // Handler for the cordova_plugins.json content.
+    // See plugman's plugin_loader.js for the details of this object.
+    // This function is only called if the really is a plugins array that isn't empty.
+    // Otherwise the XHR response handler will just call finishPluginLoading().
+    function handlePluginsObject(modules) {
+        // First create the callback for when all plugins are loaded.
+        var mapper = context.cordova.require('cordova/modulemapper');
+        onScriptLoadingComplete = function() {
+            // Loop through all the plugins and then through their clobbers and merges.
+            for (var i = 0; i < modules.length; i++) {
+                var module = modules[i];
+                if (!module) continue;
+
+                if (module.clobbers && module.clobbers.length) {
+                    for (var j = 0; j < module.clobbers.length; j++) {
+                        mapper.clobbers(module.id, module.clobbers[j]);
+                    }
+                }
 
-                    // Fire onDeviceReady event once all constructors have run and
-                    // cordova info has been received from native side.
-                    channel.join(function() {
-                        require('cordova').fireDocumentEvent('deviceready');
-                    }, channel.deviceReadyChannelsArray);
+                if (module.merges && module.merges.length) {
+                    for (var k = 0; k < module.merges.length; k++) {
+                        mapper.merges(module.id, module.merges[k]);
+                    }
+                }
 
-                }, [ channel.onDOMContentLoaded, channel.onNativeReady ]);
+                // Finally, if runs is truthy we want to simply require() the module.
+                // This can be skipped if it had any merges or clobbers, though,
+                // since the mapper will already have required the module.
+                if (module.runs && !(module.clobbers && module.clobbers.length) && !(module.merges && module.merges.length)) {
+                    context.cordova.require(module.id);
+                }
             }
-        };
 
-    // boot up once native side is ready
-    channel.onNativeReady.subscribe(_self.boot);
+            finishPluginLoading();
+        };
 
-    // _nativeReady is global variable that the native side can set
-    // to signify that the native code is ready. It is a global since
-    // it may be called before any cordova JS is ready.
-    if (window._nativeReady) {
-        channel.onNativeReady.fire();
+        // Now inject the scripts.
+        for (var i = 0; i < modules.length; i++) {
+            injectScript(modules[i].file);
+        }
     }
 
+    // Try to XHR the cordova_plugins.json file asynchronously.
+    var xhr = new context.XMLHttpRequest();
+    xhr.onreadystatechange = function() {
+        if (this.readyState != 4) { // not DONE
+            return;
+        }
+
+        // If the response is a JSON string which composes an array, call handlePluginsObject.
+        // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
+        if (this.status == 200) {
+            var obj = JSON.parse(this.responseText);
+            if (obj && obj instanceof Array && obj.length > 0) {
+                handlePluginsObject(obj);
+            } else {
+                finishPluginLoading();
+            }
+        } else {
+            finishPluginLoading();
+        }
+    };
+    xhr.open('GET', 'cordova_plugins.json', true); // Async
+    xhr.send();
 }(window));
 
 
+
 })();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLibTests/CDVFakeFileManager.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CDVFakeFileManager.h b/lib/cordova-ios/CordovaLibTests/CDVFakeFileManager.h
index 41e5523..f9300a0 100644
--- a/lib/cordova-ios/CordovaLibTests/CDVFakeFileManager.h
+++ b/lib/cordova-ios/CordovaLibTests/CDVFakeFileManager.h
@@ -19,7 +19,7 @@
 
 #import <Foundation/Foundation.h>
 
-typedef BOOL (^CDVFileExistsBlock)(NSString*);
+typedef BOOL (^ CDVFileExistsBlock)(NSString*);
 
 // Used in place of an NSFileManager for unit tests. It implements only those functions
 // which are required by the tests that use it.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLibTests/CDVFileTransferTests.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CDVFileTransferTests.m b/lib/cordova-ios/CordovaLibTests/CDVFileTransferTests.m
index 7488a5a..2effc98 100644
--- a/lib/cordova-ios/CordovaLibTests/CDVFileTransferTests.m
+++ b/lib/cordova-ios/CordovaLibTests/CDVFileTransferTests.m
@@ -140,15 +140,15 @@ static NSData *readStream(NSInputStream* stream)
 - (void)testEscapePathComponentForUrlString
 {
     STAssertTrue([@"" isEqualToString:
-            [_fileTransfer escapePathComponentForUrlString:@""]], nil);
+        [_fileTransfer escapePathComponentForUrlString:@""]], nil);
     STAssertTrue([@"foo" isEqualToString:
-            [_fileTransfer escapePathComponentForUrlString:@"foo"]], nil);
+        [_fileTransfer escapePathComponentForUrlString:@"foo"]], nil);
     STAssertTrue([@"http://a.org/spa%20ce%25" isEqualToString:
-            [_fileTransfer escapePathComponentForUrlString:@"http://a.org/spa ce%"]], nil);
+        [_fileTransfer escapePathComponentForUrlString:@"http://a.org/spa ce%"]], nil);
     STAssertTrue([@"http://a.org/spa%20ce%25/" isEqualToString:
-            [_fileTransfer escapePathComponentForUrlString:@"http://a.org/spa ce%/"]], nil);
+        [_fileTransfer escapePathComponentForUrlString:@"http://a.org/spa ce%/"]], nil);
     STAssertTrue([@"http://a.org/%25/%25/" isEqualToString:
-            [_fileTransfer escapePathComponentForUrlString:@"http://a.org/%/%/"]], nil);
+        [_fileTransfer escapePathComponentForUrlString:@"http://a.org/%/%/"]], nil);
 }
 
 - (void)testUpload_invalidServerUrl
@@ -208,7 +208,7 @@ static NSData *readStream(NSInputStream* stream)
 {
     [self setChunkedModeArg:NO];
     [self setHeaders:[NSDictionary dictionaryWithObjectsAndKeys:@"val1", @"key1",
-            [NSArray arrayWithObjects:@"val2a", @"val2b", nil], @"key2", [NSNull null], @"X-Requested-With", nil]];
+    [NSArray arrayWithObjects:@"val2a", @"val2b", nil], @"key2", [NSNull null], @"X-Requested-With", nil]];
     NSURLRequest* request = [self requestForUpload];
     STAssertTrue([@"val1" isEqualToString:[request valueForHTTPHeaderField:@"key1"]], nil);
     STAssertTrue([@"val2a,val2b" isEqualToString:[request valueForHTTPHeaderField:@"key2"]], nil);


[3/6] 2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.

Posted by fi...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFile.m b/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
index d52405d..8c65270 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
@@ -52,7 +52,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
         paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
         self.appLibraryPath = [paths objectAtIndex:0];
 
-        self.appTempPath = [NSTemporaryDirectory ()stringByStandardizingPath];  // remove trailing slash from NSTemporaryDirectory()
+        self.appTempPath = [NSTemporaryDirectory()stringByStandardizingPath];   // remove trailing slash from NSTemporaryDirectory()
 
         self.persistentPath = [NSString stringWithFormat:@"/%@", [self.appDocsPath lastPathComponent]];
         self.temporaryPath = [NSString stringWithFormat:@"/%@", [self.appTempPath lastPathComponent]];
@@ -164,7 +164,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:QUOTA_EXCEEDED_ERR];
         } else {
             NSMutableDictionary* fileSystem = [NSMutableDictionary dictionaryWithCapacity:2];
-            [fileSystem setObject:(type == TEMPORARY ? kW3FileTemporary:kW3FilePersistent) forKey:@"name"];
+            [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];
@@ -486,7 +486,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
         // 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) {
+        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
             if (asset) {
                 // We have the asset!  Retrieve the metadata and send it off.
                 NSDate* date = [asset valueForProperty:ALAssetPropertyDate];
@@ -499,7 +499,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
             }
         };
         // TODO(maxw): Consider making this a class variable since it's the same every time.
-        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+        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];
@@ -525,7 +525,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
     } else {
         // didn't get fileAttribs
         CDVFileError errorCode = ABORT_ERR;
-        NSLog (@"error getting metadata: %@", [error localizedDescription]);
+        NSLog(@"error getting metadata: %@", [error localizedDescription]);
         if ([error code] == NSFileNoSuchFileError) {
             errorCode = NOT_FOUND_ERR;
         }
@@ -779,7 +779,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
                 // 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) {
+                ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
                     if (asset) {
                         // We have the asset!  Get the data and try to copy it over.
                         if (![fileMgr fileExistsAtPath:destRootPath]) {
@@ -796,7 +796,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
 
                         // We're good to go!  Write the file to the new destination.
                         ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
-                        Byte* buffer = (Byte*)malloc ([assetRepresentation size]);
+                        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];
@@ -808,7 +808,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
                         [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
                     }
                 };
-                ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+                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];
@@ -953,7 +953,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
             // 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) {
+            ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
                 if (asset) {
                     // We have the asset!  Populate the dictionary and send it off.
                     NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
@@ -975,7 +975,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
                     [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
                 }
             };
-            ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+            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];
@@ -1053,154 +1053,181 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
     [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 - NOT USED,  iOS reads and writes using UTF8!
- *	2 - NSString* start - OPTIONAL, only provided when not == 0.
- *	3 - NSString* end - OPTIONAL, only provided when not == length.
+ *	1 - NSString* encoding
+ *	2 - NSString* start
+ *	3 - NSString* end
  */
 - (void)readAsText:(CDVInvokedUrlCommand*)command
 {
     // arguments
-    NSString* argPath = [command.arguments objectAtIndex:0];
-    NSInteger start = 0;
-    NSInteger end = -1;
-
-    if ([command.arguments count] >= 3) {
-        start = [[command.arguments objectAtIndex:2] integerValue];
-    }
-    if ([command.arguments count] >= 4) {
-        end = [[command.arguments objectAtIndex:3] integerValue];
+    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;
     }
 
-    // NSString* encoding = [command.arguments objectAtIndex:2];   // not currently used
-    CDVPluginResult* result = nil;
-
-    NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:argPath];
-
-    if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        // can't read assets-library URLs as text
-        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_READABLE_ERR];
-    } else if (!file) {
-        // invalid path entry
-        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
-    } else {
-        if (start > 0) {
-            [file seekToFileOffset:start];
-        }
-
-        NSData* readData;
-        if (end < 0) {
-            readData = [file readDataToEndOfFile];
-        } else {
-            readData = [file readDataOfLength:(end - start)];
+    [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;
+            }
         }
-
-        [file closeFile];
-        NSString* pNStrBuff = nil;
-        if (readData) {
-            pNStrBuff = [[NSString alloc] initWithBytes:[readData bytes] length:[readData length] encoding:NSUTF8StringEncoding];
-        } else {
-            // return empty string if no data
-            pNStrBuff = @"";
+        if (result == nil) {
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
         }
 
-        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:pNStrBuff];
-    }
-    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+        [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
 {
-    // arguments
-    NSString* argPath = [command.arguments objectAtIndex:0];
-    NSInteger start = 0;
-    NSInteger end = -1;
-
-    if ([command.arguments count] >= 2) {
-        start = [[command.arguments objectAtIndex:1] integerValue];
-    }
-    if ([command.arguments count] >= 3) {
-        end = [[command.arguments objectAtIndex:2] integerValue];
-    }
+    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];
+        }
 
-    CDVFileError errCode = ABORT_ERR;
-    __block CDVPluginResult* result = nil;
+        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+    }];
+}
 
-    if (!argPath) {
-        errCode = SYNTAX_ERR;
-    } else 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!  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 = [self getMimeTypeFromPath:[assetRepresentation filename]];
-                NSString* dataString = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, [data base64EncodedString]];
-                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:dataString];
-                [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];
-        };
+/* Read content of text file and return as an arraybuffer
+ * IN:
+ * NSArray* arguments
+ *	0 - NSString* fullPath
+ *	1 - NSString* start
+ *	2 - NSString* end
+ */
 
-        ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
-        [assetsLibrary assetForURL:[NSURL URLWithString:argPath] resultBlock:resultBlock failureBlock:failureBlock];
-        return;
-    } else {
-        NSString* mimeType = [self getMimeTypeFromPath:argPath];
-        if (!mimeType) {
-            // can't return as data URL if can't figure out the mimeType
-            errCode = ENCODING_ERR;
+- (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 {
-            NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:argPath];
-            if (start > 0) {
-                [file seekToFileOffset:start];
-            }
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
+        }
 
-            NSData* readData;
-            if (end < 0) {
-                readData = [file readDataToEndOfFile];
-            } else {
-                readData = [file readDataOfLength:(end - start)];
-            }
+        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+    }];
+}
 
-            [file closeFile];
-            if (readData) {
-                NSString* output = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, [readData base64EncodedString]];
-                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:output];
-            } else {
-                errCode = NOT_FOUND_ERR;
-            }
+- (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];
         }
-    }
-    if (!result) {
-        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode];
-    }
-    // NSLog(@"readAsDataURL return: %@", jsString);
-    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+
+        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+    }];
 }
 
 /* helper function to get the mimeType from the file extension
@@ -1219,7 +1246,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
             mimeType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass(typeId, kUTTagClassMIMEType);
             if (!mimeType) {
                 // special case for m4a
-                if ([(__bridge NSString*) typeId rangeOfString:@"m4a-audio"].location != NSNotFound) {
+                if ([(__bridge NSString*)typeId rangeOfString : @"m4a-audio"].location != NSNotFound) {
                     mimeType = @"audio/mp4";
                 } else if ([[fullPath pathExtension] rangeOfString:@"wav"].location != NSNotFound) {
                     mimeType = @"audio/wav";
@@ -1343,7 +1370,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
     NSString* appFile = argPath; // [ self getFullPath: argPath];
 
     BOOL bExists = [fMgr fileExistsAtPath:appFile];
-    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(bExists ? 1:0)];
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(bExists ? 1 : 0)];
 
     [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
 }
@@ -1359,7 +1386,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
     BOOL bIsDir = NO;
     BOOL bExists = [fMgr fileExistsAtPath:appFile isDirectory:&bIsDir];
 
-    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:((bExists && bIsDir) ? 1:0)];
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:((bExists && bIsDir) ? 1 : 0)];
 
     [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
 }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
index f96bb7d..d82cdd3 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
@@ -48,10 +48,10 @@ extern NSString* const kOptionsKeyCookie;
 - (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;
+                                      AndSource:(NSString*)source
+                                      AndTarget:(NSString*)target
+                                  AndHttpStatus:(int)httpStatus
+                                        AndBody:(NSString*)body;
 @property (readonly) NSMutableDictionary* activeTransfers;
 @end
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
index 4ccdce6..5741aca 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
@@ -52,8 +52,8 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
 
     while (totalBytesWritten < bytesToWrite) {
         CFIndex result = CFWriteStreamWrite(stream,
-            bytes + totalBytesWritten,
-            bytesToWrite - totalBytesWritten);
+                bytes + totalBytesWritten,
+                bytesToWrite - totalBytesWritten);
         if (result < 0) {
             CFStreamError error = CFWriteStreamGetError(stream);
             NSLog(@"WriteStreamError domain: %ld error: %ld", error.domain, error.error);
@@ -190,7 +190,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
         [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:[@"\r\n" dataUsingEncoding : NSUTF8StringEncoding]];
     }
 
     [postBodyBeforeFile appendData:formBoundaryData];
@@ -213,22 +213,22 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
         [req setHTTPBodyStream:CFBridgingRelease(readStream)];
 
         [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;
-                        }
+            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 {
+                NSLog(@"FileTransfer: Failed to open writeStream");
+            }
+            CFWriteStreamClose(writeStream);
+            CFRelease(writeStream);
+        }];
     } else {
         [postBodyBeforeFile appendData:fileData];
         [postBodyBeforeFile appendData:postBodyAfterFile];
@@ -265,11 +265,11 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     // 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) {
+        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]);
+                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];
@@ -279,7 +279,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
                 [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
             }
         };
-        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+        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];
@@ -291,12 +291,18 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     } 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);
+            NSLog(@"Error opening file %@: %@", target, err);
         }
         [self uploadData:fileData command:command];
     }
@@ -352,6 +358,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     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]) {
@@ -388,7 +395,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     }
 
     NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url];
-    [self applyRequestHeaders:nil toRequest:req];
+    [self applyRequestHeaders:headers toRequest:req];
 
     CDVFileTransferDelegate* delegate = [[CDVFileTransferDelegate alloc] init];
     delegate.command = self;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m b/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
index 4d960cd..9eb9721 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
@@ -138,14 +138,14 @@
 
     // create the formatter using the user's current default locale and formats for dates and times
     CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        dateStyle,
-        timeStyle);
+            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);
+                formatter,
+                (__bridge CFDateRef)date);
     }
 
     // if the date was converted to a string successfully then return the result
@@ -227,18 +227,18 @@
 
     // get the user's default settings for date and time formats
     CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        dateStyle,
-        timeStyle);
+            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);
+            formatter,
+            (__bridge CFStringRef)dateString,
+            NULL);
 
     // if we were able to parse the date then get the date and time components
     if (date != NULL) {
@@ -336,9 +336,9 @@
 
     // get the user's default settings for date and time formats
     CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        dateStyle,
-        timeStyle);
+            currentLocale,
+            dateStyle,
+            timeStyle);
 
     // get the date pattern to apply when formatting and parsing
     CFStringRef datePattern = CFDateFormatterGetFormat(formatter);
@@ -415,9 +415,9 @@
     }
 
     CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        kCFDateFormatterFullStyle,
-        kCFDateFormatterFullStyle);
+            currentLocale,
+            kCFDateFormatterFullStyle,
+            kCFDateFormatterFullStyle);
 
     if ((selector == CDV_SELECTOR_MONTHS) && (style == CDV_FORMAT_LONG)) {
         dataStyle = kCFDateFormatterMonthSymbols;
@@ -545,13 +545,13 @@
     }
 
     CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        style);
+            currentLocale,
+            style);
 
     // get the localized string based upon the locale and user preferences
     NSString* numberString = (__bridge_transfer NSString*)CFNumberFormatterCreateStringWithNumber(kCFAllocatorDefault,
-        formatter,
-        (__bridge CFNumberRef)number);
+            formatter,
+            (__bridge CFNumberRef)number);
 
     if (numberString) {
         NSDictionary* dictionary = [NSDictionary dictionaryWithObject:numberString forKey:@"value"];
@@ -612,8 +612,8 @@
     }
 
     CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        style);
+            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) {
@@ -622,10 +622,10 @@
 
     // parse againist the largest type to avoid data loss
     Boolean rc = CFNumberFormatterGetValueFromString(formatter,
-        (__bridge CFStringRef)numberString,
-        NULL,
-        kCFNumberDoubleType,
-        &doubleValue);
+            (__bridge CFStringRef)numberString,
+            NULL,
+            kCFNumberDoubleType,
+            &doubleValue);
 
     if (rc) {
         NSDictionary* dictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithDouble:doubleValue] forKey:@"value"];
@@ -681,8 +681,8 @@
     }
 
     CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        style);
+            currentLocale,
+            style);
 
     NSString* numberPattern = (__bridge NSString*)CFNumberFormatterGetFormat(formatter);
 
@@ -749,8 +749,8 @@
     // now set the currency code in the formatter
     if (rc) {
         CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
-            currentLocale,
-            kCFNumberFormatterCurrencyStyle);
+                currentLocale,
+                kCFNumberFormatterCurrencyStyle);
 
         CFNumberFormatterSetProperty(formatter, kCFNumberFormatterCurrencyCode, (__bridge CFStringRef)currencyCode);
         CFNumberFormatterSetProperty(formatter, kCFNumberFormatterInternationalCurrencySymbol, (__bridge CFStringRef)currencyCode);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
index 9ff460a..f63250a 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
@@ -20,6 +20,7 @@
 #import "CDVPlugin.h"
 #import "CDVInvokedUrlCommand.h"
 #import "CDVScreenOrientationDelegate.h"
+#import "CDVWebViewDelegate.h"
 
 @class CDVInAppBrowserViewController;
 
@@ -27,6 +28,7 @@
 
 - (void)browserLoadStart:(NSURL*)url;
 - (void)browserLoadStop:(NSURL*)url;
+- (void)browserLoadError:(NSError*)error forUrl:(NSURL*)url;
 - (void)browserExit;
 
 @end
@@ -47,6 +49,7 @@
     NSString* _userAgent;
     NSString* _prevUserAgent;
     NSInteger _userAgentLockToken;
+    CDVWebViewDelegate* _webViewDelegate;
 }
 
 @property (nonatomic, strong) IBOutlet UIWebView* webView;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
index 14671a5..d001dfd 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
@@ -165,7 +165,7 @@
 {
     if (self.callbackId != nil) {
         CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
-                                                      messageAsDictionary:@ {@"type":@"loadstart", @"url":[url absoluteString]}];
+                                                      messageAsDictionary:@{@"type":@"loadstart", @"url":[url absoluteString]}];
         [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
 
         [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
@@ -176,7 +176,18 @@
 {
     if (self.callbackId != nil) {
         CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
-                                                      messageAsDictionary:@ {@"type":@"loadstop", @"url":[url absoluteString]}];
+                                                      messageAsDictionary:@{@"type":@"loadstop", @"url":[url absoluteString]}];
+        [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
+
+        [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
+    }
+}
+
+- (void)browserLoadError:(NSError*)error forUrl:(NSURL*)url
+{
+    if (self.callbackId != nil) {
+        CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
+                                                      messageAsDictionary:@{@"type":@"loaderror", @"url":[url absoluteString], @"code": [NSNumber numberWithInt:error.code], @"message": error.localizedDescription}];
         [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
 
         [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
@@ -187,7 +198,7 @@
 {
     if (self.callbackId != nil) {
         CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
-                                                      messageAsDictionary:@ {@"type":@"exit"}];
+                                                      messageAsDictionary:@{@"type":@"exit"}];
         [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
 
         [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
@@ -209,6 +220,7 @@
     if (self != nil) {
         _userAgent = userAgent;
         _prevUserAgent = prevUserAgent;
+        _webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self];
         [self createViews];
     }
 
@@ -229,7 +241,7 @@
     [self.view addSubview:self.webView];
     [self.view sendSubviewToBack:self.webView];
 
-    self.webView.delegate = self;
+    self.webView.delegate = _webViewDelegate;
     self.webView.backgroundColor = [UIColor whiteColor];
 
     self.webView.clearsContextBeforeDrawing = YES;
@@ -391,10 +403,10 @@
         [self.webView loadRequest:request];
     } else {
         [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) {
-                _userAgentLockToken = lockToken;
-                [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken];
-                [self.webView loadRequest:request];
-            }];
+            _userAgentLockToken = lockToken;
+            [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken];
+            [self.webView loadRequest:request];
+        }];
     }
 }
 
@@ -419,14 +431,18 @@
     self.forwardButton.enabled = theWebView.canGoForward;
 
     [self.spinner startAnimating];
+}
 
+- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
+{
     if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStart:)]) {
-        NSURL* url = theWebView.request.URL;
+        NSURL* url = request.URL;
         if (url == nil) {
             url = _requestedURL;
         }
         [self.navigationDelegate browserLoadStart:url];
     }
+    return YES;
 }
 
 - (void)webViewDidFinishLoad:(UIWebView*)theWebView
@@ -450,7 +466,7 @@
     //    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"]];
+    BOOL isPDF = [@"true" isEqualToString :[theWebView stringByEvaluatingJavaScriptFromString:@"document.body==null"]];
     if (isPDF) {
         [CDVUserAgentUtil setUserAgent:_prevUserAgent lockToken:_userAgentLockToken];
     }
@@ -471,6 +487,11 @@
     [self.spinner stopAnimating];
 
     self.addressLabel.text = @"Load Error";
+
+    if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadError:forUrl:)]) {
+        NSURL* url = theWebView.request.URL;
+        [self.navigationDelegate browserLoadError:error forUrl:url];
+    }
 }
 
 #pragma mark CDVScreenOrientationDelegate

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h b/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
index 6eb0099..7be8884 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
@@ -34,9 +34,9 @@
 + (CDVInvokedUrlCommand*)commandFromJson:(NSArray*)jsonEntry;
 
 - (id)initWithArguments:(NSArray*)arguments
-   callbackId          :(NSString*)callbackId
-    className           :(NSString*)className
-   methodName          :(NSString*)methodName;
+             callbackId:(NSString*)callbackId
+              className:(NSString*)className
+             methodName:(NSString*)methodName;
 
 - (id)initFromJson:(NSArray*)jsonEntry;
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h
new file mode 100644
index 0000000..02fe91f
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h
@@ -0,0 +1,60 @@
+/*
+ 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 <Foundation/Foundation.h>
+
+@interface CDVJpegHeaderWriter : NSObject {
+    NSDictionary * SubIFDTagFormatDict;
+    NSDictionary * IFD0TagFormatDict;
+}
+
+- (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

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
new file mode 100644
index 0000000..7b59d11
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
@@ -0,0 +1,472 @@
+/*
+ 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"
+
+// tag info shorthand, tagno: tag number, typecode: data type:, components: number of components
+#define TAGINF(tagno, typecode, components) [NSArray arrayWithObjects: tagno, typecode, components, 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(@"0132", [NSNumber numberWithInt:EDT_ASCII_STRING], @20), @"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(@"9004",[NSNumber numberWithInt:EDT_ASCII_STRING],@20), @"DateTimeDigitized",
+                           TAGINF(@"9003",[NSNumber numberWithInt:EDT_ASCII_STRING],@20), @"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;
+}
+
+/**
+ * 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";
+    
+    //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];
+
+    //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];
+
+    // 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 {
+    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
+                                      withFormatDict: formatdict
+                                      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=0; // 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 {
+        // same calculation as above, but no exifsubifd offset
+        addr = 14+12*[ifddatablock count];
+    }
+    
+    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;
+        }
+    }
+    
+    // calculate IFD0 terminal offset tags, currently ExifSubIFD
+    int entrycount = [ifdblock count];
+    if (ifd0flag) {
+        NSNumber * offset = [NSNumber numberWithInt:[exifstr length] / 2 + [dbstr length] / 2 ];
+        
+        [self appendExifOffsetTagTo: exifstr
+                        withOffset : offset];
+        entrycount++;
+    } 
+    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 withFormatDict : (NSDictionary*) formatdict withElementData : (NSString*) data  {
+    NSArray * fielddata = [formatdict objectForKey: elementName];// format data of desired field
+    if (fielddata) {
+        // format string @"%@%@%@%@", tag number, data format, components, value
+        NSNumber * dataformat = [fielddata objectAtIndex:1];
+        NSNumber * components = [fielddata objectAtIndex:2];
+        if([components intValue] == 0) {
+            components = [NSNumber numberWithInt: [data length] * DataTypeToWidth[[dataformat intValue]-1]];            
+        }
+
+        return [[NSString alloc] initWithFormat: @"%@%@%08x",
+                                                [fielddata 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"
+                                withFormatDict: IFD0TagFormatDict
+                               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];
+    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 ([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],
+                    @"00000000"];
+        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

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
index cc6613f..dec6ab3 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
@@ -34,8 +34,8 @@
 + (void)__fixupDatabaseLocationsWithBackupType:(NSString*)backupType;
 // Visible for testing.
 + (BOOL)__verifyAndFixDatabaseLocationsWithAppPlistDict:(NSMutableDictionary*)appPlistDict
-    bundlePath                                          :(NSString*)bundlePath
-   fileManager                                         :(NSFileManager*)fileManager;
+                                             bundlePath:(NSString*)bundlePath
+                                            fileManager:(NSFileManager*)fileManager;
 @end
 
 @interface CDVBackupInfo : NSObject

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
index 68175f1..238d680 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
@@ -35,7 +35,7 @@
 {
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResignActive)
                                                  name:UIApplicationWillResignActiveNotification object:nil];
-    BOOL cloudBackup = [@"cloud" isEqualToString:self.commandDelegate.settings[@"BackupWebStorage"]];
+    BOOL cloudBackup = [@"cloud" isEqualToString : self.commandDelegate.settings[@"BackupWebStorage"]];
 
     self.backupInfo = [[self class] createBackupInfoWithCloudBackup:cloudBackup];
 }
@@ -64,8 +64,8 @@
     // ////////// 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")];
+    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")];
+    backup = [backup stringByAppendingPathComponent:(rename ? @"localstorage.appdata.db" : @"file__0.localstorage")];
 
     backupItem = [[CDVBackupInfo alloc] init];
     backupItem.backup = backup;
@@ -77,8 +77,8 @@
     // ////////// 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")];
+    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")];
+    backup = [backup stringByAppendingPathComponent:(rename ? @"websqlmain.appdata.db" : @"Databases.db")];
 
     backupItem = [[CDVBackupInfo alloc] init];
     backupItem.backup = backup;
@@ -90,8 +90,8 @@
     // ////////// 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")];
+    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")];
+    backup = [backup stringByAppendingPathComponent:(rename ? @"websqldbs.appdata.db" : @"file__0")];
 
     backupItem = [[CDVBackupInfo alloc] init];
     backupItem.backup = backup;
@@ -106,8 +106,8 @@
 + (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* 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"];
 
@@ -131,7 +131,7 @@
     return success;
 }
 
-+ (BOOL)copyFrom:(NSString*)src to:(NSString*)dest error:(NSError * __autoreleasing*)error
++ (BOOL)copyFrom:(NSString*)src to:(NSString*)dest error:(NSError* __autoreleasing*)error
 {
     NSFileManager* fileManager = [NSFileManager defaultManager];
 
@@ -149,7 +149,7 @@
     // generate unique filepath in temp directory
     CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
     CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
-    NSString* tempBackup = [[NSTemporaryDirectory () stringByAppendingPathComponent:(__bridge NSString*)uuidString] stringByAppendingPathExtension:@"bak"];
+    NSString* tempBackup = [[NSTemporaryDirectory() stringByAppendingPathComponent:(__bridge NSString*)uuidString] stringByAppendingPathExtension:@"bak"];
     CFRelease(uuidString);
     CFRelease(uuidRef);
 
@@ -334,8 +334,8 @@
         return;
     }
 
-    NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains (NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
-    NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+    NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+    NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
 
     NSMutableArray* backupInfo = [NSMutableArray arrayWithCapacity:0];
 
@@ -386,15 +386,15 @@
         backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
                 [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID];
                 backgroundTaskID = UIBackgroundTaskInvalid;
-                NSLog (@"Background task to backup WebSQL/LocalStorage expired.");
+                NSLog(@"Background task to backup WebSQL/LocalStorage expired.");
             }];
         CDVLocalStorage __weak* weakSelf = self;
         [self.commandDelegate runInBackground:^{
-                [weakSelf backup:nil];
+            [weakSelf backup:nil];
 
-                [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID];
-                backgroundTaskID = UIBackgroundTaskInvalid;
-            }];
+            [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID];
+            backgroundTaskID = UIBackgroundTaskInvalid;
+        }];
     }
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h b/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h
index 7087d43..caf0798 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h
@@ -83,11 +83,11 @@ typedef NSUInteger CDVLocationStatus;
 - (void)startLocation:(BOOL)enableHighAccuracy;
 
 - (void)locationManager:(CLLocationManager*)manager
-   didUpdateToLocation :(CLLocation*)newLocation
-          fromLocation        :(CLLocation*)oldLocation;
+    didUpdateToLocation:(CLLocation*)newLocation
+           fromLocation:(CLLocation*)oldLocation;
 
 - (void)locationManager:(CLLocationManager*)manager
-   didFailWithError    :(NSError*)error;
+       didFailWithError:(NSError*)error;
 
 - (BOOL)isLocationServicesEnabled;
 
@@ -97,7 +97,7 @@ typedef NSUInteger CDVLocationStatus;
 - (void)stopHeading:(CDVInvokedUrlCommand*)command;
 - (void)startHeadingWithFilter:(CLLocationDegrees)filter;
 - (void)locationManager:(CLLocationManager*)manager
-   didUpdateHeading    :(CLHeading*)heading;
+       didUpdateHeading:(CLHeading*)heading;
 
 - (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager*)manager;
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m b/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
index 07af30e..ed9ec26 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
@@ -591,17 +591,17 @@
 - (NSString*)JSONRepresentation
 {
     return [NSString stringWithFormat:
-        @"{ timestamp: %.00f, \
+           @"{ 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
+           [self.timestamp timeIntervalSince1970] * 1000.0,
+           self.coordinate.latitude,
+           self.coordinate.longitude,
+           self.altitude,
+           self.course,
+           self.speed,
+           self.horizontalAccuracy,
+           self.verticalAccuracy
     ];
 }
 
@@ -614,9 +614,9 @@
 - (NSString*)JSONRepresentation
 {
     return [NSString stringWithFormat:
-        @"{ code: %d, message: '%@'}",
-        self.code,
-        [self localizedDescription]
+           @"{ code: %d, message: '%@'}",
+           self.code,
+           [self localizedDescription]
     ];
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h b/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h
index 1eedb54..5b5b89f 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h
@@ -26,6 +26,7 @@
 
 - (void)alert:(CDVInvokedUrlCommand*)command;
 - (void)confirm:(CDVInvokedUrlCommand*)command;
+- (void)prompt:(CDVInvokedUrlCommand*)command;
 - (void)vibrate:(CDVInvokedUrlCommand*)command;
 
 @end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m b/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m
index 992239e..821cb9f 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m
@@ -20,12 +20,24 @@
 #import "CDVNotification.h"
 #import "NSDictionary+Extensions.h"
 
+#define DIALOG_TYPE_ALERT @"alert"
+#define DIALOG_TYPE_PROMPT @"prompt"
+
 @implementation CDVNotification
 
-- (void)showDialogWithMessage:(NSString*)message title:(NSString*)title buttons:(NSString*)buttons callbackId:(NSString*)callbackId
+/*
+ * 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.
+ *  callbackId    The commmand callback id.
+ *  dialogType    The type of alert view [alert | prompt].
+ */
+- (void)showDialogWithMessage:(NSString*)message title:(NSString*)title buttons:(NSArray*)buttons callbackId:(NSString*)callbackId dialogType:(NSString*)dialogType
 {
     CDVAlertView* alertView = [[CDVAlertView alloc]
-            initWithTitle:title
+        initWithTitle:title
                   message:message
                  delegate:self
         cancelButtonTitle:nil
@@ -33,11 +45,14 @@
 
     alertView.callbackId = callbackId;
 
-    NSArray* labels = [buttons componentsSeparatedByString:@","];
-    int count = [labels count];
+    int count = [buttons count];
 
     for (int n = 0; n < count; n++) {
-        [alertView addButtonWithTitle:[labels objectAtIndex:n]];
+        [alertView addButtonWithTitle:[buttons objectAtIndex:n]];
+    }
+
+    if ([dialogType isEqualToString:DIALOG_TYPE_PROMPT]) {
+        alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
     }
 
     [alertView show];
@@ -46,52 +61,54 @@
 - (void)alert:(CDVInvokedUrlCommand*)command
 {
     NSString* callbackId = command.callbackId;
-    NSArray* arguments = command.arguments;
-    int argc = [arguments count];
-
-    NSString* message = argc > 0 ? [arguments objectAtIndex:0] : nil;
-    NSString* title = argc > 1 ? [arguments objectAtIndex:1] : nil;
-    NSString* buttons = argc > 2 ? [arguments objectAtIndex:2] : nil;
-
-    if (!title) {
-        title = NSLocalizedString(@"Alert", @"Alert");
-    }
-    if (!buttons) {
-        buttons = NSLocalizedString(@"OK", @"OK");
-    }
+    NSString* message = [command argumentAtIndex:0];
+    NSString* title = [command argumentAtIndex:1];
+    NSString* buttons = [command argumentAtIndex:2];
 
-    [self showDialogWithMessage:message title:title buttons:buttons callbackId:callbackId];
+    [self showDialogWithMessage:message title:title buttons:@[buttons] callbackId:callbackId dialogType:DIALOG_TYPE_ALERT];
 }
 
 - (void)confirm:(CDVInvokedUrlCommand*)command
 {
     NSString* callbackId = command.callbackId;
-    NSArray* arguments = command.arguments;
-    int argc = [arguments count];
+    NSString* message = [command argumentAtIndex:0];
+    NSString* title = [command argumentAtIndex:1];
+    NSArray* buttons = [command argumentAtIndex:2];
 
-    NSString* message = argc > 0 ? [arguments objectAtIndex:0] : nil;
-    NSString* title = argc > 1 ? [arguments objectAtIndex:1] : nil;
-    NSString* buttons = argc > 2 ? [arguments objectAtIndex:2] : nil;
+    [self showDialogWithMessage:message title:title buttons:buttons callbackId:callbackId dialogType:DIALOG_TYPE_ALERT];
+}
 
-    if (!title) {
-        title = NSLocalizedString(@"Confirm", @"Confirm");
-    }
-    if (!buttons) {
-        buttons = NSLocalizedString(@"OK,Cancel", @"OK,Cancel");
-    }
+- (void)prompt:(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 callbackId:callbackId];
+    [self showDialogWithMessage:message title:title buttons:buttons callbackId:callbackId dialogType:DIALOG_TYPE_PROMPT];
 }
 
 /**
- Callback invoked when an alert dialog's buttons are clicked.
- Passes the index + label back to JS
- */
+  * Callback invoked when an alert dialog's buttons are clicked.
+  */
 - (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
 {
     CDVAlertView* cdvAlertView = (CDVAlertView*)alertView;
-    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:++buttonIndex];
-
+    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];
 }
 


[5/6] 2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.

Posted by fi...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java b/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java
index 8b023eb..4751fc3 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java
@@ -18,6 +18,7 @@
 */
 package org.apache.cordova;
 
+import java.io.ByteArrayInputStream;
 import java.util.Hashtable;
 
 import org.apache.cordova.api.CordovaInterface;
@@ -38,6 +39,7 @@ import android.util.Log;
 import android.view.View;
 import android.webkit.HttpAuthHandler;
 import android.webkit.SslErrorHandler;
+import android.webkit.WebResourceResponse;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 
@@ -66,7 +68,7 @@ public class CordovaWebViewClient extends WebViewClient {
 
     /**
      * Constructor.
-     * 
+     *
      * @param cordova
      * @param view
      */
@@ -77,7 +79,7 @@ public class CordovaWebViewClient extends WebViewClient {
 
     /**
      * Constructor.
-     * 
+     *
      * @param view
      */
     public void setWebView(CordovaWebView view) {
@@ -101,8 +103,8 @@ public class CordovaWebViewClient extends WebViewClient {
 		String callbackId = url.substring(idx3 + 1, idx4);
 		String jsonArgs   = url.substring(idx4 + 1);
         appView.pluginManager.exec(service, action, callbackId, jsonArgs);
-	}    
-	
+	}
+
     /**
      * Give the host application a chance to take over the control when a new url
      * is about to be loaded in the current WebView.
@@ -192,12 +194,8 @@ public class CordovaWebViewClient extends WebViewClient {
 
             // If our app or file:, then load into a new Cordova webview container by starting a new instance of our activity.
             // Our app continues to run.  When BACK is pressed, our app is redisplayed.
-            if (url.startsWith("file://") || url.startsWith("data:") || url.indexOf(this.appView.baseUrl) == 0 || Config.isUrlWhiteListed(url)) {
-                //This will fix iFrames
-                if (appView.useBrowserHistory || url.startsWith("data:"))
-                    return false;
-                else
-                    this.appView.loadUrl(url);
+            if (url.startsWith("file://") || url.startsWith("data:")  || Config.isUrlWhiteListed(url)) {
+                return false;
             }
 
             // If not our application, let default viewer handle
@@ -215,6 +213,34 @@ public class CordovaWebViewClient extends WebViewClient {
     }
 
     /**
+     * Check for intercepting any requests for resources.
+     * This includes images and scripts and so on, not just top-level pages.
+     * @param view          The WebView.
+     * @param url           The URL to be loaded.
+     * @return              Either null to proceed as normal, or a WebResourceResponse.
+     */
+    @Override
+    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
+      //If something isn't whitelisted, just send a blank response
+        if(!Config.isUrlWhiteListed(url) && (url.startsWith("http://") || url.startsWith("https://")))
+        {
+            return getWhitelistResponse();
+        }
+    	if (this.appView.pluginManager != null) {
+            return this.appView.pluginManager.shouldInterceptRequest(url);
+        }
+        return null;
+    }
+    
+    private WebResourceResponse getWhitelistResponse()
+    {
+        WebResourceResponse emptyResponse;
+        String empty = "";
+        ByteArrayInputStream data = new ByteArrayInputStream(empty.getBytes());
+        return new WebResourceResponse("text/plain", "UTF-8", data);
+    }
+
+    /**
      * On received http auth request.
      * The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination
      *
@@ -230,7 +256,7 @@ public class CordovaWebViewClient extends WebViewClient {
         AuthenticationToken token = this.getAuthenticationToken(host, realm);
         if (token != null) {
             handler.proceed(token.getUserName(), token.getPassword());
-        } 
+        }
         else {
             // Handle 401 like we'd normally do!
             super.onReceivedHttpAuthRequest(view, handler, host, realm);
@@ -238,22 +264,16 @@ public class CordovaWebViewClient extends WebViewClient {
     }
 
     /**
-     * Notify the host application that a page has started loading. 
-     * This method is called once for each main frame load so a page with iframes or framesets will call onPageStarted 
-     * one time for the main frame. This also means that onPageStarted will not be called when the contents of an 
-     * embedded frame changes, i.e. clicking a link whose target is an iframe. 
-     * 
+     * Notify the host application that a page has started loading.
+     * This method is called once for each main frame load so a page with iframes or framesets will call onPageStarted
+     * one time for the main frame. This also means that onPageStarted will not be called when the contents of an
+     * embedded frame changes, i.e. clicking a link whose target is an iframe.
+     *
      * @param view          The webview initiating the callback.
      * @param url           The url of the page.
      */
     @Override
     public void onPageStarted(WebView view, String url, Bitmap favicon) {
-        // Clear history so history.back() doesn't do anything.
-        // So we can reinit() native side CallbackServer & PluginManager.
-        if (!this.appView.useBrowserHistory) {
-            view.clearHistory();
-            this.doClearHistory = true;
-        }
 
         // Flush stale messages.
         this.appView.jsMessageQueue.reset();
@@ -270,7 +290,7 @@ public class CordovaWebViewClient extends WebViewClient {
     /**
      * Notify the host application that a page has finished loading.
      * This method is called only for main frame. When onPageFinished() is called, the rendering picture may not be updated yet.
-     * 
+     *
      *
      * @param view          The webview initiating the callback.
      * @param url           The url of the page.
@@ -359,11 +379,11 @@ public class CordovaWebViewClient extends WebViewClient {
     }
 
     /**
-     * Notify the host application that an SSL error occurred while loading a resource. 
-     * The host application must call either handler.cancel() or handler.proceed(). 
-     * Note that the decision may be retained for use in response to future SSL errors. 
+     * Notify the host application that an SSL error occurred while loading a resource.
+     * The host application must call either handler.cancel() or handler.proceed().
+     * Note that the decision may be retained for use in response to future SSL errors.
      * The default behavior is to cancel the load.
-     * 
+     *
      * @param view          The WebView that is initiating the callback.
      * @param handler       An SslErrorHandler object that will handle the user's response.
      * @param error         The SSL error object.
@@ -392,27 +412,10 @@ public class CordovaWebViewClient extends WebViewClient {
         }
     }
 
-    /**
-     * Notify the host application to update its visited links database.
-     * 
-     * @param view          The WebView that is initiating the callback.
-     * @param url           The url being visited.
-     * @param isReload      True if this url is being reloaded.
-     */
-    @Override
-    public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
-        /*
-         * If you do a document.location.href the url does not get pushed on the stack
-         * so we do a check here to see if the url should be pushed.
-         */
-        if (!this.appView.peekAtUrlStack().equals(url)) {
-            this.appView.pushUrl(url);
-        }
-    }
 
     /**
      * Sets the authentication token.
-     * 
+     *
      * @param authenticationToken
      * @param host
      * @param realm
@@ -429,10 +432,10 @@ public class CordovaWebViewClient extends WebViewClient {
 
     /**
      * Removes the authentication token.
-     * 
+     *
      * @param host
      * @param realm
-     * 
+     *
      * @return the authentication token or null if did not exist
      */
     public AuthenticationToken removeAuthenticationToken(String host, String realm) {
@@ -441,16 +444,16 @@ public class CordovaWebViewClient extends WebViewClient {
 
     /**
      * Gets the authentication token.
-     * 
+     *
      * In order it tries:
      * 1- host + realm
      * 2- host
      * 3- realm
      * 4- no host, no realm
-     * 
+     *
      * @param host
      * @param realm
-     * 
+     *
      * @return the authentication token
      */
     public AuthenticationToken getAuthenticationToken(String host, String realm) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/Device.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Device.java b/lib/cordova-android/framework/src/org/apache/cordova/Device.java
index 5b09c13..ad399f0 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/Device.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Device.java
@@ -38,7 +38,7 @@ import android.telephony.TelephonyManager;
 public class Device extends CordovaPlugin {
     public static final String TAG = "Device";
 
-    public static String cordovaVersion = "2.5.0";              // Cordova version
+    public static String cordovaVersion = "2.6.0rc1";              // Cordova version
     public static String platform = "Android";                  // Device OS
     public static String uuid;                                  // Device UUID
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java b/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java
index 9a7be4e..d4296cb 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java
@@ -28,6 +28,7 @@ import org.apache.cordova.api.LOG;
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -332,6 +333,7 @@ public class DroidGap extends Activity implements CordovaInterface {
      * @param webViewClient
      * @param webChromeClient
      */
+    @SuppressLint("NewApi")
     public void init(CordovaWebView webView, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient) {
         LOG.d(TAG, "DroidGap.init()");
 
@@ -349,6 +351,12 @@ public class DroidGap extends Activity implements CordovaInterface {
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 1.0F));
 
+        if (this.getBooleanProperty("disallowOverscroll", false)) {
+            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD) {
+                this.appView.setOverScrollMode(CordovaWebView.OVER_SCROLL_NEVER);
+            }
+        }
+
         // Add web view but make it invisible while loading URL
         this.appView.setVisibility(View.INVISIBLE);
         this.root.addView(this.appView);
@@ -1054,7 +1062,8 @@ public class DroidGap extends Activity implements CordovaInterface {
     {
         //Get whatever has focus!
         View childView = appView.getFocusedChild();
-        if ((appView.isCustomViewShowing() || childView != null ) && keyCode == KeyEvent.KEYCODE_BACK) {
+        if ((appView.isCustomViewShowing() || childView != null ) &&
+                (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU)) {
             return appView.onKeyUp(keyCode, event);
         } else {
             return super.onKeyUp(keyCode, event);
@@ -1074,7 +1083,7 @@ public class DroidGap extends Activity implements CordovaInterface {
         //Get whatever has focus!
         View childView = appView.getFocusedChild();
         //Determine if the focus is on the current view or not
-        if (childView != null && keyCode == KeyEvent.KEYCODE_BACK) {
+        if (childView != null && (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU)) {
                     return appView.onKeyDown(keyCode, event);
         }
         else

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/FileHelper.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/FileHelper.java b/lib/cordova-android/framework/src/org/apache/cordova/FileHelper.java
new file mode 100644
index 0000000..c10ed96
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/FileHelper.java
@@ -0,0 +1,142 @@
+/*
+       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.
+ */
+package org.apache.cordova;
+
+import android.database.Cursor;
+import android.net.Uri;
+import android.webkit.MimeTypeMap;
+
+import org.apache.cordova.api.CordovaInterface;
+import org.apache.cordova.api.LOG;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class FileHelper {
+    private static final String LOG_TAG = "FileUtils";
+    private static final String _DATA = "_data";
+
+    /**
+     * Returns the real path of the given URI string.
+     * If the given URI string represents a content:// URI, the real path is retrieved from the media store.
+     *
+     * @param uriString the URI string of the audio/image/video
+     * @param cordova the current application context
+     * @return the full path to the file
+     */
+    @SuppressWarnings("deprecation")
+    public static String getRealPath(String uriString, CordovaInterface cordova) {
+        String realPath = null;
+
+        if (uriString.startsWith("content://")) {
+            String[] proj = { _DATA };
+            Cursor cursor = cordova.getActivity().managedQuery(Uri.parse(uriString), proj, null, null, null);
+            int column_index = cursor.getColumnIndexOrThrow(_DATA);
+            cursor.moveToFirst();
+            realPath = cursor.getString(column_index);
+            if (realPath == null) {
+                LOG.e(LOG_TAG, "Could get real path for URI string %s", uriString);
+            }
+        } else if (uriString.startsWith("file://")) {
+            realPath = uriString.substring(7);
+            if (realPath.startsWith("/android_asset/")) {
+                LOG.e(LOG_TAG, "Cannot get real path for URI string %s because it is a file:///android_asset/ URI.", uriString);
+                realPath = null;
+            }
+        } else {
+            realPath = uriString;
+        }
+
+        return realPath;
+    }
+
+    /**
+     * Returns the real path of the given URI.
+     * If the given URI is a content:// URI, the real path is retrieved from the media store.
+     *
+     * @param uri the URI of the audio/image/video
+     * @param cordova the current application context
+     * @return the full path to the file
+     */
+    public static String getRealPath(Uri uri, CordovaInterface cordova) {
+        return FileHelper.getRealPath(uri.toString(), cordova);
+    }
+
+    /**
+     * Returns an input stream based on given URI string.
+     *
+     * @param uriString the URI string from which to obtain the input stream
+     * @param cordova the current application context
+     * @return an input stream into the data at the given URI or null if given an invalid URI string
+     * @throws IOException
+     */
+    public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova) throws IOException {
+        if (uriString.startsWith("content")) {
+            Uri uri = Uri.parse(uriString);
+            return cordova.getActivity().getContentResolver().openInputStream(uri);
+        } else if (uriString.startsWith("file:///android_asset/")) {
+            String relativePath = uriString.substring(22);
+            return cordova.getActivity().getAssets().open(relativePath);
+        } else {
+            return new FileInputStream(getRealPath(uriString, cordova));
+        }
+    }
+
+    /**
+     * Removes the "file://" prefix from the given URI string, if applicable.
+     * If the given URI string doesn't have a "file://" prefix, it is returned unchanged.
+     *
+     * @param uriString the URI string to operate on
+     * @return a path without the "file://" prefix
+     */
+    public static String stripFileProtocol(String uriString) {
+        if (uriString.startsWith("file://")) {
+            uriString = uriString.substring(7);
+        }
+        return uriString;
+    }
+
+    /**
+     * Returns the mime type of the data specified by the given URI string.
+     *
+     * @param uriString the URI string of the data
+     * @return the mime type of the specified data
+     */
+    public static String getMimeType(String uriString, CordovaInterface cordova) {
+        String mimeType = null;
+
+        if (uriString.startsWith("content://")) {
+            Uri uri = Uri.parse(uriString);
+            mimeType = cordova.getActivity().getContentResolver().getType(uri);
+        } else {
+            // MimeTypeMap.getFileExtensionFromUrl has a bug that occurs when the filename has a space, so we encode it.
+            // We also convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
+            String encodedUriString = uriString.replace(" ", "%20").toLowerCase();
+            String extension = MimeTypeMap.getFileExtensionFromUrl(encodedUriString);
+            if (extension.equals("3ga")) {
+                mimeType = "audio/3gpp";
+            } else {
+                mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+            }
+        }
+
+        return mimeType;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java b/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
index 623baf8..dba29af 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
@@ -18,6 +18,7 @@
 */
 package org.apache.cordova;
 
+import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
 import java.io.File;
@@ -27,7 +28,9 @@ import java.io.FileOutputStream;
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.io.StringWriter;
 import java.io.UnsupportedEncodingException;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
@@ -155,6 +158,25 @@ public class FileTransfer extends CordovaPlugin {
         return false;
     }
 
+    private static void addHeadersToRequest(URLConnection connection, JSONObject headers) {
+        try {
+            for (Iterator<?> iter = headers.keys(); iter.hasNext(); ) {
+                String headerKey = iter.next().toString();
+                JSONArray headerValues = headers.optJSONArray(headerKey);
+                if (headerValues == null) {
+                    headerValues = new JSONArray();
+                    headerValues.put(headers.getString(headerKey));
+                }
+                connection.setRequestProperty(headerKey, headerValues.getString(0));
+                for (int i = 1; i < headerValues.length(); ++i) {
+                    connection.addRequestProperty(headerKey, headerValues.getString(i));
+                }
+            }
+        } catch (JSONException e1) {
+          // No headers to be manipulated!
+        }
+    }
+
     /**
      * Uploads the specified file to the server URL provided using an HTTP multipart request.
      * @param source        Full path of the file on the file system
@@ -196,7 +218,7 @@ public class FileTransfer extends CordovaPlugin {
         try {
             url = new URL(target);
         } catch (MalformedURLException e) {
-            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, 0);
+            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0);
             Log.e(LOG_TAG, error.toString(), e);
             callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
             return;
@@ -269,22 +291,7 @@ public class FileTransfer extends CordovaPlugin {
 
                     // Handle the other headers
                     if (headers != null) {
-                        try {
-                            for (Iterator<?> iter = headers.keys(); iter.hasNext(); ) {
-                                String headerKey = iter.next().toString();
-                                JSONArray headerValues = headers.optJSONArray(headerKey);
-                                if (headerValues == null) {
-                                    headerValues = new JSONArray();
-                                    headerValues.put(headers.getString(headerKey));
-                                }
-                                conn.setRequestProperty(headerKey, headerValues.getString(0));
-                                for (int i = 1; i < headerValues.length(); ++i) {
-                                    conn.addRequestProperty(headerKey, headerValues.getString(i));
-                                }
-                            }
-                        } catch (JSONException e1) {
-                          // No headers to be manipulated!
-                        }
+                        addHeadersToRequest(conn, headers);
                     }
 
                     /*
@@ -530,18 +537,33 @@ public class FileTransfer extends CordovaPlugin {
     private static JSONObject createFileTransferError(int errorCode, String source, String target, URLConnection connection) {
 
         int httpStatus = 0;
-
+        StringBuilder bodyBuilder = new StringBuilder();
+        String body = null;
         if (connection != null) {
             try {
                 if (connection instanceof HttpURLConnection) {
                     httpStatus = ((HttpURLConnection)connection).getResponseCode();
+                    InputStream err = ((HttpURLConnection) connection).getErrorStream();
+                    if(err != null)
+                    {
+                        BufferedReader reader = new BufferedReader(new InputStreamReader(err, "UTF-8"));
+                        String line = reader.readLine();
+                        while(line != null)
+                        {
+                            bodyBuilder.append(line);
+                            line = reader.readLine();
+                            if(line != null)
+                                bodyBuilder.append('\n');
+                        }
+                        body = bodyBuilder.toString();
+                    }
                 }
             } catch (IOException e) {
                 Log.w(LOG_TAG, "Error getting HTTP status code from connection.", e);
             }
         }
 
-        return createFileTransferError(errorCode, source, target, httpStatus);
+        return createFileTransferError(errorCode, source, target, body, httpStatus);
     }
 
         /**
@@ -549,13 +571,17 @@ public class FileTransfer extends CordovaPlugin {
         * @param errorCode 	the error
         * @return JSONObject containing the error
         */
-    private static JSONObject createFileTransferError(int errorCode, String source, String target, Integer httpStatus) {
+    private static JSONObject createFileTransferError(int errorCode, String source, String target, String body, Integer httpStatus) {
         JSONObject error = null;
         try {
             error = new JSONObject();
             error.put("code", errorCode);
             error.put("source", source);
             error.put("target", target);
+            if(body != null)
+            {
+                error.put("body", body);
+            }   
             if (httpStatus != null) {
                 error.put("http_status", httpStatus);
             }
@@ -594,12 +620,13 @@ public class FileTransfer extends CordovaPlugin {
 
         final boolean trustEveryone = args.optBoolean(2);
         final String objectId = args.getString(3);
+        final JSONObject headers = args.optJSONObject(4);
 
         final URL url;
         try {
             url = new URL(source);
         } catch (MalformedURLException e) {
-            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, 0);
+            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0);
             Log.e(LOG_TAG, error.toString(), e);
             callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
             return;
@@ -608,7 +635,7 @@ public class FileTransfer extends CordovaPlugin {
 
         if (!Config.isUrlWhiteListed(source)) {
             Log.w(LOG_TAG, "Source URL is not in white list: '" + source + "'");
-            JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, 401);
+            JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, null, 401);
             callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
             return;
         }
@@ -671,6 +698,11 @@ public class FileTransfer extends CordovaPlugin {
                     {
                         connection.setRequestProperty("cookie", cookie);
                     }
+
+                    // Handle the other headers
+                    if (headers != null) {
+                        addHeadersToRequest(connection, headers);
+                    }
     
                     connection.connect();
     
@@ -718,8 +750,7 @@ public class FileTransfer extends CordovaPlugin {
                     Log.d(LOG_TAG, "Saved file: " + target);
     
                     // create FileEntry object
-                    FileUtils fileUtil = new FileUtils();
-                    JSONObject fileEntry = fileUtil.getEntry(file);
+                    JSONObject fileEntry = FileUtils.getEntry(file);
                     
                     result = new PluginResult(PluginResult.Status.OK, fileEntry);
                 } catch (FileNotFoundException e) {
@@ -826,7 +857,7 @@ public class FileTransfer extends CordovaPlugin {
                 file.delete();
             }
             // Trigger the abort callback immediately to minimize latency between it and abort() being called.
-            JSONObject error = createFileTransferError(ABORTED_ERR, context.source, context.target, -1);
+            JSONObject error = createFileTransferError(ABORTED_ERR, context.source, context.target, null, -1);
             synchronized (context) {
                 context.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, error));
                 context.aborted = true;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java b/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java
index b461b02..2135be9 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java
@@ -15,18 +15,17 @@
        KIND, either express or implied.  See the License for the
        specific language governing permissions and limitations
        under the License.
-*/
+ */
 package org.apache.cordova;
 
-import java.io.*;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.nio.channels.FileChannel;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.util.Log;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaInterface;
 import org.apache.cordova.api.CordovaPlugin;
 import org.apache.cordova.api.PluginResult;
 import org.apache.cordova.file.EncodingException;
@@ -38,23 +37,25 @@ import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
-//import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Environment;
-import android.provider.MediaStore;
-import android.webkit.MimeTypeMap;
-
-//import android.app.Activity;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.nio.channels.FileChannel;
 
 /**
  * This class provides SD card file and directory services to JavaScript.
  * Only files on the SD card can be accessed.
  */
 public class FileUtils extends CordovaPlugin {
-    @SuppressWarnings("unused")
     private static final String LOG_TAG = "FileUtils";
-    private static final String _DATA = "_data";    // The column name where the file path is stored
 
     public static int NOT_FOUND_ERR = 1;
     public static int SECURITY_ERR = 2;
@@ -75,9 +76,6 @@ public class FileUtils extends CordovaPlugin {
     public static int RESOURCE = 2;
     public static int APPLICATION = 3;
 
-    FileReader f_in;
-    FileWriter f_out;
-
     /**
      * Constructor.
      */
@@ -111,30 +109,29 @@ public class FileUtils extends CordovaPlugin {
                 callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
             }
             else if (action.equals("readAsText")) {
-                int start = 0;
-                int end = Integer.MAX_VALUE;
-                if (args.length() >= 3) {
-                    start = args.getInt(2);
-                }
-                if (args.length() >= 4) {
-                    end = args.getInt(3);
-                }
+                String encoding = args.getString(1);
+                int start = args.getInt(2);
+                int end = args.getInt(3);
 
-                String s = this.readAsText(args.getString(0), args.getString(1), start, end);
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, s));
+                this.readFileAs(args.getString(0), start, end, callbackContext, encoding, PluginResult.MESSAGE_TYPE_STRING);
             }
             else if (action.equals("readAsDataURL")) {
-                int start = 0;
-                int end = Integer.MAX_VALUE;
-                if (args.length() >= 2) {
-                    start = args.getInt(1);
-                }
-                if (args.length() >= 3) {
-                    end = args.getInt(2);
-                }
+                int start = args.getInt(1);
+                int end = args.getInt(2);
+
+                this.readFileAs(args.getString(0), start, end, callbackContext, null, -1);
+            }
+            else if (action.equals("readAsArrayBuffer")) {
+                int start = args.getInt(1);
+                int end = args.getInt(2);
 
-                String s = this.readAsDataURL(args.getString(0), start, end);
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, s));
+                this.readFileAs(args.getString(0), start, end, callbackContext, null, PluginResult.MESSAGE_TYPE_ARRAYBUFFER);
+            }
+            else if (action.equals("readAsBinaryString")) {
+                int start = args.getInt(1);
+                int end = args.getInt(2);
+
+                this.readFileAs(args.getString(0), start, end, callbackContext, null, PluginResult.MESSAGE_TYPE_BINARYSTRING);
             }
             else if (action.equals("write")) {
                 long fileSize = this.write(args.getString(0), args.getString(1), args.getInt(2));
@@ -237,11 +234,11 @@ public class FileUtils extends CordovaPlugin {
      * @param filePath the path to check
      */
     private void notifyDelete(String filePath) {
-        String newFilePath = getRealPathFromURI(Uri.parse(filePath), cordova);
+        String newFilePath = FileHelper.getRealPath(filePath, cordova);
         try {
             this.cordova.getActivity().getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-                MediaStore.Images.Media.DATA + " = ?",
-                new String[] { newFilePath });
+                    MediaStore.Images.Media.DATA + " = ?",
+                    new String[] { newFilePath });
         } catch (UnsupportedOperationException t) {
             // Was seeing this on the File mobile-spec tests on 4.0.3 x86 emulator.
             // The ContentResolver applies only when the file was registered in the
@@ -344,8 +341,8 @@ public class FileUtils extends CordovaPlugin {
      * @throws FileExistsException
      */
     private JSONObject transferTo(String fileName, String newParent, String newName, boolean move) throws JSONException, NoModificationAllowedException, IOException, InvalidModificationException, EncodingException, FileExistsException {
-        String newFileName = getRealPathFromURI(Uri.parse(fileName), cordova);
-        newParent = getRealPathFromURI(Uri.parse(newParent), cordova);
+        String newFileName = FileHelper.getRealPath(fileName, cordova);
+        newParent = FileHelper.getRealPath(newParent, cordova);
 
         // Check for invalid file name
         if (newName != null && newName.contains(":")) {
@@ -384,14 +381,14 @@ public class FileUtils extends CordovaPlugin {
             }
         } else {
             if (move) {
-            	JSONObject newFileEntry = moveFile(source, destination);
+                JSONObject newFileEntry = moveFile(source, destination);
 
-            	// If we've moved a file given its content URI, we need to clean up.
-            	if (fileName.startsWith("content://")) {
-            		notifyDelete(fileName);
-            	}
+                // If we've moved a file given its content URI, we need to clean up.
+                if (fileName.startsWith("content://")) {
+                    notifyDelete(fileName);
+                }
 
-            	return newFileEntry;
+                return newFileEntry;
             } else {
                 return copyFile(source, destination);
             }
@@ -748,7 +745,7 @@ public class FileUtils extends CordovaPlugin {
         if (fileName.startsWith("/")) {
             fp = new File(fileName);
         } else {
-            dirPath = getRealPathFromURI(Uri.parse(dirPath), cordova);
+            dirPath = FileHelper.getRealPath(dirPath, cordova);
             fp = new File(dirPath + File.separator + fileName);
         }
         return fp;
@@ -763,7 +760,7 @@ public class FileUtils extends CordovaPlugin {
      * @throws JSONException
      */
     private JSONObject getParent(String filePath) throws JSONException {
-        filePath = getRealPathFromURI(Uri.parse(filePath), cordova);
+        filePath = FileHelper.getRealPath(filePath, cordova);
 
         if (atRootDirectory(filePath)) {
             return getEntry(filePath);
@@ -779,7 +776,7 @@ public class FileUtils extends CordovaPlugin {
      * @return true if we are at the root, false otherwise.
      */
     private boolean atRootDirectory(String filePath) {
-        filePath = getRealPathFromURI(Uri.parse(filePath), cordova);
+        filePath = FileHelper.getRealPath(filePath, cordova);
 
         if (filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + cordova.getActivity().getPackageName() + "/cache") ||
                 filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath()) ||
@@ -790,26 +787,13 @@ public class FileUtils extends CordovaPlugin {
     }
 
     /**
-     * This method removes the "file://" from the passed in filePath
-     *
-     * @param filePath to be checked.
-     * @return
-     */
-    public static String stripFileProtocol(String filePath) {
-        if (filePath.startsWith("file://")) {
-            filePath = filePath.substring(7);
-        }
-        return filePath;
-    }
-
-    /**
      * Create a File object from the passed in path
      *
      * @param filePath
      * @return
      */
     private File createFileObject(String filePath) {
-    	filePath = getRealPathFromURI(Uri.parse(filePath), cordova);
+        filePath = FileHelper.getRealPath(filePath, cordova);
 
         File file = new File(filePath);
         return file;
@@ -849,7 +833,7 @@ public class FileUtils extends CordovaPlugin {
 
         JSONObject metadata = new JSONObject();
         metadata.put("size", file.length());
-        metadata.put("type", getMimeType(filePath));
+        metadata.put("type", FileHelper.getMimeType(filePath, cordova));
         metadata.put("name", file.getName());
         metadata.put("fullPath", filePath);
         metadata.put("lastModifiedDate", file.lastModified());
@@ -900,21 +884,21 @@ public class FileUtils extends CordovaPlugin {
     }
 
     /**
-     * Returns a JSON Object representing a directory on the device's file system
+     * Returns a JSON object representing the given File.
      *
-     * @param path to the directory
-     * @return
+     * @param file the File to convert
+     * @return a JSON representation of the given File
      * @throws JSONException
      */
-    public JSONObject getEntry(File file) throws JSONException {
+    public static JSONObject getEntry(File file) throws JSONException {
         JSONObject entry = new JSONObject();
 
         entry.put("isFile", file.isFile());
         entry.put("isDirectory", file.isDirectory());
         entry.put("name", file.getName());
         entry.put("fullPath", "file://" + file.getAbsolutePath());
-        // I can't add the next thing it as it would be an infinite loop
-        //entry.put("filesystem", null);
+        // The file system can't be specified, as it would lead to an infinite loop.
+        // entry.put("filesystem", null);
 
         return entry;
     }
@@ -930,123 +914,83 @@ public class FileUtils extends CordovaPlugin {
         return getEntry(new File(path));
     }
 
-    /**
-     * Identifies if action to be executed returns a value and should be run synchronously.
-     *
-     * @param action	The action to execute
-     * @return			T=returns value
-     */
-    public boolean isSynch(String action) {
-        if (action.equals("testSaveLocationExists")) {
-            return true;
-        }
-        else if (action.equals("getFreeDiskSpace")) {
-            return true;
-        }
-        else if (action.equals("testFileExists")) {
-            return true;
-        }
-        else if (action.equals("testDirectoryExists")) {
-            return true;
-        }
-        return false;
-    }
 
     //--------------------------------------------------------------------------
     // LOCAL METHODS
     //--------------------------------------------------------------------------
 
     /**
-     * Read content of text file.
+     * Read the contents of a file.
+     * This is done in a background thread; the result is sent to the callback.
      *
-     * @param filename			The name of the file.
-     * @param encoding			The encoding to return contents as.  Typical value is UTF-8.
-     * 							(see http://www.iana.org/assignments/character-sets)
-     * @param start                     Start position in the file.
-     * @param end                       End position to stop at (exclusive).
-     * @return					Contents of file.
-     * @throws FileNotFoundException, IOException
+     * @param filename          The name of the file.
+     * @param start             Start position in the file.
+     * @param end               End position to stop at (exclusive).
+     * @param callbackContext   The context through which to send the result.
+     * @param encoding          The encoding to return contents as.  Typical value is UTF-8. (see http://www.iana.org/assignments/character-sets)
+     * @param resultType        The desired type of data to send to the callback.
+     * @return                  Contents of file.
      */
-    public String readAsText(String filename, String encoding, int start, int end) throws FileNotFoundException, IOException {
-        int diff = end - start;
-        byte[] bytes = new byte[1000];
-        BufferedInputStream bis = new BufferedInputStream(getPathFromUri(filename), 1024);
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        int numRead = 0;
-
-        if (start > 0) {
-            bis.skip(start);
-        }
-
-        while ( diff > 0 && (numRead = bis.read(bytes, 0, Math.min(1000, diff))) >= 0) {
-            diff -= numRead;
-            bos.write(bytes, 0, numRead);
-        }
-
-        return new String(bos.toByteArray(), encoding);
+    public void readFileAs(final String filename, final int start, final int end, final CallbackContext callbackContext, final String encoding, final int resultType) {
+        this.cordova.getThreadPool().execute(new Runnable() {
+            public void run() {
+                try {
+                    byte[] bytes = readAsBinaryHelper(filename, start, end);
+                    
+                    PluginResult result;
+                    switch (resultType) {
+                        case PluginResult.MESSAGE_TYPE_STRING:
+                            result = new PluginResult(PluginResult.Status.OK, new String(bytes, encoding));
+                            break;
+                        case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
+                            result = new PluginResult(PluginResult.Status.OK, bytes);
+                            break;
+                        case PluginResult.MESSAGE_TYPE_BINARYSTRING:
+                            result = new PluginResult(PluginResult.Status.OK, bytes, true);
+                            break;
+                        default: // Base64.
+                            String contentType = FileHelper.getMimeType(filename, cordova);
+                            byte[] base64 = Base64.encodeBase64(bytes);
+                            String s = "data:" + contentType + ";base64," + new String(base64, "US-ASCII");
+                            result = new PluginResult(PluginResult.Status.OK, s);
+                    }
+
+                    callbackContext.sendPluginResult(result);
+                } catch (FileNotFoundException e) {
+                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_FOUND_ERR));
+                } catch (IOException e) {
+                    Log.d(LOG_TAG, e.getLocalizedMessage());
+                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_READABLE_ERR));
+                }
+            }
+        });
     }
 
     /**
-     * Read content of text file and return as base64 encoded data url.
+     * Read the contents of a file as binary.
+     * This is done synchronously; the result is returned.
      *
-     * @param filename			The name of the file.
-     * @return					Contents of file = data:<media type>;base64,<data>
-     * @throws FileNotFoundException, IOException
+     * @param filename          The name of the file.
+     * @param start             Start position in the file.
+     * @param end               End position to stop at (exclusive).
+     * @return                  Contents of the file as a byte[].
+     * @throws IOException
      */
-    public String readAsDataURL(String filename, int start, int end) throws FileNotFoundException, IOException {
-        int diff = end - start;
-        byte[] bytes = new byte[1000];
-        BufferedInputStream bis = new BufferedInputStream(getPathFromUri(filename), 1024);
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        int numRead = 0;
+    private byte[] readAsBinaryHelper(String filename, int start, int end) throws IOException {
+        int numBytesToRead = end - start;
+        byte[] bytes = new byte[numBytesToRead];
+        InputStream inputStream = FileHelper.getInputStreamFromUriString(filename, cordova);
+        int numBytesRead = 0;
 
         if (start > 0) {
-            bis.skip(start);
-        }
-
-        while (diff > 0 && (numRead = bis.read(bytes, 0, Math.min(1000, diff))) >= 0) {
-            diff -= numRead;
-            bos.write(bytes, 0, numRead);
+            inputStream.skip(start);
         }
 
-        // Determine content type from file name
-        String contentType = null;
-        if (filename.startsWith("content:")) {
-            Uri fileUri = Uri.parse(filename);
-            contentType = this.cordova.getActivity().getContentResolver().getType(fileUri);
-        }
-        else {
-            contentType = getMimeType(filename);
+        while (numBytesToRead > 0 && (numBytesRead = inputStream.read(bytes, numBytesRead, numBytesToRead)) >= 0) {
+            numBytesToRead -= numBytesRead;
         }
 
-        byte[] base64 = Base64.encodeBase64(bos.toByteArray());
-        String data = "data:" + contentType + ";base64," + new String(base64);
-        return data;
-    }
-
-    /**
-     * Looks up the mime type of a given file name.
-     *
-     * @param filename
-     * @return a mime type
-     */
-    public static String getMimeType(String filename) {
-        if (filename != null) {
-            // Stupid bug in getFileExtensionFromUrl when the file name has a space
-            // So we need to replace the space with a url encoded %20
-
-            // CB-2185: Stupid bug not putting JPG extension in the mime-type map
-            String url = filename.replace(" ", "%20").toLowerCase();
-            MimeTypeMap map = MimeTypeMap.getSingleton();
-            String extension = MimeTypeMap.getFileExtensionFromUrl(url);
-            if (extension.toLowerCase().equals("3ga")) {
-                return "audio/3gpp";
-            } else {
-                return map.getMimeTypeFromExtension(extension);
-            }
-        } else {
-            return "";
-        }
+        return bytes;
     }
 
     /**
@@ -1060,11 +1004,11 @@ public class FileUtils extends CordovaPlugin {
      */
     /**/
     public long write(String filename, String data, int offset) throws FileNotFoundException, IOException, NoModificationAllowedException {
-    	if (filename.startsWith("content://")) {
-    		throw new NoModificationAllowedException("Couldn't write to file given its content URI");
-    	}
+        if (filename.startsWith("content://")) {
+            throw new NoModificationAllowedException("Couldn't write to file given its content URI");
+        }
 
-        filename = getRealPathFromURI(Uri.parse(filename), cordova);
+        filename = FileHelper.getRealPath(filename, cordova);
 
         boolean append = false;
         if (offset > 0) {
@@ -1093,11 +1037,11 @@ public class FileUtils extends CordovaPlugin {
      * @throws NoModificationAllowedException
      */
     private long truncateFile(String filename, long size) throws FileNotFoundException, IOException, NoModificationAllowedException {
-    	if (filename.startsWith("content://")) {
-    		throw new NoModificationAllowedException("Couldn't truncate file given its content URI");
-    	}
+        if (filename.startsWith("content://")) {
+            throw new NoModificationAllowedException("Couldn't truncate file given its content URI");
+        }
 
-        filename = getRealPathFromURI(Uri.parse(filename), cordova);
+        filename = FileHelper.getRealPath(filename, cordova);
 
         RandomAccessFile raf = new RandomAccessFile(filename, "rw");
         try {
@@ -1112,48 +1056,4 @@ public class FileUtils extends CordovaPlugin {
             raf.close();
         }
     }
-
-    /**
-     * Get an input stream based on file path or content:// uri
-     *
-     * @param path
-     * @return an input stream
-     * @throws FileNotFoundException
-     */
-    private InputStream getPathFromUri(String path) throws FileNotFoundException {
-        if (path.startsWith("content")) {
-            Uri uri = Uri.parse(path);
-            return cordova.getActivity().getContentResolver().openInputStream(uri);
-        }
-        else {
-            path = getRealPathFromURI(Uri.parse(path), cordova);
-            return new FileInputStream(path);
-        }
-    }
-
-    /**
-     * Queries the media store to find out what the file path is for the Uri we supply
-     *
-     * @param contentUri the Uri of the audio/image/video
-     * @param cordova the current application context
-     * @return the full path to the file
-     */
-    @SuppressWarnings("deprecation")
-    protected static String getRealPathFromURI(Uri contentUri, CordovaInterface cordova) {
-        final String scheme = contentUri.getScheme();
-
-        if (scheme == null) {
-        	return contentUri.toString();
-    	} else if (scheme.compareTo("content") == 0) {
-            String[] proj = { _DATA };
-            Cursor cursor = cordova.getActivity().managedQuery(contentUri, proj, null, null, null);
-            int column_index = cursor.getColumnIndexOrThrow(_DATA);
-            cursor.moveToFirst();
-            return cursor.getString(column_index);
-        } else if (scheme.compareTo("file") == 0) {
-            return contentUri.getPath();
-        } else {
-            return contentUri.toString();
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java b/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java
index 86aa628..e7cdce0 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java
@@ -150,7 +150,7 @@ public class GeoBroker extends CordovaPlugin {
             o.put("altitude", (loc.hasAltitude() ? loc.getAltitude() : null));
             o.put("accuracy", loc.getAccuracy());
             o.put("heading", (loc.hasBearing() ? (loc.hasSpeed() ? loc.getBearing() : null) : null));
-            o.put("speed", loc.getSpeed());
+            o.put("velocity", loc.getSpeed());
             o.put("timestamp", loc.getTime());
         } catch (JSONException e) {
             // TODO Auto-generated catch block

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java b/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
index a96b242..2142714 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@ -42,7 +42,7 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
 
     @Override
     public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
-        if(url.contains("?") || url.contains("#")){
+        if(url.contains("?") || url.contains("#") || needsIceCreamSpaceInAssetUrlFix(url)){
             return generateWebResourceResponse(url);
         } else {
             return super.shouldInterceptRequest(view, url);
@@ -80,4 +80,18 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
         return null;
     }
     
+    private static boolean needsIceCreamSpaceInAssetUrlFix(String url) {
+        if (!url.contains("%20")){
+            return false;
+        }
+
+        switch(android.os.Build.VERSION.SDK_INT){
+            case android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH:
+            case android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1:
+                return true;
+            default:
+                return false;
+        }
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java b/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
index 7e7f862..48e27c6 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
@@ -35,7 +35,9 @@ import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.net.Uri;
+import android.os.Bundle;
 import android.text.InputType;
 import android.util.Log;
 import android.util.TypedValue;
@@ -48,6 +50,7 @@ import android.view.WindowManager.LayoutParams;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.webkit.WebChromeClient;
+import android.webkit.GeolocationPermissions.Callback;
 import android.webkit.WebSettings;
 import android.webkit.WebStorage;
 import android.webkit.WebView;
@@ -69,6 +72,8 @@ public class InAppBrowser extends CordovaPlugin {
     private static final String EXIT_EVENT = "exit";
     private static final String LOAD_START_EVENT = "loadstart";
     private static final String LOAD_STOP_EVENT = "loadstop";
+    private static final String LOAD_ERROR_EVENT = "loaderror";
+    private static final String CLOSE_BUTTON_CAPTION = "closebuttoncaption";
     private long MAX_QUOTA = 100 * 1024 * 1024;
 
     private Dialog dialog;
@@ -76,6 +81,7 @@ public class InAppBrowser extends CordovaPlugin {
     private EditText edittext;
     private boolean showLocationBar = true;
     private CallbackContext callbackContext;
+    private String buttonLabel = "Done";
     
     /**
      * Executes the request and returns PluginResult.
@@ -174,8 +180,12 @@ public class InAppBrowser extends CordovaPlugin {
                 option = new StringTokenizer(features.nextToken(), "=");
                 if (option.hasMoreElements()) {
                     String key = option.nextToken();
-                    Boolean value = option.nextToken().equals("no") ? Boolean.FALSE : Boolean.TRUE;
-                    map.put(key, value);
+                    if (key.equalsIgnoreCase(CLOSE_BUTTON_CAPTION)) {
+                        this.buttonLabel = option.nextToken();
+                    } else {
+                        Boolean value = option.nextToken().equals("no") ? Boolean.FALSE : Boolean.TRUE;
+                        map.put(key, value);
+                    }
                 }
             }
             return map;
@@ -221,6 +231,7 @@ public class InAppBrowser extends CordovaPlugin {
      */
     private void closeDialog() {
         try {
+            this.inAppWebView.loadUrl("about:blank");
             JSONObject obj = new JSONObject();
             obj.put("type", EXIT_EVENT);
 
@@ -289,7 +300,10 @@ public class InAppBrowser extends CordovaPlugin {
         // Determine if we should hide the location bar.
         showLocationBar = true;
         if (features != null) {
-            showLocationBar = features.get(LOCATION).booleanValue();
+            Boolean show = features.get(LOCATION);
+            if (show != null) {
+                showLocationBar = show.booleanValue();
+            }
         }
         
         final CordovaWebView thatWebView = this.webView;
@@ -405,7 +419,7 @@ public class InAppBrowser extends CordovaPlugin {
                 close.setLayoutParams(closeLayoutParams);
                 forward.setContentDescription("Close Button");
                 close.setId(5);
-                close.setText("Done");
+                close.setText(buttonLabel);
                 close.setOnClickListener(new View.OnClickListener() {
                     public void onClick(View v) {
                         closeDialog();
@@ -428,10 +442,18 @@ public class InAppBrowser extends CordovaPlugin {
                  */
                 // @TODO: replace with settings.setPluginState(android.webkit.WebSettings.PluginState.ON)
                 settings.setPluginsEnabled(true);
-                settings.setDatabaseEnabled(true);
-                String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath();
-                settings.setDatabasePath(databasePath);
+                
+                //Toggle whether this is enabled or not!
+                Bundle appSettings = cordova.getActivity().getIntent().getExtras();
+                boolean enableDatabase = appSettings.getBoolean("InAppBrowserStorageEnabled", true);
+                if(enableDatabase)
+                {
+                    String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath();
+                    settings.setDatabasePath(databasePath);
+                    settings.setDatabaseEnabled(true);
+                }
                 settings.setDomStorageEnabled(true);
+               
                 inAppWebView.loadUrl(url);
                 inAppWebView.setId(6);
                 inAppWebView.getSettings().setLoadWithOverviewMode(true);
@@ -472,16 +494,24 @@ public class InAppBrowser extends CordovaPlugin {
     }
 
     /**
-     * Create a new plugin result and send it back to JavaScript
+     * Create a new plugin success result and send it back to JavaScript
      *
      * @param obj a JSONObject contain event payload information
      */
     private void sendUpdate(JSONObject obj, boolean keepCallback) {
-        PluginResult result = new PluginResult(PluginResult.Status.OK, obj);
+        sendUpdate(obj, keepCallback, PluginResult.Status.OK);
+    }
+
+    /**
+     * Create a new plugin result and send it back to JavaScript
+     *
+     * @param obj a JSONObject contain event payload information
+     * @param status the status code to return to the JavaScript environment
+     */    private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) {
+        PluginResult result = new PluginResult(status, obj);
         result.setKeepCallback(keepCallback);
         this.callbackContext.sendPluginResult(result);
     }
-
     public class InAppChromeClient extends WebChromeClient {
 
         /**
@@ -514,6 +544,18 @@ public class InAppBrowser extends CordovaPlugin {
                 quotaUpdater.updateQuota(currentQuota);
             }
         }
+
+        /**
+         * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
+         *
+         * @param origin
+         * @param callback
+         */
+        @Override
+        public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
+            super.onGeolocationPermissionsShowPrompt(origin, callback);
+            callback.invoke(origin, true, false);
+        }
     }
     
     /**
@@ -543,10 +585,62 @@ public class InAppBrowser extends CordovaPlugin {
         @Override
         public void onPageStarted(WebView view, String url,  Bitmap favicon) {
             super.onPageStarted(view, url, favicon);
-            String newloc;
+            String newloc = "";
             if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) {
                 newloc = url;
-            } else {
+            } 
+            // If dialing phone (tel:5551212)
+            else if (url.startsWith(WebView.SCHEME_TEL)) {
+                try {
+                    Intent intent = new Intent(Intent.ACTION_DIAL);
+                    intent.setData(Uri.parse(url));
+                    cordova.getActivity().startActivity(intent);
+                } catch (android.content.ActivityNotFoundException e) {
+                    LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
+                }
+            }
+
+            else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:")) {
+                try {
+                    Intent intent = new Intent(Intent.ACTION_VIEW);
+                    intent.setData(Uri.parse(url));
+                    cordova.getActivity().startActivity(intent);
+                } catch (android.content.ActivityNotFoundException e) {
+                    LOG.e(LOG_TAG, "Error with " + url + ": " + e.toString());
+                }
+            }
+            // If sms:5551212?body=This is the message
+            else if (url.startsWith("sms:")) {
+                try {
+                    Intent intent = new Intent(Intent.ACTION_VIEW);
+
+                    // Get address
+                    String address = null;
+                    int parmIndex = url.indexOf('?');
+                    if (parmIndex == -1) {
+                        address = url.substring(4);
+                    }
+                    else {
+                        address = url.substring(4, parmIndex);
+
+                        // If body, then set sms body
+                        Uri uri = Uri.parse(url);
+                        String query = uri.getQuery();
+                        if (query != null) {
+                            if (query.startsWith("body=")) {
+                                intent.putExtra("sms_body", query.substring(5));
+                            }
+                        }
+                    }
+                    intent.setData(Uri.parse("sms:" + address));
+                    intent.putExtra("address", address);
+                    intent.setType("vnd.android-dir/mms-sms");
+                    cordova.getActivity().startActivity(intent);
+                } catch (android.content.ActivityNotFoundException e) {
+                    LOG.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
+                }
+            }
+            else {
                 newloc = "http://" + url;
             }
 
@@ -578,5 +672,22 @@ public class InAppBrowser extends CordovaPlugin {
                 Log.d(LOG_TAG, "Should never happen");
             }
         }
+        
+        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+            super.onReceivedError(view, errorCode, description, failingUrl);
+            
+            try {
+                JSONObject obj = new JSONObject();
+                obj.put("type", LOAD_ERROR_EVENT);
+                obj.put("url", failingUrl);
+                obj.put("code", errorCode);
+                obj.put("message", description);
+    
+                sendUpdate(obj, true, PluginResult.Status.ERROR);
+            } catch (JSONException ex) {
+                Log.d(LOG_TAG, "Should never happen");
+            }
+        	
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/JSONUtils.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/JSONUtils.java b/lib/cordova-android/framework/src/org/apache/cordova/JSONUtils.java
new file mode 100644
index 0000000..77df876
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/JSONUtils.java
@@ -0,0 +1,24 @@
+package org.apache.cordova;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+public class JSONUtils {
+	public static List<String> toStringList(JSONArray array) throws JSONException {
+        if(array == null) {
+            return null;
+        }
+        else {
+            List<String> list = new ArrayList<String>();
+
+            for (int i = 0; i < array.length(); i++) {
+                list.add(array.get(i).toString());
+            }
+
+            return list;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java b/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
index 83e1778..ea684a4 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
@@ -409,6 +409,9 @@ public class NativeToJsMessageQueue {
                 case PluginResult.MESSAGE_TYPE_STRING: // s
                     ret += 1 + pluginResult.getStrMessage().length();
                     break;
+                case PluginResult.MESSAGE_TYPE_BINARYSTRING:
+                    ret += 1 + pluginResult.getMessage().length();
+                    break;
                 case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
                     ret += 1 + pluginResult.getMessage().length();
                     break;
@@ -451,7 +454,11 @@ public class NativeToJsMessageQueue {
                     sb.append('s');
                     sb.append(pluginResult.getStrMessage());
                     break;
-                case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
+                case PluginResult.MESSAGE_TYPE_BINARYSTRING: // S
+                    sb.append('S');
+                    sb.append(pluginResult.getMessage());
+                    break;                    
+                case PluginResult.MESSAGE_TYPE_ARRAYBUFFER: // A
                     sb.append('A');
                     sb.append(pluginResult.getMessage());
                     break;
@@ -473,9 +480,9 @@ public class NativeToJsMessageQueue {
                   .append(success)
                   .append(",")
                   .append(status)
-                  .append(",")
+                  .append(",[")
                   .append(pluginResult.getMessage())
-                  .append(",")
+                  .append("],")
                   .append(pluginResult.getKeepCallback())
                   .append(");");
             }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/Notification.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Notification.java b/lib/cordova-android/framework/src/org/apache/cordova/Notification.java
index 958ab26..9d96062 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/Notification.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Notification.java
@@ -24,6 +24,7 @@ import org.apache.cordova.api.CordovaPlugin;
 import org.apache.cordova.api.PluginResult;
 import org.json.JSONArray;
 import org.json.JSONException;
+import org.json.JSONObject;
 import android.app.AlertDialog;
 import android.app.ProgressDialog;
 import android.content.Context;
@@ -32,6 +33,7 @@ import android.media.Ringtone;
 import android.media.RingtoneManager;
 import android.net.Uri;
 import android.os.Vibrator;
+import android.widget.EditText;
 
 /**
  * This class provides access to notifications on the device.
@@ -68,7 +70,11 @@ public class Notification extends CordovaPlugin {
             return true;
         }
         else if (action.equals("confirm")) {
-            this.confirm(args.getString(0), args.getString(1), args.getString(2), callbackContext);
+            this.confirm(args.getString(0), args.getString(1), args.getJSONArray(2), callbackContext);
+            return true;
+        }
+        else if (action.equals("prompt")) {
+            this.prompt(args.getString(0), args.getString(1), args.getJSONArray(2), callbackContext);
             return true;
         }
         else if (action.equals("activityStart")) {
@@ -170,7 +176,7 @@ public class Notification extends CordovaPlugin {
                         callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0));
                     }
                 });
-                
+
                 dlg.create();
                 dlg.show();
             };
@@ -188,10 +194,9 @@ public class Notification extends CordovaPlugin {
      * @param buttonLabels      A comma separated list of button labels (Up to 3 buttons)
      * @param callbackContext   The callback context.
      */
-    public synchronized void confirm(final String message, final String title, String buttonLabels, final CallbackContext callbackContext) {
+    public synchronized void confirm(final String message, final String title, final JSONArray buttonLabels, final CallbackContext callbackContext) {
 
         final CordovaInterface cordova = this.cordova;
-        final String[] fButtons = buttonLabels.split(",");
 
         Runnable runnable = new Runnable() {
             public void run() {
@@ -201,37 +206,43 @@ public class Notification extends CordovaPlugin {
                 dlg.setCancelable(true);
 
                 // First button
-                if (fButtons.length > 0) {
-                    dlg.setNegativeButton(fButtons[0],
-                            new AlertDialog.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int which) {
-                                    dialog.dismiss();
-                                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 1));
-                                }
-                            });
+                if (buttonLabels.length() > 0) {
+                    try {
+						dlg.setNegativeButton(buttonLabels.getString(0),
+						        new AlertDialog.OnClickListener() {
+						            public void onClick(DialogInterface dialog, int which) {
+						                dialog.dismiss();
+						                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 1));
+						            }
+						        });
+					} catch (JSONException e) { }
                 }
 
                 // Second button
-                if (fButtons.length > 1) {
-                    dlg.setNeutralButton(fButtons[1],
-                            new AlertDialog.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int which) {
-                                    dialog.dismiss();
-                                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 2));
-                                }
-                            });
+                if (buttonLabels.length() > 1) {
+                    try {
+						dlg.setNeutralButton(buttonLabels.getString(1),
+						        new AlertDialog.OnClickListener() {
+						            public void onClick(DialogInterface dialog, int which) {
+						                dialog.dismiss();
+						                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 2));
+						            }
+						        });
+					} catch (JSONException e) { }
                 }
 
                 // Third button
-                if (fButtons.length > 2) {
-                    dlg.setPositiveButton(fButtons[2],
-                            new AlertDialog.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int which) {
-                                    dialog.dismiss();
-                                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 3));
-                                }
-                            }
-                            );
+                if (buttonLabels.length() > 2) {
+                    try {
+						dlg.setPositiveButton(buttonLabels.getString(2),
+						        new AlertDialog.OnClickListener() {
+						            public void onClick(DialogInterface dialog, int which) {
+						                dialog.dismiss();
+						                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 3));
+						            }
+						        }
+						        );
+					} catch (JSONException e) { }
                 }
                 dlg.setOnCancelListener(new AlertDialog.OnCancelListener() {
                     public void onCancel(DialogInterface dialog)
@@ -249,6 +260,104 @@ public class Notification extends CordovaPlugin {
     }
 
     /**
+     * Builds and shows a native Android prompt dialog with given title, message, buttons.
+     * This dialog only shows up to 3 buttons.  Any labels after that will be ignored.
+     * The following results are returned to the JavaScript callback identified by callbackId:
+     *     buttonIndex			Index number of the button selected
+     *     input1				The text entered in the prompt dialog box
+     *
+     * @param message           The message the dialog should display
+     * @param title             The title of the dialog
+     * @param buttonLabels      A comma separated list of button labels (Up to 3 buttons)
+     * @param callbackContext   The callback context.
+     */
+    public synchronized void prompt(final String message, final String title, final JSONArray buttonLabels, final CallbackContext callbackContext) {
+    	
+        final CordovaInterface cordova = this.cordova;
+        final EditText promptInput =  new EditText(cordova.getActivity());
+
+        Runnable runnable = new Runnable() {
+            public void run() {
+                AlertDialog.Builder dlg = new AlertDialog.Builder(cordova.getActivity());
+                dlg.setMessage(message);
+                dlg.setTitle(title);
+                dlg.setCancelable(true);
+                
+                dlg.setView(promptInput);
+                
+                final JSONObject result = new JSONObject();
+                
+                // First button
+                if (buttonLabels.length() > 0) {
+                    try {
+						dlg.setNegativeButton(buttonLabels.getString(0),
+						        new AlertDialog.OnClickListener() {
+						            public void onClick(DialogInterface dialog, int which) {
+						                dialog.dismiss();
+						                try {
+											result.put("buttonIndex",1);
+							                result.put("input1", promptInput.getText());
+										} catch (JSONException e) { e.printStackTrace(); }
+						                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
+						            }
+						        });
+					} catch (JSONException e) { }
+                }
+
+                // Second button
+                if (buttonLabels.length() > 1) {
+                    try {
+						dlg.setNeutralButton(buttonLabels.getString(1),
+						        new AlertDialog.OnClickListener() {
+						            public void onClick(DialogInterface dialog, int which) {
+						                dialog.dismiss();
+						                try {
+											result.put("buttonIndex",2);
+							                result.put("input1", promptInput.getText());
+										} catch (JSONException e) { e.printStackTrace(); }
+						                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
+						            }
+						        });
+					} catch (JSONException e) { }
+                }
+
+                // Third button
+                if (buttonLabels.length() > 2) {
+                    try {
+						dlg.setPositiveButton(buttonLabels.getString(2),
+						        new AlertDialog.OnClickListener() {
+						            public void onClick(DialogInterface dialog, int which) {
+						                dialog.dismiss();
+						                try {
+											result.put("buttonIndex",3);
+							                result.put("input1", promptInput.getText());
+										} catch (JSONException e) { e.printStackTrace(); }
+						                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
+						            }
+						        }
+						        );
+					} catch (JSONException e) { }
+                }
+                dlg.setOnCancelListener(new AlertDialog.OnCancelListener() {
+                    public void onCancel(DialogInterface dialog)
+                    {
+                        dialog.dismiss();
+		                try {
+							result.put("buttonIndex",0);
+			                result.put("input1", promptInput.getText());
+						} catch (JSONException e) { e.printStackTrace(); }
+		                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
+                    }
+                });
+
+                dlg.create();
+                dlg.show();
+                
+            };
+        };
+        this.cordova.getActivity().runOnUiThread(runnable);
+    }
+    /**
      * Show the spinner.
      *
      * @param title     Title of the dialog

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/api/CallbackContext.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/CallbackContext.java b/lib/cordova-android/framework/src/org/apache/cordova/api/CallbackContext.java
index 2f7b15f..a5d1255 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/CallbackContext.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/CallbackContext.java
@@ -79,6 +79,15 @@ public class CallbackContext {
     public void success(byte[] message) {
         sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
     }
+    
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     *
+     * @param message           The message to add to the success result.
+     */
+    public void success(int message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
+    }
 
     /**
      * Helper for success callbacks that just returns the Status.OK by default

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaPlugin.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaPlugin.java b/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaPlugin.java
index f4c785e..2b225e6 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaPlugin.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaPlugin.java
@@ -22,7 +22,12 @@ import org.apache.cordova.CordovaArgs;
 import org.apache.cordova.CordovaWebView;
 import org.json.JSONArray;
 import org.json.JSONException;
+
+import android.annotation.TargetApi;
 import android.content.Intent;
+import android.os.Build;
+import android.util.Log;
+import android.webkit.WebResourceResponse;
 
 /**
  * Plugins must extend this class and override one of the execute methods.
@@ -150,7 +155,7 @@ public class CordovaPlugin {
     }
 
     /**
-     * By specifying a <url-filter> in plugins.xml you can map a URL (using startsWith atm) to this method.
+     * By specifying a <url-filter> in config.xml you can map a URL (using startsWith atm) to this method.
      *
      * @param url				The URL that is trying to be loaded in the Cordova webview.
      * @return					Return true to prevent the URL from loading. Default is false.
@@ -160,6 +165,17 @@ public class CordovaPlugin {
     }
 
     /**
+     * By specifying a <url-filter> in config.xml you can map a URL prefix to this method. It applies to all resources loaded in the WebView, not just top-level navigation.
+     *
+     * @param url               The URL of the resource to be loaded.
+     * @return                  Return a WebResourceResponse for the resource, or null to let the WebView handle it normally.
+     */
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+	public WebResourceResponse shouldInterceptRequest(String url) {
+        return null;
+    }
+
+    /**
      * Called when the WebView does a top-level navigation or refreshes.
      *
      * Plugins should stop any long-running processes and clean up internal state.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
index d0e6aef..337ef12 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
@@ -30,6 +30,8 @@ import org.xmlpull.v1.XmlPullParserException;
 import android.content.Intent;
 import android.content.res.XmlResourceParser;
 
+import android.webkit.WebResourceResponse;
+
 /**
  * PluginManager is exposed to JavaScript in the Cordova WebView.
  *
@@ -118,7 +120,7 @@ public class PluginManager {
                     // System.out.println("Plugin: "+name+" => "+value);
                     onload = "true".equals(xml.getAttributeValue(null, "onload"));
                     entry = new PluginEntry(service, pluginClass, onload);
-                    this.addService(entry);                   
+                    this.addService(entry);
                 }
                 //What is this?
                 else if (strNode.equals("url-filter")) {
@@ -367,6 +369,25 @@ public class PluginManager {
     }
 
     /**
+     * Called when the WebView is loading any resource, top-level or not.
+     *
+     * Uses the same url-filter tag as onOverrideUrlLoading.
+     *
+     * @param url               The URL of the resource to be loaded.
+     * @return                  Return a WebResourceResponse with the resource, or null if the WebView should handle it.
+     */
+    public WebResourceResponse shouldInterceptRequest(String url) {
+        Iterator<Entry<String, String>> it = this.urlMap.entrySet().iterator();
+        while (it.hasNext()) {
+            HashMap.Entry<String, String> pairs = it.next();
+            if (url.startsWith(pairs.getKey())) {
+                return this.getPlugin(pairs.getValue()).shouldInterceptRequest(url);
+            }
+        }
+        return null;
+    }
+
+    /**
      * Called when the app navigates or refreshes.
      */
     public void onReset() {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-android/framework/src/org/apache/cordova/api/PluginResult.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginResult.java b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginResult.java
index 4c1d833..a642200 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginResult.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginResult.java
@@ -71,11 +71,15 @@ public class PluginResult {
     }
 
     public PluginResult(Status status, byte[] data) {
+        this(status, data, false);
+    }
+
+    public PluginResult(Status status, byte[] data, boolean binaryString) {
         this.status = status.ordinal();
-        this.messageType = MESSAGE_TYPE_ARRAYBUFFER;
+        this.messageType = binaryString ? MESSAGE_TYPE_BINARYSTRING : MESSAGE_TYPE_ARRAYBUFFER;
         this.encodedMessage = Base64.encodeToString(data, Base64.NO_WRAP);
     }
-
+    
     public void setKeepCallback(boolean b) {
         this.keepCallback = b;
     }
@@ -143,6 +147,9 @@ public class PluginResult {
     public static final int MESSAGE_TYPE_BOOLEAN = 4;
     public static final int MESSAGE_TYPE_NULL = 5;
     public static final int MESSAGE_TYPE_ARRAYBUFFER = 6;
+    // Use BINARYSTRING when your string may contain null characters.
+    // This is required to work around a bug in the platform :(.
+    public static final int MESSAGE_TYPE_BINARYSTRING = 7;
 
     public static String[] StatusMessages = new String[] {
         "No result",

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-blackberry/bin/create
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/create b/lib/cordova-blackberry/bin/create
index 870bad1..b7e719b 100755
--- a/lib/cordova-blackberry/bin/create
+++ b/lib/cordova-blackberry/bin/create
@@ -56,6 +56,19 @@ function on_error {
     [ -d "$PROJECT_PATH" ] && rm -rf "$PROJECT_PATH"
 }
 
+function replace {
+    local pattern=$1
+    local filename=$2
+    # Mac OS X requires -i argument
+    if [[ "$OSTYPE" =~ "darwin" ]]
+    then
+        /usr/bin/sed -i '' -e $pattern "$filename"
+    elif [[ "$OSTYPE" =~ "linux" ]]
+    then
+        /bin/sed -i -e $pattern "$filename"
+    fi
+}
+
 # we do not want the script to silently fail
 trap on_error ERR
 trap on_exit EXIT
@@ -79,13 +92,13 @@ then
 	(cd "$BUILD_PATH" && "$ANT" create -Dproject.path="$PROJECT_PATH" &> /dev/null )
     # interpolate the activity and package into config.xml
     echo "Updating config.xml ..."
-    sed -i '' -e "s/__NAME__/${NAME}/g" "$MANIFEST_PATH"
-    sed -i '' -e "s/__PACKAGE__/${PACKAGE}/g" "$MANIFEST_PATH"
+    replace "s/__NAME__/${NAME}/g" "$MANIFEST_PATH"
+    replace "s/__PACKAGE__/${PACKAGE}/g" "$MANIFEST_PATH"
 else
 	# copy project template if in distribution
 	echo "Copying assets and resources ..."
 	cp -r "$BUILD_PATH/sample/." "$PROJECT_PATH"
     echo "Updating config.xml ..."
-    sed -i '' -e "s/cordovaExample/${NAME}/g" "$MANIFEST_PATH"
-    sed -i '' -e "s/org.apache.cordova.example/${PACKAGE}/g" "$MANIFEST_PATH"
+    replace "s/cordovaExample/${NAME}/g" "$MANIFEST_PATH"
+    replace "s/org.apache.cordova.example/${PACKAGE}/g" "$MANIFEST_PATH"
 fi

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/37b92ff4/lib/cordova-blackberry/bin/templates/project/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/www/index.html b/lib/cordova-blackberry/bin/templates/project/www/index.html
index f083790..6b53abc 100644
--- a/lib/cordova-blackberry/bin/templates/project/www/index.html
+++ b/lib/cordova-blackberry/bin/templates/project/www/index.html
@@ -18,8 +18,8 @@
     under the License.
 -->
 <html>
-    <head>      
-        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <head>
+        <meta charset="utf-8" />
         <meta name="format-detection" content="telephone=no" />
         <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
         <link rel="stylesheet" type="text/css" href="css/index.css" />