Skip to content

Commit

Permalink
Add background fetch
Browse files Browse the repository at this point in the history
  • Loading branch information
AhsanSarwar45 committed Sep 10, 2024
1 parent e238789 commit 4f24909
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 30 deletions.
16 changes: 11 additions & 5 deletions lib/alarm/logic/alarm_isolate.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:developer';
import 'dart:isolate';
import 'dart:ui';

Expand Down Expand Up @@ -29,7 +30,8 @@ void triggerScheduledNotification(int scheduleId, Json params) async {
logger.f(details.exception.toString());
};

logger.i("Alarm isolate triggered $scheduleId");
logger.i(
"Alarm isolate triggered $scheduleId, isolate: ${Service.getIsolateId(Isolate.current)}");
// print("Alarm Trigger Isolate: ${Service.getIsolateID(Isolate.current)}");
if (params == null) {
logger.e("Params was null when triggering alarm");
Expand All @@ -52,9 +54,12 @@ void triggerScheduledNotification(int scheduleId, Json params) async {
IsolateNameServer.registerPortWithName(
receivePort.sendPort, stopAlarmPortName);
receivePort.listen((message) {
logger.d("Received message: $message");
stopScheduledNotification(message);
});

// Isolate.current.addOnExitListener(receivePort.sendPort);

if (notificationType == ScheduledNotificationType.alarm) {
triggerAlarm(scheduleId, params);
} else if (notificationType == ScheduledNotificationType.timer) {
Expand All @@ -75,6 +80,9 @@ void stopScheduledNotification(List<dynamic> message) {
} else if (notificationType == ScheduledNotificationType.timer) {
stopTimer(scheduleId, action);
}

logger.i(
"Alarm stop triggered $scheduleId, isolate: ${Service.getIsolateId(Isolate.current)}");
}

void triggerAlarm(int scheduleId, Json params) async {
Expand All @@ -86,7 +94,7 @@ void triggerAlarm(int scheduleId, Json params) async {

Alarm? alarm = getAlarmById(scheduleId);
DateTime now = DateTime.now();

// Note: this won't effect the variable `alarm` as we have already retrieved that
await updateAlarms("triggerAlarm(): Updating all alarms on trigger");

Expand All @@ -105,8 +113,7 @@ void triggerAlarm(int scheduleId, Json params) async {
return;
}
if (alarm.currentScheduleDateTime == null) {
logger.i(
"Skipping alarm $scheduleId because it has no scheduled date");
logger.i("Skipping alarm $scheduleId because it has no scheduled date");
return;
}
if (now.millisecondsSinceEpoch <
Expand Down Expand Up @@ -136,7 +143,6 @@ void triggerAlarm(int scheduleId, Json params) async {
RingtonePlayer.playAlarm(alarm);
RingingManager.ringAlarm(scheduleId);


/*
Ports to set the volume of the alarm. As the RingtonePlayer only.
As the RingtonePlayer only exists in this isolate, when other isolate
Expand Down
4 changes: 2 additions & 2 deletions lib/audio/logic/ringtones.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Future<String> getRingtoneUri(FileItem fileItem) async {
switch (fileItem.type) {
case FileItemType.directory:
try {
logger.t(fileItem.uri);
// logger.t(fileItem.uri);
// logger.t(
// await Directory(alarm.ringtone.uri).list(recursive: true).toList());
List<DocumentFile>? documentFiles =
Expand All @@ -75,7 +75,7 @@ Future<String> getRingtoneUri(FileItem fileItem) async {
Random random = Random();
int index = random.nextInt(documentFiles.length);
DocumentFile documentFile = documentFiles[index];
logger.t("${documentFile.name} ${documentFile.uri}");
// logger.t("${documentFile.name} ${documentFile.uri}");
return documentFile.uri;
} else {
logger.t(
Expand Down
2 changes: 1 addition & 1 deletion lib/debug/logic/logger.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ var logger = Logger(
);

void printIsolateInfo() {
logger.i(
logger.t(
"Isolate: ${Isolate.current.debugName}, id: ${Isolate.current.hashCode}");
}
8 changes: 4 additions & 4 deletions lib/debug/types/file_logger_output.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ class FileLoggerOutput extends LogOutput {
@override
void output(OutputEvent event) {
for (var line in event.lines) {
// ignore: avoid_print
print(line);
}

String message = switch (event.origin.message.runtimeType) {
String => event.origin.message as String,
Exception => (event.origin.message as Exception).toString(),
const (String) => event.origin.message as String,
const (Exception) => (event.origin.message as Exception).toString(),
_ => "Unknown error",
};

if (!Platform.environment.containsKey('FLUTTER_TEST')) {
_writeLog(message, event.level);

if (event.level == Level.error &&
App.navigatorKey.currentContext != null) {
if (App.navigatorKey.currentContext != null) {
Future(() {
showSnackBar(App.navigatorKey.currentContext!, message,
error: true, navBar: false, fab: false);
Expand Down
24 changes: 8 additions & 16 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ import 'package:clock_app/settings/logic/initialize_settings.dart';
import 'package:clock_app/settings/types/listener_manager.dart';
import 'package:clock_app/system/data/app_info.dart';
import 'package:clock_app/system/data/device_info.dart';
import 'package:clock_app/system/logic/background_service.dart';
import 'package:clock_app/system/logic/handle_boot.dart';
import 'package:clock_app/system/logic/initialize_isolate_ports.dart';
import 'package:clock_app/timer/logic/update_timers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_boot_receiver/flutter_boot_receiver.dart';
Expand Down Expand Up @@ -49,24 +51,14 @@ void main() async {
await initializeStorage();
await initializeSettings();

await updateAlarms("Update Alarms on Start");
await updateTimers("Update Timers on Start");
updateAlarms("Update Alarms on Start");
updateTimers("Update Timers on Start");
AppVisibility.initialize();
initForegroundTask();

ReceivePort receivePort = ReceivePort();
IsolateNameServer.removePortNameMapping(updatePortName);
IsolateNameServer.registerPortWithName(receivePort.sendPort, updatePortName);
printIsolateInfo();
receivePort.listen((message) {
if (message == "updateAlarms") {
ListenerManager.notifyListeners("alarms");
} else if (message == "updateTimers") {
ListenerManager.notifyListeners("timers");
} else if (message == "updateStopwatches") {
ListenerManager.notifyListeners("stopwatch");
}
});
initBackgroundService();
initializeIsolatePorts();

runApp(const App());

registerHeadlessBackgroundService();
}
4 changes: 2 additions & 2 deletions lib/settings/screens/ringtones_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,13 @@ class _RingtonesScreenState extends State<RingtonesScreen> {
await FilePicker.platform.getDirectoryPath();

if (selectedDirectory != null && selectedDirectory.isNotEmpty) {
logger.t("selectedDirectory: $selectedDirectory");
// logger.t("selectedDirectory: $selectedDirectory");

final directory = Directory(selectedDirectory);
final List<FileSystemEntity> entities =
await directory.list().toList();

logger.t(entities);
// logger.t(entities);

String name = basename(selectedDirectory
.replaceAll("%3A", "/")
Expand Down
57 changes: 57 additions & 0 deletions lib/system/logic/background_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import 'package:background_fetch/background_fetch.dart';
import 'package:clock_app/alarm/logic/update_alarms.dart';
import 'package:clock_app/debug/logic/logger.dart';
import 'package:clock_app/timer/logic/update_timers.dart';

Future<void> initBackgroundService() async {
await BackgroundFetch.configure(
BackgroundFetchConfig(
minimumFetchInterval: 30,
stopOnTerminate: false,
enableHeadless: true,
requiresBatteryNotLow: false,
requiresCharging: false,
requiresStorageNotLow: false,
requiresDeviceIdle: false,
requiredNetworkType: NetworkType.NONE), (String taskId) async {
// <-- Event handler
// This is the fetch-event callback.
logger.i("[BackgroundFetch] Event received $taskId");

// await initializeIsolate();

await updateAlarms("initBackgroundService(): Update alarms in background service");
await updateTimers("initBackgroundService(): Update timers in background service");
// IMPORTANT: You must signal completion of your task or the OS can punish your app
// for taking too long in the background.
BackgroundFetch.finish(taskId);
}, (String taskId) async {
// <-- Task timeout handler.
// This task has exceeded its allowed running-time. You must stop what you're doing and immediately .finish(taskId)
logger.i("[BackgroundFetch] TASK TIMEOUT taskId: $taskId");
BackgroundFetch.finish(taskId);
});
}

// [Android-only] This "Headless Task" is run when the Android app is terminated with `enableHeadless: true`
@pragma('vm:entry-point')
void handleBackgroundServiceTask(HeadlessTask task) async {
String taskId = task.taskId;
bool isTimeout = task.timeout;
if (isTimeout) {
// This task has exceeded its allowed running-time.
// You must stop what you're doing and immediately .finish(taskId)
logger.i("[BackgroundFetch] Headless task timed-out: $taskId");
BackgroundFetch.finish(taskId);
return;
}
logger.i('[BackgroundFetch] Headless event received.');
await updateAlarms("handleBackgroundServiceTask(): Update alarms in background service");
await updateTimers("handleBackgroundServiceTask(): Update timers in background service");

BackgroundFetch.finish(taskId);
}

void registerHeadlessBackgroundService() {
BackgroundFetch.registerHeadlessTask(handleBackgroundServiceTask);
}
22 changes: 22 additions & 0 deletions lib/system/logic/initialize_isolate_ports.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'dart:isolate';
import 'dart:ui';

import 'package:clock_app/alarm/logic/alarm_isolate.dart';
import 'package:clock_app/debug/logic/logger.dart';
import 'package:clock_app/settings/types/listener_manager.dart';

void initializeIsolatePorts(){
ReceivePort receivePort = ReceivePort();
IsolateNameServer.removePortNameMapping(updatePortName);
IsolateNameServer.registerPortWithName(receivePort.sendPort, updatePortName);
printIsolateInfo();
receivePort.listen((message) {
if (message == "updateAlarms") {
ListenerManager.notifyListeners("alarms");
} else if (message == "updateTimers") {
ListenerManager.notifyListeners("timers");
} else if (message == "updateStopwatches") {
ListenerManager.notifyListeners("stopwatch");
}
});
}

0 comments on commit 4f24909

Please sign in to comment.