From 118ca18d5a7d77dfe37c5c9a85350a7890448de9 Mon Sep 17 00:00:00 2001
From: Joe Bowser <bowserj@apache.org>
Date: Wed, 21 Aug 2013 15:39:43 -0700
Subject: [PATCH 01/10] No longer causes a stack trace, but it doesn't cause
 the error to be called.

---
 src/android/CameraLauncher.java | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/src/android/CameraLauncher.java b/src/android/CameraLauncher.java
index ba432cb..02a9211 100755
--- a/src/android/CameraLauncher.java
+++ b/src/android/CameraLauncher.java
@@ -76,7 +76,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
     private static final String GET_PICTURE = "Get Picture";
     private static final String GET_VIDEO = "Get Video";
     private static final String GET_All = "Get All";
-
+    
     private static final String LOG_TAG = "CameraLauncher";
 
     private int mQuality;                   // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
@@ -153,15 +153,26 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                 this.targetHeight = -1;
             }
 
-            if (srcType == CAMERA) {
-                this.takePicture(destType, encodingType);
+             try {
+                if (srcType == CAMERA) {
+                    this.takePicture(destType, encodingType);
+                }
+                else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
+                    this.getImage(srcType, destType);
+                }
             }
-            else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
-                this.getImage(srcType, destType);
+            catch (IllegalArgumentException e)
+            {
+                callbackContext.error("Illegal Argument Exception");
+                PluginResult r = new PluginResult(PluginResult.Status.ERROR);
+                callbackContext.sendPluginResult(r);
+                return true;
             }
+             
             PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
             r.setKeepCallback(true);
             callbackContext.sendPluginResult(r);
+            
             return true;
         }
         return false;

From f33e00083a853594c5ea0154ae339b87eb677454 Mon Sep 17 00:00:00 2001
From: Joe Bowser <bowserj@apache.org>
Date: Wed, 4 Sep 2013 11:33:35 -0700
Subject: [PATCH 02/10] CB-4633: We really should close cursors.  It's just the
 right thing to do.

---
 src/android/CameraLauncher.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/android/CameraLauncher.java b/src/android/CameraLauncher.java
index 02a9211..7f2f20f 100755
--- a/src/android/CameraLauncher.java
+++ b/src/android/CameraLauncher.java
@@ -749,6 +749,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
             }
             Uri uri = Uri.parse(contentStore + "/" + id);
             this.cordova.getActivity().getContentResolver().delete(uri, null, null);
+            cursor.close();
         }
     }
 

From 8c77ddb86424e128e463b690e2dd10974a8a852e Mon Sep 17 00:00:00 2001
From: Andrew Grieve <agrieve@chromium.org>
Date: Fri, 6 Sep 2013 00:58:21 -0400
Subject: [PATCH 03/10] [CB-4752] Incremented plugin version on dev branch.

---
 plugin.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/plugin.xml b/plugin.xml
index 18d08e9..dcc7910 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -3,7 +3,7 @@
 <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
     xmlns:android="http://schemas.android.com/apk/res/android"
     id="org.apache.cordova.core.camera"
-    version="0.2.1">
+    version="0.2.2-dev">
     <name>Camera</name>
     <description>Cordova Camera Plugin</description>
     <license>Apache 2.0</license>

From 44517ea93f705152cd91bbafdb849a53a7d6804d Mon Sep 17 00:00:00 2001
From: Andrew Grieve <agrieve@chromium.org>
Date: Mon, 9 Sep 2013 15:10:40 -0400
Subject: [PATCH 04/10] [CB-4763] Use a copy of FileHelper.java within
 camera-plugin.

---
 plugin.xml                      |   1 +
 src/android/CameraLauncher.java |   1 -
 src/android/FileHelper.java     | 162 ++++++++++++++++++++++++++++++++
 3 files changed, 163 insertions(+), 1 deletion(-)
 create mode 100644 src/android/FileHelper.java

diff --git a/plugin.xml b/plugin.xml
index dcc7910..d31a5a7 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -35,6 +35,7 @@
         </config-file>
 
         <source-file src="src/android/CameraLauncher.java" target-dir="src/org/apache/cordova/camera" />
+        <source-file src="src/android/FileHelper.java" target-dir="src/org/apache/cordova/camera" />
 
         <js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
             <clobbers target="CameraPopoverHandle" />
