mirror of
https://github.com/M66B/FairEmail.git
synced 2026-03-29 05:15:13 +02:00
Persist notifying messages
This commit is contained in:
1800
app/schemas/eu.faircode.email.DB/90.json
Normal file
1800
app/schemas/eu.faircode.email.DB/90.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -75,6 +75,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -113,6 +115,8 @@ class Core {
|
||||
private static final long YIELD_DURATION = 200L; // milliseconds
|
||||
private static final long MIN_HIDE = 60 * 1000L; // milliseconds
|
||||
|
||||
private static final ExecutorService executor = Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory);
|
||||
|
||||
static void processOperations(
|
||||
Context context,
|
||||
EntityAccount account, EntityFolder folder,
|
||||
@@ -1724,7 +1728,7 @@ class Core {
|
||||
}
|
||||
}
|
||||
|
||||
static void notifyMessages(Context context, Map<String, List<Long>> groupNotifying, List<TupleMessageEx> messages) {
|
||||
static void notifyMessages(Context context, List<TupleMessageEx> messages) {
|
||||
Log.i("Notify messages=" + messages.size());
|
||||
|
||||
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
@@ -1735,23 +1739,17 @@ class Core {
|
||||
boolean badge = prefs.getBoolean("badge", true);
|
||||
boolean pro = Helper.isPro(context);
|
||||
|
||||
// Update widget/badge count
|
||||
if (lastUnseen < 0 || messages.size() != lastUnseen) {
|
||||
lastUnseen = messages.size();
|
||||
Widget.update(context, messages.size());
|
||||
try {
|
||||
ShortcutBadger.applyCount(context, badge ? messages.size() : 0);
|
||||
} catch (Throwable ex) {
|
||||
Log.e(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Current
|
||||
int unseen = 0;
|
||||
final Map<String, List<Long>> groupNotifying = new HashMap<>();
|
||||
Map<String, List<TupleMessageEx>> groupMessages = new HashMap<>();
|
||||
for (TupleMessageEx message : messages) {
|
||||
if (!(message.ui_seen || message.ui_ignored || message.ui_hide != 0))
|
||||
unseen++;
|
||||
|
||||
// Check if notification channel enabled
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O &&
|
||||
message.from != null && message.from.length > 0) {
|
||||
message.notifying == 0 && message.from != null && message.from.length > 0) {
|
||||
InternetAddress from = (InternetAddress) message.from[0];
|
||||
NotificationChannel channel = nm.getNotificationChannel("notification." + from.getAddress().toLowerCase());
|
||||
if (channel != null && channel.getImportance() == NotificationManager.IMPORTANCE_NONE)
|
||||
@@ -1760,27 +1758,41 @@ class Core {
|
||||
|
||||
String group = Long.toString(pro && message.accountNotify ? message.account : 0);
|
||||
if (!groupMessages.containsKey(group)) {
|
||||
groupNotifying.put(group, new ArrayList<Long>());
|
||||
groupMessages.put(group, new ArrayList<TupleMessageEx>());
|
||||
if (!groupNotifying.containsKey(group))
|
||||
groupNotifying.put(group, new ArrayList<Long>());
|
||||
}
|
||||
|
||||
// This assumes the messages are properly ordered
|
||||
if (groupMessages.get(group).size() < MAX_NOTIFICATION_COUNT)
|
||||
groupMessages.get(group).add(message);
|
||||
if (message.notifying != 0)
|
||||
groupNotifying.get(group).add(message.id * message.notifying);
|
||||
|
||||
if (!(message.ui_seen || message.ui_ignored || message.ui_hide != 0)) {
|
||||
// This assumes the messages are properly ordered
|
||||
if (groupMessages.get(group).size() < MAX_NOTIFICATION_COUNT)
|
||||
groupMessages.get(group).add(message);
|
||||
}
|
||||
}
|
||||
|
||||
// Update widget/badge count
|
||||
if (lastUnseen < 0 || unseen != lastUnseen) {
|
||||
lastUnseen = unseen;
|
||||
Widget.update(context, unseen);
|
||||
try {
|
||||
ShortcutBadger.applyCount(context, badge ? unseen : 0);
|
||||
} catch (Throwable ex) {
|
||||
Log.e(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Difference
|
||||
for (String group : groupNotifying.keySet()) {
|
||||
for (String group : groupMessages.keySet()) {
|
||||
List<Notification> notifications = getNotificationUnseen(context, group, groupMessages.get(group));
|
||||
|
||||
List<Long> all = new ArrayList<>();
|
||||
List<Long> add = new ArrayList<>();
|
||||
List<Long> remove = groupNotifying.get(group);
|
||||
final List<Long> add = new ArrayList<>();
|
||||
final List<Long> remove = groupNotifying.get(group);
|
||||
|
||||
for (Notification notification : notifications) {
|
||||
Long id = notification.extras.getLong("id", 0);
|
||||
if (id != 0) {
|
||||
all.add(id);
|
||||
if (id != 0)
|
||||
if (remove.contains(id)) {
|
||||
remove.remove(id);
|
||||
Log.i("Notify existing=" + id);
|
||||
@@ -1789,7 +1801,6 @@ class Core {
|
||||
add.add(id);
|
||||
Log.i("Notify adding=" + id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int headers = 0;
|
||||
@@ -1803,13 +1814,13 @@ class Core {
|
||||
if (notifications.size() == 0 ||
|
||||
(Build.VERSION.SDK_INT < Build.VERSION_CODES.O && headers > 0)) {
|
||||
String tag = "unseen.0";
|
||||
Log.i("Cancelling tag=" + tag);
|
||||
Log.i("Notify cancel tag=" + tag);
|
||||
nm.cancel(tag, 1);
|
||||
}
|
||||
|
||||
for (Long id : remove) {
|
||||
String tag = "unseen." + Math.abs(id);
|
||||
Log.i("Cancelling tag=" + tag);
|
||||
Log.i("Notify cancel tag=" + tag);
|
||||
nm.cancel(tag, 1);
|
||||
}
|
||||
|
||||
@@ -1823,7 +1834,29 @@ class Core {
|
||||
}
|
||||
}
|
||||
|
||||
groupNotifying.put(group, all);
|
||||
if (remove.size() + add.size() > 0) {
|
||||
final DB db = DB.getInstance(context);
|
||||
|
||||
executor.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
||||
for (long id : remove)
|
||||
db.message().setMessageNotifying(Math.abs(id), 0);
|
||||
for (long id : add)
|
||||
db.message().setMessageNotifying(Math.abs(id), (int) Math.signum(id));
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} catch (Throwable ex) {
|
||||
Log.e(ex);
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory;
|
||||
// https://developer.android.com/topic/libraries/architecture/room.html
|
||||
|
||||
@Database(
|
||||
version = 89,
|
||||
version = 90,
|
||||
entities = {
|
||||
EntityIdentity.class,
|
||||
EntityAccount.class,
|
||||
@@ -883,6 +883,13 @@ public abstract class DB extends RoomDatabase {
|
||||
db.execSQL("ALTER TABLE `account` ADD COLUMN `separator` INTEGER");
|
||||
}
|
||||
})
|
||||
.addMigrations(new Migration(89, 90) {
|
||||
@Override
|
||||
public void migrate(SupportSQLiteDatabase db) {
|
||||
Log.i("DB migration from version " + startVersion + " to " + endVersion);
|
||||
db.execSQL("ALTER TABLE `message` ADD COLUMN `notifying` INTEGER NOT NULL DEFAULT 0");
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -278,9 +278,7 @@ public interface DaoMessage {
|
||||
" WHERE account.`synchronize`" +
|
||||
" AND folder.notify" +
|
||||
" AND (account.created IS NULL OR message.received > account.created)" +
|
||||
" AND NOT message.ui_seen" +
|
||||
" AND NOT message.ui_ignored" +
|
||||
" AND message.ui_hide = 0" +
|
||||
" AND (notifying <> 0 OR NOT (message.ui_seen OR message.ui_ignored OR message.ui_hide <> 0))" +
|
||||
" ORDER BY message.received")
|
||||
LiveData<List<TupleMessageEx>> liveUnseenNotify();
|
||||
|
||||
@@ -335,6 +333,9 @@ public interface DaoMessage {
|
||||
@Query("UPDATE message SET msgid = :msgid WHERE id = :id")
|
||||
int setMessageMsgId(long id, String msgid);
|
||||
|
||||
@Query("UPDATE message SET notifying = :notifying WHERE id = :id")
|
||||
int setMessageNotifying(long id, int notifying);
|
||||
|
||||
@Query("UPDATE message SET seen = :seen WHERE id = :id")
|
||||
int setMessageSeen(long id, boolean seen);
|
||||
|
||||
|
||||
@@ -129,6 +129,8 @@ public class EntityMessage implements Serializable {
|
||||
public String flags; // system flags
|
||||
public String[] keywords; // user flags
|
||||
@NonNull
|
||||
public Integer notifying = 0;
|
||||
@NonNull
|
||||
public Boolean ui_seen = false;
|
||||
@NonNull
|
||||
public Boolean ui_answered = false;
|
||||
@@ -272,6 +274,7 @@ public class EntityMessage implements Serializable {
|
||||
this.flagged.equals(other.flagged) &&
|
||||
Objects.equals(this.flags, other.flags) &&
|
||||
Helper.equal(this.keywords, other.keywords) &&
|
||||
this.notifying.equals(other.notifying) &&
|
||||
this.ui_seen.equals(other.ui_seen) &&
|
||||
this.ui_answered.equals(other.ui_answered) &&
|
||||
this.ui_flagged.equals(other.ui_flagged) &&
|
||||
|
||||
@@ -165,12 +165,12 @@ public class ServiceSynchronize extends LifecycleService {
|
||||
});
|
||||
|
||||
db.message().liveUnseenNotify().observe(cowner, new Observer<List<TupleMessageEx>>() {
|
||||
private Map<String, List<Long>> notifying = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void onChanged(List<TupleMessageEx> messages) {
|
||||
try {
|
||||
Core.notifyMessages(ServiceSynchronize.this, notifying, messages);
|
||||
if (messages == null)
|
||||
messages = new ArrayList<>();
|
||||
Core.notifyMessages(ServiceSynchronize.this, messages);
|
||||
} catch (SecurityException ex) {
|
||||
Log.w(ex);
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ServiceSynchronize.this);
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.service.quicksettings.TileService;
|
||||
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
@@ -42,15 +43,23 @@ public class ServiceTileUnseen extends TileService {
|
||||
DB.getInstance(this).message().liveUnseenNotify().observe(owner, new Observer<List<TupleMessageEx>>() {
|
||||
@Override
|
||||
public void onChanged(List<TupleMessageEx> messages) {
|
||||
Log.i("Update tile unseen=" + messages.size());
|
||||
if (messages == null)
|
||||
messages = new ArrayList<>();
|
||||
|
||||
int unseen = 0;
|
||||
for (TupleMessageEx message : messages)
|
||||
if (!message.ui_seen && !message.ui_ignored && message.ui_hide == 0)
|
||||
unseen++;
|
||||
|
||||
Log.i("Update tile unseen=" + unseen);
|
||||
|
||||
Tile tile = getQsTile();
|
||||
if (tile != null) {
|
||||
tile.setState(messages.size() > 0 ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
|
||||
tile.setState(unseen > 0 ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
|
||||
tile.setIcon(Icon.createWithResource(ServiceTileUnseen.this,
|
||||
messages.size() > 0 ? R.drawable.baseline_mail_24 : R.drawable.baseline_mail_outline_24));
|
||||
unseen > 0 ? R.drawable.baseline_mail_24 : R.drawable.baseline_mail_outline_24));
|
||||
tile.setLabel(getResources().getQuantityString(
|
||||
R.plurals.title_tile_unseen, messages.size(), messages.size()));
|
||||
R.plurals.title_tile_unseen, unseen, unseen));
|
||||
tile.updateTile();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user