Commit b97a0603 by Maurits van Beusekom

Release permission_handler 5.0.0 and

permission_handler_platform_interface 2.0.0
parents 9b12a9f8 0f4ee3ad
......@@ -2,4 +2,4 @@ include: package:effective_dart/analysis_options.1.2.0.yaml
linter:
rules:
- public_member_api_docs
\ No newline at end of file
- public_member_api_docs
## 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
* Issue #235: Solved a bug which made it impossible to request service status on Android 7;
......
......@@ -5,26 +5,35 @@ import android.content.Intent;
import android.util.Log;
final class AppSettingsManager {
boolean openAppSettings(Context applicationContext) {
if (applicationContext == null) {
Log.d(PermissionConstants.LOG_TAG, "Unable to detect current Activity or App Context.");
return false;
@FunctionalInterface
interface OpenAppSettingsSuccessCallback {
void onSuccess(boolean appSettingsOpenedSuccessfully);
}
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 {
Intent settingsIntent = new Intent();
settingsIntent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
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_NO_HISTORY);
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
applicationContext.startActivity(settingsIntent);
context.startActivity(settingsIntent);
return true;
successCallback.onSuccess(true);
} 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 {
public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result)
{
switch (call.method) {
case "checkPermissionStatus": {
case "checkServiceStatus": {
@PermissionConstants.PermissionGroup final int permission = Integer.parseInt(call.arguments.toString());
@PermissionConstants.PermissionStatus final int permissionStatus =
permissionManager.checkPermissionStatus(
permission,
applicationContext,
activity);
serviceManager.checkServiceStatus(
permission,
applicationContext,
result::success,
(String errorCode, String errorDescription) -> result.error(
errorCode,
errorDescription,
null));
result.success(permissionStatus);
break;
}
case "checkServiceStatus": {
case "checkPermissionStatus": {
@PermissionConstants.PermissionGroup final int permission = Integer.parseInt(call.arguments.toString());
@PermissionConstants.ServiceStatus final int serviceStatus =
serviceManager.checkServiceStatus(
permission,
applicationContext);
permissionManager.checkPermissionStatus(
permission,
applicationContext,
activity,
result::success,
(String errorCode, String errorDescription) -> result.error(
errorCode,
errorDescription,
null));
result.success(serviceStatus);
break;
}
case "requestPermissions":
......@@ -88,14 +94,26 @@ final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler {
break;
case "shouldShowRequestPermissionRationale": {
@PermissionConstants.PermissionGroup final int permission = Integer.parseInt(call.arguments.toString());
final boolean showRationale = permissionManager
.shouldShowRequestPermissionRationale(permission, activity);
result.success(showRationale);
permissionManager.shouldShowRequestPermissionRationale(
permission,
activity,
result::success,
(String errorCode, String errorDescription) -> result.error(
errorCode,
errorDescription,
null));
break;
}
case "openAppSettings":
boolean isOpen = appSettingsManager.openAppSettings(applicationContext);
result.success(isOpen);
appSettingsManager.openAppSettings(
applicationContext,
result::success,
(String errorCode, String errorDescription) -> result.error(
errorCode,
errorDescription,
null));
break;
default:
result.notImplemented();
......
......@@ -62,7 +62,7 @@ final class PermissionConstants {
static final int PERMISSION_STATUS_DENIED = 0;
static final int PERMISSION_STATUS_GRANTED = 1;
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;
@Retention(RetentionPolicy.SOURCE)
......@@ -70,7 +70,7 @@ final class PermissionConstants {
PERMISSION_STATUS_DENIED,
PERMISSION_STATUS_GRANTED,
PERMISSION_STATUS_RESTRICTED,
PERMISSION_STATUS_UNKNOWN,
PERMISSION_STATUS_NOT_DETERMINED,
PERMISSION_STATUS_NEWER_ASK_AGAIN,
})
@interface PermissionStatus {
......@@ -80,14 +80,12 @@ final class PermissionConstants {
static final int SERVICE_STATUS_DISABLED = 0;
static final int SERVICE_STATUS_ENABLED = 1;
static final int SERVICE_STATUS_NOT_APPLICABLE = 2;
static final int SERVICE_STATUS_UNKNOWN = 3;
@Retention(RetentionPolicy.SOURCE)
@IntDef({
SERVICE_STATUS_DISABLED,
SERVICE_STATUS_ENABLED,
SERVICE_STATUS_NOT_APPLICABLE,
SERVICE_STATUS_UNKNOWN,
SERVICE_STATUS_NOT_APPLICABLE
})
@interface ServiceStatus {
}
......
......@@ -36,16 +36,16 @@ public final class PermissionHandlerPlugin implements FlutterPlugin, ActivityAwa
* <p>Calling this automatically initializes the plugin. However plugins initialized this way
* won't react to changes in activity or context, unlike {@link PermissionHandlerPlugin}.
*/
public static void registerWith(Registrar registrar) {
final PermissionHandlerPlugin permissionHandlerPlugin = new PermissionHandlerPlugin();
permissionHandlerPlugin.startListening(
registrar.context(),
registrar.activity(),
registrar.messenger(),
registrar::addActivityResultListener,
registrar::addRequestPermissionsResultListener
);
}
public static void registerWith(Registrar registrar) {
final PermissionHandlerPlugin permissionHandlerPlugin = new PermissionHandlerPlugin();
permissionHandlerPlugin.startListening(
registrar.context(),
registrar.activity(),
registrar.messenger(),
registrar::addActivityResultListener,
registrar::addRequestPermissionsResultListener
);
}
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
......
......@@ -238,9 +238,9 @@ public class PermissionUtils {
}
@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) {
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_DENIED;
}
......@@ -265,23 +265,12 @@ public class PermissionUtils {
}
@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) {
return false;
}
List<String> names = getManifestNames(activity, permission);
if (names == null || names.isEmpty()) {
return false;
}
boolean isNeverAskAgainSelected = false;
for (String name : names) {
isNeverAskAgainSelected |= PermissionUtils.neverAskAgainSelected(activity, name);
}
return isNeverAskAgainSelected;
return PermissionUtils.neverAskAgainSelected(activity, name);
}
@RequiresApi(api = Build.VERSION_CODES.M)
......@@ -298,7 +287,7 @@ public class PermissionUtils {
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);
return genPrefs.getBoolean(permission, false);
}
......
......@@ -17,34 +17,45 @@ import android.util.Log;
import java.util.List;
final class ServiceManager {
@PermissionConstants.ServiceStatus
int checkServiceStatus(
@FunctionalInterface
interface SuccessCallback {
void onSuccess(@PermissionConstants.ServiceStatus int serviceStatus);
}
void checkServiceStatus(
int permission,
Context context) {
if (context == null) {
Log.d(PermissionConstants.LOG_TAG, "Unable to detect current Activity or App Context.");
return PermissionConstants.SERVICE_STATUS_UNKNOWN;
Context context,
SuccessCallback successCallback,
ErrorCallback errorCallback) {
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 ||
permission == PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS ||
permission == PermissionConstants.PERMISSION_GROUP_LOCATION_WHEN_IN_USE) {
return isLocationServiceEnabled(context)
final int serviceStatus = isLocationServiceEnabled(context)
? PermissionConstants.SERVICE_STATUS_ENABLED
: PermissionConstants.SERVICE_STATUS_DISABLED;
successCallback.onSuccess(serviceStatus);
}
if (permission == PermissionConstants.PERMISSION_GROUP_PHONE) {
PackageManager pm = context.getPackageManager();
if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
return PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE;
successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE);
return;
}
TelephonyManager telephonyManager = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
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);
......@@ -52,23 +63,28 @@ final class ServiceManager {
List<ResolveInfo> callAppsList = pm.queryIntentActivities(callIntent, 0);
if (callAppsList.isEmpty()) {
return PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE;
successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE);
return;
}
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) {
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_NOT_APPLICABLE;
successCallback.onSuccess(serviceStatus);
return;
}
return PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE;
successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE);
}
private boolean isLocationServiceEnabled(Context context) {
......@@ -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.
@SuppressWarnings("deprecation")
private static boolean isLocationServiceEnabledKitKat(Context context)
......@@ -109,7 +125,7 @@ final class ServiceManager {
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.
@SuppressWarnings("deprecation")
private static boolean isLocationServiceEnablePreKitKat(Context context)
......
# 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.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
......@@ -15,96 +15,70 @@ def parse_KV_file(file, separator='=')
if !File.exists? file_abs_path
return [];
end
pods_ary = []
generated_key_values = {}
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) { |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
pods_ary.push({:name => podname, :path => podpath});
else
puts "Invalid plugin specification: #{line}"
end
}
return pods_ary
File.foreach(file_abs_path) do |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
generated_key_values[podname] = podpath
else
puts "Invalid plugin specification: #{line}"
end
end
generated_key_values
end
target 'Runner' do
# 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')
# Flutter Pod
copied_flutter_dir = File.join(__dir__, 'Flutter')
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
generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
if generated_xcode_build_settings.empty?
puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
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]))
unless File.exist?(copied_framework_path)
FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
end
}
unless File.exist?(copied_podspec_path)
FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
end
end
# Keep pod path relative so it can be checked into Podfile.lock.
pod 'Flutter', :path => 'Flutter'
# 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.map { |p|
symlink = File.join('.symlinks', 'plugins', p[:name])
File.symlink(p[:path], symlink)
pod p[:name], :path => File.join(symlink, 'ios')
}
plugin_pods.each do |name, path|
symlink = File.join('.symlinks', 'plugins', name)
File.symlink(path, symlink)
pod name, :path => File.join(symlink, 'ios')
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
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
......@@ -9,10 +9,6 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
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 */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
......@@ -28,8 +24,6 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
......@@ -40,7 +34,6 @@
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>"; };
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>"; };
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>"; };
......@@ -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>"; };
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>"; };
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; };
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>"; };
......@@ -64,8 +56,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
B7634AD7E1771AEDD2D1A5F7 /* libPods-Runner.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
......@@ -84,9 +74,7 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
......@@ -232,7 +220,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
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 */ = {
isa = PBXShellScriptBuildPhase;
......@@ -241,7 +229,7 @@
);
inputPaths = (
"${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";
outputPaths = (
......
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1130"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
......@@ -27,8 +27,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
......@@ -38,8 +36,8 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
......@@ -61,8 +59,6 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
......
......@@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>BuildSystemType</key>
<string>Original</string>
<string>Latest</string>
</dict>
</plist>
......@@ -17,33 +17,31 @@ class MyApp extends StatelessWidget {
actions: <Widget>[
IconButton(
icon: const Icon(Icons.settings),
onPressed: () {
PermissionHandler().openAppSettings().then((bool hasOpened) =>
debugPrint('App Settings opened: ' + hasOpened.toString()));
onPressed: () async {
var hasOpened = openAppSettings();
debugPrint('App Settings opened: ' + hasOpened.toString());
},
)
],
),
body: Center(
child: ListView(
children: PermissionGroup.values
.where((PermissionGroup permission) {
children: Permission.values
.where((Permission permission) {
if (Platform.isIOS) {
return permission != PermissionGroup.unknown &&
permission != PermissionGroup.sms &&
permission != PermissionGroup.storage &&
permission !=
PermissionGroup.ignoreBatteryOptimizations &&
permission != PermissionGroup.accessMediaLocation;
return permission != Permission.unknown &&
permission != Permission.sms &&
permission != Permission.storage &&
permission != Permission.ignoreBatteryOptimizations &&
permission != Permission.accessMediaLocation;
} else {
return permission != PermissionGroup.unknown &&
permission != PermissionGroup.mediaLibrary &&
permission != PermissionGroup.photos &&
permission != PermissionGroup.reminders;
return permission != Permission.unknown &&
permission != Permission.mediaLibrary &&
permission != Permission.photos &&
permission != Permission.reminders;
}
})
.map((PermissionGroup permission) =>
PermissionWidget(permission))
.map((permission) => PermissionWidget(permission))
.toList()),
),
),
......@@ -54,20 +52,20 @@ class MyApp extends StatelessWidget {
/// Permission widget which displays a permission and allows users to request
/// the permissions.
class PermissionWidget extends StatefulWidget {
/// Constructs a [PermissionWidget] for the supplied [PermissionGroup].
const PermissionWidget(this._permissionGroup);
/// Constructs a [PermissionWidget] for the supplied [Permission].
const PermissionWidget(this._permission);
final PermissionGroup _permissionGroup;
final Permission _permission;
@override
_PermissionState createState() => _PermissionState(_permissionGroup);
_PermissionState createState() => _PermissionState(_permission);
}
class _PermissionState extends State<PermissionWidget> {
_PermissionState(this._permissionGroup);
_PermissionState(this._permission);
final PermissionGroup _permissionGroup;
PermissionStatus _permissionStatus = PermissionStatus.unknown;
final Permission _permission;
PermissionStatus _permissionStatus = PermissionStatus.undetermined;
@override
void initState() {
......@@ -76,15 +74,9 @@ class _PermissionState extends State<PermissionWidget> {
_listenForPermissionStatus();
}
void _listenForPermissionStatus() {
final Future<PermissionStatus> statusFuture =
PermissionHandler().checkPermissionStatus(_permissionGroup);
statusFuture.then((PermissionStatus status) {
setState(() {
_permissionStatus = status;
});
});
void _listenForPermissionStatus() async {
final status = await _permission.status;
setState(() => _permissionStatus = status);
}
Color getPermissionColor() {
......@@ -101,7 +93,7 @@ class _PermissionState extends State<PermissionWidget> {
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(_permissionGroup.toString()),
title: Text(_permission.toString()),
subtitle: Text(
_permissionStatus.toString(),
style: TextStyle(color: getPermissionColor()),
......@@ -109,33 +101,26 @@ class _PermissionState extends State<PermissionWidget> {
trailing: IconButton(
icon: const Icon(Icons.info),
onPressed: () {
checkServiceStatus(context, _permissionGroup);
checkServiceStatus(context, _permission);
}),
onTap: () {
requestPermission(_permissionGroup);
requestPermission(_permission);
},
);
}
void checkServiceStatus(BuildContext context, PermissionGroup permission) {
PermissionHandler()
.checkServiceStatus(permission)
.then((ServiceStatus serviceStatus) {
final SnackBar snackBar =
SnackBar(content: Text(serviceStatus.toString()));
Scaffold.of(context).showSnackBar(snackBar);
});
void checkServiceStatus(BuildContext context, Permission permission) async {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text((await permission.status).toString()),
));
}
Future<void> requestPermission(PermissionGroup permission) async {
final List<PermissionGroup> permissions = <PermissionGroup>[permission];
final Map<PermissionGroup, PermissionStatus> permissionRequestResult =
await PermissionHandler().requestPermissions(permissions);
Future<void> requestPermission(Permission permission) async {
final status = await permission.request();
setState(() {
print(permissionRequestResult);
_permissionStatus = permissionRequestResult[permission];
print(status);
_permissionStatus = status;
print(_permissionStatus);
});
}
......
......@@ -16,4 +16,4 @@ dev_dependencies:
path: ../
flutter:
uses-material-design: true
\ No newline at end of file
uses-material-design: true
......@@ -107,12 +107,11 @@ typedef NS_ENUM(int, PermissionStatus) {
PermissionStatusDenied = 0,
PermissionStatusGranted,
PermissionStatusRestricted,
PermissionStatusUnknown,
PermissionStatusNotDetermined,
};
typedef NS_ENUM(int, ServiceStatus) {
ServiceStatusDisabled = 0,
ServiceStatusEnabled,
ServiceStatusNotApplicable,
ServiceStatusUnknown,
};
......@@ -23,7 +23,7 @@
return PermissionStatusUnknown;
#endif
}
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
}
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
......@@ -33,7 +33,7 @@
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) {
if (status != PermissionStatusNotDetermined) {
completionHandler(status);
return;
}
......@@ -55,7 +55,7 @@
return;
#endif
} else {
completionHandler(PermissionStatusUnknown);
completionHandler(PermissionStatusNotDetermined);
return;
}
......@@ -73,7 +73,7 @@
switch (status) {
case AVAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
case AVAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case AVAuthorizationStatusDenied:
......@@ -82,7 +82,7 @@
return PermissionStatusGranted;
}
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
}
@end
......
......@@ -20,7 +20,7 @@
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) {
if (status != PermissionStatusNotDetermined) {
completionHandler(status);
}
......@@ -37,7 +37,7 @@
switch (status) {
case CNAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
case CNAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case CNAuthorizationStatusDenied:
......@@ -51,7 +51,7 @@
switch (status) {
case kABAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
case kABAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case kABAuthorizationStatusDenied:
......@@ -61,7 +61,7 @@
}
}
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
}
+ (void)requestPermissionsFromContactStore:(PermissionStatusHandler)completionHandler API_AVAILABLE(ios(9)) {
......
......@@ -24,7 +24,7 @@
#endif
}
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
}
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
......@@ -34,7 +34,7 @@
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus permissionStatus = [self checkPermissionStatus:permission];
if (permissionStatus != PermissionStatusUnknown) {
if (permissionStatus != PermissionStatusNotDetermined) {
completionHandler(permissionStatus);
return;
}
......@@ -56,7 +56,7 @@
return;
#endif
} else {
completionHandler(PermissionStatusUnknown);
completionHandler(PermissionStatusNotDetermined);
return;
}
......@@ -75,7 +75,7 @@
switch (status) {
case EKAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
case EKAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case EKAuthorizationStatusDenied:
......@@ -84,7 +84,7 @@
return PermissionStatusGranted;
}
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
}
@end
......
......@@ -35,7 +35,7 @@
PermissionStatus status = [self checkPermissionStatus:permission];
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse && permission == PermissionGroupLocationAlways) {
// don't do anything and continue requesting permissions
} else if (status != PermissionStatusUnknown) {
} else if (status != PermissionStatusNotDetermined) {
completionHandler(status);
}
......@@ -105,7 +105,7 @@
if (permission == PermissionGroupLocationAlways) {
switch (authorizationStatus) {
case kCLAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
case kCLAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case kCLAuthorizationStatusDenied:
......@@ -118,7 +118,7 @@
switch (authorizationStatus) {
case kCLAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
case kCLAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case kCLAuthorizationStatusDenied:
......@@ -134,7 +134,7 @@
switch (authorizationStatus) {
case kCLAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
case kCLAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case kCLAuthorizationStatusDenied:
......@@ -142,7 +142,7 @@
case kCLAuthorizationStatusAuthorized:
return PermissionStatusGranted;
default:
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
}
#pragma clang diagnostic pop
......
......@@ -19,7 +19,7 @@
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) {
if (status != PermissionStatusNotDetermined) {
completionHandler(status);
return;
}
......@@ -29,7 +29,7 @@
completionHandler([MediaLibraryPermissionStrategy determinePermissionStatus:status]);
}];
} else {
completionHandler(PermissionStatusUnknown);
completionHandler(PermissionStatusNotDetermined);
return;
}
}
......@@ -41,13 +41,13 @@
return [MediaLibraryPermissionStrategy determinePermissionStatus:status];
}
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
}
+ (PermissionStatus)determinePermissionStatus:(MPMediaLibraryAuthorizationStatus)authorizationStatus API_AVAILABLE(ios(9.3)){
switch (authorizationStatus) {
case MPMediaLibraryAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
case MPMediaLibraryAuthorizationStatusDenied:
return PermissionStatusDenied;
case MPMediaLibraryAuthorizationStatusRestricted:
......@@ -56,7 +56,7 @@
return PermissionStatusGranted;
}
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
}
@end
......
......@@ -21,7 +21,7 @@
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) {
if (status != PermissionStatusNotDetermined) {
completionHandler(status);
return;
}
......@@ -59,7 +59,7 @@
if (settings.authorizationStatus == UNAuthorizationStatusDenied) {
permissionStatus = PermissionStatusDenied;
} else if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) {
permissionStatus = PermissionStatusUnknown;
permissionStatus = PermissionStatusNotDetermined;
}
dispatch_semaphore_signal(sem);
}];
......
......@@ -13,7 +13,7 @@
@implementation PhonePermissionStrategy
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
}
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
......@@ -26,7 +26,7 @@
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
completionHandler(PermissionStatusUnknown);
completionHandler(PermissionStatusNotDetermined);
}
......
......@@ -19,7 +19,7 @@
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) {
if (status != PermissionStatusNotDetermined) {
completionHandler(status);
return;
}
......@@ -38,7 +38,7 @@
+ (PermissionStatus)determinePermissionStatus:(PHAuthorizationStatus)authorizationStatus {
switch (authorizationStatus) {
case PHAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
case PHAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case PHAuthorizationStatusDenied:
......@@ -47,7 +47,7 @@
return PermissionStatusGranted;
}
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
}
@end
......
......@@ -19,13 +19,13 @@
: ServiceStatusDisabled;
}
return ServiceStatusUnknown;
return ServiceStatusDisabled;
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) {
if (status != PermissionStatusNotDetermined) {
completionHandler(status);
return;
}
......@@ -42,7 +42,7 @@
}
}];
} else {
completionHandler(PermissionStatusUnknown);
completionHandler(PermissionStatusNotDetermined);
}
}
......@@ -54,7 +54,7 @@
switch (status) {
case CMAuthorizationStatusNotDetermined:
permissionStatus = PermissionStatusUnknown;
permissionStatus = PermissionStatusNotDetermined;
break;
case CMAuthorizationStatusRestricted:
permissionStatus = PermissionStatusRestricted;
......@@ -72,7 +72,7 @@
return permissionStatus;
}
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
}
@end
......
......@@ -19,7 +19,7 @@
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) {
if (status != PermissionStatusNotDetermined) {
completionHandler(status);
return;
}
......@@ -29,7 +29,7 @@
completionHandler([SpeechPermissionStrategy determinePermissionStatus:authorizationStatus]);
}];
} else {
completionHandler(PermissionStatusUnknown);
completionHandler(PermissionStatusNotDetermined);
}
}
......@@ -40,13 +40,13 @@
return [SpeechPermissionStrategy determinePermissionStatus:status];
}
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
}
+ (PermissionStatus)determinePermissionStatus:(SFSpeechRecognizerAuthorizationStatus)authorizationStatus API_AVAILABLE(ios(10.0)){
switch (authorizationStatus) {
case SFSpeechRecognizerAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
case SFSpeechRecognizerAuthorizationStatusDenied:
return PermissionStatusDenied;
case SFSpeechRecognizerAuthorizationStatusRestricted:
......@@ -55,7 +55,7 @@
return PermissionStatusGranted;
}
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
}
@end
......
......@@ -9,14 +9,14 @@
@implementation UnknownPermissionStrategy
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
return PermissionStatusUnknown;
return PermissionStatusNotDetermined;
}
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
return ServiceStatusUnknown;
return ServiceStatusDisabled;
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
completionHandler(PermissionStatusUnknown);
completionHandler(PermissionStatusNotDetermined);
}
@end
\ No newline at end of file
@end
......@@ -3,7 +3,7 @@
#
Pod::Spec.new do |s|
s.name = 'permission_handler'
s.version = '4.4.0+hotfix.2'
s.version = '5.0.0'
s.summary = 'Permission plugin for Flutter.'
s.description = <<-DESC
Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions.
......
import 'dart:async';
import 'dart:io';
import '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
/// the Android and iOS platforms.
class PermissionHandler extends PermissionHandlerPlatform {
@override
Future<ServiceStatus> checkServiceStatus(PermissionGroup permission) {
return PermissionHandlerPlatform.instance.checkServiceStatus(permission);
}
/// Returns [true] if the app settings page could be opened, otherwise [false].
Future<bool> openAppSettings() => _handler.openAppSettings();
@override
Future<PermissionStatus> checkPermissionStatus(PermissionGroup permission) {
return PermissionHandlerPlatform.instance.checkPermissionStatus(permission);
}
/// Actions that can be executed on a permission.
extension PermissionActions on Permission {
/// The current status of this permission.
Future<PermissionStatus> get status => _handler.checkPermissionStatus(this);
@override
Future<bool> openAppSettings() {
return PermissionHandlerPlatform.instance.openAppSettings();
/// If you should show a rationale for requesting permission.
///
/// This is only implemented on Android, calling this on iOS always returns
/// [false].
Future<bool> get shouldShowRequestRationale async {
if (!Platform.isAndroid) {
return false;
}
return _handler.shouldShowRequestPermissionRationale(this);
}
@override
Future<Map<PermissionGroup, PermissionStatus>> requestPermissions(
List<PermissionGroup> permissions) {
return PermissionHandlerPlatform.instance.requestPermissions(permissions);
/// Request the user for access to this [Permission], if access hasn't already
/// been grant access before.
///
/// Returns the new [PermissionStatus].
Future<PermissionStatus> request() async {
return (await [this].request())[this];
}
}
@override
Future<bool> shouldShowRequestPermissionRationale(
PermissionGroup permission) {
if (!Platform.isAndroid) {
return Future.value(false);
}
/// Shortcuts for checking the [status] of a [Permission].
extension PermissionCheckShortcuts on Permission {
/// If this permission was never requested before.
Future<bool> get isUndetermined => status.isUndetermined;
return PermissionHandlerPlatform.instance
.shouldShowRequestPermissionRationale(permission);
}
/// 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
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
flutter:
......@@ -16,12 +16,12 @@ dependencies:
flutter:
sdk: flutter
meta: ^1.1.6
permission_handler_platform_interface: ^1.0.0
permission_handler_platform_interface: ^2.0.0
dev_dependencies:
effective_dart: ^1.2.1
plugin_platform_interface: ^1.0.1
environment:
sdk: ">=2.1.0 <3.0.0"
flutter: ">=1.12.8 <2.0.0"
\ No newline at end of file
sdk: ">=2.7.0 <3.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
- Initial open-source release.
\ No newline at end of file
- Initial open-source release.
......@@ -5,4 +5,6 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'src/method_channel/method_channel_permission_handler.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';
const MethodChannel _methodChannel =
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 {
/// Check current permission status.
///
/// Returns a [Future] containing the current permission status for the
/// supplied [PermissionGroup].
Future<PermissionStatus> checkPermissionStatus(
PermissionGroup permission) async {
/// Checks the current status of the given [Permission].
Future<PermissionStatus> checkPermissionStatus(Permission permission) async {
final status = await _methodChannel.invokeMethod(
'checkPermissionStatus', permission.value);
return Codec.decodePermissionStatus(status);
}
/// Check current service status.
///
/// Returns a [Future] containing the current service status for the supplied
/// [PermissionGroup].
/// Checks the current status of the service associated with the given
/// [Permission].
///
/// Notes about specific PermissionGroups:
/// - **PermissionGroup.phone**
/// Notes about specific permissions:
/// - **[Permission.phone]**
/// - Android:
/// - The method will return [ServiceStatus.notApplicable] when:
/// 1. the device lacks the TELEPHONY feature
/// 1. TelephonyManager.getPhoneType() returns PHONE_TYPE_NONE
/// 1. when no Intents can be resolved to handle the `tel:` scheme
/// - 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:
/// 1. the SIM card is missing
/// - the SIM card is missing
/// - iOS:
/// - 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:
/// 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
/// - **PLEASE NOTE that this is still not a perfect indication** of the
/// devices' capability to place & connect phone calls
/// as it also depends on the network condition.
Future<ServiceStatus> checkServiceStatus(PermissionGroup permission) async {
/// device's capability to place & connect phone calls as it also depends
/// on the network condition.
Future<ServiceStatus> checkServiceStatus(Permission permission) async {
final status = await _methodChannel.invokeMethod(
'checkServiceStatus', permission.value);
return Codec.decodeServiceStatus(status);
}
/// Open the App settings page.
/// Opens the app settings page.
///
/// Returns [true] if the app settings page could be opened,
/// otherwise [false] is returned.
/// Returns [true] if the app settings page could be opened, otherwise
/// [false].
Future<bool> openAppSettings() async {
final hasOpened = await _methodChannel.invokeMethod('openAppSettings');
return hasOpened;
final wasOpened = await _methodChannel.invokeMethod('openAppSettings');
return wasOpened;
}
/// 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.
Future<Map<PermissionGroup, PermissionStatus>> requestPermissions(
List<PermissionGroup> permissions) async {
final data = Codec.encodePermissionGroups(permissions);
/// Returns a [Map] containing the status per requested [Permission].
Future<Map<Permission, PermissionStatus>> requestPermissions(
List<Permission> permissions) async {
final data = Codec.encodePermissions(permissions);
final status =
await _methodChannel.invokeMethod('requestPermissions', data);
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
/// returns [false].
Future<bool> shouldShowRequestPermissionRationale(
PermissionGroup permission) async {
Permission permission) async {
final shouldShowRationale = await _methodChannel.invokeMethod(
'shouldShowRequestPermissionRationale', permission.value);
......
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.
class Codec {
/// Converts the supplied integer value into a [PermissionStatus] instance.
/// Converts the given [value] into a [PermissionStatus] instance.
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) {
return ServiceStatus.values[value];
return ServiceStatusValue.statusByValue(value);
}
/// Converts the supplied [Map] of integers into a [Map] of
/// [PermissionGroup] key and [PermissionStatus] value instances.
static Map<PermissionGroup, PermissionStatus> decodePermissionRequestResult(
/// Converts the given [Map] of [int]s into a [Map] with [Permission]s as
/// keys and their respective [PermissionStatus] as value.
static Map<Permission, PermissionStatus> decodePermissionRequestResult(
Map<int, int> value) {
return value.map((key, value) =>
MapEntry<PermissionGroup, PermissionStatus>(
PermissionGroup.values[key], PermissionStatus.values[value]));
return value.map((key, value) => MapEntry<Permission, PermissionStatus>(
Permission.byValue(key), PermissionStatusValue.statusByValue(value)));
}
/// Converts the supplied [List] containing [PermissionGroup] instances into
/// a [List] containing integers which can be used to send on the Flutter
/// method channel.
static List<int> encodePermissionGroups(List<PermissionGroup> permissions) {
/// Converts the given [List] of [Permission]s into a [List] of [int]s which
/// can be sent on the Flutter method channel.
static List<int> encodePermissions(List<Permission> permissions) {
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;
/// 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
/// as `permission_handler` does not consider newly added methods to be
......@@ -21,71 +21,67 @@ abstract class PermissionHandlerPlatform extends PlatformInterface {
/// Defaults to [MethodChannelPermissionHandler].
static PermissionHandlerPlatform get instance => _instance;
/// Platform-specific plugins should set this with their own platform-specific
/// class that extends [PermissionHandlerPlatform] when they register themselves.
/// Platform-specific plugins should set this with their own
/// platform-specific class that extends
/// [PermissionHandlerPlatform] when they register themselves.
static set instance(PermissionHandlerPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
/// Check current permission status.
///
/// Returns a [Future] containing the current permission status for the
/// supplied [PermissionGroup].
Future<PermissionStatus> checkPermissionStatus(PermissionGroup permission) {
/// Checks the current status of the given [Permission].
Future<PermissionStatus> checkPermissionStatus(Permission permission) {
throw UnimplementedError(
'checkPermissionStatus() has not been implemented.');
}
/// Check current service status.
///
/// Returns a [Future] containing the current service status for the supplied
/// [PermissionGroup].
/// Checks the current status of the service associated with the given
/// [Permission].
///
/// Notes about specific PermissionGroups:
/// - **PermissionGroup.phone**
/// Notes about specific permissions:
/// - **[Permission.phone]**
/// - Android:
/// - The method will return [ServiceStatus.notApplicable] when:
/// 1. the device lacks the TELEPHONY feature
/// 1. TelephonyManager.getPhoneType() returns PHONE_TYPE_NONE
/// 1. when no Intents can be resolved to handle the `tel:` scheme
/// - 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:
/// 1. the SIM card is missing
/// - the SIM card is missing
/// - iOS:
/// - 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:
/// 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
/// - **PLEASE NOTE that this is still not a perfect indication** of the
/// devices' capability to place & connect phone calls
/// as it also depends on the network condition.
Future<ServiceStatus> checkServiceStatus(PermissionGroup permission) {
/// device's capability to place & connect phone calls as it also depends
/// on the network condition.
Future<ServiceStatus> checkServiceStatus(Permission permission) {
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,
/// otherwise [false] is returned.
/// Returns [true] if the app settings page could be opened, otherwise
/// [false].
Future<bool> openAppSettings() {
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.
Future<Map<PermissionGroup, PermissionStatus>> requestPermissions(
List<PermissionGroup> permissions) {
/// Returns a [Map] containing the status per requested [Permission].
Future<Map<Permission, PermissionStatus>> requestPermissions(
List<Permission> permissions) {
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
/// returns [false].
Future<bool> shouldShowRequestPermissionRationale(
PermissionGroup permission) {
Future<bool> shouldShowRequestPermissionRationale(Permission permission) {
throw UnimplementedError(
'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.
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
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
version: 1.0.0
version: 2.0.0
dependencies:
flutter:
......@@ -18,5 +18,5 @@ dev_dependencies:
effective_dart: ^1.2.1
environment:
sdk: ">=2.0.0-dev.28.0 <3.0.0"
flutter: ">=1.9.1+hotfix.4 <2.0.0"
\ No newline at end of file
sdk: ">=2.6.0 <3.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