opt AndroidPermissionManager

This commit is contained in:
csf
2023-02-28 00:41:09 +09:00
parent 63185a5bcb
commit 8cd9f8745d
7 changed files with 85 additions and 101 deletions

View File

@@ -907,21 +907,14 @@ class AccessibilityListener extends StatelessWidget {
}
}
class PermissionManager {
class AndroidPermissionManager {
static Completer<bool>? _completer;
static Timer? _timer;
static var _current = "";
static final permissions = [
"audio",
"file",
"ignore_battery_optimizations",
"application_details_settings"
];
static bool isWaitingFile() {
if (_completer != null) {
return !_completer!.isCompleted && _current == "file";
return !_completer!.isCompleted && _current == kManageExternalStorage;
}
return false;
}
@@ -930,9 +923,6 @@ class PermissionManager {
if (isDesktop) {
return Future.value(true);
}
if (!permissions.contains(type)) {
return Future.error("Wrong permission!$type");
}
return gFFI.invokeMethod("check_permission", type);
}
@@ -940,17 +930,16 @@ class PermissionManager {
if (isDesktop) {
return Future.value(true);
}
if (!permissions.contains(type)) {
return Future.error("Wrong permission!$type");
}
gFFI.invokeMethod("request_permission", type);
if (type == "ignore_battery_optimizations") {
// kIgnoreBatteryOptimizations permission doesn't depend on callback result, the result will be checked and updated on page resume
if (type == kIgnoreBatteryOptimizations) {
return Future.value(false);
}
_current = type;
_completer = Completer<bool>();
gFFI.invokeMethod("request_permission", type);
// timeout
_timer?.cancel();
@@ -1484,8 +1473,8 @@ connect(BuildContext context, String id,
}
} else {
if (isFileTransfer) {
if (!await PermissionManager.check("file")) {
if (!await PermissionManager.request("file")) {
if (!await AndroidPermissionManager.check(kManageExternalStorage)) {
if (!await AndroidPermissionManager.request(kManageExternalStorage)) {
return;
}
}

View File

@@ -59,11 +59,12 @@ const double kDesktopFileTransferMaximumWidth = 300;
const double kDesktopFileTransferRowHeight = 30.0;
const double kDesktopFileTransferHeaderHeight = 25.0;
EdgeInsets get kDragToResizeAreaPadding => !kUseCompatibleUiMode && Platform.isLinux
? stateGlobal.fullscreen || stateGlobal.maximize
? EdgeInsets.zero
: EdgeInsets.all(5.0)
: EdgeInsets.zero;
EdgeInsets get kDragToResizeAreaPadding =>
!kUseCompatibleUiMode && Platform.isLinux
? stateGlobal.fullscreen || stateGlobal.maximize
? EdgeInsets.zero
: EdgeInsets.all(5.0)
: EdgeInsets.zero;
// https://en.wikipedia.org/wiki/Non-breaking_space
const int $nbsp = 0x00A0;
@@ -136,6 +137,21 @@ const kRemoteAudioDualWay = 'dual-way';
const kIgnoreDpi = true;
/// Android constants
const kActionApplicationDetailsSettings =
"android.settings.APPLICATION_DETAILS_SETTINGS";
const kActionRequestIgnoreBatteryOptimizations =
"android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
const kRecordAudio = "android.permission.RECORD_AUDIO";
const kManageExternalStorage = "android.permission.MANAGE_EXTERNAL_STORAGE";
const kSystemAlertWindow = "android.permission.SYSTEM_ALERT_WINDOW";
/// [kIgnoreBatteryOptimizations] not a Android Permission, it is a custom key, used in `ignore battery optimizations` check
const kIgnoreBatteryOptimizations = "ignore_battery_optimizations";
/// Android channel invoke type key
const kStartAction = "start_action";
/// flutter/packages/flutter/lib/src/services/keyboard_key.dart -> _keyLabels
/// see [LogicalKeyboardKey.keyLabel]
const Map<int, String> logicalKeyMap = <int, String>{

View File

@@ -6,6 +6,7 @@ import 'package:provider/provider.dart';
import '../../common.dart';
import '../../common/widgets/dialog.dart';
import '../../consts.dart';
import '../../models/platform_model.dart';
import '../../models/server_model.dart';
import 'home_page.dart';
@@ -150,10 +151,11 @@ class _ServerPageState extends State<ServerPage> {
}
void checkService() async {
gFFI.invokeMethod("check_service"); // jvm
// for Android 10/11,MANAGE_EXTERNAL_STORAGE permission from a system setting page
if (PermissionManager.isWaitingFile() && !gFFI.serverModel.fileOk) {
PermissionManager.complete("file", await PermissionManager.check("file"));
gFFI.invokeMethod("check_service");
// for Android 10/11, request MANAGE_EXTERNAL_STORAGE permission from system setting page
if (AndroidPermissionManager.isWaitingFile() && !gFFI.serverModel.fileOk) {
AndroidPermissionManager.complete(kManageExternalStorage,
await AndroidPermissionManager.check(kManageExternalStorage));
debugPrint("file permission finished");
}
}
@@ -567,7 +569,7 @@ void androidChannelInit() {
{
var type = arguments["type"] as String;
var result = arguments["result"] as bool;
PermissionManager.complete(type, result);
AndroidPermissionManager.complete(type, result);
break;
}
case "on_media_projection_canceled":

View File

@@ -10,6 +10,7 @@ import 'package:url_launcher/url_launcher.dart';
import '../../common.dart';
import '../../common/widgets/dialog.dart';
import '../../common/widgets/login.dart';
import '../../consts.dart';
import '../../models/model.dart';
import '../../models/platform_model.dart';
import '../widgets/dialog.dart';
@@ -133,7 +134,8 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
}
Future<bool> updateIgnoreBatteryStatus() async {
final res = await PermissionManager.check("ignore_battery_optimizations");
final res =
await AndroidPermissionManager.check(kIgnoreBatteryOptimizations);
if (_ignoreBatteryOpt != res) {
_ignoreBatteryOpt = res;
return true;
@@ -265,7 +267,8 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
]),
onToggle: (v) async {
if (v) {
PermissionManager.request("ignore_battery_optimizations");
gFFI.invokeMethod(
kStartAction, kActionRequestIgnoreBatteryOptimizations);
} else {
final res = await gFFI.dialogManager
.show<bool>((setState, close) => CustomAlertDialog(
@@ -282,7 +285,8 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
],
));
if (res == true) {
PermissionManager.request("application_details_settings");
gFFI.invokeMethod(
kStartAction, kActionApplicationDetailsSettings);
}
}
}));

View File

@@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_hbb/consts.dart';
import 'package:flutter_hbb/main.dart';
import 'package:flutter_hbb/models/platform_model.dart';
import 'package:get/get.dart';
@@ -154,7 +155,8 @@ class ServerModel with ChangeNotifier {
/// file true by default (if permission on)
checkAndroidPermission() async {
// audio
if (androidVersion < 30 || !await PermissionManager.check("audio")) {
if (androidVersion < 30 ||
!await AndroidPermissionManager.check(kRecordAudio)) {
_audioOk = false;
bind.mainSetOption(key: "enable-audio", value: "N");
} else {
@@ -163,7 +165,7 @@ class ServerModel with ChangeNotifier {
}
// file
if (!await PermissionManager.check("file")) {
if (!await AndroidPermissionManager.check(kManageExternalStorage)) {
_fileOk = false;
bind.mainSetOption(key: "enable-file-transfer", value: "N");
} else {
@@ -229,8 +231,8 @@ class ServerModel with ChangeNotifier {
}
toggleAudio() async {
if (!_audioOk && !await PermissionManager.check("audio")) {
final res = await PermissionManager.request("audio");
if (!_audioOk && !await AndroidPermissionManager.check(kRecordAudio)) {
final res = await AndroidPermissionManager.request(kRecordAudio);
if (!res) {
// TODO handle fail
return;
@@ -243,8 +245,10 @@ class ServerModel with ChangeNotifier {
}
toggleFile() async {
if (!_fileOk && !await PermissionManager.check("file")) {
final res = await PermissionManager.request("file");
if (!_fileOk &&
!await AndroidPermissionManager.check(kManageExternalStorage)) {
final res =
await AndroidPermissionManager.request(kManageExternalStorage);
if (!res) {
// TODO handle fail
return;
@@ -561,7 +565,8 @@ class ServerModel with ChangeNotifier {
}
Future<void> closeAll() async {
await Future.wait(_clients.map((client) => bind.cmCloseConnection(connId: client.id)));
await Future.wait(
_clients.map((client) => bind.cmCloseConnection(connId: client.id)));
_clients.clear();
tabController.state.value.tabs.clear();
}