mirror of
https://github.com/moparisthebest/k-9
synced 2025-01-08 04:08:15 -05:00
#619 "Add android wear support"
added EXTRA_MESSAGE_ID to simplify closing the correct notification and make things more robust.
This commit is contained in:
parent
764f380d45
commit
509573e014
@ -22,16 +22,38 @@ import com.fsck.k9.service.NotificationActionService;
|
||||
public class NotificationDeleteConfirmation extends Activity {
|
||||
private final static String EXTRA_ACCOUNT = "account";
|
||||
private final static String EXTRA_MESSAGE_LIST = "messages";
|
||||
private final static String EXTRA_NOTIFICATION_ID = NotificationActionService.EXTRA_NOTIFICATION_ID;
|
||||
|
||||
private final static int DIALOG_CONFIRM = 1;
|
||||
|
||||
/**
|
||||
* The account to delete the messages on.
|
||||
*/
|
||||
private Account mAccount;
|
||||
/**
|
||||
* The messages to delete.
|
||||
*/
|
||||
private ArrayList<MessageReference> mMessageRefs;
|
||||
/**
|
||||
* ID of the notification that triggered this Activity.
|
||||
* To make sure we close the correte notification afterwards because
|
||||
* there may be multiple of them due to Android Wear stacked notifications.
|
||||
*/
|
||||
private int mNotificationID;
|
||||
|
||||
public static PendingIntent getIntent(Context context, final Account account, final Serializable refs) {
|
||||
/**
|
||||
*
|
||||
* @param context context to create the PendingIntent.
|
||||
* @param account The account to delete the messages on.
|
||||
* @param refs The messages to delete.
|
||||
* @param notificationID ID of the notification that triggered this Activity.
|
||||
* @return PendingIntent that either deletes directly or shows a confirm-dialog on the phone (not on the wear device) first.
|
||||
*/
|
||||
public static PendingIntent getIntent(final Context context, final Account account, final Serializable refs, final int notificationID) {
|
||||
Intent i = new Intent(context, NotificationDeleteConfirmation.class);
|
||||
i.putExtra(EXTRA_ACCOUNT, account.getUuid());
|
||||
i.putExtra(EXTRA_MESSAGE_LIST, refs);
|
||||
i.putExtra(EXTRA_NOTIFICATION_ID, notificationID);
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
|
||||
return PendingIntent.getActivity(context, account.getAccountNumber(), i, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
@ -49,11 +71,12 @@ public class NotificationDeleteConfirmation extends Activity {
|
||||
|
||||
mAccount = preferences.getAccount(intent.getStringExtra(EXTRA_ACCOUNT));
|
||||
mMessageRefs = intent.getParcelableArrayListExtra(EXTRA_MESSAGE_LIST);
|
||||
mNotificationID = intent.getIntExtra(EXTRA_NOTIFICATION_ID, mAccount.getAccountNumber());
|
||||
|
||||
if (mAccount == null || mMessageRefs == null || mMessageRefs.isEmpty()) {
|
||||
finish();
|
||||
} else if (!K9.confirmDeleteFromNotification()) {
|
||||
triggerDelete();
|
||||
triggerDelete(mNotificationID);
|
||||
finish();
|
||||
} else {
|
||||
showDialog(DIALOG_CONFIRM);
|
||||
@ -71,7 +94,7 @@ public class NotificationDeleteConfirmation extends Activity {
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
triggerDelete();
|
||||
triggerDelete(mNotificationID);
|
||||
finish();
|
||||
}
|
||||
},
|
||||
@ -100,8 +123,8 @@ public class NotificationDeleteConfirmation extends Activity {
|
||||
super.onPrepareDialog(id, d);
|
||||
}
|
||||
|
||||
private void triggerDelete() {
|
||||
Intent i = NotificationActionService.getDeleteAllMessagesIntent(this, mAccount, mMessageRefs);
|
||||
private void triggerDelete(final int notificationID) {
|
||||
Intent i = NotificationActionService.getDeleteAllMessagesIntent(this, mAccount, mMessageRefs, notificationID);
|
||||
startService(i);
|
||||
}
|
||||
}
|
||||
|
@ -4826,19 +4826,19 @@ public class MessagingController implements Runnable {
|
||||
* Build the specific notification actions for a single message on Android Wear.
|
||||
* @param totalMsgCount if this is a stacked notification, how many other messages are there?
|
||||
*/
|
||||
private void addWearActions(final NotificationCompat.Builder builder, final int totalMsgCount, final Account account, final Message message) {
|
||||
private void addWearActions(final NotificationCompat.Builder builder, final int totalMsgCount, final Account account, final Message message, final int notificationID) {
|
||||
ArrayList<MessageReference> subAllRefs = new ArrayList<MessageReference>();
|
||||
subAllRefs.add(new MessageReference(account.getUuid(), message.getFolder().getName(), message.getUid(), message.getFlags().size()==0?null:message.getFlags().iterator().next()));
|
||||
LinkedList<Message> msgList = new LinkedList<Message>();
|
||||
msgList.add(message);
|
||||
addWearActions(builder, totalMsgCount, 1, account, subAllRefs, msgList);
|
||||
addWearActions(builder, totalMsgCount, 1, account, subAllRefs, msgList, notificationID);
|
||||
}
|
||||
/**
|
||||
* Build the specific notification actions for a single or multiple message on Android Wear.
|
||||
* @param totalMsgCount total message count (may be different from msgCount if this is a stacked notification)
|
||||
* @param msgCount message count to be handled in this (stacked or summary) notification
|
||||
*/
|
||||
private void addWearActions(final NotificationCompat.Builder builder, final int totalMsgCount, final int msgCount, final Account account, final ArrayList<MessageReference> allRefs, final List<? extends Message> messages) {
|
||||
private void addWearActions(final NotificationCompat.Builder builder, final int totalMsgCount, final int msgCount, final Account account, final ArrayList<MessageReference> allRefs, final List<? extends Message> messages, final int notificationID) {
|
||||
// we need a new wearableExtender for each notification
|
||||
final NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender();
|
||||
|
||||
@ -4858,7 +4858,7 @@ public class MessagingController implements Runnable {
|
||||
new NotificationCompat.Action.Builder(
|
||||
R.drawable.ic_action_delete_dark,
|
||||
context.getString(R.string.notification_action_delete),
|
||||
NotificationDeleteConfirmation.getIntent(context, account, allRefs))
|
||||
NotificationDeleteConfirmation.getIntent(context, account, allRefs, notificationID))
|
||||
.build();
|
||||
builder.extend(wearableExtender.addAction(wearActionDelete));
|
||||
}
|
||||
@ -4870,7 +4870,7 @@ public class MessagingController implements Runnable {
|
||||
new NotificationCompat.Action.Builder(
|
||||
R.drawable.ic_action_delete_dark,
|
||||
context.getString(R.string.notification_action_archive),
|
||||
NotificationActionService.getArchiveAllMessagesIntent(context, account, allRefs, totalMsgCount > msgCount))
|
||||
NotificationActionService.getArchiveAllMessagesIntent(context, account, allRefs, totalMsgCount > msgCount, notificationID))
|
||||
.build();
|
||||
builder.extend(wearableExtender.addAction(wearActionArchive));
|
||||
}
|
||||
@ -4881,7 +4881,7 @@ public class MessagingController implements Runnable {
|
||||
new NotificationCompat.Action.Builder(
|
||||
R.drawable.ic_action_delete_dark,
|
||||
context.getString(R.string.notification_action_spam),
|
||||
NotificationActionService.getSpamAllMessagesIntent(context, account, allRefs, totalMsgCount > msgCount))
|
||||
NotificationActionService.getSpamAllMessagesIntent(context, account, allRefs, totalMsgCount > msgCount, notificationID))
|
||||
.build();
|
||||
builder.extend(wearableExtender.addAction(wearActionSpam));
|
||||
}
|
||||
@ -4943,7 +4943,6 @@ public class MessagingController implements Runnable {
|
||||
|
||||
// Stacked notifications for Android Wear
|
||||
// https://developer.android.com/training/wearables/notifications/stacks.html
|
||||
// TODO: Bug! Stacked notification are shown on phone too, together with summary
|
||||
|
||||
// multiple messages pending, show inbox style
|
||||
NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle(builder);
|
||||
@ -4962,12 +4961,20 @@ public class MessagingController implements Runnable {
|
||||
subBuilder.setGroup(NOTIFICATION_GROUP_KEY); // same group as summary
|
||||
subBuilder.setAutoCancel(true); // summary closes all, stacked only itself
|
||||
|
||||
nID = 1000 + nID;
|
||||
// reuse existing notification IDs if some of the stacked messages
|
||||
// are already shown on the wear device.
|
||||
Integer realnID = data.getStackedChildNotification(m);
|
||||
if (realnID == null) {
|
||||
realnID = nID;
|
||||
}
|
||||
|
||||
// set content
|
||||
setNotificationContent(context, m, getMessageSender(context, account, m), getMessageSubject(context, m), subBuilder, accountDescr);
|
||||
|
||||
|
||||
// set actions
|
||||
addWearActions(subBuilder, newMessages, account, m);
|
||||
addWearActions(subBuilder, newMessages, account, m, realnID);
|
||||
if (m.isSet(Flag.FLAGGED)) {
|
||||
subBuilder.setPriority(NotificationCompat.PRIORITY_HIGH);
|
||||
}
|
||||
@ -4976,11 +4983,6 @@ public class MessagingController implements Runnable {
|
||||
// and depend on quiet time and user settings
|
||||
|
||||
// this must be done before the summary notification
|
||||
nID = 1000 + nID;
|
||||
Integer realnID = data.getStackedChildNotification(m);
|
||||
if (realnID == null) {
|
||||
realnID = nID;
|
||||
}
|
||||
notifMgr.notify(realnID, subBuilder.build());
|
||||
data.addStackedChildNotification(m, realnID);
|
||||
}
|
||||
@ -5014,12 +5016,12 @@ public class MessagingController implements Runnable {
|
||||
? R.drawable.ic_action_single_message_options_dark_vector
|
||||
: R.drawable.ic_action_single_message_options_dark,
|
||||
context.getString(R.string.notification_action_reply),
|
||||
NotificationActionService.getReplyIntent(context, account, message.makeMessageReference()));
|
||||
NotificationActionService.getReplyIntent(context, account, message.makeMessageReference(), account.getAccountNumber()));
|
||||
|
||||
// add /different) actions to show on connected Android Wear devices
|
||||
// do not add these to the a summary notification or they will affect all stacked
|
||||
// notifications
|
||||
addWearActions(builder, newMessages, newMessages, account, allRefs, data.messages);
|
||||
addWearActions(builder, newMessages, newMessages, account, allRefs, data.messages, account.getAccountNumber());
|
||||
}
|
||||
|
||||
// Mark Read on phone
|
||||
@ -5028,7 +5030,7 @@ public class MessagingController implements Runnable {
|
||||
? R.drawable.ic_action_mark_as_read_dark_vector
|
||||
: R.drawable.ic_action_mark_as_read_dark,
|
||||
context.getString(R.string.notification_action_mark_as_read),
|
||||
NotificationActionService.getReadAllMessagesIntent(context, account, allRefs));
|
||||
NotificationActionService.getReadAllMessagesIntent(context, account, allRefs, account.getAccountNumber()));
|
||||
|
||||
NotificationQuickDelete deleteOption = K9.getNotificationQuickDeleteBehaviour();
|
||||
boolean showDeleteAction = deleteOption == NotificationQuickDelete.ALWAYS ||
|
||||
@ -5045,7 +5047,7 @@ public class MessagingController implements Runnable {
|
||||
? R.drawable.ic_action_delete_dark_vector
|
||||
: R.drawable.ic_action_delete_dark,
|
||||
context.getString(R.string.notification_action_delete),
|
||||
NotificationDeleteConfirmation.getIntent(context, account, allRefs));
|
||||
NotificationDeleteConfirmation.getIntent(context, account, allRefs, account.getAccountNumber()));
|
||||
}
|
||||
|
||||
} else { // no extended notifications supported
|
||||
@ -5067,7 +5069,7 @@ public class MessagingController implements Runnable {
|
||||
builder.setContentIntent(stack.getPendingIntent(
|
||||
account.getAccountNumber(),
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT));
|
||||
builder.setDeleteIntent(NotificationActionService.getAcknowledgeIntent(context, account));
|
||||
builder.setDeleteIntent(NotificationActionService.getAcknowledgeIntent(context, account, account.getAccountNumber()));
|
||||
|
||||
// Only ring or vibrate if we have not done so already on this account and fetch
|
||||
boolean ringAndVibrate = false;
|
||||
@ -5343,15 +5345,15 @@ public class MessagingController implements Runnable {
|
||||
notificationManager.cancel(-1000 - account.getAccountNumber());
|
||||
|
||||
// cancel stacked notifications on Android Wear that share this as a summary notification
|
||||
NotificationData data = notificationData.get(account.getAccountNumber());
|
||||
if (data != null) {
|
||||
Collection<Integer> stackedChildNotifications = data.getStackedChildNotifications();
|
||||
if (stackedChildNotifications != null) {
|
||||
for (Integer stackedNotificationId : stackedChildNotifications) {
|
||||
notificationManager.cancel(stackedNotificationId);
|
||||
}
|
||||
}
|
||||
}
|
||||
//NotificationData data = notificationData.get(account.getAccountNumber());
|
||||
//if (data != null) {
|
||||
// Collection<Integer> stackedChildNotifications = data.getStackedChildNotifications();
|
||||
// if (stackedChildNotifications != null) {
|
||||
// for (Integer stackedNotificationId : stackedChildNotifications) {
|
||||
// notificationManager.cancel(stackedNotificationId);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
notificationData.remove(account.getAccountNumber());
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import com.fsck.k9.mail.Flag;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mailstore.LocalMessage;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -36,8 +37,23 @@ public class NotificationActionService extends CoreService {
|
||||
private final static String EXTRA_MESSAGE = "message";
|
||||
private final static String EXTRA_MESSAGE_LIST = "messages";
|
||||
private final static String EXTRA_DONTCANCEL = "dontcancel";
|
||||
/**
|
||||
* ID of the notification that triggered an intent.
|
||||
* Used to cancel exactly that one notification because due to
|
||||
* Android Wear there may be multiple notifications per account.
|
||||
*/
|
||||
public final static String EXTRA_NOTIFICATION_ID = "notificationid";
|
||||
|
||||
public static PendingIntent getReplyIntent(Context context, final Account account, final MessageReference ref) {
|
||||
/**
|
||||
*
|
||||
* @param context
|
||||
* @param account
|
||||
* @param ref
|
||||
* @param notificationID ID of the notification, this intent is for.
|
||||
* @see #EXTRA_NOTIFICATION_ID
|
||||
* @return
|
||||
*/
|
||||
public static PendingIntent getReplyIntent(Context context, final Account account, final MessageReference ref, final int notificationID) {
|
||||
Intent i = new Intent(context, NotificationActionService.class);
|
||||
i.putExtra(EXTRA_ACCOUNT, account.getUuid());
|
||||
i.putExtra(EXTRA_MESSAGE, ref);
|
||||
@ -46,27 +62,56 @@ public class NotificationActionService extends CoreService {
|
||||
return PendingIntent.getService(context, account.getAccountNumber(), i, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
public static PendingIntent getReadAllMessagesIntent(Context context, final Account account, final Serializable refs) {
|
||||
/**
|
||||
*
|
||||
* @param context
|
||||
* @param account
|
||||
* @param refs
|
||||
* @param notificationID ID of the notification, this intent is for.
|
||||
* @return
|
||||
* @see #EXTRA_NOTIFICATION_ID
|
||||
*/
|
||||
public static PendingIntent getReadAllMessagesIntent(Context context, final Account account, final Serializable refs, final int notificationID) {
|
||||
Intent i = new Intent(context, NotificationActionService.class);
|
||||
i.putExtra(EXTRA_ACCOUNT, account.getUuid());
|
||||
i.putExtra(EXTRA_MESSAGE_LIST, refs);
|
||||
i.putExtra(EXTRA_NOTIFICATION_ID, notificationID);
|
||||
i.setAction(READ_ALL_ACTION);
|
||||
|
||||
return PendingIntent.getService(context, account.getAccountNumber(), i, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
public static PendingIntent getAcknowledgeIntent(Context context, final Account account) {
|
||||
/**
|
||||
*
|
||||
* @param context
|
||||
* @param account
|
||||
* @param notificationID ID of the notification, this intent is for.
|
||||
* @return
|
||||
* @see #EXTRA_NOTIFICATION_ID
|
||||
*/
|
||||
public static PendingIntent getAcknowledgeIntent(Context context, final Account account, final int notificationID) {
|
||||
Intent i = new Intent(context, NotificationActionService.class);
|
||||
i.putExtra(EXTRA_ACCOUNT, account.getUuid());
|
||||
i.putExtra(EXTRA_NOTIFICATION_ID, notificationID);
|
||||
i.setAction(ACKNOWLEDGE_ACTION);
|
||||
|
||||
return PendingIntent.getService(context, account.getAccountNumber(), i, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
public static Intent getDeleteAllMessagesIntent(Context context, final Account account, final Serializable refs) {
|
||||
/**
|
||||
*
|
||||
* @param context
|
||||
* @param account
|
||||
* @param refs
|
||||
* @param notificationID ID of the notification, this intent is for.
|
||||
* @return
|
||||
* @see #EXTRA_NOTIFICATION_ID
|
||||
*/
|
||||
public static Intent getDeleteAllMessagesIntent(Context context, final Account account, final Serializable refs, final int notificationID) {
|
||||
Intent i = new Intent(context, NotificationActionService.class);
|
||||
i.putExtra(EXTRA_ACCOUNT, account.getUuid());
|
||||
i.putExtra(EXTRA_MESSAGE_LIST, refs);
|
||||
i.putExtra(EXTRA_NOTIFICATION_ID, notificationID);
|
||||
i.setAction(DELETE_ALL_ACTION);
|
||||
|
||||
return i;
|
||||
@ -93,15 +138,18 @@ public class NotificationActionService extends CoreService {
|
||||
* @param account
|
||||
* @param refs
|
||||
* @param dontCancel if true, after executing the intent, not all notifications for this account are canceled automatically
|
||||
* @param notificationID ID of the notification, this intent is for.
|
||||
* @return
|
||||
* @see #EXTRA_NOTIFICATION_ID
|
||||
*/
|
||||
public static PendingIntent getArchiveAllMessagesIntent(Context context, final Account account, final Serializable refs, final boolean dontCancel) {
|
||||
public static PendingIntent getArchiveAllMessagesIntent(Context context, final Account account, final Serializable refs, final boolean dontCancel, final int notificationID) {
|
||||
Intent i = new Intent(context, NotificationActionService.class);
|
||||
i.putExtra(EXTRA_ACCOUNT, account.getUuid());
|
||||
i.putExtra(EXTRA_MESSAGE_LIST, refs);
|
||||
if (dontCancel) {
|
||||
i.putExtra(EXTRA_DONTCANCEL, true);
|
||||
}
|
||||
i.putExtra(EXTRA_NOTIFICATION_ID, notificationID);
|
||||
i.setAction(ARCHIVE_ALL_ACTION);
|
||||
|
||||
return PendingIntent.getService(context, account.getAccountNumber(), i, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
@ -112,7 +160,7 @@ public class NotificationActionService extends CoreService {
|
||||
* Check if for the given parameters the SpamAllMessages intent is possible for Android Wear.
|
||||
* (No confirmation on the phone required and moving these messages to the spam-folder possible)<br/>
|
||||
* Since we can not show a toast like on the phone screen, we must not offer actions that can not be performed.
|
||||
* @see #getSpamAllMessagesIntent(android.content.Context, com.fsck.k9.Account, java.io.Serializable, boolean)
|
||||
* @see #getSpamAllMessagesIntent(android.content.Context, com.fsck.k9.Account, java.io.Serializable, boolean, int)
|
||||
* @param context the context to get a {@link MessagingController}
|
||||
* @param account the account (must allow moving messages to allow true as a result)
|
||||
* @param messages the messages to move to the spam folder (must be synchronized to allow true as a result)
|
||||
@ -129,15 +177,18 @@ public class NotificationActionService extends CoreService {
|
||||
* @param account
|
||||
* @param refs
|
||||
* @param dontCancel if true, after executing the intent, not all notifications for this account are canceled automatically
|
||||
* @param notificationID ID of the notification, this intent is for.
|
||||
* @return
|
||||
* @see #EXTRA_NOTIFICATION_ID
|
||||
*/
|
||||
public static PendingIntent getSpamAllMessagesIntent(Context context, final Account account, final Serializable refs, final boolean dontCancel) {
|
||||
public static PendingIntent getSpamAllMessagesIntent(Context context, final Account account, final Serializable refs, final boolean dontCancel, final int notificationID) {
|
||||
Intent i = new Intent(context, NotificationActionService.class);
|
||||
i.putExtra(EXTRA_ACCOUNT, account.getUuid());
|
||||
i.putExtra(EXTRA_MESSAGE_LIST, refs);
|
||||
if (dontCancel) {
|
||||
i.putExtra(EXTRA_DONTCANCEL, true);
|
||||
}
|
||||
i.putExtra(EXTRA_NOTIFICATION_ID, notificationID);
|
||||
i.setAction(SPAM_ALL_ACTION);
|
||||
|
||||
return PendingIntent.getService(context, account.getAccountNumber(), i, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
@ -267,7 +318,13 @@ public class NotificationActionService extends CoreService {
|
||||
// notification and keep the other stacked notifications
|
||||
if (!intent.hasExtra(EXTRA_DONTCANCEL)) {
|
||||
// there's no point in keeping the notification after the user clicked on it
|
||||
controller.notifyAccountCancel(this, account);
|
||||
if (intent.hasExtra(EXTRA_NOTIFICATION_ID)) {
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(intent.getIntExtra(EXTRA_NOTIFICATION_ID, account.getAccountNumber()));
|
||||
} else {
|
||||
controller.notifyAccountCancel(this, account);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.w(K9.LOG_TAG, "Could not find account for notification action.");
|
||||
|
Loading…
Reference in New Issue
Block a user