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

[16/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/CDV.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDV.h b/lib/cordova-ios/CordovaLib/Classes/CDV.h
new file mode 100644
index 0000000..5a0ae6a
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDV.h
@@ -0,0 +1,57 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVAvailability.h"
+
+#import "CDVPlugin.h"
+#import "CDVViewController.h"
+#import "CDVCommandDelegate.h"
+#import "CDVURLProtocol.h"
+#import "CDVInvokedUrlCommand.h"
+
+#import "CDVAccelerometer.h"
+#import "CDVBattery.h"
+#import "CDVCamera.h"
+#import "CDVCapture.h"
+#import "CDVConnection.h"
+#import "CDVContact.h"
+#import "CDVContacts.h"
+#import "CDVDebug.h"
+#import "CDVDebugConsole.h"
+#import "CDVDevice.h"
+#import "CDVFile.h"
+#import "CDVFileTransfer.h"
+#import "CDVLocation.h"
+#import "CDVNotification.h"
+#import "CDVPluginResult.h"
+#import "CDVReachability.h"
+#import "CDVSound.h"
+#import "CDVSplashScreen.h"
+#import "CDVWhitelist.h"
+#import "CDVLocalStorage.h"
+#import "CDVInAppBrowser.h"
+#import "CDVScreenOrientationDelegate.h"
+
+#import "NSArray+Comparisons.h"
+#import "NSData+Base64.h"
+#import "NSDictionary+Extensions.h"
+#import "NSMutableArray+QueueAdditions.h"
+#import "UIDevice+Extensions.h"
+
+#import "CDVJSON.h"

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVAccelerometer.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVAccelerometer.h b/lib/cordova-ios/CordovaLib/Classes/CDVAccelerometer.h
new file mode 100644
index 0000000..044ca53
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVAccelerometer.h
@@ -0,0 +1,39 @@
+/*
+ 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 "CDVPlugin.h"
+
+@interface CDVAccelerometer : CDVPlugin <UIAccelerometerDelegate>
+{
+    double x;
+    double y;
+    double z;
+    NSTimeInterval timestamp;
+}
+
+@property (readonly, assign) BOOL isRunning;
+@property (nonatomic, strong) NSString* callbackId;
+
+- (CDVAccelerometer*)init;
+
+- (void)start:(CDVInvokedUrlCommand*)command;
+- (void)stop:(CDVInvokedUrlCommand*)command;
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVAccelerometer.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVAccelerometer.m b/lib/cordova-ios/CordovaLib/Classes/CDVAccelerometer.m
new file mode 100644
index 0000000..33093d0
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVAccelerometer.m
@@ -0,0 +1,128 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVAccelerometer.h"
+
+@interface CDVAccelerometer () {}
+@property (readwrite, assign) BOOL isRunning;
+@end
+
+@implementation CDVAccelerometer
+
+@synthesize callbackId, isRunning;
+
+// defaults to 10 msec
+#define kAccelerometerInterval 40
+// g constant: -9.81 m/s^2
+#define kGravitationalConstant -9.81
+
+- (CDVAccelerometer*)init
+{
+    self = [super init];
+    if (self) {
+        x = 0;
+        y = 0;
+        z = 0;
+        timestamp = 0;
+        self.callbackId = nil;
+        self.isRunning = NO;
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [self stop:nil];
+}
+
+- (void)start:(CDVInvokedUrlCommand*)command
+{
+    NSString* cbId = command.callbackId;
+    NSTimeInterval desiredFrequency_num = kAccelerometerInterval;
+    UIAccelerometer* pAccel = [UIAccelerometer sharedAccelerometer];
+
+    // accelerometer expects fractional seconds, but we have msecs
+    pAccel.updateInterval = desiredFrequency_num / 1000;
+    self.callbackId = cbId;
+    if (!self.isRunning) {
+        pAccel.delegate = self;
+        self.isRunning = YES;
+    }
+}
+
+- (void)onReset
+{
+    [self stop:nil];
+}
+
+- (void)stop:(CDVInvokedUrlCommand*)command
+{
+    UIAccelerometer* theAccelerometer = [UIAccelerometer sharedAccelerometer];
+
+    theAccelerometer.delegate = nil;
+    self.isRunning = NO;
+}
+
+/**
+ * Picks up accel updates from device and stores them in this class
+ */
+- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration
+{
+    if (self.isRunning) {
+        x = acceleration.x;
+        y = acceleration.y;
+        z = acceleration.z;
+        timestamp = ([[NSDate date] timeIntervalSince1970] * 1000);
+        [self returnAccelInfo];
+    }
+}
+
+- (void)returnAccelInfo
+{
+    // Create an acceleration object
+    NSMutableDictionary* accelProps = [NSMutableDictionary dictionaryWithCapacity:4];
+
+    [accelProps setValue:[NSNumber numberWithDouble:x * kGravitationalConstant] forKey:@"x"];
+    [accelProps setValue:[NSNumber numberWithDouble:y * kGravitationalConstant] forKey:@"y"];
+    [accelProps setValue:[NSNumber numberWithDouble:z * kGravitationalConstant] forKey:@"z"];
+    [accelProps setValue:[NSNumber numberWithDouble:timestamp] forKey:@"timestamp"];
+
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:accelProps];
+    [result setKeepCallback:[NSNumber numberWithBool:YES]];
+    [self.commandDelegate sendPluginResult:result callbackId:self.callbackId];
+}
+
+// TODO: Consider using filtering to isolate instantaneous data vs. gravity data -jm
+
+/*
+ #define kFilteringFactor 0.1
+
+ // Use a basic low-pass filter to keep only the gravity component of each axis.
+ grav_accelX = (acceleration.x * kFilteringFactor) + ( grav_accelX * (1.0 - kFilteringFactor));
+ grav_accelY = (acceleration.y * kFilteringFactor) + ( grav_accelY * (1.0 - kFilteringFactor));
+ grav_accelZ = (acceleration.z * kFilteringFactor) + ( grav_accelZ * (1.0 - kFilteringFactor));
+
+ // Subtract the low-pass value from the current value to get a simplified high-pass filter
+ instant_accelX = acceleration.x - ( (acceleration.x * kFilteringFactor) + (instant_accelX * (1.0 - kFilteringFactor)) );
+ instant_accelY = acceleration.y - ( (acceleration.y * kFilteringFactor) + (instant_accelY * (1.0 - kFilteringFactor)) );
+ instant_accelZ = acceleration.z - ( (acceleration.z * kFilteringFactor) + (instant_accelZ * (1.0 - kFilteringFactor)) );
+
+
+ */
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/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
new file mode 100644
index 0000000..67583be
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
@@ -0,0 +1,75 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#define __CORDOVA_0_9_6 906
+#define __CORDOVA_1_0_0 10000
+#define __CORDOVA_1_1_0 10100
+#define __CORDOVA_1_2_0 10200
+#define __CORDOVA_1_3_0 10300
+#define __CORDOVA_1_4_0 10400
+#define __CORDOVA_1_4_1 10401
+#define __CORDOVA_1_5_0 10500
+#define __CORDOVA_1_6_0 10600
+#define __CORDOVA_1_6_1 10601
+#define __CORDOVA_1_7_0 10700
+#define __CORDOVA_1_8_0 10800
+#define __CORDOVA_1_8_1 10801
+#define __CORDOVA_1_9_0 10900
+#define __CORDOVA_2_0_0 20000
+#define __CORDOVA_2_1_0 20100
+#define __CORDOVA_2_2_0 20200
+#define __CORDOVA_2_3_0 20300
+#define __CORDOVA_2_4_0 20400
+#define __CORDOVA_NA 99999      /* not available */
+
+/*
+ #if CORDOVA_VERSION_MIN_REQUIRED >= __CORDOVA_1_7_0
+    // do something when its at least 1.7.0
+ #else
+    // do something else (non 1.7.0)
+ #endif
+ */
+#ifndef CORDOVA_VERSION_MIN_REQUIRED
+    #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_4_0
+#endif
+
+/*
+ Returns YES if it is at least version specified as NSString(X)
+ Usage:
+     if (IsAtLeastiOSVersion(@"5.1")) {
+         // do something for iOS 5.1 or greater
+     }
+ */
+#define IsAtLeastiOSVersion(X) ([[[UIDevice currentDevice] systemVersion] compare:X options:NSNumericSearch] != NSOrderedAscending)
+
+#define CDV_IsIPad() ([[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] && ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad))
+
+#define CDV_IsIPhone5() ([[UIScreen mainScreen] bounds].size.height == 568 && [[UIScreen mainScreen] bounds].size.width == 320)
+
+/* Return the string version of the decimal version */
+#define CDV_VERSION [NSString stringWithFormat:@"%d.%d.%d", \
+        (CORDOVA_VERSION_MIN_REQUIRED / 10000),             \
+        (CORDOVA_VERSION_MIN_REQUIRED % 10000) / 100,       \
+        (CORDOVA_VERSION_MIN_REQUIRED % 10000) % 100]
+
+#ifdef __clang__
+    #define CDV_DEPRECATED(version, msg) __attribute__((deprecated("Deprecated in Cordova " #version ". " msg)))
+#else
+    #define CDV_DEPRECATED(version, msg) __attribute__((deprecated()))
+#endif

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVBattery.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVBattery.h b/lib/cordova-ios/CordovaLib/Classes/CDVBattery.h
new file mode 100644
index 0000000..ba26c3a
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVBattery.h
@@ -0,0 +1,40 @@
+/*
+ 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 CDVBattery : CDVPlugin {
+    UIDeviceBatteryState state;
+    float level;
+    bool isPlugged;
+    NSString* callbackId;
+}
+
+@property (nonatomic) UIDeviceBatteryState state;
+@property (nonatomic) float level;
+@property (nonatomic) bool isPlugged;
+@property (strong) NSString* callbackId;
+
+- (void)updateBatteryStatus:(NSNotification*)notification;
+- (NSDictionary*)getBatteryStatus;
+- (void)start:(CDVInvokedUrlCommand*)command;
+- (void)stop:(CDVInvokedUrlCommand*)command;
+- (void)dealloc;
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVBattery.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVBattery.m b/lib/cordova-ios/CordovaLib/Classes/CDVBattery.m
new file mode 100644
index 0000000..681511c
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVBattery.m
@@ -0,0 +1,152 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVBattery.h"
+
+@interface CDVBattery (PrivateMethods)
+- (void)updateOnlineStatus;
+@end
+
+@implementation CDVBattery
+
+@synthesize state, level, callbackId, isPlugged;
+
+/*  determining type of event occurs on JavaScript side
+- (void) updateBatteryLevel:(NSNotification*)notification
+{
+    // send batterylow event for less than 25% battery
+    // send batterycritical  event for less than 10% battery
+    // W3c says to send batteryStatus event when batterylevel changes by more than 1% (iOS seems to notify each 5%)
+    // always update the navigator.device.battery info
+    float currentLevel = [[UIDevice currentDevice] batteryLevel];
+    NSString* type = @"";
+    // no check for level == -1 since this api is only called when monitoring is enabled so level should be valid
+    if (currentLevel < 0.10){
+        type = @"batterycritical";
+    } else if (currentLevel < 0.25) {
+        type = @"batterylow";
+    } else {
+        float onePercent = 0.1;
+        if (self.level >= 0 ){
+            onePercent = self.level * 0.01;
+        }
+        if (fabsf(currentLevel - self.level) > onePercent){
+            // issue batteryStatus event
+            type = @"batterystatus";
+        }
+    }
+    // update the battery info and fire event
+    NSString* jsString = [NSString stringWithFormat:@"navigator.device.battery._status(\"%@\", %@)", type,[[self getBatteryStatus] JSONRepresentation]];
+    [super writeJavascript:jsString];
+}
+ */
+
+- (void)updateBatteryStatus:(NSNotification*)notification
+{
+    NSDictionary* batteryData = [self getBatteryStatus];
+
+    if (self.callbackId) {
+        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:batteryData];
+        [result setKeepCallbackAsBool:YES];
+        [self.commandDelegate sendPluginResult:result callbackId:self.callbackId];
+    }
+}
+
+/* Get the current battery status and level.  Status will be unknown and level will be -1.0 if
+ * monitoring is turned off.
+ */
+- (NSDictionary*)getBatteryStatus
+{
+    UIDevice* currentDevice = [UIDevice currentDevice];
+    UIDeviceBatteryState currentState = [currentDevice batteryState];
+
+    isPlugged = FALSE; // UIDeviceBatteryStateUnknown or UIDeviceBatteryStateUnplugged
+    if ((currentState == UIDeviceBatteryStateCharging) || (currentState == UIDeviceBatteryStateFull)) {
+        isPlugged = TRUE;
+    }
+    float currentLevel = [currentDevice batteryLevel];
+
+    if ((currentLevel != self.level) || (currentState != self.state)) {
+        self.level = currentLevel;
+        self.state = currentState;
+    }
+
+    // W3C spec says level must be null if it is unknown
+    NSObject* w3cLevel = nil;
+    if ((currentState == UIDeviceBatteryStateUnknown) || (currentLevel == -1.0)) {
+        w3cLevel = [NSNull null];
+    } else {
+        w3cLevel = [NSNumber numberWithFloat:(currentLevel * 100)];
+    }
+    NSMutableDictionary* batteryData = [NSMutableDictionary dictionaryWithCapacity:2];
+    [batteryData setObject:[NSNumber numberWithBool:isPlugged] forKey:@"isPlugged"];
+    [batteryData setObject:w3cLevel forKey:@"level"];
+    return batteryData;
+}
+
+/* turn on battery monitoring*/
+- (void)start:(CDVInvokedUrlCommand*)command
+{
+    self.callbackId = command.callbackId;
+
+    if ([UIDevice currentDevice].batteryMonitoringEnabled == NO) {
+        [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateBatteryStatus:)
+                                                     name:UIDeviceBatteryStateDidChangeNotification object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateBatteryStatus:)
+                                                     name:UIDeviceBatteryLevelDidChangeNotification object:nil];
+    }
+}
+
+/* turn off battery monitoring */
+- (void)stop:(CDVInvokedUrlCommand*)command
+{
+    // callback one last time to clear the callback function on JS side
+    if (self.callbackId) {
+        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getBatteryStatus]];
+        [result setKeepCallbackAsBool:NO];
+        [self.commandDelegate sendPluginResult:result callbackId:self.callbackId];
+    }
+    self.callbackId = nil;
+    [[UIDevice currentDevice] setBatteryMonitoringEnabled:NO];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceBatteryStateDidChangeNotification object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceBatteryLevelDidChangeNotification object:nil];
+}
+
+- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView
+{
+    self = (CDVBattery*)[super initWithWebView:theWebView];
+    if (self) {
+        self.state = UIDeviceBatteryStateUnknown;
+        self.level = -1.0;
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [self stop:nil];
+}
+
+- (void)onReset
+{
+    [self stop:nil];
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/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
new file mode 100644
index 0000000..e32da7d
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCamera.h
@@ -0,0 +1,91 @@
+/*
+ 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"
+
+enum CDVDestinationType {
+    DestinationTypeDataUrl = 0,
+    DestinationTypeFileUri,
+    DestinationTypeNativeUri
+};
+typedef NSUInteger CDVDestinationType;
+
+enum CDVEncodingType {
+    EncodingTypeJPEG = 0,
+    EncodingTypePNG
+};
+typedef NSUInteger CDVEncodingType;
+
+enum CDVMediaType {
+    MediaTypePicture = 0,
+    MediaTypeVideo,
+    MediaTypeAll
+};
+typedef NSUInteger CDVMediaType;
+
+@interface CDVCameraPicker : UIImagePickerController
+{}
+
+@property (assign) NSInteger quality;
+@property (copy)   NSString* callbackId;
+@property (copy)   NSString* postUrl;
+@property (nonatomic) enum CDVDestinationType returnType;
+@property (nonatomic) enum CDVEncodingType encodingType;
+@property (strong) UIPopoverController* popoverController;
+@property (assign) CGSize targetSize;
+@property (assign) bool correctOrientation;
+@property (assign) bool saveToPhotoAlbum;
+@property (assign) bool cropToSize;
+@property (strong) UIWebView* webView;
+@property (assign) BOOL popoverSupported;
+
+@end
+
+// ======================================================================= //
+
+@interface CDVCamera : CDVPlugin <UIImagePickerControllerDelegate,
+    UINavigationControllerDelegate,
+    UIPopoverControllerDelegate>
+{}
+
+@property (strong) CDVCameraPicker* pickerController;
+
+/*
+ * getPicture
+ *
+ * arguments:
+ *	1: this is the javascript function that will be called with the results, the first parameter passed to the
+ *		javascript function is the picture as a Base64 encoded string
+ *  2: this is the javascript function to be called if there was an error
+ * options:
+ *	quality: integer between 1 and 100
+ */
+- (void)takePicture:(CDVInvokedUrlCommand*)command;
+- (void)postImage:(UIImage*)anImage withFilename:(NSString*)filename toUrl:(NSURL*)url;
+- (void)cleanup:(CDVInvokedUrlCommand*)command;
+
+- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info;
+- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo;
+- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker;
+- (UIImage*)imageByScalingAndCroppingForSize:(UIImage*)anImage toSize:(CGSize)targetSize;
+- (UIImage*)imageByScalingNotCroppingForSize:(UIImage*)anImage toSize:(CGSize)frameSize;
+- (UIImage*)imageCorrectedForCaptureOrientation:(UIImage*)anImage;
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/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
new file mode 100644
index 0000000..4cf5c82
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
@@ -0,0 +1,536 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVCamera.h"
+#import "NSArray+Comparisons.h"
+#import "NSData+Base64.h"
+#import "NSDictionary+Extensions.h"
+#import <MobileCoreServices/UTCoreTypes.h>
+
+#define CDV_PHOTO_PREFIX @"cdv_photo_"
+
+static NSSet* org_apache_cordova_validArrowDirections;
+
+@interface CDVCamera ()
+
+@property (readwrite, assign) BOOL hasPendingOperation;
+
+@end
+
+@implementation CDVCamera
+
++ (void)initialize
+{
+    org_apache_cordova_validArrowDirections = [[NSSet alloc] initWithObjects:[NSNumber numberWithInt:UIPopoverArrowDirectionUp], [NSNumber numberWithInt:UIPopoverArrowDirectionDown], [NSNumber numberWithInt:UIPopoverArrowDirectionLeft], [NSNumber numberWithInt:UIPopoverArrowDirectionRight], [NSNumber numberWithInt:UIPopoverArrowDirectionAny], nil];
+}
+
+@synthesize hasPendingOperation, pickerController;
+
+- (BOOL)popoverSupported
+{
+    return (NSClassFromString(@"UIPopoverController") != nil) &&
+           (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
+}
+
+/*  takePicture arguments:
+ * INDEX   ARGUMENT
+ *  0       quality
+ *  1       destination type
+ *  2       source type
+ *  3       targetWidth
+ *  4       targetHeight
+ *  5       encodingType
+ *  6       mediaType
+ *  7       allowsEdit
+ *  8       correctOrientation
+ *  9       saveToPhotoAlbum
+ */
+- (void)takePicture:(CDVInvokedUrlCommand*)command
+{
+    NSString* callbackId = command.callbackId;
+    NSArray* arguments = command.arguments;
+
+    self.hasPendingOperation = NO;
+
+    NSString* sourceTypeString = [arguments objectAtIndex:2];
+    UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera; // default
+    if (sourceTypeString != nil) {
+        sourceType = (UIImagePickerControllerSourceType)[sourceTypeString intValue];
+    }
+
+    bool hasCamera = [UIImagePickerController isSourceTypeAvailable:sourceType];
+    if (!hasCamera) {
+        NSLog(@"Camera.getPicture: source type %d not available.", sourceType);
+        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no camera available"];
+        [self.commandDelegate sendPluginResult:result callbackId:callbackId];
+        return;
+    }
+
+    bool allowEdit = [[arguments objectAtIndex:7] boolValue];
+    NSNumber* targetWidth = [arguments objectAtIndex:3];
+    NSNumber* targetHeight = [arguments objectAtIndex:4];
+    NSNumber* mediaValue = [arguments objectAtIndex:6];
+    CDVMediaType mediaType = (mediaValue) ? [mediaValue intValue] : MediaTypePicture;
+
+    CGSize targetSize = CGSizeMake(0, 0);
+    if ((targetWidth != nil) && (targetHeight != nil)) {
+        targetSize = CGSizeMake([targetWidth floatValue], [targetHeight floatValue]);
+    }
+
+    CDVCameraPicker* cameraPicker = [[CDVCameraPicker alloc] init];
+    self.pickerController = cameraPicker;
+
+    cameraPicker.delegate = self;
+    cameraPicker.sourceType = sourceType;
+    cameraPicker.allowsEditing = allowEdit; // THIS IS ALL IT TAKES FOR CROPPING - jm
+    cameraPicker.callbackId = callbackId;
+    cameraPicker.targetSize = targetSize;
+    cameraPicker.cropToSize = NO;
+    // we need to capture this state for memory warnings that dealloc this object
+    cameraPicker.webView = self.webView;
+    cameraPicker.popoverSupported = [self popoverSupported];
+
+    cameraPicker.correctOrientation = [[arguments objectAtIndex:8] boolValue];
+    cameraPicker.saveToPhotoAlbum = [[arguments objectAtIndex:9] boolValue];
+
+    cameraPicker.encodingType = ([arguments objectAtIndex:5]) ? [[arguments objectAtIndex:5] intValue] : EncodingTypeJPEG;
+
+    cameraPicker.quality = ([arguments objectAtIndex:0]) ? [[arguments objectAtIndex:0] intValue] : 50;
+    cameraPicker.returnType = ([arguments objectAtIndex:1]) ? [[arguments objectAtIndex:1] intValue] : DestinationTypeFileUri;
+
+    if (sourceType == UIImagePickerControllerSourceTypeCamera) {
+        // we only allow taking pictures (no video) in this api
+        cameraPicker.mediaTypes = [NSArray arrayWithObjects:(NSString*)kUTTypeImage, nil];
+    } else if (mediaType == MediaTypeAll) {
+        cameraPicker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:sourceType];
+    } else {
+        NSArray* mediaArray = [NSArray arrayWithObjects:(NSString*)(mediaType == MediaTypeVideo ? kUTTypeMovie:kUTTypeImage), nil];
+        cameraPicker.mediaTypes = mediaArray;
+    }
+
+    if ([self popoverSupported] && (sourceType != UIImagePickerControllerSourceTypeCamera)) {
+        if (cameraPicker.popoverController == nil) {
+            cameraPicker.popoverController = [[NSClassFromString (@"UIPopoverController")alloc] initWithContentViewController:cameraPicker];
+        }
+        int x = 0;
+        int y = 32;
+        int width = 320;
+        int height = 480;
+        UIPopoverArrowDirection arrowDirection = UIPopoverArrowDirectionAny;
+        NSDictionary* options = [command.arguments objectAtIndex:10 withDefault:nil];
+        if (options) {
+            x = [options integerValueForKey:@"x" defaultValue:0];
+            y = [options integerValueForKey:@"y" defaultValue:32];
+            width = [options integerValueForKey:@"width" defaultValue:320];
+            height = [options integerValueForKey:@"height" defaultValue:480];
+            arrowDirection = [options integerValueForKey:@"arrowDir" defaultValue:UIPopoverArrowDirectionAny];
+            if (![org_apache_cordova_validArrowDirections containsObject:[NSNumber numberWithInt:arrowDirection]]) {
+                arrowDirection = UIPopoverArrowDirectionAny;
+            }
+        }
+
+        cameraPicker.popoverController.delegate = self;
+        [cameraPicker.popoverController presentPopoverFromRect:CGRectMake(x, y, width, height)
+                                                        inView:[self.webView superview]
+                                      permittedArrowDirections:arrowDirection
+                                                      animated:YES];
+    } else {
+        if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
+            [self.viewController presentViewController:cameraPicker animated:YES completion:nil];
+        } else {
+            [self.viewController presentModalViewController:cameraPicker animated:YES];
+        }
+    }
+    self.hasPendingOperation = YES;
+}
+
+- (void)cleanup:(CDVInvokedUrlCommand*)command
+{
+    // empty the tmp directory
+    NSFileManager* fileMgr = [[NSFileManager alloc] init];
+    NSError* err = nil;
+    BOOL hasErrors = NO;
+
+    // clear contents of NSTemporaryDirectory
+    NSString* tempDirectoryPath = NSTemporaryDirectory();
+    NSDirectoryEnumerator* directoryEnumerator = [fileMgr enumeratorAtPath:tempDirectoryPath];
+    NSString* fileName = nil;
+    BOOL result;
+
+    while ((fileName = [directoryEnumerator nextObject])) {
+        // only delete the files we created
+        if (![fileName hasPrefix:CDV_PHOTO_PREFIX]) {
+            continue;
+        }
+        NSString* filePath = [tempDirectoryPath stringByAppendingPathComponent:fileName];
+        result = [fileMgr removeItemAtPath:filePath error:&err];
+        if (!result && err) {
+            NSLog(@"Failed to delete: %@ (error: %@)", filePath, err);
+            hasErrors = YES;
+        }
+    }
+
+    CDVPluginResult* pluginResult;
+    if (hasErrors) {
+        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:@"One or more files failed to be deleted."];
+    } else {
+        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
+    }
+    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
+}
+
+- (void)popoverControllerDidDismissPopover:(id)popoverController
+{
+    // [ self imagePickerControllerDidCancel:self.pickerController ];	'
+    UIPopoverController* pc = (UIPopoverController*)popoverController;
+
+    [pc dismissPopoverAnimated:YES];
+    pc.delegate = nil;
+    if (self.pickerController && self.pickerController.callbackId && self.pickerController.popoverController) {
+        self.pickerController.popoverController = nil;
+        NSString* callbackId = self.pickerController.callbackId;
+        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no image selected"];   // error callback expects string ATM
+        [self.commandDelegate sendPluginResult:result callbackId:callbackId];
+    }
+    self.hasPendingOperation = NO;
+}
+
+- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
+{
+    CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker;
+
+    if (cameraPicker.popoverSupported && (cameraPicker.popoverController != nil)) {
+        [cameraPicker.popoverController dismissPopoverAnimated:YES];
+        cameraPicker.popoverController.delegate = nil;
+        cameraPicker.popoverController = nil;
+    } else {
+        if ([cameraPicker respondsToSelector:@selector(presentingViewController)]) {
+            [[cameraPicker presentingViewController] dismissModalViewControllerAnimated:YES];
+        } else {
+            [[cameraPicker parentViewController] dismissModalViewControllerAnimated:YES];
+        }
+    }
+
+    CDVPluginResult* result = nil;
+
+    NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
+    // IMAGE TYPE
+    if ([mediaType isEqualToString:(NSString*)kUTTypeImage]) {
+        // get the image
+        UIImage* image = nil;
+        if (cameraPicker.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage]) {
+            image = [info objectForKey:UIImagePickerControllerEditedImage];
+        } else {
+            image = [info objectForKey:UIImagePickerControllerOriginalImage];
+        }
+
+        if (cameraPicker.saveToPhotoAlbum) {
+            UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
+        }
+
+        if (cameraPicker.correctOrientation) {
+            image = [self imageCorrectedForCaptureOrientation:image];
+        }
+
+        UIImage* scaledImage = nil;
+
+        if ((cameraPicker.targetSize.width > 0) && (cameraPicker.targetSize.height > 0)) {
+            // if cropToSize, resize image and crop to target size, otherwise resize to fit target without cropping
+            if (cameraPicker.cropToSize) {
+                scaledImage = [self imageByScalingAndCroppingForSize:image toSize:cameraPicker.targetSize];
+            } else {
+                scaledImage = [self imageByScalingNotCroppingForSize:image toSize:cameraPicker.targetSize];
+            }
+        }
+
+        NSData* data = nil;
+
+        if (cameraPicker.encodingType == EncodingTypePNG) {
+            data = UIImagePNGRepresentation(scaledImage == nil ? image : scaledImage);
+        } else {
+            data = UIImageJPEGRepresentation(scaledImage == nil ? image : scaledImage, cameraPicker.quality / 100.0f);
+        }
+
+        if (cameraPicker.returnType == DestinationTypeFileUri) {
+            // write to temp directory and return URI
+            // get the temp directory path
+            NSString* docsPath = [NSTemporaryDirectory ()stringByStandardizingPath];
+            NSError* err = nil;
+            NSFileManager* fileMgr = [[NSFileManager alloc] init]; // recommended by apple (vs [NSFileManager defaultManager]) to be threadsafe
+            // generate unique file name
+            NSString* filePath;
+
+            int i = 1;
+            do {
+                filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, cameraPicker.encodingType == EncodingTypePNG ? @"png":@"jpg"];
+            } while ([fileMgr fileExistsAtPath:filePath]);
+
+            // save file
+            if (![data writeToFile:filePath options:NSAtomicWrite error:&err]) {
+                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]];
+            } else {
+                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[NSURL fileURLWithPath:filePath] absoluteString]];
+            }
+        } else if (cameraPicker.returnType == DestinationTypeNativeUri) {
+            NSString* nativeUri = [(NSURL*)[info objectForKey:UIImagePickerControllerReferenceURL] absoluteString];
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:nativeUri];
+        } else {
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[data base64EncodedString]];
+        }
+    }
+    // NOT IMAGE TYPE (MOVIE)
+    else {
+        NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] absoluteString];
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:moviePath];
+    }
+
+    if (result) {
+        [self.commandDelegate sendPluginResult:result callbackId:cameraPicker.callbackId];
+    }
+
+    self.hasPendingOperation = NO;
+    self.pickerController = nil;
+}
+
+// older api calls newer didFinishPickingMediaWithInfo
+- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo
+{
+    NSDictionary* imageInfo = [NSDictionary dictionaryWithObject:image forKey:UIImagePickerControllerOriginalImage];
+
+    [self imagePickerController:picker didFinishPickingMediaWithInfo:imageInfo];
+}
+
+- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker
+{
+    CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker;
+
+    if ([cameraPicker respondsToSelector:@selector(presentingViewController)]) {
+        [[cameraPicker presentingViewController] dismissModalViewControllerAnimated:YES];
+    } else {
+        [[cameraPicker parentViewController] dismissModalViewControllerAnimated:YES];
+    }
+    // popoverControllerDidDismissPopover:(id)popoverController is called if popover is cancelled
+
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no image selected"];   // error callback expects string ATM
+    [self.commandDelegate sendPluginResult:result callbackId:cameraPicker.callbackId];
+
+    self.hasPendingOperation = NO;
+    self.pickerController = nil;
+}
+
+- (UIImage*)imageByScalingAndCroppingForSize:(UIImage*)anImage toSize:(CGSize)targetSize
+{
+    UIImage* sourceImage = anImage;
+    UIImage* newImage = nil;
+    CGSize imageSize = sourceImage.size;
+    CGFloat width = imageSize.width;
+    CGFloat height = imageSize.height;
+    CGFloat targetWidth = targetSize.width;
+    CGFloat targetHeight = targetSize.height;
+    CGFloat scaleFactor = 0.0;
+    CGFloat scaledWidth = targetWidth;
+    CGFloat scaledHeight = targetHeight;
+    CGPoint thumbnailPoint = CGPointMake(0.0, 0.0);
+
+    if (CGSizeEqualToSize(imageSize, targetSize) == NO) {
+        CGFloat widthFactor = targetWidth / width;
+        CGFloat heightFactor = targetHeight / height;
+
+        if (widthFactor > heightFactor) {
+            scaleFactor = widthFactor; // scale to fit height
+        } else {
+            scaleFactor = heightFactor; // scale to fit width
+        }
+        scaledWidth = width * scaleFactor;
+        scaledHeight = height * scaleFactor;
+
+        // center the image
+        if (widthFactor > heightFactor) {
+            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
+        } else if (widthFactor < heightFactor) {
+            thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
+        }
+    }
+
+    UIGraphicsBeginImageContext(targetSize); // this will crop
+
+    CGRect thumbnailRect = CGRectZero;
+    thumbnailRect.origin = thumbnailPoint;
+    thumbnailRect.size.width = scaledWidth;
+    thumbnailRect.size.height = scaledHeight;
+
+    [sourceImage drawInRect:thumbnailRect];
+
+    newImage = UIGraphicsGetImageFromCurrentImageContext();
+    if (newImage == nil) {
+        NSLog(@"could not scale image");
+    }
+
+    // pop the context to get back to the default
+    UIGraphicsEndImageContext();
+    return newImage;
+}
+
+- (UIImage*)imageCorrectedForCaptureOrientation:(UIImage*)anImage
+{
+    float rotation_radians = 0;
+    bool perpendicular = false;
+
+    switch ([anImage imageOrientation]) {
+        case UIImageOrientationUp :
+            rotation_radians = 0.0;
+            break;
+
+        case UIImageOrientationDown :
+            rotation_radians = M_PI; // don't be scared of radians, if you're reading this, you're good at math
+            break;
+
+        case UIImageOrientationRight:
+            rotation_radians = M_PI_2;
+            perpendicular = true;
+            break;
+
+        case UIImageOrientationLeft:
+            rotation_radians = -M_PI_2;
+            perpendicular = true;
+            break;
+
+        default:
+            break;
+    }
+
+    UIGraphicsBeginImageContext(CGSizeMake(anImage.size.width, anImage.size.height));
+    CGContextRef context = UIGraphicsGetCurrentContext();
+
+    // Rotate around the center point
+    CGContextTranslateCTM(context, anImage.size.width / 2, anImage.size.height / 2);
+    CGContextRotateCTM(context, rotation_radians);
+
+    CGContextScaleCTM(context, 1.0, -1.0);
+    float width = perpendicular ? anImage.size.height : anImage.size.width;
+    float height = perpendicular ? anImage.size.width : anImage.size.height;
+    CGContextDrawImage(context, CGRectMake(-width / 2, -height / 2, width, height), [anImage CGImage]);
+
+    // Move the origin back since the rotation might've change it (if its 90 degrees)
+    if (perpendicular) {
+        CGContextTranslateCTM(context, -anImage.size.height / 2, -anImage.size.width / 2);
+    }
+
+    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    return newImage;
+}
+
+- (UIImage*)imageByScalingNotCroppingForSize:(UIImage*)anImage toSize:(CGSize)frameSize
+{
+    UIImage* sourceImage = anImage;
+    UIImage* newImage = nil;
+    CGSize imageSize = sourceImage.size;
+    CGFloat width = imageSize.width;
+    CGFloat height = imageSize.height;
+    CGFloat targetWidth = frameSize.width;
+    CGFloat targetHeight = frameSize.height;
+    CGFloat scaleFactor = 0.0;
+    CGSize scaledSize = frameSize;
+
+    if (CGSizeEqualToSize(imageSize, frameSize) == NO) {
+        CGFloat widthFactor = targetWidth / width;
+        CGFloat heightFactor = targetHeight / height;
+
+        // opposite comparison to imageByScalingAndCroppingForSize in order to contain the image within the given bounds
+        if (widthFactor > heightFactor) {
+            scaleFactor = heightFactor; // scale to fit height
+        } else {
+            scaleFactor = widthFactor; // scale to fit width
+        }
+        scaledSize = CGSizeMake(MIN(width * scaleFactor, targetWidth), MIN(height * scaleFactor, targetHeight));
+    }
+
+    UIGraphicsBeginImageContext(scaledSize); // this will resize
+
+    [sourceImage drawInRect:CGRectMake(0, 0, scaledSize.width, scaledSize.height)];
+
+    newImage = UIGraphicsGetImageFromCurrentImageContext();
+    if (newImage == nil) {
+        NSLog(@"could not scale image");
+    }
+
+    // pop the context to get back to the default
+    UIGraphicsEndImageContext();
+    return newImage;
+}
+
+- (void)postImage:(UIImage*)anImage withFilename:(NSString*)filename toUrl:(NSURL*)url
+{
+    self.hasPendingOperation = YES;
+
+    NSString* boundary = @"----BOUNDARY_IS_I";
+
+    NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url];
+    [req setHTTPMethod:@"POST"];
+
+    NSString* contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
+    [req setValue:contentType forHTTPHeaderField:@"Content-type"];
+
+    NSData* imageData = UIImagePNGRepresentation(anImage);
+
+    // adding the body
+    NSMutableData* postBody = [NSMutableData data];
+
+    // first parameter an image
+    [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
+    [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"upload\"; filename=\"%@\"\r\n", filename] dataUsingEncoding:NSUTF8StringEncoding]];
+    [postBody appendData:[@"Content-Type: image/png\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
+    [postBody appendData:imageData];
+
+    //	// second parameter information
+    //	[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
+    //	[postBody appendData:[@"Content-Disposition: form-data; name=\"some_other_name\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
+    //	[postBody appendData:[@"some_other_value" dataUsingEncoding:NSUTF8StringEncoding]];
+    //	[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r \n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
+
+    [req setHTTPBody:postBody];
+
+    NSURLResponse* response;
+    NSError* error;
+    [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&error];
+
+    //  NSData* result = [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&error];
+    //	NSString * resultStr =  [[[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding] autorelease];
+
+    self.hasPendingOperation = NO;
+}
+
+@end
+
+@implementation CDVCameraPicker
+
+@synthesize quality, postUrl;
+@synthesize returnType;
+@synthesize callbackId;
+@synthesize popoverController;
+@synthesize targetSize;
+@synthesize correctOrientation;
+@synthesize saveToPhotoAlbum;
+@synthesize encodingType;
+@synthesize cropToSize;
+@synthesize webView;
+@synthesize popoverSupported;
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVCapture.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCapture.h b/lib/cordova-ios/CordovaLib/Classes/CDVCapture.h
new file mode 100644
index 0000000..afb82b4
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCapture.h
@@ -0,0 +1,118 @@
+/*
+ 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 <MobileCoreServices/MobileCoreServices.h>
+#import <AVFoundation/AVFoundation.h>
+#import "CDVPlugin.h"
+#import "CDVFile.h"
+
+enum CDVCaptureError {
+    CAPTURE_INTERNAL_ERR = 0,
+    CAPTURE_APPLICATION_BUSY = 1,
+    CAPTURE_INVALID_ARGUMENT = 2,
+    CAPTURE_NO_MEDIA_FILES = 3,
+    CAPTURE_NOT_SUPPORTED = 20
+};
+typedef NSUInteger CDVCaptureError;
+
+@interface CDVImagePicker : UIImagePickerController
+{
+    NSString* callbackid;
+    NSInteger quality;
+    NSString* mimeType;
+}
+@property (assign) NSInteger quality;
+@property (copy)   NSString* callbackId;
+@property (copy)   NSString* mimeType;
+
+@end
+
+@interface CDVCapture : CDVPlugin <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
+{
+    CDVImagePicker* pickerController;
+    BOOL inUse;
+}
+@property BOOL inUse;
+- (void)captureAudio:(CDVInvokedUrlCommand*)command;
+- (void)captureImage:(CDVInvokedUrlCommand*)command;
+- (CDVPluginResult*)processImage:(UIImage*)image type:(NSString*)mimeType forCallbackId:(NSString*)callbackId;
+- (void)captureVideo:(CDVInvokedUrlCommand*)command;
+- (CDVPluginResult*)processVideo:(NSString*)moviePath forCallbackId:(NSString*)callbackId;
+- (void)getMediaModes:(CDVInvokedUrlCommand*)command;
+- (void)getFormatData:(CDVInvokedUrlCommand*)command;
+- (NSDictionary*)getMediaDictionaryFromPath:(NSString*)fullPath ofType:(NSString*)type;
+- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info;
+- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo;
+- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker;
+
+@end
+
+@interface CDVAudioNavigationController : UINavigationController
+
+@end
+
+/* AudioRecorderViewController is used to create a simple view for audio recording.
+ *  It is created from [Capture captureAudio].  It creates a very simple interface for
+ *  recording by presenting just a record/stop button and a Done button to close the view.
+ *  The recording time is displayed and recording for a specified duration is supported. When duration
+ *  is specified there is no UI to the user - recording just stops when the specified
+ *  duration is reached.  The UI has been minimized to avoid localization.
+ */
+@interface CDVAudioRecorderViewController : UIViewController <AVAudioRecorderDelegate>
+{
+    CDVCaptureError errorCode;
+    NSString* callbackId;
+    NSNumber* duration;
+    CDVCapture* captureCommand;
+    UIBarButtonItem* doneButton;
+    UIView* recordingView;
+    UIButton* recordButton;
+    UIImage* recordImage;
+    UIImage* stopRecordImage;
+    UILabel* timerLabel;
+    AVAudioRecorder* avRecorder;
+    AVAudioSession* avSession;
+    CDVPluginResult* pluginResult;
+    NSTimer* timer;
+    BOOL isTimed;
+}
+@property (nonatomic) CDVCaptureError errorCode;
+@property (nonatomic, copy) NSString* callbackId;
+@property (nonatomic, copy) NSNumber* duration;
+@property (nonatomic, strong) CDVCapture* captureCommand;
+@property (nonatomic, strong) UIBarButtonItem* doneButton;
+@property (nonatomic, strong) UIView* recordingView;
+@property (nonatomic, strong) UIButton* recordButton;
+@property (nonatomic, strong) UIImage* recordImage;
+@property (nonatomic, strong) UIImage* stopRecordImage;
+@property (nonatomic, strong) UILabel* timerLabel;
+@property (nonatomic, strong) AVAudioRecorder* avRecorder;
+@property (nonatomic, strong) AVAudioSession* avSession;
+@property (nonatomic, strong) CDVPluginResult* pluginResult;
+@property (nonatomic, strong) NSTimer* timer;
+@property (nonatomic) BOOL isTimed;
+
+- (id)initWithCommand:(CDVPlugin*)theCommand duration:(NSNumber*)theDuration callbackId:(NSString*)theCallbackId;
+- (void)processButton:(id)sender;
+- (void)stopRecordingCleanup;
+- (void)dismissAudioView:(id)sender;
+- (NSString*)formatTime:(int)interval;
+- (void)updateTime;
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/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
new file mode 100644
index 0000000..95c3f17
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m
@@ -0,0 +1,850 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVCapture.h"
+#import "CDVJSON.h"
+#import "CDVAvailability.h"
+#import "CDVViewController.h"
+
+#define kW3CMediaFormatHeight @"height"
+#define kW3CMediaFormatWidth @"width"
+#define kW3CMediaFormatCodecs @"codecs"
+#define kW3CMediaFormatBitrate @"bitrate"
+#define kW3CMediaFormatDuration @"duration"
+#define kW3CMediaModeType @"type"
+
+@implementation CDVImagePicker
+
+@synthesize quality;
+@synthesize callbackId;
+@synthesize mimeType;
+
+- (uint64_t)accessibilityTraits
+{
+    NSString* systemVersion = [[UIDevice currentDevice] systemVersion];
+
+    if (([systemVersion compare:@"4.0" options:NSNumericSearch] != NSOrderedAscending)) { // this means system version is not less than 4.0
+        return UIAccessibilityTraitStartsMediaSession;
+    }
+
+    return UIAccessibilityTraitNone;
+}
+
+@end
+
+@implementation CDVCapture
+@synthesize inUse;
+
+- (id)initWithWebView:(UIWebView*)theWebView
+{
+    self = (CDVCapture*)[super initWithWebView:theWebView];
+    if (self) {
+        self.inUse = NO;
+    }
+    return self;
+}
+
+- (void)captureAudio:(CDVInvokedUrlCommand*)command
+{
+    NSString* callbackId = command.callbackId;
+    NSDictionary* options = [command.arguments objectAtIndex:0];
+
+    if ([options isKindOfClass:[NSNull class]]) {
+        options = [NSDictionary dictionary];
+    }
+
+    NSNumber* duration = [options objectForKey:@"duration"];
+    // the default value of duration is 0 so use nil (no duration) if default value
+    if (duration) {
+        duration = [duration doubleValue] == 0 ? nil : duration;
+    }
+    CDVPluginResult* result = nil;
+
+    if (NSClassFromString(@"AVAudioRecorder") == nil) {
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_NOT_SUPPORTED];
+    } else if (self.inUse == YES) {
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_APPLICATION_BUSY];
+    } else {
+        // all the work occurs here
+        CDVAudioRecorderViewController* audioViewController = [[CDVAudioRecorderViewController alloc] initWithCommand:self duration:duration callbackId:callbackId];
+
+        // Now create a nav controller and display the view...
+        CDVAudioNavigationController* navController = [[CDVAudioNavigationController alloc] initWithRootViewController:audioViewController];
+
+        self.inUse = YES;
+
+        if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
+            [self.viewController presentViewController:navController animated:YES completion:nil];
+        } else {
+            [self.viewController presentModalViewController:navController animated:YES];
+        }
+    }
+
+    if (result) {
+        [self.commandDelegate sendPluginResult:result callbackId:callbackId];
+    }
+}
+
+- (void)captureImage:(CDVInvokedUrlCommand*)command
+{
+    NSString* callbackId = command.callbackId;
+    NSDictionary* options = [command.arguments objectAtIndex:0];
+
+    if ([options isKindOfClass:[NSNull class]]) {
+        options = [NSDictionary dictionary];
+    }
+    NSString* mode = [options objectForKey:@"mode"];
+
+    // options could contain limit and mode neither of which are supported at this time
+    // taking more than one picture (limit) is only supported if provide own controls via cameraOverlayView property
+    // can support mode in OS
+
+    if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
+        NSLog(@"Capture.imageCapture: camera not available.");
+        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_NOT_SUPPORTED];
+        [self.commandDelegate sendPluginResult:result callbackId:callbackId];
+    } else {
+        if (pickerController == nil) {
+            pickerController = [[CDVImagePicker alloc] init];
+        }
+
+        pickerController.delegate = self;
+        pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
+        pickerController.allowsEditing = NO;
+        if ([pickerController respondsToSelector:@selector(mediaTypes)]) {
+            // iOS 3.0
+            pickerController.mediaTypes = [NSArray arrayWithObjects:(NSString*)kUTTypeImage, nil];
+        }
+
+        /*if ([pickerController respondsToSelector:@selector(cameraCaptureMode)]){
+            // iOS 4.0
+            pickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
+            pickerController.cameraDevice = UIImagePickerControllerCameraDeviceRear;
+            pickerController.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto;
+        }*/
+        // CDVImagePicker specific property
+        pickerController.callbackId = callbackId;
+        pickerController.mimeType = mode;
+
+        if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
+            [self.viewController presentViewController:pickerController animated:YES completion:nil];
+        } else {
+            [self.viewController presentModalViewController:pickerController animated:YES];
+        }
+    }
+}
+
+/* Process a still image from the camera.
+ * IN:
+ *  UIImage* image - the UIImage data returned from the camera
+ *  NSString* callbackId
+ */
+- (CDVPluginResult*)processImage:(UIImage*)image type:(NSString*)mimeType forCallbackId:(NSString*)callbackId
+{
+    CDVPluginResult* result = nil;
+
+    // save the image to photo album
+    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
+
+    NSData* data = nil;
+    if (mimeType && [mimeType isEqualToString:@"image/png"]) {
+        data = UIImagePNGRepresentation(image);
+    } else {
+        data = UIImageJPEGRepresentation(image, 0.5);
+    }
+
+    // write to temp directory and return URI
+    NSString* docsPath = [NSTemporaryDirectory ()stringByStandardizingPath];  // use file system temporary directory
+    NSError* err = nil;
+    NSFileManager* fileMgr = [[NSFileManager alloc] init];
+
+    // generate unique file name
+    NSString* filePath;
+    int i = 1;
+    do {
+        filePath = [NSString stringWithFormat:@"%@/photo_%03d.jpg", docsPath, i++];
+    } while ([fileMgr fileExistsAtPath:filePath]);
+
+    if (![data writeToFile:filePath options:NSAtomicWrite error:&err]) {
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageToErrorObject:CAPTURE_INTERNAL_ERR];
+        if (err) {
+            NSLog(@"Error saving image: %@", [err localizedDescription]);
+        }
+    } else {
+        // create MediaFile object
+
+        NSDictionary* fileDict = [self getMediaDictionaryFromPath:filePath ofType:mimeType];
+        NSArray* fileArray = [NSArray arrayWithObject:fileDict];
+
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:fileArray];
+    }
+
+    return result;
+}
+
+- (void)captureVideo:(CDVInvokedUrlCommand*)command
+{
+    NSString* callbackId = command.callbackId;
+    NSDictionary* options = [command.arguments objectAtIndex:0];
+
+    if ([options isKindOfClass:[NSNull class]]) {
+        options = [NSDictionary dictionary];
+    }
+
+    // options could contain limit, duration and mode, only duration is supported (but is not due to apple bug)
+    // taking more than one video (limit) is only supported if provide own controls via cameraOverlayView property
+    // NSNumber* duration = [options objectForKey:@"duration"];
+    NSString* mediaType = nil;
+
+    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
+        // there is a camera, it is available, make sure it can do movies
+        pickerController = [[CDVImagePicker alloc] init];
+
+        NSArray* types = nil;
+        if ([UIImagePickerController respondsToSelector:@selector(availableMediaTypesForSourceType:)]) {
+            types = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
+            // NSLog(@"MediaTypes: %@", [types description]);
+
+            if ([types containsObject:(NSString*)kUTTypeMovie]) {
+                mediaType = (NSString*)kUTTypeMovie;
+            } else if ([types containsObject:(NSString*)kUTTypeVideo]) {
+                mediaType = (NSString*)kUTTypeVideo;
+            }
+        }
+    }
+    if (!mediaType) {
+        // don't have video camera return error
+        NSLog(@"Capture.captureVideo: video mode not available.");
+        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_NOT_SUPPORTED];
+        [self.commandDelegate sendPluginResult:result callbackId:callbackId];
+        pickerController = nil;
+    } else {
+        pickerController.delegate = self;
+        pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
+        pickerController.allowsEditing = NO;
+        // iOS 3.0
+        pickerController.mediaTypes = [NSArray arrayWithObjects:mediaType, nil];
+
+        /*if ([mediaType isEqualToString:(NSString*)kUTTypeMovie]){
+            if (duration) {
+                pickerController.videoMaximumDuration = [duration doubleValue];
+            }
+            //NSLog(@"pickerController.videoMaximumDuration = %f", pickerController.videoMaximumDuration);
+        }*/
+
+        // iOS 4.0
+        if ([pickerController respondsToSelector:@selector(cameraCaptureMode)]) {
+            pickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo;
+            // pickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;
+            // pickerController.cameraDevice = UIImagePickerControllerCameraDeviceRear;
+            // pickerController.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto;
+        }
+        // CDVImagePicker specific property
+        pickerController.callbackId = callbackId;
+
+        if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
+            [self.viewController presentViewController:pickerController animated:YES completion:nil];
+        } else {
+            [self.viewController presentModalViewController:pickerController animated:YES];
+        }
+    }
+}
+
+- (CDVPluginResult*)processVideo:(NSString*)moviePath forCallbackId:(NSString*)callbackId
+{
+    // save the movie to photo album (only avail as of iOS 3.1)
+
+    /* don't need, it should automatically get saved
+     NSLog(@"can save %@: %d ?", moviePath, UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(moviePath));
+    if (&UIVideoAtPathIsCompatibleWithSavedPhotosAlbum != NULL && UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(moviePath) == YES) {
+        NSLog(@"try to save movie");
+        UISaveVideoAtPathToSavedPhotosAlbum(moviePath, nil, nil, nil);
+        NSLog(@"finished saving movie");
+    }*/
+    // create MediaFile object
+    NSDictionary* fileDict = [self getMediaDictionaryFromPath:moviePath ofType:nil];
+    NSArray* fileArray = [NSArray arrayWithObject:fileDict];
+
+    return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:fileArray];
+}
+
+- (void)getMediaModes:(CDVInvokedUrlCommand*)command
+{
+    // NSString* callbackId = [arguments objectAtIndex:0];
+    // NSMutableDictionary* imageModes = nil;
+    NSArray* imageArray = nil;
+    NSArray* movieArray = nil;
+    NSArray* audioArray = nil;
+
+    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
+        // there is a camera, find the modes
+        // can get image/jpeg or image/png from camera
+
+        /* can't find a way to get the default height and width and other info
+         * for images/movies taken with UIImagePickerController
+         */
+        NSDictionary* jpg = [NSDictionary dictionaryWithObjectsAndKeys:
+            [NSNumber numberWithInt:0], kW3CMediaFormatHeight,
+            [NSNumber numberWithInt:0], kW3CMediaFormatWidth,
+            @"image/jpeg", kW3CMediaModeType,
+            nil];
+        NSDictionary* png = [NSDictionary dictionaryWithObjectsAndKeys:
+            [NSNumber numberWithInt:0], kW3CMediaFormatHeight,
+            [NSNumber numberWithInt:0], kW3CMediaFormatWidth,
+            @"image/png", kW3CMediaModeType,
+            nil];
+        imageArray = [NSArray arrayWithObjects:jpg, png, nil];
+
+        if ([UIImagePickerController respondsToSelector:@selector(availableMediaTypesForSourceType:)]) {
+            NSArray* types = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
+
+            if ([types containsObject:(NSString*)kUTTypeMovie]) {
+                NSDictionary* mov = [NSDictionary dictionaryWithObjectsAndKeys:
+                    [NSNumber numberWithInt:0], kW3CMediaFormatHeight,
+                    [NSNumber numberWithInt:0], kW3CMediaFormatWidth,
+                    @"video/quicktime", kW3CMediaModeType,
+                    nil];
+                movieArray = [NSArray arrayWithObject:mov];
+            }
+        }
+    }
+    NSDictionary* modes = [NSDictionary dictionaryWithObjectsAndKeys:
+        imageArray ? (NSObject*)                          imageArray:[NSNull null], @"image",
+        movieArray ? (NSObject*)                          movieArray:[NSNull null], @"video",
+        audioArray ? (NSObject*)                          audioArray:[NSNull null], @"audio",
+        nil];
+    NSString* jsString = [NSString stringWithFormat:@"navigator.device.capture.setSupportedModes(%@);", [modes JSONString]];
+    [self.commandDelegate evalJs:jsString];
+}
+
+- (void)getFormatData:(CDVInvokedUrlCommand*)command
+{
+    NSString* callbackId = command.callbackId;
+    // existence of fullPath checked on JS side
+    NSString* fullPath = [command.arguments objectAtIndex:0];
+    // mimeType could be null
+    NSString* mimeType = nil;
+
+    if ([command.arguments count] > 1) {
+        mimeType = [command.arguments objectAtIndex:1];
+    }
+    BOOL bError = NO;
+    CDVCaptureError errorCode = CAPTURE_INTERNAL_ERR;
+    CDVPluginResult* result = nil;
+
+    if (!mimeType || [mimeType isKindOfClass:[NSNull class]]) {
+        // try to determine mime type if not provided
+        id command = [self.commandDelegate getCommandInstance:@"File"];
+        bError = !([command isKindOfClass:[CDVFile class]]);
+        if (!bError) {
+            CDVFile* cdvFile = (CDVFile*)command;
+            mimeType = [cdvFile getMimeTypeFromPath:fullPath];
+            if (!mimeType) {
+                // can't do much without mimeType, return error
+                bError = YES;
+                errorCode = CAPTURE_INVALID_ARGUMENT;
+            }
+        }
+    }
+    if (!bError) {
+        // create and initialize return dictionary
+        NSMutableDictionary* formatData = [NSMutableDictionary dictionaryWithCapacity:5];
+        [formatData setObject:[NSNull null] forKey:kW3CMediaFormatCodecs];
+        [formatData setObject:[NSNumber numberWithInt:0] forKey:kW3CMediaFormatBitrate];
+        [formatData setObject:[NSNumber numberWithInt:0] forKey:kW3CMediaFormatHeight];
+        [formatData setObject:[NSNumber numberWithInt:0] forKey:kW3CMediaFormatWidth];
+        [formatData setObject:[NSNumber numberWithInt:0] forKey:kW3CMediaFormatDuration];
+
+        if ([mimeType rangeOfString:@"image/"].location != NSNotFound) {
+            UIImage* image = [UIImage imageWithContentsOfFile:fullPath];
+            if (image) {
+                CGSize imgSize = [image size];
+                [formatData setObject:[NSNumber numberWithInteger:imgSize.width] forKey:kW3CMediaFormatWidth];
+                [formatData setObject:[NSNumber numberWithInteger:imgSize.height] forKey:kW3CMediaFormatHeight];
+            }
+        } else if (([mimeType rangeOfString:@"video/"].location != NSNotFound) && (NSClassFromString(@"AVURLAsset") != nil)) {
+            NSURL* movieURL = [NSURL fileURLWithPath:fullPath];
+            AVURLAsset* movieAsset = [[AVURLAsset alloc] initWithURL:movieURL options:nil];
+            CMTime duration = [movieAsset duration];
+            [formatData setObject:[NSNumber numberWithFloat:CMTimeGetSeconds(duration)]  forKey:kW3CMediaFormatDuration];
+
+            NSArray* allVideoTracks = [movieAsset tracksWithMediaType:AVMediaTypeVideo];
+            if ([allVideoTracks count] > 0) {
+                AVAssetTrack* track = [[movieAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
+                CGSize size = [track naturalSize];
+
+                [formatData setObject:[NSNumber numberWithFloat:size.height] forKey:kW3CMediaFormatHeight];
+                [formatData setObject:[NSNumber numberWithFloat:size.width] forKey:kW3CMediaFormatWidth];
+                // not sure how to get codecs or bitrate???
+                // AVMetadataItem
+                // AudioFile
+            } else {
+                NSLog(@"No video tracks found for %@", fullPath);
+            }
+        } else if ([mimeType rangeOfString:@"audio/"].location != NSNotFound) {
+            if (NSClassFromString(@"AVAudioPlayer") != nil) {
+                NSURL* fileURL = [NSURL fileURLWithPath:fullPath];
+                NSError* err = nil;
+
+                AVAudioPlayer* avPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&err];
+                if (!err) {
+                    // get the data
+                    [formatData setObject:[NSNumber numberWithDouble:[avPlayer duration]] forKey:kW3CMediaFormatDuration];
+                    if ([avPlayer respondsToSelector:@selector(settings)]) {
+                        NSDictionary* info = [avPlayer settings];
+                        NSNumber* bitRate = [info objectForKey:AVEncoderBitRateKey];
+                        if (bitRate) {
+                            [formatData setObject:bitRate forKey:kW3CMediaFormatBitrate];
+                        }
+                    }
+                } // else leave data init'ed to 0
+            }
+        }
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:formatData];
+        // NSLog(@"getFormatData: %@", [formatData description]);
+    }
+    if (bError) {
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errorCode];
+    }
+    if (result) {
+        [self.commandDelegate sendPluginResult:result callbackId:callbackId];
+    }
+}
+
+- (NSDictionary*)getMediaDictionaryFromPath:(NSString*)fullPath ofType:(NSString*)type
+{
+    NSFileManager* fileMgr = [[NSFileManager alloc] init];
+    NSMutableDictionary* fileDict = [NSMutableDictionary dictionaryWithCapacity:5];
+
+    [fileDict setObject:[fullPath lastPathComponent] forKey:@"name"];
+    [fileDict setObject:fullPath forKey:@"fullPath"];
+    // determine type
+    if (!type) {
+        id command = [self.commandDelegate getCommandInstance:@"File"];
+        if ([command isKindOfClass:[CDVFile class]]) {
+            CDVFile* cdvFile = (CDVFile*)command;
+            NSString* mimeType = [cdvFile getMimeTypeFromPath:fullPath];
+            [fileDict setObject:(mimeType != nil ? (NSObject*)mimeType:[NSNull null]) forKey:@"type"];
+        }
+    }
+    NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:fullPath error:nil];
+    [fileDict setObject:[NSNumber numberWithUnsignedLongLong:[fileAttrs fileSize]] forKey:@"size"];
+    NSDate* modDate = [fileAttrs fileModificationDate];
+    NSNumber* msDate = [NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000];
+    [fileDict setObject:msDate forKey:@"lastModifiedDate"];
+
+    return fileDict;
+}
+
+- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo
+{
+    // older api calls new one
+    [self imagePickerController:picker didFinishPickingMediaWithInfo:editingInfo];
+}
+
+/* Called when image/movie is finished recording.
+ * Calls success or error code as appropriate
+ * if successful, result  contains an array (with just one entry since can only get one image unless build own camera UI) of MediaFile object representing the image
+ *      name
+ *      fullPath
+ *      type
+ *      lastModifiedDate
+ *      size
+ */
+- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
+{
+    CDVImagePicker* cameraPicker = (CDVImagePicker*)picker;
+    NSString* callbackId = cameraPicker.callbackId;
+
+    if ([picker respondsToSelector:@selector(presentingViewController)]) {
+        [[picker presentingViewController] dismissModalViewControllerAnimated:YES];
+    } else {
+        [[picker parentViewController] dismissModalViewControllerAnimated:YES];
+    }
+
+    CDVPluginResult* result = nil;
+
+    UIImage* image = nil;
+    NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
+    if (!mediaType || [mediaType isEqualToString:(NSString*)kUTTypeImage]) {
+        // mediaType is nil then only option is UIImagePickerControllerOriginalImage
+        if ([UIImagePickerController respondsToSelector:@selector(allowsEditing)] &&
+            (cameraPicker.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage])) {
+            image = [info objectForKey:UIImagePickerControllerEditedImage];
+        } else {
+            image = [info objectForKey:UIImagePickerControllerOriginalImage];
+        }
+    }
+    if (image != nil) {
+        // mediaType was image
+        result = [self processImage:image type:cameraPicker.mimeType forCallbackId:callbackId];
+    } else if ([mediaType isEqualToString:(NSString*)kUTTypeMovie]) {
+        // process video
+        NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
+        if (moviePath) {
+            result = [self processVideo:moviePath forCallbackId:callbackId];
+        }
+    }
+    if (!result) {
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_INTERNAL_ERR];
+    }
+    [self.commandDelegate sendPluginResult:result callbackId:callbackId];
+    pickerController = nil;
+}
+
+- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker
+{
+    CDVImagePicker* cameraPicker = (CDVImagePicker*)picker;
+    NSString* callbackId = cameraPicker.callbackId;
+
+    if ([picker respondsToSelector:@selector(presentingViewController)]) {
+        [[picker presentingViewController] dismissModalViewControllerAnimated:YES];
+    } else {
+        [[picker parentViewController] dismissModalViewControllerAnimated:YES];
+    }
+
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_NO_MEDIA_FILES];
+    [self.commandDelegate sendPluginResult:result callbackId:callbackId];
+    pickerController = nil;
+}
+
+@end
+
+@implementation CDVAudioNavigationController
+
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000
+    - (NSUInteger)supportedInterfaceOrientations
+    {
+        // delegate to CVDAudioRecorderViewController
+        return [self.topViewController supportedInterfaceOrientations];
+    }
+
+#endif
+
+@end
+
+@implementation CDVAudioRecorderViewController
+@synthesize errorCode, callbackId, duration, captureCommand, doneButton, recordingView, recordButton, recordImage, stopRecordImage, timerLabel, avRecorder, avSession, pluginResult, timer, isTimed;
+
+- (NSString*)resolveImageResource:(NSString*)resource
+{
+    NSString* systemVersion = [[UIDevice currentDevice] systemVersion];
+    BOOL isLessThaniOS4 = ([systemVersion compare:@"4.0" options:NSNumericSearch] == NSOrderedAscending);
+
+    // the iPad image (nor retina) differentiation code was not in 3.x, and we have to explicitly set the path
+    // if user wants iPhone only app to run on iPad they must remove *~ipad.* images from capture.bundle
+    if (isLessThaniOS4) {
+        NSString* iPadResource = [NSString stringWithFormat:@"%@~ipad.png", resource];
+        if (CDV_IsIPad() && [UIImage imageNamed:iPadResource]) {
+            return iPadResource;
+        } else {
+            return [NSString stringWithFormat:@"%@.png", resource];
+        }
+    }
+
+    return resource;
+}
+
+- (id)initWithCommand:(CDVCapture*)theCommand duration:(NSNumber*)theDuration callbackId:(NSString*)theCallbackId
+{
+    if ((self = [super init])) {
+        self.captureCommand = theCommand;
+        self.duration = theDuration;
+        self.callbackId = theCallbackId;
+        self.errorCode = CAPTURE_NO_MEDIA_FILES;
+        self.isTimed = self.duration != nil;
+
+        return self;
+    }
+
+    return nil;
+}
+
+- (void)loadView
+{
+    // create view and display
+    CGRect viewRect = [[UIScreen mainScreen] applicationFrame];
+    UIView* tmp = [[UIView alloc] initWithFrame:viewRect];
+
+    // make backgrounds
+    NSString* microphoneResource = @"Capture.bundle/microphone";
+
+    if (CDV_IsIPhone5()) {
+        microphoneResource = @"Capture.bundle/microphone-568h";
+    }
+
+    UIImage* microphone = [UIImage imageNamed:[self resolveImageResource:microphoneResource]];
+    UIView* microphoneView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, viewRect.size.width, microphone.size.height)];
+    [microphoneView setBackgroundColor:[UIColor colorWithPatternImage:microphone]];
+    [microphoneView setUserInteractionEnabled:NO];
+    [microphoneView setIsAccessibilityElement:NO];
+    [tmp addSubview:microphoneView];
+
+    // add bottom bar view
+    UIImage* grayBkg = [UIImage imageNamed:[self resolveImageResource:@"Capture.bundle/controls_bg"]];
+    UIView* controls = [[UIView alloc] initWithFrame:CGRectMake(0, microphone.size.height, viewRect.size.width, grayBkg.size.height)];
+    [controls setBackgroundColor:[UIColor colorWithPatternImage:grayBkg]];
+    [controls setUserInteractionEnabled:NO];
+    [controls setIsAccessibilityElement:NO];
+    [tmp addSubview:controls];
+
+    // make red recording background view
+    UIImage* recordingBkg = [UIImage imageNamed:[self resolveImageResource:@"Capture.bundle/recording_bg"]];
+    UIColor* background = [UIColor colorWithPatternImage:recordingBkg];
+    self.recordingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, viewRect.size.width, recordingBkg.size.height)];
+    [self.recordingView setBackgroundColor:background];
+    [self.recordingView setHidden:YES];
+    [self.recordingView setUserInteractionEnabled:NO];
+    [self.recordingView setIsAccessibilityElement:NO];
+    [tmp addSubview:self.recordingView];
+
+    // add label
+    self.timerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, viewRect.size.width, recordingBkg.size.height)];
+    // timerLabel.autoresizingMask = reSizeMask;
+    [self.timerLabel setBackgroundColor:[UIColor clearColor]];
+    [self.timerLabel setTextColor:[UIColor whiteColor]];
+    [self.timerLabel setTextAlignment:UITextAlignmentCenter];
+    [self.timerLabel setText:@"0:00"];
+    [self.timerLabel setAccessibilityHint:NSLocalizedString(@"recorded time in minutes and seconds", nil)];
+    self.timerLabel.accessibilityTraits |= UIAccessibilityTraitUpdatesFrequently;
+    self.timerLabel.accessibilityTraits &= ~UIAccessibilityTraitStaticText;
+    [tmp addSubview:self.timerLabel];
+
+    // Add record button
+
+    self.recordImage = [UIImage imageNamed:[self resolveImageResource:@"Capture.bundle/record_button"]];
+    self.stopRecordImage = [UIImage imageNamed:[self resolveImageResource:@"Capture.bundle/stop_button"]];
+    self.recordButton.accessibilityTraits |= [self accessibilityTraits];
+    self.recordButton = [[UIButton alloc] initWithFrame:CGRectMake((viewRect.size.width - recordImage.size.width) / 2, (microphone.size.height + (grayBkg.size.height - recordImage.size.height) / 2), recordImage.size.width, recordImage.size.height)];
+    [self.recordButton setAccessibilityLabel:NSLocalizedString(@"toggle audio recording", nil)];
+    [self.recordButton setImage:recordImage forState:UIControlStateNormal];
+    [self.recordButton addTarget:self action:@selector(processButton:) forControlEvents:UIControlEventTouchUpInside];
+    [tmp addSubview:recordButton];
+
+    // make and add done button to navigation bar
+    self.doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismissAudioView:)];
+    [self.doneButton setStyle:UIBarButtonItemStyleDone];
+    self.navigationItem.rightBarButtonItem = self.doneButton;
+
+    [self setView:tmp];
+}
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+    UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
+    NSError* error = nil;
+
+    if (self.avSession == nil) {
+        // create audio session
+        self.avSession = [AVAudioSession sharedInstance];
+        if (error) {
+            // return error if can't create recording audio session
+            NSLog(@"error creating audio session: %@", [[error userInfo] description]);
+            self.errorCode = CAPTURE_INTERNAL_ERR;
+            [self dismissAudioView:nil];
+        }
+    }
+
+    // create file to record to in temporary dir
+
+    NSString* docsPath = [NSTemporaryDirectory ()stringByStandardizingPath];  // use file system temporary directory
+    NSError* err = nil;
+    NSFileManager* fileMgr = [[NSFileManager alloc] init];
+
+    // generate unique file name
+    NSString* filePath;
+    int i = 1;
+    do {
+        filePath = [NSString stringWithFormat:@"%@/audio_%03d.wav", docsPath, i++];
+    } while ([fileMgr fileExistsAtPath:filePath]);
+
+    NSURL* fileURL = [NSURL fileURLWithPath:filePath isDirectory:NO];
+
+    // create AVAudioPlayer
+    self.avRecorder = [[AVAudioRecorder alloc] initWithURL:fileURL settings:nil error:&err];
+    if (err) {
+        NSLog(@"Failed to initialize AVAudioRecorder: %@\n", [err localizedDescription]);
+        self.avRecorder = nil;
+        // return error
+        self.errorCode = CAPTURE_INTERNAL_ERR;
+        [self dismissAudioView:nil];
+    } else {
+        self.avRecorder.delegate = self;
+        [self.avRecorder prepareToRecord];
+        self.recordButton.enabled = YES;
+        self.doneButton.enabled = YES;
+    }
+}
+
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000
+    - (NSUInteger)supportedInterfaceOrientations
+    {
+        NSUInteger orientation = UIInterfaceOrientationMaskPortrait; // must support portrait
+        NSUInteger supported = [captureCommand.viewController supportedInterfaceOrientations];
+
+        orientation = orientation | (supported & UIInterfaceOrientationMaskPortraitUpsideDown);
+        return orientation;
+    }
+
+#endif
+
+- (void)viewDidUnload
+{
+    [self setView:nil];
+    [self.captureCommand setInUse:NO];
+}
+
+- (void)processButton:(id)sender
+{
+    if (self.avRecorder.recording) {
+        // stop recording
+        [self.avRecorder stop];
+        self.isTimed = NO;  // recording was stopped via button so reset isTimed
+        // view cleanup will occur in audioRecordingDidFinishRecording
+    } else {
+        // begin recording
+        [self.recordButton setImage:stopRecordImage forState:UIControlStateNormal];
+        self.recordButton.accessibilityTraits &= ~[self accessibilityTraits];
+        [self.recordingView setHidden:NO];
+        NSError* error = nil;
+        [self.avSession setCategory:AVAudioSessionCategoryRecord error:&error];
+        [self.avSession setActive:YES error:&error];
+        if (error) {
+            // can't continue without active audio session
+            self.errorCode = CAPTURE_INTERNAL_ERR;
+            [self dismissAudioView:nil];
+        } else {
+            if (self.duration) {
+                self.isTimed = true;
+                [self.avRecorder recordForDuration:[duration doubleValue]];
+            } else {
+                [self.avRecorder record];
+            }
+            [self.timerLabel setText:@"0.00"];
+            self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:@selector(updateTime) userInfo:nil repeats:YES];
+            self.doneButton.enabled = NO;
+        }
+        UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
+    }
+}
+
+/*
+ * helper method to clean up when stop recording
+ */
+- (void)stopRecordingCleanup
+{
+    if (self.avRecorder.recording) {
+        [self.avRecorder stop];
+    }
+    [self.recordButton setImage:recordImage forState:UIControlStateNormal];
+    self.recordButton.accessibilityTraits |= [self accessibilityTraits];
+    [self.recordingView setHidden:YES];
+    self.doneButton.enabled = YES;
+    if (self.avSession) {
+        // deactivate session so sounds can come through
+        [self.avSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
+        [self.avSession setActive:NO error:nil];
+    }
+    if (self.duration && self.isTimed) {
+        // VoiceOver announcement so user knows timed recording has finished
+        BOOL isUIAccessibilityAnnouncementNotification = (&UIAccessibilityAnnouncementNotification != NULL);
+        if (isUIAccessibilityAnnouncementNotification) {
+            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 500ull * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
+                    UIAccessibilityPostNotification (UIAccessibilityAnnouncementNotification, NSLocalizedString (@"timed recording complete", nil));
+                });
+        }
+    } else {
+        // issue a layout notification change so that VO will reannounce the button label when recording completes
+        UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
+    }
+}
+
+- (void)dismissAudioView:(id)sender
+{
+    // called when done button pressed or when error condition to do cleanup and remove view
+    if ([self.captureCommand.viewController.modalViewController respondsToSelector:@selector(presentingViewController)]) {
+        [[self.captureCommand.viewController.modalViewController presentingViewController] dismissModalViewControllerAnimated:YES];
+    } else {
+        [[self.captureCommand.viewController.modalViewController parentViewController] dismissModalViewControllerAnimated:YES];
+    }
+
+    if (!self.pluginResult) {
+        // return error
+        self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:self.errorCode];
+    }
+
+    self.avRecorder = nil;
+    [self.avSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
+    [self.avSession setActive:NO error:nil];
+    [self.captureCommand setInUse:NO];
+    UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
+    // return result
+    [self.captureCommand.commandDelegate sendPluginResult:pluginResult callbackId:callbackId];
+}
+
+- (void)updateTime
+{
+    // update the label with the elapsed time
+    [self.timerLabel setText:[self formatTime:self.avRecorder.currentTime]];
+}
+
+- (NSString*)formatTime:(int)interval
+{
+    // is this format universal?
+    int secs = interval % 60;
+    int min = interval / 60;
+
+    if (interval < 60) {
+        return [NSString stringWithFormat:@"0:%02d", interval];
+    } else {
+        return [NSString stringWithFormat:@"%d:%02d", min, secs];
+    }
+}
+
+- (void)audioRecorderDidFinishRecording:(AVAudioRecorder*)recorder successfully:(BOOL)flag
+{
+    // may be called when timed audio finishes - need to stop time and reset buttons
+    [self.timer invalidate];
+    [self stopRecordingCleanup];
+
+    // generate success result
+    if (flag) {
+        NSString* filePath = [avRecorder.url path];
+        // NSLog(@"filePath: %@", filePath);
+        NSDictionary* fileDict = [captureCommand getMediaDictionaryFromPath:filePath ofType:@"audio/wav"];
+        NSArray* fileArray = [NSArray arrayWithObject:fileDict];
+
+        self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:fileArray];
+    } else {
+        self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageToErrorObject:CAPTURE_INTERNAL_ERR];
+    }
+}
+
+- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder*)recorder error:(NSError*)error
+{
+    [self.timer invalidate];
+    [self stopRecordingCleanup];
+
+    NSLog(@"error recording audio");
+    self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageToErrorObject:CAPTURE_INTERNAL_ERR];
+    [self dismissAudioView:nil];
+}
+
+@end