Commit e0e18e25 by Maurits van Beusekom

Added option to check service status

parent 277c8810
## 2.2.0
* Added new method `checkServiceStatus` to allow users to check if the location services (on Android and iOS) and motion services (iOS only) are enabled;
* When checking permission status (using `checkPermissionStatus`) return `PermissionStatus.disabled` when permissions are granted or denied and the location services (on Android and iOS) or the motion services (iOS only) are disabled.
## 2.1.3
* Fixed bug on iOS where result of the `openAppSettings` call always returned `false`;
......
......@@ -22,7 +22,7 @@ To use this plugin, add `permission_handler` as a [dependency in your pubspec.ya
```yaml
dependencies:
permission_handler: '^2.1.3'
permission_handler: '^2.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.
......@@ -45,6 +45,16 @@ import 'package:permission_handler/permission_handler.dart';
PermissionStatus permission = await PermissionHandler().checkPermissionStatus(PermissionGroup.contacts);
```
### Checking service status
``` dart
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`.
### Open app settings
``` dart
......
......@@ -12,6 +12,7 @@ import androidx.core.content.ContextCompat
import android.util.Log
import com.baseflow.permissionhandler.data.PermissionGroup
import com.baseflow.permissionhandler.data.PermissionStatus
import com.baseflow.permissionhandler.data.ServiceStatus
import com.baseflow.permissionhandler.utils.Codec
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
......@@ -99,7 +100,14 @@ class PermissionHandlerPlugin(private val registrar: Registrar, private var requ
call.method == "checkPermissionStatus" -> {
val permission = Codec.decodePermissionGroup(call.arguments)
val permissionStatus = checkPermissionStatus(permission)
handleSuccess(permissionStatus, result)
result?.success(Codec.encodePermissionStatus(permissionStatus))
}
call.method == "checkServiceStatus" -> {
val permission = Codec.decodePermissionGroup(call.arguments)
val serviceStatus = checkServiceStatus(permission)
result?.success(Codec.encodeServiceStatus(serviceStatus))
}
call.method == "requestPermissions" -> {
if (mResult != null) {
......@@ -168,6 +176,20 @@ class PermissionHandlerPlugin(private val registrar: Registrar, private var requ
return PermissionStatus.GRANTED
}
private fun checkServiceStatus(permission: PermissionGroup) : ServiceStatus {
val context: Context? = registrar.activity() ?: registrar.activeContext()
if (context == null) {
Log.d(mLogTag, "Unable to detect current Activity or App Context.")
return ServiceStatus.UNKNOWN
}
if (permission == PermissionGroup.LOCATION || permission == PermissionGroup.LOCATION_ALWAYS || permission == PermissionGroup.LOCATION_WHEN_IN_USE) {
return if(isLocationServiceEnabled(context)) ServiceStatus.ENABLED else ServiceStatus.DISABLED
}
return ServiceStatus.NOT_APPLICABLE
}
private fun shouldShowRequestPermissionRationale(permission: PermissionGroup) : Boolean {
val activity = registrar.activity()
if(activity == null)
......@@ -479,8 +501,4 @@ class PermissionHandlerPlugin(private val registrar: Registrar, private var requ
return !TextUtils.isEmpty(locationProviders)
}
}
private fun handleSuccess(permissionStatus: PermissionStatus, result: Result?) {
result?.success(Codec.encodePermissionStatus(permissionStatus))
}
}
package com.baseflow.permissionhandler.data
import com.google.gson.annotations.SerializedName
enum class ServiceStatus {
@SerializedName("unknown")
UNKNOWN,
@SerializedName("disabled")
DISABLED,
@SerializedName("enabled")
ENABLED,
@SerializedName("notApplicable")
NOT_APPLICABLE,
}
\ No newline at end of file
......@@ -2,6 +2,7 @@ package com.baseflow.permissionhandler.utils
import com.baseflow.permissionhandler.data.PermissionGroup
import com.baseflow.permissionhandler.data.PermissionStatus
import com.baseflow.permissionhandler.data.ServiceStatus
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
......@@ -29,6 +30,11 @@ class Codec {
}
@JvmStatic
fun encodeServiceStatus(serviceStatus: ServiceStatus) : String {
return gsonDecoder.toJson(serviceStatus)
}
@JvmStatic
fun encodePermissionRequestResult(permissionResults: Map<PermissionGroup, PermissionStatus>) : String {
val jsonString = gsonDecoder.toJson(permissionResults)
return jsonString
......
......@@ -98,12 +98,27 @@ class _PermissionState extends State<PermissionWidget> {
_permissionStatus.toString(),
style: TextStyle(color: getPermissionColor()),
),
onTap: () async {
trailing: IconButton(
icon: const Icon(Icons.info),
onPressed: () {
checkServiceStatus(context, _permissionGroup);
}),
onTap: () {
requestPermission(_permissionGroup);
},
);
}
void checkServiceStatus(BuildContext context, PermissionGroup permission) {
PermissionHandler().checkServiceStatus(permission)
.then((ServiceStatus serviceStatus) {
final SnackBar snackBar = SnackBar(
content: Text(serviceStatus.toString()));
Scaffold.of(context).showSnackBar(snackBar);
});
}
void requestPermission(PermissionGroup permission) {
final List<PermissionGroup> permissions = <PermissionGroup>[permission];
final Future<Map<PermissionGroup, PermissionStatus>> requestFuture =
......
......@@ -22,6 +22,13 @@ class PermissionManager: NSObject {
result(Codec.encodePermissionStatus(permissionStatus: permissionStatus))
}
static func checkServiceStatus(permission: PermissionGroup, result: @escaping FlutterResult) {
let permissionStrategy = PermissionManager.createPermissionStrategy(permission: permission)
let serviceStatus = permissionStrategy.checkServiceStatus(permission: permission)
result(Codec.encodeServiceStatus(serviceStatus: serviceStatus))
}
func requestPermissions(permissions: [PermissionGroup], completion: @escaping PermissionRequestCompletion) {
var requestQueue = Set(permissions.map { $0 })
var permissionStatusResult: [PermissionGroup: PermissionStatus] = [:]
......
......@@ -25,6 +25,12 @@ public class SwiftPermissionHandlerPlugin: NSObject, FlutterPlugin {
PermissionManager.checkPermissionStatus(
permission: permission,
result: result)
} else if call.method == "checkServiceStatus" {
let permission: PermissionGroup = Codec.decodePermissionGroup(from: call.arguments)
PermissionManager.checkServiceStatus(
permission: permission,
result: result)
} else if call.method == "requestPermissions" {
if _methodResult != nil {
result(FlutterError(
......
//
// ServiceStatus.swift
// permission_handler
//
// Created by Maurits van Beusekom on 12/02/2019.
//
import Foundation
enum ServiceStatus : String, Codable {
case disabled = "disabled"
case enabled = "enabled"
case notApplicable = "notApplicable"
case unknown = "unknown"
}
......@@ -19,6 +19,10 @@ class AudioVideoPermissionStrategy : NSObject, PermissionStrategy {
return PermissionStatus.unknown
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return ServiceStatus.notApplicable
}
private static func getPermissionStatus(mediaType: AVMediaType) -> PermissionStatus {
let status: AVAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: mediaType)
......
......@@ -45,6 +45,10 @@ class ContactPermissionStrategy : NSObject, PermissionStrategy {
}
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return ServiceStatus.notApplicable
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let permissionStatus = checkPermissionStatus(permission: permission)
......
......@@ -36,6 +36,10 @@ class EventPermissionStrategy : NSObject, PermissionStrategy {
}
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return ServiceStatus.notApplicable
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let permissionStatus = checkPermissionStatus(permission: permission)
......
......@@ -23,13 +23,19 @@ class LocationPermissionStrategy : NSObject, PermissionStrategy, CLLocationManag
permission: permission,
authorizationStatus: authorizationStatus)
if permissionStatus == PermissionStatus.granted && !CLLocationManager.locationServicesEnabled() {
if (permissionStatus == PermissionStatus.granted || permissionStatus == PermissionStatus.denied) && !CLLocationManager.locationServicesEnabled() {
return PermissionStatus.disabled
}
return permissionStatus
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return CLLocationManager.locationServicesEnabled()
? ServiceStatus.enabled
: ServiceStatus.disabled
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let permissionStatus = checkPermissionStatus(permission: permission)
......
......@@ -24,6 +24,10 @@ class MediaLibraryPermissionStrategy : NSObject, PermissionStrategy {
return PermissionStatus.unknown
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return ServiceStatus.notApplicable
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) -> Void {
let status = checkPermissionStatus(permission: permission)
if status != PermissionStatus.unknown {
......
......@@ -11,5 +11,6 @@ typealias PermissionStatusHandler = (_ permissionStatus: PermissionStatus) -> Vo
protocol PermissionStrategy {
func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler)
}
......@@ -20,6 +20,10 @@ class PhotoPermissionStrategy : NSObject, PermissionStrategy {
return PhotoPermissionStrategy.determinePermissionStatus(authorizationStatus: status)
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return ServiceStatus.notApplicable
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let status = checkPermissionStatus(permission: permission)
......
......@@ -30,7 +30,7 @@ class SensorPermissionStrategy : NSObject, PermissionStrategy {
permissionStatus = PermissionStatus.unknown
}
if permissionStatus == PermissionStatus.granted && !CMMotionActivityManager.isActivityAvailable() {
if (permissionStatus == PermissionStatus.granted || permissionStatus == PermissionStatus.denied) && !CMMotionActivityManager.isActivityAvailable() {
return PermissionStatus.disabled
} else {
return permissionStatus
......@@ -40,6 +40,16 @@ class SensorPermissionStrategy : NSObject, PermissionStrategy {
return PermissionStatus.unknown
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
if #available(iOS 11.0, *) {
return CMMotionActivityManager.isActivityAvailable()
? ServiceStatus.enabled
: ServiceStatus.disabled
}
return ServiceStatus.unknown
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let status = checkPermissionStatus(permission: permission)
......
......@@ -24,6 +24,10 @@ class SpeechPermissionStrategy : NSObject, PermissionStrategy {
return PermissionStatus.unknown
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return ServiceStatus.notApplicable
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let status = checkPermissionStatus(permission: permission)
......
......@@ -12,6 +12,10 @@ class UnknownPermissionStrategy : NSObject, PermissionStrategy {
return PermissionStatus.unknown
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return ServiceStatus.unknown
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
completionHandler(PermissionStatus.unknown)
}
......
......@@ -31,6 +31,11 @@ struct Codec {
return status
}
static func encodeServiceStatus(serviceStatus: ServiceStatus) -> String? {
let status = "\"" + serviceStatus.rawValue + "\""
return status
}
static func encodePermissionRequestResult(permissionStatusResult: [PermissionGroup: PermissionStatus]) -> String? {
let jsonDict = Dictionary(uniqueKeysWithValues:
permissionStatusResult.map {
......
......@@ -3,7 +3,7 @@
#
Pod::Spec.new do |s|
s.name = 'permission_handler'
s.version = '2.1.3'
s.version = '2.2.0'
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.
......
......@@ -18,6 +18,21 @@ enum PermissionStatus {
unknown
}
/// Defines the state of a service related to the permission group
enum ServiceStatus {
/// The unknown service status indicates the state of the service could not be determined.
unknown,
/// There is not separate service for the supplied permission group.
notApplicable,
/// The service for the supplied permission group is disabled.
disabled,
/// The service for the supplied permission group is enabled.
enabled
}
/// Defines the permission groups for which permissions can be checked or requested.
enum PermissionGroup {
/// The unknown permission only used for return type, never requested
......
......@@ -29,20 +29,35 @@ class PermissionHandler {
final MethodChannel _methodChannel;
/// Check current permission status.
///
/// Returns a [Future] containing the current permission status for the supplied [PermissionGroup].
Future<PermissionStatus> checkPermissionStatus(
PermissionGroup permission) async {
final String status = await _methodChannel.invokeMethod(
final String status = await _methodChannel.invokeMethod<String>(
'checkPermissionStatus', Codec.encodePermissionGroup(permission));
return Codec.decodePermissionStatus(status);
}
/// Check current service status.
///
/// Returns a [Future] containing the current service status for the supplied [PermissionGroup].
Future<ServiceStatus> checkServiceStatus(
PermissionGroup permission) async {
final String status = await _methodChannel.invokeMethod<String>(
'checkServiceStatus', Codec.encodePermissionGroup(permission));
return Codec.decodeServiceStatus(status);
}
/// Open the App settings page.
///
/// 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 bool hasOpened = await _methodChannel.invokeMethod<bool>(
'openAppSettings');
return hasOpened;
}
......@@ -53,7 +68,8 @@ class PermissionHandler {
List<PermissionGroup> permissions) async {
final String jsonData = Codec.encodePermissionGroups(permissions);
final String status =
await _methodChannel.invokeMethod('requestPermissions', jsonData);
await _methodChannel.invokeMethod<String>(
'requestPermissions', jsonData);
return Codec.decodePermissionRequestResult(status);
}
......@@ -68,7 +84,7 @@ class PermissionHandler {
return false;
}
final bool shouldShowRationale = await _methodChannel.invokeMethod(
final bool shouldShowRationale = await _methodChannel.invokeMethod<bool>(
'shouldShowRequestPermissionRationale',
Codec.encodePermissionGroup(permission));
......
......@@ -2,12 +2,19 @@ part of permission_handler;
class Codec {
static PermissionStatus decodePermissionStatus(String value) {
final dynamic permission = json.decode(value);
final String permission = json.decode(value);
return PermissionStatus.values.firstWhere(
(PermissionStatus e) => e.toString().split('.').last == permission);
}
static ServiceStatus decodeServiceStatus(String value) {
final String status = json.decode(value);
return ServiceStatus.values.firstWhere(
(ServiceStatus s) => s.toString().split('.').last == status);
}
static Map<PermissionGroup, PermissionStatus> decodePermissionRequestResult(
String value) {
final Map<String, dynamic> jsonObject = json.decode(value);
......
name: permission_handler
description: Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions.
version: 2.1.3
version: 2.2.0
author: Baseflow <hello@baseflow.com>
homepage: https://github.com/baseflowit/flutter-permission-handler
......
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