Persist notifying messages

pull/157/head
M66B 5 years ago
parent 828d936325
commit dd3d92d61f

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();
}
}

Loading…
Cancel
Save