diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index d1c7834ab..42c797924 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -52,6 +52,10 @@
- New private message.
- %d new private messages.
+
+ - New group message.
+ - %d new group messages.
+
- New forum post.
- %d new forum posts.
@@ -328,6 +332,7 @@
Notifications
Show alerts for private messages
+ Show alerts for group messages
Show alerts for forum posts
Show alerts for blog posts
Vibrate
diff --git a/briar-android/res/xml/settings.xml b/briar-android/res/xml/settings.xml
index 92048e8cf..325194258 100644
--- a/briar-android/res/xml/settings.xml
+++ b/briar-android/res/xml/settings.xml
@@ -63,6 +63,12 @@
android:persistent="false"
android:title="@string/notify_private_messages_setting"/>
+
+
contactCounts = new HashMap<>();
+ private final Map groupCounts = new HashMap<>();
private final Map forumCounts = new HashMap<>();
private final Map blogCounts = new HashMap<>();
- private int contactTotal = 0, forumTotal = 0, blogTotal = 0;
+ private int contactTotal = 0, groupTotal = 0, forumTotal = 0, blogTotal = 0;
private int introductionTotal = 0;
private int nextRequestId = 0;
private ContactId blockedContact = null;
private GroupId blockedGroup = null;
- private boolean blockContacts = false, blockForums = false;
- private boolean blockBlogs = false, blockIntroductions = false;
+ private boolean blockContacts = false, blockGroups = false;
+ private boolean blockForums = false, blockBlogs = false;
+ private boolean blockIntroductions = false;
private volatile Settings settings = new Settings();
@@ -144,6 +155,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
public Void call() {
IntentFilter filter = new IntentFilter();
filter.addAction(CLEAR_PRIVATE_MESSAGE_ACTION);
+ filter.addAction(CLEAR_GROUP_ACTION);
filter.addAction(CLEAR_FORUM_ACTION);
filter.addAction(CLEAR_BLOG_ACTION);
filter.addAction(CLEAR_INTRODUCTION_ACTION);
@@ -165,6 +177,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
@Override
public Void call() {
clearContactNotification();
+ clearGroupMessageNotification();
clearForumPostNotification();
clearBlogPostNotification();
clearIntroductionSuccessNotification();
@@ -188,6 +201,15 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
nm.cancel(PRIVATE_MESSAGE_NOTIFICATION_ID);
}
+ @UiThread
+ private void clearGroupMessageNotification() {
+ groupCounts.clear();
+ groupTotal = 0;
+ Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
+ NotificationManager nm = (NotificationManager) o;
+ nm.cancel(GROUP_MESSAGE_NOTIFICATION_ID);
+ }
+
@UiThread
private void clearForumPostNotification() {
forumCounts.clear();
@@ -222,6 +244,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
} else if (e instanceof PrivateMessageReceivedEvent) {
PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
showContactNotification(p.getContactId());
+ } else if (e instanceof GroupMessageAddedEvent) {
+ GroupMessageAddedEvent g = (GroupMessageAddedEvent) e;
+ showGroupMessageNotification(g.getGroupId());
} else if (e instanceof ForumPostReceivedEvent) {
ForumPostReceivedEvent f = (ForumPostReceivedEvent) e;
showForumPostNotification(f.getGroupId());
@@ -367,6 +392,101 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
});
}
+ @UiThread
+ private void showGroupMessageNotification(final GroupId g) {
+ androidExecutor.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (blockGroups) return;
+ if (g.equals(blockedGroup)) return;
+ Integer count = groupCounts.get(g);
+ if (count == null) groupCounts.put(g, 1);
+ else groupCounts.put(g, count + 1);
+ groupTotal++;
+ updateGroupMessageNotification();
+ }
+ });
+ }
+
+ @Override
+ public void clearGroupMessageNotification(final GroupId g) {
+ androidExecutor.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Integer count = groupCounts.remove(g);
+ if (count == null) return; // Already cleared
+ groupTotal -= count;
+ updateGroupMessageNotification();
+ }
+ });
+ }
+
+ @UiThread
+ private void updateGroupMessageNotification() {
+ if (groupTotal == 0) {
+ clearGroupMessageNotification();
+ } else if (settings.getBoolean(PREF_NOTIFY_GROUP, true)) {
+ 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.getResources().getQuantityString(
+ R.plurals.group_message_notification_text, groupTotal,
+ groupTotal));
+ String ringtoneUri = settings.get("notifyRingtoneUri");
+ if (!StringUtils.isNullOrEmpty(ringtoneUri))
+ b.setSound(Uri.parse(ringtoneUri));
+ b.setDefaults(getDefaults());
+ b.setOnlyAlertOnce(true);
+ b.setAutoCancel(true);
+ // Clear the counters if the notification is dismissed
+ Intent clear = new Intent(CLEAR_GROUP_ACTION);
+ PendingIntent delete = PendingIntent.getBroadcast(appContext, 0,
+ clear, 0);
+ b.setDeleteIntent(delete);
+ if (groupCounts.size() == 1) {
+ // Touching the notification shows the relevant group
+ Intent i = new Intent(appContext, GroupActivity.class);
+ GroupId g = groupCounts.keySet().iterator().next();
+ i.putExtra(GROUP_ID, g.getBytes());
+ String idHex = StringUtils.toHexString(g.getBytes());
+ i.setData(Uri.parse(GROUP_URI + "/" + idHex));
+ i.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
+ TaskStackBuilder t = TaskStackBuilder.create(appContext);
+ t.addParentStack(GroupActivity.class);
+ t.addNextIntent(i);
+ b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
+ } else {
+ // Touching the notification shows the group list
+ Intent i = new Intent(appContext, NavDrawerActivity.class);
+ i.putExtra(INTENT_GROUPS, true);
+ i.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
+ i.setData(Uri.parse(GROUP_URI));
+ TaskStackBuilder t = TaskStackBuilder.create(appContext);
+ t.addParentStack(NavDrawerActivity.class);
+ t.addNextIntent(i);
+ b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
+ }
+ if (Build.VERSION.SDK_INT >= 21) {
+ b.setCategory(CATEGORY_SOCIAL);
+ b.setVisibility(VISIBILITY_SECRET);
+ }
+ Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
+ NotificationManager nm = (NotificationManager) o;
+ nm.notify(GROUP_MESSAGE_NOTIFICATION_ID, b.build());
+ }
+ }
+
+ @Override
+ public void clearAllGroupMessageNotifications() {
+ androidExecutor.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ clearGroupMessageNotification();
+ }
+ });
+ }
+
@UiThread
private void showForumPostNotification(final GroupId g) {
androidExecutor.runOnUiThread(new Runnable() {
@@ -654,6 +774,26 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
});
}
+ @Override
+ public void blockAllGroupMessageNotifications() {
+ androidExecutor.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ blockGroups = true;
+ }
+ });
+ }
+
+ @Override
+ public void unblockAllGroupMessageNotifications() {
+ androidExecutor.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ blockGroups = false;
+ }
+ });
+ }
+
@Override
public void blockAllForumPostNotifications() {
androidExecutor.runOnUiThread(new Runnable() {
@@ -704,6 +844,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
public void run() {
if (CLEAR_PRIVATE_MESSAGE_ACTION.equals(action)) {
clearContactNotification();
+ } else if (CLEAR_GROUP_ACTION.equals(action)) {
+ clearGroupMessageNotification();
} else if (CLEAR_FORUM_ACTION.equals(action)) {
clearForumPostNotification();
} else if (CLEAR_BLOG_ACTION.equals(action)) {
diff --git a/briar-android/src/org/briarproject/android/NavDrawerActivity.java b/briar-android/src/org/briarproject/android/NavDrawerActivity.java
index 16b3700cd..cc2fbbcbf 100644
--- a/briar-android/src/org/briarproject/android/NavDrawerActivity.java
+++ b/briar-android/src/org/briarproject/android/NavDrawerActivity.java
@@ -46,6 +46,7 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
OnNavigationItemSelectedListener {
static final String INTENT_CONTACTS = "intent_contacts";
+ static final String INTENT_GROUPS = "intent_groups";
static final String INTENT_FORUMS = "intent_forums";
static final String INTENT_BLOGS = "intent_blogs";
@@ -70,10 +71,10 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
exitIfStartupFailed(intent);
- // FIXME why was the stack cleared here?
- // This prevents state from being restored properly
-// clearBackStack();
- if (intent.getBooleanExtra(INTENT_FORUMS, false)) {
+ // TODO don't create new instances if they are on the stack (#606)
+ if (intent.getBooleanExtra(INTENT_GROUPS, false)) {
+ startFragment(GroupListFragment.newInstance());
+ } else if (intent.getBooleanExtra(INTENT_FORUMS, false)) {
startFragment(ForumListFragment.newInstance());
} else if (intent.getBooleanExtra(INTENT_CONTACTS, false)) {
startFragment(ContactListFragment.newInstance());
diff --git a/briar-android/src/org/briarproject/android/api/AndroidNotificationManager.java b/briar-android/src/org/briarproject/android/api/AndroidNotificationManager.java
index 1140ff573..6a199a0fe 100644
--- a/briar-android/src/org/briarproject/android/api/AndroidNotificationManager.java
+++ b/briar-android/src/org/briarproject/android/api/AndroidNotificationManager.java
@@ -13,6 +13,10 @@ public interface AndroidNotificationManager {
void clearAllContactNotifications();
+ void clearGroupMessageNotification(GroupId g);
+
+ void clearAllGroupMessageNotifications();
+
void clearForumPostNotification(GroupId g);
void clearAllForumPostNotifications();
@@ -33,6 +37,10 @@ public interface AndroidNotificationManager {
void unblockAllContactNotifications();
+ void blockAllGroupMessageNotifications();
+
+ void unblockAllGroupMessageNotifications();
+
void blockAllForumPostNotifications();
void unblockAllForumPostNotifications();
diff --git a/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java b/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java
index a3d655126..60fab261f 100644
--- a/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java
+++ b/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java
@@ -50,6 +50,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
private static final int REQUEST_RINGTONE = 2;
public static final String SETTINGS_NAMESPACE = "android-ui";
+ public static final String PREF_NOTIFY_GROUP = "notifyGroupMessages";
public static final String PREF_NOTIFY_BLOG = "notifyBlogPosts";
private static final Logger LOG =
@@ -60,6 +61,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
private ListPreference enableBluetooth;
private ListPreference torOverMobile;
private CheckBoxPreference notifyPrivateMessages;
+ private CheckBoxPreference notifyGroupMessages;
private CheckBoxPreference notifyForumPosts;
private CheckBoxPreference notifyBlogPosts;
private CheckBoxPreference notifyVibration;
@@ -91,6 +93,8 @@ public class SettingsFragment extends PreferenceFragmentCompat
(ListPreference) findPreference("pref_key_tor_mobile");
notifyPrivateMessages = (CheckBoxPreference) findPreference(
"pref_key_notify_private_messages");
+ notifyGroupMessages = (CheckBoxPreference) findPreference(
+ "pref_key_notify_group_messages");
notifyForumPosts = (CheckBoxPreference) findPreference(
"pref_key_notify_forum_posts");
notifyBlogPosts = (CheckBoxPreference) findPreference(
@@ -102,6 +106,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
enableBluetooth.setOnPreferenceChangeListener(this);
torOverMobile.setOnPreferenceChangeListener(this);
notifyPrivateMessages.setOnPreferenceChangeListener(this);
+ notifyGroupMessages.setOnPreferenceChangeListener(this);
notifyForumPosts.setOnPreferenceChangeListener(this);
notifyBlogPosts.setOnPreferenceChangeListener(this);
notifyVibration.setOnPreferenceChangeListener(this);
@@ -199,6 +204,9 @@ public class SettingsFragment extends PreferenceFragmentCompat
notifyPrivateMessages.setChecked(settings.getBoolean(
"notifyPrivateMessages", true));
+ notifyGroupMessages.setChecked(settings.getBoolean(
+ PREF_NOTIFY_GROUP, true));
+
notifyForumPosts.setChecked(settings.getBoolean(
"notifyForumPosts", true));
@@ -247,6 +255,10 @@ public class SettingsFragment extends PreferenceFragmentCompat
Settings s = new Settings();
s.putBoolean("notifyPrivateMessages", (Boolean) o);
storeSettings(s);
+ } else if (preference == notifyGroupMessages) {
+ Settings s = new Settings();
+ s.putBoolean(PREF_NOTIFY_GROUP, (Boolean) o);
+ storeSettings(s);
} else if (preference == notifyForumPosts) {
Settings s = new Settings();
s.putBoolean("notifyForumPosts", (Boolean) o);
diff --git a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java
index 34ce9768f..8146f200a 100644
--- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java
@@ -59,7 +59,7 @@ public class GroupControllerImpl extends
@Override
public void onActivityStart() {
super.onActivityStart();
- // TODO: Add new notification manager methods for private groups
+ notificationManager.clearGroupMessageNotification(getGroupId());
}
@Override
diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java
index 8be76289f..4524e484b 100644
--- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java
@@ -2,6 +2,7 @@ package org.briarproject.android.privategroup.list;
import android.support.annotation.CallSuper;
+import org.briarproject.android.api.AndroidNotificationManager;
import org.briarproject.android.controller.DbControllerImpl;
import org.briarproject.android.controller.handler.ResultExceptionHandler;
import org.briarproject.api.clients.MessageTracker.GroupCount;
@@ -41,6 +42,7 @@ public class GroupListControllerImpl extends DbControllerImpl
private final PrivateGroupManager groupManager;
private final GroupInvitationManager groupInvitationManager;
+ private final AndroidNotificationManager notificationManager;
private final EventBus eventBus;
protected volatile GroupListListener listener;
@@ -48,10 +50,12 @@ public class GroupListControllerImpl extends DbControllerImpl
@Inject
GroupListControllerImpl(@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager, PrivateGroupManager groupManager,
- GroupInvitationManager groupInvitationManager, EventBus eventBus) {
+ GroupInvitationManager groupInvitationManager,
+ AndroidNotificationManager notificationManager, EventBus eventBus) {
super(dbExecutor, lifecycleManager);
this.groupManager = groupManager;
this.groupInvitationManager = groupInvitationManager;
+ this.notificationManager = notificationManager;
this.eventBus = eventBus;
}
@@ -67,13 +71,15 @@ public class GroupListControllerImpl extends DbControllerImpl
throw new IllegalStateException(
"GroupListListener needs to be attached");
eventBus.addListener(this);
- // TODO: Add new notification manager methods for private groups
+ notificationManager.blockAllGroupMessageNotifications();
+ notificationManager.clearAllGroupMessageNotifications();
}
@Override
@CallSuper
public void onStop() {
eventBus.removeListener(this);
+ notificationManager.unblockAllGroupMessageNotifications();
}
@Override