diff --git a/src/android/CameraLauncher.java b/src/android/CameraLauncher.java
index 7f2f20f..c8961f6 100755
--- a/src/android/CameraLauncher.java
+++ b/src/android/CameraLauncher.java
@@ -28,7 +28,6 @@ import java.io.OutputStream;
 
 import org.apache.cordova.ExifHelper;
 import org.apache.cordova.DirectoryManager;
-import org.apache.cordova.FileHelper;
 import org.apache.cordova.CallbackContext;
 import org.apache.cordova.CordovaPlugin;
 import org.apache.cordova.LOG;
diff --git a/src/android/FileHelper.java b/src/android/FileHelper.java
new file mode 100644
index 0000000..fb7fc6f
--- /dev/null
+++ b/src/android/FileHelper.java
@@ -0,0 +1,162 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+ */
+package org.apache.cordova.camera;
+
+import android.database.Cursor;
+import android.net.Uri;
+import android.webkit.MimeTypeMap;
+
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.LOG;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.Locale;
+
+public class FileHelper {
+    private static final String LOG_TAG = "FileUtils";
+    private static final String _DATA = "_data";
+
+    /**
+     * Returns the real path of the given URI string.
+     * If the given URI string represents a content:// URI, the real path is retrieved from the media store.
+     *
+     * @param uriString the URI string of the audio/image/video
+     * @param cordova the current application context
+     * @return the full path to the file
+     */
+    @SuppressWarnings("deprecation")
+    public static String getRealPath(String uriString, CordovaInterface cordova) {
+        String realPath = null;
+
+        if (uriString.startsWith("content://")) {
+            String[] proj = { _DATA };
+            Cursor cursor = cordova.getActivity().managedQuery(Uri.parse(uriString), proj, null, null, null);
+            int column_index = cursor.getColumnIndexOrThrow(_DATA);
+            cursor.moveToFirst();
+            realPath = cursor.getString(column_index);
+            if (realPath == null) {
+                LOG.e(LOG_TAG, "Could get real path for URI string %s", uriString);
+            }
+        } else if (uriString.startsWith("file://")) {
+            realPath = uriString.substring(7);
+            if (realPath.startsWith("/android_asset/")) {
+                LOG.e(LOG_TAG, "Cannot get real path for URI string %s because it is a file:///android_asset/ URI.", uriString);
+                realPath = null;
+            }
+        } else {
+            realPath = uriString;
+        }
+
+        return realPath;
+    }
+
+    /**
+     * Returns the real path of the given URI.
+     * If the given URI is a content:// URI, the real path is retrieved from the media store.
+     *
+     * @param uri the URI of the audio/image/video
+     * @param cordova the current application context
+     * @return the full path to the file
+     */
+    public static String getRealPath(Uri uri, CordovaInterface cordova) {
+        return FileHelper.getRealPath(uri.toString(), cordova);
+    }
+
+    /**
+     * Returns an input stream based on given URI string.
+     *
+     * @param uriString the URI string from which to obtain the input stream
+     * @param cordova the current application context
+     * @return an input stream into the data at the given URI or null if given an invalid URI string
+     * @throws IOException
+     */
+    public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova) throws IOException {
+        if (uriString.startsWith("content")) {
+            Uri uri = Uri.parse(uriString);
+            return cordova.getActivity().getContentResolver().openInputStream(uri);
+        } else if (uriString.startsWith("file://")) {
+            int question = uriString.indexOf("?");
+            if (question > -1) {
+            	uriString = uriString.substring(0,question);
+            }
+            if (uriString.startsWith("file:///android_asset/")) {
+                Uri uri = Uri.parse(uriString);
+                String relativePath = uri.getPath().substring(15);
+                return cordova.getActivity().getAssets().open(relativePath);
+            } else {
+                return new FileInputStream(getRealPath(uriString, cordova));
+            }
+        } else {
+            return new FileInputStream(getRealPath(uriString, cordova));
+        }
+    }
+
+    /**
+     * Removes the "file://" prefix from the given URI string, if applicable.
+     * If the given URI string doesn't have a "file://" prefix, it is returned unchanged.
+     *
+     * @param uriString the URI string to operate on
+     * @return a path without the "file://" prefix
+     */
+    public static String stripFileProtocol(String uriString) {
+        if (uriString.startsWith("file://")) {
+            uriString = uriString.substring(7);
+        }
+        return uriString;
+    }
+
+    public static String getMimeTypeForExtension(String path) {
+        String extension = path;
+        int lastDot = extension.lastIndexOf('.');
+        if (lastDot != -1) {
+            extension = extension.substring(lastDot + 1);
+        }
+        // Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
+        extension = extension.toLowerCase(Locale.getDefault());
+        if (extension.equals("3ga")) {
+            return "audio/3gpp";
+        }
+        return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+    }
+    
+    /**
+     * Returns the mime type of the data specified by the given URI string.
+     *
+     * @param uriString the URI string of the data
+     * @return the mime type of the specified data
+     */
+    public static String getMimeType(String uriString, CordovaInterface cordova) {
+        String mimeType = null;
+
+        Uri uri = Uri.parse(uriString);
+        if (uriString.startsWith("content://")) {
+            mimeType = cordova.getActivity().getContentResolver().getType(uri);
+        } else {
+            mimeType = getMimeTypeForExtension(uri.getPath());
+        }
+
+        return mimeType;
+    }
+}

