fix(#443): guard battery-optimization platform calls (Gemini review)

Gemini flagged two unhandled PlatformException paths (SAFELANE §6):
- isIgnoringBatteryOptimizations could throw -> banner silently never shows;
  now caught + logged, leaving the banner hidden on an unknown status.
- openIgnoreBatteryOptimizationSettings could throw -> button did nothing with
  no feedback; now caught + logged + a snackbar tells the user it failed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pull/460/head
Strycher 2 months ago
parent bd4701c6ff
commit 844cf69800

@ -2683,5 +2683,9 @@
"batteryOptimizationDismiss": "Dismiss",
"@batteryOptimizationDismiss": {
"description": "Tooltip for the button that hides the battery-optimization banner for this session (#443)."
},
"batteryOptimizationOpenFailed": "Couldn't open battery settings",
"@batteryOptimizationOpenFailed": {
"description": "Snackbar shown when the battery-optimization settings screen could not be opened (#443)."
}
}

@ -8079,6 +8079,12 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'Dismiss'**
String get batteryOptimizationDismiss;
/// Snackbar shown when the battery-optimization settings screen could not be opened (#443).
///
/// In en, this message translates to:
/// **'Couldn\'t open battery settings'**
String get batteryOptimizationOpenFailed;
}
class _AppLocalizationsDelegate

@ -4726,4 +4726,7 @@ class AppLocalizationsBg extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4743,4 +4743,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4648,4 +4648,7 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4731,4 +4731,7 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4759,4 +4759,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4748,4 +4748,7 @@ class AppLocalizationsHu extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4736,4 +4736,7 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4502,4 +4502,7 @@ class AppLocalizationsJa extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4503,4 +4503,7 @@ class AppLocalizationsKo extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4711,4 +4711,7 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4748,4 +4748,7 @@ class AppLocalizationsPl extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4724,4 +4724,7 @@ class AppLocalizationsPt extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4742,4 +4742,7 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4708,4 +4708,7 @@ class AppLocalizationsSk extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4706,4 +4706,7 @@ class AppLocalizationsSl extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4681,4 +4681,7 @@ class AppLocalizationsSv extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4743,4 +4743,7 @@ class AppLocalizationsUk extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -4376,4 +4376,7 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get batteryOptimizationDismiss => 'Dismiss';
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
}

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
import '../l10n/l10n.dart';
import '../utils/app_logger.dart';
import '../utils/platform_info.dart';
/// Warns the user when the app is NOT exempt from Android battery optimization
@ -58,15 +59,36 @@ class _BatteryOptimizationBannerState extends State<BatteryOptimizationBanner>
Future<void> _check() async {
if (!PlatformInfo.isAndroid) return;
final ignoring = await FlutterForegroundTask.isIgnoringBatteryOptimizations;
try {
final ignoring =
await FlutterForegroundTask.isIgnoringBatteryOptimizations;
if (!mounted) return;
setState(() => _ignoring = ignoring);
} catch (e) {
// Can't confirm the status — leave the banner hidden rather than risk a
// false warning, but surface the failure to the log (SAFELANE §6).
appLogger.warn(
'Battery-optimization status check failed: $e',
tag: 'BatteryBanner',
);
}
}
Future<void> _openSettings() async {
try {
await FlutterForegroundTask.openIgnoreBatteryOptimizationSettings();
// The user returns via resume, which triggers _check() and clears the
// banner if they applied the change.
} catch (e) {
appLogger.warn(
'Failed to open battery-optimization settings: $e',
tag: 'BatteryBanner',
);
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.batteryOptimizationOpenFailed)),
);
}
}
@override

Loading…
Cancel
Save

Powered by TurnKey Linux.