Skip to content

Commit

Permalink
Improve Android error & version handling
Browse files Browse the repository at this point in the history
  • Loading branch information
gdelataillade committed Jan 30, 2024
1 parent 8e7c876 commit 5baed7a
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 34 deletions.
5 changes: 3 additions & 2 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
<uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
android:maxSdkVersion="32" />
<application>
<receiver android:name=".AlarmReceiver" />
<service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,21 +129,31 @@ class AlarmPlugin: FlutterPlugin, MethodCallHandler {
}

fun handleDelayedAlarm(context: Context, intent: Intent, delayInSeconds: Int, id: Int) {
val triggerTime = System.currentTimeMillis() + delayInSeconds * 1000L
val pendingIntent = PendingIntent.getBroadcast(
context,
id,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent)
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent)
try {
val triggerTime = System.currentTimeMillis() + delayInSeconds * 1000L
val pendingIntent = PendingIntent.getBroadcast(
context,
id,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)

val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager
?: throw IllegalStateException("AlarmManager not available")

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent)
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent)
}
} catch (e: ClassCastException) {
Log.e("AlarmPlugin", "AlarmManager service type casting failed", e)
} catch (e: IllegalStateException) {
Log.e("AlarmPlugin", "AlarmManager service not available", e)
} catch (e: Exception) {
Log.e("AlarmPlugin", "Error in handling delayed alarm", e)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import com.gdelataillade.alarm.services.VolumeService

import android.app.Service
import android.app.PendingIntent
import android.app.ForegroundServiceStartNotAllowedException
import android.content.Intent
import android.content.Context
import android.content.pm.ServiceInfo
import android.os.IBinder
import android.os.PowerManager
import android.os.Build
import io.flutter.Log
import io.flutter.plugin.common.MethodChannel
import io.flutter.embedding.engine.dart.DartExecutor
Expand Down Expand Up @@ -74,7 +77,21 @@ class AlarmService : Service() {
val pendingIntent = PendingIntent.getActivity(this, id!!, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)

val notification = notificationHandler.buildNotification(notificationTitle!!, notificationBody!!, fullScreenIntent!!, pendingIntent)
startForeground(id, notification)

try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
startForeground(id, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK)
} else {
startForeground(id, notification)
}
} catch (e: ForegroundServiceStartNotAllowedException) {
// Specific handling for ForegroundServiceStartNotAllowedException
Log.e("AlarmService", "Foreground service start not allowed", e)
} catch (e: SecurityException) {
Log.e("AlarmService", "Security exception in starting foreground service", e)
} catch (e: Exception) {
Log.e("AlarmService", "Error in starting foreground service", e)
}

try {
if (channel != null) {
Expand Down Expand Up @@ -115,18 +132,24 @@ class AlarmService : Service() {
}

fun stopAlarm(id: Int) {
ringingAlarmIds = audioService?.getPlayingMediaPlayersIds()!!
try {
ringingAlarmIds = audioService?.getPlayingMediaPlayersIds()!!

volumeService?.restorePreviousVolume(showSystemUI)
volumeService?.abandonAudioFocus()
volumeService?.restorePreviousVolume(showSystemUI)
volumeService?.abandonAudioFocus()

audioService?.stopAudio(id)
if (audioService?.isMediaPlayerEmpty()!!) {
vibrationService?.stopVibrating()
stopSelf()
}
audioService?.stopAudio(id)
if (audioService?.isMediaPlayerEmpty()!!) {
vibrationService?.stopVibrating()
stopSelf()
}

stopForeground(true)
stopForeground(true)
} catch (e: IllegalStateException) {
Log.e("AlarmService", "Illegal State: ${e.message}", e)
} catch (e: Exception) {
Log.e("AlarmService", "Error in stopping alarm: ${e.message}", e)
}
}

override fun onDestroy() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class NotificationHandler(private val context: Context) {
.setContentText(body)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setCategory(NotificationCompat.CATEGORY_ALARM)
.setAutoCancel(false)
.setAutoCancel(true)
.setOngoing(true)
.setContentIntent(notificationPendingIntent)
.setSound(null)
Expand Down
2 changes: 1 addition & 1 deletion example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ android {
namespace 'com.gdelataillade.alarm.alarm_example'

compileSdkVersion 33
ndkVersion flutter.ndkVersion
ndkVersion "25.1.8937393"

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
Expand Down
5 changes: 3 additions & 2 deletions example/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
<uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
android:maxSdkVersion="32" />
<application
android:label="alarm_example"
android:name="${applicationName}"
Expand Down
5 changes: 3 additions & 2 deletions help/INSTALL-ANDROID.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ Then, add the following permissions to your `AndroidManifest.xml` within the `<m
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
<uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
android:maxSdkVersion="32" />
```

See more details on Android permissions [here](https://developer.android.com/reference/android/Manifest.permission).
Expand Down
5 changes: 5 additions & 0 deletions lib/alarm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ class Alarm {
}

static void alarmSettingsValidation(AlarmSettings alarmSettings) {
if (alarmSettings.id == 0 || alarmSettings.id == -1) {
throw AlarmException(
'Alarm id cannot be 0 or -1. Provided: ${alarmSettings.id}',
);
}
if (!alarmSettings.assetAudioPath.contains('.')) {
throw AlarmException(
'Provided audio path is not valid: ${alarmSettings.assetAudioPath}',
Expand Down
3 changes: 2 additions & 1 deletion lib/model/alarm_settings.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class AlarmSettings {
/// Unique identifier assiocated with the alarm.
/// Unique identifier assiocated with the alarm. Cannot be 0 or -1;
final int id;

/// Date and time when the alarm will be triggered.
Expand Down Expand Up @@ -46,6 +46,7 @@ class AlarmSettings {

/// Whether to show a notification when application is killed to warn
/// the user that the alarms won't ring anymore. Enabled by default.
/// Recommanded for iOS.
final bool enableNotificationOnKill;

/// Whether to turn screen on and display full screen notification
Expand Down

0 comments on commit 5baed7a

Please sign in to comment.