From df028dd2571ab8fd1032a20b0f55ca2b32e8c0b9 Mon Sep 17 00:00:00 2001
From: Andrew Grieve <agrieve@chromium.org>
Date: Mon, 9 Sep 2013 16:03:36 -0400
Subject: [PATCH 05/10] [CB-4764] Remove reference to DirectoryManager from
 CameraLauncher

---
 src/android/CameraLauncher.java | 46 ++++++++++++++++-----------------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/src/android/CameraLauncher.java b/src/android/CameraLauncher.java
index c8961f6..4d01179 100755
--- a/src/android/CameraLauncher.java
+++ b/src/android/CameraLauncher.java
@@ -27,7 +27,6 @@ import java.io.IOException;
 import java.io.OutputStream;
 
 import org.apache.cordova.ExifHelper;
-import org.apache.cordova.DirectoryManager;
 import org.apache.cordova.CallbackContext;
 import org.apache.cordova.CordovaPlugin;
 import org.apache.cordova.LOG;
@@ -94,23 +93,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
     private MediaScannerConnection conn;    // Used to update gallery app with newly-written files
     private Uri scanMe;                     // Uri of image to be added to content store
 
-    //This should never be null!
-    //private CordovaInterface cordova;
-
-    /**
-     * Constructor.
-     */
-    public CameraLauncher() {
-    }
-
-//    public void setContext(CordovaInterface mCtx) {
-//        super.setContext(mCtx);
-//        if (CordovaInterface.class.isInstance(mCtx))
-//            cordova = (CordovaInterface) mCtx;
-//        else
-//            LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
-//    }
-
     /**
      * Executes the request and returns PluginResult.
      *
@@ -181,6 +163,24 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
     // LOCAL METHODS
     //--------------------------------------------------------------------------
 
+    private String getTempDirectoryPath() {
+        File cache = null;
+
+        // SD Card Mounted
+        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+            cache = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
+                    "/Android/data/" + cordova.getActivity().getPackageName() + "/cache/");
+        }
+        // Use internal storage
+        else {
+            cache = cordova.getActivity().getCacheDir();
+        }
+
+        // Create the cache directory if it doesn't exist
+        cache.mkdirs();
+        return cache.getAbsolutePath();
+    }
+
     /**
      * Take a picture with the camera.
      * When an image is captured or the camera view is cancelled, the result is returned
@@ -223,9 +223,9 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
     private File createCaptureFile(int encodingType) {
         File photo = null;
         if (encodingType == JPEG) {
-            photo = new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), ".Pic.jpg");
+            photo = new File(getTempDirectoryPath(), ".Pic.jpg");
         } else if (encodingType == PNG) {
-            photo = new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), ".Pic.png");
+            photo = new File(getTempDirectoryPath(), ".Pic.png");
         } else {
             throw new IllegalArgumentException("Invalid Encoding Type: " + encodingType);
         }
@@ -289,7 +289,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                     ExifHelper exif = new ExifHelper();
                     try {
                         if (this.encodingType == JPEG) {
-                            exif.createInFile(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/.Pic.jpg");
+                            exif.createInFile(getTempDirectoryPath() + "/.Pic.jpg");
                             exif.readExifData();
                             rotate = exif.getOrientation();
                         }
@@ -330,7 +330,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                             //Just because we have a media URI doesn't mean we have a real file, we need to make it
                             uri = Uri.fromFile(new File(FileHelper.getRealPath(inputUri, this.cordova)));
                         } else {
-                            uri = Uri.fromFile(new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), System.currentTimeMillis() + ".jpg"));
+                            uri = Uri.fromFile(new File(getTempDirectoryPath(), System.currentTimeMillis() + ".jpg"));
                         }
 
                         if (uri == null) {
@@ -450,7 +450,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                             if (this.targetHeight > 0 && this.targetWidth > 0) {
                                 try {
                                     // Create an ExifHelper to save the exif data that is lost during compression
-                                    String resizePath = DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/resize.jpg";
+                                    String resizePath = getTempDirectoryPath() + "/resize.jpg";
                                     // Some content: URIs do not map to file paths (e.g. picasa).
                                     String realPath = FileHelper.getRealPath(uri, this.cordova);
                                     ExifHelper exif = new ExifHelper();

From bc32c501daea502009bac4f83e06531846534f6c Mon Sep 17 00:00:00 2001
From: Andrew Grieve <agrieve@chromium.org>
Date: Mon, 9 Sep 2013 16:14:48 -0400
Subject: [PATCH 06/10] [CB-4765] Move ExifHelper.java into Camera Plugin

---
 plugin.xml                      |   1 +
 src/android/CameraLauncher.java |   1 -
 src/android/ExifHelper.java     | 185 ++++++++++++++++++++++++++++++++
 3 files changed, 186 insertions(+), 1 deletion(-)
 create mode 100644 src/android/ExifHelper.java

diff --git a/plugin.xml b/plugin.xml
index d31a5a7..7f58841 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -36,6 +36,7 @@
 
         <source-file src="src/android/CameraLauncher.java" target-dir="src/org/apache/cordova/camera" />
         <source-file src="src/android/FileHelper.java" target-dir="src/org/apache/cordova/camera" />
+        <source-file src="src/android/ExifHelper.java" target-dir="src/org/apache/cordova/camera" />
 
         <js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
             <clobbers target="CameraPopoverHandle" />
diff --git a/src/android/CameraLauncher.java b/src/android/CameraLauncher.java
index 4d01179..ec8222d 100755
--- a/src/android/CameraLauncher.java
+++ b/src/android/CameraLauncher.java
@@ -26,7 +26,6 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 
-import org.apache.cordova.ExifHelper;
 import org.apache.cordova.CallbackContext;
 import org.apache.cordova.CordovaPlugin;
 import org.apache.cordova.LOG;
diff --git a/src/android/ExifHelper.java b/src/android/ExifHelper.java
new file mode 100644
index 0000000..5160a2f
--- /dev/null
+++ b/src/android/ExifHelper.java
@@ -0,0 +1,185 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.camera;
+
+import java.io.IOException;
+
+import android.media.ExifInterface;
+
+public class ExifHelper {
+    private String aperture = null;
+    private String datetime = null;
+    private String exposureTime = null;
+    private String flash = null;
+    private String focalLength = null;
+    private String gpsAltitude = null;
+    private String gpsAltitudeRef = null;
+    private String gpsDateStamp = null;
+    private String gpsLatitude = null;
+    private String gpsLatitudeRef = null;
+    private String gpsLongitude = null;
+    private String gpsLongitudeRef = null;
+    private String gpsProcessingMethod = null;
+    private String gpsTimestamp = null;
+    private String iso = null;
+    private String make = null;
+    private String model = null;
+    private String orientation = null;
+    private String whiteBalance = null;
+
+    private ExifInterface inFile = null;
+    private ExifInterface outFile = null;
+
+    /**
+     * The file before it is compressed
+     *
+     * @param filePath
+     * @throws IOException
+     */
+    public void createInFile(String filePath) throws IOException {
+        this.inFile = new ExifInterface(filePath);
+    }
+
+    /**
+     * The file after it has been compressed
+     *
+     * @param filePath
+     * @throws IOException
+     */
+    public void createOutFile(String filePath) throws IOException {
+        this.outFile = new ExifInterface(filePath);
+    }
+
+    /**
+     * Reads all the EXIF data from the input file.
+     */
+    public void readExifData() {
+        this.aperture = inFile.getAttribute(ExifInterface.TAG_APERTURE);
+        this.datetime = inFile.getAttribute(ExifInterface.TAG_DATETIME);
+        this.exposureTime = inFile.getAttribute(ExifInterface.TAG_EXPOSURE_TIME);
+        this.flash = inFile.getAttribute(ExifInterface.TAG_FLASH);
+        this.focalLength = inFile.getAttribute(ExifInterface.TAG_FOCAL_LENGTH);
+        this.gpsAltitude = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE);
+        this.gpsAltitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF);
+        this.gpsDateStamp = inFile.getAttribute(ExifInterface.TAG_GPS_DATESTAMP);
+        this.gpsLatitude = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
+        this.gpsLatitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
+        this.gpsLongitude = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
+        this.gpsLongitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
+        this.gpsProcessingMethod = inFile.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD);
+        this.gpsTimestamp = inFile.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP);
+        this.iso = inFile.getAttribute(ExifInterface.TAG_ISO);
+        this.make = inFile.getAttribute(ExifInterface.TAG_MAKE);
+        this.model = inFile.getAttribute(ExifInterface.TAG_MODEL);
+        this.orientation = inFile.getAttribute(ExifInterface.TAG_ORIENTATION);
+        this.whiteBalance = inFile.getAttribute(ExifInterface.TAG_WHITE_BALANCE);
+    }
+
+    /**
+     * Writes the previously stored EXIF data to the output file.
+     *
+     * @throws IOException
+     */
+    public void writeExifData() throws IOException {
+        // Don't try to write to a null file
+        if (this.outFile == null) {
+            return;
+        }
+
+        if (this.aperture != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_APERTURE, this.aperture);
+        }
+        if (this.datetime != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_DATETIME, this.datetime);
+        }
+        if (this.exposureTime != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_EXPOSURE_TIME, this.exposureTime);
+        }
+        if (this.flash != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_FLASH, this.flash);
+        }
+        if (this.focalLength != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_FOCAL_LENGTH, this.focalLength);
+        }
+        if (this.gpsAltitude != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, this.gpsAltitude);
+        }
+        if (this.gpsAltitudeRef != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF, this.gpsAltitudeRef);
+        }
+        if (this.gpsDateStamp != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_DATESTAMP, this.gpsDateStamp);
+        }
+        if (this.gpsLatitude != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE, this.gpsLatitude);
+        }
+        if (this.gpsLatitudeRef != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, this.gpsLatitudeRef);
+        }
+        if (this.gpsLongitude != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, this.gpsLongitude);
+        }
+        if (this.gpsLongitudeRef != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, this.gpsLongitudeRef);
+        }
+        if (this.gpsProcessingMethod != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD, this.gpsProcessingMethod);
+        }
+        if (this.gpsTimestamp != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, this.gpsTimestamp);
+        }
+        if (this.iso != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_ISO, this.iso);
+        }
+        if (this.make != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_MAKE, this.make);
+        }
+        if (this.model != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_MODEL, this.model);
+        }
+        if (this.orientation != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_ORIENTATION, this.orientation);
+        }
+        if (this.whiteBalance != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_WHITE_BALANCE, this.whiteBalance);
+        }
+
+        this.outFile.saveAttributes();
+    }
+
+    public int getOrientation() {
+        int o = Integer.parseInt(this.orientation);
+
+        if (o == ExifInterface.ORIENTATION_NORMAL) {
+            return 0;
+        } else if (o == ExifInterface.ORIENTATION_ROTATE_90) {
+            return 90;
+        } else if (o == ExifInterface.ORIENTATION_ROTATE_180) {
+            return 180;
+        } else if (o == ExifInterface.ORIENTATION_ROTATE_270) {
+            return 270;
+        } else {
+            return 0;
+        }
+    }
+
+    public void resetOrientation() {
+        this.orientation = "" + ExifInterface.ORIENTATION_NORMAL;
+    }
+}

