Commit 24ecfe2a by Maurits van Beusekom

Release 3.2.0

parents bc3e34a5 f63c6c23
## 3.2.0
* Add support for Androids' "ignore battery optimizations" permission;
* Improve error logging;
* Documented support for AndroidX.
## 3.1.0 ## 3.1.0
* Support service status inquiry for phone permission on iOS & Android. * Support service status inquiry for phone permission on iOS & Android.
......
...@@ -22,10 +22,29 @@ To use this plugin, add `permission_handler` as a [dependency in your pubspec.ya ...@@ -22,10 +22,29 @@ To use this plugin, add `permission_handler` as a [dependency in your pubspec.ya
```yaml ```yaml
dependencies: dependencies:
permission_handler: '^3.1.0' permission_handler: '^3.2.0'
``` ```
> **NOTE:** There's a known issue with integrating plugins that use Swift into a Flutter project created with the Objective-C template. See issue [Flutter#16049](https://github.com/flutter/flutter/issues/16049) for help on integration. > **NOTE:** As of version 3.1.0 the permission_handler plugin switched to the AndroidX version of the Android Support Libraries. This means you need to make sure your Android project is also upgraded to support AndroidX. Detailed instructions can be found [here](https://flutter.dev/docs/development/packages-and-plugins/androidx-compatibility).
>
>The TL;DR version is:
>
>1. Add the following to your "gradle.properties" file:
>
>```
>android.useAndroidX=true
>android.enableJetifier=true
>```
>2. Make sure you set the `compileSdkVersion` in your "android/app/build.gradle" file to 28:
>
>```
>android {
> compileSdkVersion 28
>
> ...
>}
>```
>3. Make sure you replace all the `android.` dependencies to their AndroidX counterparts (a full list can be found here: https://developer.android.com/jetpack/androidx/migrate).
## API ## API
......
...@@ -11,11 +11,15 @@ import android.content.pm.ResolveInfo; ...@@ -11,11 +11,15 @@ import android.content.pm.ResolveInfo;
import android.location.LocationManager; import android.location.LocationManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.PowerManager;
import android.provider.Settings; import android.provider.Settings;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import io.flutter.plugin.common.PluginRegistry.ActivityResultListener;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -37,6 +41,7 @@ import io.flutter.plugin.common.PluginRegistry.Registrar; ...@@ -37,6 +41,7 @@ import io.flutter.plugin.common.PluginRegistry.Registrar;
public class PermissionHandlerPlugin implements MethodCallHandler { public class PermissionHandlerPlugin implements MethodCallHandler {
private static final String LOG_TAG = "permissions_handler"; private static final String LOG_TAG = "permissions_handler";
private static final int PERMISSION_CODE = 24; private static final int PERMISSION_CODE = 24;
private static final int PERMISSION_CODE_IGNORE_BATTERY_OPTIMIZATIONS = 5672353;
//PERMISSION_GROUP //PERMISSION_GROUP
private static final int PERMISSION_GROUP_CALENDAR = 0; private static final int PERMISSION_GROUP_CALENDAR = 0;
...@@ -54,7 +59,8 @@ public class PermissionHandlerPlugin implements MethodCallHandler { ...@@ -54,7 +59,8 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
private static final int PERMISSION_GROUP_SMS = 12; private static final int PERMISSION_GROUP_SMS = 12;
private static final int PERMISSION_GROUP_SPEECH = 13; private static final int PERMISSION_GROUP_SPEECH = 13;
private static final int PERMISSION_GROUP_STORAGE = 14; private static final int PERMISSION_GROUP_STORAGE = 14;
private static final int PERMISSION_GROUP_UNKNOWN = 15; private static final int PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS = 15;
private static final int PERMISSION_GROUP_UNKNOWN = 16;
private PermissionHandlerPlugin(Registrar mRegistrar) { private PermissionHandlerPlugin(Registrar mRegistrar) {
this.mRegistrar = mRegistrar; this.mRegistrar = mRegistrar;
...@@ -77,6 +83,7 @@ public class PermissionHandlerPlugin implements MethodCallHandler { ...@@ -77,6 +83,7 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
PERMISSION_GROUP_SMS, PERMISSION_GROUP_SMS,
PERMISSION_GROUP_SPEECH, PERMISSION_GROUP_SPEECH,
PERMISSION_GROUP_STORAGE, PERMISSION_GROUP_STORAGE,
PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS,
PERMISSION_GROUP_UNKNOWN, PERMISSION_GROUP_UNKNOWN,
}) })
private @interface PermissionGroup { private @interface PermissionGroup {
...@@ -133,6 +140,18 @@ public class PermissionHandlerPlugin implements MethodCallHandler { ...@@ -133,6 +140,18 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
} }
} }
}); });
registrar.addActivityResultListener(new ActivityResultListener() {
@Override
public boolean onActivityResult(int requestCode, int responseCode, Intent intent) {
if (requestCode == PERMISSION_CODE_IGNORE_BATTERY_OPTIMIZATIONS) {
permissionHandlerPlugin.handleIgnoreBatteryOptimizationsRequest(responseCode == Activity.RESULT_OK);
return true;
}
return false;
}
});
} }
@PermissionGroup @PermissionGroup
...@@ -232,14 +251,14 @@ public class PermissionHandlerPlugin implements MethodCallHandler { ...@@ -232,14 +251,14 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
final List<String> names = getManifestNames(permission); final List<String> names = getManifestNames(permission);
if (names == null) { if (names == null) {
Log.d(LOG_TAG, "No android specific permissions needed for: $permission"); Log.d(LOG_TAG, "No android specific permissions needed for: " + permission);
return PERMISSION_STATUS_GRANTED; return PERMISSION_STATUS_GRANTED;
} }
//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(LOG_TAG, "No permissions found in manifest for: $permission"); Log.d(LOG_TAG, "No permissions found in manifest for: " + permission);
return PERMISSION_STATUS_UNKNOWN; return PERMISSION_STATUS_UNKNOWN;
} }
...@@ -249,10 +268,25 @@ public class PermissionHandlerPlugin implements MethodCallHandler { ...@@ -249,10 +268,25 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
return PERMISSION_STATUS_UNKNOWN; return PERMISSION_STATUS_UNKNOWN;
} }
final boolean targetsMOrHigher = context.getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.M; final boolean targetsMOrHigher = context.getApplicationInfo().targetSdkVersion >= 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.
if (targetsMOrHigher) { if (targetsMOrHigher) {
if (permission == PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS) {
String packageName = context.getPackageName();
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
// PowerManager.isIgnoringBatteryOptimizations has been included in Android M first.
if (VERSION.SDK_INT >= VERSION_CODES.M) {
if (pm.isIgnoringBatteryOptimizations(packageName)) {
return PERMISSION_STATUS_GRANTED;
} else {
return PERMISSION_STATUS_DENIED;
}
} else {
return PERMISSION_STATUS_RESTRICTED;
}
}
final int permissionStatus = ContextCompat.checkSelfPermission(context, name); final int permissionStatus = ContextCompat.checkSelfPermission(context, name);
if (permissionStatus == PackageManager.PERMISSION_DENIED) { if (permissionStatus == PackageManager.PERMISSION_DENIED) {
return PERMISSION_STATUS_DENIED; return PERMISSION_STATUS_DENIED;
...@@ -312,6 +346,10 @@ public class PermissionHandlerPlugin implements MethodCallHandler { ...@@ -312,6 +346,10 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
return SERVICE_STATUS_ENABLED; return SERVICE_STATUS_ENABLED;
} }
if (permission == PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS) {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? SERVICE_STATUS_ENABLED : SERVICE_STATUS_NOT_APPLICABLE;
}
return SERVICE_STATUS_NOT_APPLICABLE; return SERVICE_STATUS_NOT_APPLICABLE;
} }
...@@ -326,12 +364,12 @@ public class PermissionHandlerPlugin implements MethodCallHandler { ...@@ -326,12 +364,12 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
// if isn't an android specific group then go ahead and return false; // if isn't an android specific group then go ahead and return false;
if (names == null) { if (names == null) {
Log.d(LOG_TAG, "No android specific permissions needed for: $permission"); Log.d(LOG_TAG, "No android specific permissions needed for: " + permission);
return false; return false;
} }
if (names.isEmpty()) { if (names.isEmpty()) {
Log.d(LOG_TAG, "No permissions found in manifest for: $permission no need to show request rationale"); Log.d(LOG_TAG, "No permissions found in manifest for: " + permission + " no need to show request rationale");
return false; return false;
} }
...@@ -371,7 +409,15 @@ public class PermissionHandlerPlugin implements MethodCallHandler { ...@@ -371,7 +409,15 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
continue; continue;
} }
permissionsToRequest.addAll(names); if (permission == PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS) {
String packageName = mRegistrar.context().getPackageName();
Intent intent = new Intent();
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
mRegistrar.activity().startActivityForResult(intent, PERMISSION_CODE_IGNORE_BATTERY_OPTIMIZATIONS);
} else {
permissionsToRequest.addAll(names);
}
} else { } else {
if (!mRequestResults.containsKey(permission)) { if (!mRequestResults.containsKey(permission)) {
mRequestResults.put(permission, PERMISSION_STATUS_GRANTED); mRequestResults.put(permission, PERMISSION_STATUS_GRANTED);
...@@ -429,6 +475,18 @@ public class PermissionHandlerPlugin implements MethodCallHandler { ...@@ -429,6 +475,18 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
processResult(); processResult();
} }
private void handleIgnoreBatteryOptimizationsRequest(boolean granted) {
if (mResult == null) {
return;
}
int status = granted ? PERMISSION_STATUS_GRANTED : PERMISSION_STATUS_DENIED;
mRequestResults.put(PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS, status);
processResult();
}
@PermissionStatus @PermissionStatus
private int toPermissionStatus(int grantResult) { private int toPermissionStatus(int grantResult) {
return grantResult == PackageManager.PERMISSION_GRANTED ? PERMISSION_STATUS_GRANTED : PERMISSION_STATUS_DENIED; return grantResult == PackageManager.PERMISSION_GRANTED ? PERMISSION_STATUS_GRANTED : PERMISSION_STATUS_DENIED;
...@@ -533,7 +591,7 @@ public class PermissionHandlerPlugin implements MethodCallHandler { ...@@ -533,7 +591,7 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
break; break;
case PERMISSION_GROUP_SENSORS: case PERMISSION_GROUP_SENSORS:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { if (VERSION.SDK_INT >= VERSION_CODES.KITKAT_WATCH) {
if (hasPermissionInManifest(Manifest.permission.BODY_SENSORS)) { if (hasPermissionInManifest(Manifest.permission.BODY_SENSORS)) {
permissionNames.add(Manifest.permission.BODY_SENSORS); permissionNames.add(Manifest.permission.BODY_SENSORS);
} }
...@@ -565,6 +623,11 @@ public class PermissionHandlerPlugin implements MethodCallHandler { ...@@ -565,6 +623,11 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
permissionNames.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); permissionNames.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
break; break;
case PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS:
if (VERSION.SDK_INT >= VERSION_CODES.M && hasPermissionInManifest(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS))
permissionNames.add(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
break;
case PERMISSION_GROUP_MEDIA_LIBRARY: case PERMISSION_GROUP_MEDIA_LIBRARY:
case PERMISSION_GROUP_PHOTOS: case PERMISSION_GROUP_PHOTOS:
case PERMISSION_GROUP_REMINDERS: case PERMISSION_GROUP_REMINDERS:
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SENSORS" /> <uses-permission android:name="android.permission.SENSORS" />
<uses-permission android:name="android.permission.BODY_SENSORS" /> <uses-permission android:name="android.permission.BODY_SENSORS" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="io.flutter.app.FlutterApplication"
......
...@@ -29,7 +29,9 @@ class MyApp extends StatelessWidget { ...@@ -29,7 +29,9 @@ class MyApp extends StatelessWidget {
if (Platform.isIOS) { if (Platform.isIOS) {
return permission != PermissionGroup.unknown && return permission != PermissionGroup.unknown &&
permission != PermissionGroup.sms && permission != PermissionGroup.sms &&
permission != PermissionGroup.storage; permission != PermissionGroup.storage &&
permission !=
PermissionGroup.ignoreBatteryOptimizations;
} else { } else {
return permission != PermissionGroup.unknown && return permission != PermissionGroup.unknown &&
permission != PermissionGroup.mediaLibrary && permission != PermissionGroup.mediaLibrary &&
......
...@@ -21,6 +21,7 @@ typedef NS_ENUM(int, PermissionGroup) { ...@@ -21,6 +21,7 @@ typedef NS_ENUM(int, PermissionGroup) {
PermissionGroupSms, PermissionGroupSms,
PermissionGroupSpeech, PermissionGroupSpeech,
PermissionGroupStorage, PermissionGroupStorage,
PermissionGroupIgnoreBatteryOptimizations,
PermissionGroupUnknown, PermissionGroupUnknown,
}; };
......
...@@ -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 = '3.1.0' s.version = '3.2.0'
s.summary = 'Permission plugin for Flutter.' s.summary = 'Permission plugin for Flutter.'
s.description = <<-DESC s.description = <<-DESC
A new Flutter project. A new Flutter project.
......
...@@ -143,8 +143,12 @@ class PermissionGroup { ...@@ -143,8 +143,12 @@ class PermissionGroup {
/// iOS: Nothing /// iOS: Nothing
static const PermissionGroup storage = PermissionGroup._(14); static const PermissionGroup storage = PermissionGroup._(14);
/// Android: Ignore Battery Optimizations
static const PermissionGroup ignoreBatteryOptimizations =
PermissionGroup._(15);
/// The unknown permission only used for return type, never requested /// The unknown permission only used for return type, never requested
static const PermissionGroup unknown = PermissionGroup._(15); static const PermissionGroup unknown = PermissionGroup._(16);
static const List<PermissionGroup> values = <PermissionGroup>[ static const List<PermissionGroup> values = <PermissionGroup>[
calendar, calendar,
...@@ -162,6 +166,7 @@ class PermissionGroup { ...@@ -162,6 +166,7 @@ class PermissionGroup {
sms, sms,
speech, speech,
storage, storage,
ignoreBatteryOptimizations,
unknown, unknown,
]; ];
...@@ -181,6 +186,7 @@ class PermissionGroup { ...@@ -181,6 +186,7 @@ class PermissionGroup {
'sms', 'sms',
'speech', 'speech',
'storage', 'storage',
'ignoreBatteryOptimizations',
'unknown', 'unknown',
]; ];
......
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: 3.1.0 version: 3.2.0
authors: authors:
- Baseflow <hello@baseflow.com> - Baseflow <hello@baseflow.com>
- long1eu <home@long1.eu> - long1eu <home@long1.eu>
......
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