fbmobile/lib/core/services/permission_service.dart
Varakh e661171fd2
All checks were successful
/ build (push) Successful in 5m17s
Various improvements and #noissue
- Bumped Android minSdk to 30 (Android 11)
- Fixed permission service not handling Android SDK 33 correctly
- Fixed permission service not being started during application start
2023-11-26 23:53:17 +01:00

149 lines
4.5 KiB
Dart

import 'dart:async';
import 'dart:io' show Platform;
import 'package:device_info_plus/device_info_plus.dart';
import 'package:logger/logger.dart';
import 'package:permission_handler/permission_handler.dart';
import '../../constants.dart';
import '../../core/services/stoppable_service.dart';
import '../../core/util/logger.dart';
class PermissionService extends StoppableService {
final Logger _logger = getLogger();
Timer? _serviceCheckTimer;
bool _devicePermissionDialogActive = false;
bool _deviceInformationInitialized = false;
bool _useStoragePermission = true;
PermissionService();
Future checkEnabledAndPermission() async {
if (_devicePermissionDialogActive) {
_logger.d('Device permission dialog active, skipping');
return;
}
bool allGranted = false;
bool anyPermanentlyDenied = false;
// Since Android compileSdk >= 33, "storage" is deprecated
// Instead, request access to all of
// - Permission.photos
// - Permission.videos
// - Permission.audio
//
// For iOS and Android < 33, keep using "storage"
if (_useStoragePermission) {
PermissionStatus storagePermission = await Permission.storage.status;
allGranted = PermissionStatus.granted == storagePermission;
anyPermanentlyDenied =
PermissionStatus.permanentlyDenied == storagePermission;
} else {
PermissionStatus photosPermission = await Permission.photos.status;
PermissionStatus videosPermission = await Permission.videos.status;
PermissionStatus audioPermission = await Permission.audio.status;
allGranted = PermissionStatus.granted == photosPermission &&
PermissionStatus.granted == videosPermission &&
PermissionStatus.granted == audioPermission;
anyPermanentlyDenied =
PermissionStatus.permanentlyDenied == photosPermission ||
PermissionStatus.permanentlyDenied == videosPermission ||
PermissionStatus.permanentlyDenied == audioPermission;
}
// show warning to user to manually handle, don't enforce it over and over again
if (anyPermanentlyDenied) {
_logger.w(
"At least one required permission has been denied permanently, stopping service");
stop();
return;
}
// all good, stop the permission service
if (allGranted) {
_logger.d("All permissions have been granted, stopping service");
stop();
return;
}
// not all have been granted, show OS dialog
_logger.d(
"Not all permissions have been granted yet, initializing permission dialog");
_devicePermissionDialogActive = true;
if (_useStoragePermission) {
await [Permission.storage].request().whenComplete(() {
_logger.d('Device request permission finished');
_devicePermissionDialogActive = false;
});
} else {
await [Permission.photos, Permission.videos, Permission.audio]
.request()
.whenComplete(() {
_logger.d('Device request permission finished');
_devicePermissionDialogActive = false;
});
}
}
@override
Future start() async {
super.start();
await _determineDeviceInfo();
await checkEnabledAndPermission();
_serviceCheckTimer = Timer.periodic(
const Duration(milliseconds: Constants.mediaPermissionCheckInterval),
(serviceTimer) async {
if (!super.serviceStopped) {
await checkEnabledAndPermission();
} else {
serviceTimer.cancel();
}
});
_logger.d('PermissionService started');
}
@override
void stop() {
_removeServiceCheckTimer();
super.stop();
_logger.d('PermissionService stopped');
}
Future _determineDeviceInfo() async {
if (_deviceInformationInitialized) {
_logger.d('Device information already initialized, skipping');
return;
}
DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
if (Platform.isAndroid) {
final androidInfo = await deviceInfoPlugin.androidInfo;
if (androidInfo.version.sdkInt >= 33) {
_useStoragePermission = false;
}
}
if (_useStoragePermission) {
_logger.d('Device requires [storage] permission');
} else {
_logger.d('Device requires [photos,videos,audio] permission');
}
_deviceInformationInitialized = true;
}
void _removeServiceCheckTimer() {
if (_serviceCheckTimer != null) {
_serviceCheckTimer!.cancel();
_serviceCheckTimer = null;
_logger.d('Removed service check timer');
}
}
}