1. use XXPermissions to manage REQUEST_IGNORE_BATTERY_OPTIMIZATIONS.
2. pre-request permission on Start on Boot enabled.
This commit is contained in:
parent
73bc963311
commit
60ab29ad6e
@ -18,6 +18,7 @@ import android.provider.Settings
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
|
import com.hjq.permissions.XXPermissions
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
@ -76,7 +77,7 @@ class MainActivity : FlutterActivity() {
|
|||||||
}
|
}
|
||||||
"check_permission" -> {
|
"check_permission" -> {
|
||||||
if (call.arguments is String) {
|
if (call.arguments is String) {
|
||||||
result.success(checkPermission(context, call.arguments as String))
|
result.success(XXPermissions.isGranted(context, call.arguments as String))
|
||||||
} else {
|
} else {
|
||||||
result.success(false)
|
result.success(false)
|
||||||
}
|
}
|
||||||
@ -115,10 +116,6 @@ class MainActivity : FlutterActivity() {
|
|||||||
)
|
)
|
||||||
result.success(true)
|
result.success(true)
|
||||||
}
|
}
|
||||||
"init_input" -> {
|
|
||||||
initInput()
|
|
||||||
result.success(true)
|
|
||||||
}
|
|
||||||
"stop_input" -> {
|
"stop_input" -> {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
InputService.ctx?.disableSelf()
|
InputService.ctx?.disableSelf()
|
||||||
@ -177,13 +174,6 @@ class MainActivity : FlutterActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initInput() {
|
|
||||||
val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
|
|
||||||
if (intent.resolveActivity(packageManager) != null) {
|
|
||||||
startActivity(intent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
val inputPer = InputService.isOpen
|
val inputPer = InputService.isOpen
|
||||||
|
@ -13,6 +13,7 @@ import android.os.Build
|
|||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
|
import android.provider.Settings
|
||||||
import android.provider.Settings.*
|
import android.provider.Settings.*
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.content.ContextCompat.getSystemService
|
import androidx.core.content.ContextCompat.getSystemService
|
||||||
@ -41,8 +42,6 @@ const val START_ACTION = "start_action"
|
|||||||
const val GET_START_ON_BOOT_OPT = "get_start_on_boot_opt"
|
const val GET_START_ON_BOOT_OPT = "get_start_on_boot_opt"
|
||||||
const val SET_START_ON_BOOT_OPT = "set_start_on_boot_opt"
|
const val SET_START_ON_BOOT_OPT = "set_start_on_boot_opt"
|
||||||
|
|
||||||
const val IGNORE_BATTERY_OPTIMIZATIONS = "ignore_battery_optimizations"
|
|
||||||
|
|
||||||
const val KEY_SHARED_PREFERENCES = "KEY_SHARED_PREFERENCES"
|
const val KEY_SHARED_PREFERENCES = "KEY_SHARED_PREFERENCES"
|
||||||
const val KEY_START_ON_BOOT_OPT = "KEY_START_ON_BOOT_OPT"
|
const val KEY_START_ON_BOOT_OPT = "KEY_START_ON_BOOT_OPT"
|
||||||
|
|
||||||
@ -70,21 +69,15 @@ fun requestPermission(context: Context, type: String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
fun checkPermission(context: Context, type: String): Boolean {
|
|
||||||
if (IGNORE_BATTERY_OPTIMIZATIONS == type) {
|
|
||||||
val pw = context.getSystemService(Context.POWER_SERVICE) as PowerManager
|
|
||||||
return pw.isIgnoringBatteryOptimizations(context.packageName)
|
|
||||||
}
|
|
||||||
return XXPermissions.isGranted(context, type)
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
@RequiresApi(Build.VERSION_CODES.M)
|
||||||
fun startAction(context: Context, action: String) {
|
fun startAction(context: Context, action: String) {
|
||||||
try {
|
try {
|
||||||
context.startActivity(Intent(action).apply {
|
context.startActivity(Intent(action).apply {
|
||||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
data = Uri.parse("package:" + context.packageName)
|
// don't pass package name when launch ACTION_ACCESSIBILITY_SETTINGS
|
||||||
|
if (ACTION_ACCESSIBILITY_SETTINGS != action) {
|
||||||
|
data = Uri.parse("package:" + context.packageName)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
@ -931,6 +931,8 @@ class AndroidPermissionManager {
|
|||||||
gFFI.invokeMethod(AndroidChannel.kStartAction, action);
|
gFFI.invokeMethod(AndroidChannel.kStartAction, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// We use XXPermissions to request permissions,
|
||||||
|
/// for supported types, see https://github.com/getActivity/XXPermissions/blob/e46caea32a64ad7819df62d448fb1c825481cd28/library/src/main/java/com/hjq/permissions/Permission.java
|
||||||
static Future<bool> request(String type) {
|
static Future<bool> request(String type) {
|
||||||
if (isDesktop) {
|
if (isDesktop) {
|
||||||
return Future.value(true);
|
return Future.value(true);
|
||||||
@ -938,17 +940,16 @@ class AndroidPermissionManager {
|
|||||||
|
|
||||||
gFFI.invokeMethod("request_permission", type);
|
gFFI.invokeMethod("request_permission", type);
|
||||||
|
|
||||||
// kIgnoreBatteryOptimizations permission doesn't depend on callback result, the result will be checked and updated on page resume
|
// clear last task
|
||||||
if (type == kIgnoreBatteryOptimizations) {
|
if (_completer?.isCompleted == false) {
|
||||||
return Future.value(false);
|
_completer?.complete(false);
|
||||||
}
|
}
|
||||||
|
_timer?.cancel();
|
||||||
|
|
||||||
_current = type;
|
_current = type;
|
||||||
_completer = Completer<bool>();
|
_completer = Completer<bool>();
|
||||||
|
|
||||||
// timeout
|
_timer = Timer(Duration(seconds: 120), () {
|
||||||
_timer?.cancel();
|
|
||||||
_timer = Timer(Duration(seconds: 60), () {
|
|
||||||
if (_completer == null) return;
|
if (_completer == null) return;
|
||||||
if (!_completer!.isCompleted) {
|
if (!_completer!.isCompleted) {
|
||||||
_completer!.complete(false);
|
_completer!.complete(false);
|
||||||
|
@ -140,17 +140,14 @@ const kIgnoreDpi = true;
|
|||||||
/// Android constants
|
/// Android constants
|
||||||
const kActionApplicationDetailsSettings =
|
const kActionApplicationDetailsSettings =
|
||||||
"android.settings.APPLICATION_DETAILS_SETTINGS";
|
"android.settings.APPLICATION_DETAILS_SETTINGS";
|
||||||
const kActionRequestIgnoreBatteryOptimizations =
|
|
||||||
"android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
|
|
||||||
const kActionAccessibilitySettings = "android.settings.ACCESSIBILITY_SETTINGS";
|
const kActionAccessibilitySettings = "android.settings.ACCESSIBILITY_SETTINGS";
|
||||||
|
|
||||||
const kRecordAudio = "android.permission.RECORD_AUDIO";
|
const kRecordAudio = "android.permission.RECORD_AUDIO";
|
||||||
const kManageExternalStorage = "android.permission.MANAGE_EXTERNAL_STORAGE";
|
const kManageExternalStorage = "android.permission.MANAGE_EXTERNAL_STORAGE";
|
||||||
|
const kRequestIgnoreBatteryOptimizations =
|
||||||
|
"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
|
||||||
const kSystemAlertWindow = "android.permission.SYSTEM_ALERT_WINDOW";
|
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
|
/// Android channel invoke type key
|
||||||
class AndroidChannel {
|
class AndroidChannel {
|
||||||
static final kStartAction = "start_action";
|
static final kStartAction = "start_action";
|
||||||
|
@ -65,7 +65,6 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
update = true;
|
update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO need input
|
|
||||||
// start on boot depends on ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS and SYSTEM_ALERT_WINDOW
|
// start on boot depends on ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS and SYSTEM_ALERT_WINDOW
|
||||||
var enableStartOnBoot =
|
var enableStartOnBoot =
|
||||||
await gFFI.invokeMethod(AndroidChannel.kGetStartOnBootOpt);
|
await gFFI.invokeMethod(AndroidChannel.kGetStartOnBootOpt);
|
||||||
@ -162,8 +161,8 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> checkAndUpdateIgnoreBatteryStatus() async {
|
Future<bool> checkAndUpdateIgnoreBatteryStatus() async {
|
||||||
final res =
|
final res = await AndroidPermissionManager.check(
|
||||||
await AndroidPermissionManager.check(kIgnoreBatteryOptimizations);
|
kRequestIgnoreBatteryOptimizations);
|
||||||
if (_ignoreBatteryOpt != res) {
|
if (_ignoreBatteryOpt != res) {
|
||||||
_ignoreBatteryOpt = res;
|
_ignoreBatteryOpt = res;
|
||||||
return true;
|
return true;
|
||||||
@ -305,8 +304,8 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
]),
|
]),
|
||||||
onToggle: (v) async {
|
onToggle: (v) async {
|
||||||
if (v) {
|
if (v) {
|
||||||
AndroidPermissionManager.startAction(
|
await AndroidPermissionManager.request(
|
||||||
kActionRequestIgnoreBatteryOptimizations);
|
kRequestIgnoreBatteryOptimizations);
|
||||||
} else {
|
} else {
|
||||||
final res = await gFFI.dialogManager
|
final res = await gFFI.dialogManager
|
||||||
.show<bool>((setState, close) => CustomAlertDialog(
|
.show<bool>((setState, close) => CustomAlertDialog(
|
||||||
@ -332,17 +331,34 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
enhancementsTiles.add(SettingsTile.switchTile(
|
enhancementsTiles.add(SettingsTile.switchTile(
|
||||||
initialValue: _enableStartOnBoot,
|
initialValue: _enableStartOnBoot,
|
||||||
title: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
title: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
Text("$translate('Start on Boot') (beta)"),
|
Text("${translate('Start on Boot')} (beta)"),
|
||||||
Text(
|
Text(
|
||||||
'* ${translate('Start the screen recording service on boot, which requires special permissions')}',
|
'* ${translate('Start the screen recording service on boot, which requires special permissions')}',
|
||||||
style: Theme.of(context).textTheme.bodySmall),
|
style: Theme.of(context).textTheme.bodySmall),
|
||||||
]),
|
]),
|
||||||
onToggle: (v) async {
|
onToggle: (toValue) async {
|
||||||
if (v) {
|
if (toValue) {
|
||||||
// TODO
|
// 1. request kIgnoreBatteryOptimizations
|
||||||
} else {
|
if (!await AndroidPermissionManager.check(
|
||||||
gFFI.invokeMethod(AndroidChannel.kSetStartOnBootOpt, false);
|
kRequestIgnoreBatteryOptimizations)) {
|
||||||
|
if (!await AndroidPermissionManager.request(
|
||||||
|
kRequestIgnoreBatteryOptimizations)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. request kSystemAlertWindow
|
||||||
|
if (!await AndroidPermissionManager.check(kSystemAlertWindow)) {
|
||||||
|
if (!await AndroidPermissionManager.request(kSystemAlertWindow)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (Optional) 3. request input permission
|
||||||
}
|
}
|
||||||
|
setState(() => _enableStartOnBoot = toValue);
|
||||||
|
|
||||||
|
gFFI.invokeMethod(AndroidChannel.kSetStartOnBootOpt, toValue);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return SettingsList(
|
return SettingsList(
|
||||||
@ -446,7 +462,6 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool canStartOnBoot() {
|
bool canStartOnBoot() {
|
||||||
// TODO need input
|
|
||||||
// start on boot depends on ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS and SYSTEM_ALERT_WINDOW
|
// start on boot depends on ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS and SYSTEM_ALERT_WINDOW
|
||||||
if (_hasIgnoreBattery && !_ignoreBatteryOpt) {
|
if (_hasIgnoreBattery && !_ignoreBatteryOpt) {
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user