From 224e7cfb2006a5d7ef8e7083b6913715312b23f4 Mon Sep 17 00:00:00 2001
From: Andrew Grieve <agrieve@chromium.org>
Date: Mon, 9 Sep 2013 16:21:30 -0400
Subject: [PATCH 07/10] Fix compiler warnings

---
 src/android/FileHelper.java | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/src/android/FileHelper.java b/src/android/FileHelper.java
index fb7fc6f..24ced59 100644
--- a/src/android/FileHelper.java
+++ b/src/android/FileHelper.java
@@ -26,12 +26,8 @@ import org.apache.cordova.CordovaInterface;
 import org.apache.cordova.LOG;
 
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.Charset;
 import java.util.Locale;
 
 public class FileHelper {

From 9bcf725e393e76502253f01b28399c1fa6bd6b5c Mon Sep 17 00:00:00 2001
From: James Jong <wjamesjong@gmail.com>
Date: Mon, 16 Sep 2013 15:13:35 -0400
Subject: [PATCH 08/10] [CB-4823] Fix XCode 5 camera plugin warnings

---
 src/ios/CDVCamera.m | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/ios/CDVCamera.m b/src/ios/CDVCamera.m
index e0f195f..19f8148 100644
--- a/src/ios/CDVCamera.m
+++ b/src/ios/CDVCamera.m
@@ -150,9 +150,11 @@ static NSSet* org_apache_cordova_validArrowDirections;
         NSDictionary* options = [command.arguments objectAtIndex:10 withDefault:nil];
         [self displayPopover:options];
     } else {
-        if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
+        SEL selector = NSSelectorFromString(@"presentViewController:animated:completion:");
+        if ([self.viewController respondsToSelector:selector]) {
             [self.viewController presentViewController:cameraPicker animated:YES completion:nil];
         } else {
+            // deprecated as of iOS >= 6.0
             [self.viewController presentModalViewController:cameraPicker animated:YES];
         }
     }

