diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java b/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java
index 968f84832c..9f4d52d0bf 100644
--- a/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java
+++ b/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java
@@ -96,6 +96,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
private CheckBox cbNotifyActionSeen;
private CheckBox cbNotifyActionHide;
private CheckBox cbNotifyActionSnooze;
+ private CheckBox cbNotifyActionTts;
private TextView tvNotifyActionsPro;
private SwitchCompat swLight;
private Button btnSound;
@@ -144,7 +145,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
"notify_newest_first", "notify_summary",
"notify_trash", "notify_junk", "notify_block_sender", "notify_archive", "notify_move",
"notify_reply", "notify_reply_direct",
- "notify_flag", "notify_seen", "notify_hide", "notify_snooze",
+ "notify_flag", "notify_seen", "notify_hide", "notify_snooze", "notify_tts",
"light", "sound", "notify_screen_on",
"badge", "unseen_ignored",
"notify_grouping", "notify_private", "notify_background_only", "notify_known", "notify_suppress_in_call", "notify_suppress_in_car",
@@ -188,6 +189,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
cbNotifyActionSeen = view.findViewById(R.id.cbNotifyActionSeen);
cbNotifyActionHide = view.findViewById(R.id.cbNotifyActionHide);
cbNotifyActionSnooze = view.findViewById(R.id.cbNotifyActionSnooze);
+ cbNotifyActionTts = view.findViewById(R.id.cbNotifyActionTts);
tvNotifyActionsPro = view.findViewById(R.id.tvNotifyActionsPro);
swLight = view.findViewById(R.id.swLight);
btnSound = view.findViewById(R.id.btnSound);
@@ -516,6 +518,13 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
}
});
+ cbNotifyActionTts.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean checked) {
+ prefs.edit().putBoolean("notify_tts", checked).apply();
+ }
+ });
+
Helper.linkPro(tvNotifyActionsPro);
Helper.linkPro(tvNotifyKnownPro);
@@ -894,6 +903,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
cbNotifyActionSeen.setChecked(prefs.getBoolean("notify_seen", true) || !pro);
cbNotifyActionHide.setChecked(prefs.getBoolean("notify_hide", false) && pro);
cbNotifyActionSnooze.setChecked(prefs.getBoolean("notify_snooze", false) && pro);
+ cbNotifyActionTts.setChecked(prefs.getBoolean("notify_tts", false) && pro);
swLight.setChecked(prefs.getBoolean("light", false));
swNotifyScreenOn.setChecked(prefs.getBoolean("notify_screen_on", false));
@@ -941,6 +951,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
cbNotifyActionSeen.setEnabled(pro && !summary);
cbNotifyActionHide.setEnabled(pro && !summary);
cbNotifyActionSnooze.setEnabled(pro && !summary);
+ cbNotifyActionTts.setEnabled(pro && !summary);
swNotifyPreviewAll.setEnabled(!summary && swNotifyPreview.isChecked());
swNotifyPreviewOnly.setEnabled(!summary && swNotifyPreview.isChecked());
swWearablePreview.setEnabled(!summary && swNotifyPreview.isChecked());
diff --git a/app/src/main/java/eu/faircode/email/NotificationHelper.java b/app/src/main/java/eu/faircode/email/NotificationHelper.java
index 1b3384a8a5..632186f936 100644
--- a/app/src/main/java/eu/faircode/email/NotificationHelper.java
+++ b/app/src/main/java/eu/faircode/email/NotificationHelper.java
@@ -720,6 +720,7 @@ class NotificationHelper {
boolean notify_seen = (prefs.getBoolean("notify_seen", true) || !pro);
boolean notify_hide = (prefs.getBoolean("notify_hide", false) && pro);
boolean notify_snooze = (prefs.getBoolean("notify_snooze", false) && pro);
+ boolean notify_tts = (prefs.getBoolean("notify_tts", false) && pro);
boolean notify_remove = prefs.getBoolean("notify_remove", true);
boolean light = prefs.getBoolean("light", false);
String sound = prefs.getString("sound", null);
@@ -1334,6 +1335,27 @@ class NotificationHelper {
wactions.add(actionSnooze.build());
}
+ if (message.content && notify_tts) {
+ Intent tts = new Intent(context, ServiceTTS.class);
+ tts.putExtra(ServiceTTS.EXTRA_FLUSH, true);
+ tts.putExtra(ServiceTTS.EXTRA_TEXT, "");
+ tts.putExtra(ServiceTTS.EXTRA_LANGUAGE, message.language);
+ tts.putExtra(ServiceTTS.EXTRA_UTTERANCE_ID, "tts:" + message.id);
+ tts.putExtra(ServiceTTS.EXTRA_GROUP, group);
+ tts.putExtra(ServiceTTS.EXTRA_MESSAGE, message.id);
+ PendingIntent piTts = PendingIntentCompat.getService(
+ context, ServiceTTS.PI_TTS, tts, PendingIntent.FLAG_UPDATE_CURRENT);
+ NotificationCompat.Action.Builder actionTts = new NotificationCompat.Action.Builder(
+ R.drawable.twotone_play_arrow_24,
+ context.getString(R.string.title_rule_tts),
+ piTts)
+ .setShowsUserInterface(false)
+ .setAllowGeneratedReplies(false);
+ mbuilder.addAction(actionTts.build());
+
+ wactions.add(actionTts.build());
+ }
+
// https://developer.android.com/training/wearables/notifications
// https://developer.android.com/reference/androidx/core/app/NotificationCompat.Action.WearableExtender
mbuilder.extend(new NotificationCompat.WearableExtender()
diff --git a/app/src/main/java/eu/faircode/email/ServiceTTS.java b/app/src/main/java/eu/faircode/email/ServiceTTS.java
index c7ba8a1d69..baf81f2020 100644
--- a/app/src/main/java/eu/faircode/email/ServiceTTS.java
+++ b/app/src/main/java/eu/faircode/email/ServiceTTS.java
@@ -20,13 +20,16 @@ package eu.faircode.email;
*/
import android.app.Notification;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.OperationCanceledException;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
+import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
@@ -46,9 +49,13 @@ public class ServiceTTS extends ServiceBase {
static final String EXTRA_TEXT = "text";
static final String EXTRA_LANGUAGE = "language";
static final String EXTRA_UTTERANCE_ID = "utterance";
+ static final String EXTRA_MESSAGE = "message";
+ static final String EXTRA_GROUP = "group";
static final String ACTION_TTS_COMPLETED = BuildConfig.APPLICATION_ID + ".TTS";
+ static final int PI_TTS = 1;
+
@Override
public void onCreate() {
Log.i("Service TTS create");
@@ -145,9 +152,40 @@ public class ServiceTTS extends ServiceBase {
final String text = intent.getStringExtra(EXTRA_TEXT);
final String language = intent.getStringExtra(EXTRA_LANGUAGE);
final String utteranceId = intent.getStringExtra(EXTRA_UTTERANCE_ID);
+ final long group = intent.getLongExtra(EXTRA_GROUP, 0);
+ final long message = intent.getLongExtra(EXTRA_MESSAGE, -1L);
final Locale locale = (language == null ? Locale.getDefault() : new Locale(language));
+ if (message > 0) {
+ String tag = "unseen." + group + "." + message;
+ Log.i("MMM cancel tag=" + tag);
+ NotificationManager nm = Helper.getSystemService(this, NotificationManager.class);
+ nm.cancel(tag, NotificationHelper.NOTIFICATION_TAGGED);
+
+ Helper.getSerialExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ String body = Helper.readText(EntityMessage.getFile(ServiceTTS.this, message));
+ String text = HtmlHelper.getFullText(ServiceTTS.this, body);
+
+ // Avoid: Not enough namespace quota ... for ...
+ text = HtmlHelper.truncate(text, getMaxTextSize() / 3);
+
+ intent.putExtra(EXTRA_TEXT, text);
+ intent.removeExtra(EXTRA_GROUP);
+ intent.removeExtra(EXTRA_MESSAGE);
+ onTts(intent);
+ } catch (Throwable ex) {
+ Log.e(ex);
+ }
+ }
+ });
+
+ return;
+ }
+
final Runnable speak = new RunnableEx("tts") {
@Override
public void delegate() {
diff --git a/app/src/main/res/layout/fragment_options_notifications.xml b/app/src/main/res/layout/fragment_options_notifications.xml
index 54fe11c64c..40cd8915e2 100644
--- a/app/src/main/res/layout/fragment_options_notifications.xml
+++ b/app/src/main/res/layout/fragment_options_notifications.xml
@@ -397,6 +397,16 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbNotifyActionHide" />
+
+