From 9710b7cddb4401d90ce8fe0d0b020313b643d62d Mon Sep 17 00:00:00 2001 From: M66B Date: Sat, 18 Jun 2022 16:52:50 +0200 Subject: [PATCH] Defer new message notification when calling --- app/src/main/java/eu/faircode/email/Core.java | 9 -- .../email/FragmentOptionsNotifications.java | 3 + .../eu/faircode/email/ServiceSynchronize.java | 104 ++++++++++++------ .../java/eu/faircode/email/TwoStateOwner.java | 41 +------ .../layout/fragment_options_notifications.xml | 15 +-- app/src/main/res/values/strings.xml | 3 +- 6 files changed, 81 insertions(+), 94 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/Core.java b/app/src/main/java/eu/faircode/email/Core.java index 363f97960a..9a95a77236 100644 --- a/app/src/main/java/eu/faircode/email/Core.java +++ b/app/src/main/java/eu/faircode/email/Core.java @@ -4943,7 +4943,6 @@ class Core { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); boolean badge = prefs.getBoolean("badge", true); boolean notify_background_only = prefs.getBoolean("notify_background_only", false); - boolean notify_suppress_in_call = prefs.getBoolean("notify_suppress_in_call", false); boolean notify_summary = prefs.getBoolean("notify_summary", false); boolean notify_preview = prefs.getBoolean("notify_preview", true); boolean notify_preview_only = prefs.getBoolean("notify_preview_only", false); @@ -4998,14 +4997,6 @@ class Core { continue; } - if (notify_suppress_in_call && message.notifying == 0 && - MediaPlayerHelper.isInCall(context)) { - Log.i("Notify call=" + message.id); - if (!message.ui_ignored) - db.message().setMessageUiIgnored(message.id, true); - continue; - } - long group = (pro && message.accountNotify ? message.account : 0); if (!message.folderUnified) group = -message.folder; diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java b/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java index 63daa9ac4c..37b7b26b73 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java @@ -468,6 +468,9 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared } }); + swNotifySuppressInCall.setVisibility( + Build.VERSION.SDK_INT < Build.VERSION_CODES.S + ? View.GONE : View.VISIBLE); swNotifySuppressInCall.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java index 3c611dbfaf..e94cb49112 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java @@ -678,39 +678,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences }; }); - final TwoStateOwner cowner = new TwoStateOwner(this, "liveUnseenNotify"); - - if (BuildConfig.DEBUG && - Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - // Widgets will be disabled too - AudioManager am = Helper.getSystemService(this, AudioManager.class); - - AudioManager.OnModeChangedListener listener = new AudioManager.OnModeChangedListener() { - @Override - public void onModeChanged(int mode) { - boolean inCall = MediaPlayerHelper.isInCall(mode); - boolean notify_suppress_in_call = prefs.getBoolean("notify_suppress_in_call", false); - Log.i("Owner inCall=" + inCall + " suppress=" + notify_suppress_in_call); - cowner.setEnabled(!notify_suppress_in_call || !inCall); - } - }; - listener.onModeChanged(am.getMode()); // Init - - getLifecycle().addObserver(new LifecycleObserver() { - private boolean registered = false; - - @OnLifecycleEvent(Lifecycle.Event.ON_ANY) - public void onStateChanged() { - if (ServiceSynchronize.this.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) { - am.addOnModeChangedListener(executor, listener); - registered = true; - } else if (registered) { - am.removeOnModeChangedListener(listener); - registered = false; - } - } - }); - } + final TwoStateOwner cowner = new TwoStateOwner(this, "liveSynchronizing"); db.folder().liveSynchronizing().observe(this, new Observer>() { private List lastAccounts = new ArrayList<>(); @@ -784,15 +752,79 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences } }); + // New message notifications batching + Core.NotificationData notificationData = new Core.NotificationData(this); + MutableLiveData> mutableUnseenNotify = new MutableLiveData<>(); db.message().liveUnseenNotify().observe(cowner, new Observer>() { + @Override + public void onChanged(List messages) { + mutableUnseenNotify.setValue(messages); + } + }); + + final TwoStateOwner mowner = new TwoStateOwner(this, "mutableUnseenNotify"); + + AudioManager am = Helper.getSystemService(this, AudioManager.class); + if (am == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + mowner.start(); + Log.i("Audio mode legacy"); + } else { + AudioManager.OnModeChangedListener listener = new AudioManager.OnModeChangedListener() { + @Override + public void onModeChanged(int mode) { + getMainHandler().post(new RunnableEx("AudioMode") { + @Override + public void delegate() { + boolean incall = MediaPlayerHelper.isInCall(mode); + boolean suppress = prefs.getBoolean("notify_suppress_in_call", false); + boolean start = (!suppress || !incall); + Log.i("Audio mode start=" + start + + " incall=" + incall + + " suppress=" + suppress); + if (start) + mowner.start(); + else + mowner.stop(); + } + }); + } + }; + listener.onModeChanged(am.getMode()); // Init + + getLifecycle().addObserver(new LifecycleObserver() { + private boolean registered = false; + + @OnLifecycleEvent(Lifecycle.Event.ON_ANY) + public void onStateChanged() { + try { + if (ServiceSynchronize.this.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) { + if (!registered) { + am.addOnModeChangedListener(executor, listener); + registered = true; + } + } else { + if (registered) { + am.removeOnModeChangedListener(listener); + registered = false; + } + } + Log.i("Audio mode registered=" + registered); + } catch (Throwable ex) { + Log.e(ex); + } + } + }); + } + + mutableUnseenNotify.observe(mowner, new Observer>() { private final ExecutorService executor = Helper.getBackgroundExecutor(1, "notify"); @Override public void onChanged(final List messages) { - executor.submit(new RunnableEx("liveUnseenNotify") { + executor.submit(new RunnableEx("mutableUnseenNotify") { @Override public void delegate() { try { @@ -809,6 +841,8 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences } }); + // Message count widgets + db.message().liveWidgetUnseen(null).observe(cowner, new Observer>() { private Integer lastCount = null; private List last = null; @@ -874,6 +908,8 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences } }); + // Message list widgets + db.message().liveWidgetUnified().observe(cowner, new Observer>() { private List last = null; diff --git a/app/src/main/java/eu/faircode/email/TwoStateOwner.java b/app/src/main/java/eu/faircode/email/TwoStateOwner.java index 940ff3f6c5..91fd478804 100644 --- a/app/src/main/java/eu/faircode/email/TwoStateOwner.java +++ b/app/src/main/java/eu/faircode/email/TwoStateOwner.java @@ -37,8 +37,6 @@ import java.util.Objects; public class TwoStateOwner implements LifecycleOwner { private String name; - private boolean enabled = true; - private Boolean start = null; private boolean owned = true; private Object condition; private LifecycleRegistry registry; @@ -79,27 +77,6 @@ public class TwoStateOwner implements LifecycleOwner { }); } - void setEnabled(boolean value) { - Log.i("Owner enable=" + value + " state=" + registry.getCurrentState().name()); - if (enabled && !value) { - boolean started = registry.getCurrentState().isAtLeast(Lifecycle.State.STARTED); - stop(); - start = (started ? true : null); - Log.i("Owner stopped start=" + start); - } - - enabled = value; - - if (enabled && start != null) { - Log.i("Owner restore start=" + start); - if (start) - start(); - else - stop(); - start = null; - } - } - private void create() { if (owned) { // Initialize @@ -122,21 +99,15 @@ public class TwoStateOwner implements LifecycleOwner { } void start() { - if (enabled) { - Lifecycle.State state = registry.getCurrentState(); - if (!state.equals(Lifecycle.State.STARTED) && !state.equals(Lifecycle.State.DESTROYED)) - setState(Lifecycle.State.STARTED); - } else - start = true; + Lifecycle.State state = registry.getCurrentState(); + if (!state.equals(Lifecycle.State.STARTED) && !state.equals(Lifecycle.State.DESTROYED)) + setState(Lifecycle.State.STARTED); } void stop() { - if (enabled) { - Lifecycle.State state = registry.getCurrentState(); - if (!state.equals(Lifecycle.State.CREATED) && !state.equals(Lifecycle.State.DESTROYED)) - setState(Lifecycle.State.CREATED); - } else - start = false; + Lifecycle.State state = registry.getCurrentState(); + if (!state.equals(Lifecycle.State.CREATED) && !state.equals(Lifecycle.State.DESTROYED)) + setState(Lifecycle.State.CREATED); } void restart() { diff --git a/app/src/main/res/layout/fragment_options_notifications.xml b/app/src/main/res/layout/fragment_options_notifications.xml index 1bb12650b6..f1a64dbd3a 100644 --- a/app/src/main/res/layout/fragment_options_notifications.xml +++ b/app/src/main/res/layout/fragment_options_notifications.xml @@ -549,19 +549,6 @@ app:layout_constraintTop_toBottomOf="@id/tvNotifyKnownPro" app:switchPadding="12dp" /> - - Let the number of new messages match the number of notifications Show notifications when in the background only Show notifications for contacts only - Suppress notifications when calling + Delay notifications while on a call Show summary notification only Show message preview in notifications Preview all text @@ -879,7 +879,6 @@ Only available on supported launchers At most three actions will be shown - Suppressed notifications will not be shown again later New message notifications will always be removed on being swiped away and on marking messages read Tap on the channel name to set the channel properties To set the default sound, etc