mirror of
https://github.com/apache/cordova-plugin-camera.git
synced 2026-02-14 00:04:54 +08:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f32b78c82 | ||
|
|
eb009471ab | ||
|
|
1d32ea46f0 | ||
|
|
e2193631d5 | ||
|
|
e8fa1695c4 | ||
|
|
e1911a3c78 | ||
|
|
ef5484a2aa |
1
.ratignore
Normal file
1
.ratignore
Normal file
@@ -0,0 +1 @@
|
||||
TEMPLATE.md
|
||||
@@ -400,7 +400,12 @@ scenario, the image may not appear when the cordova activity is restored.
|
||||
|
||||
Android uses intents to launch the camera activity on the device to capture
|
||||
images, and on phones with low memory, the Cordova activity may be killed. In this
|
||||
scenario, the image may not appear when the Cordova activity is restored.
|
||||
scenario, the result from the plugin call will be delivered via the resume event.
|
||||
See [the Android Lifecycle guide](http://cordova.apache.org/docs/en/dev/guide/platforms/android/lifecycle.html)
|
||||
for more information. The `pendingResult.result` value will contain the value that
|
||||
would be passed to the callbacks (either the URI/URL or an error message). Check
|
||||
the `pendingResult.pluginStatus` to determine whether or not the call was
|
||||
successful.
|
||||
|
||||
#### Browser Quirks
|
||||
|
||||
|
||||
@@ -20,6 +20,13 @@
|
||||
-->
|
||||
# Release Notes
|
||||
|
||||
### 2.1.0 (Jan 15, 2016)
|
||||
* added `.ratignore`
|
||||
* CB-10319 **Android** Adding reflective helper methods for permission requests
|
||||
* CB-9189 **Android** Implementing `save/restore` API to handle Activity destruction
|
||||
* CB-10241 App Crash cause by Camera Plugin **iOS 7**
|
||||
* CB-8940 Setting `z-index` values to maximum for UI buttons.
|
||||
|
||||
### 2.0.0 (Nov 18, 2015)
|
||||
* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) Updated `RELEASENOTES` to be newest to oldest
|
||||
* [CB-8863](https://issues.apache.org/jira/browse/CB-8863) correct block usage for `async` calls
|
||||
|
||||
@@ -77,7 +77,12 @@ scenario, the image may not appear when the cordova activity is restored.
|
||||
|
||||
Android uses intents to launch the camera activity on the device to capture
|
||||
images, and on phones with low memory, the Cordova activity may be killed. In this
|
||||
scenario, the image may not appear when the Cordova activity is restored.
|
||||
scenario, the result from the plugin call will be delivered via the resume event.
|
||||
See [the Android Lifecycle guide](http://cordova.apache.org/docs/en/dev/guide/platforms/android/lifecycle.html)
|
||||
for more information. The `pendingResult.result` value will contain the value that
|
||||
would be passed to the callbacks (either the URI/URL or an error message). Check
|
||||
the `pendingResult.pluginStatus` to determine whether or not the call was
|
||||
successful.
|
||||
|
||||
#### Browser Quirks
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cordova-plugin-camera",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.0",
|
||||
"description": "Cordova Camera Plugin",
|
||||
"cordova": {
|
||||
"id": "cordova-plugin-camera",
|
||||
|
||||
19
plugin.xml
19
plugin.xml
@@ -22,7 +22,7 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:rim="http://www.blackberry.com/ns/widgets"
|
||||
id="cordova-plugin-camera"
|
||||
version="2.0.0">
|
||||
version="2.1.0">
|
||||
<name>Camera</name>
|
||||
<description>Cordova Camera Plugin</description>
|
||||
<license>Apache 2.0</license>
|
||||
@@ -30,10 +30,6 @@
|
||||
<repo>https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera.git</repo>
|
||||
<issue>https://issues.apache.org/jira/browse/CB/component/12320645</issue>
|
||||
|
||||
<engines>
|
||||
<engine name="cordova-android" version=">=5.0.0-dev" />
|
||||
</engines>
|
||||
|
||||
<js-module src="www/CameraConstants.js" name="Camera">
|
||||
<clobbers target="Camera" />
|
||||
</js-module>
|
||||
@@ -54,12 +50,12 @@
|
||||
<feature name="Camera">
|
||||
<param name="firefoxos-package" value="Camera" />
|
||||
</feature>
|
||||
</config-file>
|
||||
|
||||
</config-file>
|
||||
|
||||
<js-module src="src/firefoxos/CameraProxy.js" name="CameraProxy">
|
||||
<runs />
|
||||
</js-module>
|
||||
</platform>
|
||||
</platform>
|
||||
|
||||
<!-- android -->
|
||||
<platform name="android">
|
||||
@@ -75,6 +71,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" />
|
||||
<source-file src="src/android/PermissionHelper.java" target-dir="src/org/apache/cordova/camera" />
|
||||
|
||||
<js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
|
||||
<clobbers target="CameraPopoverHandle" />
|
||||
@@ -102,7 +99,7 @@
|
||||
</js-module>
|
||||
|
||||
</platform>
|
||||
|
||||
|
||||
<!-- ubuntu -->
|
||||
<platform name="ubuntu">
|
||||
<config-file target="config.xml" parent="/*">
|
||||
@@ -151,11 +148,11 @@
|
||||
<framework src="MobileCoreServices.framework" />
|
||||
<framework src="CoreGraphics.framework" />
|
||||
<framework src="AVFoundation.framework" />
|
||||
|
||||
|
||||
<config-file target="*-Info.plist" parent="NSLocationWhenInUseUsageDescription">
|
||||
<string></string>
|
||||
</config-file>
|
||||
|
||||
|
||||
</platform>
|
||||
|
||||
<!-- blackberry10 -->
|
||||
|
||||
@@ -114,12 +114,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
||||
private Uri scanMe; // Uri of image to be added to content store
|
||||
private Uri croppedUri;
|
||||
|
||||
|
||||
protected void getReadPermission(int requestCode)
|
||||
{
|
||||
cordova.requestPermission(this, requestCode, Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
@@ -178,8 +172,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
||||
// preserve the original exif data and filename in the modified file that is
|
||||
// created
|
||||
if(this.mediaType == PICTURE && (this.destType == FILE_URI || this.destType == NATIVE_URI)
|
||||
&& fileWillBeModified() && !cordova.hasPermission(permissions[0])) {
|
||||
getReadPermission(SAVE_TO_ALBUM_SEC);
|
||||
&& fileWillBeModified() && !PermissionHelper.hasPermission(this, permissions[0])) {
|
||||
PermissionHelper.requestPermission(this, SAVE_TO_ALBUM_SEC, Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
} else {
|
||||
this.getImage(this.srcType, destType, encodingType);
|
||||
}
|
||||
@@ -238,10 +232,10 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
||||
* @param returnType Set the type of image to return.
|
||||
*/
|
||||
public void callTakePicture(int returnType, int encodingType) {
|
||||
if (cordova.hasPermission(permissions[0])) {
|
||||
if (PermissionHelper.hasPermission(this, permissions[0])) {
|
||||
takePicture(returnType, encodingType);
|
||||
} else {
|
||||
getReadPermission(TAKE_PIC_SEC);
|
||||
PermissionHelper.requestPermission(this, TAKE_PIC_SEC, Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,7 +497,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
||||
} else {
|
||||
writeUncompressedImage(this.imageUri, uri);
|
||||
}
|
||||
|
||||
|
||||
this.callbackContext.success(uri.toString());
|
||||
}
|
||||
} else {
|
||||
@@ -1214,4 +1208,58 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
|
||||
return (this.targetWidth > 0 && this.targetHeight > 0) ||
|
||||
this.correctOrientation || this.allowEdit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Taking or choosing a picture launches another Activity, so we need to implement the
|
||||
* save/restore APIs to handle the case where the CordovaActivity is killed by the OS
|
||||
* before we get the launched Activity's result.
|
||||
*/
|
||||
public Bundle onSaveInstanceState() {
|
||||
Bundle state = new Bundle();
|
||||
state.putInt("destType", this.destType);
|
||||
state.putInt("srcType", this.srcType);
|
||||
state.putInt("mQuality", this.mQuality);
|
||||
state.putInt("targetWidth", this.targetWidth);
|
||||
state.putInt("targetHeight", this.targetHeight);
|
||||
state.putInt("encodingType", this.encodingType);
|
||||
state.putInt("mediaType", this.mediaType);
|
||||
state.putInt("numPics", this.numPics);
|
||||
state.putBoolean("allowEdit", this.allowEdit);
|
||||
state.putBoolean("correctOrientation", this.correctOrientation);
|
||||
state.putBoolean("saveToPhotoAlbum", this.saveToPhotoAlbum);
|
||||
|
||||
if(this.croppedUri != null) {
|
||||
state.putString("croppedUri", this.croppedUri.toString());
|
||||
}
|
||||
|
||||
if(this.imageUri != null) {
|
||||
state.putString("imageUri", this.imageUri.toString());
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
public void onRestoreStateForActivityResult(Bundle state, CallbackContext callbackContext) {
|
||||
this.destType = state.getInt("destType");
|
||||
this.srcType = state.getInt("srcType");
|
||||
this.mQuality = state.getInt("mQuality");
|
||||
this.targetWidth = state.getInt("targetWidth");
|
||||
this.targetHeight = state.getInt("targetHeight");
|
||||
this.encodingType = state.getInt("encodingType");
|
||||
this.mediaType = state.getInt("mediaType");
|
||||
this.numPics = state.getInt("numPics");
|
||||
this.allowEdit = state.getBoolean("allowEdit");
|
||||
this.correctOrientation = state.getBoolean("correctOrientation");
|
||||
this.saveToPhotoAlbum = state.getBoolean("saveToPhotoAlbum");
|
||||
|
||||
if(state.containsKey("croppedUri")) {
|
||||
this.croppedUri = Uri.parse(state.getString("croppedUri"));
|
||||
}
|
||||
|
||||
if(state.containsKey("imageUri")) {
|
||||
this.imageUri = Uri.parse(state.getString("imageUri"));
|
||||
}
|
||||
|
||||
this.callbackContext = callbackContext;
|
||||
}
|
||||
}
|
||||
|
||||
138
src/android/PermissionHelper.java
Normal file
138
src/android/PermissionHelper.java
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
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.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.cordova.CordovaInterface;
|
||||
import org.apache.cordova.CordovaPlugin;
|
||||
import org.apache.cordova.LOG;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
/**
|
||||
* This class provides reflective methods for permission requesting and checking so that plugins
|
||||
* written for cordova-android 5.0.0+ can still compile with earlier cordova-android versions.
|
||||
*/
|
||||
public class PermissionHelper {
|
||||
private static final String LOG_TAG = "CordovaPermissionHelper";
|
||||
|
||||
/**
|
||||
* Requests a "dangerous" permission for the application at runtime. This is a helper method
|
||||
* alternative to cordovaInterface.requestPermission() that does not require the project to be
|
||||
* built with cordova-android 5.0.0+
|
||||
*
|
||||
* @param plugin The plugin the permission is being requested for
|
||||
* @param requestCode A requestCode to be passed to the plugin's onRequestPermissionResult()
|
||||
* along with the result of the permission request
|
||||
* @param permission The permission to be requested
|
||||
*/
|
||||
public static void requestPermission(CordovaPlugin plugin, int requestCode, String permission) {
|
||||
PermissionHelper.requestPermissions(plugin, requestCode, new String[] {permission});
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests "dangerous" permissions for the application at runtime. This is a helper method
|
||||
* alternative to cordovaInterface.requestPermissions() that does not require the project to be
|
||||
* built with cordova-android 5.0.0+
|
||||
*
|
||||
* @param plugin The plugin the permissions are being requested for
|
||||
* @param requestCode A requestCode to be passed to the plugin's onRequestPermissionResult()
|
||||
* along with the result of the permissions request
|
||||
* @param permissions The permissions to be requested
|
||||
*/
|
||||
public static void requestPermissions(CordovaPlugin plugin, int requestCode, String[] permissions) {
|
||||
try {
|
||||
Method requestPermission = CordovaInterface.class.getDeclaredMethod(
|
||||
"requestPermissions", CordovaPlugin.class, int.class, String[].class);
|
||||
|
||||
// If there is no exception, then this is cordova-android 5.0.0+
|
||||
requestPermission.invoke(plugin.cordova, plugin, requestCode, permissions);
|
||||
} catch (NoSuchMethodException noSuchMethodException) {
|
||||
// cordova-android version is less than 5.0.0, so permission is implicitly granted
|
||||
LOG.d(LOG_TAG, "No need to request permissions " + Arrays.toString(permissions));
|
||||
|
||||
// Notify the plugin that all were granted by using more reflection
|
||||
deliverPermissionResult(plugin, requestCode, permissions);
|
||||
} catch (IllegalAccessException illegalAccessException) {
|
||||
// Should never be caught; this is a public method
|
||||
LOG.e(LOG_TAG, "IllegalAccessException when requesting permissions " + Arrays.toString(permissions), illegalAccessException);
|
||||
} catch(InvocationTargetException invocationTargetException) {
|
||||
// This method does not throw any exceptions, so this should never be caught
|
||||
LOG.e(LOG_TAG, "invocationTargetException when requesting permissions " + Arrays.toString(permissions), invocationTargetException);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks at runtime to see if the application has been granted a permission. This is a helper
|
||||
* method alternative to cordovaInterface.hasPermission() that does not require the project to
|
||||
* be built with cordova-android 5.0.0+
|
||||
*
|
||||
* @param plugin The plugin the permission is being checked against
|
||||
* @param permission The permission to be checked
|
||||
*
|
||||
* @return True if the permission has already been granted and false otherwise
|
||||
*/
|
||||
public static boolean hasPermission(CordovaPlugin plugin, String permission) {
|
||||
try {
|
||||
Method hasPermission = CordovaInterface.class.getDeclaredMethod("hasPermission", String.class);
|
||||
|
||||
// If there is no exception, then this is cordova-android 5.0.0+
|
||||
return (Boolean) hasPermission.invoke(plugin.cordova, permission);
|
||||
} catch (NoSuchMethodException noSuchMethodException) {
|
||||
// cordova-android version is less than 5.0.0, so permission is implicitly granted
|
||||
LOG.d(LOG_TAG, "No need to check for permission " + permission);
|
||||
return true;
|
||||
} catch (IllegalAccessException illegalAccessException) {
|
||||
// Should never be caught; this is a public method
|
||||
LOG.e(LOG_TAG, "IllegalAccessException when checking permission " + permission, illegalAccessException);
|
||||
} catch(InvocationTargetException invocationTargetException) {
|
||||
// This method does not throw any exceptions, so this should never be caught
|
||||
LOG.e(LOG_TAG, "invocationTargetException when checking permission " + permission, invocationTargetException);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void deliverPermissionResult(CordovaPlugin plugin, int requestCode, String[] permissions) {
|
||||
// Generate the request results
|
||||
int[] requestResults = new int[permissions.length];
|
||||
Arrays.fill(requestResults, PackageManager.PERMISSION_GRANTED);
|
||||
|
||||
try {
|
||||
Method onRequestPermissionResult = CordovaPlugin.class.getDeclaredMethod(
|
||||
"onRequestPermissionResult", int.class, String[].class, int[].class);
|
||||
|
||||
onRequestPermissionResult.invoke(plugin, requestCode, permissions, requestResults);
|
||||
} catch (NoSuchMethodException noSuchMethodException) {
|
||||
// Should never be caught since the plugin must be written for cordova-android 5.0.0+ if it
|
||||
// made it to this point
|
||||
LOG.e(LOG_TAG, "NoSuchMethodException when delivering permissions results", noSuchMethodException);
|
||||
} catch (IllegalAccessException illegalAccessException) {
|
||||
// Should never be caught; this is a public method
|
||||
LOG.e(LOG_TAG, "IllegalAccessException when delivering permissions results", illegalAccessException);
|
||||
} catch(InvocationTargetException invocationTargetException) {
|
||||
// This method may throw a JSONException. We are just duplicating cordova-android's
|
||||
// exception handling behavior here; all it does is log the exception in CordovaActivity,
|
||||
// print the stacktrace, and ignore it
|
||||
LOG.e(LOG_TAG, "InvocationTargetException when delivering permissions results", invocationTargetException);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,9 +163,12 @@ static NSString* toBase64(NSData* data) {
|
||||
if (authStatus == AVAuthorizationStatusDenied ||
|
||||
authStatus == AVAuthorizationStatusRestricted) {
|
||||
// If iOS 8+, offer a link to the Settings app
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
|
||||
NSString* settingsButton = (&UIApplicationOpenSettingsURLString != NULL)
|
||||
? NSLocalizedString(@"Settings", nil)
|
||||
: nil;
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
// Denied; show an alert
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
@@ -216,7 +219,12 @@ static NSString* toBase64(NSData* data) {
|
||||
{
|
||||
// If Settings button (on iOS 8), open the settings app
|
||||
if (buttonIndex == 1) {
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
|
||||
if (&UIApplicationOpenSettingsURLString != NULL) {
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
// Dismiss the view
|
||||
|
||||
@@ -73,6 +73,9 @@ var windowsPhoneVideoContainers = [".avi", ".3gp", ".3g2", ".wmv", ".3gp", ".3g
|
||||
// Default aspect ratio 1.78 (16:9 hd video standard)
|
||||
var DEFAULT_ASPECT_RATIO = '1.8';
|
||||
|
||||
// Highest possible z-index supported across browsers. Anything used above is converted to this value.
|
||||
var HIGHEST_POSSIBLE_Z_INDEX = 2147483647;
|
||||
|
||||
// Resize method
|
||||
function resizeImage(successCallback, errorCallback, file, targetWidth, targetHeight, encodingType) {
|
||||
var tempPhotoFileName = "";
|
||||
@@ -329,18 +332,18 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
|
||||
// Create fullscreen preview
|
||||
// z-order style element for capturePreview and cameraCancelButton elts
|
||||
// is necessary to avoid overriding by another page elements, -1 sometimes is not enough
|
||||
capturePreview = document.createElement("video");
|
||||
capturePreview.style.cssText = "position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 999;";
|
||||
capturePreview = document.createElement("video");
|
||||
capturePreview.style.cssText = "position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: " + (HIGHEST_POSSIBLE_Z_INDEX - 1) + ";";
|
||||
|
||||
// Create capture button
|
||||
cameraCaptureButton = document.createElement("button");
|
||||
cameraCaptureButton.innerText = "Take";
|
||||
cameraCaptureButton.style.cssText = buttonStyle + "position: fixed; left: 0; bottom: 0; margin: 20px; z-index: 1000";
|
||||
cameraCaptureButton.style.cssText = buttonStyle + "position: fixed; left: 0; bottom: 0; margin: 20px; z-index: " + HIGHEST_POSSIBLE_Z_INDEX + ";";
|
||||
|
||||
// Create cancel button
|
||||
cameraCancelButton = document.createElement("button");
|
||||
cameraCancelButton.innerText = "Cancel";
|
||||
cameraCancelButton.style.cssText = buttonStyle + "position: fixed; right: 0; bottom: 0; margin: 20px; z-index: 1000";
|
||||
cameraCancelButton.style.cssText = buttonStyle + "position: fixed; right: 0; bottom: 0; margin: 20px; z-index: " + HIGHEST_POSSIBLE_Z_INDEX + ";";
|
||||
|
||||
capture = new CaptureNS.MediaCapture();
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:rim="http://www.blackberry.com/ns/widgets"
|
||||
id="cordova-plugin-camera-tests"
|
||||
version="2.0.0">
|
||||
version="2.1.0">
|
||||
<name>Cordova Camera Plugin Tests</name>
|
||||
<license>Apache 2.0</license>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user