From 8077d302fefea25b77d853eaf388cddddea7a12b Mon Sep 17 00:00:00 2001
From: Andrew Grieve <agrieve@chromium.org>
Date: Tue, 17 Sep 2013 11:36:13 -0400
Subject: [PATCH 09/10] Rename CHANGELOG.md -> RELEASENOTES.md

---
 CHANGELOG.md => RELEASENOTES.md | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename CHANGELOG.md => RELEASENOTES.md (100%)

diff --git a/CHANGELOG.md b/RELEASENOTES.md
similarity index 100%
rename from CHANGELOG.md
rename to RELEASENOTES.md

From 3a3bbb1cc9bfe4d04a560bf86bead1fd01a2904f Mon Sep 17 00:00:00 2001
From: Herm Wong <herm.wong@gmail.com>
Date: Wed, 18 Sep 2013 16:22:13 -0700
Subject: [PATCH 10/10] added Camera API for FirefoxOS

---
 plugin.xml                   | 12 +++++++++
 src/firefoxos/CameraProxy.js | 52 ++++++++++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+)
 create mode 100644 src/firefoxos/CameraProxy.js

diff --git a/plugin.xml b/plugin.xml
index 7f58841..dbf89d4 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -139,5 +139,17 @@
         </js-module>
 
     </platform>
