mirror of
https://github.com/moparisthebest/Yaaic
synced 2024-11-22 17:02:21 -05:00
Overhaul notifications system
Features: * Now displays the number of mentions that the user has not seen in the notification. * When no mentions are outstanding, display which servers the user is connected to, not the last message. * When more than one mention is outstanding, display the names of the conversations with new mentions, not just the last message received. * Notifications of mentions are suppressed if you're in the conversation at the time of the mention. * Notifications of mentions automatically clear when you bring up the conversation. * Vibrate notifications now generate the user's chosen default vibrate pattern, not a hard-coded one. * Add ticker text to the notification that's displayed when the IRCService goes into the foreground, instead of displaying a blank ticker. To allow for all of this, the implementation moves most of the details of generating the notification text into the IRCService, which now exposes addNewMention() and notifyConnected()/notifyDisconnected() methods instead of the lower-level updateNotification().
This commit is contained in:
parent
09fedc6975
commit
61960c9add
@ -113,8 +113,10 @@
|
||||
<string name="command_desc_voice">Give a user voice status</string>
|
||||
<string name="command_desc_whois">Get information about a user</string>
|
||||
|
||||
<string name="notification_running">Yaaic is running</string>
|
||||
<string name="notification_connected">Connected to %1$s</string>
|
||||
<string name="notification_disconnected">Disconnected from %1$s</string>
|
||||
<string name="notification_mentions">New messages in: %1$s</string>
|
||||
|
||||
<string name="message_connected">Connected to %1$s</string>
|
||||
<string name="message_deop">%1$s deops %2$s</string>
|
||||
|
@ -154,7 +154,7 @@ public class ConversationActivity extends Activity implements ServiceConnection,
|
||||
|
||||
deckAdapter = new DeckAdapter();
|
||||
deck = (Gallery) findViewById(R.id.deck);
|
||||
deck.setOnItemSelectedListener(new ConversationSelectedListener(server, (TextView) findViewById(R.id.title), dots));
|
||||
deck.setOnItemSelectedListener(new ConversationSelectedListener(this, server, (TextView) findViewById(R.id.title), dots));
|
||||
deck.setAdapter(deckAdapter);
|
||||
deck.setOnItemClickListener(new ConversationClickListener(deckAdapter, switcher));
|
||||
deck.setBackgroundDrawable(new NonScalingBackgroundDrawable(this, deck, R.drawable.background));
|
||||
@ -244,6 +244,14 @@ public class ConversationActivity extends Activity implements ServiceConnection,
|
||||
mAdapter.addBulkMessages(conversation.getBuffer());
|
||||
conversation.clearBuffer();
|
||||
}
|
||||
|
||||
// Clear new message notifications for the selected conversation
|
||||
if (conversation.getStatus() == Conversation.STATUS_SELECTED && conversation.getNewMentions() > 0) {
|
||||
Intent ackIntent = new Intent(this, IRCService.class);
|
||||
ackIntent.setAction(IRCService.ACTION_ACK_NEW_MENTIONS);
|
||||
ackIntent.putExtra(IRCService.EXTRA_ACK_CONVTITLE, conversation.getName());
|
||||
startService(ackIntent);
|
||||
}
|
||||
}
|
||||
|
||||
// Join channel that has been selected in JoinActivity (onActivityResult())
|
||||
@ -256,6 +264,8 @@ public class ConversationActivity extends Activity implements ServiceConnection,
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
server.setIsForeground(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -266,6 +276,8 @@ public class ConversationActivity extends Activity implements ServiceConnection,
|
||||
{
|
||||
super.onPause();
|
||||
|
||||
server.setIsForeground(false);
|
||||
|
||||
if (binder != null && binder.getService() != null) {
|
||||
binder.getService().checkServiceStatus();
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ public class IRCConnection extends PircBot
|
||||
Broadcast.createServerIntent(Broadcast.SERVER_UPDATE, server.getId())
|
||||
);
|
||||
|
||||
service.updateNotification(service.getString(R.string.notification_connected, server.getTitle()));
|
||||
service.notifyConnected(server.getTitle());
|
||||
|
||||
Message message = new Message(service.getString(R.string.message_connected, server.getTitle()));
|
||||
message.setColor(Message.COLOR_GREEN);
|
||||
@ -245,12 +245,15 @@ public class IRCConnection extends PircBot
|
||||
|
||||
boolean mentioned = isMentioned(action);
|
||||
if (mentioned || target.equals(this.getNick())) {
|
||||
service.updateNotification(
|
||||
target + ": " + sender + " " + action,
|
||||
if (conversation.getStatus() != Conversation.STATUS_SELECTED || !server.getIsForeground()) {
|
||||
service.addNewMention(
|
||||
conversation,
|
||||
conversation.getName() + ": " + sender + " " + action,
|
||||
service.getSettings().isVibrateHighlightEnabled(),
|
||||
service.getSettings().isSoundHighlightEnabled()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (mentioned) {
|
||||
// highlight
|
||||
@ -410,20 +413,24 @@ public class IRCConnection extends PircBot
|
||||
protected void onMessage(String target, String sender, String login, String hostname, String text)
|
||||
{
|
||||
Message message = new Message(text, sender);
|
||||
Conversation conversation = server.getConversation(target);
|
||||
|
||||
if (isMentioned(text)) {
|
||||
// highlight
|
||||
message.setColor(Message.COLOR_RED);
|
||||
service.updateNotification(
|
||||
if (conversation.getStatus() != Conversation.STATUS_SELECTED || !server.getIsForeground()) {
|
||||
service.addNewMention(
|
||||
conversation,
|
||||
target + ": <" + sender + "> " + text,
|
||||
service.getSettings().isVibrateHighlightEnabled(),
|
||||
service.getSettings().isSoundHighlightEnabled()
|
||||
);
|
||||
|
||||
server.getConversation(target).setStatus(Conversation.STATUS_HIGHLIGHT);
|
||||
}
|
||||
|
||||
server.getConversation(target).addMessage(message);
|
||||
conversation.setStatus(Conversation.STATUS_HIGHLIGHT);
|
||||
}
|
||||
|
||||
conversation.addMessage(message);
|
||||
|
||||
Intent intent = Broadcast.createConversationIntent(
|
||||
Broadcast.CONVERSATION_MESSAGE,
|
||||
@ -619,11 +626,14 @@ public class IRCConnection extends PircBot
|
||||
return;
|
||||
}
|
||||
|
||||
service.updateNotification(
|
||||
if (conversation.getStatus() != Conversation.STATUS_SELECTED || !server.getIsForeground()) {
|
||||
service.addNewMention(
|
||||
conversation,
|
||||
"<" + sender + "> " + text,
|
||||
service.getSettings().isVibrateHighlightEnabled(),
|
||||
service.getSettings().isSoundHighlightEnabled()
|
||||
);
|
||||
}
|
||||
|
||||
if (isMentioned(text)) {
|
||||
message.setColor(Message.COLOR_RED);
|
||||
@ -1099,7 +1109,7 @@ public class IRCConnection extends PircBot
|
||||
server.setStatus(Status.DISCONNECTED);
|
||||
}
|
||||
|
||||
service.updateNotification(service.getString(R.string.notification_disconnected, server.getTitle()));
|
||||
service.notifyDisconnected(server.getTitle());
|
||||
|
||||
Intent sIntent = Broadcast.createServerIntent(Broadcast.SERVER_UPDATE, server.getId());
|
||||
service.sendBroadcast(sIntent);
|
||||
|
@ -24,6 +24,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import org.jibble.pircbot.IrcException;
|
||||
import org.jibble.pircbot.NickAlreadyInUseException;
|
||||
@ -32,6 +33,7 @@ import org.yaaic.Yaaic;
|
||||
import org.yaaic.activity.ServersActivity;
|
||||
import org.yaaic.db.Database;
|
||||
import org.yaaic.model.Broadcast;
|
||||
import org.yaaic.model.Conversation;
|
||||
import org.yaaic.model.Message;
|
||||
import org.yaaic.model.Server;
|
||||
import org.yaaic.model.ServerInfo;
|
||||
@ -54,6 +56,11 @@ public class IRCService extends Service
|
||||
private final IRCBinder binder;
|
||||
private final HashMap<Integer, IRCConnection> connections;
|
||||
private boolean foreground = false;
|
||||
private ArrayList<String> connectedServerTitles;
|
||||
private LinkedHashMap<String, Conversation> mentions;
|
||||
private int newMentions = 0;
|
||||
|
||||
private static final int FOREGROUND_NOTIFICATION = 1;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static final Class[] mStartForegroundSignature = new Class[] { int.class, Notification.class };
|
||||
@ -62,6 +69,8 @@ public class IRCService extends Service
|
||||
|
||||
public static final String ACTION_FOREGROUND = "org.yaaic.service.foreground";
|
||||
public static final String ACTION_BACKGROUND = "org.yaaic.service.background";
|
||||
public static final String ACTION_ACK_NEW_MENTIONS = "org.yaaic.service.ack_new_mentions";
|
||||
public static final String EXTRA_ACK_CONVTITLE = "org.yaaic.service.ack_convtitle";
|
||||
|
||||
private NotificationManager notificationManager;
|
||||
private Method mStartForeground;
|
||||
@ -80,6 +89,8 @@ public class IRCService extends Service
|
||||
|
||||
this.connections = new HashMap<Integer, IRCConnection>();
|
||||
this.binder = new IRCBinder(this);
|
||||
this.connectedServerTitles = new ArrayList<String>();
|
||||
this.mentions = new LinkedHashMap<String, Conversation>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -166,7 +177,7 @@ public class IRCService extends Service
|
||||
foreground = true;
|
||||
|
||||
// Set the icon, scrolling text and timestamp
|
||||
notification = new Notification(R.drawable.icon, "", System.currentTimeMillis());
|
||||
notification = new Notification(R.drawable.icon, getText(R.string.notification_running), System.currentTimeMillis());
|
||||
|
||||
// The PendingIntent to launch our activity if the user selects this notification
|
||||
Intent notifyIntent = new Intent(this, ServersActivity.class);
|
||||
@ -176,51 +187,146 @@ public class IRCService extends Service
|
||||
// Set the info for the views that show in the notification panel.
|
||||
notification.setLatestEventInfo(this, getText(R.string.app_name), "", contentIntent);
|
||||
|
||||
startForegroundCompat(R.string.app_name, notification);
|
||||
startForegroundCompat(FOREGROUND_NOTIFICATION, notification);
|
||||
} else if (ACTION_BACKGROUND.equals(intent.getAction()) && !foreground) {
|
||||
stopForegroundCompat(R.string.app_name);
|
||||
stopForegroundCompat(FOREGROUND_NOTIFICATION);
|
||||
} else if (ACTION_ACK_NEW_MENTIONS.equals(intent.getAction())) {
|
||||
ackNewMentions(intent.getStringExtra(EXTRA_ACK_CONVTITLE));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update notification
|
||||
*
|
||||
* @param text The text to display
|
||||
*/
|
||||
public void updateNotification(String text)
|
||||
{
|
||||
updateNotification(text, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update notification and vibrate if needed
|
||||
*
|
||||
* @param text The text to display
|
||||
* @param text The ticker text to display
|
||||
* @param contentText The text to display in the notification dropdown
|
||||
* @param vibrate True if the device should vibrate, false otherwise
|
||||
* @param sound True if the device should make sound, false otherwise
|
||||
*/
|
||||
public void updateNotification(String text, boolean vibrate, boolean sound)
|
||||
private void updateNotification(String text, String contentText, boolean vibrate, boolean sound)
|
||||
{
|
||||
if (foreground) {
|
||||
notificationManager.cancel(R.string.app_name);
|
||||
notification = new Notification(R.drawable.icon, text, System.currentTimeMillis());
|
||||
Intent notifyIntent = new Intent(this, ServersActivity.class);
|
||||
notifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notifyIntent, 0);
|
||||
notification.setLatestEventInfo(this, getText(R.string.app_name), text, contentIntent);
|
||||
|
||||
if (contentText == null) {
|
||||
if (!connectedServerTitles.isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String title : connectedServerTitles) {
|
||||
sb.append(title + ", ");
|
||||
}
|
||||
contentText = getString(R.string.notification_connected, sb.substring(0, sb.length()-2));
|
||||
} else {
|
||||
contentText = "";
|
||||
}
|
||||
}
|
||||
|
||||
notification.setLatestEventInfo(this, getText(R.string.app_name), contentText, contentIntent);
|
||||
|
||||
if (vibrate) {
|
||||
long[] pattern = {0,100,200,300};
|
||||
notification.vibrate = pattern;
|
||||
notification.defaults |= Notification.DEFAULT_VIBRATE;
|
||||
}
|
||||
|
||||
if (sound) {
|
||||
notification.defaults |= Notification.DEFAULT_SOUND;
|
||||
}
|
||||
|
||||
notificationManager.notify(R.string.app_name, notification);
|
||||
notification.number = newMentions;
|
||||
|
||||
notificationManager.notify(FOREGROUND_NOTIFICATION, notification);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the status bar notification for a new mention
|
||||
*/
|
||||
private void notifyMention(String msg, boolean vibrate, boolean sound)
|
||||
{
|
||||
String contentText = null;
|
||||
|
||||
if (newMentions == 1 && msg != null) {
|
||||
contentText = msg;
|
||||
} else if (newMentions >= 1) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Conversation conv : mentions.values()) {
|
||||
sb.append(conv.getName() + " (" + conv.getNewMentions() + "), ");
|
||||
}
|
||||
contentText = getString(R.string.notification_mentions, sb.substring(0, sb.length()-2));
|
||||
}
|
||||
|
||||
updateNotification(msg, contentText, vibrate, sound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the service of a new mention (updates the status bar notification)
|
||||
*
|
||||
* @param conversation The conversation where the new mention occurred
|
||||
* @param msg The text of the new message
|
||||
* @param vibrate Whether the notification should include vibration
|
||||
* @param sound Whether the notification should include sound
|
||||
*/
|
||||
public void addNewMention(Conversation conversation, String msg, boolean vibrate, boolean sound)
|
||||
{
|
||||
if (conversation == null)
|
||||
return;
|
||||
|
||||
String convTitle = conversation.getName();
|
||||
|
||||
conversation.addNewMention();
|
||||
++newMentions;
|
||||
if (!mentions.containsKey(convTitle)) {
|
||||
mentions.put(convTitle, conversation);
|
||||
}
|
||||
|
||||
notifyMention(msg, vibrate, sound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the service that new mentions have been viewed (updates the status bar notification)
|
||||
*
|
||||
* @param convTitle The title of the conversation whose new mentions have been read
|
||||
*/
|
||||
public void ackNewMentions(String convTitle)
|
||||
{
|
||||
if (convTitle == null)
|
||||
return;
|
||||
|
||||
Conversation conversation = mentions.remove(convTitle);
|
||||
if (conversation == null)
|
||||
return;
|
||||
newMentions -= conversation.getNewMentions();
|
||||
conversation.clearNewMentions();
|
||||
if (newMentions < 0)
|
||||
newMentions = 0;
|
||||
|
||||
notifyMention(null, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the service of connection to a server (updates the status bar notification)
|
||||
*
|
||||
* @param title The title of the newly connected server
|
||||
*/
|
||||
public void notifyConnected(String title)
|
||||
{
|
||||
connectedServerTitles.add(title);
|
||||
updateNotification(getString(R.string.notification_connected, title), null, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the service of disconnection from a server (updates the status bar notification)
|
||||
*
|
||||
* @param title The title of the disconnected server
|
||||
*/
|
||||
public void notifyDisconnected(String title)
|
||||
{
|
||||
connectedServerTitles.remove(title);
|
||||
updateNotification(getString(R.string.notification_disconnected, title), null, false, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is a wrapper around the new startForeground method, using the older
|
||||
* APIs if it is not available.
|
||||
|
@ -24,11 +24,14 @@ import org.yaaic.model.Channel;
|
||||
import org.yaaic.model.Conversation;
|
||||
import org.yaaic.model.Server;
|
||||
import org.yaaic.view.ConversationSwitcher;
|
||||
import org.yaaic.irc.IRCService;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.TextView;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
/**
|
||||
* Listener for conversation selections
|
||||
@ -37,6 +40,7 @@ import android.widget.TextView;
|
||||
*/
|
||||
public class ConversationSelectedListener implements OnItemSelectedListener
|
||||
{
|
||||
private final Context ctx;
|
||||
private final Server server;
|
||||
private final TextView titleView;
|
||||
private final ConversationSwitcher switcher;
|
||||
@ -47,8 +51,9 @@ public class ConversationSelectedListener implements OnItemSelectedListener
|
||||
* @param server
|
||||
* @param titleView
|
||||
*/
|
||||
public ConversationSelectedListener(Server server, TextView titleView, ConversationSwitcher switcher)
|
||||
public ConversationSelectedListener(Context ctx, Server server, TextView titleView, ConversationSwitcher switcher)
|
||||
{
|
||||
this.ctx = ctx;
|
||||
this.server = server;
|
||||
this.titleView = titleView;
|
||||
this.switcher = switcher;
|
||||
@ -80,6 +85,13 @@ public class ConversationSelectedListener implements OnItemSelectedListener
|
||||
previousConversation.setStatus(Conversation.STATUS_DEFAULT);
|
||||
}
|
||||
|
||||
if (conversation.getNewMentions() > 0) {
|
||||
Intent i = new Intent(ctx, IRCService.class);
|
||||
i.setAction(IRCService.ACTION_ACK_NEW_MENTIONS);
|
||||
i.putExtra(IRCService.EXTRA_ACK_CONVTITLE, conversation.getName());
|
||||
ctx.startService(i);
|
||||
}
|
||||
|
||||
conversation.setStatus(Conversation.STATUS_SELECTED);
|
||||
server.setSelectedConversation(conversation.getName());
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ public abstract class Conversation
|
||||
private final LinkedList<Message> history;
|
||||
private final String name;
|
||||
private int status = 1;
|
||||
private int newMentions = 0;
|
||||
|
||||
/**
|
||||
* Get the type of conversation (channel, query, ..)
|
||||
@ -179,4 +180,28 @@ public abstract class Conversation
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the count of unread mentions in this conversation
|
||||
*/
|
||||
public void addNewMention()
|
||||
{
|
||||
++newMentions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark all new mentions as unread
|
||||
*/
|
||||
public void clearNewMentions()
|
||||
{
|
||||
newMentions = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of unread mentions in this conversation
|
||||
*/
|
||||
public int getNewMentions()
|
||||
{
|
||||
return newMentions;
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ public class Server
|
||||
|
||||
private int status = Status.DISCONNECTED;
|
||||
private String selected = "";
|
||||
private boolean isForeground = false;
|
||||
|
||||
/**
|
||||
* Create a new server object
|
||||
@ -404,4 +405,20 @@ public class Server
|
||||
|
||||
return R.drawable.connecting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether a ConversationActivity for this server is currently in the foreground.
|
||||
*/
|
||||
public boolean getIsForeground()
|
||||
{
|
||||
return isForeground;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether a ConversationActivity for this server is currently in the foreground.
|
||||
*/
|
||||
public void setIsForeground(boolean isForeground)
|
||||
{
|
||||
this.isForeground = isForeground;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user