Repository: cordova-plugin-camera Updated Branches: refs/heads/master e2193631d -> 1d32ea46f
CB-10319 android: Adding reflective helper methods for permission requests Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/repo Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/commit/1d32ea46 Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/tree/1d32ea46 Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/diff/1d32ea46 Branch: refs/heads/master Commit: 1d32ea46f0ebcbf5cbc3d8a255170bf7186533c8 Parents: e219363 Author: riknoll <richard.b.kn...@gmail.com> Authored: Mon Jan 4 15:22:35 2016 -0800 Committer: riknoll <richard.b.kn...@gmail.com> Committed: Tue Jan 12 17:42:29 2016 -0800 ---------------------------------------------------------------------- plugin.xml | 17 ++-- src/android/CameraLauncher.java | 14 +--- src/android/PermissionHelper.java | 138 +++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 20 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/1d32ea46/plugin.xml ---------------------------------------------------------------------- diff --git a/plugin.xml b/plugin.xml index 673761e..3df1e81 100644 --- a/plugin.xml +++ b/plugin.xml @@ -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 --> http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/1d32ea46/src/android/CameraLauncher.java ---------------------------------------------------------------------- diff --git a/src/android/CameraLauncher.java b/src/android/CameraLauncher.java index ff8599b..15e908f 100644 --- a/src/android/CameraLauncher.java +++ b/src/android/CameraLauncher.java @@ -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); } } http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/1d32ea46/src/android/PermissionHelper.java ---------------------------------------------------------------------- diff --git a/src/android/PermissionHelper.java b/src/android/PermissionHelper.java new file mode 100644 index 0000000..cf4247b --- /dev/null +++ b/src/android/PermissionHelper.java @@ -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); + } + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cordova.apache.org For additional commands, e-mail: commits-h...@cordova.apache.org