mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-30 13:35:18 +00:00
Support for bundled notifications (Android wear and Android N)
// FREEBIE
This commit is contained in:
parent
0c6bfdbd0d
commit
a9bd84c69c
@ -454,7 +454,7 @@
|
|||||||
|
|
||||||
<receiver android:name=".notifications.MarkReadReceiver"
|
<receiver android:name=".notifications.MarkReadReceiver"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true">
|
android:exported="false">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="org.thoughtcrime.securesms.notifications.CLEAR"/>
|
<action android:name="org.thoughtcrime.securesms.notifications.CLEAR"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
37
build.gradle
37
build.gradle
@ -53,10 +53,10 @@ dependencies {
|
|||||||
compile 'de.greenrobot:eventbus:2.4.0'
|
compile 'de.greenrobot:eventbus:2.4.0'
|
||||||
compile 'pl.tajchert:waitingdots:0.1.0'
|
compile 'pl.tajchert:waitingdots:0.1.0'
|
||||||
compile 'com.soundcloud.android:android-crop:0.9.10@aar'
|
compile 'com.soundcloud.android:android-crop:0.9.10@aar'
|
||||||
compile 'com.android.support:appcompat-v7:24.2.1'
|
compile 'com.android.support:appcompat-v7:25.0.1'
|
||||||
compile 'com.android.support:recyclerview-v7:24.2.1'
|
compile 'com.android.support:recyclerview-v7:25.0.1'
|
||||||
compile 'com.android.support:design:24.2.1'
|
compile 'com.android.support:design:25.0.1'
|
||||||
compile 'com.android.support:cardview-v7:24.2.1'
|
compile 'com.android.support:cardview-v7:25.0.1'
|
||||||
compile 'com.melnykov:floatingactionbutton:1.3.0'
|
compile 'com.melnykov:floatingactionbutton:1.3.0'
|
||||||
compile 'com.google.zxing:android-integration:3.1.0'
|
compile 'com.google.zxing:android-integration:3.1.0'
|
||||||
compile ('com.android.support:support-v4-preferencefragment:1.0.0@aar'){
|
compile ('com.android.support:support-v4-preferencefragment:1.0.0@aar'){
|
||||||
@ -120,10 +120,10 @@ dependencyVerification {
|
|||||||
'de.greenrobot:eventbus:61d743a748156a372024d083de763b9e91ac2dcb3f6a1cbc74995c7ddab6e968',
|
'de.greenrobot:eventbus:61d743a748156a372024d083de763b9e91ac2dcb3f6a1cbc74995c7ddab6e968',
|
||||||
'pl.tajchert:waitingdots:2835d49e0787dbcb606c5a60021ced66578503b1e9fddcd7a5ef0cd5f095ba2c',
|
'pl.tajchert:waitingdots:2835d49e0787dbcb606c5a60021ced66578503b1e9fddcd7a5ef0cd5f095ba2c',
|
||||||
'com.soundcloud.android:android-crop:ffd4b973cf6e97f7d64118a0dc088df50e9066fd5634fe6911dd0c0c5d346177',
|
'com.soundcloud.android:android-crop:ffd4b973cf6e97f7d64118a0dc088df50e9066fd5634fe6911dd0c0c5d346177',
|
||||||
'com.android.support:appcompat-v7:ead7ac8011fb40676df8adc2856cae934edab55fc4444654c0ac6ea443736088',
|
'com.android.support:appcompat-v7:7fead560a22ea4b15848ce3000f312ef611fac0953bf90ca8710a72a1f6e36ea',
|
||||||
'com.android.support:recyclerview-v7:9077766a1a0f4e89528fbf9dcdf6d5880a8686f0266fa852d58d803beeef18fa',
|
'com.android.support:recyclerview-v7:803baba7be537ace8c5cb8a775e37547c22a04c4b028833796c45c26ec1deca2',
|
||||||
'com.android.support:design:89842bb1243507fe3079066ea4ea58795effe69cdf9a819e05274d21760adfc2',
|
'com.android.support:design:07a72eb68c888b38d7b78e450e1af8a84e571406e0cf911889e0645d5a41f1e4',
|
||||||
'com.android.support:cardview-v7:2303b351686d1db060b5fcf1a9c709c79b4a54a85bfda0fb3c4849e244606ee1',
|
'com.android.support:cardview-v7:50d88fae8cd1076cb90504d36ca5ee9df4018555c8f041bd28f43274c0fc9e1f',
|
||||||
'com.melnykov:floatingactionbutton:15d58d4fac0f7a288d0e5301bbaf501a146f5b3f5921277811bf99bd3b397263',
|
'com.melnykov:floatingactionbutton:15d58d4fac0f7a288d0e5301bbaf501a146f5b3f5921277811bf99bd3b397263',
|
||||||
'com.google.zxing:android-integration:89e56aadf1164bd71e57949163c53abf90af368b51669c0d4a47a163335f95c4',
|
'com.google.zxing:android-integration:89e56aadf1164bd71e57949163c53abf90af368b51669c0d4a47a163335f95c4',
|
||||||
'com.android.support:support-v4-preferencefragment:5470f5872514a6226fa1fc6f4e000991f38805691c534cf0bd2778911fc773ad',
|
'com.android.support:support-v4-preferencefragment:5470f5872514a6226fa1fc6f4e000991f38805691c534cf0bd2778911fc773ad',
|
||||||
@ -139,9 +139,10 @@ dependencyVerification {
|
|||||||
'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259',
|
'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259',
|
||||||
'cn.carbswang.android:NumberPickerView:18b3c316d62c7c277978a8d4ed57a5b8f4e943762264960f579a8a549c756729',
|
'cn.carbswang.android:NumberPickerView:18b3c316d62c7c277978a8d4ed57a5b8f4e943762264960f579a8a549c756729',
|
||||||
'com.google.android.gms:play-services-base:ef36e50fa5c0415ed41f74dd399a889efd2fa327c449036e140c7c3786aa0e1f',
|
'com.google.android.gms:play-services-base:ef36e50fa5c0415ed41f74dd399a889efd2fa327c449036e140c7c3786aa0e1f',
|
||||||
'com.android.support:support-annotations:1e4d471c5378b283d95abfb128e7ed3c6b3cb19bb6f0c317a9b75e48e99365ff',
|
'com.android.support:support-annotations:bd94ab42c841db16fb480f4c65d33d297e544655ecc498b37c5cf33a0c5f1968',
|
||||||
'com.android.support:support-compat:8e4fe0078b68073e8f5bcb52aa5b6407fd456d47c51aa0f8e8d1e23c69da06c1',
|
'com.android.support:support-compat:d04f15aa5f2ae9e8cb7d025bf02dfd4fd6f6800628ceb107e0589634c9e4e537',
|
||||||
'com.android.support:support-core-ui:ecc9184b7f438980e1c4a08b089d62dbc53ff90091f442d91fec27322a02c73c',
|
'com.android.support:support-core-ui:29205ac978a1839d92be3d32db2385dac10f8688bba649e51650023c76de2f00',
|
||||||
|
'com.android.support:transition:9fd1e6d27cb70b3c5cd19f842b48bbb05cb4e5c93a22372769c342523393e8ea',
|
||||||
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
|
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
|
||||||
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||||
'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f',
|
'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f',
|
||||||
@ -158,18 +159,18 @@ dependencyVerification {
|
|||||||
'com.squareup.okio:okio:5e1098bd3fdee4c3347f5ab815b40ba851e4ab1b348c5e49a5b0362f0ce6e978',
|
'com.squareup.okio:okio:5e1098bd3fdee4c3347f5ab815b40ba851e4ab1b348c5e49a5b0362f0ce6e978',
|
||||||
'com.fasterxml.jackson.core:jackson-annotations:0ca408c24202a7626ec8b861e99d85eca5e38b73311dd6dd12e3e9deecc3fe94',
|
'com.fasterxml.jackson.core:jackson-annotations:0ca408c24202a7626ec8b861e99d85eca5e38b73311dd6dd12e3e9deecc3fe94',
|
||||||
'com.fasterxml.jackson.core:jackson-core:cbf4604784b4de226262845447a1ad3bb38a6728cebe86562e2c5afada8be2c0',
|
'com.fasterxml.jackson.core:jackson-core:cbf4604784b4de226262845447a1ad3bb38a6728cebe86562e2c5afada8be2c0',
|
||||||
'com.android.support:support-vector-drawable:6ee37a7f7b93c1df1294e6f6f97df3724ac989fcda0549faf677001085330548',
|
'com.android.support:support-vector-drawable:071ae3695bf8427d3cbfc8791492a3d9c804a4b111aa2a72fbfe7790ea268e5d',
|
||||||
'com.android.support:animated-vector-drawable:5aa30f578e1daefb26bef0ce06414266fbb4cdf5d4259f42a92c7bd83dcd81b4',
|
'com.android.support:animated-vector-drawable:70443a2857f9968c4e2c27c107657ce2291d774f8a50f03444e12ab637451175',
|
||||||
'com.android.support:support-v4:cac2956f5c4bb363cc0ba824ac16ea2a687d1c305d434416a34772a5f9375ed7',
|
'com.android.support:support-v4:50da261acc4ca3d2dea9a43106bf65488711ca97b20a4daa095dba381c205c98',
|
||||||
'com.android.support:support-media-compat:fa29a23eadd685631584b2c0c624a36e3bb79a33e257b00304501ad682fa2be3',
|
'com.android.support:support-media-compat:01cac57af687bed9a6cb4ce803bebd1b7e6b8469c14f1f9ac6b4596637ff73d6',
|
||||||
'com.android.support:support-core-utils:0fbc508e41dd6e8c634f310ee88452aaf8f48b6a843a369b115130b80d2fc05f',
|
'com.android.support:support-core-utils:632c3750bd991da8b591f24a8916e74ca6063ae7f525f005c96981725c9bf491',
|
||||||
'com.android.support:support-fragment:d8030f0bf0f64214a29dc4e14d5ccd225e59f66ed15eb37f3a5022e773dd1fda',
|
'com.android.support:support-fragment:da47261a1d7c3d33e6e911335a7f4ce01135923bb221d3ab84625d005fa1969f',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 24
|
compileSdkVersion 25
|
||||||
buildToolsVersion '23.0.3'
|
buildToolsVersion '23.0.3'
|
||||||
useLibrary 'org.apache.http.legacy'
|
useLibrary 'org.apache.http.legacy'
|
||||||
|
|
||||||
|
@ -36,8 +36,7 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
|||||||
|
|
||||||
public class NotificationBarManager {
|
public class NotificationBarManager {
|
||||||
|
|
||||||
private static final int RED_PHONE_NOTIFICATION = 313388;
|
public static final int RED_PHONE_NOTIFICATION = 313388;
|
||||||
private static final int MISSED_CALL_NOTIFICATION = 313389;
|
|
||||||
|
|
||||||
public static final int TYPE_INCOMING_RINGING = 1;
|
public static final int TYPE_INCOMING_RINGING = 1;
|
||||||
public static final int TYPE_OUTGOING_RINGING = 2;
|
public static final int TYPE_OUTGOING_RINGING = 2;
|
||||||
|
@ -17,18 +17,15 @@
|
|||||||
|
|
||||||
package org.thoughtcrime.securesms.notifications;
|
package org.thoughtcrime.securesms.notifications;
|
||||||
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.app.NotificationManagerCompat;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob;
|
|
||||||
import org.whispersystems.libsignal.logging.Log;
|
import org.whispersystems.libsignal.logging.Log;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -39,9 +36,10 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class AndroidAutoHeardReceiver extends MasterSecretBroadcastReceiver {
|
public class AndroidAutoHeardReceiver extends MasterSecretBroadcastReceiver {
|
||||||
|
|
||||||
public static final String TAG = AndroidAutoHeardReceiver.class.getSimpleName();
|
public static final String TAG = AndroidAutoHeardReceiver.class.getSimpleName();
|
||||||
public static final String HEARD_ACTION = "org.thoughtcrime.securesms.notifications.ANDROID_AUTO_HEARD";
|
public static final String HEARD_ACTION = "org.thoughtcrime.securesms.notifications.ANDROID_AUTO_HEARD";
|
||||||
public static final String THREAD_IDS_EXTRA = "car_heard_thread_ids";
|
public static final String THREAD_IDS_EXTRA = "car_heard_thread_ids";
|
||||||
|
public static final String NOTIFICATION_ID_EXTRA = "car_notification_id";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onReceive(final Context context, Intent intent,
|
protected void onReceive(final Context context, Intent intent,
|
||||||
@ -53,8 +51,8 @@ public class AndroidAutoHeardReceiver extends MasterSecretBroadcastReceiver {
|
|||||||
final long[] threadIds = intent.getLongArrayExtra(THREAD_IDS_EXTRA);
|
final long[] threadIds = intent.getLongArrayExtra(THREAD_IDS_EXTRA);
|
||||||
|
|
||||||
if (threadIds != null) {
|
if (threadIds != null) {
|
||||||
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
|
int notificationId = intent.getIntExtra(NOTIFICATION_ID_EXTRA, -1);
|
||||||
.cancel(MessageNotifier.NOTIFICATION_ID);
|
NotificationManagerCompat.from(context).cancel(notificationId);
|
||||||
|
|
||||||
new AsyncTask<Void, Void, Void>() {
|
new AsyncTask<Void, Void, Void>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
package org.thoughtcrime.securesms.notifications;
|
package org.thoughtcrime.securesms.notifications;
|
||||||
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.v4.app.NotificationManagerCompat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.ExpirationInfo;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.ExpirationInfo;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||||
@ -24,9 +22,10 @@ import java.util.List;
|
|||||||
|
|
||||||
public class MarkReadReceiver extends MasterSecretBroadcastReceiver {
|
public class MarkReadReceiver extends MasterSecretBroadcastReceiver {
|
||||||
|
|
||||||
private static final String TAG = MarkReadReceiver.class.getSimpleName();
|
private static final String TAG = MarkReadReceiver.class.getSimpleName();
|
||||||
public static final String CLEAR_ACTION = "org.thoughtcrime.securesms.notifications.CLEAR";
|
public static final String CLEAR_ACTION = "org.thoughtcrime.securesms.notifications.CLEAR";
|
||||||
public static final String THREAD_IDS_EXTRA = "thread_ids";
|
public static final String THREAD_IDS_EXTRA = "thread_ids";
|
||||||
|
public static final String NOTIFICATION_ID_EXTRA = "notification_id";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onReceive(final Context context, Intent intent, @Nullable final MasterSecret masterSecret)
|
protected void onReceive(final Context context, Intent intent, @Nullable final MasterSecret masterSecret)
|
||||||
@ -37,10 +36,7 @@ public class MarkReadReceiver extends MasterSecretBroadcastReceiver {
|
|||||||
final long[] threadIds = intent.getLongArrayExtra(THREAD_IDS_EXTRA);
|
final long[] threadIds = intent.getLongArrayExtra(THREAD_IDS_EXTRA);
|
||||||
|
|
||||||
if (threadIds != null) {
|
if (threadIds != null) {
|
||||||
Log.w("TAG", "threadIds length: " + threadIds.length);
|
NotificationManagerCompat.from(context).cancel(intent.getIntExtra(NOTIFICATION_ID_EXTRA, -1));
|
||||||
|
|
||||||
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
|
|
||||||
.cancel(MessageNotifier.NOTIFICATION_ID);
|
|
||||||
|
|
||||||
new AsyncTask<Void, Void, Void>() {
|
new AsyncTask<Void, Void, Void>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -30,14 +30,17 @@ import android.media.RingtoneManager;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.service.notification.StatusBarNotification;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.app.NotificationManagerCompat;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.thoughtcrime.redphone.ui.NotificationBarManager;
|
||||||
import org.thoughtcrime.redphone.util.Util;
|
import org.thoughtcrime.redphone.util.Util;
|
||||||
import org.thoughtcrime.securesms.ConversationActivity;
|
import org.thoughtcrime.securesms.ConversationActivity;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
@ -84,7 +87,9 @@ public class MessageNotifier {
|
|||||||
private static final String TAG = MessageNotifier.class.getSimpleName();
|
private static final String TAG = MessageNotifier.class.getSimpleName();
|
||||||
|
|
||||||
public static final String EXTRA_VOICE_REPLY = "extra_voice_reply";
|
public static final String EXTRA_VOICE_REPLY = "extra_voice_reply";
|
||||||
public static final int NOTIFICATION_ID = 1338;
|
|
||||||
|
private static final int SUMMARY_NOTIFICATION_ID = 1338;
|
||||||
|
private static final String NOTIFICATION_GROUP = "messages";
|
||||||
private static final long MIN_AUDIBLE_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(2);
|
private static final long MIN_AUDIBLE_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(2);
|
||||||
private static final long DESKTOP_ACTIVITY_PERIOD = TimeUnit.MINUTES.toMillis(1);
|
private static final long DESKTOP_ACTIVITY_PERIOD = TimeUnit.MINUTES.toMillis(1);
|
||||||
|
|
||||||
@ -101,10 +106,6 @@ public class MessageNotifier {
|
|||||||
lastDesktopActivityTimestamp = timestamp;
|
lastDesktopActivityTimestamp = timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void cancelDelayedNotifications() {
|
|
||||||
executor.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void notifyMessageDeliveryFailed(Context context, Recipients recipients, long threadId) {
|
public static void notifyMessageDeliveryFailed(Context context, Recipients recipients, long threadId) {
|
||||||
if (visibleThread == threadId) {
|
if (visibleThread == threadId) {
|
||||||
sendInThreadNotification(context, recipients);
|
sendInThreadNotification(context, recipients);
|
||||||
@ -120,6 +121,49 @@ public class MessageNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void cancelDelayedNotifications() {
|
||||||
|
executor.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void cancelActiveNotifications(@NonNull Context context) {
|
||||||
|
NotificationManager notifications = ServiceUtil.getNotificationManager(context);
|
||||||
|
notifications.cancel(SUMMARY_NOTIFICATION_ID);
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= 23) {
|
||||||
|
StatusBarNotification[] activeNotifications = notifications.getActiveNotifications();
|
||||||
|
|
||||||
|
for (StatusBarNotification activeNotification : activeNotifications) {
|
||||||
|
if (activeNotification.getId() != NotificationBarManager.RED_PHONE_NOTIFICATION) {
|
||||||
|
notifications.cancel(activeNotification.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void cancelOrphanedNotifications(@NonNull Context context, NotificationState notificationState) {
|
||||||
|
if (Build.VERSION.SDK_INT >= 23) {
|
||||||
|
NotificationManager notifications = ServiceUtil.getNotificationManager(context);
|
||||||
|
StatusBarNotification[] activeNotifications = notifications.getActiveNotifications();
|
||||||
|
|
||||||
|
for (StatusBarNotification notification : activeNotifications) {
|
||||||
|
boolean validNotification = false;
|
||||||
|
|
||||||
|
if (notification.getId() != SUMMARY_NOTIFICATION_ID && notification.getId() != NotificationBarManager.RED_PHONE_NOTIFICATION) {
|
||||||
|
for (NotificationItem item : notificationState.getNotifications()) {
|
||||||
|
if (notification.getId() == (SUMMARY_NOTIFICATION_ID + item.getThreadId())) {
|
||||||
|
validNotification = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validNotification) {
|
||||||
|
notifications.cancel(notification.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void updateNotification(@NonNull Context context, @Nullable MasterSecret masterSecret) {
|
public static void updateNotification(@NonNull Context context, @Nullable MasterSecret masterSecret) {
|
||||||
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
||||||
return;
|
return;
|
||||||
@ -194,8 +238,7 @@ public class MessageNotifier {
|
|||||||
if ((telcoCursor == null || telcoCursor.isAfterLast()) &&
|
if ((telcoCursor == null || telcoCursor.isAfterLast()) &&
|
||||||
(pushCursor == null || pushCursor.isAfterLast()))
|
(pushCursor == null || pushCursor.isAfterLast()))
|
||||||
{
|
{
|
||||||
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
|
cancelActiveNotifications(context);
|
||||||
.cancel(NOTIFICATION_ID);
|
|
||||||
updateBadge(context, 0);
|
updateBadge(context, 0);
|
||||||
clearReminder(context);
|
clearReminder(context);
|
||||||
return;
|
return;
|
||||||
@ -214,11 +257,18 @@ public class MessageNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (notificationState.hasMultipleThreads()) {
|
if (notificationState.hasMultipleThreads()) {
|
||||||
|
if (Build.VERSION.SDK_INT >= 23) {
|
||||||
|
for (long threadId : notificationState.getThreads()) {
|
||||||
|
sendSingleThreadNotification(context, masterSecret, new NotificationState(notificationState.getNotificationsForThread(threadId)), false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sendMultipleThreadNotification(context, notificationState, signal);
|
sendMultipleThreadNotification(context, notificationState, signal);
|
||||||
} else {
|
} else {
|
||||||
sendSingleThreadNotification(context, masterSecret, notificationState, signal);
|
sendSingleThreadNotification(context, masterSecret, notificationState, signal, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cancelOrphanedNotifications(context, notificationState);
|
||||||
updateBadge(context, notificationState.getMessageCount());
|
updateBadge(context, notificationState.getMessageCount());
|
||||||
|
|
||||||
if (signal) {
|
if (signal) {
|
||||||
@ -233,33 +283,35 @@ public class MessageNotifier {
|
|||||||
private static void sendSingleThreadNotification(@NonNull Context context,
|
private static void sendSingleThreadNotification(@NonNull Context context,
|
||||||
@Nullable MasterSecret masterSecret,
|
@Nullable MasterSecret masterSecret,
|
||||||
@NonNull NotificationState notificationState,
|
@NonNull NotificationState notificationState,
|
||||||
boolean signal)
|
boolean signal, boolean bundled)
|
||||||
{
|
{
|
||||||
if (notificationState.getNotifications().isEmpty()) {
|
if (notificationState.getNotifications().isEmpty()) {
|
||||||
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
|
if (!bundled) cancelActiveNotifications(context);
|
||||||
.cancel(NOTIFICATION_ID);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SingleRecipientNotificationBuilder builder = new SingleRecipientNotificationBuilder(context, masterSecret, TextSecurePreferences.getNotificationPrivacy(context));
|
SingleRecipientNotificationBuilder builder = new SingleRecipientNotificationBuilder(context, masterSecret, TextSecurePreferences.getNotificationPrivacy(context));
|
||||||
List<NotificationItem> notifications = notificationState.getNotifications();
|
List<NotificationItem> notifications = notificationState.getNotifications();
|
||||||
Recipients recipients = notifications.get(0).getRecipients();
|
Recipients recipients = notifications.get(0).getRecipients();
|
||||||
|
int notificationId = (int) (SUMMARY_NOTIFICATION_ID + (bundled ? notifications.get(0).getThreadId() : 0));
|
||||||
|
|
||||||
|
|
||||||
builder.setThread(notifications.get(0).getRecipients());
|
builder.setThread(notifications.get(0).getRecipients());
|
||||||
builder.setMessageCount(notificationState.getMessageCount());
|
builder.setMessageCount(notificationState.getMessageCount());
|
||||||
builder.setPrimaryMessageBody(recipients, notifications.get(0).getIndividualRecipient(),
|
builder.setPrimaryMessageBody(recipients, notifications.get(0).getIndividualRecipient(),
|
||||||
notifications.get(0).getText(), notifications.get(0).getSlideDeck());
|
notifications.get(0).getText(), notifications.get(0).getSlideDeck());
|
||||||
builder.setContentIntent(notifications.get(0).getPendingIntent(context));
|
builder.setContentIntent(notifications.get(0).getPendingIntent(context));
|
||||||
|
builder.setGroup(NOTIFICATION_GROUP);
|
||||||
|
|
||||||
long timestamp = notifications.get(0).getTimestamp();
|
long timestamp = notifications.get(0).getTimestamp();
|
||||||
if (timestamp != 0) builder.setWhen(timestamp);
|
if (timestamp != 0) builder.setWhen(timestamp);
|
||||||
|
|
||||||
builder.addActions(masterSecret,
|
builder.addActions(masterSecret,
|
||||||
notificationState.getMarkAsReadIntent(context),
|
notificationState.getMarkAsReadIntent(context, notificationId),
|
||||||
notificationState.getQuickReplyIntent(context, notifications.get(0).getRecipients()),
|
notificationState.getQuickReplyIntent(context, notifications.get(0).getRecipients()),
|
||||||
notificationState.getWearableReplyIntent(context, notifications.get(0).getRecipients()));
|
notificationState.getWearableReplyIntent(context, notifications.get(0).getRecipients()));
|
||||||
builder.addAndroidAutoAction(notificationState.getAndroidAutoReplyIntent(context, notifications.get(0).getRecipients()),
|
builder.addAndroidAutoAction(notificationState.getAndroidAutoReplyIntent(context, notifications.get(0).getRecipients()),
|
||||||
notificationState.getAndroidAutoHeardIntent(context, notifications.get(0).getRecipients()), notifications.get(0).getTimestamp());
|
notificationState.getAndroidAutoHeardIntent(context, notificationId), notifications.get(0).getTimestamp());
|
||||||
|
|
||||||
ListIterator<NotificationItem> iterator = notifications.listIterator(notifications.size());
|
ListIterator<NotificationItem> iterator = notifications.listIterator(notifications.size());
|
||||||
|
|
||||||
@ -274,8 +326,11 @@ public class MessageNotifier {
|
|||||||
notifications.get(0).getText());
|
notifications.get(0).getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
|
if (!bundled) {
|
||||||
.notify(NOTIFICATION_ID, builder.build());
|
builder.setGroupSummary(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationManagerCompat.from(context).notify(notificationId, builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sendMultipleThreadNotification(@NonNull Context context,
|
private static void sendMultipleThreadNotification(@NonNull Context context,
|
||||||
@ -287,11 +342,12 @@ public class MessageNotifier {
|
|||||||
|
|
||||||
builder.setMessageCount(notificationState.getMessageCount(), notificationState.getThreadCount());
|
builder.setMessageCount(notificationState.getMessageCount(), notificationState.getThreadCount());
|
||||||
builder.setMostRecentSender(notifications.get(0).getIndividualRecipient());
|
builder.setMostRecentSender(notifications.get(0).getIndividualRecipient());
|
||||||
|
builder.setGroup(NOTIFICATION_GROUP);
|
||||||
|
|
||||||
long timestamp = notifications.get(0).getTimestamp();
|
long timestamp = notifications.get(0).getTimestamp();
|
||||||
if (timestamp != 0) builder.setWhen(timestamp);
|
if (timestamp != 0) builder.setWhen(timestamp);
|
||||||
|
|
||||||
builder.addActions(notificationState.getMarkAsReadIntent(context));
|
builder.addActions(notificationState.getMarkAsReadIntent(context, SUMMARY_NOTIFICATION_ID));
|
||||||
|
|
||||||
ListIterator<NotificationItem> iterator = notifications.listIterator(notifications.size());
|
ListIterator<NotificationItem> iterator = notifications.listIterator(notifications.size());
|
||||||
|
|
||||||
@ -306,8 +362,7 @@ public class MessageNotifier {
|
|||||||
notifications.get(0).getText());
|
notifications.get(0).getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
|
NotificationManagerCompat.from(context).notify(SUMMARY_NOTIFICATION_ID, builder.build());
|
||||||
.notify(NOTIFICATION_ID, builder.build());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sendInThreadNotification(Context context, Recipients recipients) {
|
private static void sendInThreadNotification(Context context, Recipients recipients) {
|
||||||
|
@ -31,6 +31,7 @@ public class MultipleRecipientNotificationBuilder extends AbstractNotificationBu
|
|||||||
setCategory(NotificationCompat.CATEGORY_MESSAGE);
|
setCategory(NotificationCompat.CATEGORY_MESSAGE);
|
||||||
setPriority(NotificationCompat.PRIORITY_HIGH);
|
setPriority(NotificationCompat.PRIORITY_HIGH);
|
||||||
setDeleteIntent(PendingIntent.getBroadcast(context, 0, new Intent(MessageNotifier.DeleteReceiver.DELETE_REMINDER_ACTION), 0));
|
setDeleteIntent(PendingIntent.getBroadcast(context, 0, new Intent(MessageNotifier.DeleteReceiver.DELETE_REMINDER_ACTION), 0));
|
||||||
|
setGroupSummary(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMessageCount(int messageCount, int threadCount) {
|
public void setMessageCount(int messageCount, int threadCount) {
|
||||||
|
@ -4,6 +4,7 @@ import android.app.PendingIntent;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.VibrateSt
|
|||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -20,12 +22,25 @@ import java.util.Set;
|
|||||||
public class NotificationState {
|
public class NotificationState {
|
||||||
|
|
||||||
private final LinkedList<NotificationItem> notifications = new LinkedList<>();
|
private final LinkedList<NotificationItem> notifications = new LinkedList<>();
|
||||||
private final Set<Long> threads = new HashSet<>();
|
private final LinkedHashSet<Long> threads = new LinkedHashSet<>();
|
||||||
|
|
||||||
private int notificationCount = 0;
|
private int notificationCount = 0;
|
||||||
|
|
||||||
|
public NotificationState() {}
|
||||||
|
|
||||||
|
public NotificationState(@NonNull List<NotificationItem> items) {
|
||||||
|
for (NotificationItem item : items) {
|
||||||
|
addNotification(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addNotification(NotificationItem item) {
|
public void addNotification(NotificationItem item) {
|
||||||
notifications.addFirst(item);
|
notifications.addFirst(item);
|
||||||
|
|
||||||
|
if (threads.contains(item.getThreadId())) {
|
||||||
|
threads.remove(item.getThreadId());
|
||||||
|
}
|
||||||
|
|
||||||
threads.add(item.getThreadId());
|
threads.add(item.getThreadId());
|
||||||
notificationCount++;
|
notificationCount++;
|
||||||
}
|
}
|
||||||
@ -58,6 +73,10 @@ public class NotificationState {
|
|||||||
return threads.size() > 1;
|
return threads.size() > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LinkedHashSet<Long> getThreads() {
|
||||||
|
return threads;
|
||||||
|
}
|
||||||
|
|
||||||
public int getThreadCount() {
|
public int getThreadCount() {
|
||||||
return threads.size();
|
return threads.size();
|
||||||
}
|
}
|
||||||
@ -70,7 +89,17 @@ public class NotificationState {
|
|||||||
return notifications;
|
return notifications;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PendingIntent getMarkAsReadIntent(Context context) {
|
public List<NotificationItem> getNotificationsForThread(long threadId) {
|
||||||
|
LinkedList<NotificationItem> list = new LinkedList<>();
|
||||||
|
|
||||||
|
for (NotificationItem item : notifications) {
|
||||||
|
if (item.getThreadId() == threadId) list.addFirst(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PendingIntent getMarkAsReadIntent(Context context, int notificationId) {
|
||||||
long[] threadArray = new long[threads.size()];
|
long[] threadArray = new long[threads.size()];
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
@ -80,14 +109,10 @@ public class NotificationState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Intent intent = new Intent(MarkReadReceiver.CLEAR_ACTION);
|
Intent intent = new Intent(MarkReadReceiver.CLEAR_ACTION);
|
||||||
|
intent.setClass(context, MarkReadReceiver.class);
|
||||||
|
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
||||||
intent.putExtra(MarkReadReceiver.THREAD_IDS_EXTRA, threadArray);
|
intent.putExtra(MarkReadReceiver.THREAD_IDS_EXTRA, threadArray);
|
||||||
intent.setPackage(context.getPackageName());
|
intent.putExtra(MarkReadReceiver.NOTIFICATION_ID_EXTRA, notificationId);
|
||||||
|
|
||||||
// XXX : This is an Android bug. If we don't pull off the extra
|
|
||||||
// once before handing off the PendingIntent, the array will be
|
|
||||||
// truncated to one element when the PendingIntent fires. Thanks guys!
|
|
||||||
Log.w("NotificationState", "Pending array off intent length: " +
|
|
||||||
intent.getLongArrayExtra("thread_ids").length);
|
|
||||||
|
|
||||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
}
|
}
|
||||||
@ -96,6 +121,8 @@ public class NotificationState {
|
|||||||
if (threads.size() != 1) throw new AssertionError("We only support replies to single thread notifications!");
|
if (threads.size() != 1) throw new AssertionError("We only support replies to single thread notifications!");
|
||||||
|
|
||||||
Intent intent = new Intent(WearReplyReceiver.REPLY_ACTION);
|
Intent intent = new Intent(WearReplyReceiver.REPLY_ACTION);
|
||||||
|
intent.setClass(context, WearReplyReceiver.class);
|
||||||
|
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
||||||
intent.putExtra(WearReplyReceiver.RECIPIENT_IDS_EXTRA, recipients.getIds());
|
intent.putExtra(WearReplyReceiver.RECIPIENT_IDS_EXTRA, recipients.getIds());
|
||||||
intent.setPackage(context.getPackageName());
|
intent.setPackage(context.getPackageName());
|
||||||
|
|
||||||
@ -106,6 +133,8 @@ public class NotificationState {
|
|||||||
if (threads.size() != 1) throw new AssertionError("We only support replies to single thread notifications!");
|
if (threads.size() != 1) throw new AssertionError("We only support replies to single thread notifications!");
|
||||||
|
|
||||||
Intent intent = new Intent(AndroidAutoReplyReceiver.REPLY_ACTION);
|
Intent intent = new Intent(AndroidAutoReplyReceiver.REPLY_ACTION);
|
||||||
|
intent.setClass(context, AndroidAutoReplyReceiver.class);
|
||||||
|
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
||||||
intent.putExtra(AndroidAutoReplyReceiver.RECIPIENT_IDS_EXTRA, recipients.getIds());
|
intent.putExtra(AndroidAutoReplyReceiver.RECIPIENT_IDS_EXTRA, recipients.getIds());
|
||||||
intent.putExtra(AndroidAutoReplyReceiver.THREAD_ID_EXTRA, (long)threads.toArray()[0]);
|
intent.putExtra(AndroidAutoReplyReceiver.THREAD_ID_EXTRA, (long)threads.toArray()[0]);
|
||||||
intent.setPackage(context.getPackageName());
|
intent.setPackage(context.getPackageName());
|
||||||
@ -113,7 +142,7 @@ public class NotificationState {
|
|||||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PendingIntent getAndroidAutoHeardIntent(Context context, Recipients recipients) {
|
public PendingIntent getAndroidAutoHeardIntent(Context context, int notificationId) {
|
||||||
long[] threadArray = new long[threads.size()];
|
long[] threadArray = new long[threads.size()];
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (long thread : threads) {
|
for (long thread : threads) {
|
||||||
@ -122,17 +151,17 @@ public class NotificationState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Intent intent = new Intent(AndroidAutoHeardReceiver.HEARD_ACTION);
|
Intent intent = new Intent(AndroidAutoHeardReceiver.HEARD_ACTION);
|
||||||
|
intent.setClass(context, AndroidAutoHeardReceiver.class);
|
||||||
|
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
||||||
intent.putExtra(AndroidAutoHeardReceiver.THREAD_IDS_EXTRA, threadArray);
|
intent.putExtra(AndroidAutoHeardReceiver.THREAD_IDS_EXTRA, threadArray);
|
||||||
|
intent.putExtra(AndroidAutoHeardReceiver.NOTIFICATION_ID_EXTRA, notificationId);
|
||||||
intent.setPackage(context.getPackageName());
|
intent.setPackage(context.getPackageName());
|
||||||
|
|
||||||
Log.w("NotificationState", "getAndroidAutoHeardIntent - Pending array off intent length: " +
|
|
||||||
intent.getLongArrayExtra(AndroidAutoHeardReceiver.THREAD_IDS_EXTRA).length);
|
|
||||||
|
|
||||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PendingIntent getQuickReplyIntent(Context context, Recipients recipients) {
|
public PendingIntent getQuickReplyIntent(Context context, Recipients recipients) {
|
||||||
if (threads.size() != 1) throw new AssertionError("We only support replies to single thread notifications!");
|
if (threads.size() != 1) throw new AssertionError("We only support replies to single thread notifications! " + threads.size());
|
||||||
|
|
||||||
Intent intent = new Intent(context, ConversationPopupActivity.class);
|
Intent intent = new Intent(context, ConversationPopupActivity.class);
|
||||||
intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
||||||
|
@ -24,15 +24,11 @@ import android.os.Bundle;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.RemoteInput;
|
import android.support.v4.app.RemoteInput;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
|
||||||
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob;
|
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
|
Loading…
Reference in New Issue
Block a user