forked from Baseflow/flutter-permission-handler
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
checkPermissionStatus
for normal permissions (Baseflow#1198)
* Implement `checkPermissionStatus` * Add tests * Make small touch-ups * Run `dart format .`
- Loading branch information
1 parent
24d756f
commit 28a934c
Showing
17 changed files
with
625 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 2 additions & 0 deletions
2
permission_handler_android/lib/permission_handler_android.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
export 'src/android_object_mirrors/activity.dart'; | ||
export 'src/android_object_mirrors/activity_compat.dart'; | ||
export 'src/android_object_mirrors/manifest.dart'; | ||
export 'src/extensions.dart'; | ||
export 'src/missing_android_activity_exception.dart'; | ||
|
||
export 'src/android.dart'; | ||
export 'src/permission_handler_android.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
permission_handler_android/lib/src/android_object_mirrors/package_manager.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/// Class for retrieving various kinds of information related to the application | ||
/// packages that are currently installed on the device. You can find this class | ||
/// through Context#getPackageManager. | ||
/// | ||
/// See https://developer.android.com/reference/android/content/pm/PackageManager. | ||
class PackageManager { | ||
const PackageManager._(); | ||
|
||
/// Permission check result: this is returned by checkPermission(String, String) if the permission has not been granted to the given package. | ||
/// | ||
/// Constant Value: -1 (0xffffffff) | ||
static const int permissionDenied = -1; | ||
|
||
/// Permission check result: this is returned by checkPermission(String, String) if the permission has been granted to the given package. | ||
/// | ||
/// Constant Value: 0 (0x00000000) | ||
static const int permissionGranted = 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart'; | ||
|
||
import 'android_object_mirrors/manifest.dart'; | ||
|
||
/// An extension on [Permission] that provides a [manifestStrings] getter. | ||
extension PermissionToManifestStrings on Permission { | ||
/// Returns the matching Manifest.permission strings for this permission. | ||
/// | ||
/// TODO(jweener): translate all permissions that will be universally | ||
/// available. | ||
List<String> get manifestStrings { | ||
// ignore: deprecated_member_use | ||
if (this == Permission.calendarFullAccess || this == Permission.calendar) { | ||
return [ | ||
Manifest.permission.readCalendar, | ||
Manifest.permission.writeCalendar, | ||
]; | ||
} else if (this == Permission.calendarWriteOnly) { | ||
return [Manifest.permission.writeCalendar]; | ||
} else if (this == Permission.camera) { | ||
return [Manifest.permission.camera]; | ||
} | ||
|
||
throw UnimplementedError( | ||
'There is no matching Manifest.permission string for $this', | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart'; | ||
import 'package:shared_preferences/shared_preferences.dart'; | ||
|
||
import 'android_object_mirrors/activity.dart'; | ||
import 'android_object_mirrors/activity_compat.dart'; | ||
import 'android_object_mirrors/package_manager.dart'; | ||
|
||
/// A class that provides methods for setting and getting whether a manifest | ||
/// permission was denied before. | ||
class ManifestPersistentStorage { | ||
const ManifestPersistentStorage._(); | ||
|
||
/// Writes to shared preferences that the permission was denied before. | ||
static Future<void> setDeniedBefore(String manifestString) async { | ||
final sp = await SharedPreferences.getInstance(); | ||
sp.setBool(manifestString, true); | ||
} | ||
|
||
/// Reads from shared preferences if the permission was denied before. | ||
static Future<bool> wasDeniedBefore(String manifestString) async { | ||
final sp = await SharedPreferences.getInstance(); | ||
return sp.getBool(manifestString) ?? false; | ||
} | ||
} | ||
|
||
/// Returns a [PermissionStatus] for a given manifest permission. | ||
/// | ||
/// Note: This method has side-effects as it will store whether the permission | ||
/// was denied before in persistent memory. | ||
/// | ||
/// When [PackageManager.permissionDenied] is received, we do not know if the | ||
/// permission was denied permanently. The OS does not tell us whether the | ||
/// user dismissed the dialog or pressed 'deny'. Therefore, we need a more | ||
/// sophisticated (read: hacky) approach to determine whether the permission | ||
/// status is [PermissionStatus.denied] or | ||
/// [PermissionStatus.permanentlyDenied]. | ||
/// | ||
/// The OS behavior has been researched experimentally and is displayed in the | ||
/// following diagrams: | ||
/// | ||
/// **State machine diagram:** | ||
/// | ||
/// Dismissed | ||
/// ┌┐ | ||
/// ┌──┘▼─────┐ Granted ┌───────┐ | ||
/// │Not asked├──────────►Granted│ | ||
/// └─┬───────┘ └─▲─────┘ | ||
/// │ Granted │ | ||
/// │Denied ┌───────────┘ | ||
/// │ │ | ||
/// ┌─▼────────┴┐ ┌────────────────────────────────┐ | ||
/// │Denied once├────────►Denied twice(permanently denied)│ | ||
/// └──▲┌───────┘ Denied └────────────────────────────────┘ | ||
/// └┘ | ||
/// Dismissed | ||
/// | ||
/// **Scenario table listing output of | ||
/// [ActivityCompat.shouldShowRequestPermissionRationale]:** | ||
/// | ||
/// ┌────────────┬────────────────┬─────────┬───────────────────────────────────┬─────────────────────────┐ | ||
/// │ Scenario # │ Previous state │ Action │ New state │ 'Show rationale' output │ | ||
/// ├────────────┼────────────────┼─────────┼───────────────────────────────────┼─────────────────────────┤ | ||
/// │ 1. │ Not asked │ Dismiss │ Not asked │ false │ | ||
/// │ 2. │ Not asked │ Deny │ Denied once │ true │ | ||
/// │ 3. │ Denied once │ Dismiss │ Denied once │ true │ | ||
/// │ 4. │ Denied once │ Deny │ Denied twice (permanently denied) │ false │ | ||
/// └────────────┴────────────────┴─────────┴───────────────────────────────────┴─────────────────────────┘ | ||
/// | ||
/// To distinguish between scenarios, we can use | ||
/// [ActivityCompat.shouldShowRequestPermissionRationale]. If it returns true, | ||
/// we can safely return [PermissionStatus.denied]. To distinguish between | ||
/// scenarios 1 and 4, however, we need an extra mechanism. We opt to store a | ||
/// boolean stating whether permission has been requested before. Using a | ||
/// combination of checking for showing the permission rationale and the | ||
/// boolean, we can distinguish all scenarios and return the appropriate | ||
/// permission status. | ||
/// | ||
/// Changing permissions via the app info screen (so outside of the application) | ||
/// changes the permission state to 'Granted' if the permission is allowed, or | ||
/// 'Denied once' if denied. This behavior should not require any additional | ||
/// logic. | ||
Future<PermissionStatus> grantResultToPermissionStatus( | ||
Activity activity, | ||
String manifestString, | ||
int grantResult, | ||
) async { | ||
if (grantResult == PackageManager.permissionGranted) { | ||
return PermissionStatus.granted; | ||
} | ||
|
||
final bool wasDeniedBefore = | ||
await ManifestPersistentStorage.wasDeniedBefore(manifestString); | ||
final bool shouldShowRationale = | ||
await ActivityCompat.shouldShowRequestPermissionRationale( | ||
activity, | ||
manifestString, | ||
); | ||
|
||
final bool isDeniedNow = | ||
wasDeniedBefore ? !shouldShowRationale : shouldShowRationale; | ||
|
||
if (!wasDeniedBefore && isDeniedNow) { | ||
ManifestPersistentStorage.setDeniedBefore(manifestString); | ||
} | ||
|
||
if (wasDeniedBefore && isDeniedNow) { | ||
return PermissionStatus.permanentlyDenied; | ||
} | ||
return PermissionStatus.denied; | ||
} |
Oops, something went wrong.