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/01/22 02:57:59 UTC

[9/52] [partial] support for 2.4.0rc1. "vendored" the platform libs in. added Gord and Braden as contributors. removed dependency on unzip and axed the old download-cordova code.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/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
new file mode 100644
index 0000000..3c5a48b
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVReachability.m
@@ -0,0 +1,260 @@
+/*
+
+ File: Reachability.m
+ Abstract: Basic demonstration of how to use the SystemConfiguration Reachability APIs.
+ Version: 2.2
+
+ Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms.  If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under
+ Apple's copyrights in this original Apple software (the "Apple Software"), to
+ use, reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions
+ of the Apple Software.
+ Neither the name, trademarks, service marks or logos of Apple Inc. may be used
+ to endorse or promote products derived from the Apple Software without specific
+ prior written permission from Apple.  Except as expressly stated in this notice,
+ no other rights or licenses, express or implied, are granted by Apple herein,
+ including but not limited to any patent rights that may be infringed by your
+ derivative works or by other works in which the Apple Software may be
+ incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
+ DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
+ CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+ APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Copyright (C) 2010 Apple Inc. All Rights Reserved.
+
+*/
+
+#import <sys/socket.h>
+#import <netinet/in.h>
+#import <netinet6/in6.h>
+#import <arpa/inet.h>
+#import <ifaddrs.h>
+#import <netdb.h>
+
+#import <CoreFoundation/CoreFoundation.h>
+
+#import "CDVReachability.h"
+
+#define kShouldPrintReachabilityFlags 0
+
+static void CDVPrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
+{
+#if kShouldPrintReachabilityFlags
+        NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
+        (flags & kSCNetworkReachabilityFlagsIsWWAN)               ? 'W' : '-',
+        (flags & kSCNetworkReachabilityFlagsReachable)            ? 'R' : '-',
+
+        (flags & kSCNetworkReachabilityFlagsTransientConnection)  ? 't' : '-',
+        (flags & kSCNetworkReachabilityFlagsConnectionRequired)   ? 'c' : '-',
+        (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic)  ? 'C' : '-',
+        (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
+        (flags & kSCNetworkReachabilityFlagsConnectionOnDemand)   ? 'D' : '-',
+        (flags & kSCNetworkReachabilityFlagsIsLocalAddress)       ? 'l' : '-',
+        (flags & kSCNetworkReachabilityFlagsIsDirect)             ? 'd' : '-',
+        comment
+        );
+#endif
+}
+
+@implementation CDVReachability
+
+static void CDVReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
+{
+#pragma unused (target, flags)
+    //	NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
+    //	NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
+
+    // Converted the asserts above to conditionals, with safe return from the function
+    if (info == NULL) {
+        NSLog(@"info was NULL in ReachabilityCallback");
+        return;
+    }
+
+    if (![(__bridge NSObject*) info isKindOfClass:[CDVReachability class]]) {
+        NSLog(@"info was wrong class in ReachabilityCallback");
+        return;
+    }
+
+    // We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively
+    // in case someon uses the Reachability object in a different thread.
+    @autoreleasepool {
+        CDVReachability* noteObject = (__bridge CDVReachability*)info;
+        // Post a notification to notify the client that the network reachability changed.
+        [[NSNotificationCenter defaultCenter] postNotificationName:kReachabilityChangedNotification object:noteObject];
+    }
+}
+
+- (BOOL)startNotifier
+{
+    BOOL retVal = NO;
+    SCNetworkReachabilityContext context = {0, (__bridge void*)(self), NULL, NULL, NULL};
+
+    if (SCNetworkReachabilitySetCallback(reachabilityRef, CDVReachabilityCallback, &context)) {
+        if (SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
+            retVal = YES;
+        }
+    }
+    return retVal;
+}
+
+- (void)stopNotifier
+{
+    if (reachabilityRef != NULL) {
+        SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+    }
+}
+
+- (void)dealloc
+{
+    [self stopNotifier];
+    if (reachabilityRef != NULL) {
+        CFRelease(reachabilityRef);
+    }
+}
+
++ (CDVReachability*)reachabilityWithHostName:(NSString*)hostName;
+{
+    CDVReachability* retVal = NULL;
+    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
+    if (reachability != NULL) {
+        retVal = [[self alloc] init];
+        if (retVal != NULL) {
+            retVal->reachabilityRef = reachability;
+            retVal->localWiFiRef = NO;
+        }
+    }
+    return retVal;
+}
+
++ (CDVReachability*)reachabilityWithAddress:(const struct sockaddr_in*)hostAddress;
+{
+    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
+    CDVReachability* retVal = NULL;
+    if (reachability != NULL) {
+        retVal = [[self alloc] init];
+        if (retVal != NULL) {
+            retVal->reachabilityRef = reachability;
+            retVal->localWiFiRef = NO;
+        }
+    }
+    return retVal;
+}
+
++ (CDVReachability*)reachabilityForInternetConnection;
+{
+    struct sockaddr_in zeroAddress;
+    bzero(&zeroAddress, sizeof(zeroAddress));
+    zeroAddress.sin_len = sizeof(zeroAddress);
+    zeroAddress.sin_family = AF_INET;
+    return [self reachabilityWithAddress:&zeroAddress];
+}
+
++ (CDVReachability*)reachabilityForLocalWiFi;
+{
+    struct sockaddr_in localWifiAddress;
+    bzero(&localWifiAddress, sizeof(localWifiAddress));
+    localWifiAddress.sin_len = sizeof(localWifiAddress);
+    localWifiAddress.sin_family = AF_INET;
+    // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
+    localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
+    CDVReachability* retVal = [self reachabilityWithAddress:&localWifiAddress];
+    if (retVal != NULL) {
+        retVal->localWiFiRef = YES;
+    }
+    return retVal;
+}
+
+#pragma mark Network Flag Handling
+
+- (NetworkStatus)localWiFiStatusForFlags:(SCNetworkReachabilityFlags)flags
+{
+    CDVPrintReachabilityFlags(flags, "localWiFiStatusForFlags");
+
+    BOOL retVal = NotReachable;
+    if ((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect)) {
+        retVal = ReachableViaWiFi;
+    }
+    return retVal;
+}
+
+- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
+{
+    CDVPrintReachabilityFlags(flags, "networkStatusForFlags");
+    if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) {
+        // if target host is not reachable
+        return NotReachable;
+    }
+
+    BOOL retVal = NotReachable;
+
+    if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) {
+        // if target host is reachable and no connection is required
+        //  then we'll assume (for now) that your on Wi-Fi
+        retVal = ReachableViaWiFi;
+    }
+
+    if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand) != 0) ||
+            ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))) {
+        // ... and the connection is on-demand (or on-traffic) if the
+        //     calling application is using the CFSocketStream or higher APIs
+
+        if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) {
+            // ... and no [user] intervention is needed
+            retVal = ReachableViaWiFi;
+        }
+    }
+
+    if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) {
+        // ... but WWAN connections are OK if the calling application
+        //     is using the CFNetwork (CFSocketStream?) APIs.
+        retVal = ReachableViaWWAN;
+    }
+    return retVal;
+}
+
+- (BOOL)connectionRequired;
+{
+    NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
+    SCNetworkReachabilityFlags flags;
+    if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
+        return flags & kSCNetworkReachabilityFlagsConnectionRequired;
+    }
+    return NO;
+}
+
+- (NetworkStatus)currentReachabilityStatus
+{
+    NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef");
+    NetworkStatus retVal = NotReachable;
+    SCNetworkReachabilityFlags flags;
+    if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
+        if (localWiFiRef) {
+            retVal = [self localWiFiStatusForFlags:flags];
+        } else {
+            retVal = [self networkStatusForFlags:flags];
+        }
+    }
+    return retVal;
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVScreenOrientationDelegate.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVScreenOrientationDelegate.h b/lib/cordova-ios/CordovaLib/Classes/CDVScreenOrientationDelegate.h
new file mode 100644
index 0000000..7226205
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVScreenOrientationDelegate.h
@@ -0,0 +1,28 @@
+/*
+ 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>
+
+@protocol CDVScreenOrientationDelegate <NSObject>
+
+- (NSUInteger)supportedInterfaceOrientations;
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
+- (BOOL)shouldAutorotate;
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVSound.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVSound.h b/lib/cordova-ios/CordovaLib/Classes/CDVSound.h
new file mode 100644
index 0000000..6551621
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSound.h
@@ -0,0 +1,110 @@
+/*
+ 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>
+#import <AudioToolbox/AudioServices.h>
+#import <AVFoundation/AVFoundation.h>
+
+#import "CDVPlugin.h"
+
+enum CDVMediaError {
+    MEDIA_ERR_ABORTED = 1,
+    MEDIA_ERR_NETWORK = 2,
+    MEDIA_ERR_DECODE = 3,
+    MEDIA_ERR_NONE_SUPPORTED = 4
+};
+typedef NSUInteger CDVMediaError;
+
+enum CDVMediaStates {
+    MEDIA_NONE = 0,
+    MEDIA_STARTING = 1,
+    MEDIA_RUNNING = 2,
+    MEDIA_PAUSED = 3,
+    MEDIA_STOPPED = 4
+};
+typedef NSUInteger CDVMediaStates;
+
+enum CDVMediaMsg {
+    MEDIA_STATE = 1,
+    MEDIA_DURATION = 2,
+    MEDIA_POSITION = 3,
+    MEDIA_ERROR = 9
+};
+typedef NSUInteger CDVMediaMsg;
+
+@interface CDVAudioPlayer : AVAudioPlayer
+{
+    NSString* mediaId;
+}
+@property (nonatomic, copy) NSString* mediaId;
+@end
+
+@interface CDVAudioRecorder : AVAudioRecorder
+{
+    NSString* mediaId;
+}
+@property (nonatomic, copy) NSString* mediaId;
+@end
+
+@interface CDVAudioFile : NSObject
+{
+    NSString* resourcePath;
+    NSURL* resourceURL;
+    CDVAudioPlayer* player;
+    CDVAudioRecorder* recorder;
+    NSNumber* volume;
+}
+
+@property (nonatomic, strong) NSString* resourcePath;
+@property (nonatomic, strong) NSURL* resourceURL;
+@property (nonatomic, strong) CDVAudioPlayer* player;
+@property (nonatomic, strong) NSNumber* volume;
+
+@property (nonatomic, strong) CDVAudioRecorder* recorder;
+
+@end
+
+@interface CDVSound : CDVPlugin <AVAudioPlayerDelegate, AVAudioRecorderDelegate>
+{
+    NSMutableDictionary* soundCache;
+    AVAudioSession* avSession;
+}
+@property (nonatomic, strong) NSMutableDictionary* soundCache;
+@property (nonatomic, strong) AVAudioSession* avSession;
+
+- (void)startPlayingAudio:(CDVInvokedUrlCommand*)command;
+- (void)pausePlayingAudio:(CDVInvokedUrlCommand*)command;
+- (void)stopPlayingAudio:(CDVInvokedUrlCommand*)command;
+- (void)seekToAudio:(CDVInvokedUrlCommand*)command;
+- (void)release:(CDVInvokedUrlCommand*)command;
+- (void)getCurrentPositionAudio:(CDVInvokedUrlCommand*)command;
+
+- (BOOL)hasAudioSession;
+
+// helper methods
+- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId;
+- (BOOL)prepareToPlay:(CDVAudioFile*)audioFile withId:(NSString*)mediaId;
+- (NSString*)createMediaErrorWithCode:(CDVMediaError)code message:(NSString*)message;
+
+- (void)startRecordingAudio:(CDVInvokedUrlCommand*)command;
+- (void)stopRecordingAudio:(CDVInvokedUrlCommand*)command;
+
+- (void)setVolume:(CDVInvokedUrlCommand*)command;
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/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
new file mode 100644
index 0000000..e6f729a
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
@@ -0,0 +1,587 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVSound.h"
+#import "CDVViewController.h"
+#import "NSArray+Comparisons.h"
+#import "CDVJSON.h"
+
+#define DOCUMENTS_SCHEME_PREFIX @"documents://"
+#define HTTP_SCHEME_PREFIX @"http://"
+#define HTTPS_SCHEME_PREFIX @"https://"
+
+@implementation CDVSound
+
+@synthesize soundCache, avSession;
+
+// Maps a url for a resource path
+// "Naked" resource paths are assumed to be from the www folder as its base
+- (NSURL*)urlForResource:(NSString*)resourcePath
+{
+    NSURL* resourceURL = nil;
+    NSString* filePath = nil;
+
+    // first try to find HTTP:// or Documents:// resources
+
+    if ([resourcePath hasPrefix:HTTP_SCHEME_PREFIX] || [resourcePath hasPrefix:HTTPS_SCHEME_PREFIX]) {
+        // if it is a http url, use it
+        NSLog(@"Will use resource '%@' from the Internet.", resourcePath);
+        resourceURL = [NSURL URLWithString:resourcePath];
+    } else if ([resourcePath hasPrefix:DOCUMENTS_SCHEME_PREFIX]) {
+        filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", [CDVViewController applicationDocumentsDirectory]]];
+        NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath);
+    } else {
+        // attempt to find file path in www directory
+        filePath = [self.commandDelegate pathForResource:resourcePath];
+        if (filePath != nil) {
+            NSLog(@"Found resource '%@' in the web folder.", filePath);
+        } else {
+            filePath = resourcePath;
+            NSLog(@"Will attempt to use file resource '%@'", filePath);
+        }
+    }
+    // check that file exists for all but HTTP_SHEME_PREFIX
+    if (filePath != nil) {
+        // try to access file
+        NSFileManager* fMgr = [[NSFileManager alloc] init];
+        if (![fMgr fileExistsAtPath:filePath]) {
+            resourceURL = nil;
+            NSLog(@"Unknown resource '%@'", resourcePath);
+        } else {
+            // it's a valid file url, use it
+            resourceURL = [NSURL fileURLWithPath:filePath];
+        }
+    }
+    return resourceURL;
+}
+
+// Creates or gets the cached audio file resource object
+- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId
+{
+    BOOL bError = NO;
+    CDVMediaError errcode = MEDIA_ERR_NONE_SUPPORTED;
+    NSString* errMsg = @"";
+    NSString* jsString = nil;
+    CDVAudioFile* audioFile = nil;
+    NSURL* resourceURL = nil;
+
+    if ([self soundCache] == nil) {
+        [self setSoundCache:[NSMutableDictionary dictionaryWithCapacity:1]];
+    } else {
+        audioFile = [[self soundCache] objectForKey:mediaId];
+    }
+    if (audioFile == nil) {
+        // validate resourcePath and create
+
+        if ((resourcePath == nil) || ![resourcePath isKindOfClass:[NSString class]] || [resourcePath isEqualToString:@""]) {
+            bError = YES;
+            errcode = MEDIA_ERR_ABORTED;
+            errMsg = @"invalid media src argument";
+        } else {
+            resourceURL = [self urlForResource:resourcePath];
+        }
+
+        if (resourceURL == nil) {
+            bError = YES;
+            errcode = MEDIA_ERR_ABORTED;
+            errMsg = [NSString stringWithFormat:@"Cannot use audio file from resource '%@'", resourcePath];
+        }
+        if (bError) {
+            // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, errcode];
+            jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:errcode message:errMsg]];
+            [self.commandDelegate evalJs:jsString];
+        } else {
+            audioFile = [[CDVAudioFile alloc] init];
+            audioFile.resourcePath = resourcePath;
+            audioFile.resourceURL = resourceURL;
+            [[self soundCache] setObject:audioFile forKey:mediaId];
+        }
+    }
+    return audioFile;
+}
+
+// returns whether or not audioSession is available - creates it if necessary
+- (BOOL)hasAudioSession
+{
+    BOOL bSession = YES;
+
+    if (!self.avSession) {
+        NSError* error = nil;
+
+        self.avSession = [AVAudioSession sharedInstance];
+        if (error) {
+            // is not fatal if can't get AVAudioSession , just log the error
+            NSLog(@"error creating audio session: %@", [[error userInfo] description]);
+            self.avSession = nil;
+            bSession = NO;
+        }
+    }
+    return bSession;
+}
+
+// helper function to create a error object string
+- (NSString*)createMediaErrorWithCode:(CDVMediaError)code message:(NSString*)message
+{
+    NSMutableDictionary* errorDict = [NSMutableDictionary dictionaryWithCapacity:2];
+
+    [errorDict setObject:[NSNumber numberWithUnsignedInt:code] forKey:@"code"];
+    [errorDict setObject:message ? message:@"" forKey:@"message"];
+    return [errorDict JSONString];
+}
+
+- (void)create:(CDVInvokedUrlCommand*)command
+{
+    NSString* mediaId = [command.arguments objectAtIndex:0];
+    NSString* resourcePath = [command.arguments objectAtIndex:1];
+
+    CDVAudioFile* audioFile = [self audioFileForResource:resourcePath withId:mediaId];
+
+    if (audioFile == nil) {
+        NSString* errorMessage = [NSString stringWithFormat:@"Failed to initialize Media file with path %@", resourcePath];
+        NSString* jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMessage]];
+        [self.commandDelegate evalJs:jsString];
+    } else {
+        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
+        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+    }
+}
+
+- (void)setVolume:(CDVInvokedUrlCommand*)command
+{
+    NSString* callbackId = command.callbackId;
+
+#pragma unused(callbackId)
+    NSString* mediaId = [command.arguments objectAtIndex:0];
+    NSNumber* volume = [command.arguments objectAtIndex:1 withDefault:[NSNumber numberWithFloat:1.0]];
+
+    CDVAudioFile* audioFile;
+    if ([self soundCache] == nil) {
+        [self setSoundCache:[NSMutableDictionary dictionaryWithCapacity:1]];
+    } else {
+        audioFile = [[self soundCache] objectForKey:mediaId];
+        audioFile.volume = volume;
+        [[self soundCache] setObject:audioFile forKey:mediaId];
+    }
+
+    // don't care for any callbacks
+}
+
+- (void)startPlayingAudio:(CDVInvokedUrlCommand*)command
+{
+    NSString* callbackId = command.callbackId;
+
+#pragma unused(callbackId)
+    NSString* mediaId = [command.arguments objectAtIndex:0];
+    NSString* resourcePath = [command.arguments objectAtIndex:1];
+    NSDictionary* options = [command.arguments objectAtIndex:2 withDefault:nil];
+
+    BOOL bError = NO;
+    NSString* jsString = nil;
+
+    CDVAudioFile* audioFile = [self audioFileForResource:resourcePath withId:mediaId];
+
+    if (audioFile != nil) {
+        if (audioFile.player == nil) {
+            bError = [self prepareToPlay:audioFile withId:mediaId];
+        }
+        if (!bError) {
+            // audioFile.player != nil  or player was successfully created
+            // get the audioSession and set the category to allow Playing when device is locked or ring/silent switch engaged
+            if ([self hasAudioSession]) {
+                NSError* __autoreleasing err = nil;
+                NSNumber* playAudioWhenScreenIsLocked = [options objectForKey:@"playAudioWhenScreenIsLocked"];
+                BOOL bPlayAudioWhenScreenIsLocked = YES;
+                if (playAudioWhenScreenIsLocked != nil) {
+                    bPlayAudioWhenScreenIsLocked = [playAudioWhenScreenIsLocked boolValue];
+                }
+
+                NSString* sessionCategory = bPlayAudioWhenScreenIsLocked ? AVAudioSessionCategoryPlayback : AVAudioSessionCategorySoloAmbient;
+                [self.avSession setCategory:sessionCategory error:&err];
+                if (![self.avSession setActive:YES error:&err]) {
+                    // other audio with higher priority that does not allow mixing could cause this to fail
+                    NSLog(@"Unable to play audio: %@", [err localizedFailureReason]);
+                    bError = YES;
+                }
+            }
+            if (!bError) {
+                NSLog(@"Playing audio sample '%@'", audioFile.resourcePath);
+                NSNumber* loopOption = [options objectForKey:@"numberOfLoops"];
+                NSInteger numberOfLoops = 0;
+                if (loopOption != nil) {
+                    numberOfLoops = [loopOption intValue] - 1;
+                }
+                audioFile.player.numberOfLoops = numberOfLoops;
+                if (audioFile.player.isPlaying) {
+                    [audioFile.player stop];
+                    audioFile.player.currentTime = 0;
+                }
+                if (audioFile.volume != nil) {
+                    audioFile.player.volume = [audioFile.volume floatValue];
+                }
+
+                [audioFile.player play];
+                double position = round(audioFile.player.duration * 1000) / 1000;
+                jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%.3f);\n%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_DURATION, position, @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_RUNNING];
+                [self.commandDelegate evalJs:jsString];
+            }
+        }
+        if (bError) {
+            /*  I don't see a problem playing previously recorded audio so removing this section - BG
+            NSError* error;
+            // try loading it one more time, in case the file was recorded previously
+            audioFile.player = [[ AVAudioPlayer alloc ] initWithContentsOfURL:audioFile.resourceURL error:&error];
+            if (error != nil) {
+                NSLog(@"Failed to initialize AVAudioPlayer: %@\n", error);
+                audioFile.player = nil;
+            } else {
+                NSLog(@"Playing audio sample '%@'", audioFile.resourcePath);
+                audioFile.player.numberOfLoops = numberOfLoops;
+                [audioFile.player play];
+            } */
+            // error creating the session or player
+            // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR,  MEDIA_ERR_NONE_SUPPORTED];
+            jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_NONE_SUPPORTED message:nil]];
+            [self.commandDelegate evalJs:jsString];
+        }
+    }
+    // else audioFile was nil - error already returned from audioFile for resource
+    return;
+}
+
+- (BOOL)prepareToPlay:(CDVAudioFile*)audioFile withId:(NSString*)mediaId
+{
+    BOOL bError = NO;
+    NSError* __autoreleasing playerError = nil;
+
+    // create the player
+    NSURL* resourceURL = audioFile.resourceURL;
+
+    if ([resourceURL isFileURL]) {
+        audioFile.player = [[CDVAudioPlayer alloc] initWithContentsOfURL:resourceURL error:&playerError];
+    } else {
+        NSURLRequest* request = [NSURLRequest requestWithURL:resourceURL];
+        NSURLResponse* __autoreleasing response = nil;
+        NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&playerError];
+        if (playerError) {
+            NSLog(@"Unable to download audio from: %@", [resourceURL absoluteString]);
+        } else {
+            // bug in AVAudioPlayer when playing downloaded data in NSData - we have to download the file and play from disk
+            CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
+            CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
+            NSString* filePath = [NSString stringWithFormat:@"%@/%@", [NSTemporaryDirectory ()stringByStandardizingPath], uuidString];
+            CFRelease(uuidString);
+            CFRelease(uuidRef);
+
+            [data writeToFile:filePath atomically:YES];
+            NSURL* fileURL = [NSURL fileURLWithPath:filePath];
+            audioFile.player = [[CDVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&playerError];
+        }
+    }
+
+    if (playerError != nil) {
+        NSLog(@"Failed to initialize AVAudioPlayer: %@\n", [playerError localizedDescription]);
+        audioFile.player = nil;
+        if (self.avSession) {
+            [self.avSession setActive:NO error:nil];
+        }
+        bError = YES;
+    } else {
+        audioFile.player.mediaId = mediaId;
+        audioFile.player.delegate = self;
+        bError = ![audioFile.player prepareToPlay];
+    }
+    return bError;
+}
+
+- (void)stopPlayingAudio:(CDVInvokedUrlCommand*)command
+{
+    NSString* mediaId = [command.arguments objectAtIndex:0];
+    CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId];
+    NSString* jsString = nil;
+
+    if ((audioFile != nil) && (audioFile.player != nil)) {
+        NSLog(@"Stopped playing audio sample '%@'", audioFile.resourcePath);
+        [audioFile.player stop];
+        audioFile.player.currentTime = 0;
+        jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_STOPPED];
+    }  // ignore if no media playing
+    if (jsString) {
+        [self.commandDelegate evalJs:jsString];
+    }
+}
+
+- (void)pausePlayingAudio:(CDVInvokedUrlCommand*)command
+{
+    NSString* mediaId = [command.arguments objectAtIndex:0];
+    NSString* jsString = nil;
+    CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId];
+
+    if ((audioFile != nil) && (audioFile.player != nil)) {
+        NSLog(@"Paused playing audio sample '%@'", audioFile.resourcePath);
+        [audioFile.player pause];
+        jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_PAUSED];
+    }
+    // ignore if no media playing
+
+    if (jsString) {
+        [self.commandDelegate evalJs:jsString];
+    }
+}
+
+- (void)seekToAudio:(CDVInvokedUrlCommand*)command
+{
+    // args:
+    // 0 = Media id
+    // 1 = path to resource
+    // 2 = seek to location in milliseconds
+
+    NSString* mediaId = [command.arguments objectAtIndex:0];
+
+    CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId];
+    double position = [[command.arguments objectAtIndex:1] doubleValue];
+
+    if ((audioFile != nil) && (audioFile.player != nil)) {
+        double posInSeconds = position / 1000;
+        audioFile.player.currentTime = posInSeconds;
+        NSString* jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%f);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_POSITION, posInSeconds];
+
+        [self.commandDelegate evalJs:jsString];
+    }
+}
+
+- (void)release:(CDVInvokedUrlCommand*)command
+{
+    NSString* mediaId = [command.arguments objectAtIndex:0];
+
+    if (mediaId != nil) {
+        CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId];
+        if (audioFile != nil) {
+            if (audioFile.player && [audioFile.player isPlaying]) {
+                [audioFile.player stop];
+            }
+            if (audioFile.recorder && [audioFile.recorder isRecording]) {
+                [audioFile.recorder stop];
+            }
+            if (self.avSession) {
+                [self.avSession setActive:NO error:nil];
+                self.avSession = nil;
+            }
+            [[self soundCache] removeObjectForKey:mediaId];
+            NSLog(@"Media with id %@ released", mediaId);
+        }
+    }
+}
+
+- (void)getCurrentPositionAudio:(CDVInvokedUrlCommand*)command
+{
+    NSString* callbackId = command.callbackId;
+    NSString* mediaId = [command.arguments objectAtIndex:0];
+
+#pragma unused(mediaId)
+    CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId];
+    double position = -1;
+
+    if ((audioFile != nil) && (audioFile.player != nil) && [audioFile.player isPlaying]) {
+        position = round(audioFile.player.currentTime * 1000) / 1000;
+    }
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:position];
+    NSString* jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%.3f);\n%@", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_POSITION, position, [result toSuccessCallbackString:callbackId]];
+    [self.commandDelegate evalJs:jsString];
+}
+
+- (void)startRecordingAudio:(CDVInvokedUrlCommand*)command
+{
+    NSString* callbackId = command.callbackId;
+
+#pragma unused(callbackId)
+
+    NSString* mediaId = [command.arguments objectAtIndex:0];
+    CDVAudioFile* audioFile = [self audioFileForResource:[command.arguments objectAtIndex:1] withId:mediaId];
+    NSString* jsString = nil;
+    NSString* errorMsg = @"";
+
+    if (audioFile != nil) {
+        NSError* __autoreleasing error = nil;
+
+        if (audioFile.recorder != nil) {
+            [audioFile.recorder stop];
+            audioFile.recorder = nil;
+        }
+        // get the audioSession and set the category to allow recording when device is locked or ring/silent switch engaged
+        if ([self hasAudioSession]) {
+            [self.avSession setCategory:AVAudioSessionCategoryRecord error:nil];
+            if (![self.avSession setActive:YES error:&error]) {
+                // other audio with higher priority that does not allow mixing could cause this to fail
+                errorMsg = [NSString stringWithFormat:@"Unable to record audio: %@", [error localizedFailureReason]];
+                // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, MEDIA_ERR_ABORTED];
+                jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]];
+                [self.commandDelegate evalJs:jsString];
+                return;
+            }
+        }
+
+        // create a new recorder for each start record
+        audioFile.recorder = [[CDVAudioRecorder alloc] initWithURL:audioFile.resourceURL settings:nil error:&error];
+
+        bool recordingSuccess = NO;
+        if (error == nil) {
+            audioFile.recorder.delegate = self;
+            audioFile.recorder.mediaId = mediaId;
+            recordingSuccess = [audioFile.recorder record];
+            if (recordingSuccess) {
+                NSLog(@"Started recording audio sample '%@'", audioFile.resourcePath);
+                jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_RUNNING];
+            }
+        }
+
+        if ((error != nil) || (recordingSuccess == NO)) {
+            if (error != nil) {
+                errorMsg = [NSString stringWithFormat:@"Failed to initialize AVAudioRecorder: %@\n", [error localizedFailureReason]];
+            } else {
+                errorMsg = @"Failed to start recording using AVAudioRecorder";
+            }
+            audioFile.recorder = nil;
+            if (self.avSession) {
+                [self.avSession setActive:NO error:nil];
+            }
+            jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]];
+        }
+    } else {
+        // file does not exist
+        NSLog(@"Could not start recording audio, file '%@' does not exist.", audioFile.resourcePath);
+        jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:@"File to record to does not exist"]];
+    }
+    if (jsString) {
+        [self.commandDelegate evalJs:jsString];
+    }
+    return;
+}
+
+- (void)stopRecordingAudio:(CDVInvokedUrlCommand*)command
+{
+    NSString* mediaId = [command.arguments objectAtIndex:0];
+
+    CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId];
+    NSString* jsString = nil;
+
+    if ((audioFile != nil) && (audioFile.recorder != nil)) {
+        NSLog(@"Stopped recording audio sample '%@'", audioFile.resourcePath);
+        [audioFile.recorder stop];
+        // no callback - that will happen in audioRecorderDidFinishRecording
+    }
+    // ignore if no media recording
+    if (jsString) {
+        [self.commandDelegate evalJs:jsString];
+    }
+}
+
+- (void)audioRecorderDidFinishRecording:(AVAudioRecorder*)recorder successfully:(BOOL)flag
+{
+    CDVAudioRecorder* aRecorder = (CDVAudioRecorder*)recorder;
+    NSString* mediaId = aRecorder.mediaId;
+    CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId];
+    NSString* jsString = nil;
+
+    if (audioFile != nil) {
+        NSLog(@"Finished recording audio sample '%@'", audioFile.resourcePath);
+    }
+    if (flag) {
+        jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_STOPPED];
+    } else {
+        // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, MEDIA_ERR_DECODE];
+        jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_DECODE message:nil]];
+    }
+    if (self.avSession) {
+        [self.avSession setActive:NO error:nil];
+    }
+    [self.commandDelegate evalJs:jsString];
+}
+
+- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer*)player successfully:(BOOL)flag
+{
+    CDVAudioPlayer* aPlayer = (CDVAudioPlayer*)player;
+    NSString* mediaId = aPlayer.mediaId;
+    CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId];
+    NSString* jsString = nil;
+
+    if (audioFile != nil) {
+        NSLog(@"Finished playing audio sample '%@'", audioFile.resourcePath);
+    }
+    if (flag) {
+        jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_STOPPED];
+    } else {
+        // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, MEDIA_ERR_DECODE];
+        jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_DECODE message:nil]];
+    }
+    if (self.avSession) {
+        [self.avSession setActive:NO error:nil];
+    }
+    [self.commandDelegate evalJs:jsString];
+}
+
+- (void)onMemoryWarning
+{
+    [[self soundCache] removeAllObjects];
+    [self setSoundCache:nil];
+    [self setAvSession:nil];
+
+    [super onMemoryWarning];
+}
+
+- (void)dealloc
+{
+    [[self soundCache] removeAllObjects];
+}
+
+- (void)onReset
+{
+    for (CDVAudioFile* audioFile in [[self soundCache] allValues]) {
+        if (audioFile != nil) {
+            if (audioFile.player != nil) {
+                [audioFile.player stop];
+                audioFile.player.currentTime = 0;
+            }
+            if (audioFile.recorder != nil) {
+                [audioFile.recorder stop];
+            }
+        }
+    }
+
+    [[self soundCache] removeAllObjects];
+}
+
+@end
+
+@implementation CDVAudioFile
+
+@synthesize resourcePath;
+@synthesize resourceURL;
+@synthesize player, volume;
+@synthesize recorder;
+
+@end
+@implementation CDVAudioPlayer
+@synthesize mediaId;
+
+@end
+
+@implementation CDVAudioRecorder
+@synthesize mediaId;
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/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
new file mode 100644
index 0000000..b0d8615
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h
@@ -0,0 +1,28 @@
+/*
+ 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>
+#import "CDVPlugin.h"
+
+@interface CDVSplashScreen : CDVPlugin {}
+
+- (void)show:(CDVInvokedUrlCommand*)command;
+- (void)hide:(CDVInvokedUrlCommand*)command;
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/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
new file mode 100644
index 0000000..2512328
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
@@ -0,0 +1,49 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVSplashScreen.h"
+#import "CDVViewController.h"
+
+@implementation CDVSplashScreen
+
+- (void)__show:(BOOL)show
+{
+    // Legacy support - once deprecated classes removed, clean this up
+    id <UIApplicationDelegate> delegate = [[UIApplication sharedApplication] delegate];
+
+    if ([delegate respondsToSelector:@selector(viewController)]) {
+        id vc = [delegate performSelector:@selector(viewController)];
+        if ([vc isKindOfClass:[CDVViewController class]]) {
+            ((CDVViewController*)vc).imageView.hidden = !show;
+            ((CDVViewController*)vc).activityView.hidden = !show;
+        }
+    }
+}
+
+- (void)show:(CDVInvokedUrlCommand*)command
+{
+    [self __show:YES];
+}
+
+- (void)hide:(CDVInvokedUrlCommand*)command
+{
+    [self __show:NO];
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.h b/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.h
new file mode 100644
index 0000000..5444f6d
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.h
@@ -0,0 +1,29 @@
+/*
+ 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>
+#import "CDVAvailability.h"
+
+@class CDVViewController;
+
+@interface CDVURLProtocol : NSURLProtocol {}
+
++ (void)registerViewController:(CDVViewController*)viewController;
++ (void)unregisterViewController:(CDVViewController*)viewController;
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/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
new file mode 100644
index 0000000..a645288
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m
@@ -0,0 +1,209 @@
+/*
+ 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 "CDVURLProtocol.h"
+#import "CDVCommandQueue.h"
+#import "CDVWhitelist.h"
+#import "CDVViewController.h"
+
+@interface CDVHTTPURLResponse : NSHTTPURLResponse
+- (id)initWithUnauthorizedURL:(NSURL*)url;
+- (id)initWithBlankResponse:(NSURL*)url;
+@property (nonatomic) NSInteger statusCode;
+@end
+
+static CDVWhitelist * gWhitelist = nil;
+// Contains a set of NSNumbers of addresses of controllers. It doesn't store
+// the actual pointer to avoid retaining.
+static NSMutableSet* gRegisteredControllers = nil;
+
+// Returns the registered view controller that sent the given request.
+// If the user-agent is not from a UIWebView, or if it's from an unregistered one,
+// then nil is returned.
+static CDVViewController *viewControllerForRequest(NSURLRequest* request)
+{
+    // The exec bridge explicitly sets the VC address in a header.
+    // This works around the User-Agent not being set for file: URLs.
+    NSString* addrString = [request valueForHTTPHeaderField:@"vc"];
+
+    if (addrString == nil) {
+        NSString* userAgent = [request valueForHTTPHeaderField:@"User-Agent"];
+        if (userAgent == nil) {
+            return nil;
+        }
+        NSUInteger bracketLocation = [userAgent rangeOfString:@"(" options:NSBackwardsSearch].location;
+        if (bracketLocation == NSNotFound) {
+            return nil;
+        }
+        addrString = [userAgent substringFromIndex:bracketLocation + 1];
+    }
+
+    long long viewControllerAddress = [addrString longLongValue];
+    @synchronized(gRegisteredControllers) {
+        if (![gRegisteredControllers containsObject:[NSNumber numberWithLongLong:viewControllerAddress]]) {
+            return nil;
+        }
+    }
+
+    return (__bridge CDVViewController*)(void*)viewControllerAddress;
+}
+
+@implementation CDVURLProtocol
+
++ (void)registerPGHttpURLProtocol {}
+
++ (void)registerURLProtocol {}
+
+// Called to register the URLProtocol, and to make it away of an instance of
+// a ViewController.
++ (void)registerViewController:(CDVViewController*)viewController
+{
+    if (gRegisteredControllers == nil) {
+        [NSURLProtocol registerClass:[CDVURLProtocol class]];
+        gRegisteredControllers = [[NSMutableSet alloc] initWithCapacity:8];
+        // The whitelist doesn't change, so grab the first one and store it.
+        gWhitelist = viewController.whitelist;
+
+        // Note that we grab the whitelist from the first viewcontroller for now - but this will change
+        // when we allow a registered viewcontroller to have its own whitelist (e.g InAppBrowser)
+        // Differentiating the requests will be through the 'vc' http header below as used for the js->objc bridge.
+        //  The 'vc' value is generated by casting the viewcontroller object to a (long long) value (see CDVViewController::webViewDidFinishLoad)
+        if (gWhitelist == nil) {
+            NSLog(@"WARNING: NO whitelist has been set in CDVURLProtocol.");
+        }
+    }
+
+    @synchronized(gRegisteredControllers) {
+        [gRegisteredControllers addObject:[NSNumber numberWithLongLong:(long long)viewController]];
+    }
+}
+
++ (void)unregisterViewController:(CDVViewController*)viewController
+{
+    @synchronized(gRegisteredControllers) {
+        [gRegisteredControllers removeObject:[NSNumber numberWithLongLong:(long long)viewController]];
+    }
+}
+
++ (BOOL)canInitWithRequest:(NSURLRequest*)theRequest
+{
+    NSURL* theUrl = [theRequest URL];
+    CDVViewController* viewController = viewControllerForRequest(theRequest);
+
+    if (viewController != nil) {
+        if ([[theUrl path] isEqualToString:@"/!gap_exec"]) {
+            NSString* queuedCommandsJSON = [theRequest valueForHTTPHeaderField:@"cmds"];
+            NSString* requestId = [theRequest valueForHTTPHeaderField:@"rc"];
+            if (requestId == nil) {
+                NSLog(@"!cordova request missing rc header");
+                return NO;
+            }
+            BOOL hasCmds = [queuedCommandsJSON length] > 0;
+            if (hasCmds) {
+                SEL sel = @selector(enqueCommandBatch:);
+                [viewController.commandQueue performSelectorOnMainThread:sel withObject:queuedCommandsJSON waitUntilDone:NO];
+            } else {
+                SEL sel = @selector(maybeFetchCommandsFromJs:);
+                [viewController.commandQueue performSelectorOnMainThread:sel withObject:[NSNumber numberWithInteger:[requestId integerValue]] waitUntilDone:NO];
+            }
+            // Returning NO here would be 20% faster, but it spams WebInspector's console with failure messages.
+            // If JS->Native bridge speed is really important for an app, they should use the iframe bridge.
+            // Returning YES here causes the request to come through canInitWithRequest two more times.
+            // For this reason, we return NO when cmds exist.
+            return !hasCmds;
+        }
+        // we only care about http and https connections.
+        // CORS takes care of http: trying to access file: URLs.
+        if ([gWhitelist schemeIsAllowed:[theUrl scheme]]) {
+            // if it FAILS the whitelist, we return TRUE, so we can fail the connection later
+            return ![gWhitelist URLIsAllowed:theUrl];
+        }
+    }
+
+    return NO;
+}
+
++ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)request
+{
+    // NSLog(@"%@ received %@", self, NSStringFromSelector(_cmd));
+    return request;
+}
+
+- (void)startLoading
+{
+    // NSLog(@"%@ received %@ - start", self, NSStringFromSelector(_cmd));
+    NSURL* url = [[self request] URL];
+
+    if ([[url path] isEqualToString:@"/!gap_exec"]) {
+        CDVHTTPURLResponse* response = [[CDVHTTPURLResponse alloc] initWithBlankResponse:url];
+        [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+        [[self client] URLProtocolDidFinishLoading:self];
+        return;
+    }
+
+    NSString* body = [gWhitelist errorStringForURL:url];
+
+    CDVHTTPURLResponse* response = [[CDVHTTPURLResponse alloc] initWithUnauthorizedURL:url];
+
+    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+
+    [[self client] URLProtocol:self didLoadData:[body dataUsingEncoding:NSASCIIStringEncoding]];
+
+    [[self client] URLProtocolDidFinishLoading:self];
+}
+
+- (void)stopLoading
+{
+    // do any cleanup here
+}
+
++ (BOOL)requestIsCacheEquivalent:(NSURLRequest*)requestA toRequest:(NSURLRequest*)requestB
+{
+    return NO;
+}
+
+@end
+
+@implementation CDVHTTPURLResponse
+@synthesize statusCode;
+
+- (id)initWithUnauthorizedURL:(NSURL*)url
+{
+    self = [super initWithURL:url MIMEType:@"text/plain" expectedContentLength:-1 textEncodingName:@"UTF-8"];
+    if (self) {
+        self.statusCode = 401;
+    }
+    return self;
+}
+
+- (id)initWithBlankResponse:(NSURL*)url
+{
+    self = [super initWithURL:url MIMEType:@"text/plain" expectedContentLength:-1 textEncodingName:@"UTF-8"];
+    if (self) {
+        self.statusCode = 200;
+    }
+    return self;
+}
+
+- (NSDictionary*)allHeaderFields
+{
+    return nil;
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.h b/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.h
new file mode 100644
index 0000000..fdea596
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.h
@@ -0,0 +1,25 @@
+/*
+ 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 CDVUserAgentUtil : NSObject
++ (NSString*)originalUserAgent;
++ (void)setUserAgent:(NSString*)newValue;
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/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
new file mode 100644
index 0000000..ac5c994
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m
@@ -0,0 +1,76 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVUserAgentUtil.h"
+
+#import <UIKit/UIKit.h>
+
+static NSString* gOriginalUserAgent = nil;
+static NSString* kCdvUserAgentKey = @"Cordova-User-Agent";
+static NSString* kCdvUserAgentVersionKey = @"Cordova-User-Agent-Version";
+
+@implementation CDVUserAgentUtil
+
++ (NSString*)originalUserAgent
+{
+    if (gOriginalUserAgent == nil) {
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppLocaleDidChange:)
+                                                     name:NSCurrentLocaleDidChangeNotification object:nil];
+
+        NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
+        NSString* systemVersion = [[UIDevice currentDevice] systemVersion];
+        NSString* localeStr = [[NSLocale currentLocale] localeIdentifier];
+        NSString* systemAndLocale = [NSString stringWithFormat:@"%@ %@", systemVersion, localeStr];
+
+        NSString* cordovaUserAgentVersion = [userDefaults stringForKey:kCdvUserAgentVersionKey];
+        gOriginalUserAgent = [userDefaults stringForKey:kCdvUserAgentKey];
+        BOOL cachedValueIsOld = ![systemAndLocale isEqualToString:cordovaUserAgentVersion];
+
+        if ((gOriginalUserAgent == nil) || cachedValueIsOld) {
+            UIWebView* sampleWebView = [[UIWebView alloc] initWithFrame:CGRectZero];
+            gOriginalUserAgent = [sampleWebView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
+
+            [userDefaults setObject:gOriginalUserAgent forKey:kCdvUserAgentKey];
+            [userDefaults setObject:systemAndLocale forKey:kCdvUserAgentVersionKey];
+
+            [userDefaults synchronize];
+        }
+    }
+    return gOriginalUserAgent;
+}
+
++ (void)setUserAgent:(NSString*)newValue
+{
+    // Setting the UserAgent must occur before a UIWebView is instantiated.
+    // It is read per instantiation, so it does not affect previously created views.
+    // Except! When a PDF is loaded, all currently active UIWebViews reload their
+    // User-Agent from the NSUserDefaults some time after the DidFinishLoad of the PDF bah!
+    NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:newValue, @"UserAgent", nil];
+
+    [[NSUserDefaults standardUserDefaults] registerDefaults:dict];
+}
+
++ (void)onAppLocaleDidChange:(NSNotification*)notification
+{
+    // TODO: We should figure out how to update the user-agent of existing UIWebViews when this happens.
+    // Maybe use the PDF bug (noted in setUserAgent:).
+    gOriginalUserAgent = nil;
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/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
new file mode 100644
index 0000000..ed6f7fc
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h
@@ -0,0 +1,76 @@
+/*
+ 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 <UIKit/UIKit.h>
+#import <Foundation/NSJSONSerialization.h>
+#import "CDVAvailability.h"
+#import "CDVInvokedUrlCommand.h"
+#import "CDVCommandDelegate.h"
+#import "CDVWhitelist.h"
+#import "CDVScreenOrientationDelegate.h"
+
+@class CDVCommandQueue;
+@class CDVCommandDelegateImpl;
+
+@interface CDVViewController : UIViewController <UIWebViewDelegate, CDVScreenOrientationDelegate>{
+    @protected
+    CDVCommandDelegateImpl* _commandDelegate;
+    @protected
+    CDVCommandQueue* _commandQueue;
+    NSString* _userAgent;
+}
+
+@property (nonatomic, strong) IBOutlet UIWebView* webView;
+
+@property (nonatomic, readonly, strong) NSMutableDictionary* pluginObjects;
+@property (nonatomic, readonly, strong) NSDictionary* pluginsMap;
+@property (nonatomic, readonly, strong) NSDictionary* settings;
+@property (nonatomic, readonly, strong) NSXMLParser* configParser;
+@property (nonatomic, readonly, strong) CDVWhitelist* whitelist; // readonly for public
+@property (nonatomic, readonly, assign) BOOL loadFromString;
+
+@property (nonatomic, readwrite, assign) BOOL useSplashScreen;
+@property (nonatomic, readonly, strong) IBOutlet UIActivityIndicatorView* activityView;
+@property (nonatomic, readonly, strong) UIImageView* imageView;
+
+@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) NSString* userAgent;
+
++ (NSDictionary*)getBundlePlist:(NSString*)plistName;
++ (NSString*)applicationDocumentsDirectory;
+
+- (void)printMultitaskingInfo;
+- (void)createGapView;
+- (UIWebView*)newCordovaViewWithFrame:(CGRect)bounds;
+
+- (void)javascriptAlert:(NSString*)text;
+- (NSString*)appURLScheme;
+
+- (NSArray*)parseInterfaceOrientations:(NSArray*)orientations;
+- (BOOL)supportsOrientation:(UIInterfaceOrientation)orientation;
+
+- (id)getCommandInstance:(NSString*)pluginName;
+- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className;
+
+- (BOOL)URLisAllowed:(NSURL*)url;
+
+@end