+ 
+    <!-- firefoxos -->
+    <platform name="firefoxos">
+        <config-file target="config.xml" parent="/*">
+            <feature name="Camera">
+                <param name="firefoxos-package" value="Camera" />
+            </feature>
+        </config-file>                                         
+        <js-module src="src/firefoxos/CameraProxy.js" name="CameraProxy">
+            <runs />
+        </js-module>
+    </platform>
 
 </plugin>
diff --git a/src/firefoxos/CameraProxy.js b/src/firefoxos/CameraProxy.js
new file mode 100644
index 0000000..bbed304
--- /dev/null
+++ b/src/firefoxos/CameraProxy.js
@@ -0,0 +1,52 @@
+/*
+ *
+ * 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.
+ *
+*/
+
+
+
+function getPicture(cameraSuccess, cameraError, cameraOptions) {
+  cameraError = cameraError || function(){};
+  var pick = new MozActivity({
+    name: "pick",
+    data: {
+      type: ["image/png", "image/jpg", "image/jpeg"]
+    }
+  });
+  pick.onerror = cameraError;
+  pick.onsuccess = function() {
+    // image is returned as Blob in this.result.blob
+    // we need to call cameraSuccess with url or base64 encoded image
+    if (cameraOptions && cameraOptions.destinationType == 0) {
+      // TODO: base64
+      return;
+    }
+    if (!cameraOptions || !cameraOptions.destinationType || cameraOptions.destinationType > 0) {
+      // url
+      return cameraSuccess(window.URL.createObjectURL(this.result.blob));
+    }
+  };
+}
+
+module.exports = {
+  getPicture: getPicture,
+  cleanup: function(){}
+};
+
+require("cordova/firefoxos/commandProxy").add("Camera", module.exports);
\ No newline at end of file