diff --git a/app/src/main/java/eu/faircode/email/MediaPlayerHelper.java b/app/src/main/java/eu/faircode/email/MediaPlayerHelper.java
index c9b22193a8..85dc78d0e3 100644
--- a/app/src/main/java/eu/faircode/email/MediaPlayerHelper.java
+++ b/app/src/main/java/eu/faircode/email/MediaPlayerHelper.java
@@ -1,13 +1,16 @@
package eu.faircode.email;
import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.content.Context;
+import android.content.Intent;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
+import androidx.core.app.NotificationCompat;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
@@ -21,6 +24,17 @@ public class MediaPlayerHelper {
static final int DEFAULT_SOUND_DURATION = 30; // seconds
static final int DEFAULT_ALARM_DURATION = 30; // seconds
+ private static Object lock = new Object();
+ private static Semaphore sem;
+
+ static void stop(Context context) {
+ EntityLog.log(context, "Alarm stop");
+ synchronized (lock) {
+ if (sem != null)
+ sem.release();
+ }
+ }
+
static void queue(Context context, String uri) {
try {
queue(context, Uri.parse(uri), false, DEFAULT_SOUND_DURATION);
@@ -47,7 +61,9 @@ public class MediaPlayerHelper {
}
private static void play(Context context, Uri uri, boolean alarm, int duration) throws IOException {
- Semaphore sem = new Semaphore(0);
+ synchronized (lock) {
+ sem = new Semaphore(0);
+ }
AudioAttributes attrs = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -67,22 +83,56 @@ public class MediaPlayerHelper {
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
- mp.stop();
- mp.release();
sem.release();
}
});
mediaPlayer.prepareAsync();
+ NotificationManager nm = Helper.getSystemService(context, NotificationManager.class);
+ if (alarm) {
+ Intent intent = new Intent(context, ServiceUI.class)
+ .setAction("alarm");
+ PendingIntent piStop = PendingIntentCompat.getService(
+ context, ServiceUI.PI_ALARM, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ NotificationCompat.Action.Builder actionStop = new NotificationCompat.Action.Builder(
+ R.drawable.twotone_stop_24,
+ context.getString(R.string.title_rule_alarm_stop),
+ piStop)
+ .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_MUTE)
+ .setShowsUserInterface(false)
+ .setAllowGeneratedReplies(false);
+
+ NotificationCompat.Builder builder =
+ new NotificationCompat.Builder(context, "alerts")
+ .setSmallIcon(R.drawable.baseline_warning_white_24)
+ .setContentTitle(context.getString(R.string.title_rule_alarm_title))
+ .setSilent(true)
+ .setAutoCancel(false)
+ .addAction(actionStop.build())
+ .setShowWhen(true)
+ .setPriority(NotificationCompat.PRIORITY_MAX)
+ .setOnlyAlertOnce(true)
+ .setCategory(NotificationCompat.CATEGORY_ALARM)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
+
+ nm.notify("alarm", 1, builder.build());
+ }
+
try {
boolean acquired = sem.tryAcquire(duration, TimeUnit.SECONDS);
EntityLog.log(context, "Alarm acquired=" + acquired);
- if (!acquired) {
- mediaPlayer.stop();
- mediaPlayer.release();
- }
+ mediaPlayer.stop();
+ mediaPlayer.release();
} catch (Throwable ex) {
Log.w(ex);
+ } finally {
+ if (alarm)
+ nm.cancel("alarm", 1);
+ }
+
+ synchronized (lock) {
+ sem = null;
}
}
diff --git a/app/src/main/java/eu/faircode/email/ServiceUI.java b/app/src/main/java/eu/faircode/email/ServiceUI.java
index cd628a233c..f306b958e0 100644
--- a/app/src/main/java/eu/faircode/email/ServiceUI.java
+++ b/app/src/main/java/eu/faircode/email/ServiceUI.java
@@ -58,6 +58,7 @@ public class ServiceUI extends IntentService {
static final int PI_SNOOZE = 10;
static final int PI_IGNORED = 11;
static final int PI_DELETE = 12;
+ static final int PI_ALARM = 13;
public ServiceUI() {
this(ServiceUI.class.getName());
@@ -177,6 +178,10 @@ public class ServiceUI extends IntentService {
// ignore
break;
+ case "alarm":
+ onAlarm(intent);
+ break;
+
default:
throw new IllegalArgumentException("Unknown UI action: " + parts[0]);
}
@@ -502,6 +507,10 @@ public class ServiceUI extends IntentService {
onSync(aid, fid, fid < 0);
}
+ private void onAlarm(Intent intent) {
+ MediaPlayerHelper.stop(this);
+ }
+
static void sync(Context context, Long account) {
try {
Intent sync = new Intent(context, ServiceUI.class)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 13f0bb3edf..0b26858eb0 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1992,6 +1992,8 @@
Use as alarm
This will ignore "do not disturb" rules
Maximum alarm duration (seconds)
+ Alarm
+ Stop
Synchronize
Folders