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

feat(android): modified plugin annotation format for multi-permissions and empty (auto-grant) #3822

Merged
merged 6 commits into from
Nov 19, 2020
Merged
Show file tree
Hide file tree
Changes from 4 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
105 changes: 75 additions & 30 deletions android/capacitor/src/main/java/com/getcapacitor/Plugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.getcapacitor.annotation.Permission;
import com.getcapacitor.util.PermissionHelper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -188,8 +189,10 @@ public boolean hasDefinedPermissions(String[] permissions) {
*/
public boolean hasDefinedPermissions(Permission[] permissions) {
for (Permission perm : permissions) {
if (!PermissionHelper.hasDefinedPermission(getContext(), perm.permission())) {
return false;
for (String permString : perm.permission()) {
if (!PermissionHelper.hasDefinedPermission(getContext(), permString)) {
return false;
}
}
}
return true;
Expand Down Expand Up @@ -241,8 +244,10 @@ public boolean hasRequiredPermissions() {
}

for (Permission perm : annotation.permissions()) {
if (!hasPermission(perm.permission())) {
return false;
for (String permString : perm.permission()) {
if (!hasPermission(permString)) {
return false;
}
}
}

Expand Down Expand Up @@ -272,24 +277,40 @@ public JSObject getPermissionStates() {
JSObject permissionsResults = new JSObject();
CapacitorPlugin annotation = handle.getPluginAnnotation();
for (Permission perm : annotation.permissions()) {
String key = perm.alias().isEmpty() ? perm.permission() : perm.alias();
String permissionStatus = hasPermission(perm.permission()) ? "granted" : "prompt";

// Check if there is a cached permission state for the "Never ask again" state
if (permissionStatus.equals("prompt")) {
SharedPreferences prefs = getContext().getSharedPreferences(PERMISSION_PREFS, Activity.MODE_PRIVATE);
String state = prefs.getString(perm.permission(), null);

if (state != null) {
permissionStatus = state;
// If a permission is defined with no permission constants, return "granted" for it.
// Otherwise, get its true state.
if (perm.permission().length == 0 || (perm.permission().length == 1 && perm.permission()[0].isEmpty())) {
String key = perm.alias();
if (!key.isEmpty()) {
String existingResult = permissionsResults.getString(key);

// auto set permission state to granted if the alias is empty.
if (existingResult == null) {
permissionsResults.put(key, "granted");
}
}
}
} else {
for (String permString : perm.permission()) {
String key = perm.alias().isEmpty() ? permString : perm.alias();
String permissionStatus = hasPermission(permString) ? "granted" : "prompt";

// Check if there is a cached permission state for the "Never ask again" state
if (permissionStatus.equals("prompt")) {
SharedPreferences prefs = getContext().getSharedPreferences(PERMISSION_PREFS, Activity.MODE_PRIVATE);
String state = prefs.getString(permString, null);

if (state != null) {
permissionStatus = state;
}
}

String existingResult = permissionsResults.getString(key);
String existingResult = permissionsResults.getString(key);

// multiple permissions with the same alias must all be true, otherwise all false.
if (existingResult == null || existingResult.equals("granted")) {
permissionsResults.put(key, permissionStatus);
// multiple permissions with the same alias must all be true, otherwise all false.
if (existingResult == null || existingResult.equals("granted")) {
permissionsResults.put(key, permissionStatus);
}
}
}
}

Expand All @@ -316,12 +337,12 @@ public void pluginRequestAllPermissions() {
return;
}

String[] perms = new String[annotation.permissions().length];
for (int i = 0; i < perms.length; i++) {
perms[i] = annotation.permissions()[i].permission();
HashSet<String> perms = new HashSet<>();
for (Permission perm : annotation.permissions()) {
perms.addAll(Arrays.asList(perm.permission()));
}

ActivityCompat.requestPermissions(getActivity(), perms, annotation.permissionRequestCode());
ActivityCompat.requestPermissions(getActivity(), perms.toArray(new String[0]), annotation.permissionRequestCode());
}

/**
Expand Down Expand Up @@ -470,6 +491,7 @@ public void removeAllListeners(PluginCall call) {
@PluginMethod
public void requestPermissions(PluginCall call) {
String[] perms = null;
Set<String> autoGrantPerms = new HashSet<>();
int permissionRequestCode;

// If call was made with a list of permissions to request, save them to be requested
Expand All @@ -489,15 +511,27 @@ public void requestPermissions(PluginCall call) {
} else {
// If call was made without any custom permissions, request all from plugin annotation
if (providedPermsList == null || providedPermsList.isEmpty()) {
perms = new String[annotation.permissions().length];
for (int i = 0; i < perms.length; i++) {
perms[i] = annotation.permissions()[i].permission();
HashSet<String> permsSet = new HashSet<>();
for (Permission perm : annotation.permissions()) {
// If a permission is defined with no permission constants, separate it for auto-granting.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still confused as to why this part is necessary: (perm.permission().length == 1 && perm.permission()[0].isEmpty())

It is handling this case?

@Permission(permission = {""}, alias = ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes or this valid definition

@Permission(permission = "", alias = ...

which on the back end translates to an array containing one empty element

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's switch to Kotlin.

// Otherwise, it is added to the list to be requested.
if (perm.permission().length == 0 || (perm.permission().length == 1 && perm.permission()[0].isEmpty())) {
carlpoole marked this conversation as resolved.
Show resolved Hide resolved
if (!perm.alias().isEmpty()) {
autoGrantPerms.add(perm.alias());
}
} else {
permsSet.addAll(Arrays.asList(perm.permission()));
}
}

perms = permsSet.toArray(new String[0]);
} else {
Set<String> permsSet = new HashSet<>();
for (Permission perm : annotation.permissions()) {
if (providedPermsList.contains(perm.alias()) || providedPermsList.contains(perm.permission())) {
permsSet.add(perm.permission());
for (String permString : perm.permission()) {
if (providedPermsList.contains(perm.alias()) || providedPermsList.contains(permString)) {
permsSet.add(permString);
}
}
}

Expand All @@ -517,7 +551,18 @@ public void requestPermissions(PluginCall call) {

pluginRequestPermissions(perms, permissionRequestCode);
} else {
call.resolve();
// if the plugin only has auto-grant permissions, return those
if (!autoGrantPerms.isEmpty()) {
JSObject permissionsResults = new JSObject();

for (String perm : autoGrantPerms) {
permissionsResults.put(perm, "granted");
}

call.resolve(permissionsResults);
} else {
call.resolve();
}
}
}

Expand Down Expand Up @@ -578,7 +623,7 @@ protected void onRequestPermissionsResult(int requestCode, String[] permissions,
* @param grantResults
* @return true if permissions were saved and defined correctly, false if not
*/
public boolean validatePermissions(String[] permissions, int[] grantResults) {
protected boolean validatePermissions(String[] permissions, int[] grantResults) {
SharedPreferences prefs = getContext().getSharedPreferences(PERMISSION_PREFS, Activity.MODE_PRIVATE);

if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
@Retention(RetentionPolicy.RUNTIME)
public @interface Permission {
/**
* The Android string for the permission.
* Eg: Manifest.permission.ACCESS_COARSE_LOCATION
* or "android.permission.ACCESS_COARSE_LOCATION"
* An array of Android permission strings.
* Eg: {Manifest.permission.ACCESS_COARSE_LOCATION}
* or {"android.permission.ACCESS_COARSE_LOCATION"}
*/
String permission() default "";
String[] permission() default {};
carlpoole marked this conversation as resolved.
Show resolved Hide resolved

/**
* An optional name to use instead of the Android permission string.
Expand Down