Added setting to show summary notification only

Biometric authentication will auto enable a redacted summary
pull/162/head
M66B 5 years ago
parent ed98ea5e6f
commit 9b0fba796b

@ -2514,14 +2514,24 @@ class Core {
static void notifyMessages(Context context, List<TupleMessageEx> messages, Map<Long, List<Long>> groupNotifying) {
if (messages == null)
messages = new ArrayList<>();
Log.i("Notify messages=" + messages.size());
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (nm == null)
return;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean notify_summary = prefs.getBoolean("notify_summary", false);
boolean biometrics = prefs.getBoolean("biometrics", false);
boolean biometric_notify = prefs.getBoolean("biometrics_notify", false);
boolean pro = ActivityBilling.isPro(context);
if (biometrics && !biometric_notify)
notify_summary = true;
Log.i("Notify messages=" + messages.size() +
" biometrics=" + biometrics + "/" + biometric_notify +
" summary=" + notify_summary);
Map<Long, List<TupleMessageEx>> groupMessages = new HashMap<>();
for (long group : groupNotifying.keySet())
groupMessages.put(group, new ArrayList<>());
@ -2562,9 +2572,9 @@ class Core {
// Difference
for (long group : groupMessages.keySet()) {
// Difference
final List<Long> add = new ArrayList<>();
final List<Long> remove = new ArrayList<>(groupNotifying.get(group));
int new_messages = 0;
List<Long> add = new ArrayList<>();
List<Long> remove = new ArrayList<>(groupNotifying.get(group));
for (TupleMessageEx message : groupMessages.get(group)) {
long id = (message.content ? message.id : -message.id);
if (remove.contains(id)) {
@ -2572,18 +2582,27 @@ class Core {
Log.i("Notify existing=" + id);
} else {
add.add(id);
remove.remove(-id);
Log.i("Notify adding=" + id);
boolean existing = remove.contains(-id);
if (existing)
remove.remove(-id);
else
new_messages++;
Log.i("Notify adding=" + id + " existing=" + existing);
}
}
if (remove.size() + add.size() == 0) {
if (notify_summary
? remove.size() + new_messages == 0
: remove.size() + add.size() == 0) {
Log.i("Notify unchanged");
continue;
}
// Build notifications
List<Notification> notifications = getNotificationUnseen(context, group, groupMessages.get(group));
List<Notification> notifications = getNotificationUnseen(context,
group, groupMessages.get(group),
notify_summary, new_messages,
biometrics && !biometric_notify);
Log.i("Notify group=" + group + " count=" + notifications.size() +
" added=" + add.size() + " removed=" + remove.size());
@ -2605,6 +2624,12 @@ class Core {
db.message().setMessageNotifying(Math.abs(id), 0);
}
for (Long id : add) {
groupNotifying.get(group).add(id);
groupNotifying.get(group).remove(-id);
db.message().setMessageNotifying(Math.abs(id), (int) Math.signum(id));
}
for (Notification notification : notifications) {
long id = notification.extras.getLong("id", 0);
if ((id == 0 && add.size() + remove.size() > 0) || add.contains(id)) {
@ -2612,18 +2637,15 @@ class Core {
Log.i("Notifying tag=" + tag + " id=" + id +
(Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? "" : " channel=" + notification.getChannelId()));
nm.notify(tag, 1, notification);
if (id != 0) {
groupNotifying.get(group).add(id);
groupNotifying.get(group).remove(-id);
db.message().setMessageNotifying(Math.abs(id), (int) Math.signum(id));
}
}
}
}
}
private static List<Notification> getNotificationUnseen(Context context, long group, List<TupleMessageEx> messages) {
private static List<Notification> getNotificationUnseen(
Context context,
long group, List<TupleMessageEx> messages,
boolean notify_summary, int new_messages, boolean redacted) {
List<Notification> notifications = new ArrayList<>();
// Android 7+ N https://developer.android.com/training/notify-user/group
@ -2636,8 +2658,6 @@ class Core {
boolean pro = ActivityBilling.isPro(context);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean biometrics = prefs.getBoolean("biometrics", false);
boolean biometric_notify = prefs.getBoolean("biometrics_notify", false);
boolean name_email = prefs.getBoolean("name_email", false);
boolean flags = prefs.getBoolean("flags", true);
boolean notify_preview = prefs.getBoolean("notify_preview", true);
@ -2659,7 +2679,7 @@ class Core {
messageContact.put(message, ContactInfo.get(context, message.from, false));
// Summary notification
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N || notify_summary) {
// Build pending intents
Intent summary = new Intent(context, ActivityView.class).setAction("unified");
PendingIntent piSummary = PendingIntent.getActivity(context, ActivityView.REQUEST_UNIFIED, summary, PendingIntent.FLAG_UPDATE_CURRENT);
@ -2667,12 +2687,6 @@ class Core {
Intent clear = new Intent(context, ServiceUI.class).setAction("clear:" + group);
PendingIntent piClear = PendingIntent.getService(context, ServiceUI.PI_CLEAR, clear, PendingIntent.FLAG_UPDATE_CURRENT);
// Wearable action
NotificationCompat.Action.Builder actionDismiss = new NotificationCompat.Action.Builder(
R.drawable.baseline_clear_all_24,
context.getString(R.string.title_dismiss),
piClear);
// Build title
String title = context.getResources().getQuantityString(
R.plurals.title_notification_unseen, messages.size(), messages.size());
@ -2688,12 +2702,25 @@ class Core {
.setDeleteIntent(piClear)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setCategory(NotificationCompat.CATEGORY_STATUS)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setGroup(Long.toString(group))
.setGroupSummary(true)
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN)
.extend(new NotificationCompat.WearableExtender()
.addAction(actionDismiss.build()));
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
if (notify_summary) {
builder.setOnlyAlertOnce(new_messages == 0);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
if (new_messages > 0)
setLightAndSound(builder, light, sound);
else
builder.setSound(null);
} else {
builder
.setGroup(Long.toString(group))
.setGroupSummary(true)
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
builder.setSound(null);
}
if (pro && group != 0 && messages.size() > 0) {
TupleMessageEx amessage = messages.get(0);
@ -2704,15 +2731,14 @@ class Core {
builder.setSubText(amessage.accountName);
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
builder.setSound(null);
Notification pub = builder.build();
builder
.setVisibility(NotificationCompat.VISIBILITY_PRIVATE)
.setPublicVersion(pub);
if (!biometrics || biometric_notify) {
if (redacted)
builder.setContentText(context.getString(R.string.title_setup_biometrics));
else {
DateFormat DTF = Helper.getDateTimeInstance(context, SimpleDateFormat.SHORT, SimpleDateFormat.SHORT);
StringBuilder sb = new StringBuilder();
for (EntityMessage message : messages) {
@ -2731,6 +2757,9 @@ class Core {
notifications.add(builder.build());
}
if (notify_summary)
return notifications;
// Message notifications
for (TupleMessageEx message : messages) {
ContactInfo info = messageContact.get(message);
@ -2791,40 +2820,15 @@ class Core {
.setGroupSummary(false)
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
int def = 0;
if (light) {
def |= DEFAULT_LIGHTS;
Log.i("Notify light enabled");
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
setLightAndSound(mbuilder, light, sound);
Uri uri = (sound == null ? null : Uri.parse(sound));
if (uri == null || "file".equals(uri.getScheme()))
uri = null;
Log.i("Notify sound=" + uri);
String folderName = message.folderDisplay == null
? Helper.localizeFolderName(context, message.folderName)
: message.folderDisplay;
if (uri == null)
def |= DEFAULT_SOUND;
else
mbuilder.setSound(uri);
mbuilder.setDefaults(def);
}
if (biometrics && !biometric_notify)
mbuilder
.setContentTitle(context.getResources().getQuantityString(
R.plurals.title_notification_unseen, 1, 1))
.setContentText(context.getString(R.string.title_setup_biometrics));
else {
String folderName = message.folderDisplay == null
? Helper.localizeFolderName(context, message.folderName)
: message.folderDisplay;
mbuilder.setContentTitle(info.getDisplayName(name_email))
.setSubText(message.accountName + " · " + folderName);
}
mbuilder.setContentTitle(info.getDisplayName(name_email))
.setSubText(message.accountName + " · " + folderName);
DB db = DB.getInstance(context);
@ -2936,43 +2940,41 @@ class Core {
mbuilder.addAction(actionSnooze.build());
}
if (!biometrics || biometric_notify) {
if (!TextUtils.isEmpty(message.subject))
mbuilder.setContentText(message.subject);
if (!TextUtils.isEmpty(message.subject))
mbuilder.setContentText(message.subject);
if (message.content && notify_preview)
try {
String body = Helper.readText(message.getFile(context));
StringBuilder sbm = new StringBuilder();
if (!TextUtils.isEmpty(message.subject))
sbm.append(message.subject).append("<br>");
String text = Jsoup.parse(body).text();
if (!TextUtils.isEmpty(text)) {
sbm.append("<em>");
if (text.length() > HtmlHelper.PREVIEW_SIZE) {
sbm.append(text.substring(0, HtmlHelper.PREVIEW_SIZE));
sbm.append("…");
} else
sbm.append(text);
sbm.append("</em>");
}
mbuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(HtmlHelper.fromHtml(sbm.toString())));
} catch (IOException ex) {
Log.e(ex);
mbuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(ex.toString()));
db.message().setMessageContent(message.id, false, null, null, null);
if (message.content && notify_preview)
try {
String body = Helper.readText(message.getFile(context));
StringBuilder sbm = new StringBuilder();
if (!TextUtils.isEmpty(message.subject))
sbm.append(message.subject).append("<br>");
String text = Jsoup.parse(body).text();
if (!TextUtils.isEmpty(text)) {
sbm.append("<em>");
if (text.length() > HtmlHelper.PREVIEW_SIZE) {
sbm.append(text.substring(0, HtmlHelper.PREVIEW_SIZE));
sbm.append("…");
} else
sbm.append(text);
sbm.append("</em>");
}
mbuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(HtmlHelper.fromHtml(sbm.toString())));
} catch (IOException ex) {
Log.e(ex);
mbuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(ex.toString()));
db.message().setMessageContent(message.id, false, null, null, null);
}
if (info.hasPhoto())
mbuilder.setLargeIcon(info.getPhotoBitmap());
if (info.hasPhoto())
mbuilder.setLargeIcon(info.getPhotoBitmap());
if (info.hasLookupUri())
mbuilder.addPerson(info.getLookupUri().toString());
if (info.hasLookupUri())
mbuilder.addPerson(info.getLookupUri().toString());
if (pro && message.accountColor != null) {
mbuilder.setColor(message.accountColor);
mbuilder.setColorized(true);
}
if (pro && message.accountColor != null) {
mbuilder.setColor(message.accountColor);
mbuilder.setColorized(true);
}
notifications.add(mbuilder.build());
@ -2981,6 +2983,27 @@ class Core {
return notifications;
}
private static void setLightAndSound(NotificationCompat.Builder builder, boolean light, String sound) {
int def = 0;
if (light) {
def |= DEFAULT_LIGHTS;
Log.i("Notify light enabled");
}
Uri uri = (sound == null ? null : Uri.parse(sound));
if (uri == null || "file".equals(uri.getScheme()))
uri = null;
Log.i("Notify sound=" + uri);
if (uri == null)
def |= DEFAULT_SOUND;
else
builder.setSound(uri);
builder.setDefaults(def);
}
// FolderClosedException: can happen when no connectivity
// IllegalStateException:

@ -56,6 +56,7 @@ import static android.app.Activity.RESULT_OK;
public class FragmentOptionsNotifications extends FragmentBase implements SharedPreferences.OnSharedPreferenceChangeListener {
private SwitchCompat swBadge;
private SwitchCompat swUnseenIgnored;
private SwitchCompat swNotifySummary;
private SwitchCompat swNotifyPreview;
private CheckBox cbNotifyActionTrash;
private CheckBox cbNotifyActionJunk;
@ -82,7 +83,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
private final static String[] RESET_OPTIONS = new String[]{
"badge", "unseen_ignored",
"notify_preview", "notify_trash", "notify_junk", "notify_archive", "notify_reply", "notify_reply_direct", "notify_flag",
"notify_summary", "notify_preview", "notify_trash", "notify_junk", "notify_archive", "notify_reply", "notify_reply_direct", "notify_flag",
"notify_seen", "notify_snooze", "notify_snooze_duration", "notify_remove",
"biometrics_notify",
"light", "sound", "alert_once"
@ -100,6 +101,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
swBadge = view.findViewById(R.id.swBadge);
swUnseenIgnored = view.findViewById(R.id.swUnseenIgnored);
swNotifySummary = view.findViewById(R.id.swNotifySummary);
swNotifyPreview = view.findViewById(R.id.swNotifyPreview);
cbNotifyActionTrash = view.findViewById(R.id.cbNotifyActionTrash);
cbNotifyActionJunk = view.findViewById(R.id.cbNotifyActionJunk);
@ -147,6 +149,14 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
}
});
swNotifySummary.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("notify_summary", checked).apply();
enableOptions();
}
});
swNotifyPreview.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
@ -354,6 +364,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
swBadge.setChecked(prefs.getBoolean("badge", true));
swUnseenIgnored.setChecked(prefs.getBoolean("unseen_ignored", false));
swNotifySummary.setChecked(prefs.getBoolean("notify_summary", false));
swNotifyPreview.setChecked(prefs.getBoolean("notify_preview", true));
cbNotifyActionTrash.setChecked(prefs.getBoolean("notify_trash", true) || !pro);
@ -366,20 +377,31 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
cbNotifyActionSnooze.setChecked(prefs.getBoolean("notify_snooze", false) || !pro);
etNotifyActionSnooze.setText(Integer.toString(prefs.getInt("notify_snooze_duration", 60)));
cbNotifyActionTrash.setEnabled(pro);
cbNotifyActionJunk.setEnabled(pro);
cbNotifyActionArchive.setEnabled(pro);
cbNotifyActionReply.setEnabled(pro);
cbNotifyActionReplyDirect.setEnabled(pro);
cbNotifyActionFlag.setEnabled(pro);
cbNotifyActionSeen.setEnabled(pro);
cbNotifyActionSnooze.setEnabled(pro);
swNotifyRemove.setChecked(prefs.getBoolean("notify_remove", true));
swBiometricsNotify.setChecked(prefs.getBoolean("biometrics_notify", false));
swLight.setChecked(prefs.getBoolean("light", false));
swAlertOnce.setChecked(!prefs.getBoolean("alert_once", true));
enableOptions();
}
private void enableOptions() {
boolean pro = ActivityBilling.isPro(getContext());
boolean checked = swNotifySummary.isChecked();
swNotifyPreview.setEnabled(!checked);
cbNotifyActionTrash.setEnabled(pro && !checked);
cbNotifyActionJunk.setEnabled(pro && !checked);
cbNotifyActionArchive.setEnabled(pro && !checked);
cbNotifyActionReply.setEnabled(pro && !checked);
cbNotifyActionReplyDirect.setEnabled(pro && !checked);
cbNotifyActionFlag.setEnabled(pro && !checked);
cbNotifyActionSeen.setEnabled(pro && !checked);
cbNotifyActionSnooze.setEnabled(pro && !checked);
etNotifyActionSnooze.setEnabled(pro && !checked);
swNotifyRemove.setEnabled(pro && !checked);
swBiometricsNotify.setEnabled(!checked);
}
@Override

@ -46,6 +46,17 @@
app:layout_constraintTop_toBottomOf="@id/tvBadgeHint"
app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swNotifySummary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_advanced_notify_summary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swUnseenIgnored"
app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swNotifyPreview"
android:layout_width="0dp"
@ -55,7 +66,7 @@
android:text="@string/title_advanced_notify_preview"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swUnseenIgnored"
app:layout_constraintTop_toBottomOf="@id/swNotifySummary"
app:switchPadding="12dp" />
<TextView

@ -285,6 +285,7 @@
<string name="title_advanced_badge">Show launcher icon with number of new messages</string>
<string name="title_advanced_unseen_ignored">Let the number of new messages match the number of notifications</string>
<string name="title_advanced_notify_summary">Show summary notification only</string>
<string name="title_advanced_notify_preview">Show message preview in notifications</string>
<string name="title_advanced_notify_actions">Notification actions</string>
<string name="title_advanced_notify_action_trash">Trash</string>

Loading…
Cancel
Save