Merge branch '734-notifications-for-private-group-messages' into 'master'

Show Notifications for Group Messages

Closes #734

See merge request !391
This commit is contained in:
akwizgran
2016-11-08 12:06:15 +00:00
8 changed files with 193 additions and 13 deletions

View File

@@ -52,6 +52,10 @@
<item quantity="one">New private message.</item>
<item quantity="other">%d new private messages.</item>
</plurals>
<plurals name="group_message_notification_text">
<item quantity="one">New group message.</item>
<item quantity="other">%d new group messages.</item>
</plurals>
<plurals name="forum_post_notification_text">
<item quantity="one">New forum post.</item>
<item quantity="other">%d new forum posts.</item>
@@ -328,6 +332,7 @@
<!-- Settings Notifications -->
<string name="notification_settings_title">Notifications</string>
<string name="notify_private_messages_setting">Show alerts for private messages</string>
<string name="notify_group_messages_setting">Show alerts for group messages</string>
<string name="notify_forum_posts_setting">Show alerts for forum posts</string>
<string name="notify_blog_posts_setting">Show alerts for blog posts</string>
<string name="notify_vibration_setting">Vibrate</string>

View File

@@ -63,6 +63,12 @@
android:persistent="false"
android:title="@string/notify_private_messages_setting"/>
<CheckBoxPreference
android:defaultValue="true"
android:key="pref_key_notify_group_messages"
android:persistent="false"
android:title="@string/notify_group_messages_setting"/>
<CheckBoxPreference
android:defaultValue="true"
android:key="pref_key_notify_forum_posts"

View File

@@ -18,6 +18,7 @@ import org.briarproject.android.api.AndroidExecutor;
import org.briarproject.android.api.AndroidNotificationManager;
import org.briarproject.android.contact.ConversationActivity;
import org.briarproject.android.forum.ForumActivity;
import org.briarproject.android.privategroup.conversation.GroupActivity;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DatabaseExecutor;
import org.briarproject.api.db.DbException;
@@ -25,6 +26,7 @@ import org.briarproject.api.event.BlogPostAddedEvent;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.ForumPostReceivedEvent;
import org.briarproject.api.event.GroupMessageAddedEvent;
import org.briarproject.api.event.IntroductionRequestReceivedEvent;
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
import org.briarproject.api.event.IntroductionSucceededEvent;
@@ -64,8 +66,10 @@ import static org.briarproject.android.BriarActivity.GROUP_ID;
import static org.briarproject.android.NavDrawerActivity.INTENT_BLOGS;
import static org.briarproject.android.NavDrawerActivity.INTENT_CONTACTS;
import static org.briarproject.android.NavDrawerActivity.INTENT_FORUMS;
import static org.briarproject.android.NavDrawerActivity.INTENT_GROUPS;
import static org.briarproject.android.contact.ConversationActivity.CONTACT_ID;
import static org.briarproject.android.fragment.SettingsFragment.PREF_NOTIFY_BLOG;
import static org.briarproject.android.fragment.SettingsFragment.PREF_NOTIFY_GROUP;
import static org.briarproject.android.fragment.SettingsFragment.SETTINGS_NAMESPACE;
class AndroidNotificationManagerImpl implements AndroidNotificationManager,
@@ -73,13 +77,16 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
// Notification IDs
private static final int PRIVATE_MESSAGE_NOTIFICATION_ID = 3;
private static final int FORUM_POST_NOTIFICATION_ID = 4;
private static final int BLOG_POST_NOTIFICATION_ID = 5;
private static final int INTRODUCTION_SUCCESS_NOTIFICATION_ID = 6;
private static final int GROUP_MESSAGE_NOTIFICATION_ID = 4;
private static final int FORUM_POST_NOTIFICATION_ID = 5;
private static final int BLOG_POST_NOTIFICATION_ID = 6;
private static final int INTRODUCTION_SUCCESS_NOTIFICATION_ID = 7;
// Content URIs to differentiate between pending intents
private static final String CONTACT_URI =
"content://org.briarproject/contact";
private static final String GROUP_URI =
"content://org.briarproject/group";
private static final String FORUM_URI =
"content://org.briarproject/forum";
private static final String BLOG_URI =
@@ -88,6 +95,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
// Actions for intents that are broadcast when notifications are dismissed
private static final String CLEAR_PRIVATE_MESSAGE_ACTION =
"org.briarproject.briar.CLEAR_PRIVATE_MESSAGE_NOTIFICATION";
private static final String CLEAR_GROUP_ACTION =
"org.briarproject.briar.CLEAR_GROUP_NOTIFICATION";
private static final String CLEAR_FORUM_ACTION =
"org.briarproject.briar.CLEAR_FORUM_NOTIFICATION";
private static final String CLEAR_BLOG_ACTION =
@@ -107,15 +116,17 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
// The following must only be accessed on the main UI thread
private final Map<ContactId, Integer> contactCounts = new HashMap<>();
private final Map<GroupId, Integer> groupCounts = new HashMap<>();
private final Map<GroupId, Integer> forumCounts = new HashMap<>();
private final Map<GroupId, Integer> 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)) {

View File

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

View File

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

View File

@@ -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);

View File

@@ -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

View File

@@ -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