Commit 78604e7f by Jeroen Weener Committed by GitHub

Enhancement/split bind call redirection service permission (#1157)

* Remove `BIND_CALL_REDIRECTION_SERVICE` permission from `PERMISSION_GROUP_PHONE`

* Remove `BIND_CALL_REDIRECTION_SERVICE` permission from manifest

* Combine all permission results instead of returning the first

* Update changelog and version

* Update CHANGELOG and version
parent a021685f
## 11.0.2
* Fixes a bug where `Permission.Phone` would always return 'denied' when requesting the permission status.
* Fixes a bug where Flutter permissions that require multiple Android permissions would base their status on the status of the first Android permission, as opposed to the result of all relevant Android permissions.
## 11.0.1 ## 11.0.1
* Fixes `java.lang.IllegalStateException: Reply already submitted` when requesting post notification permission. * Fixes `java.lang.IllegalStateException: Reply already submitted` when requesting post notification permission.
......
...@@ -2,8 +2,10 @@ package com.baseflow.permissionhandler; ...@@ -2,8 +2,10 @@ package com.baseflow.permissionhandler;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
final class PermissionConstants { final class PermissionConstants {
static final String LOG_TAG = "permissions_handler"; static final String LOG_TAG = "permissions_handler";
...@@ -99,6 +101,7 @@ final class PermissionConstants { ...@@ -99,6 +101,7 @@ final class PermissionConstants {
static final int PERMISSION_STATUS_LIMITED = 3; static final int PERMISSION_STATUS_LIMITED = 3;
static final int PERMISSION_STATUS_NEVER_ASK_AGAIN = 4; static final int PERMISSION_STATUS_NEVER_ASK_AGAIN = 4;
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef({ @IntDef({
PERMISSION_STATUS_DENIED, PERMISSION_STATUS_DENIED,
......
package com.baseflow.permissionhandler; package com.baseflow.permissionhandler;
import static com.baseflow.permissionhandler.PermissionUtils.strictestStatus;
import android.Manifest; import android.Manifest;
import android.app.Activity; import android.app.Activity;
import android.app.AlarmManager; import android.app.AlarmManager;
...@@ -23,8 +25,10 @@ import androidx.core.content.ContextCompat; ...@@ -23,8 +25,10 @@ import androidx.core.content.ContextCompat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import io.flutter.plugin.common.PluginRegistry; import io.flutter.plugin.common.PluginRegistry;
...@@ -177,7 +181,12 @@ final class PermissionManager implements PluginRegistry.ActivityResultListener, ...@@ -177,7 +181,12 @@ final class PermissionManager implements PluginRegistry.ActivityResultListener,
final int result = grantResults[i]; final int result = grantResults[i];
if (permission == PermissionConstants.PERMISSION_GROUP_MICROPHONE) { if (permission == PermissionConstants.PERMISSION_GROUP_PHONE) {
@Nullable @PermissionConstants.PermissionStatus Integer previousResult = requestResults.get(PermissionConstants.PERMISSION_GROUP_PHONE);
@PermissionConstants.PermissionStatus int newResult = PermissionUtils.toPermissionStatus(this.activity, permissionName, result);
@Nullable @PermissionConstants.PermissionStatus Integer strictestStatus = strictestStatus(previousResult, newResult);
requestResults.put(PermissionConstants.PERMISSION_GROUP_PHONE, strictestStatus);
} else if (permission == PermissionConstants.PERMISSION_GROUP_MICROPHONE) {
if (!requestResults.containsKey(PermissionConstants.PERMISSION_GROUP_MICROPHONE)) { if (!requestResults.containsKey(PermissionConstants.PERMISSION_GROUP_MICROPHONE)) {
requestResults.put( requestResults.put(
PermissionConstants.PERMISSION_GROUP_MICROPHONE, PermissionConstants.PERMISSION_GROUP_MICROPHONE,
...@@ -451,6 +460,7 @@ final class PermissionManager implements PluginRegistry.ActivityResultListener, ...@@ -451,6 +460,7 @@ final class PermissionManager implements PluginRegistry.ActivityResultListener,
final boolean targetsMOrHigher = context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.M; final boolean targetsMOrHigher = context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.M;
Set<@PermissionConstants.PermissionStatus Integer> permissionStatuses = new HashSet<>();
for (String name : names) { for (String name : names) {
// Only handle them if the client app actually targets a API level greater than M. // Only handle them if the client app actually targets a API level greater than M.
if (targetsMOrHigher) { if (targetsMOrHigher) {
...@@ -460,67 +470,76 @@ final class PermissionManager implements PluginRegistry.ActivityResultListener, ...@@ -460,67 +470,76 @@ final class PermissionManager implements PluginRegistry.ActivityResultListener,
// PowerManager.isIgnoringBatteryOptimizations has been included in Android M first. // PowerManager.isIgnoringBatteryOptimizations has been included in Android M first.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (pm != null && pm.isIgnoringBatteryOptimizations(packageName)) { if (pm != null && pm.isIgnoringBatteryOptimizations(packageName)) {
return PermissionConstants.PERMISSION_STATUS_GRANTED; permissionStatuses.add(PermissionConstants.PERMISSION_STATUS_GRANTED);
} else { } else {
return PermissionConstants.PERMISSION_STATUS_DENIED; permissionStatuses.add(PermissionConstants.PERMISSION_STATUS_DENIED);
} }
} else { } else {
return PermissionConstants.PERMISSION_STATUS_RESTRICTED; permissionStatuses.add(PermissionConstants.PERMISSION_STATUS_RESTRICTED);
} }
} }
if (permission == PermissionConstants.PERMISSION_GROUP_MANAGE_EXTERNAL_STORAGE) { if (permission == PermissionConstants.PERMISSION_GROUP_MANAGE_EXTERNAL_STORAGE) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
return PermissionConstants.PERMISSION_STATUS_RESTRICTED; permissionStatuses.add(PermissionConstants.PERMISSION_STATUS_RESTRICTED);
} }
return Environment.isExternalStorageManager() int status = Environment.isExternalStorageManager()
? PermissionConstants.PERMISSION_STATUS_GRANTED ? PermissionConstants.PERMISSION_STATUS_GRANTED
: PermissionConstants.PERMISSION_STATUS_DENIED; : PermissionConstants.PERMISSION_STATUS_DENIED;
permissionStatuses.add(status);
} }
if (permission == PermissionConstants.PERMISSION_GROUP_SYSTEM_ALERT_WINDOW) { if (permission == PermissionConstants.PERMISSION_GROUP_SYSTEM_ALERT_WINDOW) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return Settings.canDrawOverlays(context) int status = Settings.canDrawOverlays(context)
? PermissionConstants.PERMISSION_STATUS_GRANTED ? PermissionConstants.PERMISSION_STATUS_GRANTED
: PermissionConstants.PERMISSION_STATUS_DENIED; : PermissionConstants.PERMISSION_STATUS_DENIED;
permissionStatuses.add(status);
} }
} }
if (permission == PermissionConstants.PERMISSION_GROUP_REQUEST_INSTALL_PACKAGES) { if (permission == PermissionConstants.PERMISSION_GROUP_REQUEST_INSTALL_PACKAGES) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return context.getPackageManager().canRequestPackageInstalls() int status = context.getPackageManager().canRequestPackageInstalls()
? PermissionConstants.PERMISSION_STATUS_GRANTED ? PermissionConstants.PERMISSION_STATUS_GRANTED
: PermissionConstants.PERMISSION_STATUS_DENIED; : PermissionConstants.PERMISSION_STATUS_DENIED;
permissionStatuses.add(status);
} }
} }
if (permission == PermissionConstants.PERMISSION_GROUP_ACCESS_NOTIFICATION_POLICY) { if (permission == PermissionConstants.PERMISSION_GROUP_ACCESS_NOTIFICATION_POLICY) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Application.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Application.NOTIFICATION_SERVICE);
return notificationManager.isNotificationPolicyAccessGranted() int status = notificationManager.isNotificationPolicyAccessGranted()
? PermissionConstants.PERMISSION_STATUS_GRANTED ? PermissionConstants.PERMISSION_STATUS_GRANTED
: PermissionConstants.PERMISSION_STATUS_DENIED; : PermissionConstants.PERMISSION_STATUS_DENIED;
permissionStatuses.add(status);
} }
} }
if (permission == PermissionConstants.PERMISSION_GROUP_SCHEDULE_EXACT_ALARM) { if (permission == PermissionConstants.PERMISSION_GROUP_SCHEDULE_EXACT_ALARM) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
return alarmManager.canScheduleExactAlarms() int status = alarmManager.canScheduleExactAlarms()
? PermissionConstants.PERMISSION_STATUS_GRANTED ? PermissionConstants.PERMISSION_STATUS_GRANTED
: PermissionConstants.PERMISSION_STATUS_DENIED; : PermissionConstants.PERMISSION_STATUS_DENIED;
permissionStatuses.add(status);
} else { } else {
return PermissionConstants.PERMISSION_STATUS_GRANTED; permissionStatuses.add(PermissionConstants.PERMISSION_STATUS_GRANTED);
} }
} }
final int permissionStatus = ContextCompat.checkSelfPermission(context, name); final int permissionStatus = ContextCompat.checkSelfPermission(context, name);
if (permissionStatus != PackageManager.PERMISSION_GRANTED) { if (permissionStatus != PackageManager.PERMISSION_GRANTED) {
return PermissionUtils.determineDeniedVariant(activity, name); permissionStatuses.add(PermissionUtils.determineDeniedVariant(activity, name));
} }
} }
} }
if (!permissionStatuses.isEmpty()) {
return strictestStatus(permissionStatuses);
}
return PermissionConstants.PERMISSION_STATUS_GRANTED; return PermissionConstants.PERMISSION_STATUS_GRANTED;
} }
......
...@@ -17,6 +17,8 @@ import androidx.core.app.ActivityCompat; ...@@ -17,6 +17,8 @@ import androidx.core.app.ActivityCompat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List; import java.util.List;
public class PermissionUtils { public class PermissionUtils {
...@@ -48,7 +50,6 @@ public class PermissionUtils { ...@@ -48,7 +50,6 @@ public class PermissionUtils {
case Manifest.permission.WRITE_CALL_LOG: case Manifest.permission.WRITE_CALL_LOG:
case Manifest.permission.ADD_VOICEMAIL: case Manifest.permission.ADD_VOICEMAIL:
case Manifest.permission.USE_SIP: case Manifest.permission.USE_SIP:
case Manifest.permission.BIND_CALL_REDIRECTION_SERVICE:
return PermissionConstants.PERMISSION_GROUP_PHONE; return PermissionConstants.PERMISSION_GROUP_PHONE;
case Manifest.permission.BODY_SENSORS: case Manifest.permission.BODY_SENSORS:
return PermissionConstants.PERMISSION_GROUP_SENSORS; return PermissionConstants.PERMISSION_GROUP_SENSORS;
...@@ -154,9 +155,8 @@ public class PermissionUtils { ...@@ -154,9 +155,8 @@ public class PermissionUtils {
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.READ_PHONE_STATE)) if (hasPermissionInManifest(context, permissionNames, Manifest.permission.READ_PHONE_STATE))
permissionNames.add(Manifest.permission.READ_PHONE_STATE); permissionNames.add(Manifest.permission.READ_PHONE_STATE);
if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.Q && hasPermissionInManifest(context, permissionNames, Manifest.permission.READ_PHONE_NUMBERS)) { if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.Q && hasPermissionInManifest(context, permissionNames, Manifest.permission.READ_PHONE_NUMBERS))
permissionNames.add(Manifest.permission.READ_PHONE_NUMBERS); permissionNames.add(Manifest.permission.READ_PHONE_NUMBERS);
}
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.CALL_PHONE)) if (hasPermissionInManifest(context, permissionNames, Manifest.permission.CALL_PHONE))
permissionNames.add(Manifest.permission.CALL_PHONE); permissionNames.add(Manifest.permission.CALL_PHONE);
...@@ -173,9 +173,6 @@ public class PermissionUtils { ...@@ -173,9 +173,6 @@ public class PermissionUtils {
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.USE_SIP)) if (hasPermissionInManifest(context, permissionNames, Manifest.permission.USE_SIP))
permissionNames.add(Manifest.permission.USE_SIP); permissionNames.add(Manifest.permission.USE_SIP);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && hasPermissionInManifest(context, permissionNames, Manifest.permission.BIND_CALL_REDIRECTION_SERVICE))
permissionNames.add(Manifest.permission.BIND_CALL_REDIRECTION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && hasPermissionInManifest(context, permissionNames, Manifest.permission.ANSWER_PHONE_CALLS)) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && hasPermissionInManifest(context, permissionNames, Manifest.permission.ANSWER_PHONE_CALLS))
permissionNames.add(Manifest.permission.ANSWER_PHONE_CALLS); permissionNames.add(Manifest.permission.ANSWER_PHONE_CALLS);
...@@ -458,6 +455,32 @@ public class PermissionUtils { ...@@ -458,6 +455,32 @@ public class PermissionUtils {
return PermissionConstants.PERMISSION_STATUS_GRANTED; return PermissionConstants.PERMISSION_STATUS_GRANTED;
} }
@NonNull
@PermissionConstants.PermissionStatus
static Integer strictestStatus(final @NonNull Collection<@PermissionConstants.PermissionStatus Integer> statuses) {
if (statuses.contains(PermissionConstants.PERMISSION_STATUS_NEVER_ASK_AGAIN))
return PermissionConstants.PERMISSION_STATUS_NEVER_ASK_AGAIN;
if (statuses.contains(PermissionConstants.PERMISSION_STATUS_RESTRICTED))
return PermissionConstants.PERMISSION_STATUS_RESTRICTED;
if (statuses.contains(PermissionConstants.PERMISSION_STATUS_DENIED))
return PermissionConstants.PERMISSION_STATUS_DENIED;
if (statuses.contains(PermissionConstants.PERMISSION_STATUS_LIMITED))
return PermissionConstants.PERMISSION_STATUS_LIMITED;
return PermissionConstants.PERMISSION_STATUS_GRANTED;
}
@NonNull
@PermissionConstants.PermissionStatus
static Integer strictestStatus(
final @Nullable @PermissionConstants.PermissionStatus Integer statusA,
final @Nullable @PermissionConstants.PermissionStatus Integer statusB) {
final Collection<@PermissionConstants.PermissionStatus Integer> statuses = new HashSet<>();
statuses.add(statusA);
statuses.add(statusB);
return strictestStatus(statuses);
}
/** /**
* Determines whether a permission was either 'denied' or 'permanently denied'. * Determines whether a permission was either 'denied' or 'permanently denied'.
* <p> * <p>
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
<uses-permission android:name="android.permission.USE_SIP"/> <uses-permission android:name="android.permission.USE_SIP"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/> <uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/> <uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
<uses-permission android:name="android.permission.BIND_CALL_REDIRECTION_SERVICE"/>
<!-- Permissions options for the `calendar` group --> <!-- Permissions options for the `calendar` group -->
<uses-permission android:name="android.permission.READ_CALENDAR" /> <uses-permission android:name="android.permission.READ_CALENDAR" />
......
name: permission_handler_android name: permission_handler_android
description: Permission plugin for Flutter. This plugin provides the Android API to request and check permissions. description: Permission plugin for Flutter. This plugin provides the Android API to request and check permissions.
homepage: https://github.com/baseflow/flutter-permission-handler homepage: https://github.com/baseflow/flutter-permission-handler
version: 11.0.1 version: 11.0.2
environment: environment:
sdk: ">=2.15.0 <4.0.0" sdk: ">=2.15.0 <4.0.0"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment