From a5b09a0f65f14abaf384199df1d8c516bbaeb680 Mon Sep 17 00:00:00 2001 From: akwizgran <akwizgran@users.sourceforge.net> Date: Fri, 7 Mar 2014 12:21:12 +0000 Subject: [PATCH] Better notifications. Development task #67. --- briar-android/res/values/strings.xml | 6 +- .../briarproject/android/AndroidModule.java | 10 +- .../AndroidNotificationManagerImpl.java | 170 ++++++++++++++++++ .../briarproject/android/BriarService.java | 53 +----- .../android/contact/ConversationActivity.java | 66 +++++-- .../android/groups/GroupActivity.java | 39 +++- .../android/AndroidNotificationManager.java | 21 +++ 7 files changed, 288 insertions(+), 77 deletions(-) create mode 100644 briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java create mode 100644 briar-api/src/org/briarproject/api/android/AndroidNotificationManager.java diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index f71e679791..229cf49244 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -76,10 +76,8 @@ <string name="add_button">Add</string> <string name="cancel_button">Cancel</string> <string name="post_sent_toast">Post sent</string> - <string name="private_message_notification_title">New private message</string> - <string name="private_message_notification_text">Touch to show.</string> - <string name="group_post_notification_title">New forum post</string> - <string name="group_post_notification_text">Touch to show.</string> + <string name="private_message_notification_text">New private message.</string> + <string name="group_post_notification_text">New forum post.</string> <string name="settings_title">Settings</string> <string name="activate_bluetooth_option">Activate Bluetooth while signed in</string> <string name="activate_bluetooth_explanation">Briar uses Bluetooth to communicate with nearby contacts</string> diff --git a/briar-android/src/org/briarproject/android/AndroidModule.java b/briar-android/src/org/briarproject/android/AndroidModule.java index 78c7a3a579..3f871d2c9f 100644 --- a/briar-android/src/org/briarproject/android/AndroidModule.java +++ b/briar-android/src/org/briarproject/android/AndroidModule.java @@ -14,6 +14,7 @@ import java.util.concurrent.ThreadPoolExecutor; import javax.inject.Singleton; import org.briarproject.api.android.AndroidExecutor; +import org.briarproject.api.android.AndroidNotificationManager; import org.briarproject.api.android.DatabaseUiExecutor; import org.briarproject.api.android.ReferenceManager; import org.briarproject.api.db.DatabaseConfig; @@ -57,9 +58,12 @@ public class AndroidModule extends AbstractModule { } protected void configure() { - bind(AndroidExecutor.class).to(AndroidExecutorImpl.class); - bind(ReferenceManager.class).to( - ReferenceManagerImpl.class).in(Singleton.class); + bind(AndroidExecutor.class).to(AndroidExecutorImpl.class).in( + Singleton.class); + bind(AndroidNotificationManager.class).to( + AndroidNotificationManagerImpl.class).in(Singleton.class); + bind(ReferenceManager.class).to(ReferenceManagerImpl.class).in( + Singleton.class); bind(UiCallback.class).toInstance(uiCallback); } diff --git a/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java b/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java new file mode 100644 index 0000000000..51dcea4d1e --- /dev/null +++ b/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java @@ -0,0 +1,170 @@ +package org.briarproject.android; + +import static android.app.Notification.DEFAULT_ALL; +import static android.content.Context.NOTIFICATION_SERVICE; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; + +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Inject; + +import org.briarproject.R; +import org.briarproject.android.contact.ContactListActivity; +import org.briarproject.android.contact.ConversationActivity; +import org.briarproject.android.groups.GroupActivity; +import org.briarproject.android.groups.GroupListActivity; +import org.briarproject.api.ContactId; +import org.briarproject.api.android.AndroidNotificationManager; +import org.briarproject.api.messaging.GroupId; + +import android.app.Application; +import android.app.NotificationManager; +import android.content.Context; +import android.content.Intent; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.TaskStackBuilder; + +class AndroidNotificationManagerImpl implements AndroidNotificationManager { + + private static final int PRIVATE_MESSAGE_NOTIFICATION_ID = 3; + private static final int GROUP_POST_NOTIFICATION_ID = 4; + + private final Context appContext; + private final Map<ContactId, Integer> contactCounts = + new HashMap<ContactId, Integer>(); // Locking: this + private final Map<GroupId, Integer> groupCounts = + new HashMap<GroupId, Integer>(); // Locking: this + + private int privateTotal = 0, groupTotal = 0; // Locking: this + + @Inject + public AndroidNotificationManagerImpl(Application app) { + this.appContext = app.getApplicationContext(); + } + + public synchronized void showPrivateMessageNotification(ContactId c) { + Integer count = contactCounts.get(c); + if(count == null) contactCounts.put(c, 1); + else contactCounts.put(c, count + 1); + privateTotal++; + updatePrivateMessageNotification(); + } + + public synchronized void clearPrivateMessageNotification(ContactId c) { + Integer count = contactCounts.remove(c); + if(count == null) return; // Already cleared + privateTotal -= count; + updatePrivateMessageNotification(); + } + + // Locking: this + private void updatePrivateMessageNotification() { + if(privateTotal == 0) { + clearPrivateMessageNotification(); + } else { + NotificationCompat.Builder b = + new NotificationCompat.Builder(appContext); + b.setSmallIcon(R.drawable.message_notification_icon); + b.setContentTitle(appContext.getText(R.string.app_name)); + b.setContentText(appContext.getText( + R.string.private_message_notification_text)); + b.setDefaults(DEFAULT_ALL); + b.setOnlyAlertOnce(true); + if(contactCounts.size() == 1) { + Intent i = new Intent(appContext, ConversationActivity.class); + ContactId c = contactCounts.keySet().iterator().next(); + i.putExtra("briar.CONTACT_ID", c.getInt()); + i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_SINGLE_TOP); + TaskStackBuilder tsb = TaskStackBuilder.create(appContext); + tsb.addParentStack(ConversationActivity.class); + tsb.addNextIntent(i); + b.setContentIntent(tsb.getPendingIntent(0, 0)); + } else { + Intent i = new Intent(appContext, ContactListActivity.class); + i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_SINGLE_TOP); + TaskStackBuilder tsb = TaskStackBuilder.create(appContext); + tsb.addParentStack(ContactListActivity.class); + tsb.addNextIntent(i); + b.setContentIntent(tsb.getPendingIntent(0, 0)); + } + Object o = appContext.getSystemService(NOTIFICATION_SERVICE); + NotificationManager nm = (NotificationManager) o; + nm.notify(PRIVATE_MESSAGE_NOTIFICATION_ID, b.build()); + } + } + + // Locking: this + private void clearPrivateMessageNotification() { + Object o = appContext.getSystemService(NOTIFICATION_SERVICE); + NotificationManager nm = (NotificationManager) o; + nm.cancel(PRIVATE_MESSAGE_NOTIFICATION_ID); + } + + public synchronized void showGroupPostNotification(GroupId g) { + Integer count = groupCounts.get(g); + if(count == null) groupCounts.put(g, 1); + else groupCounts.put(g, count + 1); + groupTotal++; + updateGroupPostNotification(); + } + + public synchronized void clearGroupPostNotification(GroupId g) { + Integer count = groupCounts.remove(g); + if(count == null) return; // Already cleared + groupTotal -= count; + updateGroupPostNotification(); + } + + // Locking: this + private void updateGroupPostNotification() { + if(groupTotal == 0) { + clearGroupPostNotification(); + } else { + NotificationCompat.Builder b = + new NotificationCompat.Builder(appContext); + b.setSmallIcon(R.drawable.message_notification_icon); + b.setContentTitle(appContext.getText(R.string.app_name)); + b.setContentText(appContext.getText( + R.string.group_post_notification_text)); + b.setDefaults(DEFAULT_ALL); + b.setOnlyAlertOnce(true); + if(groupCounts.size() == 1) { + Intent i = new Intent(appContext, GroupActivity.class); + GroupId g = groupCounts.keySet().iterator().next(); + i.putExtra("briar.GROUP_ID", g.getBytes()); + i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_SINGLE_TOP); + TaskStackBuilder tsb = TaskStackBuilder.create(appContext); + tsb.addParentStack(GroupActivity.class); + tsb.addNextIntent(i); + b.setContentIntent(tsb.getPendingIntent(0, 0)); + } else { + Intent i = new Intent(appContext, GroupListActivity.class); + i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_SINGLE_TOP); + TaskStackBuilder tsb = TaskStackBuilder.create(appContext); + tsb.addParentStack(GroupListActivity.class); + tsb.addNextIntent(i); + b.setContentIntent(tsb.getPendingIntent(0, 0)); + } + Object o = appContext.getSystemService(NOTIFICATION_SERVICE); + NotificationManager nm = (NotificationManager) o; + nm.notify(GROUP_POST_NOTIFICATION_ID, b.build()); + } + } + + // Locking: this + private void clearGroupPostNotification() { + Object o = appContext.getSystemService(NOTIFICATION_SERVICE); + NotificationManager nm = (NotificationManager) o; + nm.cancel(GROUP_POST_NOTIFICATION_ID); + } + + public synchronized void clearNotifications() { + contactCounts.clear(); + groupCounts.clear(); + privateTotal = groupTotal = 0; + clearPrivateMessageNotification(); + clearGroupPostNotification(); + } +} diff --git a/briar-android/src/org/briarproject/android/BriarService.java b/briar-android/src/org/briarproject/android/BriarService.java index 4e556b2db7..bbf576174c 100644 --- a/briar-android/src/org/briarproject/android/BriarService.java +++ b/briar-android/src/org/briarproject/android/BriarService.java @@ -1,6 +1,5 @@ package org.briarproject.android; -import static android.app.Notification.DEFAULT_ALL; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; @@ -15,10 +14,9 @@ import java.util.logging.Logger; import javax.inject.Inject; import org.briarproject.R; -import org.briarproject.android.contact.ContactListActivity; -import org.briarproject.android.groups.GroupListActivity; import org.briarproject.api.ContactId; import org.briarproject.api.android.AndroidExecutor; +import org.briarproject.api.android.AndroidNotificationManager; import org.briarproject.api.android.DatabaseUiExecutor; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseConfig; @@ -38,14 +36,11 @@ import android.content.ServiceConnection; import android.os.Binder; import android.os.IBinder; import android.support.v4.app.NotificationCompat; -import android.support.v4.app.TaskStackBuilder; public class BriarService extends RoboService implements EventListener { private static final int ONGOING_NOTIFICATION_ID = 1; private static final int FAILURE_NOTIFICATION_ID = 2; - private static final int PRIVATE_MESSAGE_NOTIFICATION_ID = 3; - private static final int GROUP_POST_NOTIFICATION_ID = 4; private static final Logger LOG = Logger.getLogger(BriarService.class.getName()); @@ -54,6 +49,7 @@ public class BriarService extends RoboService implements EventListener { private final Binder binder = new BriarBinder(); @Inject private DatabaseConfig databaseConfig; + @Inject private AndroidNotificationManager notificationManager; // Fields that are accessed from background threads must be volatile @Inject private volatile LifecycleManager lifecycleManager; @@ -135,11 +131,8 @@ public class BriarService extends RoboService implements EventListener { public void onDestroy() { super.onDestroy(); if(LOG.isLoggable(INFO)) LOG.info("Destroyed"); - Object o = getSystemService(NOTIFICATION_SERVICE); - NotificationManager nm = (NotificationManager) o; - nm.cancel(PRIVATE_MESSAGE_NOTIFICATION_ID); - nm.cancel(GROUP_POST_NOTIFICATION_ID); stopForeground(true); + notificationManager.clearNotifications(); // Stop the services in a background thread new Thread() { @Override @@ -168,8 +161,8 @@ public class BriarService extends RoboService implements EventListener { try { lifecycleManager.waitForDatabase(); if(g.equals(db.getInboxGroupId(c))) - showPrivateMessageNotification(); - else showGroupPostNotification(); + notificationManager.showPrivateMessageNotification(c); + else notificationManager.showGroupPostNotification(g); } catch(DbException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -182,42 +175,6 @@ public class BriarService extends RoboService implements EventListener { }); } - private void showPrivateMessageNotification() { - NotificationCompat.Builder b = new NotificationCompat.Builder(this); - b.setSmallIcon(R.drawable.message_notification_icon); - b.setContentTitle(getText(R.string.private_message_notification_title)); - b.setContentText(getText(R.string.private_message_notification_text)); - b.setAutoCancel(true); - b.setDefaults(DEFAULT_ALL); - Intent i = new Intent(this, ContactListActivity.class); - i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_SINGLE_TOP); - TaskStackBuilder tsb = TaskStackBuilder.create(this); - tsb.addParentStack(ContactListActivity.class); - tsb.addNextIntent(i); - b.setContentIntent(tsb.getPendingIntent(0, 0)); - Object o = getSystemService(NOTIFICATION_SERVICE); - NotificationManager nm = (NotificationManager) o; - nm.notify(PRIVATE_MESSAGE_NOTIFICATION_ID, b.build()); - } - - private void showGroupPostNotification() { - NotificationCompat.Builder b = new NotificationCompat.Builder(this); - b.setSmallIcon(R.drawable.message_notification_icon); - b.setContentTitle(getText(R.string.group_post_notification_title)); - b.setContentText(getText(R.string.group_post_notification_text)); - b.setAutoCancel(true); - b.setDefaults(DEFAULT_ALL); - Intent i = new Intent(this, GroupListActivity.class); - i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_SINGLE_TOP); - TaskStackBuilder tsb = TaskStackBuilder.create(this); - tsb.addParentStack(GroupListActivity.class); - tsb.addNextIntent(i); - b.setContentIntent(tsb.getPendingIntent(0, 0)); - Object o = getSystemService(NOTIFICATION_SERVICE); - NotificationManager nm = (NotificationManager) o; - nm.notify(GROUP_POST_NOTIFICATION_ID, b.build()); - } - /** Waits for the database to be opened before returning. */ public void waitForDatabase() throws InterruptedException { lifecycleManager.waitForDatabase(); diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java index a3540fe149..e815591c00 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java @@ -37,7 +37,9 @@ import org.briarproject.android.util.HorizontalBorder; import org.briarproject.android.util.LayoutUtils; import org.briarproject.android.util.ListLoadingProgressBar; import org.briarproject.api.AuthorId; +import org.briarproject.api.Contact; import org.briarproject.api.ContactId; +import org.briarproject.api.android.AndroidNotificationManager; import org.briarproject.api.crypto.CryptoExecutor; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DbException; @@ -81,9 +83,9 @@ implements EventListener, OnClickListener, OnItemClickListener { private static final Logger LOG = Logger.getLogger(ConversationActivity.class.getName()); + @Inject private AndroidNotificationManager notificationManager; @Inject @CryptoExecutor private Executor cryptoExecutor; private Map<MessageId, byte[]> bodyCache = new HashMap<MessageId, byte[]>(); - private String contactName = null; private TextView empty = null; private ConversationAdapter adapter = null; private ListView list = null; @@ -95,6 +97,7 @@ implements EventListener, OnClickListener, OnItemClickListener { @Inject private volatile DatabaseComponent db; @Inject private volatile MessageFactory messageFactory; private volatile ContactId contactId = null; + private volatile String contactName = null; private volatile GroupId groupId = null; private volatile Group group = null; private volatile AuthorId localAuthorId = null; @@ -107,15 +110,6 @@ implements EventListener, OnClickListener, OnItemClickListener { int id = i.getIntExtra("briar.CONTACT_ID", -1); if(id == -1) throw new IllegalStateException(); contactId = new ContactId(id); - contactName = i.getStringExtra("briar.CONTACT_NAME"); - if(contactName == null) throw new IllegalStateException(); - setTitle(contactName); - byte[] b = i.getByteArrayExtra("briar.GROUP_ID"); - if(b == null) throw new IllegalStateException(); - groupId = new GroupId(b); - b = i.getByteArrayExtra("briar.LOCAL_AUTHOR_ID"); - if(b == null) throw new IllegalStateException(); - localAuthorId = new AuthorId(b); Intent data = new Intent(); data.putExtra("briar.CONTACT_ID", id); @@ -194,25 +188,59 @@ implements EventListener, OnClickListener, OnItemClickListener { public void onResume() { super.onResume(); db.addListener(this); - loadHeadersAndGroup(); + loadContactAndGroup(); + loadHeaders(); } - private void loadHeadersAndGroup() { + private void loadContactAndGroup() { + runOnDbThread(new Runnable() { + public void run() { + try { + long now = System.currentTimeMillis(); + Contact contact = db.getContact(contactId); + contactName = contact.getAuthor().getName(); + localAuthorId = contact.getLocalAuthorId(); + groupId = db.getInboxGroupId(contactId); + group = db.getGroup(groupId); + long duration = System.currentTimeMillis() - now; + if(LOG.isLoggable(INFO)) { + LOG.info("Loading contact and group took " + + duration + " ms"); + } + displayContactName(); + } catch(NoSuchContactException e) { + finishOnUiThread(); + } catch(NoSuchSubscriptionException e) { + finishOnUiThread(); + } catch(DbException e) { + if(LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } + } + }); + } + + private void displayContactName() { + runOnUiThread(new Runnable() { + public void run() { + setTitle(contactName); + } + }); + } + + private void loadHeaders() { runOnDbThread(new Runnable() { public void run() { try { long now = System.currentTimeMillis(); Collection<MessageHeader> headers = db.getInboxMessageHeaders(contactId); - group = db.getGroup(groupId); long duration = System.currentTimeMillis() - now; if(LOG.isLoggable(INFO)) - LOG.info("Load took " + duration + " ms"); + LOG.info("Loading headers took " + duration + " ms"); displayHeaders(headers); } catch(NoSuchContactException e) { finishOnUiThread(); - } catch(NoSuchSubscriptionException e) { - finishOnUiThread(); } catch(DbException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -225,6 +253,7 @@ implements EventListener, OnClickListener, OnItemClickListener { runOnUiThread(new Runnable() { public void run() { loading.setVisibility(GONE); + setTitle(contactName); sendButton.setEnabled(true); adapter.clear(); if(headers.isEmpty()) { @@ -306,6 +335,7 @@ implements EventListener, OnClickListener, OnItemClickListener { } private void markMessagesRead() { + notificationManager.clearPrivateMessageNotification(contactId); List<MessageId> unread = new ArrayList<MessageId>(); int count = adapter.getCount(); for(int i = 0; i < count; i++) { @@ -346,11 +376,11 @@ implements EventListener, OnClickListener, OnItemClickListener { GroupId g = ((MessageAddedEvent) e).getGroup().getId(); if(g.equals(groupId)) { if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading"); - loadHeadersAndGroup(); + loadHeaders(); } } else if(e instanceof MessageExpiredEvent) { if(LOG.isLoggable(INFO)) LOG.info("Message expired, reloading"); - loadHeadersAndGroup(); + loadHeaders(); } } diff --git a/briar-android/src/org/briarproject/android/groups/GroupActivity.java b/briar-android/src/org/briarproject/android/groups/GroupActivity.java index c38c7985e9..ed343db93e 100644 --- a/briar-android/src/org/briarproject/android/groups/GroupActivity.java +++ b/briar-android/src/org/briarproject/android/groups/GroupActivity.java @@ -27,6 +27,7 @@ import org.briarproject.android.BriarActivity; import org.briarproject.android.util.HorizontalBorder; import org.briarproject.android.util.ListLoadingProgressBar; import org.briarproject.api.Author; +import org.briarproject.api.android.AndroidNotificationManager; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DbException; import org.briarproject.api.db.MessageHeader; @@ -37,6 +38,7 @@ import org.briarproject.api.event.EventListener; import org.briarproject.api.event.MessageAddedEvent; import org.briarproject.api.event.MessageExpiredEvent; import org.briarproject.api.event.SubscriptionRemovedEvent; +import org.briarproject.api.messaging.Group; import org.briarproject.api.messaging.GroupId; import org.briarproject.api.messaging.MessageId; @@ -59,8 +61,8 @@ OnClickListener, OnItemClickListener { private static final Logger LOG = Logger.getLogger(GroupActivity.class.getName()); + @Inject private AndroidNotificationManager notificationManager; private Map<MessageId, byte[]> bodyCache = new HashMap<MessageId, byte[]>(); - private String groupName = null; private TextView empty = null; private GroupAdapter adapter = null; private ListView list = null; @@ -69,6 +71,7 @@ OnClickListener, OnItemClickListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; private volatile GroupId groupId = null; + private volatile String groupName = null; @Override public void onCreate(Bundle state) { @@ -78,9 +81,6 @@ OnClickListener, OnItemClickListener { byte[] b = i.getByteArrayExtra("briar.GROUP_ID"); if(b == null) throw new IllegalStateException(); groupId = new GroupId(b); - groupName = i.getStringExtra("briar.GROUP_NAME"); - if(groupName == null) throw new IllegalStateException(); - setTitle(groupName); LinearLayout layout = new LinearLayout(this); layout.setLayoutParams(MATCH_MATCH); @@ -128,9 +128,39 @@ OnClickListener, OnItemClickListener { public void onResume() { super.onResume(); db.addListener(this); + loadGroup(); loadHeaders(); } + private void loadGroup() { + runOnDbThread(new Runnable() { + public void run() { + try { + long now = System.currentTimeMillis(); + Group g = db.getGroup(groupId); + groupName = g.getName(); + long duration = System.currentTimeMillis() - now; + if(LOG.isLoggable(INFO)) + LOG.info("Loading group " + duration + " ms"); + displayGroupName(); + } catch(NoSuchSubscriptionException e) { + finishOnUiThread(); + } catch(DbException e) { + if(LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } + } + }); + } + + private void displayGroupName() { + runOnUiThread(new Runnable() { + public void run() { + setTitle(groupName); + } + }); + } + private void loadHeaders() { runOnDbThread(new Runnable() { public void run() { @@ -236,6 +266,7 @@ OnClickListener, OnItemClickListener { } private void markMessagesRead() { + notificationManager.clearGroupPostNotification(groupId); List<MessageId> unread = new ArrayList<MessageId>(); int count = adapter.getCount(); for(int i = 0; i < count; i++) { diff --git a/briar-api/src/org/briarproject/api/android/AndroidNotificationManager.java b/briar-api/src/org/briarproject/api/android/AndroidNotificationManager.java new file mode 100644 index 0000000000..c0be8a754f --- /dev/null +++ b/briar-api/src/org/briarproject/api/android/AndroidNotificationManager.java @@ -0,0 +1,21 @@ +package org.briarproject.api.android; + +import org.briarproject.api.ContactId; +import org.briarproject.api.messaging.GroupId; + +/** + * Manages notifications for private messages and group posts. All methods must + * be called from the Android UI thread. + */ +public interface AndroidNotificationManager { + + public void showPrivateMessageNotification(ContactId c); + + public void clearPrivateMessageNotification(ContactId c); + + public void showGroupPostNotification(GroupId g); + + public void clearGroupPostNotification(GroupId g); + + public void clearNotifications(); +} -- GitLab