Commit 5923e974 by Maurits van Beusekom

Implemented NOT DETERMINED on Android

parents 201b92c5 933a560e
## 4.4.0+hotfix.1
* Issue #233: Solved a bug that prevented Android applications running in the background to check the permission status.
## 4.4.0
* Updated plugin structure to confirm to the Flutter federated plugin architecture. This will make it easier to add new platform implementations (see: https://medium.com/flutter/how-to-write-a-flutter-web-plugin-part-2-afdddb69ece6);
......
......@@ -12,8 +12,15 @@ On Android, you can show a rationale for requesting a permission.
While the permissions are being requested during runtime, you'll still need to tell the OS which permissions your app might potentially use.
That requires adding permission configuration to Android- and iOS-specific files.
<<<<<<< HEAD
<details>
<summary>Android</summary>
=======
```yaml
dependencies:
permission_handler: '^4.4.0+hotfix.1'
```
>>>>>>> upstream/develop
> The current version of the plugin requires AndroidX.
>
......
......@@ -68,6 +68,7 @@ final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler {
@PermissionConstants.PermissionGroup final int permission = Integer.parseInt(call.arguments.toString());
permissionManager.checkPermissionStatus(
permission,
applicationContext,
activity,
result::success,
(String errorCode, String errorDescription) -> result.error(
......
......@@ -62,7 +62,7 @@ final class PermissionConstants {
static final int PERMISSION_STATUS_DENIED = 0;
static final int PERMISSION_STATUS_GRANTED = 1;
static final int PERMISSION_STATUS_RESTRICTED = 2;
static final int PERMISSION_STATUS_UNKNOWN = 3;
static final int PERMISSION_STATUS_NOT_DETERMINED = 3;
static final int PERMISSION_STATUS_NEWER_ASK_AGAIN = 4;
@Retention(RetentionPolicy.SOURCE)
......@@ -70,7 +70,7 @@ final class PermissionConstants {
PERMISSION_STATUS_DENIED,
PERMISSION_STATUS_GRANTED,
PERMISSION_STATUS_RESTRICTED,
PERMISSION_STATUS_UNKNOWN,
PERMISSION_STATUS_NOT_DETERMINED,
PERMISSION_STATUS_NEWER_ASK_AGAIN,
})
@interface PermissionStatus {
......
......@@ -52,6 +52,7 @@ final class PermissionManager {
void checkPermissionStatus(
@PermissionConstants.PermissionGroup int permission,
Context context,
Activity activity,
CheckPermissionsSuccessCallback successCallback,
ErrorCallback errorCallback) {
......@@ -66,6 +67,7 @@ final class PermissionManager {
successCallback.onSuccess(determinePermissionStatus(
permission,
context,
activity));
}
......@@ -95,7 +97,7 @@ final class PermissionManager {
Map<Integer, Integer> requestResults = new HashMap<>();
ArrayList<String> permissionsToRequest = new ArrayList<>();
for (Integer permission : permissions) {
@PermissionConstants.PermissionStatus final int permissionStatus = determinePermissionStatus(permission, activity);
@PermissionConstants.PermissionStatus final int permissionStatus = determinePermissionStatus(permission, activity, activity);
if (permissionStatus == PermissionConstants.PERMISSION_STATUS_GRANTED) {
if (!requestResults.containsKey(permission)) {
requestResults.put(permission, PermissionConstants.PERMISSION_STATUS_GRANTED);
......@@ -109,7 +111,7 @@ final class PermissionManager {
// if we can't add as unknown and continue
if (names == null || names.isEmpty()) {
if (!requestResults.containsKey(permission)) {
requestResults.put(permission, PermissionConstants.PERMISSION_STATUS_UNKNOWN);
requestResults.put(permission, PermissionConstants.PERMISSION_STATUS_NOT_DETERMINED);
}
continue;
......@@ -159,13 +161,14 @@ final class PermissionManager {
@PermissionConstants.PermissionStatus
private int determinePermissionStatus(
@PermissionConstants.PermissionGroup int permission,
Context context,
Activity activity) {
if (permission == PermissionConstants.PERMISSION_GROUP_NOTIFICATION) {
return checkNotificationPermissionStatus(activity);
return checkNotificationPermissionStatus(context);
}
final List<String> names = PermissionUtils.getManifestNames(activity, permission);
final List<String> names = PermissionUtils.getManifestNames(context, permission);
if (names == null) {
Log.d(PermissionConstants.LOG_TAG, "No android specific permissions needed for: " + permission);
......@@ -176,17 +179,17 @@ final class PermissionManager {
//if no permissions were found then there is an issue and permission is not set in Android manifest
if (names.size() == 0) {
Log.d(PermissionConstants.LOG_TAG, "No permissions found in manifest for: " + permission);
return PermissionConstants.PERMISSION_STATUS_UNKNOWN;
return PermissionConstants.PERMISSION_STATUS_NOT_DETERMINED;
}
final boolean targetsMOrHigher = activity.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.M;
final boolean targetsMOrHigher = context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.M;
for (String name : names) {
// Only handle them if the client app actually targets a API level greater than M.
if (targetsMOrHigher) {
if (permission == PermissionConstants.PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS) {
String packageName = activity.getPackageName();
PowerManager pm = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
String packageName = context.getPackageName();
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
// PowerManager.isIgnoringBatteryOptimizations has been included in Android M first.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (pm != null && pm.isIgnoringBatteryOptimizations(packageName)) {
......@@ -198,16 +201,19 @@ final class PermissionManager {
return PermissionConstants.PERMISSION_STATUS_RESTRICTED;
}
}
final int permissionStatus = ContextCompat.checkSelfPermission(activity, name);
final int permissionStatus = ContextCompat.checkSelfPermission(context, name);
if (permissionStatus == PackageManager.PERMISSION_DENIED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
PermissionUtils.isNeverAskAgainSelected(activity, permission)) {
if (!PermissionUtils.getRequestedPermissionBefore(context, name))
{
return PermissionConstants.PERMISSION_STATUS_NOT_DETERMINED;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
PermissionUtils.isNeverAskAgainSelected(activity, name)) {
return PermissionConstants.PERMISSION_STATUS_NEWER_ASK_AGAIN;
} else {
return PermissionConstants.PERMISSION_STATUS_DENIED;
}
} else if (permissionStatus != PackageManager.PERMISSION_GRANTED) {
return PermissionConstants.PERMISSION_STATUS_UNKNOWN;
return PermissionConstants.PERMISSION_STATUS_DENIED;
}
}
}
......@@ -284,7 +290,9 @@ final class PermissionManager {
? PermissionConstants.PERMISSION_STATUS_GRANTED
: PermissionConstants.PERMISSION_STATUS_DENIED;
callback.onSuccess(new HashMap<>(PermissionConstants.PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS, status));
HashMap<Integer, Integer> results = new HashMap<>();
results.put(PermissionConstants.PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS, status);
callback.onSuccess(results);
return true;
}
}
......@@ -323,8 +331,10 @@ final class PermissionManager {
alreadyCalled = true;
for (int i = 0; i < permissions.length; i++) {
final String permissionName = permissions[i];
@PermissionConstants.PermissionGroup final int permission =
PermissionUtils.parseManifestName(permissions[i]);
PermissionUtils.parseManifestName(permissionName);
if (permission == PermissionConstants.PERMISSION_GROUP_UNKNOWN)
continue;
......@@ -335,23 +345,23 @@ final class PermissionManager {
if (!requestResults.containsKey(PermissionConstants.PERMISSION_GROUP_MICROPHONE)) {
requestResults.put(
PermissionConstants.PERMISSION_GROUP_MICROPHONE,
PermissionUtils.toPermissionStatus(this.activity, permission, result));
PermissionUtils.toPermissionStatus(this.activity, permissionName, result));
}
if (!requestResults.containsKey(PermissionConstants.PERMISSION_GROUP_SPEECH)) {
requestResults.put(
PermissionConstants.PERMISSION_GROUP_SPEECH,
PermissionUtils.toPermissionStatus(this.activity, permission, result));
PermissionUtils.toPermissionStatus(this.activity, permissionName, result));
}
} else if (permission == PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS) {
@PermissionConstants.PermissionStatus int permissionStatus =
PermissionUtils.toPermissionStatus(this.activity, permission, result);
PermissionUtils.toPermissionStatus(this.activity, permissionName, result);
if (!requestResults.containsKey(PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS)) {
requestResults.put(PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS, permissionStatus);
}
} else if (permission == PermissionConstants.PERMISSION_GROUP_LOCATION) {
@PermissionConstants.PermissionStatus int permissionStatus =
PermissionUtils.toPermissionStatus(this.activity, permission, result);
PermissionUtils.toPermissionStatus(this.activity, permissionName, result);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
if (!requestResults.containsKey(PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS)) {
......@@ -371,7 +381,7 @@ final class PermissionManager {
} else if (!requestResults.containsKey(permission)) {
requestResults.put(
permission,
PermissionUtils.toPermissionStatus(this.activity, permission, result));
PermissionUtils.toPermissionStatus(this.activity, permissionName, result));
}
PermissionUtils.updatePermissionShouldShowStatus(this.activity, permission);
......
......@@ -11,6 +11,7 @@ import android.util.Log;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.Arrays;
......@@ -237,9 +238,9 @@ public class PermissionUtils {
}
@PermissionConstants.PermissionStatus
static int toPermissionStatus(final Activity activity, @PermissionConstants.PermissionGroup int permission, int grantResult) {
static int toPermissionStatus(final Activity activity, final String permissionName, int grantResult) {
if (grantResult == PackageManager.PERMISSION_DENIED) {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && PermissionUtils.isNeverAskAgainSelected(activity, permission)
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && PermissionUtils.isNeverAskAgainSelected(activity, permissionName)
? PermissionConstants.PERMISSION_STATUS_NEWER_ASK_AGAIN
: PermissionConstants.PERMISSION_STATUS_DENIED;
}
......@@ -264,23 +265,12 @@ public class PermissionUtils {
}
@RequiresApi(api = Build.VERSION_CODES.M)
static boolean isNeverAskAgainSelected(final Activity activity, @PermissionConstants.PermissionGroup int permission) {
static boolean isNeverAskAgainSelected(final Activity activity, final String name) {
if (activity == null) {
return false;
}
List<String> names = getManifestNames(activity, permission);
if (names == null || names.isEmpty()) {
return false;
}
boolean isNeverAskAgainSelected = false;
for (String name : names) {
isNeverAskAgainSelected |= PermissionUtils.neverAskAgainSelected(activity, name);
}
return isNeverAskAgainSelected;
return PermissionUtils.neverAskAgainSelected(activity, name);
}
@RequiresApi(api = Build.VERSION_CODES.M)
......@@ -297,7 +287,7 @@ public class PermissionUtils {
editor.apply();
}
private static boolean getRequestedPermissionBefore(final Context context, final String permission) {
static boolean getRequestedPermissionBefore(final Context context, final String permission) {
SharedPreferences genPrefs = context.getSharedPreferences("GENERIC_PREFERENCES", Context.MODE_PRIVATE);
return genPrefs.getBoolean(permission, false);
}
......
......@@ -96,7 +96,7 @@ final class ServiceManager {
return locationManager.isLocationEnabled();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
return isLocationServiceEnablePrePie(context);
return isLocationServiceEnabledKitKat(context);
} else {
return isLocationServiceEnablePreKitKat(context);
}
......@@ -105,10 +105,11 @@ final class ServiceManager {
// Suppress deprecation warnings since its purpose is to support to be backwards compatible with
// pre Pie versions of Android.
@SuppressWarnings("deprecation")
private static boolean isLocationServiceEnablePrePie(Context context)
private static boolean isLocationServiceEnabledKitKat(Context context)
{
if (VERSION.SDK_INT < VERSION_CODES.P)
if (Build.VERSION.SDK_INT < VERSION_CODES.KITKAT) {
return false;
}
final int locationMode;
......
......@@ -57,6 +57,9 @@
<!-- Permissions options for the `activityRecognition` group -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<!-- Permissions options for the `ignoreBatteryOptimizations` group -->
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<application
android:name="io.flutter.app.FlutterApplication"
android:icon="@mipmap/ic_launcher"
......
......@@ -3,7 +3,7 @@
#
Pod::Spec.new do |s|
s.name = 'permission_handler'
s.version = '4.4.0'
s.version = '4.4.0+hotfix.1'
s.summary = 'Permission plugin for Flutter.'
s.description = <<-DESC
Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions.
......
name: permission_handler
description: Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions.
version: 4.4.0
version: 4.4.0+hotfix.1
homepage: https://github.com/baseflowit/flutter-permission-handler
flutter:
......
......@@ -21,8 +21,9 @@ abstract class PermissionHandlerPlatform extends PlatformInterface {
/// Defaults to [MethodChannelPermissionHandler].
static PermissionHandlerPlatform get instance => _instance;
/// Platform-specific plugins should set this with their own platform-specific
/// class that extends [PermissionHandlerPlatform] when they register themselves.
/// Platform-specific plugins should set this with their own
/// platform-specific class that extends
/// [PermissionHandlerPlatform] when they register themselves.
static set instance(PermissionHandlerPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
......
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