Commit 5e46381c by Maurits van Beusekom Committed by GitHub

Merge branch 'develop' into develop

parents 20ba9a77 7f9322c6
......@@ -162,7 +162,7 @@ import 'package:permission_handler/permission_handler.dart';
ServiceStatus serviceStatus = await PermissionHandler().checkServiceStatus(PermissionGroup.location);
```
Checking the service status only makes sense for the `PermissionGroup.location` on Android and the `PermissionGroup.location`, `PermissionGroup.locationWhenInUser`, `PermissionGroup.locationAlways` or `PermissionGroup.sensors` on iOS. All other permission groups are not backed by a separate service and will always return `ServiceStatus.notApplicable`.
Checking the service status only makes sense for the `PermissionGroup.location` on Android and the `PermissionGroup.location`, `PermissionGroup.locationWhenInUse`, `PermissionGroup.locationAlways` or `PermissionGroup.sensors` on iOS. All other permission groups are not backed by a separate service and will always return `ServiceStatus.notApplicable`.
### Open app settings
......
include: package:pedantic/analysis_options.1.7.0.yaml
include: package:effective_dart/analysis_options.1.2.0.yaml
linter:
rules:
- public_member_api_docs
\ No newline at end of file
......@@ -65,7 +65,8 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
private static final int PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS = 15;
private static final int PERMISSION_GROUP_NOTIFICATION = 16;
private static final int PERMISSION_GROUP_ACCESS_MEDIA_LOCATION = 17;
private static final int PERMISSION_GROUP_UNKNOWN = 18;
private static final int PERMISSION_GROUP_ACTIVITY_RECOGNITION = 18;
private static final int PERMISSION_GROUP_UNKNOWN = 19;
private PermissionHandlerPlugin(Registrar mRegistrar) {
this.mRegistrar = mRegistrar;
......@@ -91,6 +92,7 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS,
PERMISSION_GROUP_NOTIFICATION,
PERMISSION_GROUP_ACCESS_MEDIA_LOCATION,
PERMISSION_GROUP_ACTIVITY_RECOGNITION,
PERMISSION_GROUP_UNKNOWN,
})
private @interface PermissionGroup {
......@@ -202,6 +204,8 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
return PERMISSION_GROUP_STORAGE;
case Manifest.permission.ACCESS_MEDIA_LOCATION:
return PERMISSION_GROUP_ACCESS_MEDIA_LOCATION;
case Manifest.permission.ACTIVITY_RECOGNITION:
return PERMISSION_GROUP_ACTIVITY_RECOGNITION;
default:
return PERMISSION_GROUP_UNKNOWN;
}
......@@ -313,6 +317,7 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
}
}
}
return PERMISSION_STATUS_GRANTED;
}
......@@ -683,6 +688,11 @@ public class PermissionHandlerPlugin implements MethodCallHandler {
permissionNames.add(Manifest.permission.ACCESS_MEDIA_LOCATION);
break;
case PERMISSION_GROUP_ACTIVITY_RECOGNITION:
if (VERSION.SDK_INT >= VERSION_CODES.Q && hasPermissionInManifest(Manifest.permission.ACTIVITY_RECOGNITION))
permissionNames.add(Manifest.permission.ACTIVITY_RECOGNITION);
break;
case PERMISSION_GROUP_NOTIFICATION:
case PERMISSION_GROUP_MEDIA_LIBRARY:
case PERMISSION_GROUP_PHOTOS:
......
......@@ -5,6 +5,8 @@ import 'package:permission_handler/permission_handler.dart';
void main() => runApp(MyApp());
/// Example Flutter Application demonstrating the functionality of the
/// Permission Handler plugin.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
......@@ -49,7 +51,10 @@ class MyApp extends StatelessWidget {
}
}
/// Permission widget which displays a permission and allows users to request
/// the permissions.
class PermissionWidget extends StatefulWidget {
/// Constructs a [PermissionWidget] for the supplied [PermissionGroup].
const PermissionWidget(this._permissionGroup);
final PermissionGroup _permissionGroup;
......
......@@ -2,6 +2,7 @@
class PermissionStatus {
const PermissionStatus._(this.value);
/// Integer representation of the [PermissionStatus].
final int value;
/// Permission to access the requested feature is denied by the user.
......@@ -13,17 +14,19 @@ class PermissionStatus {
/// Permission to access the requested feature is granted by the user.
static const PermissionStatus granted = PermissionStatus._(2);
/// Permission to access the requested feature is denied by the OS (only on iOS).
/// The user cannot change this app's status, possibly due to active restrictions such as
/// parental controls being in place.
/// Permission to access the requested feature is denied by the OS (only on
/// iOS). The user cannot change this app's status, possibly due to active
/// restrictions such as parental controls being in place.
static const PermissionStatus restricted = PermissionStatus._(3);
/// Permission is in an unknown state
static const PermissionStatus unknown = PermissionStatus._(4);
/// Permission to access the requested feature is denied by the user and never show selected (only on Android).
/// Permission to access the requested feature is denied by the user and
/// never show selected (only on Android).
static const PermissionStatus neverAskAgain = PermissionStatus._(5);
/// Returns a list of all possible [PermissionStatus] values.
static const List<PermissionStatus> values = <PermissionStatus>[
denied,
disabled,
......@@ -50,6 +53,7 @@ class PermissionStatus {
class ServiceStatus {
const ServiceStatus._(this.value);
/// Integer representation of the [ServiceStatus].
final int value;
/// The service for the supplied permission group is disabled.
......@@ -61,9 +65,11 @@ class ServiceStatus {
/// There is no service for the supplied permission group.
static const ServiceStatus notApplicable = ServiceStatus._(2);
/// The unknown service status indicates the state of the service could not be determined.
/// The unknown service status indicates the state of the service could not
/// be determined.
static const ServiceStatus unknown = ServiceStatus._(3);
/// Returns a list of all possible [ServiceStatus] values.
static const List<ServiceStatus> values = <ServiceStatus>[
disabled,
enabled,
......@@ -82,10 +88,12 @@ class ServiceStatus {
String toString() => 'ServiceStatus.${_names[value]}';
}
/// Defines the permission groups for which permissions can be checked or requested.
/// Defines the permission groups for which permissions can be checked or
/// requested.
class PermissionGroup {
const PermissionGroup._(this.value);
/// Integer representation of the [PermissionGroup].
final int value;
/// Android: Calendar
......@@ -147,7 +155,8 @@ class PermissionGroup {
static const PermissionGroup speech = PermissionGroup._(13);
/// Android: External Storage
/// iOS: Access to folders like `Documents` or `Downloads`. Implicitly granted.
/// iOS: Access to folders like `Documents` or `Downloads`. Implicitly
/// granted.
static const PermissionGroup storage = PermissionGroup._(14);
/// Android: Ignore Battery Optimizations
......@@ -158,12 +167,19 @@ class PermissionGroup {
/// iOS: Notification
static const PermissionGroup notification = PermissionGroup._(16);
/// Android: Allows an application to access any geographic locations persisted in the user's shared collection.
/// Android: Allows an application to access any geographic locations
/// persisted in the user's shared collection.
static const PermissionGroup access_media_location = PermissionGroup._(17);
/// When running on Android Q and above: Activity Recognition
/// When running on Android < Q: Nothing
/// iOS: Nothing
static const PermissionGroup activity_recognition = PermissionGroup._(18);
/// The unknown permission only used for return type, never requested
static const PermissionGroup unknown = PermissionGroup._(18);
static const PermissionGroup unknown = PermissionGroup._(19);
/// Returns a list of all possible [PermissionGroup] values.
static const List<PermissionGroup> values = <PermissionGroup>[
calendar,
camera,
......@@ -183,6 +199,7 @@ class PermissionGroup {
ignoreBatteryOptimizations,
notification,
access_media_location,
activity_recognition,
unknown,
];
......@@ -205,6 +222,7 @@ class PermissionGroup {
'ignoreBatteryOptimizations',
'notification',
'access_media_location',
'activity_recognition',
'unknown',
];
......
......@@ -4,14 +4,21 @@ import 'dart:io';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
import 'package:permission_handler/src/permission_enums.dart';
import 'package:permission_handler/src/utils/codec.dart';
import 'permission_enums.dart';
import 'utils/codec.dart';
/// Provides a cross-platform (iOS, Android) API to request and check permissions.
/// Provides a cross-platform (iOS, Android) API to request and check
/// permissions.
class PermissionHandler {
/// Constructs a singleton instance of [Geolocator].
///
/// When a second instance is created, the first instance will not be able to
/// listen to the EventChannel because it is overridden. Forcing the class to
/// be a singleton class can prevent misuse of creating a second instance
/// from a programmer.
factory PermissionHandler() {
if (_instance == null) {
const MethodChannel methodChannel =
const methodChannel =
MethodChannel('flutter.baseflow.com/permissions/methods');
_instance = PermissionHandler.private(methodChannel);
......@@ -19,6 +26,8 @@ class PermissionHandler {
return _instance;
}
/// This constructor is only used for testing and shouldn't be accessed by
/// users of the plugin.
@visibleForTesting
PermissionHandler.private(this._methodChannel);
......@@ -28,10 +37,11 @@ class PermissionHandler {
/// Check current permission status.
///
/// Returns a [Future] containing the current permission status for the supplied [PermissionGroup].
/// Returns a [Future] containing the current permission status for the
/// supplied [PermissionGroup].
Future<PermissionStatus> checkPermissionStatus(
PermissionGroup permission) async {
final int status = await _methodChannel.invokeMethod(
final status = await _methodChannel.invokeMethod(
'checkPermissionStatus', permission.value);
return Codec.decodePermissionStatus(status);
......@@ -39,7 +49,8 @@ class PermissionHandler {
/// Check current service status.
///
/// Returns a [Future] containing the current service status for the supplied [PermissionGroup].
/// Returns a [Future] containing the current service status for the supplied
/// [PermissionGroup].
///
/// Notes about specific PermissionGroups:
/// - **PermissionGroup.phone**
......@@ -60,7 +71,7 @@ class PermissionHandler {
/// devices' capability to place & connect phone calls
/// as it also depends on the network condition.
Future<ServiceStatus> checkServiceStatus(PermissionGroup permission) async {
final int status = await _methodChannel.invokeMethod(
final status = await _methodChannel.invokeMethod(
'checkServiceStatus', permission.value);
return Codec.decodeServiceStatus(status);
......@@ -68,9 +79,10 @@ class PermissionHandler {
/// Open the App settings page.
///
/// Returns [true] if the app settings page could be opened, otherwise [false] is returned.
/// Returns [true] if the app settings page could be opened,
/// otherwise [false] is returned.
Future<bool> openAppSettings() async {
final bool hasOpened = await _methodChannel.invokeMethod('openAppSettings');
final hasOpened = await _methodChannel.invokeMethod('openAppSettings');
return hasOpened;
}
......@@ -80,8 +92,8 @@ class PermissionHandler {
/// Returns a [Map] containing the status per requested permissiongroup.
Future<Map<PermissionGroup, PermissionStatus>> requestPermissions(
List<PermissionGroup> permissions) async {
final List<int> data = Codec.encodePermissionGroups(permissions);
final Map<dynamic, dynamic> status =
final data = Codec.encodePermissionGroups(permissions);
final status =
await _methodChannel.invokeMethod('requestPermissions', data);
return Codec.decodePermissionRequestResult(Map<int, int>.from(status));
......@@ -97,7 +109,7 @@ class PermissionHandler {
return false;
}
final bool shouldShowRationale = await _methodChannel.invokeMethod(
final shouldShowRationale = await _methodChannel.invokeMethod(
'shouldShowRequestPermissionRationale', permission.value);
return shouldShowRationale;
......
import 'package:permission_handler/src/permission_enums.dart';
import '../permission_enums.dart';
/// Provides utility methods for encoding messages that are send on the Flutter
/// message channel.
class Codec {
/// Converts the supplied integer value into a [PermissionStatus] instance.
static PermissionStatus decodePermissionStatus(int value) {
return PermissionStatus.values[value];
}
/// Converts the supplied integer value into a [ServiceStatus] instance.
static ServiceStatus decodeServiceStatus(int value) {
return ServiceStatus.values[value];
}
/// Converts the supplied [Map] of integers into a [Map] of
/// [PermissionGroup] key and [PermissionStatus] value instances.
static Map<PermissionGroup, PermissionStatus> decodePermissionRequestResult(
Map<int, int> value) {
return value.map((int key, int value) =>
return value.map((key, value) =>
MapEntry<PermissionGroup, PermissionStatus>(
PermissionGroup.values[key], PermissionStatus.values[value]));
}
/// Converts the supplied [List] containing [PermissionGroup] instances into
/// a [List] containing integers which can be used to send on the Flutter
/// method channel.
static List<int> encodePermissionGroups(List<PermissionGroup> permissions) {
return permissions.map((PermissionGroup it) => it.value).toList();
return permissions.map((it) => it.value).toList();
}
}
......@@ -13,7 +13,7 @@ dependencies:
meta: ^1.1.6
dev_dependencies:
pedantic: ^1.7.0
effective_dart: ^1.2.1
flutter:
plugin:
......
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