Skip to content

Commit

Permalink
refactor(android): Rework permission management to make WRITE_EXTERNA…
Browse files Browse the repository at this point in the history
…L_STORAGE optional
  • Loading branch information
breautek committed Oct 28, 2024
1 parent 7d159cf commit b497214
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 37 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,16 @@ quality, even if a `quality` parameter is specified. To avoid common
memory problems, set `Camera.destinationType` to `FILE_URI` rather
than `DATA_URL`.

__NOTE__: To use `saveToPhotoAlbum` option on Android 9 (API 28) and lower, the `WRITE_EXTERNAL_STORAGE` permission must be declared.

To do this, add the following in your `config.xml`:

```xml
<config-file target="AndroidManifest.xml" parent="/*" xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
</config-file>
```

#### FILE_URI Usage

When `FILE_URI` is used, the returned path is not directly usable. The file path needs to be resolved into
Expand All @@ -198,6 +208,8 @@ For use cases that involve temporary use, it is valid and safe to use the tempor

__NOTE__: The returned schemes is an implementation detail. Do not assume that it will always be a `file://` URI.

Android 10 (API 29) and later devices does not require `WRITE_EXTERNAL_STORAGE` permission. If your application only supports Android 10 or later, then this step is not necessary.

__Supported Platforms__

- Android
Expand Down Expand Up @@ -301,7 +313,7 @@ Optional parameters to customize the camera settings.
| targetHeight | <code>number</code> | | Height in pixels to scale image. Must be used with `targetWidth`. Aspect ratio remains constant. |
| mediaType | <code>[MediaType](#module_Camera.MediaType)</code> | <code>PICTURE</code> | Set the type of media to select from. Only works when `PictureSourceType` is `PHOTOLIBRARY` or `SAVEDPHOTOALBUM`. |
| correctOrientation | <code>Boolean</code> | | Rotate the image to correct for the orientation of the device during capture. |
| saveToPhotoAlbum | <code>Boolean</code> | | Save the image to the photo album on the device after capture. |
| saveToPhotoAlbum | <code>Boolean</code> | | Save the image to the photo album on the device after capture.<br />See [Android Quirks](#cameragetpicturesuccesscallback-errorcallback-options). |
| popoverOptions | <code>[CameraPopoverOptions](#module_CameraPopoverOptions)</code> | | iOS-only options that specify popover location in iPad. |
| cameraDirection | <code>[Direction](#module_Camera.Direction)</code> | <code>BACK</code> | Choose the camera to use (front- or back-facing). |

Expand Down
77 changes: 41 additions & 36 deletions src/android/CameraLauncher.java
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
this.callTakePicture(destType, encodingType);
}
else if ((this.srcType == PHOTOLIBRARY) || (this.srcType == SAVEDPHOTOALBUM)) {
// FIXME: Stop always requesting the permission
String[] permissions = getPermissions(true, mediaType);
if(!hasPermissions(permissions)) {
PermissionHelper.requestPermissions(this, SAVE_TO_ALBUM_SEC, permissions);
} else {
this.getImage(this.srcType, destType);
}
this.getImage(this.srcType, destType);
}
}
catch (IllegalArgumentException e)
Expand Down Expand Up @@ -261,46 +255,57 @@ private String getTempDirectoryPath() {
* @param encodingType Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
*/
public void callTakePicture(int returnType, int encodingType) {
String[] storagePermissions = getPermissions(true, mediaType);
boolean saveAlbumPermission;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
saveAlbumPermission = this.saveToPhotoAlbum ? hasPermissions(storagePermissions) : true;
} else {
saveAlbumPermission = hasPermissions(storagePermissions);
}
boolean takePicturePermission = PermissionHelper.hasPermission(this, Manifest.permission.CAMERA);

// CB-10120: The CAMERA permission does not need to be requested unless it is declared
// in AndroidManifest.xml. This plugin does not declare it, but others may and so we must
// check the package info to determine if the permission is present.
boolean manifestContainsCameraPermission = false;

if (!takePicturePermission) {
takePicturePermission = true;
try {
PackageManager packageManager = this.cordova.getActivity().getPackageManager();
String[] permissionsInPackage = packageManager.getPackageInfo(this.cordova.getActivity().getPackageName(), PackageManager.GET_PERMISSIONS).requestedPermissions;
if (permissionsInPackage != null) {
for (String permission : permissionsInPackage) {
if (permission.equals(Manifest.permission.CAMERA)) {
takePicturePermission = false;
break;
}
// write permission is not necessary, unless if we are saving to photo album
// On API 29+ devices, write permission is completely obsolete and not required.
boolean manifestContainsWriteExternalPermission = false;

boolean cameraPermissionGranted = PermissionHelper.hasPermission(this, Manifest.permission.CAMERA);
boolean writeExternalPermissionGranted = false;
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
writeExternalPermissionGranted = PermissionHelper.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
else {
writeExternalPermissionGranted = true;
}

try {
PackageManager packageManager = this.cordova.getActivity().getPackageManager();
String[] permissionsInPackage = packageManager.getPackageInfo(this.cordova.getActivity().getPackageName(), PackageManager.GET_PERMISSIONS).requestedPermissions;
if (permissionsInPackage != null) {
for (String permission : permissionsInPackage) {
if (permission.equals(Manifest.permission.CAMERA)) {
manifestContainsCameraPermission = true;
}
else if (permission.equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
manifestContainsWriteExternalPermission = true;
}
}
} catch (NameNotFoundException e) {
// We are requesting the info for our package, so this should
// never be caught
}
} catch (NameNotFoundException e) {
// We are requesting the info for our package, so this should
// never be caught
}

ArrayList<String> requiredPermissions = new ArrayList<>();
if (manifestContainsCameraPermission && !cameraPermissionGranted) {
requiredPermissions.add(Manifest.permission.CAMERA);
}

if (takePicturePermission && saveAlbumPermission) {
if (saveToPhotoAlbum && !writeExternalPermissionGranted) {
requiredPermissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}

if (!requiredPermissions.isEmpty()) {
PermissionHelper.requestPermissions(this, TAKE_PIC_SEC, requiredPermissions.toArray(new String[0]));
}
else {
takePicture(returnType, encodingType);
} else if (saveAlbumPermission) {
PermissionHelper.requestPermission(this, TAKE_PIC_SEC, Manifest.permission.CAMERA);
} else if (takePicturePermission) {
PermissionHelper.requestPermissions(this, TAKE_PIC_SEC, storagePermissions);
} else {
PermissionHelper.requestPermissions(this, TAKE_PIC_SEC, getPermissions(false, mediaType));
}
}

Expand Down

0 comments on commit b497214

Please sign in to comment.