Skip to content

Commit

Permalink
Fix aos storage permission not be requested when api above 33 (#168)
Browse files Browse the repository at this point in the history
* chore: add image/video, music/audio permission into android manifest

* feat: seperate permission request content by aos api 33

* chore: add device into package

* refactor: migrate file page to null safety, with pieces of UI improvements such as color

* refactor: null-safety migrations
  • Loading branch information
Xanonymous-GitHub authored Feb 16, 2023
1 parent 327f239 commit 510d499
Show file tree
Hide file tree
Showing 12 changed files with 296 additions and 266 deletions.
11 changes: 7 additions & 4 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Remove the REQUEST_INSTALL_PACKAGES permission since the `open_file` package has enabled this permission. -->
<!-- TODO: migrate to `open_file_safe` package or modify dependencies in `alice` -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" tools:node="remove"/>

<application
Expand Down
4 changes: 1 addition & 3 deletions lib/src/config/constants.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// TODO: remove sdk version selector after migrating to null-safety.
// @dart=2.10
class Constants {
static List sortList = [
static List<String> sortList = [
"File name (A to Z)",
"File name (Z to A)",
"Date (oldest first)",
Expand Down
63 changes: 34 additions & 29 deletions lib/src/providers/category_provider.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// TODO: remove sdk version selector after migrating to null-safety.
// @dart=2.10
import 'dart:io';

import 'package:flutter/foundation.dart';
Expand All @@ -15,14 +13,14 @@ class CategoryProvider extends ChangeNotifier {
}

bool loading = false;
List<FileSystemEntity> downloads = [];
List<String> downloadTabs = [];
final List<FileSystemEntity> downloads = [];
final List<String> downloadTabs = [];

List<FileSystemEntity> images = [];
List<String> imageTabs = [];
final List<FileSystemEntity> images = [];
final List<String> imageTabs = [];

List<FileSystemEntity> audio = [];
List<String> audioTabs = [];
final List<FileSystemEntity> audio = [];
final List<String> audioTabs = [];

bool showHidden = false;
int sort = 0;
Expand All @@ -32,15 +30,18 @@ class CategoryProvider extends ChangeNotifier {
downloadTabs.clear();
downloads.clear();
downloadTabs.add("All");
List<Directory> storages = await FileUtils.getStorageList();
for (var dir in storages) {
final List<Directory> storages = await FileUtils.getStorageList();
for (final dir in storages) {
if (Directory("${dir.path}Download").existsSync()) {
List<FileSystemEntity> files = Directory("${dir.path}Download").listSync();
final List<FileSystemEntity> files = Directory("${dir.path}Download").listSync();
for (final file in files) {
if (FileSystemEntity.isFileSync(file.path)) {
downloads.add(file);
downloadTabs.add(file.path.split("/")[file.path.split("/").length - 2]);
downloadTabs = downloadTabs.toSet().toList();
final tmpDownloadTabs = [...downloadTabs, file.path.split("/")[file.path.split("/").length - 2]]
..toSet().toList();
downloadTabs
..clear()
..addAll(tmpDownloadTabs);
notifyListeners();
}
}
Expand All @@ -54,13 +55,15 @@ class CategoryProvider extends ChangeNotifier {
imageTabs.clear();
images.clear();
imageTabs.add("All");
List<FileSystemEntity> files = await FileUtils.getAllFiles(showHidden: showHidden);
for (var file in files) {
String mimeType = mime(file.path) ?? "";
final List<FileSystemEntity> files = await FileUtils.getAllFiles(showHidden: showHidden);
for (final file in files) {
final mimeType = mime(file.path) ?? "";
if (mimeType.split("/")[0] == type) {
images.add(file);
imageTabs.add(file.path.split("/")[file.path.split("/").length - 2]);
imageTabs = imageTabs.toSet().toList();
final tmpImageTabs = [...imageTabs, file.path.split("/")[file.path.split("/").length - 2]]..toSet().toList();
imageTabs
..clear()
..addAll(tmpImageTabs);
}
notifyListeners();
}
Expand All @@ -72,17 +75,19 @@ class CategoryProvider extends ChangeNotifier {
audioTabs.clear();
audio.clear();
audioTabs.add("All");
List<FileSystemEntity> files = await FileUtils.getAllFiles(showHidden: showHidden);
for (var file in files) {
String mimeType = mime(file.path);
final List<FileSystemEntity> files = await FileUtils.getAllFiles(showHidden: showHidden);
for (final file in files) {
final mimeType = mime(file.path);
if (type == "text" && extension(file.path) == ".pdf") {
audio.add(file);
}
if (mimeType != null) {
if (mimeType.split("/")[0] == type) {
audio.add(file);
audioTabs.add(file.path.split("/")[file.path.split("/").length - 2]);
audioTabs = audioTabs.toSet().toList();
final tmpAudioTabs = [...audioTabs, file.path.split("/")[file.path.split("/").length - 2]]..toSet().toList();
audioTabs
..clear()
..addAll(tmpAudioTabs);
}
notifyListeners();
}
Expand All @@ -96,28 +101,28 @@ class CategoryProvider extends ChangeNotifier {
}

setHidden(value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setBool("hidden", value);
showHidden = value;
notifyListeners();
}

getHidden() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool h = prefs.getBool("hidden") ?? false;
final SharedPreferences prefs = await SharedPreferences.getInstance();
final bool h = prefs.getBool("hidden") ?? false;
setHidden(h);
}

Future setSort(value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setInt("sort", value);
sort = value;
notifyListeners();
}

getSort() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
int h = prefs.getInt("sort") ?? 0;
final SharedPreferences prefs = await SharedPreferences.getInstance();
final int h = prefs.getInt("sort") ?? 0;
setSort(h);
}
}
37 changes: 31 additions & 6 deletions lib/src/util/permissions_util.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,43 @@
import 'dart:io';

import 'package:device_info_plus/device_info_plus.dart';
import 'package:permission_handler/permission_handler.dart';

class PermissionsUtil {
/// Checks if the APP can access to the file sys on the current device.
///
/// If it can not access to, an External Storage (id = 15) warning will occurred.
/// So please check if the androidManifest.xml has the following permission declarations:
/// - uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
/// - uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
static Future<bool> checkHasAosStoragePermission() async {
// On iOS, the permission is managed by xcode project config.
if (Platform.isIOS) return true;
assert(Platform.isAndroid, 'The platform most be either aos or ios.');

return await Permission.storage.request().isGranted;
final deviceInfoPlugin = DeviceInfoPlugin();
final androidSdkVersion = (await deviceInfoPlugin.androidInfo).version.sdkInt;
final requiredPermissions = <Permission>[];

// About the new `Granular media permissions` policy:
// Above Android API 33, the permission of storage is split into image/videos and music/audio.
// Which means we can't request the `READ_EXTERNAL_STORAGE`.
// And since the `permission_handler v10.2.0` still not support the new policy,
// we have to request the separate permissions.
// Please refer to https://developer.android.com/about/versions/13/behavior-changes-13#granular-media-permissions
if (androidSdkVersion >= 33) {
requiredPermissions.addAll([
Permission.videos,
Permission.audio,
]);
} else {
requiredPermissions.addAll([
Permission.storage,
]);
}

await requiredPermissions.request();
final determineResult = await Future.wait(requiredPermissions.map((permission) => permission.isGranted));

// Since the requiredPermissions is a list, user can choose to grant or deny any of them.
// So we have to check if any of them (instead of `every`) is granted.
// This depends on all the permissions in the list are able to make the App
// access the device's storage once they've been granted.
return determineResult.any((permission) => permission);
}
}
Loading

0 comments on commit 510d499

Please sign in to comment.