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