diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml index cadb8490399fd28f2f684339c455649753cbd899..c43e5aa27c3b6250bdcb4385fc02dbda64c52ea0 100644 --- a/briar-android/src/main/AndroidManifest.xml +++ b/briar-android/src/main/AndroidManifest.xml @@ -32,6 +32,11 @@ </intent-filter> </service> + <service + android:name="org.briarproject.briar.android.NotificationCleanupService" + android:exported="false"> + </service> + <activity android:name="org.briarproject.briar.android.reporting.DevReportActivity" android:excludeFromRecents="true" diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java index 25d553bbeb8fb36a362ebbad1496d8c5db4bc53c..652ef527d4325294c8e9c69eb4ea4877ad501e25 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java @@ -151,6 +151,8 @@ public interface AndroidComponent void inject(RecentEmojiPageModel recentEmojiPageModel); + void inject(NotificationCleanupService notificationCleanupService); + // Eager singleton load void inject(AppModule.EagerSingletons init); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java index 6b4df66c50e0a2c803c92c23ac75836b5ec431e2..329f7b9968433d9a064e12cd81cfd635a66eab86 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java @@ -2,6 +2,7 @@ package org.briarproject.briar.android; import android.app.Application; import android.app.NotificationManager; +import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -83,16 +84,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, 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.briar/contact"; - private static final String GROUP_URI = - "content://org.briarproject.briar/group"; - private static final String FORUM_URI = - "content://org.briarproject.briar/forum"; - private static final String BLOG_URI = - "content://org.briarproject.briar/blog"; - private static final long SOUND_DELAY = TimeUnit.SECONDS.toMillis(2); private static final Logger LOG = @@ -268,7 +259,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, if (count == null) contactCounts.put(c, 1); else contactCounts.put(c, count + 1); contactTotal++; - updateContactNotification(); + updateContactNotification(true); } }); } @@ -281,13 +272,13 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, Integer count = contactCounts.remove(c); if (count == null) return; // Already cleared contactTotal -= count; - updateContactNotification(); + updateContactNotification(false); } }); } @UiThread - private void updateContactNotification() { + private void updateContactNotification(boolean mayAlertAgain) { if (contactTotal == 0) { clearContactNotification(); } else if (settings.getBoolean(PREF_NOTIFY_PRIVATE, true)) { @@ -303,7 +294,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, boolean showOnLockScreen = settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false); b.setLockscreenVisibility(CATEGORY_MESSAGE, showOnLockScreen); - playSound(b); + if (mayAlertAgain) setAlertProperties(b); + setDeleteIntent(b, CONTACT_URI); if (contactCounts.size() == 1) { // Touching the notification shows the relevant conversation Intent i = new Intent(appContext, ConversationActivity.class); @@ -333,17 +325,15 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, } @UiThread - private void playSound(BriarNotificationBuilder b) { - boolean sound = settings.getBoolean(PREF_NOTIFY_SOUND, true); - if (!sound) return; - + private void setAlertProperties(BriarNotificationBuilder b) { long currentTime = clock.currentTimeMillis(); if (currentTime - lastSound > SOUND_DELAY) { + boolean sound = settings.getBoolean(PREF_NOTIFY_SOUND, true); String ringtoneUri = settings.get(PREF_NOTIFY_RINGTONE_URI); - if (!StringUtils.isNullOrEmpty(ringtoneUri)) + if (sound && !StringUtils.isNullOrEmpty(ringtoneUri)) b.setSound(Uri.parse(ringtoneUri)); b.setDefaults(getDefaults()); - lastSound = clock.currentTimeMillis(); + lastSound = currentTime; } } @@ -359,6 +349,23 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, return defaults; } + private void setDeleteIntent(BriarNotificationBuilder b, String uri) { + Intent i = new Intent(appContext, NotificationCleanupService.class); + i.setData(Uri.parse(uri)); + b.setDeleteIntent(PendingIntent.getService(appContext, nextRequestId++, + i, 0)); + } + + @Override + public void clearAllContactNotifications() { + androidExecutor.runOnUiThread(new Runnable() { + @Override + public void run() { + clearContactNotification(); + } + }); + } + @UiThread private void showGroupMessageNotification(final GroupId g) { androidExecutor.runOnUiThread(new Runnable() { @@ -370,7 +377,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, if (count == null) groupCounts.put(g, 1); else groupCounts.put(g, count + 1); groupTotal++; - updateGroupMessageNotification(); + updateGroupMessageNotification(true); } }); } @@ -383,13 +390,13 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, Integer count = groupCounts.remove(g); if (count == null) return; // Already cleared groupTotal -= count; - updateGroupMessageNotification(); + updateGroupMessageNotification(false); } }); } @UiThread - private void updateGroupMessageNotification() { + private void updateGroupMessageNotification(boolean mayAlertAgain) { if (groupTotal == 0) { clearGroupMessageNotification(); } else if (settings.getBoolean(PREF_NOTIFY_GROUP, true)) { @@ -405,7 +412,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, boolean showOnLockScreen = settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false); b.setLockscreenVisibility(CATEGORY_SOCIAL, showOnLockScreen); - playSound(b); + if (mayAlertAgain) setAlertProperties(b); + setDeleteIntent(b, GROUP_URI); if (groupCounts.size() == 1) { // Touching the notification shows the relevant group Intent i = new Intent(appContext, GroupActivity.class); @@ -435,6 +443,16 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, } } + @Override + public void clearAllGroupMessageNotifications() { + androidExecutor.runOnUiThread(new Runnable() { + @Override + public void run() { + clearGroupMessageNotification(); + } + }); + } + @UiThread private void showForumPostNotification(final GroupId g) { androidExecutor.runOnUiThread(new Runnable() { @@ -446,7 +464,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, if (count == null) forumCounts.put(g, 1); else forumCounts.put(g, count + 1); forumTotal++; - updateForumPostNotification(); + updateForumPostNotification(true); } }); } @@ -459,13 +477,13 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, Integer count = forumCounts.remove(g); if (count == null) return; // Already cleared forumTotal -= count; - updateForumPostNotification(); + updateForumPostNotification(false); } }); } @UiThread - private void updateForumPostNotification() { + private void updateForumPostNotification(boolean mayAlertAgain) { if (forumTotal == 0) { clearForumPostNotification(); } else if (settings.getBoolean(PREF_NOTIFY_FORUM, true)) { @@ -481,7 +499,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, boolean showOnLockScreen = settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false); b.setLockscreenVisibility(CATEGORY_SOCIAL, showOnLockScreen); - playSound(b); + if (mayAlertAgain) setAlertProperties(b); + setDeleteIntent(b, FORUM_URI); if (forumCounts.size() == 1) { // Touching the notification shows the relevant forum Intent i = new Intent(appContext, ForumActivity.class); @@ -511,6 +530,16 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, } } + @Override + public void clearAllForumPostNotifications() { + androidExecutor.runOnUiThread(new Runnable() { + @Override + public void run() { + clearForumPostNotification(); + } + }); + } + @UiThread private void showBlogPostNotification(final GroupId g) { androidExecutor.runOnUiThread(new Runnable() { @@ -522,7 +551,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, if (count == null) blogCounts.put(g, 1); else blogCounts.put(g, count + 1); blogTotal++; - updateBlogPostNotification(); + updateBlogPostNotification(true); } }); } @@ -535,13 +564,13 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, Integer count = blogCounts.remove(g); if (count == null) return; // Already cleared blogTotal -= count; - updateBlogPostNotification(); + updateBlogPostNotification(false); } }); } @UiThread - private void updateBlogPostNotification() { + private void updateBlogPostNotification(boolean mayAlertAgain) { if (blogTotal == 0) { clearBlogPostNotification(); } else if (settings.getBoolean(PREF_NOTIFY_BLOG, true)) { @@ -557,7 +586,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, boolean showOnLockScreen = settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false); b.setLockscreenVisibility(CATEGORY_SOCIAL, showOnLockScreen); - playSound(b); + if (mayAlertAgain) setAlertProperties(b); + setDeleteIntent(b, BLOG_URI); // Touching the notification shows the combined blog feed Intent i = new Intent(appContext, NavDrawerActivity.class); i.putExtra(INTENT_BLOGS, true); @@ -607,7 +637,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, boolean showOnLockScreen = settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false); b.setLockscreenVisibility(CATEGORY_MESSAGE, showOnLockScreen); - playSound(b); + setAlertProperties(b); + setDeleteIntent(b, INTRODUCTION_URI); // Touching the notification shows the contact list Intent i = new Intent(appContext, NavDrawerActivity.class); i.putExtra(INTENT_CONTACTS, true); @@ -623,6 +654,16 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, nm.notify(INTRODUCTION_SUCCESS_NOTIFICATION_ID, b.build()); } + @Override + public void clearAllIntroductionNotifications() { + androidExecutor.runOnUiThread(new Runnable() { + @Override + public void run() { + clearIntroductionSuccessNotification(); + } + }); + } + @Override public void blockNotification(final GroupId g) { androidExecutor.runOnUiThread(new Runnable() { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/NotificationCleanupService.java b/briar-android/src/main/java/org/briarproject/briar/android/NotificationCleanupService.java new file mode 100644 index 0000000000000000000000000000000000000000..56d2161114ecb845f5d5e06ae3a20b16b765bf5d --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/NotificationCleanupService.java @@ -0,0 +1,53 @@ +package org.briarproject.briar.android; + +import android.app.IntentService; +import android.content.Intent; +import android.support.annotation.Nullable; + +import org.briarproject.briar.api.android.AndroidNotificationManager; + +import javax.inject.Inject; + +import static org.briarproject.briar.api.android.AndroidNotificationManager.BLOG_URI; +import static org.briarproject.briar.api.android.AndroidNotificationManager.CONTACT_URI; +import static org.briarproject.briar.api.android.AndroidNotificationManager.FORUM_URI; +import static org.briarproject.briar.api.android.AndroidNotificationManager.GROUP_URI; +import static org.briarproject.briar.api.android.AndroidNotificationManager.INTRODUCTION_URI; + +public class NotificationCleanupService extends IntentService { + + private static final String TAG = + NotificationCleanupService.class.getName(); + + @Inject + AndroidNotificationManager notificationManager; + + public NotificationCleanupService() { + super(TAG); + } + + @Override + public void onCreate() { + super.onCreate(); + AndroidComponent applicationComponent = + ((BriarApplication) getApplication()).getApplicationComponent(); + applicationComponent.inject(this); + } + + @Override + protected void onHandleIntent(@Nullable Intent i) { + if (i == null || i.getData() == null) return; + String uri = i.getData().toString(); + if (uri.equals(CONTACT_URI)) { + notificationManager.clearAllContactNotifications(); + } else if (uri.equals(GROUP_URI)) { + notificationManager.clearAllGroupMessageNotifications(); + } else if (uri.equals(FORUM_URI)) { + notificationManager.clearAllForumPostNotifications(); + } else if (uri.equals(BLOG_URI)) { + notificationManager.clearAllBlogPostNotifications(); + } else if (uri.equals(INTRODUCTION_URI)) { + notificationManager.clearAllIntroductionNotifications(); + } + } +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java index d52915fce9e1ea38572f5935c4e0c61e689afb19..0faca234140bf3fdd8de0d2c3e036b0c3d2abefd 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java @@ -179,6 +179,8 @@ public class ContactListFragment extends BaseFragment implements EventListener { public void onStart() { super.onStart(); eventBus.addListener(this); + notificationManager.clearAllContactNotifications(); + notificationManager.clearAllIntroductionNotifications(); loadContacts(); list.startPeriodicUpdate(); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumListFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumListFragment.java index 4873684ccb579a10d9f23aaace5851dcbf42853f..a1d88d884541bc8a4e43454020e918586fc9a8b4 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumListFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumListFragment.java @@ -119,6 +119,7 @@ public class ForumListFragment extends BaseEventFragment implements @Override public void onStart() { super.onStart(); + notificationManager.clearAllForumPostNotifications(); loadForums(); loadAvailableForums(); list.startPeriodicUpdate(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/list/GroupListControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/list/GroupListControllerImpl.java index 6cde4e9552a4a99320a6bc73c3a426a1f1b0bb59..cbe85631eba1c57ae514aae84b66c7ec0eda04c8 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/list/GroupListControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/list/GroupListControllerImpl.java @@ -79,6 +79,7 @@ class GroupListControllerImpl extends DbControllerImpl throw new IllegalStateException( "GroupListListener needs to be attached"); eventBus.addListener(this); + notificationManager.clearAllGroupMessageNotifications(); } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/BriarNotificationBuilder.java b/briar-android/src/main/java/org/briarproject/briar/android/util/BriarNotificationBuilder.java index 76fab9de4b37a84f902f179d050cad377f1fed12..73c50d8dd901985d7cd49108c0c8e23300cbcfd7 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/util/BriarNotificationBuilder.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/util/BriarNotificationBuilder.java @@ -6,7 +6,6 @@ import android.support.annotation.ColorRes; import android.support.v4.content.ContextCompat; import android.support.v7.app.NotificationCompat; -import static android.support.v4.app.NotificationCompat.CATEGORY_MESSAGE; import static android.support.v4.app.NotificationCompat.VISIBILITY_PRIVATE; import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET; @@ -15,6 +14,8 @@ public class BriarNotificationBuilder extends NotificationCompat.Builder { public BriarNotificationBuilder(Context context) { super(context); + // Auto-cancel does not fire the delete intent, see + // https://issuetracker.google.com/issues/36961721 setAutoCancel(true); } @@ -27,10 +28,8 @@ public class BriarNotificationBuilder extends NotificationCompat.Builder { boolean show) { if (Build.VERSION.SDK_INT >= 21) { setCategory(category); - if (show) - setVisibility(VISIBILITY_PRIVATE); - else - setVisibility(VISIBILITY_SECRET); + if (show) setVisibility(VISIBILITY_PRIVATE); + else setVisibility(VISIBILITY_SECRET); } return this; } diff --git a/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java b/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java index 167ee816b49a5805451577468dcab3d436b660f9..d95d258da2bc76c59708998fad708dae82158503 100644 --- a/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java +++ b/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java @@ -9,6 +9,7 @@ import org.briarproject.bramble.api.sync.GroupId; */ public interface AndroidNotificationManager { + // Keys for notification preferences String PREF_NOTIFY_PRIVATE = "notifyPrivateMessages"; String PREF_NOTIFY_GROUP = "notifyGroupMessages"; String PREF_NOTIFY_FORUM = "notifyForumPosts"; @@ -20,16 +21,31 @@ public interface AndroidNotificationManager { String PREF_NOTIFY_VIBRATION = "notifyVibration"; String PREF_NOTIFY_LOCK_SCREEN = "notifyLockScreen"; + // Content URIs for pending intents + String CONTACT_URI = "content://org.briarproject.briar/contact"; + String GROUP_URI = "content://org.briarproject.briar/group"; + String FORUM_URI = "content://org.briarproject.briar/forum"; + String BLOG_URI = "content://org.briarproject.briar/blog"; + String INTRODUCTION_URI = "content://org.briarproject.briar/introduction"; + void clearContactNotification(ContactId c); + void clearAllContactNotifications(); + void clearGroupMessageNotification(GroupId g); + void clearAllGroupMessageNotifications(); + void clearForumPostNotification(GroupId g); + void clearAllForumPostNotifications(); + void clearBlogPostNotification(GroupId g); void clearAllBlogPostNotifications(); + void clearAllIntroductionNotifications(); + void blockContactNotification(ContactId c); void unblockContactNotification(ContactId c);