Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(camera): Request only the permissions needed by Android version #1713

Merged
merged 2 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions camera/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ This API requires the following permissions be added to your `AndroidManifest.xm
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
```

You can also specify those permissions only for the Android versions where they will be requested:

```xml
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29"/>
```

The storage permissions are for reading/saving photo files.

Read about [Setting Permissions](https://capacitorjs.com/docs/android/configuration#setting-permissions) in the [Android Guide](https://capacitorjs.com/docs/android) for more information on setting Android permissions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,19 @@
name = "Camera",
permissions = {
@Permission(strings = { Manifest.permission.CAMERA }, alias = CameraPlugin.CAMERA),
// SDK VERSIONS 32 AND BELOW
// SDK VERSIONS 29 AND BELOW
@Permission(
strings = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE },
alias = CameraPlugin.PHOTOS
),
/*
SDK VERSIONS 30-32
This alias is a placeholder and the PHOTOS alias will be updated to use this permission
so that the end user does not need to explicitly use separate aliases depending
on the SDK version.
*/
@Permission(strings = { Manifest.permission.READ_EXTERNAL_STORAGE }, alias = CameraPlugin.READ_EXTERNAL_STORAGE),
/*
SDK VERSIONS 33 AND ABOVE
This alias is a placeholder and the PHOTOS alias will be updated to use these permissions
so that the end user does not need to explicitly use separate aliases depending
Expand All @@ -82,6 +89,7 @@ public class CameraPlugin extends Plugin {
static final String CAMERA = "camera";
static final String PHOTOS = "photos";
static final String MEDIA = "media";
static final String READ_EXTERNAL_STORAGE = "readExternalStorage";

// Message constants
private static final String INVALID_RESULT_TYPE_ERROR = "Invalid resultType option";
Expand Down Expand Up @@ -206,11 +214,16 @@ else if (!hasCameraPerms) {
}

private boolean checkPhotosPermissions(PluginCall call) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
if (getPermissionState(PHOTOS) != PermissionState.GRANTED) {
requestPermissionForAlias(PHOTOS, call, "cameraPermissionsCallback");
return false;
}
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
if (getPermissionState(READ_EXTERNAL_STORAGE) != PermissionState.GRANTED) {
requestPermissionForAlias(READ_EXTERNAL_STORAGE, call, "cameraPermissionsCallback");
return false;
}
} else if (getPermissionState(MEDIA) != PermissionState.GRANTED) {
requestPermissionForAlias(MEDIA, call, "cameraPermissionsCallback");
return false;
Expand All @@ -235,9 +248,13 @@ private void cameraPermissionsCallback(PluginCall call) {
call.reject(PERMISSION_DENIED_ERROR_CAMERA);
return;
} else if (settings.getSource() == CameraSource.PHOTOS) {
PermissionState permissionState = (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
? getPermissionState(PHOTOS)
: getPermissionState(MEDIA);
String alias = MEDIA;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
alias = PHOTOS;
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
alias = READ_EXTERNAL_STORAGE;
}
PermissionState permissionState = getPermissionState(alias);
if (permissionState != PermissionState.GRANTED) {
Logger.debug(getLogTag(), "User denied photos permission: " + permissionState.toString());
call.reject(PERMISSION_DENIED_ERROR_PHOTOS);
Expand All @@ -257,6 +274,12 @@ protected void requestPermissionForAliases(@NonNull String[] aliases, @NonNull P
aliases[i] = MEDIA;
}
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
for (int i = 0; i < aliases.length; i++) {
if (aliases[i].equals(PHOTOS)) {
aliases[i] = READ_EXTERNAL_STORAGE;
}
}
}
super.requestPermissionForAliases(aliases, call, callbackName);
}
Expand Down Expand Up @@ -817,9 +840,15 @@ public Map<String, PermissionState> getPermissionStates() {
permissionStates.put(CAMERA, PermissionState.GRANTED);
}

// If the SDK version is 33 or higher, update the PHOTOS state to match the MEDIA state.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && permissionStates.containsKey(MEDIA)) {
permissionStates.put(PHOTOS, permissionStates.get(MEDIA));
// If the SDK version is 30 or higher, update the PHOTOS state to match the MEDIA or READ_EXTERNAL_STORAGE states.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
String alias = READ_EXTERNAL_STORAGE;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
alias = MEDIA;
}
if (permissionStates.containsKey(alias)) {
permissionStates.put(PHOTOS, permissionStates.get(alias));
}
}

return permissionStates;
Expand Down