Commit b97a0603 by Maurits van Beusekom

Release permission_handler 5.0.0 and

permission_handler_platform_interface 2.0.0
parents 9b12a9f8 0f4ee3ad
## 5.0.0
* **BREAKING**: Implemented more intuitive API exposed by `permission_handler_platform_interface: 2.0.0` ([#230](https://github.com/Baseflow/flutter-permission-handler/issues/230)).
## 4.4.0+hotfix.2 ## 4.4.0+hotfix.2
* Issue #235: Solved a bug which made it impossible to request service status on Android 7; * Issue #235: Solved a bug which made it impossible to request service status on Android 7;
......
...@@ -5,26 +5,35 @@ import android.content.Intent; ...@@ -5,26 +5,35 @@ import android.content.Intent;
import android.util.Log; import android.util.Log;
final class AppSettingsManager { final class AppSettingsManager {
boolean openAppSettings(Context applicationContext) { @FunctionalInterface
if (applicationContext == null) { interface OpenAppSettingsSuccessCallback {
Log.d(PermissionConstants.LOG_TAG, "Unable to detect current Activity or App Context."); void onSuccess(boolean appSettingsOpenedSuccessfully);
return false; }
void openAppSettings(
Context context,
OpenAppSettingsSuccessCallback successCallback,
ErrorCallback errorCallback) {
if(context == null) {
Log.d(PermissionConstants.LOG_TAG, "Context cannot be null.");
errorCallback.onError("PermissionHandler.AppSettingsManager", "Android context cannot be null.");
return;
} }
try { try {
Intent settingsIntent = new Intent(); Intent settingsIntent = new Intent();
settingsIntent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); settingsIntent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
settingsIntent.addCategory(Intent.CATEGORY_DEFAULT); settingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
settingsIntent.setData(android.net.Uri.parse("package:" + applicationContext.getPackageName())); settingsIntent.setData(android.net.Uri.parse("package:" + context.getPackageName()));
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); settingsIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
applicationContext.startActivity(settingsIntent); context.startActivity(settingsIntent);
return true; successCallback.onSuccess(true);
} catch (Exception ex) { } catch (Exception ex) {
return false; successCallback.onSuccess(false);
} }
} }
} }
package com.baseflow.permissionhandler;
@FunctionalInterface
interface ErrorCallback {
void onError(String errorCode, String errorDescription);
}
...@@ -51,25 +51,31 @@ final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler { ...@@ -51,25 +51,31 @@ final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler {
public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result)
{ {
switch (call.method) { switch (call.method) {
case "checkPermissionStatus": { case "checkServiceStatus": {
@PermissionConstants.PermissionGroup final int permission = Integer.parseInt(call.arguments.toString()); @PermissionConstants.PermissionGroup final int permission = Integer.parseInt(call.arguments.toString());
@PermissionConstants.PermissionStatus final int permissionStatus = serviceManager.checkServiceStatus(
permissionManager.checkPermissionStatus(
permission, permission,
applicationContext, applicationContext,
activity); result::success,
(String errorCode, String errorDescription) -> result.error(
errorCode,
errorDescription,
null));
result.success(permissionStatus);
break; break;
} }
case "checkServiceStatus": { case "checkPermissionStatus": {
@PermissionConstants.PermissionGroup final int permission = Integer.parseInt(call.arguments.toString()); @PermissionConstants.PermissionGroup final int permission = Integer.parseInt(call.arguments.toString());
@PermissionConstants.ServiceStatus final int serviceStatus = permissionManager.checkPermissionStatus(
serviceManager.checkServiceStatus(
permission, permission,
applicationContext); applicationContext,
activity,
result::success,
(String errorCode, String errorDescription) -> result.error(
errorCode,
errorDescription,
null));
result.success(serviceStatus);
break; break;
} }
case "requestPermissions": case "requestPermissions":
...@@ -88,14 +94,26 @@ final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler { ...@@ -88,14 +94,26 @@ final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler {
break; break;
case "shouldShowRequestPermissionRationale": { case "shouldShowRequestPermissionRationale": {
@PermissionConstants.PermissionGroup final int permission = Integer.parseInt(call.arguments.toString()); @PermissionConstants.PermissionGroup final int permission = Integer.parseInt(call.arguments.toString());
final boolean showRationale = permissionManager permissionManager.shouldShowRequestPermissionRationale(
.shouldShowRequestPermissionRationale(permission, activity); permission,
result.success(showRationale); activity,
result::success,
(String errorCode, String errorDescription) -> result.error(
errorCode,
errorDescription,
null));
break; break;
} }
case "openAppSettings": case "openAppSettings":
boolean isOpen = appSettingsManager.openAppSettings(applicationContext); appSettingsManager.openAppSettings(
result.success(isOpen); applicationContext,
result::success,
(String errorCode, String errorDescription) -> result.error(
errorCode,
errorDescription,
null));
break; break;
default: default:
result.notImplemented(); result.notImplemented();
......
...@@ -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 {
...@@ -80,14 +80,12 @@ final class PermissionConstants { ...@@ -80,14 +80,12 @@ final class PermissionConstants {
static final int SERVICE_STATUS_DISABLED = 0; static final int SERVICE_STATUS_DISABLED = 0;
static final int SERVICE_STATUS_ENABLED = 1; static final int SERVICE_STATUS_ENABLED = 1;
static final int SERVICE_STATUS_NOT_APPLICABLE = 2; static final int SERVICE_STATUS_NOT_APPLICABLE = 2;
static final int SERVICE_STATUS_UNKNOWN = 3;
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef({ @IntDef({
SERVICE_STATUS_DISABLED, SERVICE_STATUS_DISABLED,
SERVICE_STATUS_ENABLED, SERVICE_STATUS_ENABLED,
SERVICE_STATUS_NOT_APPLICABLE, SERVICE_STATUS_NOT_APPLICABLE
SERVICE_STATUS_UNKNOWN,
}) })
@interface ServiceStatus { @interface ServiceStatus {
} }
......
...@@ -238,9 +238,9 @@ public class PermissionUtils { ...@@ -238,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;
} }
...@@ -265,23 +265,12 @@ public class PermissionUtils { ...@@ -265,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)
...@@ -298,7 +287,7 @@ public class PermissionUtils { ...@@ -298,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);
} }
......
...@@ -17,34 +17,45 @@ import android.util.Log; ...@@ -17,34 +17,45 @@ import android.util.Log;
import java.util.List; import java.util.List;
final class ServiceManager { final class ServiceManager {
@PermissionConstants.ServiceStatus @FunctionalInterface
int checkServiceStatus( interface SuccessCallback {
void onSuccess(@PermissionConstants.ServiceStatus int serviceStatus);
}
void checkServiceStatus(
int permission, int permission,
Context context) { Context context,
if (context == null) { SuccessCallback successCallback,
Log.d(PermissionConstants.LOG_TAG, "Unable to detect current Activity or App Context."); ErrorCallback errorCallback) {
return PermissionConstants.SERVICE_STATUS_UNKNOWN; if(context == null) {
Log.d(PermissionConstants.LOG_TAG, "Context cannot be null.");
errorCallback.onError("PermissionHandler.ServiceManager", "Android context cannot be null.");
return;
} }
if (permission == PermissionConstants.PERMISSION_GROUP_LOCATION || if (permission == PermissionConstants.PERMISSION_GROUP_LOCATION ||
permission == PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS || permission == PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS ||
permission == PermissionConstants.PERMISSION_GROUP_LOCATION_WHEN_IN_USE) { permission == PermissionConstants.PERMISSION_GROUP_LOCATION_WHEN_IN_USE) {
return isLocationServiceEnabled(context) final int serviceStatus = isLocationServiceEnabled(context)
? PermissionConstants.SERVICE_STATUS_ENABLED ? PermissionConstants.SERVICE_STATUS_ENABLED
: PermissionConstants.SERVICE_STATUS_DISABLED; : PermissionConstants.SERVICE_STATUS_DISABLED;
successCallback.onSuccess(serviceStatus);
} }
if (permission == PermissionConstants.PERMISSION_GROUP_PHONE) { if (permission == PermissionConstants.PERMISSION_GROUP_PHONE) {
PackageManager pm = context.getPackageManager(); PackageManager pm = context.getPackageManager();
if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
return PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE; successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE);
return;
} }
TelephonyManager telephonyManager = (TelephonyManager) context TelephonyManager telephonyManager = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE); .getSystemService(Context.TELEPHONY_SERVICE);
if (telephonyManager == null || telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE) { if (telephonyManager == null || telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE) {
return PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE; successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE);
return;
} }
Intent callIntent = new Intent(Intent.ACTION_CALL); Intent callIntent = new Intent(Intent.ACTION_CALL);
...@@ -52,23 +63,28 @@ final class ServiceManager { ...@@ -52,23 +63,28 @@ final class ServiceManager {
List<ResolveInfo> callAppsList = pm.queryIntentActivities(callIntent, 0); List<ResolveInfo> callAppsList = pm.queryIntentActivities(callIntent, 0);
if (callAppsList.isEmpty()) { if (callAppsList.isEmpty()) {
return PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE; successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE);
return;
} }
if (telephonyManager.getSimState() != TelephonyManager.SIM_STATE_READY) { if (telephonyManager.getSimState() != TelephonyManager.SIM_STATE_READY) {
return PermissionConstants.SERVICE_STATUS_DISABLED; successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_DISABLED);
return;
} }
return PermissionConstants.SERVICE_STATUS_ENABLED; successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_ENABLED);
return;
} }
if (permission == PermissionConstants.PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS) { if (permission == PermissionConstants.PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS) {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M final int serviceStatus = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
? PermissionConstants.SERVICE_STATUS_ENABLED ? PermissionConstants.SERVICE_STATUS_ENABLED
: PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE; : PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE;
successCallback.onSuccess(serviceStatus);
return;
} }
return PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE; successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE);
} }
private boolean isLocationServiceEnabled(Context context) { private boolean isLocationServiceEnabled(Context context) {
...@@ -86,7 +102,7 @@ final class ServiceManager { ...@@ -86,7 +102,7 @@ final class ServiceManager {
} }
} }
// Suppress deprecation warnings since it's 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 isLocationServiceEnabledKitKat(Context context) private static boolean isLocationServiceEnabledKitKat(Context context)
...@@ -109,7 +125,7 @@ final class ServiceManager { ...@@ -109,7 +125,7 @@ final class ServiceManager {
return locationMode != Settings.Secure.LOCATION_MODE_OFF; return locationMode != Settings.Secure.LOCATION_MODE_OFF;
} }
// Suppress deprecation warnings since it's purpose is to support to be backwards compatible with // Suppress deprecation warnings since its purpose is to support to be backwards compatible with
// pre KitKat versions of Android. // pre KitKat versions of Android.
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private static boolean isLocationServiceEnablePreKitKat(Context context) private static boolean isLocationServiceEnablePreKitKat(Context context)
......
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
platform :ios, '8.0' # platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true' ENV['COCOAPODS_DISABLE_STATS'] = 'true'
...@@ -15,96 +15,70 @@ def parse_KV_file(file, separator='=') ...@@ -15,96 +15,70 @@ def parse_KV_file(file, separator='=')
if !File.exists? file_abs_path if !File.exists? file_abs_path
return []; return [];
end end
pods_ary = [] generated_key_values = {}
skip_line_start_symbols = ["#", "/"] skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) { |line| File.foreach(file_abs_path) do |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator) plugin = line.split(pattern=separator)
if plugin.length == 2 if plugin.length == 2
podname = plugin[0].strip() podname = plugin[0].strip()
path = plugin[1].strip() path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path) podpath = File.expand_path("#{path}", file_abs_path)
pods_ary.push({:name => podname, :path => podpath}); generated_key_values[podname] = podpath
else else
puts "Invalid plugin specification: #{line}" puts "Invalid plugin specification: #{line}"
end end
} end
return pods_ary generated_key_values
end end
target 'Runner' do target 'Runner' do
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock # Flutter Pod
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks') copied_flutter_dir = File.join(__dir__, 'Flutter')
system('mkdir -p .symlinks/plugins') copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
# Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
# That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
# CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
unless File.exist?(generated_xcode_build_settings_path)
raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
# Flutter Pods unless File.exist?(copied_framework_path)
generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
if generated_xcode_build_settings.empty? end
puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first." unless File.exist?(copied_podspec_path)
FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
end end
generated_xcode_build_settings.map { |p|
if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
symlink = File.join('.symlinks', 'flutter')
File.symlink(File.dirname(p[:path]), symlink)
pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
end end
}
# Keep pod path relative so it can be checked into Podfile.lock.
pod 'Flutter', :path => 'Flutter'
# Plugin Pods # Plugin Pods
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
plugin_pods = parse_KV_file('../.flutter-plugins') plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.map { |p| plugin_pods.each do |name, path|
symlink = File.join('.symlinks', 'plugins', p[:name]) symlink = File.join('.symlinks', 'plugins', name)
File.symlink(p[:path], symlink) File.symlink(path, symlink)
pod p[:name], :path => File.join(symlink, 'ios') pod name, :path => File.join(symlink, 'ios')
} end
end end
post_install do |installer| post_install do |installer|
installer.pods_project.targets.each do |target| installer.pods_project.targets.each do |target|
target.build_configurations.each do |config| target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO' config.build_settings['ENABLE_BITCODE'] = 'NO'
# You can remove unused permissions here
# for more infomation: https://github.com/BaseflowIT/flutter-permission-handler/blob/develop/ios/Classes/PermissionHandlerEnums.h
# e.g. when you don't need camera permission, just add 'PERMISSION_CAMERA=0'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## dart: PermissionGroup.calendar
# 'PERMISSION_EVENTS=0',
## dart: PermissionGroup.reminders
# 'PERMISSION_REMINDERS=0',
## dart: PermissionGroup.contacts
# 'PERMISSION_CONTACTS=0',
## dart: PermissionGroup.camera
# 'PERMISSION_CAMERA=0',
## dart: PermissionGroup.microphone
# 'PERMISSION_MICROPHONE=0',
## dart: PermissionGroup.speech
# 'PERMISSION_SPEECH_RECOGNIZER=0',
## dart: PermissionGroup.photos
# 'PERMISSION_PHOTOS=0',
## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
# 'PERMISSION_LOCATION=0',
## dart: PermissionGroup.notification
# 'PERMISSION_NOTIFICATIONS=0',
## dart: PermissionGroup.mediaLibrary
# 'PERMISSION_MEDIA_LIBRARY=0',
## dart: PermissionGroup.sensors
# 'PERMISSION_SENSORS=0'
]
end end
end end
end end
...@@ -9,10 +9,6 @@ ...@@ -9,10 +9,6 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
...@@ -28,8 +24,6 @@ ...@@ -28,8 +24,6 @@
dstPath = ""; dstPath = "";
dstSubfolderSpec = 10; dstSubfolderSpec = 10;
files = ( files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
); );
name = "Embed Frameworks"; name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
...@@ -40,7 +34,6 @@ ...@@ -40,7 +34,6 @@
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
4B425729EC83DC3B462CA8DE /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; }; 4B425729EC83DC3B462CA8DE /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
...@@ -49,7 +42,6 @@ ...@@ -49,7 +42,6 @@
89CBFAE60E5774D9B3D21DEF /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; }; 89CBFAE60E5774D9B3D21DEF /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
...@@ -64,8 +56,6 @@ ...@@ -64,8 +56,6 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
B7634AD7E1771AEDD2D1A5F7 /* libPods-Runner.a in Frameworks */, B7634AD7E1771AEDD2D1A5F7 /* libPods-Runner.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
...@@ -84,9 +74,7 @@ ...@@ -84,9 +74,7 @@
9740EEB11CF90186004384FC /* Flutter */ = { 9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */, 9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */,
...@@ -232,7 +220,7 @@ ...@@ -232,7 +220,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
}; };
8BA3EF5BA9C129C83EB3F474 /* [CP] Embed Pods Frameworks */ = { 8BA3EF5BA9C129C83EB3F474 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
...@@ -241,7 +229,7 @@ ...@@ -241,7 +229,7 @@
); );
inputPaths = ( inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios-release/Flutter.framework", "${PODS_ROOT}/../Flutter/Flutter.framework",
); );
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
outputPaths = ( outputPaths = (
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1020" LastUpgradeVersion = "1130"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
...@@ -27,8 +27,6 @@ ...@@ -27,8 +27,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion> <MacroExpansion>
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
...@@ -38,8 +36,8 @@ ...@@ -38,8 +36,8 @@
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<AdditionalOptions> <Testables>
</AdditionalOptions> </Testables>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
...@@ -61,8 +59,6 @@ ...@@ -61,8 +59,6 @@
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Profile" buildConfiguration = "Profile"
......
...@@ -3,6 +3,6 @@ ...@@ -3,6 +3,6 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>BuildSystemType</key> <key>BuildSystemType</key>
<string>Original</string> <string>Latest</string>
</dict> </dict>
</plist> </plist>
...@@ -17,33 +17,31 @@ class MyApp extends StatelessWidget { ...@@ -17,33 +17,31 @@ class MyApp extends StatelessWidget {
actions: <Widget>[ actions: <Widget>[
IconButton( IconButton(
icon: const Icon(Icons.settings), icon: const Icon(Icons.settings),
onPressed: () { onPressed: () async {
PermissionHandler().openAppSettings().then((bool hasOpened) => var hasOpened = openAppSettings();
debugPrint('App Settings opened: ' + hasOpened.toString())); debugPrint('App Settings opened: ' + hasOpened.toString());
}, },
) )
], ],
), ),
body: Center( body: Center(
child: ListView( child: ListView(
children: PermissionGroup.values children: Permission.values
.where((PermissionGroup permission) { .where((Permission permission) {
if (Platform.isIOS) { if (Platform.isIOS) {
return permission != PermissionGroup.unknown && return permission != Permission.unknown &&
permission != PermissionGroup.sms && permission != Permission.sms &&
permission != PermissionGroup.storage && permission != Permission.storage &&
permission != permission != Permission.ignoreBatteryOptimizations &&
PermissionGroup.ignoreBatteryOptimizations && permission != Permission.accessMediaLocation;
permission != PermissionGroup.accessMediaLocation;
} else { } else {
return permission != PermissionGroup.unknown && return permission != Permission.unknown &&
permission != PermissionGroup.mediaLibrary && permission != Permission.mediaLibrary &&
permission != PermissionGroup.photos && permission != Permission.photos &&
permission != PermissionGroup.reminders; permission != Permission.reminders;
} }
}) })
.map((PermissionGroup permission) => .map((permission) => PermissionWidget(permission))
PermissionWidget(permission))
.toList()), .toList()),
), ),
), ),
...@@ -54,20 +52,20 @@ class MyApp extends StatelessWidget { ...@@ -54,20 +52,20 @@ class MyApp extends StatelessWidget {
/// Permission widget which displays a permission and allows users to request /// Permission widget which displays a permission and allows users to request
/// the permissions. /// the permissions.
class PermissionWidget extends StatefulWidget { class PermissionWidget extends StatefulWidget {
/// Constructs a [PermissionWidget] for the supplied [PermissionGroup]. /// Constructs a [PermissionWidget] for the supplied [Permission].
const PermissionWidget(this._permissionGroup); const PermissionWidget(this._permission);
final PermissionGroup _permissionGroup; final Permission _permission;
@override @override
_PermissionState createState() => _PermissionState(_permissionGroup); _PermissionState createState() => _PermissionState(_permission);
} }
class _PermissionState extends State<PermissionWidget> { class _PermissionState extends State<PermissionWidget> {
_PermissionState(this._permissionGroup); _PermissionState(this._permission);
final PermissionGroup _permissionGroup; final Permission _permission;
PermissionStatus _permissionStatus = PermissionStatus.unknown; PermissionStatus _permissionStatus = PermissionStatus.undetermined;
@override @override
void initState() { void initState() {
...@@ -76,15 +74,9 @@ class _PermissionState extends State<PermissionWidget> { ...@@ -76,15 +74,9 @@ class _PermissionState extends State<PermissionWidget> {
_listenForPermissionStatus(); _listenForPermissionStatus();
} }
void _listenForPermissionStatus() { void _listenForPermissionStatus() async {
final Future<PermissionStatus> statusFuture = final status = await _permission.status;
PermissionHandler().checkPermissionStatus(_permissionGroup); setState(() => _permissionStatus = status);
statusFuture.then((PermissionStatus status) {
setState(() {
_permissionStatus = status;
});
});
} }
Color getPermissionColor() { Color getPermissionColor() {
...@@ -101,7 +93,7 @@ class _PermissionState extends State<PermissionWidget> { ...@@ -101,7 +93,7 @@ class _PermissionState extends State<PermissionWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListTile( return ListTile(
title: Text(_permissionGroup.toString()), title: Text(_permission.toString()),
subtitle: Text( subtitle: Text(
_permissionStatus.toString(), _permissionStatus.toString(),
style: TextStyle(color: getPermissionColor()), style: TextStyle(color: getPermissionColor()),
...@@ -109,33 +101,26 @@ class _PermissionState extends State<PermissionWidget> { ...@@ -109,33 +101,26 @@ class _PermissionState extends State<PermissionWidget> {
trailing: IconButton( trailing: IconButton(
icon: const Icon(Icons.info), icon: const Icon(Icons.info),
onPressed: () { onPressed: () {
checkServiceStatus(context, _permissionGroup); checkServiceStatus(context, _permission);
}), }),
onTap: () { onTap: () {
requestPermission(_permissionGroup); requestPermission(_permission);
}, },
); );
} }
void checkServiceStatus(BuildContext context, PermissionGroup permission) { void checkServiceStatus(BuildContext context, Permission permission) async {
PermissionHandler() Scaffold.of(context).showSnackBar(SnackBar(
.checkServiceStatus(permission) content: Text((await permission.status).toString()),
.then((ServiceStatus serviceStatus) { ));
final SnackBar snackBar =
SnackBar(content: Text(serviceStatus.toString()));
Scaffold.of(context).showSnackBar(snackBar);
});
} }
Future<void> requestPermission(PermissionGroup permission) async { Future<void> requestPermission(Permission permission) async {
final List<PermissionGroup> permissions = <PermissionGroup>[permission]; final status = await permission.request();
final Map<PermissionGroup, PermissionStatus> permissionRequestResult =
await PermissionHandler().requestPermissions(permissions);
setState(() { setState(() {
print(permissionRequestResult); print(status);
_permissionStatus = permissionRequestResult[permission]; _permissionStatus = status;
print(_permissionStatus); print(_permissionStatus);
}); });
} }
......
...@@ -107,12 +107,11 @@ typedef NS_ENUM(int, PermissionStatus) { ...@@ -107,12 +107,11 @@ typedef NS_ENUM(int, PermissionStatus) {
PermissionStatusDenied = 0, PermissionStatusDenied = 0,
PermissionStatusGranted, PermissionStatusGranted,
PermissionStatusRestricted, PermissionStatusRestricted,
PermissionStatusUnknown, PermissionStatusNotDetermined,
}; };
typedef NS_ENUM(int, ServiceStatus) { typedef NS_ENUM(int, ServiceStatus) {
ServiceStatusDisabled = 0, ServiceStatusDisabled = 0,
ServiceStatusEnabled, ServiceStatusEnabled,
ServiceStatusNotApplicable, ServiceStatusNotApplicable,
ServiceStatusUnknown,
}; };
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
return PermissionStatusUnknown; return PermissionStatusUnknown;
#endif #endif
} }
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
} }
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission { - (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler { - (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission]; PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) { if (status != PermissionStatusNotDetermined) {
completionHandler(status); completionHandler(status);
return; return;
} }
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
return; return;
#endif #endif
} else { } else {
completionHandler(PermissionStatusUnknown); completionHandler(PermissionStatusNotDetermined);
return; return;
} }
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
switch (status) { switch (status) {
case AVAuthorizationStatusNotDetermined: case AVAuthorizationStatusNotDetermined:
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
case AVAuthorizationStatusRestricted: case AVAuthorizationStatusRestricted:
return PermissionStatusRestricted; return PermissionStatusRestricted;
case AVAuthorizationStatusDenied: case AVAuthorizationStatusDenied:
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
return PermissionStatusGranted; return PermissionStatusGranted;
} }
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
} }
@end @end
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler { - (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission]; PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) { if (status != PermissionStatusNotDetermined) {
completionHandler(status); completionHandler(status);
} }
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
switch (status) { switch (status) {
case CNAuthorizationStatusNotDetermined: case CNAuthorizationStatusNotDetermined:
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
case CNAuthorizationStatusRestricted: case CNAuthorizationStatusRestricted:
return PermissionStatusRestricted; return PermissionStatusRestricted;
case CNAuthorizationStatusDenied: case CNAuthorizationStatusDenied:
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
switch (status) { switch (status) {
case kABAuthorizationStatusNotDetermined: case kABAuthorizationStatusNotDetermined:
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
case kABAuthorizationStatusRestricted: case kABAuthorizationStatusRestricted:
return PermissionStatusRestricted; return PermissionStatusRestricted;
case kABAuthorizationStatusDenied: case kABAuthorizationStatusDenied:
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
} }
} }
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
} }
+ (void)requestPermissionsFromContactStore:(PermissionStatusHandler)completionHandler API_AVAILABLE(ios(9)) { + (void)requestPermissionsFromContactStore:(PermissionStatusHandler)completionHandler API_AVAILABLE(ios(9)) {
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#endif #endif
} }
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
} }
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission { - (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler { - (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus permissionStatus = [self checkPermissionStatus:permission]; PermissionStatus permissionStatus = [self checkPermissionStatus:permission];
if (permissionStatus != PermissionStatusUnknown) { if (permissionStatus != PermissionStatusNotDetermined) {
completionHandler(permissionStatus); completionHandler(permissionStatus);
return; return;
} }
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
return; return;
#endif #endif
} else { } else {
completionHandler(PermissionStatusUnknown); completionHandler(PermissionStatusNotDetermined);
return; return;
} }
...@@ -75,7 +75,7 @@ ...@@ -75,7 +75,7 @@
switch (status) { switch (status) {
case EKAuthorizationStatusNotDetermined: case EKAuthorizationStatusNotDetermined:
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
case EKAuthorizationStatusRestricted: case EKAuthorizationStatusRestricted:
return PermissionStatusRestricted; return PermissionStatusRestricted;
case EKAuthorizationStatusDenied: case EKAuthorizationStatusDenied:
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
return PermissionStatusGranted; return PermissionStatusGranted;
} }
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
} }
@end @end
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
PermissionStatus status = [self checkPermissionStatus:permission]; PermissionStatus status = [self checkPermissionStatus:permission];
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse && permission == PermissionGroupLocationAlways) { if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse && permission == PermissionGroupLocationAlways) {
// don't do anything and continue requesting permissions // don't do anything and continue requesting permissions
} else if (status != PermissionStatusUnknown) { } else if (status != PermissionStatusNotDetermined) {
completionHandler(status); completionHandler(status);
} }
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
if (permission == PermissionGroupLocationAlways) { if (permission == PermissionGroupLocationAlways) {
switch (authorizationStatus) { switch (authorizationStatus) {
case kCLAuthorizationStatusNotDetermined: case kCLAuthorizationStatusNotDetermined:
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
case kCLAuthorizationStatusRestricted: case kCLAuthorizationStatusRestricted:
return PermissionStatusRestricted; return PermissionStatusRestricted;
case kCLAuthorizationStatusDenied: case kCLAuthorizationStatusDenied:
...@@ -118,7 +118,7 @@ ...@@ -118,7 +118,7 @@
switch (authorizationStatus) { switch (authorizationStatus) {
case kCLAuthorizationStatusNotDetermined: case kCLAuthorizationStatusNotDetermined:
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
case kCLAuthorizationStatusRestricted: case kCLAuthorizationStatusRestricted:
return PermissionStatusRestricted; return PermissionStatusRestricted;
case kCLAuthorizationStatusDenied: case kCLAuthorizationStatusDenied:
...@@ -134,7 +134,7 @@ ...@@ -134,7 +134,7 @@
switch (authorizationStatus) { switch (authorizationStatus) {
case kCLAuthorizationStatusNotDetermined: case kCLAuthorizationStatusNotDetermined:
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
case kCLAuthorizationStatusRestricted: case kCLAuthorizationStatusRestricted:
return PermissionStatusRestricted; return PermissionStatusRestricted;
case kCLAuthorizationStatusDenied: case kCLAuthorizationStatusDenied:
...@@ -142,7 +142,7 @@ ...@@ -142,7 +142,7 @@
case kCLAuthorizationStatusAuthorized: case kCLAuthorizationStatusAuthorized:
return PermissionStatusGranted; return PermissionStatusGranted;
default: default:
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
} }
#pragma clang diagnostic pop #pragma clang diagnostic pop
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler { - (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission]; PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) { if (status != PermissionStatusNotDetermined) {
completionHandler(status); completionHandler(status);
return; return;
} }
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
completionHandler([MediaLibraryPermissionStrategy determinePermissionStatus:status]); completionHandler([MediaLibraryPermissionStrategy determinePermissionStatus:status]);
}]; }];
} else { } else {
completionHandler(PermissionStatusUnknown); completionHandler(PermissionStatusNotDetermined);
return; return;
} }
} }
...@@ -41,13 +41,13 @@ ...@@ -41,13 +41,13 @@
return [MediaLibraryPermissionStrategy determinePermissionStatus:status]; return [MediaLibraryPermissionStrategy determinePermissionStatus:status];
} }
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
} }
+ (PermissionStatus)determinePermissionStatus:(MPMediaLibraryAuthorizationStatus)authorizationStatus API_AVAILABLE(ios(9.3)){ + (PermissionStatus)determinePermissionStatus:(MPMediaLibraryAuthorizationStatus)authorizationStatus API_AVAILABLE(ios(9.3)){
switch (authorizationStatus) { switch (authorizationStatus) {
case MPMediaLibraryAuthorizationStatusNotDetermined: case MPMediaLibraryAuthorizationStatusNotDetermined:
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
case MPMediaLibraryAuthorizationStatusDenied: case MPMediaLibraryAuthorizationStatusDenied:
return PermissionStatusDenied; return PermissionStatusDenied;
case MPMediaLibraryAuthorizationStatusRestricted: case MPMediaLibraryAuthorizationStatusRestricted:
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
return PermissionStatusGranted; return PermissionStatusGranted;
} }
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
} }
@end @end
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler { - (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission]; PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) { if (status != PermissionStatusNotDetermined) {
completionHandler(status); completionHandler(status);
return; return;
} }
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
if (settings.authorizationStatus == UNAuthorizationStatusDenied) { if (settings.authorizationStatus == UNAuthorizationStatusDenied) {
permissionStatus = PermissionStatusDenied; permissionStatus = PermissionStatusDenied;
} else if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) { } else if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) {
permissionStatus = PermissionStatusUnknown; permissionStatus = PermissionStatusNotDetermined;
} }
dispatch_semaphore_signal(sem); dispatch_semaphore_signal(sem);
}]; }];
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
@implementation PhonePermissionStrategy @implementation PhonePermissionStrategy
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission { - (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
} }
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission { - (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
} }
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler { - (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
completionHandler(PermissionStatusUnknown); completionHandler(PermissionStatusNotDetermined);
} }
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler { - (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission]; PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) { if (status != PermissionStatusNotDetermined) {
completionHandler(status); completionHandler(status);
return; return;
} }
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
+ (PermissionStatus)determinePermissionStatus:(PHAuthorizationStatus)authorizationStatus { + (PermissionStatus)determinePermissionStatus:(PHAuthorizationStatus)authorizationStatus {
switch (authorizationStatus) { switch (authorizationStatus) {
case PHAuthorizationStatusNotDetermined: case PHAuthorizationStatusNotDetermined:
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
case PHAuthorizationStatusRestricted: case PHAuthorizationStatusRestricted:
return PermissionStatusRestricted; return PermissionStatusRestricted;
case PHAuthorizationStatusDenied: case PHAuthorizationStatusDenied:
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
return PermissionStatusGranted; return PermissionStatusGranted;
} }
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
} }
@end @end
......
...@@ -19,13 +19,13 @@ ...@@ -19,13 +19,13 @@
: ServiceStatusDisabled; : ServiceStatusDisabled;
} }
return ServiceStatusUnknown; return ServiceStatusDisabled;
} }
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler { - (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission]; PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) { if (status != PermissionStatusNotDetermined) {
completionHandler(status); completionHandler(status);
return; return;
} }
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
} }
}]; }];
} else { } else {
completionHandler(PermissionStatusUnknown); completionHandler(PermissionStatusNotDetermined);
} }
} }
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
switch (status) { switch (status) {
case CMAuthorizationStatusNotDetermined: case CMAuthorizationStatusNotDetermined:
permissionStatus = PermissionStatusUnknown; permissionStatus = PermissionStatusNotDetermined;
break; break;
case CMAuthorizationStatusRestricted: case CMAuthorizationStatusRestricted:
permissionStatus = PermissionStatusRestricted; permissionStatus = PermissionStatusRestricted;
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
return permissionStatus; return permissionStatus;
} }
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
} }
@end @end
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler { - (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission]; PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) { if (status != PermissionStatusNotDetermined) {
completionHandler(status); completionHandler(status);
return; return;
} }
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
completionHandler([SpeechPermissionStrategy determinePermissionStatus:authorizationStatus]); completionHandler([SpeechPermissionStrategy determinePermissionStatus:authorizationStatus]);
}]; }];
} else { } else {
completionHandler(PermissionStatusUnknown); completionHandler(PermissionStatusNotDetermined);
} }
} }
...@@ -40,13 +40,13 @@ ...@@ -40,13 +40,13 @@
return [SpeechPermissionStrategy determinePermissionStatus:status]; return [SpeechPermissionStrategy determinePermissionStatus:status];
} }
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
} }
+ (PermissionStatus)determinePermissionStatus:(SFSpeechRecognizerAuthorizationStatus)authorizationStatus API_AVAILABLE(ios(10.0)){ + (PermissionStatus)determinePermissionStatus:(SFSpeechRecognizerAuthorizationStatus)authorizationStatus API_AVAILABLE(ios(10.0)){
switch (authorizationStatus) { switch (authorizationStatus) {
case SFSpeechRecognizerAuthorizationStatusNotDetermined: case SFSpeechRecognizerAuthorizationStatusNotDetermined:
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
case SFSpeechRecognizerAuthorizationStatusDenied: case SFSpeechRecognizerAuthorizationStatusDenied:
return PermissionStatusDenied; return PermissionStatusDenied;
case SFSpeechRecognizerAuthorizationStatusRestricted: case SFSpeechRecognizerAuthorizationStatusRestricted:
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
return PermissionStatusGranted; return PermissionStatusGranted;
} }
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
} }
@end @end
......
...@@ -9,14 +9,14 @@ ...@@ -9,14 +9,14 @@
@implementation UnknownPermissionStrategy @implementation UnknownPermissionStrategy
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission { - (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
return PermissionStatusUnknown; return PermissionStatusNotDetermined;
} }
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission { - (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
return ServiceStatusUnknown; return ServiceStatusDisabled;
} }
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler { - (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
completionHandler(PermissionStatusUnknown); completionHandler(PermissionStatusNotDetermined);
} }
@end @end
...@@ -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+hotfix.2' s.version = '5.0.0'
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.
......
import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart'; import 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart';
export 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart' export 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart'
show PermissionGroup, PermissionStatus, ServiceStatus; show Permission, PermissionStatus, ServiceStatus;
/// The Android and iOS implementation of [PermissionHandlerPlatform]. PermissionHandlerPlatform get _handler => PermissionHandlerPlatform.instance;
/// Opens the app settings page.
/// ///
/// This class implements the `package:permission_handler` functionality for /// Returns [true] if the app settings page could be opened, otherwise [false].
/// the Android and iOS platforms. Future<bool> openAppSettings() => _handler.openAppSettings();
class PermissionHandler extends PermissionHandlerPlatform {
@override
Future<ServiceStatus> checkServiceStatus(PermissionGroup permission) {
return PermissionHandlerPlatform.instance.checkServiceStatus(permission);
}
@override /// Actions that can be executed on a permission.
Future<PermissionStatus> checkPermissionStatus(PermissionGroup permission) { extension PermissionActions on Permission {
return PermissionHandlerPlatform.instance.checkPermissionStatus(permission); /// The current status of this permission.
} Future<PermissionStatus> get status => _handler.checkPermissionStatus(this);
@override /// If you should show a rationale for requesting permission.
Future<bool> openAppSettings() { ///
return PermissionHandlerPlatform.instance.openAppSettings(); /// This is only implemented on Android, calling this on iOS always returns
/// [false].
Future<bool> get shouldShowRequestRationale async {
if (!Platform.isAndroid) {
return false;
} }
@override return _handler.shouldShowRequestPermissionRationale(this);
Future<Map<PermissionGroup, PermissionStatus>> requestPermissions(
List<PermissionGroup> permissions) {
return PermissionHandlerPlatform.instance.requestPermissions(permissions);
} }
@override /// Request the user for access to this [Permission], if access hasn't already
Future<bool> shouldShowRequestPermissionRationale( /// been grant access before.
PermissionGroup permission) { ///
if (!Platform.isAndroid) { /// Returns the new [PermissionStatus].
return Future.value(false); Future<PermissionStatus> request() async {
return (await [this].request())[this];
} }
}
return PermissionHandlerPlatform.instance /// Shortcuts for checking the [status] of a [Permission].
.shouldShowRequestPermissionRationale(permission); extension PermissionCheckShortcuts on Permission {
} /// If this permission was never requested before.
Future<bool> get isUndetermined => status.isUndetermined;
/// If the user granted this permission.
Future<bool> get isGranted => status.isGranted;
/// If the user denied this permission.
Future<bool> get isDenied => status.isDenied;
/// If the OS denied this permission. The user cannot change the status,
/// possibly due to active restrictions such as parental controls being in
/// place.
/// *Only supported on iOS.*
Future<bool> get isRestricted => status.isRestricted;
/// If the user denied this permission and selected to never again show a
/// request for it. The user may still change the permission's status in the
/// device settings.
/// *Only supported on Android.*
Future<bool> get isPermanentlyDenied => status.isPermanentlyDenied;
}
/// Actions that apply only to permissions that have an associated service.
extension ServicePermissionActions on PermissionWithService {
/// Checks the current status of the service associated with this permission.
///
/// Notes about specific permissions:
/// - **[Permission.phone]**
/// - Android:
/// - The method will return [ServiceStatus.notApplicable] when:
/// - the device lacks the TELEPHONY feature
/// - TelephonyManager.getPhoneType() returns PHONE_TYPE_NONE
/// - when no Intents can be resolved to handle the `tel:` scheme
/// - The method will return [ServiceStatus.disabled] when:
/// - the SIM card is missing
/// - iOS:
/// - The method will return [ServiceStatus.notApplicable] when:
/// - the native code can not find a handler for the `tel:` scheme
/// - The method will return [ServiceStatus.disabled] when:
/// - the mobile network code (MNC) is either 0 or 65535. See
/// https://stackoverflow.com/a/11595365 for details
/// - **PLEASE NOTE that this is still not a perfect indication** of the
/// device's capability to place & connect phone calls as it also depends
/// on the network condition.
Future<ServiceStatus> get serviceStatus => _handler.checkServiceStatus(this);
}
/// Actions that can be taken on a [List] of [Permission]s.
extension PermissionListActions on List<Permission> {
/// Requests the user for access to these permissions, if they haven't already
/// been granted before.
///
/// Returns a [Map] containing the status per requested [Permission].
Future<Map<Permission, PermissionStatus>> request() =>
_handler.requestPermissions(this);
} }
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+hotfix.2 version: 5.0.0
homepage: https://github.com/baseflowit/flutter-permission-handler homepage: https://github.com/baseflowit/flutter-permission-handler
flutter: flutter:
...@@ -16,12 +16,12 @@ dependencies: ...@@ -16,12 +16,12 @@ dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
meta: ^1.1.6 meta: ^1.1.6
permission_handler_platform_interface: ^1.0.0 permission_handler_platform_interface: ^2.0.0
dev_dependencies: dev_dependencies:
effective_dart: ^1.2.1 effective_dart: ^1.2.1
plugin_platform_interface: ^1.0.1 plugin_platform_interface: ^1.0.1
environment: environment:
sdk: ">=2.1.0 <3.0.0" sdk: ">=2.7.0 <3.0.0"
flutter: ">=1.12.8 <2.0.0" flutter: ">=1.12.8 <2.0.0"
## 2.0.0
- **BREAKING**: Created a much more intuitive API using Dart's new extension methods ([#230](https://github.com/Baseflow/flutter-permission-handler/issues/230)). Big thank you to [@marcelgarus](https://github.com/marcelgarus) for the idea and doing all the grunt work.
## 1.0.0 ## 1.0.0
- Initial open-source release. - Initial open-source release.
...@@ -5,4 +5,6 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart'; ...@@ -5,4 +5,6 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'src/method_channel/method_channel_permission_handler.dart'; import 'src/method_channel/method_channel_permission_handler.dart';
part 'src/permission_handler_platform_interface.dart'; part 'src/permission_handler_platform_interface.dart';
part 'src/permission_handler_enums.dart'; part 'src/permission_status.dart';
part 'src/permissions.dart';
part 'src/service_status.dart';
...@@ -8,78 +8,72 @@ import 'utils/codec.dart'; ...@@ -8,78 +8,72 @@ import 'utils/codec.dart';
const MethodChannel _methodChannel = const MethodChannel _methodChannel =
MethodChannel('flutter.baseflow.com/permissions/methods'); MethodChannel('flutter.baseflow.com/permissions/methods');
/// An implementation of [PermissionHandlerPlatform] that uses method channels. /// An implementation of [PermissionHandlerPlatform] that uses [MethodChannel]s.
class MethodChannelPermissionHandler extends PermissionHandlerPlatform { class MethodChannelPermissionHandler extends PermissionHandlerPlatform {
/// Check current permission status. /// Checks the current status of the given [Permission].
/// Future<PermissionStatus> checkPermissionStatus(Permission permission) async {
/// Returns a [Future] containing the current permission status for the
/// supplied [PermissionGroup].
Future<PermissionStatus> checkPermissionStatus(
PermissionGroup permission) async {
final status = await _methodChannel.invokeMethod( final status = await _methodChannel.invokeMethod(
'checkPermissionStatus', permission.value); 'checkPermissionStatus', permission.value);
return Codec.decodePermissionStatus(status); return Codec.decodePermissionStatus(status);
} }
/// Check current service status. /// Checks the current status of the service associated with the given
/// /// [Permission].
/// Returns a [Future] containing the current service status for the supplied
/// [PermissionGroup].
/// ///
/// Notes about specific PermissionGroups: /// Notes about specific permissions:
/// - **PermissionGroup.phone** /// - **[Permission.phone]**
/// - Android: /// - Android:
/// - The method will return [ServiceStatus.notApplicable] when: /// - The method will return [ServiceStatus.notApplicable] when:
/// 1. the device lacks the TELEPHONY feature /// - the device lacks the TELEPHONY feature
/// 1. TelephonyManager.getPhoneType() returns PHONE_TYPE_NONE /// - TelephonyManager.getPhoneType() returns PHONE_TYPE_NONE
/// 1. when no Intents can be resolved to handle the `tel:` scheme /// - when no Intents can be resolved to handle the `tel:` scheme
/// - The method will return [ServiceStatus.disabled] when: /// - The method will return [ServiceStatus.disabled] when:
/// 1. the SIM card is missing /// - the SIM card is missing
/// - iOS: /// - iOS:
/// - The method will return [ServiceStatus.notApplicable] when: /// - The method will return [ServiceStatus.notApplicable] when:
/// 1. the native code can not find a handler for the `tel:` scheme /// - the native code can not find a handler for the `tel:` scheme
/// - The method will return [ServiceStatus.disabled] when: /// - The method will return [ServiceStatus.disabled] when:
/// 1. the mobile network code (MNC) is either 0 or 65535. See /// - the mobile network code (MNC) is either 0 or 65535. See
/// https://stackoverflow.com/a/11595365 for details /// https://stackoverflow.com/a/11595365 for details
/// - **PLEASE NOTE that this is still not a perfect indication** of the /// - **PLEASE NOTE that this is still not a perfect indication** of the
/// devices' capability to place & connect phone calls /// device's capability to place & connect phone calls as it also depends
/// as it also depends on the network condition. /// on the network condition.
Future<ServiceStatus> checkServiceStatus(PermissionGroup permission) async { Future<ServiceStatus> checkServiceStatus(Permission permission) async {
final status = await _methodChannel.invokeMethod( final status = await _methodChannel.invokeMethod(
'checkServiceStatus', permission.value); 'checkServiceStatus', permission.value);
return Codec.decodeServiceStatus(status); return Codec.decodeServiceStatus(status);
} }
/// Open the App settings page. /// Opens the app settings page.
/// ///
/// Returns [true] if the app settings page could be opened, /// Returns [true] if the app settings page could be opened, otherwise
/// otherwise [false] is returned. /// [false].
Future<bool> openAppSettings() async { Future<bool> openAppSettings() async {
final hasOpened = await _methodChannel.invokeMethod('openAppSettings'); final wasOpened = await _methodChannel.invokeMethod('openAppSettings');
return wasOpened;
return hasOpened;
} }
/// Request the user for access to the supplied list of permissiongroups. /// Requests the user for access to the supplied list of [Permission]s, if
/// they have not already been granted before.
/// ///
/// Returns a [Map] containing the status per requested permissiongroup. /// Returns a [Map] containing the status per requested [Permission].
Future<Map<PermissionGroup, PermissionStatus>> requestPermissions( Future<Map<Permission, PermissionStatus>> requestPermissions(
List<PermissionGroup> permissions) async { List<Permission> permissions) async {
final data = Codec.encodePermissionGroups(permissions); final data = Codec.encodePermissions(permissions);
final status = final status =
await _methodChannel.invokeMethod('requestPermissions', data); await _methodChannel.invokeMethod('requestPermissions', data);
return Codec.decodePermissionRequestResult(Map<int, int>.from(status)); return Codec.decodePermissionRequestResult(Map<int, int>.from(status));
} }
/// Request to see if you should show a rationale for requesting permission. /// Checks if you should show a rationale for requesting permission.
/// ///
/// This method is only implemented on Android, calling this on iOS always /// This method is only implemented on Android, calling this on iOS always
/// returns [false]. /// returns [false].
Future<bool> shouldShowRequestPermissionRationale( Future<bool> shouldShowRequestPermissionRationale(
PermissionGroup permission) async { Permission permission) async {
final shouldShowRationale = await _methodChannel.invokeMethod( final shouldShowRationale = await _methodChannel.invokeMethod(
'shouldShowRequestPermissionRationale', permission.value); 'shouldShowRequestPermissionRationale', permission.value);
......
import '../../../permission_handler_platform_interface.dart'; import '../../../permission_handler_platform_interface.dart';
/// Provides utility methods for encoding messages that are send on the Flutter /// Provides utility methods for encoding messages that are sent on the Flutter
/// message channel. /// message channel.
class Codec { class Codec {
/// Converts the supplied integer value into a [PermissionStatus] instance. /// Converts the given [value] into a [PermissionStatus] instance.
static PermissionStatus decodePermissionStatus(int value) { static PermissionStatus decodePermissionStatus(int value) {
return PermissionStatus.values[value]; return PermissionStatusValue.statusByValue(value);
} }
/// Converts the supplied integer value into a [ServiceStatus] instance. /// Converts the given [value] into a [ServiceStatus] instance.
static ServiceStatus decodeServiceStatus(int value) { static ServiceStatus decodeServiceStatus(int value) {
return ServiceStatus.values[value]; return ServiceStatusValue.statusByValue(value);
} }
/// Converts the supplied [Map] of integers into a [Map] of /// Converts the given [Map] of [int]s into a [Map] with [Permission]s as
/// [PermissionGroup] key and [PermissionStatus] value instances. /// keys and their respective [PermissionStatus] as value.
static Map<PermissionGroup, PermissionStatus> decodePermissionRequestResult( static Map<Permission, PermissionStatus> decodePermissionRequestResult(
Map<int, int> value) { Map<int, int> value) {
return value.map((key, value) => return value.map((key, value) => MapEntry<Permission, PermissionStatus>(
MapEntry<PermissionGroup, PermissionStatus>( Permission.byValue(key), PermissionStatusValue.statusByValue(value)));
PermissionGroup.values[key], PermissionStatus.values[value]));
} }
/// Converts the supplied [List] containing [PermissionGroup] instances into /// Converts the given [List] of [Permission]s into a [List] of [int]s which
/// a [List] containing integers which can be used to send on the Flutter /// can be sent on the Flutter method channel.
/// method channel. static List<int> encodePermissions(List<Permission> permissions) {
static List<int> encodePermissionGroups(List<PermissionGroup> permissions) {
return permissions.map((it) => it.value).toList(); return permissions.map((it) => it.value).toList();
} }
} }
part of permission_handler_platform_interface;
/// Defines the state of a permission group
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.
static const PermissionStatus denied = PermissionStatus._(0);
/// Permission to access the requested feature is granted by the user.
static const PermissionStatus granted = PermissionStatus._(1);
/// 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._(2);
/// Permission is in an unknown state
static const PermissionStatus unknown = PermissionStatus._(3);
/// Permission to access the requested feature is denied by the user and
/// never show selected (only on Android).
static const PermissionStatus neverAskAgain = PermissionStatus._(4);
/// Returns a list of all possible [PermissionStatus] values.
static const List<PermissionStatus> values = <PermissionStatus>[
denied,
granted,
restricted,
unknown,
neverAskAgain,
];
static const List<String> _names = <String>[
'denied',
'granted',
'restricted',
'unknown',
'neverAskAgain',
];
@override
String toString() => 'PermissionStatus.${_names[value]}';
}
/// Defines the state of a service related to the permission group
class ServiceStatus {
const ServiceStatus._(this.value);
/// Integer representation of the [ServiceStatus].
final int value;
/// The service for the supplied permission group is disabled.
static const ServiceStatus disabled = ServiceStatus._(0);
/// The service for the supplied permission group is enabled.
static const ServiceStatus enabled = ServiceStatus._(1);
/// 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.
static const ServiceStatus unknown = ServiceStatus._(3);
/// Returns a list of all possible [ServiceStatus] values.
static const List<ServiceStatus> values = <ServiceStatus>[
disabled,
enabled,
notApplicable,
unknown,
];
static const List<String> _names = <String>[
'disabled',
'enabled',
'notApplicable',
'unknown',
];
@override
String toString() => 'ServiceStatus.${_names[value]}';
}
/// 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
/// iOS: Calendar (Events)
static const PermissionGroup calendar = PermissionGroup._(0);
/// Android: Camera
/// iOS: Photos (Camera Roll and Camera)
static const PermissionGroup camera = PermissionGroup._(1);
/// Android: Contacts
/// iOS: AddressBook
static const PermissionGroup contacts = PermissionGroup._(2);
/// Android: Fine and Coarse Location
/// iOS: CoreLocation (Always and WhenInUse)
static const PermissionGroup location = PermissionGroup._(3);
/// Android:
/// When running on Android < Q: Fine and Coarse Location
/// When running on Android Q and above: Background Location Permission
/// iOS: CoreLocation - Always
static const PermissionGroup locationAlways = PermissionGroup._(4);
/// Android: Fine and Coarse Location
/// iOS: CoreLocation - WhenInUse
static const PermissionGroup locationWhenInUse = PermissionGroup._(5);
/// Android: None
/// iOS: MPMediaLibrary
static const PermissionGroup mediaLibrary = PermissionGroup._(6);
/// Android: Microphone
/// iOS: Microphone
static const PermissionGroup microphone = PermissionGroup._(7);
/// Android: Phone
/// iOS: Nothing
static const PermissionGroup phone = PermissionGroup._(8);
/// Android: Nothing
/// iOS: Photos
static const PermissionGroup photos = PermissionGroup._(9);
/// Android: Nothing
/// iOS: Reminders
static const PermissionGroup reminders = PermissionGroup._(10);
/// Android: Body Sensors
/// iOS: CoreMotion
static const PermissionGroup sensors = PermissionGroup._(11);
/// Android: Sms
/// iOS: Nothing
static const PermissionGroup sms = PermissionGroup._(12);
/// Android: Microphone
/// iOS: Speech
static const PermissionGroup speech = PermissionGroup._(13);
/// Android: External Storage
/// iOS: Access to folders like `Documents` or `Downloads`. Implicitly
/// granted.
static const PermissionGroup storage = PermissionGroup._(14);
/// Android: Ignore Battery Optimizations
static const PermissionGroup ignoreBatteryOptimizations =
PermissionGroup._(15);
/// Android: Notification
/// iOS: Notification
static const PermissionGroup notification = PermissionGroup._(16);
/// Android: Allows an application to access any geographic locations
/// persisted in the user's shared collection.
static const PermissionGroup accessMediaLocation = PermissionGroup._(17);
/// When running on Android Q and above: Activity Recognition
/// When running on Android < Q: Nothing
/// iOS: Nothing
static const PermissionGroup activityRecognition = PermissionGroup._(18);
/// The unknown permission only used for return type, never requested
static const PermissionGroup unknown = PermissionGroup._(19);
/// Returns a list of all possible [PermissionGroup] values.
static const List<PermissionGroup> values = <PermissionGroup>[
calendar,
camera,
contacts,
location,
locationAlways,
locationWhenInUse,
mediaLibrary,
microphone,
phone,
photos,
reminders,
sensors,
sms,
speech,
storage,
ignoreBatteryOptimizations,
notification,
accessMediaLocation,
activityRecognition,
unknown,
];
static const List<String> _names = <String>[
'calendar',
'camera',
'contacts',
'location',
'locationAlways',
'locationWhenInUse',
'mediaLibrary',
'microphone',
'phone',
'photos',
'reminders',
'sensors',
'sms',
'speech',
'storage',
'ignoreBatteryOptimizations',
'notification',
'access_media_location',
'activity_recognition',
'unknown',
];
@override
String toString() => 'PermissionGroup.${_names[value]}';
}
part of permission_handler_platform_interface; part of permission_handler_platform_interface;
/// The interface that implementations of permission_handler must implement. /// The interface that implementations of `permission_handler` must implement.
/// ///
/// Platform implementations should extend this class rather than implement it /// Platform implementations should extend this class rather than implement it
/// as `permission_handler` does not consider newly added methods to be /// as `permission_handler` does not consider newly added methods to be
...@@ -21,71 +21,67 @@ abstract class PermissionHandlerPlatform extends PlatformInterface { ...@@ -21,71 +21,67 @@ 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;
} }
/// Check current permission status. /// Checks the current status of the given [Permission].
/// Future<PermissionStatus> checkPermissionStatus(Permission permission) {
/// Returns a [Future] containing the current permission status for the
/// supplied [PermissionGroup].
Future<PermissionStatus> checkPermissionStatus(PermissionGroup permission) {
throw UnimplementedError( throw UnimplementedError(
'checkPermissionStatus() has not been implemented.'); 'checkPermissionStatus() has not been implemented.');
} }
/// Check current service status. /// Checks the current status of the service associated with the given
/// /// [Permission].
/// Returns a [Future] containing the current service status for the supplied
/// [PermissionGroup].
/// ///
/// Notes about specific PermissionGroups: /// Notes about specific permissions:
/// - **PermissionGroup.phone** /// - **[Permission.phone]**
/// - Android: /// - Android:
/// - The method will return [ServiceStatus.notApplicable] when: /// - The method will return [ServiceStatus.notApplicable] when:
/// 1. the device lacks the TELEPHONY feature /// - the device lacks the TELEPHONY feature
/// 1. TelephonyManager.getPhoneType() returns PHONE_TYPE_NONE /// - TelephonyManager.getPhoneType() returns PHONE_TYPE_NONE
/// 1. when no Intents can be resolved to handle the `tel:` scheme /// - when no Intents can be resolved to handle the `tel:` scheme
/// - The method will return [ServiceStatus.disabled] when: /// - The method will return [ServiceStatus.disabled] when:
/// 1. the SIM card is missing /// - the SIM card is missing
/// - iOS: /// - iOS:
/// - The method will return [ServiceStatus.notApplicable] when: /// - The method will return [ServiceStatus.notApplicable] when:
/// 1. the native code can not find a handler for the `tel:` scheme /// - the native code can not find a handler for the `tel:` scheme
/// - The method will return [ServiceStatus.disabled] when: /// - The method will return [ServiceStatus.disabled] when:
/// 1. the mobile network code (MNC) is either 0 or 65535. See /// - the mobile network code (MNC) is either 0 or 65535. See
/// https://stackoverflow.com/a/11595365 for details /// https://stackoverflow.com/a/11595365 for details
/// - **PLEASE NOTE that this is still not a perfect indication** of the /// - **PLEASE NOTE that this is still not a perfect indication** of the
/// devices' capability to place & connect phone calls /// device's capability to place & connect phone calls as it also depends
/// as it also depends on the network condition. /// on the network condition.
Future<ServiceStatus> checkServiceStatus(PermissionGroup permission) { Future<ServiceStatus> checkServiceStatus(Permission permission) {
throw UnimplementedError('checkServiceStatus() has not been implemented.'); throw UnimplementedError('checkServiceStatus() has not been implemented.');
} }
/// Open the App settings page. /// Opens the app settings page.
/// ///
/// Returns [true] if the app settings page could be opened, /// Returns [true] if the app settings page could be opened, otherwise
/// otherwise [false] is returned. /// [false].
Future<bool> openAppSettings() { Future<bool> openAppSettings() {
throw UnimplementedError('openAppSettings() has not been implemented.'); throw UnimplementedError('openAppSettings() has not been implemented.');
} }
/// Request the user for access to the supplied list of permissiongroups. /// Requests the user for access to the supplied list of [Permission]s, if
/// they have not already been granted before.
/// ///
/// Returns a [Map] containing the status per requested permissiongroup. /// Returns a [Map] containing the status per requested [Permission].
Future<Map<PermissionGroup, PermissionStatus>> requestPermissions( Future<Map<Permission, PermissionStatus>> requestPermissions(
List<PermissionGroup> permissions) { List<Permission> permissions) {
throw UnimplementedError('requestPermissions() has not been implemented.'); throw UnimplementedError('requestPermissions() has not been implemented.');
} }
/// Request to see if you should show a rationale for requesting permission. /// Checks if you should show a rationale for requesting permission.
/// ///
/// This method is only implemented on Android, calling this on iOS always /// This method is only implemented on Android, calling this on iOS always
/// returns [false]. /// returns [false].
Future<bool> shouldShowRequestPermissionRationale( Future<bool> shouldShowRequestPermissionRationale(Permission permission) {
PermissionGroup permission) {
throw UnimplementedError( throw UnimplementedError(
'shouldShowRequestPermissionRationale() has not been implemented.'); 'shouldShowRequestPermissionRationale() has not been implemented.');
} }
......
part of permission_handler_platform_interface;
/// Defines the state of a [Permission].
enum PermissionStatus {
/// The permission wasn't requested yet.
undetermined,
/// The user granted access to the requested feature.
granted,
/// The user denied access to the requested feature.
denied,
/// The OS denied access to the requested feature. The user cannot change
/// this app's status, possibly due to active restrictions such as parental
/// controls being in place.
/// *Only supported on iOS.*
restricted,
/// The user denied access to the requested feature and selected to never
/// again show a request for this permission. The user may still change the
/// permission status in the settings.
/// *Only supported on Android.*
permanentlyDenied,
}
extension PermissionStatusValue on PermissionStatus {
int get value {
switch (this) {
case PermissionStatus.denied:
return 0;
case PermissionStatus.granted:
return 1;
case PermissionStatus.restricted:
return 2;
case PermissionStatus.undetermined:
return 3;
case PermissionStatus.permanentlyDenied:
return 4;
default:
throw UnimplementedError();
}
}
static PermissionStatus statusByValue(int value) {
return [
PermissionStatus.denied,
PermissionStatus.granted,
PermissionStatus.restricted,
PermissionStatus.undetermined,
PermissionStatus.permanentlyDenied,
][value];
}
}
extension PermissionStatusGetters on PermissionStatus {
/// If the permission was never requested before.
bool get isUndetermined => this == PermissionStatus.undetermined;
/// If the user granted access to the requested feature.
bool get isGranted => this == PermissionStatus.granted;
/// If the user denied access to the requested feature.
bool get isDenied => this == PermissionStatus.denied;
/// If the OS denied access to the requested feature. The user cannot change
/// this app's status, possibly due to active restrictions such as parental
/// controls being in place.
/// *Only supported on iOS.*
bool get isRestricted => this == PermissionStatus.restricted;
/// If the user denied access to the requested feature and selected to never
/// again show a request for this permission. The user may still change the
/// permission status in the settings.
/// *Only supported on Android.*
bool get isPermanentlyDenied => this == PermissionStatus.permanentlyDenied;
}
extension FuturePermissionStatusGetters on Future<PermissionStatus> {
/// If the permission was never requested before.
Future<bool> get isUndetermined async => (await this).isUndetermined;
/// If the user granted access to the requested feature.
Future<bool> get isGranted async => (await this).isGranted;
/// If the user denied access to the requested feature.
Future<bool> get isDenied async => (await this).isDenied;
/// If the OS denied access to the requested feature. The user cannot change
/// this app's status, possibly due to active restrictions such as parental
/// controls being in place.
/// *Only supported on iOS.*
Future<bool> get isRestricted async => (await this).isRestricted;
/// If the user denied access to the requested feature and selected to never
/// again show a request for this permission. The user may still change the
/// permission status in the settings.
/// *Only supported on Android.*
Future<bool> get isPermanentlyDenied async =>
(await this).isPermanentlyDenied;
}
part of permission_handler_platform_interface;
/// A special kind of permission used to access a service. Additionally to the
/// actions that normal [Permission]s have, you can also query the status of
/// the related service.
class PermissionWithService extends Permission {
const PermissionWithService._(int value) : super._(value);
}
/// Defines the permissions which can be checked and requested.
class Permission {
const Permission._(this.value);
factory Permission.byValue(int value) => values[value];
/// Integer representation of the [Permission].
final int value;
/// Android: Calendar
/// iOS: Calendar (Events)
static const calendar = Permission._(0);
/// Android: Camera
/// iOS: Photos (Camera Roll and Camera)
static const camera = Permission._(1);
/// Android: Contacts
/// iOS: AddressBook
static const contacts = Permission._(2);
/// Android: Fine and Coarse Location
/// iOS: CoreLocation (Always and WhenInUse)
static const location = PermissionWithService._(3);
/// Android:
/// When running on Android < Q: Fine and Coarse Location
/// When running on Android Q and above: Background Location Permission
/// iOS: CoreLocation - Always
static const locationAlways = PermissionWithService._(4);
/// Android: Fine and Coarse Location
/// iOS: CoreLocation - WhenInUse
static const locationWhenInUse = PermissionWithService._(5);
/// Android: None
/// iOS: MPMediaLibrary
static const mediaLibrary = Permission._(6);
/// Android: Microphone
/// iOS: Microphone
static const microphone = Permission._(7);
/// Android: Phone
/// iOS: Nothing
static const phone = Permission._(8);
/// Android: Nothing
/// iOS: Photos
static const photos = Permission._(9);
/// Android: Nothing
/// iOS: Reminders
static const reminders = Permission._(10);
/// Android: Body Sensors
/// iOS: CoreMotion
static const sensors = Permission._(11);
/// Android: Sms
/// iOS: Nothing
static const sms = Permission._(12);
/// Android: Microphone
/// iOS: Speech
static const speech = Permission._(13);
/// Android: External Storage
/// iOS: Access to folders like `Documents` or `Downloads`. Implicitly
/// granted.
static const storage = Permission._(14);
/// Android: Ignore Battery Optimizations
static const ignoreBatteryOptimizations = Permission._(15);
/// Android: Notification
/// iOS: Notification
static const notification = Permission._(16);
/// Android: Allows an application to access any geographic locations
/// persisted in the user's shared collection.
static const accessMediaLocation = Permission._(17);
/// When running on Android Q and above: Activity Recognition
/// When running on Android < Q: Nothing
/// iOS: Nothing
static const activityRecognition = Permission._(18);
/// The unknown only used for return type, never requested
static const unknown = Permission._(19);
/// Returns a list of all possible [PermissionGroup] values.
static const List<Permission> values = <Permission>[
calendar,
camera,
contacts,
location,
locationAlways,
locationWhenInUse,
mediaLibrary,
microphone,
phone,
photos,
reminders,
sensors,
sms,
speech,
storage,
ignoreBatteryOptimizations,
notification,
accessMediaLocation,
activityRecognition,
unknown,
];
static const List<String> _names = <String>[
'calendar',
'camera',
'contacts',
'location',
'locationAlways',
'locationWhenInUse',
'mediaLibrary',
'microphone',
'phone',
'photos',
'reminders',
'sensors',
'sms',
'speech',
'storage',
'ignoreBatteryOptimizations',
'notification',
'access_media_location',
'activity_recognition',
'unknown',
];
@override
String toString() => 'Permission.${_names[value]}';
}
part of permission_handler_platform_interface;
enum ServiceStatus {
/// The service for the permission is disabled.
disabled,
/// The service for the permission is enabled.
enabled,
/// The permission does not have an associated service on the current
/// platform.
notApplicable,
}
extension ServiceStatusValue on ServiceStatus {
int get value {
switch (this) {
case ServiceStatus.disabled:
return 0;
case ServiceStatus.enabled:
return 1;
case ServiceStatus.notApplicable:
return 2;
default:
throw UnimplementedError();
}
}
static ServiceStatus statusByValue(int value) {
return [
ServiceStatus.disabled,
ServiceStatus.enabled,
ServiceStatus.notApplicable,
][value];
}
}
extension ServiceStatusGetters on ServiceStatus {
/// If the service for the permission is disabled.
bool get isDisabled => this == ServiceStatus.disabled;
/// If the service for the permission is enabled.
bool get isEnabled => this == ServiceStatus.enabled;
/// If the permission does not have an associated service on the current
/// platform.
bool get isNotApplicable => this == ServiceStatus.notApplicable;
}
extension FutureServiceStatusGetters on Future<ServiceStatus> {
/// If the service for the permission is disabled.
Future<bool> get isDisabled async => (await this).isDisabled;
/// If the service for the permission is enabled.
Future<bool> get isEnabled async => (await this).isEnabled;
/// If the permission does not have an associated service on the current
/// platform.
Future<bool> get isNotApplicable async => (await this).isNotApplicable;
}
...@@ -3,7 +3,7 @@ description: A common platform interface for the permission_handler plugin. ...@@ -3,7 +3,7 @@ description: A common platform interface for the permission_handler plugin.
homepage: https://github.com/baseflow/flutter-permission-handler/tree/master/permission_handler_platform_interface homepage: https://github.com/baseflow/flutter-permission-handler/tree/master/permission_handler_platform_interface
# NOTE: We strongly prefer non-breaking changes, even at the expense of a # NOTE: We strongly prefer non-breaking changes, even at the expense of a
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
version: 1.0.0 version: 2.0.0
dependencies: dependencies:
flutter: flutter:
...@@ -18,5 +18,5 @@ dev_dependencies: ...@@ -18,5 +18,5 @@ dev_dependencies:
effective_dart: ^1.2.1 effective_dart: ^1.2.1
environment: environment:
sdk: ">=2.0.0-dev.28.0 <3.0.0" sdk: ">=2.6.0 <3.0.0"
flutter: ">=1.9.1+hotfix.4 <2.0.0" flutter: ">=1.9.1+hotfix.4 <2.0.0"
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