Compare commits

..

15 Commits

Author SHA1 Message Date
Erisu
4584f15d9f Updated version and RELEASENOTES.md for release 5.0.0 (camera-20200914) 2020-09-14 12:19:36 +09:00
エリス
0111e93448 ci(travis): update osx xcode image (#648)
* ci(travis): update osx xcode image
* ci: use travis's latest supported osx_image xcode11.6
2020-09-03 19:35:43 +09:00
jcesarmobile
0333d001c7 breaking: remove NATIVE_URI DestinationType (#637) 2020-08-07 14:38:05 +02:00
エリス
45496213b3 breaking: bump project requirements (#628) 2020-07-28 20:25:48 +09:00
エリス
3f42591363 chore: remove deprecated file transfer plugin (#634) 2020-07-23 20:16:36 +09:00
jcesarmobile
e2ecd7fe91 fix(android): return error if file url is null (#632) 2020-07-23 12:11:55 +02:00
Loïc Le Malliaud
eb7fc333ee fix(android): use provider prefix to avoid conflicts other plugin providers (#510)
Co-authored-by: jcesarmobile <jcesarmobile@gmail.com>
2020-07-16 13:08:40 +02:00
jcesarmobile
fd155d9705 breaking(android): stop using CordovaUri helper class (#617) 2020-07-14 16:26:09 +02:00
エリス
2bf5b9347e chore: add package-lock.json (#630) 2020-07-14 19:26:24 +09:00
エリス
efb633969e chore(package): use short notation (#631) 2020-07-14 19:15:57 +09:00
エリス
973bbbbac7 feat: migrate to @cordova/eslint-config@3.x (#629) 2020-07-14 19:15:29 +09:00
エリス
358522c0b5 ci: fix additional tests (#626) 2020-07-14 17:55:23 +09:00
エリス
8766956abb breaking: bump version 5.0.0-dev (#627) 2020-07-14 17:55:04 +09:00
jcesarmobile
d89c25cd82 fix(ios): tempFilePath called twice if using CameraUsesGeolocation (#612) 2020-06-25 18:23:01 +02:00
Jesse MacFadyen
ba4f77468f chore(release): 4.2.0-dev 2020-05-07 01:34:03 -07:00
23 changed files with 1921 additions and 398 deletions

View File

@@ -1,10 +1,23 @@
# 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.
root: true
extends: semistandard
rules:
indent:
- error
- 4
camelcase: off
padded-blocks: off
operator-linebreak: off
no-throw-literal: off
extends: '@cordova/eslint-config/browser'
overrides:
- files: [tests/**/*.js]
extends: '@cordova/eslint-config/node-tests'

View File

@@ -13,8 +13,8 @@ env:
global:
- SAUCE_USERNAME=snay
- TRAVIS_NODE_VERSION=12
- ANDROID_API_LEVEL=28
- ANDROID_BUILD_TOOLS_VERSION=28.0.3
- ANDROID_API_LEVEL=29
- ANDROID_BUILD_TOOLS_VERSION=29.0.2
language: node_js
node_js: 12
@@ -23,7 +23,7 @@ node_js: 12
_ios: &_ios
os: osx
osx_image: xcode10.3
osx_image: xcode11.6
_android: &_android
language: android
@@ -43,7 +43,8 @@ matrix:
include:
# additional tests
- env: ADDITIONAL_TESTS_DIR=./tests/ios
language: objective-c
os: osx
osx_image: xcode11.5
# local tests, without saucelabs
- env: PLATFORM=local/browser

View File

@@ -276,19 +276,14 @@ Optional parameters to customize the camera settings.
### Camera.DestinationType : <code>enum</code>
Defines the output format of `Camera.getPicture` call.
_Note:_ On iOS passing `DestinationType.NATIVE_URI` along with
`PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SAVEDPHOTOALBUM` will
disable any image modifications (resize, quality change, cropping, etc.) due
to implementation specific.
**Kind**: static enum property of <code>[Camera](#module_Camera)</code>
**Properties**
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| DATA_URL | <code>number</code> | <code>0</code> | Return base64 encoded string. DATA_URL can be very memory intensive and cause app crashes or out of memory errors. Use FILE_URI or NATIVE_URI if possible |
| DATA_URL | <code>number</code> | <code>0</code> | Return base64 encoded string. DATA_URL can be very memory intensive and cause app crashes or out of memory errors. Use FILE_URI if possible |
| FILE_URI | <code>number</code> | <code>1</code> | Return file uri (content://media/external/images/media/2 for Android) |
| NATIVE_URI | <code>number</code> | <code>2</code> | Return native uri (eg. asset-library://... for iOS) |
<a name="module_Camera.EncodingType"></a>
@@ -317,9 +312,6 @@ to implementation specific.
### Camera.PictureSourceType : <code>enum</code>
Defines the output format of `Camera.getPicture` call.
_Note:_ On iOS passing `PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SAVEDPHOTOALBUM`
along with `DestinationType.NATIVE_URI` will disable any image modifications (resize, quality
change, cropping, etc.) due to implementation specific.
**Kind**: static enum property of <code>[Camera](#module_Camera)</code>
**Properties**
@@ -435,7 +427,7 @@ Take a photo and retrieve it as a Base64-encoded image:
* Warning: Using DATA_URL is not recommended! The DATA_URL destination
* type is very memory intensive, even with a low quality setting. Using it
* can result in out of memory errors and application crashes. Use FILE_URI
* or NATIVE_URI instead.
* instead.
*/
navigator.camera.getPicture(onSuccess, onFail, { quality: 25,
destinationType: Camera.DestinationType.DATA_URL
@@ -508,9 +500,6 @@ More information about Windows Phone 8.1 picker APIs is here: [How to continue y
- When using `destinationType.FILE_URI`, photos are saved in the application's temporary directory. The contents of the application's temporary directory is deleted when the application ends.
- When using `destinationType.NATIVE_URI` and `sourceType.CAMERA`, photos are saved in the saved photo album regardless on the value of `saveToPhotoAlbum` parameter.
- When using `destinationType.NATIVE_URI` and `sourceType.PHOTOLIBRARY` or `sourceType.SAVEDPHOTOALBUM`, all editing options are ignored and link is returned to original picture.
[android_lifecycle]: http://cordova.apache.org/docs/en/dev/guide/platforms/android/lifecycle.html

View File

@@ -20,6 +20,22 @@
-->
# Release Notes
### 5.0.0 (Sep 14, 2020)
* [GH-648](https://github.com/apache/cordova-plugin-camera/pull/648) ci(travis): update osx xcode image
* [GH-637](https://github.com/apache/cordova-plugin-camera/pull/637) breaking: remove `NATIVE_URI` DestinationType
* [GH-628](https://github.com/apache/cordova-plugin-camera/pull/628) breaking: bump project requirements
* [GH-634](https://github.com/apache/cordova-plugin-camera/pull/634) chore: remove deprecated `file-transfer` plugin
* [GH-632](https://github.com/apache/cordova-plugin-camera/pull/632) fix(android): return error if file url is null
* [GH-510](https://github.com/apache/cordova-plugin-camera/pull/510) fix(android): use provider prefix to avoid conflicts other plugin providers
* [GH-617](https://github.com/apache/cordova-plugin-camera/pull/617) breaking(android): stop using `CordovaUri` helper class
* [GH-630](https://github.com/apache/cordova-plugin-camera/pull/630) chore: add `package-lock.json`
* [GH-631](https://github.com/apache/cordova-plugin-camera/pull/631) chore(package): use short notation
* [GH-629](https://github.com/apache/cordova-plugin-camera/pull/629) feat: migrate to `@cordova/eslint-config@3.x`
* [GH-626](https://github.com/apache/cordova-plugin-camera/pull/626) ci: fix additional tests
* [GH-627](https://github.com/apache/cordova-plugin-camera/pull/627) breaking: bump version 5.0.0-dev
* [GH-612](https://github.com/apache/cordova-plugin-camera/pull/612) fix(ios): `tempFilePath` called twice if using `CameraUsesGeolocation`
### 4.2.0 (May 07, 2020)
* Cache images in device storage, devices have enough space now.
* docs(readme): app renamed to Google Photos

1724
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "cordova-plugin-camera",
"version": "4.2.0",
"version": "5.0.0",
"description": "Cordova Camera Plugin",
"types": "./types/index.d.ts",
"cordova": {
@@ -13,13 +13,8 @@
"osx"
]
},
"repository": {
"type": "git",
"url": "https://github.com/apache/cordova-plugin-camera"
},
"bugs": {
"url": "https://github.com/apache/cordova-plugin-camera/issues"
},
"repository": "github:apache/cordova-plugin-camera",
"bugs": "https://github.com/apache/cordova-plugin-camera/issues",
"keywords": [
"cordova",
"camera",
@@ -31,8 +26,8 @@
"cordova-osx"
],
"scripts": {
"test": "npm run eslint",
"eslint": "node node_modules/eslint/bin/eslint www && node node_modules/eslint/bin/eslint src && node node_modules/eslint/bin/eslint tests"
"test": "npm run lint",
"lint": "eslint ."
},
"author": "Apache Software Foundation",
"license": "Apache-2.0",
@@ -46,17 +41,16 @@
"cordova": ">=7.1.0"
},
"5.0.0": {
"cordova-android": ">=9.0.0",
"cordova-ios": ">=5.1.0",
"cordova": ">=9.0.0"
},
"6.0.0": {
"cordova": ">100"
}
}
},
"devDependencies": {
"eslint": "^4.3.0",
"eslint-config-semistandard": "^11.0.0",
"eslint-config-standard": "^10.2.1",
"eslint-plugin-import": "^2.3.0",
"eslint-plugin-node": "^5.0.0",
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-standard": "^3.0.1"
"@cordova/eslint-config": "^3.0.0"
}
}

View File

@@ -21,7 +21,7 @@
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
id="cordova-plugin-camera"
version="4.2.0">
version="5.0.0">
<name>Camera</name>
<description>Cordova Camera Plugin</description>
<license>Apache 2.0</license>
@@ -30,8 +30,9 @@
<issue>https://github.com/apache/cordova-plugin-camera/issues</issue>
<engines>
<engine name="cordova" version=">=7.1.0"/>
<engine name="cordova-android" version=">=6.3.0" />
<engine name="cordova" version=">=9.0.0"/>
<engine name="cordova-android" version=">=9.0.0" />
<engine name="cordova-ios" version=">=5.1.0" />
</engines>
<js-module src="www/CameraConstants.js" name="Camera">
@@ -59,7 +60,7 @@
<config-file target="AndroidManifest.xml" parent="application">
<provider
android:name="org.apache.cordova.camera.FileProvider"
android:authorities="${applicationId}.provider"
android:authorities="${applicationId}.cordova.plugin.camera.provider"
android:exported="false"
android:grantUriPermissions="true" >
<meta-data
@@ -69,7 +70,6 @@
</config-file>
<source-file src="src/android/CameraLauncher.java" target-dir="src/org/apache/cordova/camera" />
<source-file src="src/android/CordovaUri.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" />
<source-file src="src/android/FileProvider.java" target-dir="src/org/apache/cordova/camera" />
@@ -151,12 +151,12 @@
<js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
<clobbers target="CameraPopoverHandle" />
</js-module>
<header-file src="src/osx/CDVCamera.h" />
<source-file src="src/osx/CDVCamera.m" />
<framework src="Quartz.framework" />
<framework src="AppKit.framework" />
</platform>
</plugin>

View File

@@ -69,7 +69,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
private static final int DATA_URL = 0; // Return base64 encoded string
private static final int FILE_URI = 1; // Return file uri (content://media/external/images/media/2 for Android)
private static final int NATIVE_URI = 2; // On Android, this is the same as FILE_URI
private static final int PHOTOLIBRARY = 0; // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
private static final int CAMERA = 1; // Take picture from camera
@@ -109,7 +108,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
private int targetWidth; // desired width of the image
private int targetHeight; // desired height of the image
private CordovaUri imageUri; // Uri of captured image
private Uri imageUri; // Uri of captured image
private String imageFilePath; // File where the image is stored
private int encodingType; // Type of encoding to use
private int mediaType; // What type of media to retrieve
private int destType; // Source type (needs to be saved for the permission handling)
@@ -127,6 +127,7 @@ 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
private Uri croppedUri;
private String croppedFilePath;
private ExifHelper exifData; // Exif data from source
private String applicationId;
@@ -290,10 +291,11 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// Specify file so that large image is captured and returned
File photo = createCaptureFile(encodingType);
this.imageUri = new CordovaUri(FileProvider.getUriForFile(cordova.getActivity(),
applicationId + ".provider",
photo));
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri.getCorrectUri());
this.imageFilePath = photo.getAbsolutePath();
this.imageUri = FileProvider.getUriForFile(cordova.getActivity(),
applicationId + ".cordova.plugin.camera.provider",
photo);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
//We can write to this URI, this will hopefully allow us to write files to get to the next step
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
@@ -360,6 +362,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
Intent intent = new Intent();
String title = GET_PICTURE;
croppedUri = null;
croppedFilePath = null;
if (this.mediaType == PICTURE) {
intent.setType("image/*");
if (this.allowEdit) {
@@ -375,8 +378,9 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
}
File photo = createCaptureFile(JPEG);
croppedUri = Uri.fromFile(photo);
File croppedFile = createCaptureFile(JPEG);
croppedFilePath = croppedFile.getAbsolutePath();
croppedUri = Uri.fromFile(croppedFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, croppedUri);
} else {
intent.setAction(Intent.ACTION_GET_CONTENT);
@@ -428,7 +432,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
cropIntent.putExtra("aspectY", 1);
}
// create new file handle to get full resolution crop
croppedUri = Uri.fromFile(createCaptureFile(this.encodingType, System.currentTimeMillis() + ""));
croppedFilePath = createCaptureFile(this.encodingType, System.currentTimeMillis() + "").getAbsolutePath();
croppedUri = Uri.parse(croppedFilePath);
cropIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
cropIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
cropIntent.putExtra("output", croppedUri);
@@ -466,8 +471,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
ExifHelper exif = new ExifHelper();
String sourcePath = (this.allowEdit && this.croppedUri != null) ?
FileHelper.stripFileProtocol(this.croppedUri.toString()) :
this.imageUri.getFilePath();
this.croppedFilePath :
this.imageFilePath;
if (this.encodingType == JPEG) {
@@ -494,7 +499,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
if (this.allowEdit && this.croppedUri != null) {
writeUncompressedImage(croppedUri, galleryUri);
} else {
Uri imageUri = this.imageUri.getFileUri();
Uri imageUri = this.imageUri;
writeUncompressedImage(imageUri, galleryUri);
}
@@ -526,7 +531,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
}
// If sending filename back
else if (destType == FILE_URI || destType == NATIVE_URI) {
else if (destType == FILE_URI) {
// If all this is true we shouldn't compress the image.
if (this.targetHeight == -1 && this.targetWidth == -1 && this.mQuality == 100 &&
!this.correctOrientation) {
@@ -539,10 +544,10 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
Uri uri = Uri.fromFile(createCaptureFile(this.encodingType, System.currentTimeMillis() + ""));
if (this.allowEdit && this.croppedUri != null) {
Uri croppedUri = Uri.fromFile(new File(getFileNameFromUri(this.croppedUri)));
Uri croppedUri = Uri.parse(croppedFilePath);
writeUncompressedImage(croppedUri, uri);
} else {
Uri imageUri = this.imageUri.getFileUri();
Uri imageUri = this.imageUri;
writeUncompressedImage(imageUri, uri);
}
@@ -588,7 +593,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
throw new IllegalStateException();
}
this.cleanup(FILE_URI, this.imageUri.getFileUri(), galleryUri, bitmap);
this.cleanup(FILE_URI, this.imageUri, galleryUri, bitmap);
bitmap = null;
}
@@ -680,68 +685,75 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
LOG.d(LOG_TAG, "File location is: " + fileLocation);
String uriString = uri.toString();
String finalLocation = fileLocation != null ? fileLocation : uriString;
String mimeType = FileHelper.getMimeType(uriString, this.cordova);
// If you ask for video or the selected file doesn't have JPEG or PNG mime type
// there will be no attempt to resize any returned data
if (this.mediaType == VIDEO || !(JPEG_MIME_TYPE.equalsIgnoreCase(mimeType) || PNG_MIME_TYPE.equalsIgnoreCase(mimeType))) {
this.callbackContext.success(fileLocation);
}
else {
if (finalLocation == null) {
this.failPicture("Error retrieving result.");
} else {
// This is a special case to just return the path as no scaling,
// rotating, nor compressing needs to be done
if (this.targetHeight == -1 && this.targetWidth == -1 &&
(destType == FILE_URI || destType == NATIVE_URI) && !this.correctOrientation &&
mimeType != null && mimeType.equalsIgnoreCase(getMimetypeForFormat(encodingType)))
{
this.callbackContext.success(uriString);
} else {
Bitmap bitmap = null;
try {
bitmap = getScaledAndRotatedBitmap(uriString);
} catch (IOException e) {
e.printStackTrace();
}
if (bitmap == null) {
LOG.d(LOG_TAG, "I either have a null image path or bitmap");
this.failPicture("Unable to create bitmap!");
return;
}
// If you ask for video or the selected file doesn't have JPEG or PNG mime type
// there will be no attempt to resize any returned data
if (this.mediaType == VIDEO || !(JPEG_MIME_TYPE.equalsIgnoreCase(mimeType) || PNG_MIME_TYPE.equalsIgnoreCase(mimeType))) {
this.callbackContext.success(finalLocation);
}
else {
// If sending base64 image back
if (destType == DATA_URL) {
this.processPicture(bitmap, this.encodingType);
}
// If sending filename back
else if (destType == FILE_URI || destType == NATIVE_URI) {
// Did we modify the image?
if ( (this.targetHeight > 0 && this.targetWidth > 0) ||
(this.correctOrientation && this.orientationCorrected) ||
!mimeType.equalsIgnoreCase(getMimetypeForFormat(encodingType)))
{
try {
String modifiedPath = this.outputModifiedBitmap(bitmap, uri);
// The modified image is cached by the app in order to get around this and not have to delete you
// application cache I'm adding the current system time to the end of the file url.
this.callbackContext.success("file://" + modifiedPath + "?" + System.currentTimeMillis());
} catch (Exception e) {
e.printStackTrace();
this.failPicture("Error retrieving image.");
}
} else {
this.callbackContext.success(fileLocation);
// This is a special case to just return the path as no scaling,
// rotating, nor compressing needs to be done
if (this.targetHeight == -1 && this.targetWidth == -1 &&
destType == FILE_URI && !this.correctOrientation &&
mimeType != null && mimeType.equalsIgnoreCase(getMimetypeForFormat(encodingType)))
{
this.callbackContext.success(finalLocation);
} else {
Bitmap bitmap = null;
try {
bitmap = getScaledAndRotatedBitmap(uriString);
} catch (IOException e) {
e.printStackTrace();
}
if (bitmap == null) {
LOG.d(LOG_TAG, "I either have a null image path or bitmap");
this.failPicture("Unable to create bitmap!");
return;
}
// If sending base64 image back
if (destType == DATA_URL) {
this.processPicture(bitmap, this.encodingType);
}
// If sending filename back
else if (destType == FILE_URI) {
// Did we modify the image?
if ( (this.targetHeight > 0 && this.targetWidth > 0) ||
(this.correctOrientation && this.orientationCorrected) ||
!mimeType.equalsIgnoreCase(getMimetypeForFormat(encodingType)))
{
try {
String modifiedPath = this.outputModifiedBitmap(bitmap, uri);
// The modified image is cached by the app in order to get around this and not have to delete you
// application cache I'm adding the current system time to the end of the file url.
this.callbackContext.success("file://" + modifiedPath + "?" + System.currentTimeMillis());
} catch (Exception e) {
e.printStackTrace();
this.failPicture("Error retrieving image.");
}
} else {
this.callbackContext.success(finalLocation);
}
}
if (bitmap != null) {
bitmap.recycle();
bitmap = null;
}
System.gc();
}
if (bitmap != null) {
bitmap.recycle();
bitmap = null;
}
System.gc();
}
}
}
/**
@@ -789,7 +801,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
try {
if (this.allowEdit) {
Uri tmpFile = FileProvider.getUriForFile(cordova.getActivity(),
applicationId + ".provider",
applicationId + ".cordova.plugin.camera.provider",
createCaptureFile(this.encodingType));
performCrop(tmpFile, destType, intent);
} else {
@@ -1336,11 +1348,11 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
state.putBoolean("saveToPhotoAlbum", this.saveToPhotoAlbum);
if (this.croppedUri != null) {
state.putString(CROPPED_URI_KEY, this.croppedUri.toString());
state.putString(CROPPED_URI_KEY, this.croppedFilePath);
}
if (this.imageUri != null) {
state.putString(IMAGE_URI_KEY, this.imageUri.getFileUri().toString());
state.putString(IMAGE_URI_KEY, this.imageFilePath);
}
return state;
@@ -1365,28 +1377,9 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
if (state.containsKey(IMAGE_URI_KEY)) {
//I have no idea what type of URI is being passed in
this.imageUri = new CordovaUri(Uri.parse(state.getString(IMAGE_URI_KEY)));
this.imageUri = Uri.parse(state.getString(IMAGE_URI_KEY));
}
this.callbackContext = callbackContext;
}
/*
* This is dirty, but it does the job.
*
* Since the FilesProvider doesn't really provide you a way of getting a URL from the file,
* and since we actually need the Camera to create the file for us most of the time, we don't
* actually write the file, just generate the location based on a timestamp, we need to get it
* back from the Intent.
*
* However, the FilesProvider preserves the path, so we can at least write to it from here, since
* we own the context in this case.
*/
private String getFileNameFromUri(Uri uri) {
String fullUri = uri.toString();
String partial_path = fullUri.split("external_files")[1];
File external_storage = Environment.getExternalStorageDirectory();
String path = external_storage.getAbsolutePath() + partial_path;
return path;
}
}

View File

@@ -1,104 +0,0 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.cordova.camera;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.support.v4.content.FileProvider;
import java.io.File;
/*
* This class exists because Andorid FilesProvider doesn't work on Android 4.4.4 and below and throws
* weird errors. I'm not sure why writing to shared cache directories is somehow verboten, but it is
* and this error is irritating for a Compatibility library to have.
*
*/
public class CordovaUri {
private Uri androidUri;
private String fileName;
private Uri fileUri;
/*
* We always expect a FileProvider string to be passed in for the file that we create
*
*/
CordovaUri (Uri inputUri)
{
//Determine whether the file is a content or file URI
if(inputUri.getScheme().equals("content"))
{
androidUri = inputUri;
fileName = getFileNameFromUri(androidUri);
fileUri = Uri.parse("file://" + fileName);
}
else
{
fileUri = inputUri;
fileName = FileHelper.stripFileProtocol(inputUri.toString());
}
}
public Uri getFileUri()
{
return fileUri;
}
public String getFilePath()
{
return fileName;
}
/*
* This only gets called by takePicture
*/
public Uri getCorrectUri()
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
return androidUri;
else
return fileUri;
}
/*
* This is dirty, but it does the job.
*
* Since the FilesProvider doesn't really provide you a way of getting a URL from the file,
* and since we actually need the Camera to create the file for us most of the time, we don't
* actually write the file, just generate the location based on a timestamp, we need to get it
* back from the Intent.
*
* However, the FilesProvider preserves the path, so we can at least write to it from here, since
* we own the context in this case.
*/
private String getFileNameFromUri(Uri uri) {
String fullUri = uri.toString();
String partial_path = fullUri.split("external_files")[1];
File external_storage = Environment.getExternalStorageDirectory();
String path = external_storage.getAbsolutePath() + partial_path;
return path;
}
}

View File

@@ -50,16 +50,7 @@ public class FileHelper {
*/
@SuppressWarnings("deprecation")
public static String getRealPath(Uri uri, CordovaInterface cordova) {
String realPath = null;
if (Build.VERSION.SDK_INT < 11)
realPath = FileHelper.getRealPathFromURI_BelowAPI11(cordova.getActivity(), uri);
// SDK >= 11
else
realPath = FileHelper.getRealPathFromURI_API11_And_Above(cordova.getActivity(), uri);
return realPath;
return FileHelper.getRealPathFromURI(cordova.getActivity(), uri);
}
/**
@@ -75,11 +66,9 @@ public class FileHelper {
}
@SuppressLint("NewApi")
public static String getRealPathFromURI_API11_And_Above(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
public static String getRealPathFromURI(final Context context, final Uri uri) {
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
if (DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {

View File

@@ -17,5 +17,5 @@
-->
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
<cache-path name="cache_files" path="." />
</paths>

View File

@@ -112,7 +112,7 @@ function capture (success, errorCallback, opts) {
};
if (navigator.getUserMedia) {
navigator.getUserMedia({video: true, audio: false}, successCallback, errorCallback);
navigator.getUserMedia({ video: true, audio: false }, successCallback, errorCallback);
} else {
alert('Browser does not support camera :(');
}

View File

@@ -24,8 +24,7 @@
enum CDVDestinationType {
DestinationTypeDataUrl = 0,
DestinationTypeFileUri,
DestinationTypeNativeUri
DestinationTypeFileUri
};
typedef NSUInteger CDVDestinationType;

View File

@@ -168,7 +168,7 @@ static NSString* toBase64(NSData* data) {
[weakSelf sendNoPermissionResult:command.callbackId];
}]];
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Settings", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
[weakSelf sendNoPermissionResult:command.callbackId];
}]];
[weakSelf.viewController presentViewController:alertController animated:YES completion:nil];
@@ -383,6 +383,7 @@ static NSString* toBase64(NSData* data) {
}
[[self locationManager] startUpdatingLocation];
}
data = nil;
}
}
break;
@@ -396,15 +397,10 @@ static NSString* toBase64(NSData* data) {
- (NSString*)tempFilePath:(NSString*)extension
{
NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath];
NSFileManager* fileMgr = [[NSFileManager alloc] init]; // recommended by Apple (vs [NSFileManager defaultManager]) to be threadsafe
NSString* filePath;
// unique file name
NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
NSNumber *timeStampObj = [NSNumber numberWithDouble: timeStamp];
do {
filePath = [NSString stringWithFormat:@"%@/%@%ld.%@", docsPath, CDV_PHOTO_PREFIX, [timeStampObj longValue], extension];
} while ([fileMgr fileExistsAtPath:filePath]);
NSString* filePath = [NSString stringWithFormat:@"%@/%@%ld.%@", docsPath, CDV_PHOTO_PREFIX, [timeStampObj longValue], extension];
return filePath;
}
@@ -444,33 +440,16 @@ static NSString* toBase64(NSData* data) {
UIImage* image = nil;
switch (options.destinationType) {
case DestinationTypeNativeUri:
case DestinationTypeDataUrl:
{
NSURL* url = [info objectForKey:UIImagePickerControllerReferenceURL];
saveToPhotoAlbum = NO;
// If, for example, we use sourceType = Camera, URL might be nil because image is stored in memory.
// In this case we must save image to device before obtaining an URI.
if (url == nil) {
image = [self retrieveImage:info options:options];
ALAssetsLibrary* library = [ALAssetsLibrary new];
[library writeImageToSavedPhotosAlbum:image.CGImage orientation:(ALAssetOrientation)(image.imageOrientation) completionBlock:^(NSURL *assetURL, NSError *error) {
CDVPluginResult* resultToReturn = nil;
if (error) {
resultToReturn = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
} else {
NSString* nativeUri = [[self urlTransformer:assetURL] absoluteString];
resultToReturn = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:nativeUri];
}
completion(resultToReturn);
}];
return;
} else {
NSString* nativeUri = [[self urlTransformer:url] absoluteString];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:nativeUri];
image = [self retrieveImage:info options:options];
NSData* data = [self processImage:image info:info options:options];
if (data) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:toBase64(data)];
}
}
break;
case DestinationTypeFileUri:
default: // DestinationTypeFileUri
{
image = [self retrieveImage:info options:options];
NSData* data = [self processImage:image info:info options:options];
@@ -489,22 +468,10 @@ static NSString* toBase64(NSData* data) {
}
}
break;
case DestinationTypeDataUrl:
{
image = [self retrieveImage:info options:options];
NSData* data = [self processImage:image info:info options:options];
if (data) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:toBase64(data)];
}
}
break;
default:
break;
};
if (saveToPhotoAlbum && image) {
ALAssetsLibrary* library = [ALAssetsLibrary new];
[library writeImageToSavedPhotosAlbum:image.CGImage orientation:(ALAssetOrientation)(image.imageOrientation) completionBlock:nil];
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
completion(result);
@@ -580,10 +547,8 @@ static NSString* toBase64(NSData* data) {
dispatch_block_t invoke = ^ (void) {
CDVPluginResult* result;
if (picker.sourceType == UIImagePickerControllerSourceTypeCamera && [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] != ALAuthorizationStatusAuthorized) {
if (picker.sourceType == UIImagePickerControllerSourceTypeCamera && [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] != AVAuthorizationStatusAuthorized) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"has no access to camera"];
} else if (picker.sourceType != UIImagePickerControllerSourceTypeCamera && ! IsAtLeastiOSVersion(@"11.0") && [ALAssetsLibrary authorizationStatus] != ALAuthorizationStatusAuthorized) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"has no access to assets"];
} else {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"No Image Selected"];
}
@@ -698,7 +663,12 @@ static NSString* toBase64(NSData* data) {
}
switch (options.destinationType) {
case DestinationTypeFileUri:
case DestinationTypeDataUrl:
{
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:toBase64(self.data)];
}
break;
default: // DestinationTypeFileUri
{
NSError* err = nil;
NSString* extension = self.pickerController.pictureOptions.encodingType == EncodingTypePNG ? @"png":@"jpg";
@@ -713,14 +683,6 @@ static NSString* toBase64(NSData* data) {
}
}
break;
case DestinationTypeDataUrl:
{
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:toBase64(self.data)];
}
break;
case DestinationTypeNativeUri:
default:
break;
};
if (result) {
@@ -733,8 +695,7 @@ static NSString* toBase64(NSData* data) {
self.metadata = nil;
if (options.saveToPhotoAlbum) {
ALAssetsLibrary *library = [ALAssetsLibrary new];
[library writeImageDataToSavedPhotosAlbum:self.data metadata:self.metadata completionBlock:nil];
UIImageWriteToSavedPhotosAlbum([[UIImage alloc] initWithData:self.data], nil, nil, nil);
}
}

View File

@@ -24,8 +24,7 @@
enum CDVDestinationType {
DestinationTypeDataUrl = 0,
DestinationTypeFileUri,
DestinationTypeNativeUri
DestinationTypeFileUri
};
typedef NSUInteger CDVDestinationType;

View File

@@ -161,7 +161,7 @@ static NSMutableArray *cleanUpFiles;
/*!
Returns to JavaScript a URI.
Called when Camera.DestinationType.FILE_URI or Camera.DestinationType.NATIVE_URI.
Called when Camera.DestinationType.FILE_URI.
*/
- (void)returnUri:(NSString *)path command:(CDVInvokedUrlCommand *)command options:(CDVPictureOptions *)pictureOptions {
NSString *protocol = (pictureOptions.destinationType == DestinationTypeFileUri) ? @"file://" : @"";

View File

@@ -190,17 +190,13 @@ function takePictureFromFileWP (successCallback, errorCallback, args) {
webUIApp.removeEventListener('activated', filePickerActivationHandler);
return;
}
if (destinationType === Camera.DestinationType.FILE_URI || destinationType === Camera.DestinationType.NATIVE_URI) {
if (destinationType === Camera.DestinationType.FILE_URI) {
if (targetHeight > 0 && targetWidth > 0) {
resizeImage(successCallback, errorCallback, file, targetWidth, targetHeight, encodingType);
} else {
var storageFolder = getAppData().localFolder;
file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting).done(function (storageFile) {
if (destinationType === Camera.DestinationType.NATIVE_URI) {
successCallback('ms-appdata:///local/' + storageFile.name);
} else {
successCallback(URL.createObjectURL(storageFile));
}
successCallback(URL.createObjectURL(storageFile));
}, function () {
errorCallback("Can't access localStorage folder.");
});
@@ -259,17 +255,13 @@ function takePictureFromFileWindows (successCallback, errorCallback, args) {
errorCallback("User didn't choose a file.");
return;
}
if (destinationType === Camera.DestinationType.FILE_URI || destinationType === Camera.DestinationType.NATIVE_URI) {
if (destinationType === Camera.DestinationType.FILE_URI) {
if (targetHeight > 0 && targetWidth > 0) {
resizeImage(successCallback, errorCallback, file, targetWidth, targetHeight, encodingType);
} else {
var storageFolder = getAppData().localFolder;
file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting).done(function (storageFile) {
if (destinationType === Camera.DestinationType.NATIVE_URI) {
successCallback('ms-appdata:///local/' + storageFile.name);
} else {
successCallback(URL.createObjectURL(storageFile));
}
successCallback(URL.createObjectURL(storageFile));
}, function () {
errorCallback("Can't access localStorage folder.");
});
@@ -374,7 +366,6 @@ function takePictureFromCameraWP (successCallback, errorCallback, args) {
return capture.initializeAsync(captureSettings);
}).then(function () {
// create focus control if available
var VideoDeviceController = capture.videoDeviceController;
var FocusControl = VideoDeviceController.focusControl;
@@ -477,7 +468,6 @@ function takePictureFromCameraWP (successCallback, errorCallback, args) {
}
function captureAction () {
var encodingProperties;
var fileName;
var tempFolder = getAppData().temporaryFolder;
@@ -715,7 +705,7 @@ function takePictureFromCameraWindows (successCallback, errorCallback, args) {
if (targetWidth === -1 && targetHeight === -1) {
maxRes = UIMaxRes.highestAvailable;
// Temp fix for CB-10539
// Temp fix for CB-10539
/* else if (totalPixels <= 320 * 240) {
maxRes = UIMaxRes.verySmallQvga;
} */
@@ -781,7 +771,7 @@ function takePictureFromCameraWindows (successCallback, errorCallback, args) {
function savePhoto (picture, options, successCallback, errorCallback) {
// success callback for capture operation
var success = function (picture) {
if (options.destinationType === Camera.DestinationType.FILE_URI || options.destinationType === Camera.DestinationType.NATIVE_URI) {
if (options.destinationType === Camera.DestinationType.FILE_URI) {
if (options.targetHeight > 0 && options.targetWidth > 0) {
resizeImage(successCallback, errorCallback, picture, options.targetWidth, options.targetHeight, options.encodingType);
} else {
@@ -812,7 +802,6 @@ function savePhoto (picture, options, successCallback, errorCallback) {
if (!options.saveToPhotoAlbum) {
success(picture);
} else {
var savePicker = new Windows.Storage.Pickers.FileSavePicker();
var saveFile = function (file) {

View File

@@ -1,6 +1,6 @@
{
"name": "cordova-plugin-camera-tests",
"version": "4.2.0",
"version": "5.0.0",
"description": "",
"cordova": {
"id": "cordova-plugin-camera-tests",

View File

@@ -22,12 +22,10 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:rim="http://www.blackberry.com/ns/widgets"
id="cordova-plugin-camera-tests"
version="4.2.0">
version="5.0.0">
<name>Cordova Camera Plugin Tests</name>
<license>Apache 2.0</license>
<dependency id="cordova-plugin-file-transfer" />
<js-module src="tests.js" name="tests">
</js-module>
</plugin>

View File

@@ -19,7 +19,7 @@
*
*/
/* globals Camera, resolveLocalFileSystemURL, FileEntry, CameraPopoverOptions, FileTransfer, FileUploadOptions, LocalFileSystem, MSApp */
/* globals Camera, resolveLocalFileSystemURL, FileEntry, CameraPopoverOptions, LocalFileSystem, MSApp */
/* eslint-env jasmine */
exports.defineAutoTests = function () {
@@ -42,10 +42,8 @@ exports.defineAutoTests = function () {
it('camera.spec.2 should contain three DestinationType constants', function () {
expect(Camera.DestinationType.DATA_URL).toBe(0);
expect(Camera.DestinationType.FILE_URI).toBe(1);
expect(Camera.DestinationType.NATIVE_URI).toBe(2);
expect(navigator.camera.DestinationType.DATA_URL).toBe(0);
expect(navigator.camera.DestinationType.FILE_URI).toBe(1);
expect(navigator.camera.DestinationType.NATIVE_URI).toBe(2);
});
it('camera.spec.3 should contain two EncodingType constants', function () {
@@ -140,7 +138,7 @@ exports.defineManualTests = function (contentEl, createActionButton) {
function getPictureWin (data) {
setPicture(data);
// TODO: Fix resolveLocalFileSystemURI to work with native-uri.
if (pictureUrl.indexOf('file:') === 0 || pictureUrl.indexOf('content:') === 0 || pictureUrl.indexOf('ms-appdata:') === 0 || pictureUrl.indexOf('assets-library:') === 0) {
if (pictureUrl.indexOf('file:') === 0 || pictureUrl.indexOf('content:') === 0) {
resolveLocalFileSystemURL(data, function (e) {
fileEntry = e;
logCallback('resolveLocalFileSystemURL()', true)(e.toURL());
@@ -167,26 +165,6 @@ exports.defineManualTests = function (contentEl, createActionButton) {
};
}
function uploadImage () {
var ft = new FileTransfer();
var options = new FileUploadOptions();
options.fileKey = 'photo';
options.fileName = 'test.jpg';
options.mimeType = 'image/jpeg';
ft.onprogress = function (progressEvent) {
console.log('progress: ' + progressEvent.loaded + ' of ' + progressEvent.total);
};
var server = 'http://sheltered-retreat-43956.herokuapp.com';
ft.upload(pictureUrl, server + '/upload', win, fail, options);
function win (information_back) {
log('upload complete');
}
function fail (message) {
log('upload failed: ' + JSON.stringify(message));
}
}
function logCallback (apiName, success) {
return function () {
log('Call to ' + apiName + (success ? ' success: ' : ' failed: ') + JSON.stringify([].slice.call(arguments)));
@@ -194,7 +172,7 @@ exports.defineManualTests = function (contentEl, createActionButton) {
}
/**
* Select image from library using a NATIVE_URI destination type
* Select image from library
* This calls FileEntry.getMetadata, FileEntry.setMetadata, FileEntry.getParent, FileEntry.file, and FileReader.readAsDataURL.
*/
function readFile () {
@@ -237,7 +215,7 @@ exports.defineManualTests = function (contentEl, createActionButton) {
}
/**
* Copy image from library using a NATIVE_URI destination type
* Copy image from library
* This calls FileEntry.copyTo and FileEntry.moveTo.
*/
function copyImage () {
@@ -271,7 +249,7 @@ exports.defineManualTests = function (contentEl, createActionButton) {
}
/**
* Write image to library using a NATIVE_URI destination type
* Write image to library
* This calls FileEntry.createWriter, FileWriter.write, and FileWriter.truncate.
*/
function writeImage () {
@@ -305,7 +283,7 @@ exports.defineManualTests = function (contentEl, createActionButton) {
}
/**
* Remove image from library using a NATIVE_URI destination type
* Remove image from library
* This calls FileEntry.remove.
*/
function removeImage () {
@@ -378,7 +356,7 @@ exports.defineManualTests = function (contentEl, createActionButton) {
var options = '';
if (typeof values === 'boolean') {
values = { 'true': 1, 'false': 0 };
values = { true: 1, false: 0 };
}
for (var k in values) {
var isSelected = '';
@@ -409,9 +387,9 @@ exports.defineManualTests = function (contentEl, createActionButton) {
createOptionsEl('destinationType', Camera.DestinationType, camDestinationTypeDefault) +
createOptionsEl('encodingType', Camera.EncodingType, camEncodingTypeDefault) +
createOptionsEl('mediaType', Camera.MediaType, camMediaTypeDefault) +
createOptionsEl('quality', { '0': 0, '50': 50, '80': 80, '100': 100 }, camQualityDefault) +
createOptionsEl('targetWidth', { '50': 50, '200': 200, '800': 800, '2048': 2048 }) +
createOptionsEl('targetHeight', { '50': 50, '200': 200, '800': 800, '2048': 2048 }) +
createOptionsEl('quality', { 0: 0, 50: 50, 80: 80, 100: 100 }, camQualityDefault) +
createOptionsEl('targetWidth', { 50: 50, 200: 200, 800: 800, 2048: 2048 }) +
createOptionsEl('targetHeight', { 50: 50, 200: 200, 800: 800, 2048: 2048 }) +
createOptionsEl('allowEdit', true, camAllowEditDefault) +
createOptionsEl('correctOrientation', true, camCorrectOrientationDefault) +
createOptionsEl('saveToPhotoAlbum', true, camSaveToPhotoAlbumDefault) +
@@ -498,10 +476,6 @@ exports.defineManualTests = function (contentEl, createActionButton) {
writeImage();
}, 'write');
createActionButton('Upload Image', function () {
uploadImage();
}, 'upload');
createActionButton('Draw Using Canvas', function () {
displayImageUsingCanvas();
}, 'draw_canvas');

3
types/index.d.ts vendored
View File

@@ -51,8 +51,6 @@ interface CameraOptions {
* Defined in navigator.camera.DestinationType. Default is FILE_URI.
* DATA_URL : 0, Return image as base64-encoded string
* FILE_URI : 1, Return image file URI
* NATIVE_URI : 2 Return image native URI
* (e.g., assets-library:// on iOS or content:// on Android)
*/
destinationType?: number;
/**
@@ -149,7 +147,6 @@ declare var Camera: {
DestinationType: {
DATA_URL: number;
FILE_URI: number;
NATIVE_URI: number
}
Direction: {
BACK: number;

View File

@@ -26,20 +26,14 @@ module.exports = {
/**
* @description
* Defines the output format of `Camera.getPicture` call.
* _Note:_ On iOS passing `DestinationType.NATIVE_URI` along with
* `PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SAVEDPHOTOALBUM` will
* disable any image modifications (resize, quality change, cropping, etc.) due
* to implementation specific.
*
* @enum {number}
*/
DestinationType: {
/** Return base64 encoded string. DATA_URL can be very memory intensive and cause app crashes or out of memory errors. Use FILE_URI or NATIVE_URI if possible */
/** Return base64 encoded string. DATA_URL can be very memory intensive and cause app crashes or out of memory errors. Use FILE_URI if possible */
DATA_URL: 0,
/** Return file uri (content://media/external/images/media/2 for Android) */
FILE_URI: 1,
/** Return native uri (eg. asset-library://... for iOS) */
NATIVE_URI: 2
FILE_URI: 1
},
/**
* @enum {number}
@@ -64,9 +58,6 @@ module.exports = {
/**
* @description
* Defines the output format of `Camera.getPicture` call.
* _Note:_ On iOS passing `PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SAVEDPHOTOALBUM`
* along with `DestinationType.NATIVE_URI` will disable any image modifications (resize, quality
* change, cropping, etc.) due to implementation specific.
*
* @enum {number}
*/

View File

@@ -58,7 +58,7 @@ var CameraPopoverHandle = function () {
* @param {module:CameraPopoverOptions} popoverOptions
*/
this.setPosition = function (popoverOptions) {
var args = [ popoverOptions ];
var args = [popoverOptions];
exec(null, null, 'Camera', 'repositionPopover', args);
};
};