Commit bcbb1c98 authored by Grigory Fedorov's avatar Grigory Fedorov

Merge branch 'feature/notifications' into develop

parents fcbb6053 ef08f374
...@@ -8,8 +8,8 @@ android { ...@@ -8,8 +8,8 @@ android {
applicationId "com.xabber.androiddev" applicationId "com.xabber.androiddev"
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 21 targetSdkVersion 21
versionCode 88 versionCode 107
versionName '0.10.3' versionName '0.10.10'
} }
buildTypes { buildTypes {
...@@ -18,6 +18,10 @@ android { ...@@ -18,6 +18,10 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
} }
} }
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
} }
dependencies { dependencies {
......
...@@ -123,7 +123,14 @@ ...@@ -123,7 +123,14 @@
<activity <activity
android:label="@string/occupant_list" android:label="@string/occupant_list"
android:name="com.xabber.android.ui.OccupantList" android:name="com.xabber.android.ui.OccupantList"
/> android:parentActivityName="com.xabber.android.ui.ChatViewer"
>
<!-- Parent activity meta-data to support 4.0 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.xabber.android.ui.ChatViewer" />
</activity>
<activity <activity
android:label="@string/chat_viewer" android:label="@string/chat_viewer"
android:name="com.xabber.android.ui.ChatViewer" android:name="com.xabber.android.ui.ChatViewer"
......
...@@ -14,18 +14,6 @@ ...@@ -14,18 +14,6 @@
*/ */
package com.xabber.android.data.account; package com.xabber.android.data.account;
import java.security.KeyPair;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.jivesoftware.smack.util.StringUtils;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.database.Cursor; import android.database.Cursor;
import android.os.Build; import android.os.Build;
...@@ -46,6 +34,18 @@ import com.xabber.android.data.roster.RosterManager; ...@@ -46,6 +34,18 @@ import com.xabber.android.data.roster.RosterManager;
import com.xabber.androiddev.R; import com.xabber.androiddev.R;
import com.xabber.xmpp.address.Jid; import com.xabber.xmpp.address.Jid;
import org.jivesoftware.smack.util.StringUtils;
import java.security.KeyPair;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
/** /**
* This class manage all operations with accounts. * This class manage all operations with accounts.
* <p/> * <p/>
...@@ -117,9 +117,9 @@ public class AccountManager implements OnLoadListener, OnWipeListener { ...@@ -117,9 +117,9 @@ public class AccountManager implements OnLoadListener, OnWipeListener {
enabledAccounts = new HashSet<String>(); enabledAccounts = new HashSet<String>();
savedStatuses = new ArrayList<SavedStatus>(); savedStatuses = new ArrayList<SavedStatus>();
authorizationErrorProvider = new BaseAccountNotificationProvider<AccountAuthorizationError>( authorizationErrorProvider = new BaseAccountNotificationProvider<AccountAuthorizationError>(
R.drawable.ic_stat_auth_failed); R.drawable.ic_stat_error);
passwordRequestProvider = new BaseAccountNotificationProvider<PasswordRequest>( passwordRequestProvider = new BaseAccountNotificationProvider<PasswordRequest>(
R.drawable.ic_stat_request); R.drawable.ic_stat_ic_add_circle);
TypedArray accountAvatars = application.getResources() TypedArray accountAvatars = application.getResources()
.obtainTypedArray(R.array.account_avatars); .obtainTypedArray(R.array.account_avatars);
......
...@@ -14,6 +14,19 @@ ...@@ -14,6 +14,19 @@
*/ */
package com.xabber.android.data.connection; package com.xabber.android.data.connection;
import android.content.res.AssetManager;
import com.xabber.android.data.Application;
import com.xabber.android.data.LogManager;
import com.xabber.android.data.OnClearListener;
import com.xabber.android.data.OnLoadListener;
import com.xabber.android.data.notification.BaseNotificationProvider;
import com.xabber.android.data.notification.NotificationManager;
import com.xabber.androiddev.R;
import org.jivesoftware.smack.CertificateListener;
import org.jivesoftware.smack.util.StringUtils;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
...@@ -34,19 +47,6 @@ import java.util.HashMap; ...@@ -34,19 +47,6 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.jivesoftware.smack.CertificateListener;
import org.jivesoftware.smack.util.StringUtils;
import android.content.res.AssetManager;
import com.xabber.android.data.Application;
import com.xabber.android.data.LogManager;
import com.xabber.android.data.OnClearListener;
import com.xabber.android.data.OnLoadListener;
import com.xabber.android.data.notification.BaseNotificationProvider;
import com.xabber.android.data.notification.NotificationManager;
import com.xabber.androiddev.R;
/** /**
* Manage certificate exceptions. * Manage certificate exceptions.
* <p/> * <p/>
...@@ -94,7 +94,7 @@ public class CertificateManager implements OnLoadListener, OnClearListener { ...@@ -94,7 +94,7 @@ public class CertificateManager implements OnLoadListener, OnClearListener {
private final Map<CertificateInvalidReason, KeyStore> defaultStores; private final Map<CertificateInvalidReason, KeyStore> defaultStores;
private final BaseNotificationProvider<PendingCertificate> pendingCertificateProvider = new BaseNotificationProvider<PendingCertificate>( private final BaseNotificationProvider<PendingCertificate> pendingCertificateProvider = new BaseNotificationProvider<PendingCertificate>(
R.drawable.ic_stat_auth_failed) { R.drawable.ic_stat_error) {
@Override @Override
public void clearNotifications() { public void clearNotifications() {
......
...@@ -14,16 +14,6 @@ ...@@ -14,16 +14,6 @@
*/ */
package com.xabber.android.data.extension.archive; package com.xabber.android.data.extension.archive;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.Packet;
import com.xabber.android.data.Application; import com.xabber.android.data.Application;
import com.xabber.android.data.LogManager; import com.xabber.android.data.LogManager;
import com.xabber.android.data.NetworkException; import com.xabber.android.data.NetworkException;
...@@ -68,6 +58,16 @@ import com.xabber.xmpp.archive.Session; ...@@ -68,6 +58,16 @@ import com.xabber.xmpp.archive.Session;
import com.xabber.xmpp.archive.SessionRemove; import com.xabber.xmpp.archive.SessionRemove;
import com.xabber.xmpp.rsm.Set; import com.xabber.xmpp.rsm.Set;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.Packet;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
/** /**
* Manage server side archive. Replicate it with memory storage. * Manage server side archive. Replicate it with memory storage.
* <p/> * <p/>
...@@ -164,7 +164,7 @@ public class MessageArchiveManager implements OnPacketListener, ...@@ -164,7 +164,7 @@ public class MessageArchiveManager implements OnPacketListener,
modificationRequests = new NestedMap<Boolean>(); modificationRequests = new NestedMap<Boolean>();
chatStorages = new NestedNestedMaps<String, ChatStorage>(); chatStorages = new NestedNestedMaps<String, ChatStorage>();
availableArchiveRequestProvider = new BaseAccountNotificationProvider<AvailableArchiveRequest>( availableArchiveRequestProvider = new BaseAccountNotificationProvider<AvailableArchiveRequest>(
R.drawable.ic_stat_request); R.drawable.ic_stat_ic_help_black);
} }
@Override @Override
......
...@@ -14,16 +14,6 @@ ...@@ -14,16 +14,6 @@
*/ */
package com.xabber.android.data.extension.attention; package com.xabber.android.data.extension.attention;
import java.util.Iterator;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import android.media.AudioManager; import android.media.AudioManager;
import android.net.Uri; import android.net.Uri;
...@@ -51,6 +41,16 @@ import com.xabber.androiddev.R; ...@@ -51,6 +41,16 @@ import com.xabber.androiddev.R;
import com.xabber.xmpp.address.Jid; import com.xabber.xmpp.address.Jid;
import com.xabber.xmpp.attention.Attention; import com.xabber.xmpp.attention.Attention;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import java.util.Iterator;
/** /**
* XEP-0224: Attention. * XEP-0224: Attention.
* *
...@@ -86,7 +86,7 @@ public class AttentionManager implements OnPacketListener, OnLoadListener { ...@@ -86,7 +86,7 @@ public class AttentionManager implements OnPacketListener, OnLoadListener {
} }
private final EntityNotificationProvider<AttentionRequest> attentionRequestProvider = new EntityNotificationProvider<AttentionRequest>( private final EntityNotificationProvider<AttentionRequest> attentionRequestProvider = new EntityNotificationProvider<AttentionRequest>(
R.drawable.ic_stat_attention) { R.drawable.ic_stat_error) {
@Override @Override
public Uri getSound() { public Uri getSound() {
......
...@@ -14,17 +14,6 @@ ...@@ -14,17 +14,6 @@
*/ */
package com.xabber.android.data.extension.muc; package com.xabber.android.data.extension.muc;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.packet.MUCUser;
import android.database.Cursor; import android.database.Cursor;
import com.xabber.android.data.Application; import com.xabber.android.data.Application;
...@@ -46,6 +35,17 @@ import com.xabber.android.data.roster.RosterManager; ...@@ -46,6 +35,17 @@ import com.xabber.android.data.roster.RosterManager;
import com.xabber.androiddev.R; import com.xabber.androiddev.R;
import com.xabber.xmpp.muc.MUC; import com.xabber.xmpp.muc.MUC;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.packet.MUCUser;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
/** /**
* Manage multi user chats. * Manage multi user chats.
* <p/> * <p/>
...@@ -72,9 +72,9 @@ public class MUCManager implements OnLoadListener, OnPacketListener { ...@@ -72,9 +72,9 @@ public class MUCManager implements OnLoadListener, OnPacketListener {
private MUCManager() { private MUCManager() {
inviteProvider = new EntityNotificationProvider<RoomInvite>( inviteProvider = new EntityNotificationProvider<RoomInvite>(
R.drawable.ic_stat_subscribe); R.drawable.ic_stat_ic_add_circle);
authorizationErrorProvider = new EntityNotificationProvider<RoomAuthorizationError>( authorizationErrorProvider = new EntityNotificationProvider<RoomAuthorizationError>(
R.drawable.ic_stat_auth_failed); R.drawable.ic_stat_error);
} }
@Override @Override
......
...@@ -14,29 +14,6 @@ ...@@ -14,29 +14,6 @@
*/ */
package com.xabber.android.data.extension.otr; package com.xabber.android.data.extension.otr;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import net.java.otr4j.OtrEngineHost;
import net.java.otr4j.OtrEngineListener;
import net.java.otr4j.OtrException;
import net.java.otr4j.OtrPolicy;
import net.java.otr4j.OtrPolicyImpl;
import net.java.otr4j.crypto.OtrCryptoEngineImpl;
import net.java.otr4j.crypto.OtrCryptoException;
import net.java.otr4j.io.SerializationUtils;
import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionID;
import net.java.otr4j.session.SessionImpl;
import net.java.otr4j.session.SessionStatus;
import android.database.Cursor; import android.database.Cursor;
import com.xabber.android.data.Application; import com.xabber.android.data.Application;
...@@ -66,6 +43,29 @@ import com.xabber.androiddev.R; ...@@ -66,6 +43,29 @@ import com.xabber.androiddev.R;
import com.xabber.xmpp.archive.OtrMode; import com.xabber.xmpp.archive.OtrMode;
import com.xabber.xmpp.archive.SaveMode; import com.xabber.xmpp.archive.SaveMode;
import net.java.otr4j.OtrEngineHost;
import net.java.otr4j.OtrEngineListener;
import net.java.otr4j.OtrException;
import net.java.otr4j.OtrPolicy;
import net.java.otr4j.OtrPolicyImpl;
import net.java.otr4j.crypto.OtrCryptoEngineImpl;
import net.java.otr4j.crypto.OtrCryptoException;
import net.java.otr4j.io.SerializationUtils;
import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionID;
import net.java.otr4j.session.SessionImpl;
import net.java.otr4j.session.SessionStatus;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/** /**
* Manage off-the-record encryption. * Manage off-the-record encryption.
* <p/> * <p/>
...@@ -134,9 +134,9 @@ public class OTRManager implements OtrEngineHost, OtrEngineListener, ...@@ -134,9 +134,9 @@ public class OTRManager implements OtrEngineHost, OtrEngineListener,
private OTRManager() { private OTRManager() {
smRequestProvider = new EntityNotificationProvider<SMRequest>( smRequestProvider = new EntityNotificationProvider<SMRequest>(
R.drawable.ic_stat_request); R.drawable.ic_stat_ic_help_black);
smProgressProvider = new EntityNotificationProvider<SMProgress>( smProgressProvider = new EntityNotificationProvider<SMProgress>(
R.drawable.ic_stat_play); R.drawable.ic_stat_ic_play_circle_fill);
smProgressProvider.setCanClearNotifications(false); smProgressProvider.setCanClearNotifications(false);
fingerprints = new NestedNestedMaps<String, Boolean>(); fingerprints = new NestedNestedMaps<String, Boolean>();
actives = new NestedMap<String>(); actives = new NestedMap<String>();
......
package com.xabber.android.data.notification;
import android.app.PendingIntent;
import android.content.Intent;
import android.media.AudioManager;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.StyleSpan;
import com.xabber.android.data.Application;
import com.xabber.android.data.SettingsManager;
import com.xabber.android.data.extension.avatar.AvatarManager;
import com.xabber.android.data.extension.muc.MUCManager;
import com.xabber.android.data.message.MessageItem;
import com.xabber.android.data.message.chat.ChatManager;
import com.xabber.android.data.message.phrase.PhraseManager;
import com.xabber.android.data.roster.RosterManager;
import com.xabber.android.ui.ChatViewer;
import com.xabber.android.utils.StringUtils;
import com.xabber.androiddev.R;
import java.util.List;
public class MessageNotificationCreator {
private final Application application;
private List<MessageNotification> messageNotifications;
private NotificationCompat.Builder notificationBuilder;
public MessageNotificationCreator() {
application = Application.getInstance();
}
public android.app.Notification notifyMessageNotification(List<MessageNotification> messageNotifications,
MessageItem messageItem) {
this.messageNotifications = messageNotifications;
if (messageNotifications.isEmpty()) {
return null;
}
int messageCount = 0;
for (MessageNotification messageNotification : messageNotifications) {
messageCount += messageNotification.getCount();
}
MessageNotification message = messageNotifications.get(messageNotifications.size() - 1);
boolean showText = ChatManager.getInstance().isShowText(message.getAccount(), message.getUser());
notificationBuilder = new NotificationCompat.Builder(application);
notificationBuilder.setContentTitle(getTitle(message, messageCount));
notificationBuilder.setContentText(getText(message, showText));
notificationBuilder.setSubText(message.getAccount());
notificationBuilder.setTicker(getText(message, showText));
notificationBuilder.setSmallIcon(getSmallIcon());
notificationBuilder.setLargeIcon(getLargeIcon(message));
notificationBuilder.setWhen(message.getTimestamp().getTime());
notificationBuilder.setColor(NotificationManager.COLOR_MATERIAL_RED_500);
notificationBuilder.setStyle(getStyle(message, messageCount, showText));
notificationBuilder.setContentIntent(getIntent(message));
notificationBuilder.setCategory(NotificationCompat.CATEGORY_MESSAGE);
notificationBuilder.setPriority(NotificationCompat.PRIORITY_HIGH);
addEffects(messageItem);
return notificationBuilder.build();
}
private CharSequence getTitle(MessageNotification message, int messageCount) {
if (isFromOneContact()) {
return getSingleContactTitle(message, messageCount);
} else {
return getMultiContactTitle(messageCount);
}
}
private CharSequence getSingleContactTitle(MessageNotification message, int messageCount) {
if (messageCount > 1) {
return application.getString(R.string.chat_messages_from_contact,
messageCount, getTextForMessages(messageCount), getContactName(message));
} else {
return getContactName(message);
}
}
private String getContactName(MessageNotification message) {
return RosterManager.getInstance().getName(message.getAccount(), message.getUser());
}
private CharSequence getMultiContactTitle(int messageCount) {
String messageText = getTextForMessages(messageCount);
String contactText = StringUtils.getQuantityString(application.getResources(),
R.array.chat_contact_quantity, messageNotifications.size());
return application.getString(R.string.chat_status,
messageCount, messageText, messageNotifications.size(), contactText);
}
private String getTextForMessages(int messageCount) {
return StringUtils.getQuantityString(
application.getResources(), R.array.chat_message_quantity, messageCount);
}
private CharSequence getText(MessageNotification message, boolean showText) {
if (isFromOneContact()) {
if (showText) {
return message.getText();
} else {
return null;
}
} else {
return getContactNameAndMessage(message, showText);
}
}
private int getSmallIcon() {
return R.drawable.ic_stat_chat;
}
private android.graphics.Bitmap getLargeIcon(MessageNotification message) {
if (isFromOneContact()) {
if (MUCManager.getInstance().hasRoom(message.getAccount(), message.getUser())) {
return AvatarManager.getInstance().getRoomBitmap(message.getUser());
} else {
return AvatarManager.getInstance().getUserBitmap(message.getUser());
}
}
return null;
}
private boolean isFromOneContact() {
return messageNotifications.size() == 1;
}
private NotificationCompat.Style getStyle(MessageNotification message, int messageCount, boolean showText) {
if (isFromOneContact()) {
NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle();
bigTextStyle.setBigContentTitle(getSingleContactTitle(message, messageCount));
if (showText) {
bigTextStyle.bigText(message.getText());
}
bigTextStyle.setSummaryText(message.getAccount());
return bigTextStyle;
} else {
return getInboxStyle(messageCount, message.getAccount());
}
}
private NotificationCompat.Style getInboxStyle(int messageCount, String accountName) {
NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
inboxStyle.setBigContentTitle(getMultiContactTitle(messageCount));
for (int i = 1; i <= messageNotifications.size(); i++) {
MessageNotification messageNotification = messageNotifications.get(messageNotifications.size() - i);
boolean showTextForThisContact
= ChatManager.getInstance().isShowText(messageNotification.getAccount(), messageNotification.getUser());
inboxStyle.addLine(getContactNameAndMessage(messageNotification, showTextForThisContact));
}
inboxStyle.setSummaryText(accountName);
return inboxStyle;
}
private Spannable getContactNameAndMessage(MessageNotification messageNotification, boolean showText) {
String userName = getContactName(messageNotification);
Spannable spannableString;
if (showText) {
String contactAndMessage = application.getString(
R.string.chat_contact_and_message, userName, messageNotification.getText());
spannableString = new SpannableString(contactAndMessage);
} else {
spannableString = new SpannableString(userName);
}
spannableString.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, userName.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannableString;
}
private PendingIntent getIntent(MessageNotification message) {
Intent chatIntent
= ChatViewer.createClearTopIntent(application, message.getAccount(), message.getUser());
return PendingIntent.getActivity(application, 0, chatIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private void addEffects(MessageItem messageItem) {
if (messageItem == null) {
return;
}
if (messageItem.getChat().getFirstNotification() || !SettingsManager.eventsFirstOnly()) {
Uri sound = PhraseManager.getInstance().getSound(messageItem.getChat().getAccount(),
messageItem.getChat().getUser(), messageItem.getText());
boolean makeVibration = ChatManager.getInstance().isMakeVibro(messageItem.getChat().getAccount(),
messageItem.getChat().getUser());
NotificationManager.getInstance().setNotificationDefaults(notificationBuilder,
makeVibration, sound, AudioManager.STREAM_NOTIFICATION);
}
}
}
...@@ -14,23 +14,15 @@ ...@@ -14,23 +14,15 @@
*/ */
package com.xabber.android.data.notification; package com.xabber.android.data.notification;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import android.app.Notification; import android.app.Notification;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.media.AudioManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.Vibrator; import android.os.Vibrator;
import android.widget.RemoteViews; import android.support.v4.app.NotificationCompat;
import com.xabber.android.data.Application; import com.xabber.android.data.Application;
import com.xabber.android.data.LogManager; import com.xabber.android.data.LogManager;
...@@ -45,52 +37,56 @@ import com.xabber.android.data.account.OnAccountArchiveModeChangedListener; ...@@ -45,52 +37,56 @@ import com.xabber.android.data.account.OnAccountArchiveModeChangedListener;
import com.xabber.android.data.account.OnAccountChangedListener; import com.xabber.android.data.account.OnAccountChangedListener;
import com.xabber.android.data.account.OnAccountRemovedListener; import com.xabber.android.data.account.OnAccountRemovedListener;
import com.xabber.android.data.connection.ConnectionState; import com.xabber.android.data.connection.ConnectionState;
import com.xabber.android.data.extension.avatar.AvatarManager;
import com.xabber.android.data.extension.muc.MUCManager;
import com.xabber.android.data.message.MessageItem; import com.xabber.android.data.message.MessageItem;
import com.xabber.android.data.message.MessageManager; import com.xabber.android.data.message.MessageManager;
import com.xabber.android.data.message.chat.ChatManager;
import com.xabber.android.data.message.phrase.PhraseManager;
import com.xabber.android.data.roster.RosterManager; import com.xabber.android.data.roster.RosterManager;
import com.xabber.android.ui.ChatViewer;
import com.xabber.android.ui.ClearNotifications; import com.xabber.android.ui.ClearNotifications;
import com.xabber.android.ui.ContactList; import com.xabber.android.ui.ContactList;
import com.xabber.android.ui.ReconnectionActivity; import com.xabber.android.ui.ReconnectionActivity;
import com.xabber.android.utils.Emoticons;
import com.xabber.android.utils.StringUtils; import com.xabber.android.utils.StringUtils;
import com.xabber.androiddev.R; import com.xabber.androiddev.R;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
/** /**
* Manage notifications about message, subscription and authentication. * Manage notifications about message, subscription and authentication.
* *
* @author alexander.ivanov * @author alexander.ivanov
*/ */
public class NotificationManager implements OnInitializedListener, public class NotificationManager implements OnInitializedListener, OnAccountChangedListener,
OnAccountChangedListener, OnCloseListener, OnLoadListener, Runnable, OnCloseListener, OnLoadListener, Runnable, OnAccountRemovedListener,
OnAccountRemovedListener, OnAccountArchiveModeChangedListener { OnAccountArchiveModeChangedListener {
public static final int PERSISTENT_NOTIFICATION_ID = 1; public static final int PERSISTENT_NOTIFICATION_ID = 1;
private static final int CHAT_NOTIFICATION_ID = 2; public static final int MESSAGE_NOTIFICATION_ID = 2;
private static final int BASE_NOTIFICATION_PROVIDER_ID = 0x10; private static final int BASE_NOTIFICATION_PROVIDER_ID = 0x10;
private static final long VIBRATION_DURATION = 500; private static final long VIBRATION_DURATION = 500;
private static final int MAX_NOTIFICATION_TEXT = 80;
private final long startTime; public static final int COLOR_MATERIAL_RED_500 = 0xF44336;
private final Application application; private final Application application;
private final android.app.NotificationManager notificationManager; private final android.app.NotificationManager notificationManager;
private final Notification persistentNotification;
private final PendingIntent clearNotifications; private final PendingIntent clearNotifications;
private final Handler handler; private final Handler handler;
private NotificationCompat.Builder persistentNotificationBuilder;
private MessageNotificationCreator messageNotificationCreator;
/** /**
* Runnable to start vibration. * Runnable to start vibration.
*/ */
private final Runnable startVibro; private final Runnable startVibration;
/** /**
* Runnable to force stop vibration. * Runnable to force stop vibration.
*/ */
private final Runnable stopVibro; private final Runnable stopVibration;
/** /**
* List of providers for notifications. * List of providers for notifications.
...@@ -115,42 +111,62 @@ public class NotificationManager implements OnInitializedListener, ...@@ -115,42 +111,62 @@ public class NotificationManager implements OnInitializedListener,
private NotificationManager() { private NotificationManager() {
this.application = Application.getInstance(); this.application = Application.getInstance();
notificationManager = (android.app.NotificationManager) application
.getSystemService(Context.NOTIFICATION_SERVICE); notificationManager = (android.app.NotificationManager)
persistentNotification = new Notification(); application.getSystemService(Context.NOTIFICATION_SERVICE);
handler = new Handler(); handler = new Handler();
providers = new ArrayList<NotificationProvider<? extends NotificationItem>>(); providers = new ArrayList<>();
messageNotifications = new ArrayList<MessageNotification>(); messageNotifications = new ArrayList<>();
startTime = System.currentTimeMillis(); clearNotifications = PendingIntent.getActivity(
clearNotifications = PendingIntent.getActivity(application, 0, application, 0, ClearNotifications.createIntent(application), 0);
ClearNotifications.createIntent(application), 0);
stopVibro = new Runnable() { stopVibration = new Runnable() {
@Override @Override
public void run() { public void run() {
handler.removeCallbacks(startVibro); handler.removeCallbacks(startVibration);
handler.removeCallbacks(stopVibro); handler.removeCallbacks(stopVibration);
((Vibrator) NotificationManager.this.application ((Vibrator) NotificationManager.this.application.
.getSystemService(Context.VIBRATOR_SERVICE)).cancel(); getSystemService(Context.VIBRATOR_SERVICE)).cancel();
} }
}; };
startVibro = new Runnable() {
startVibration = new Runnable() {
@Override @Override
public void run() { public void run() {
handler.removeCallbacks(startVibro); handler.removeCallbacks(startVibration);
handler.removeCallbacks(stopVibro); handler.removeCallbacks(stopVibration);
((Vibrator) NotificationManager.this.application ((Vibrator) NotificationManager.this.application
.getSystemService(Context.VIBRATOR_SERVICE)).cancel(); .getSystemService(Context.VIBRATOR_SERVICE)).cancel();
((Vibrator) NotificationManager.this.application ((Vibrator) NotificationManager.this.application
.getSystemService(Context.VIBRATOR_SERVICE)) .getSystemService(Context.VIBRATOR_SERVICE))
.vibrate(VIBRATION_DURATION); .vibrate(VIBRATION_DURATION);
handler.postDelayed(stopVibro, VIBRATION_DURATION); handler.postDelayed(stopVibration, VIBRATION_DURATION);
} }
}; };
persistentNotificationBuilder = new NotificationCompat.Builder(application);
initPersistentNotification();
messageNotificationCreator = new MessageNotificationCreator();
}
private void initPersistentNotification() {
persistentNotificationBuilder.setContentTitle(application.getString(R.string.application_name));
persistentNotificationBuilder.setDeleteIntent(clearNotifications);
persistentNotificationBuilder.setOngoing(true);
persistentNotificationBuilder.setWhen(System.currentTimeMillis());
persistentNotificationBuilder.setCategory(NotificationCompat.CATEGORY_SERVICE);
persistentNotificationBuilder.setPriority(NotificationCompat.PRIORITY_LOW);
persistentNotificationBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
} }
@Override @Override
public void onLoad() { public void onLoad() {
final Collection<MessageNotification> messageNotifications = new ArrayList<MessageNotification>(); final Collection<MessageNotification> messageNotifications = new ArrayList<>();
Cursor cursor = NotificationTable.getInstance().list(); Cursor cursor = NotificationTable.getInstance().list();
try { try {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
...@@ -176,10 +192,11 @@ public class NotificationManager implements OnInitializedListener, ...@@ -176,10 +192,11 @@ public class NotificationManager implements OnInitializedListener,
private void onLoaded(Collection<MessageNotification> messageNotifications) { private void onLoaded(Collection<MessageNotification> messageNotifications) {
this.messageNotifications.addAll(messageNotifications); this.messageNotifications.addAll(messageNotifications);
for (MessageNotification messageNotification : messageNotifications) for (MessageNotification messageNotification : messageNotifications) {
MessageManager.getInstance().openChat( MessageManager.getInstance().openChat(
messageNotification.getAccount(), messageNotification.getAccount(),
messageNotification.getUser()); messageNotification.getUser());
}
} }
@Override @Override
...@@ -193,8 +210,7 @@ public class NotificationManager implements OnInitializedListener, ...@@ -193,8 +210,7 @@ public class NotificationManager implements OnInitializedListener,
* *
* @param provider * @param provider
*/ */
public void registerNotificationProvider( public void registerNotificationProvider(NotificationProvider<? extends NotificationItem> provider) {
NotificationProvider<? extends NotificationItem> provider) {
providers.add(provider); providers.add(provider);
} }
...@@ -208,63 +224,89 @@ public class NotificationManager implements OnInitializedListener, ...@@ -208,63 +224,89 @@ public class NotificationManager implements OnInitializedListener,
public <T extends NotificationItem> void updateNotifications( public <T extends NotificationItem> void updateNotifications(
NotificationProvider<T> provider, T notify) { NotificationProvider<T> provider, T notify) {
int id = providers.indexOf(provider); int id = providers.indexOf(provider);
if (id == -1)
if (id == -1) {
throw new IllegalStateException( throw new IllegalStateException(
"registerNotificationProvider() must be called from onLoaded() method."); "registerNotificationProvider() must be called from onLoaded() method.");
else }
id += BASE_NOTIFICATION_PROVIDER_ID;
Iterator<? extends NotificationItem> iterator = provider id += BASE_NOTIFICATION_PROVIDER_ID;
.getNotifications().iterator(); Iterator<? extends NotificationItem> iterator = provider.getNotifications().iterator();
if (!iterator.hasNext()) { if (!iterator.hasNext()) {
notificationManager.cancel(id); notificationManager.cancel(id);
return;
}
NotificationItem top;
String ticker;
if (notify == null) {
top = iterator.next();
ticker = null;
} else { } else {
NotificationItem top; top = notify;
String ticker; ticker = top.getTitle();
if (notify == null) {
top = iterator.next();
ticker = null;
} else {
top = notify;
ticker = top.getTitle();
}
Intent intent = top.getIntent();
Notification notification = new Notification(provider.getIcon(),
ticker, System.currentTimeMillis());
if (!provider.canClearNotifications())
notification.flags |= Notification.FLAG_NO_CLEAR;
notification.setLatestEventInfo(application, top.getTitle(), top
.getText(), PendingIntent.getActivity(application, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT));
if (ticker != null)
setNotificationDefaults(notification,
SettingsManager.eventsVibro(), provider.getSound(),
provider.getStreamType());
notification.deleteIntent = clearNotifications;
notify(id, notification);
} }
Intent intent = top.getIntent();
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(application);
notificationBuilder.setSmallIcon(provider.getIcon());
notificationBuilder.setTicker(ticker);
if (!provider.canClearNotifications()) {
notificationBuilder.setOngoing(true);
}
notificationBuilder.setContentTitle(top.getTitle());
notificationBuilder.setContentText(top.getText());
notificationBuilder.setContentIntent(PendingIntent.getActivity(application, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT));
if (ticker != null) {
setNotificationDefaults(notificationBuilder, SettingsManager.eventsVibro(), provider.getSound(), provider.getStreamType());
}
notificationBuilder.setDeleteIntent(clearNotifications);
notificationBuilder.setColor(COLOR_MATERIAL_RED_500);
notify(id, notificationBuilder.build());
} }
/** /**
* Sound, vibration and lightning flags. * Sound, vibration and lightning flags.
* *
* @param notification * @param notificationBuilder
* @param streamType * @param streamType
*/ */
private void setNotificationDefaults(Notification notification, public void setNotificationDefaults(NotificationCompat.Builder notificationBuilder, boolean vibration, Uri sound, int streamType) {
boolean vibro, Uri sound, int streamType) { notificationBuilder.setSound(sound, streamType);
notification.audioStreamType = streamType; notificationBuilder.setDefaults(0);
notification.defaults = 0;
notification.sound = sound; int defaults = 0;
if (vibro) {
if (SettingsManager.eventsIgnoreSystemVibro()) if (vibration) {
handler.post(startVibro); if (SettingsManager.eventsIgnoreSystemVibro()) {
else startVibration();
notification.defaults |= Notification.DEFAULT_VIBRATE; } else {
defaults |= Notification.DEFAULT_VIBRATE;
}
} }
if (SettingsManager.eventsLightning()) { if (SettingsManager.eventsLightning()) {
notification.defaults |= Notification.DEFAULT_LIGHTS; defaults |= Notification.DEFAULT_LIGHTS;
notification.flags |= Notification.FLAG_SHOW_LIGHTS;
} }
notificationBuilder.setDefaults(defaults);
}
public void startVibration() {
handler.post(startVibration);
} }
/** /**
...@@ -281,231 +323,121 @@ public class NotificationManager implements OnInitializedListener, ...@@ -281,231 +323,121 @@ public class NotificationManager implements OnInitializedListener,
* @return * @return
*/ */
private void updateMessageNotification(MessageItem ticker) { private void updateMessageNotification(MessageItem ticker) {
Collection<String> accountList = AccountManager.getInstance() updatePersistentNotification();
.getAccounts();
int accountCount = accountList.size(); Notification messageNotification = messageNotificationCreator.notifyMessageNotification(messageNotifications, ticker);
boolean started = application.isInitialized();
if (messageNotification != null) {
notify(MESSAGE_NOTIFICATION_ID, messageNotification);
} else {
notificationManager.cancel(MESSAGE_NOTIFICATION_ID);
}
}
private void updatePersistentNotification() {
int waiting = 0; int waiting = 0;
int connecting = 0; int connecting = 0;
int connected = 0; int connected = 0;
Collection<String> accountList = AccountManager.getInstance().getAccounts();
for (String account : accountList) { for (String account : accountList) {
ConnectionState state = AccountManager.getInstance() ConnectionState state = AccountManager.getInstance().getAccount(account).getState();
.getAccount(account).getState();
if (RosterManager.getInstance().isRosterReceived(account)) if (RosterManager.getInstance().isRosterReceived(account)) {
connected++; connected++;
else if (state == ConnectionState.connecting } else if (state == ConnectionState.connecting || state == ConnectionState.authentication) {
|| state == ConnectionState.authentication)
connecting++; connecting++;
else if (state == ConnectionState.waiting) } else if (state == ConnectionState.waiting) {
waiting++; waiting++;
}
}
final Intent persistentIntent;
if (waiting > 0 && application.isInitialized()) {
persistentIntent = ReconnectionActivity.createIntent(application);
} else {
persistentIntent = ContactList.createPersistentIntent(application);
} }
if (connected > 0) {
persistentNotificationBuilder.setColor(COLOR_MATERIAL_RED_500);
persistentNotificationBuilder.setSmallIcon(R.drawable.ic_stat_light_bulb_big);
} else {
persistentNotificationBuilder.setColor(NotificationCompat.COLOR_DEFAULT);
persistentNotificationBuilder.setSmallIcon(R.drawable.ic_stat_light_bulb_big_off);
}
persistentNotificationBuilder.setContentText(getConnectionState(waiting, connecting, connected, accountList.size()));
persistentNotificationBuilder.setContentIntent(PendingIntent.getActivity(application, 0, persistentIntent,
PendingIntent.FLAG_UPDATE_CURRENT));
notify(PERSISTENT_NOTIFICATION_ID, persistentNotificationBuilder.build());
}
private String getConnectionState(int waiting, int connecting, int connected, int accountCount) {
String accountQuantity; String accountQuantity;
String connectionState; String connectionState;
if (connected > 0) { if (connected > 0) {
accountQuantity = StringUtils.getQuantityString( accountQuantity = StringUtils.getQuantityString(
application.getResources(), R.array.account_quantity, application.getResources(), R.array.account_quantity, accountCount);
accountCount);
String connectionFormat = StringUtils.getQuantityString( String connectionFormat = StringUtils.getQuantityString(
application.getResources(), application.getResources(), R.array.connection_state_connected, connected);
R.array.connection_state_connected, connected);
connectionState = String.format(connectionFormat, connected, connectionState = String.format(connectionFormat, connected, accountCount, accountQuantity);
accountCount, accountQuantity);
} else if (connecting > 0) { } else if (connecting > 0) {
accountQuantity = StringUtils.getQuantityString( accountQuantity = StringUtils.getQuantityString(
application.getResources(), R.array.account_quantity, application.getResources(), R.array.account_quantity, accountCount);
accountCount);
String connectionFormat = StringUtils.getQuantityString( String connectionFormat = StringUtils.getQuantityString(
application.getResources(), application.getResources(), R.array.connection_state_connecting, connecting);
R.array.connection_state_connecting, connecting);
connectionState = String.format(connectionFormat, connecting, connectionState = String.format(connectionFormat, connecting, accountCount, accountQuantity);
accountCount, accountQuantity);
} else if (waiting > 0 && started) { } else if (waiting > 0 && application.isInitialized()) {
accountQuantity = StringUtils.getQuantityString( accountQuantity = StringUtils.getQuantityString(
application.getResources(), R.array.account_quantity, application.getResources(), R.array.account_quantity, accountCount);
accountCount);
String connectionFormat = StringUtils.getQuantityString( String connectionFormat = StringUtils.getQuantityString(
application.getResources(), application.getResources(), R.array.connection_state_waiting, waiting);
R.array.connection_state_waiting, waiting);
connectionState = String.format(connectionFormat, waiting,
accountCount, accountQuantity);
} else {
accountQuantity = StringUtils.getQuantityString(
application.getResources(),
R.array.account_quantity_offline, accountCount);
connectionState = application.getString(
R.string.connection_state_offline, accountCount,
accountQuantity);
}
final Intent persistentIntent; connectionState = String.format(connectionFormat, waiting, accountCount, accountQuantity);
if (waiting > 0 && started)
persistentIntent = ReconnectionActivity.createIntent(application);
else
persistentIntent = ContactList.createPersistentIntent(application);
if (messageNotifications.isEmpty()) {
notificationManager.cancel(CHAT_NOTIFICATION_ID);
} else { } else {
int messageCount = 0; accountQuantity = StringUtils.getQuantityString(
for (MessageNotification messageNotification : messageNotifications) application.getResources(), R.array.account_quantity_offline, accountCount);
messageCount += messageNotification.getCount(); connectionState = application.getString(
MessageNotification message = messageNotifications R.string.connection_state_offline, accountCount, accountQuantity);
.get(messageNotifications.size() - 1);
RemoteViews chatViews = new RemoteViews(
application.getPackageName(), R.layout.chat_notification);
Intent chatIntent = ChatViewer.createClearTopIntent(application,
message.getAccount(), message.getUser());
if (MUCManager.getInstance().hasRoom(message.getAccount(),
message.getUser()))
chatViews.setImageViewBitmap(R.id.icon, AvatarManager
.getInstance().getRoomBitmap(message.getUser()));
else
chatViews.setImageViewBitmap(R.id.icon, AvatarManager
.getInstance().getUserBitmap(message.getUser()));
chatViews.setTextViewText(R.id.title, RosterManager.getInstance()
.getName(message.getAccount(), message.getUser()));
String text;
if (ChatManager.getInstance().isShowText(message.getAccount(),
message.getUser()))
text = trimText(message.getText());
else
text = "";
chatViews.setTextViewText(R.id.text2,
Emoticons.getSmiledText(application, text));
chatViews.setTextViewText(R.id.time,
StringUtils.getSmartTimeText(message.getTimestamp()));
String messageText = StringUtils.getQuantityString(
application.getResources(), R.array.chat_message_quantity,
messageCount);
String contactText = StringUtils.getQuantityString(
application.getResources(), R.array.chat_contact_quantity,
messageNotifications.size());
String status = application.getString(R.string.chat_status,
messageCount, messageText, messageNotifications.size(),
contactText);
chatViews.setTextViewText(R.id.text, status);
Notification notification = new Notification();
if (Build.VERSION.SDK_INT >= 14
&& SettingsManager.eventsPersistent()) {
// Ongoing icons are in the left side, so hide this one.
notification.icon = R.drawable.ic_placeholder;
notification.when = Long.MIN_VALUE;
} else {
// Ongoing icons are in the right side, so show this one.
updateNotification(notification, ticker);
notification.icon = connected > 0 ? R.drawable.ic_stat_message
: R.drawable.ic_stat_message_offline;
notification.when = System.currentTimeMillis();
}
notification.contentView = chatViews;
notification.contentIntent = PendingIntent.getActivity(application,
0, chatIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notification.deleteIntent = clearNotifications;
try {
notify(CHAT_NOTIFICATION_ID, notification);
} catch (RuntimeException e) {
LogManager.exception(this, e);
// Try to remove avatar in order to avoid
// OutOfMemoryError on the Android system side.
chatViews.setImageViewResource(R.id.icon,
R.drawable.ic_placeholder);
notify(CHAT_NOTIFICATION_ID, notification);
}
} }
return connectionState;
}
persistentNotification.icon = R.drawable.ic_stat_normal;
persistentNotification.setLatestEventInfo(application, application
.getString(R.string.application_name), connectionState,
PendingIntent.getActivity(application, 0, persistentIntent,
PendingIntent.FLAG_UPDATE_CURRENT));
persistentNotification.flags = Notification.FLAG_ONGOING_EVENT
| Notification.FLAG_NO_CLEAR;
persistentNotification.defaults = 0;
persistentNotification.sound = null;
persistentNotification.tickerText = null;
if (Build.VERSION.SDK_INT >= 14 && SettingsManager.eventsPersistent()) {
// Ongoing icons are in the left side, so always use it.
persistentNotification.when = startTime;
if (messageNotifications.isEmpty()) {
persistentNotification.icon = connected > 0 ? R.drawable.ic_stat_normal
: R.drawable.ic_stat_offline;
} else {
persistentNotification.icon = connected > 0 ? R.drawable.ic_stat_message
: R.drawable.ic_stat_message_offline;
}
updateNotification(persistentNotification, ticker);
} else {
// Ongoing icons are in the right side, so hide it if necessary.
if (messageNotifications.isEmpty()) {
persistentNotification.icon = connected > 0 ? R.drawable.ic_stat_normal
: R.drawable.ic_stat_offline;
persistentNotification.when = startTime;
// Show ticker for the messages in active chat.
updateNotification(persistentNotification, ticker);
} else {
persistentNotification.icon = R.drawable.ic_placeholder;
persistentNotification.when = Build.VERSION.SDK_INT >= 9 ? -Long.MAX_VALUE
: Long.MAX_VALUE;
}
}
if (SettingsManager.eventsPersistent()) {
notify(PERSISTENT_NOTIFICATION_ID, persistentNotification);
} else {
notificationManager.cancel(PERSISTENT_NOTIFICATION_ID);
}
}
private void notify(int id, Notification notification) { private void notify(int id, Notification notification) {
LogManager.i(this, "Notification: " + id + ", ticker: " LogManager.i(this, "Notification: " + id
+ notification.tickerText + ", sound: " + notification.sound + ", ticker: " + notification.tickerText
+ ", vibro: " + ", sound: " + notification.sound
+ (notification.defaults & Notification.DEFAULT_VIBRATE) + ", vibro: " + (notification.defaults & Notification.DEFAULT_VIBRATE)
+ ", light: " + ", light: " + (notification.defaults & Notification.DEFAULT_LIGHTS));
+ (notification.defaults & Notification.DEFAULT_LIGHTS));
try { try {
notificationManager.notify(id, notification); notificationManager.notify(id, notification);
} catch (SecurityException e) { } catch (SecurityException e) {
LogManager.exception(this, e);
} }
} }
/** private MessageNotification getMessageNotification(String account, String user) {
* Update notification according to ticker. for (MessageNotification messageNotification : messageNotifications) {
* if (messageNotification.equals(account, user)) {
* @param notification
* @param ticker
*/
private void updateNotification(Notification notification,
MessageItem ticker) {
if (ticker == null)
return;
if (ticker.getChat().getFirstNotification()
|| !SettingsManager.eventsFirstOnly())
setNotificationDefaults(
notification,
ChatManager.getInstance().isMakeVibro(
ticker.getChat().getAccount(),
ticker.getChat().getUser()),
PhraseManager.getInstance().getSound(
ticker.getChat().getAccount(),
ticker.getChat().getUser(), ticker.getText()),
AudioManager.STREAM_NOTIFICATION);
if (ChatManager.getInstance().isShowText(ticker.getChat().getAccount(),
ticker.getChat().getUser()))
notification.tickerText = trimText(ticker.getText());
}
private MessageNotification getMessageNotification(String account,
String user) {
for (MessageNotification messageNotification : messageNotifications)
if (messageNotification.equals(account, user))
return messageNotification; return messageNotification;
}
}
return null; return null;
} }
...@@ -515,33 +447,33 @@ public class NotificationManager implements OnInitializedListener, ...@@ -515,33 +447,33 @@ public class NotificationManager implements OnInitializedListener,
* @param messageItem * @param messageItem
* @param addNotification Whether notification should be stored. * @param addNotification Whether notification should be stored.
*/ */
public void onMessageNotification(MessageItem messageItem, public void onMessageNotification(MessageItem messageItem, boolean addNotification) {
boolean addNotification) {
if (addNotification) { if (addNotification) {
MessageNotification messageNotification = getMessageNotification( MessageNotification messageNotification = getMessageNotification(
messageItem.getChat().getAccount(), messageItem.getChat() messageItem.getChat().getAccount(), messageItem.getChat().getUser());
.getUser()); if (messageNotification == null) {
if (messageNotification == null) messageNotification = new MessageNotification(
messageNotification = new MessageNotification(messageItem messageItem.getChat().getAccount(), messageItem.getChat().getUser(), null, null, 0);
.getChat().getAccount(), messageItem.getChat() } else {
.getUser(), null, null, 0);
else
messageNotifications.remove(messageNotification); messageNotifications.remove(messageNotification);
}
messageNotification.addMessage(messageItem.getText()); messageNotification.addMessage(messageItem.getText());
messageNotifications.add(messageNotification); messageNotifications.add(messageNotification);
final String account = messageNotification.getAccount(); final String account = messageNotification.getAccount();
final String user = messageNotification.getUser(); final String user = messageNotification.getUser();
final String text = messageNotification.getText(); final String text = messageNotification.getText();
final Date timestamp = messageNotification.getTimestamp(); final Date timestamp = messageNotification.getTimestamp();
final int count = messageNotification.getCount(); final int count = messageNotification.getCount();
if (AccountManager.getInstance().getArchiveMode(account) != ArchiveMode.dontStore)
if (AccountManager.getInstance().getArchiveMode(account) != ArchiveMode.dontStore) {
Application.getInstance().runInBackground(new Runnable() { Application.getInstance().runInBackground(new Runnable() {
@Override @Override
public void run() { public void run() {
NotificationTable.getInstance().write(account, user, NotificationTable.getInstance().write(account, user, text, timestamp, count);
text, timestamp, count);
} }
}); });
}
} }
updateMessageNotification(messageItem); updateMessageNotification(messageItem);
} }
...@@ -614,12 +546,13 @@ public class NotificationManager implements OnInitializedListener, ...@@ -614,12 +546,13 @@ public class NotificationManager implements OnInitializedListener,
@Override @Override
public void onAccountRemoved(AccountItem accountItem) { public void onAccountRemoved(AccountItem accountItem) {
for (NotificationProvider<? extends NotificationItem> notificationProvider : providers) for (NotificationProvider<? extends NotificationItem> notificationProvider : providers) {
if (notificationProvider instanceof AccountNotificationProvider) { if (notificationProvider instanceof AccountNotificationProvider) {
((AccountNotificationProvider<? extends NotificationItem>) notificationProvider) ((AccountNotificationProvider) notificationProvider)
.clearAccountNotifications(accountItem.getAccount()); .clearAccountNotifications(accountItem.getAccount());
updateNotifications(notificationProvider, null); updateNotifications(notificationProvider, null);
} }
}
} }
@Override @Override
...@@ -629,24 +562,11 @@ public class NotificationManager implements OnInitializedListener, ...@@ -629,24 +562,11 @@ public class NotificationManager implements OnInitializedListener,
} }
public Notification getPersistentNotification() { public Notification getPersistentNotification() {
return persistentNotification; return persistentNotificationBuilder.build();
} }
@Override @Override
public void onClose() { public void onClose() {
notificationManager.cancelAll(); notificationManager.cancelAll();
} }
/**
* @param text
* @return Trimmed text.
*/
private static String trimText(String text) {
if (text.length() > MAX_NOTIFICATION_TEXT)
return text.substring(0, MAX_NOTIFICATION_TEXT - 3) + "...";
else
return text;
}
} }
...@@ -14,20 +14,6 @@ ...@@ -14,20 +14,6 @@
*/ */
package com.xabber.android.data.roster; package com.xabber.android.data.roster;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Type;
import org.jivesoftware.smack.packet.RosterPacket;
import org.jivesoftware.smack.packet.RosterPacket.ItemType;
import org.jivesoftware.smack.util.StringUtils;
import com.xabber.android.data.Application; import com.xabber.android.data.Application;
import com.xabber.android.data.NetworkException; import com.xabber.android.data.NetworkException;
import com.xabber.android.data.OnLoadListener; import com.xabber.android.data.OnLoadListener;
...@@ -46,6 +32,20 @@ import com.xabber.android.data.notification.NotificationManager; ...@@ -46,6 +32,20 @@ import com.xabber.android.data.notification.NotificationManager;
import com.xabber.androiddev.R; import com.xabber.androiddev.R;
import com.xabber.xmpp.address.Jid; import com.xabber.xmpp.address.Jid;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Type;
import org.jivesoftware.smack.packet.RosterPacket;
import org.jivesoftware.smack.packet.RosterPacket.ItemType;
import org.jivesoftware.smack.util.StringUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
/** /**
* Process contact's presence information. * Process contact's presence information.
* *
...@@ -86,7 +86,7 @@ public class PresenceManager implements OnArchiveModificationsReceivedListener, ...@@ -86,7 +86,7 @@ public class PresenceManager implements OnArchiveModificationsReceivedListener,
private PresenceManager() { private PresenceManager() {
subscriptionRequestProvider = new EntityNotificationProvider<SubscriptionRequest>( subscriptionRequestProvider = new EntityNotificationProvider<SubscriptionRequest>(
R.drawable.ic_stat_subscribe); R.drawable.ic_stat_ic_add_circle);
requestedSubscriptions = new HashMap<String, HashSet<String>>(); requestedSubscriptions = new HashMap<String, HashSet<String>>();
presenceContainers = new NestedMap<ResourceContainer>(); presenceContainers = new NestedMap<ResourceContainer>();
readyAccounts = new ArrayList<String>(); readyAccounts = new ArrayList<String>();
......
...@@ -61,6 +61,8 @@ public class OccupantList extends ManagedListActivity implements ...@@ -61,6 +61,8 @@ public class OccupantList extends ManagedListActivity implements
setContentView(R.layout.list); setContentView(R.layout.list);
listAdapter = new OccupantListAdapter(this, account, room); listAdapter = new OccupantListAdapter(this, account, room);
setListAdapter(listAdapter); setListAdapter(listAdapter);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} }
@Override @Override
......
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:layout_width="@dimen/notification_large_icon_width"
android:layout_height="@dimen/notification_large_icon_height"
android:background="@drawable/notify_panel_notification_icon_bg_tile"
android:gravity="center"
>
<ImageView
android:id="@+id/icon"
android:layout_width="48dip"
android:layout_height="48dip"
android:src="@drawable/avatar_1_1" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:paddingLeft="12dp"
android:paddingRight="12dp"
>
<LinearLayout
android:id="@+id/line1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView android:id="@+id/title"
android:textAppearance="@style/NotificationTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:layout_weight="1"
/>
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:singleLine="true"
android:gravity="center"
android:paddingLeft="8dp"
android:text="22:11:00"
android:textAppearance="@style/NotificationText"
/>
</LinearLayout>
<TextView android:id="@+id/text2"
android:textAppearance="@style/NotificationText2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-2dp"
android:layout_marginBottom="-2dp"
android:singleLine="true"
android:fadingEdge="horizontal"
android:ellipsize="marquee"
/>
<LinearLayout
android:id="@+id/line3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView android:id="@+id/text"
android:textAppearance="@style/NotificationText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2013, Redsolution LTD. All rights reserved.
This file is part of Xabber project; you can redistribute it and/or
modify it under the terms of the GNU General Public License, Version 3.
Xabber is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License,
along with this program. If not, see http://www.gnu.org/licenses/.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="3dp">
<ImageView
android:id="@+id/icon"
android:layout_width="48dip"
android:layout_height="48dip"
android:layout_marginRight="6dip"
android:layout_centerVertical="true"
android:src="@drawable/avatar_1_1"
/>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textStyle="bold"
android:singleLine="true"
android:gravity="bottom"
android:layout_toRightOf="@id/icon"
android:text="name"
style="@style/NotificationTitle"
/>
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:layout_toRightOf="@id/icon"
android:layout_below="@id/title"
android:layout_marginRight="10dip"
android:text="22:11:00"
style="@style/NotificationText"
/>
<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:layout_below="@id/title"
android:layout_toRightOf="@id/time"
android:ellipsize="marquee"
android:text="text text text text text text text text text text text"
style="@style/NotificationText"
/>
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:layout_below="@id/time"
android:layout_toRightOf="@id/icon"
android:text="1 message from 1 contact"
style="@style/NotificationText"
/>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"> <resources>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png -->
<string name="account_quantity_1">учетной записи</string> <string name="account_quantity_1">учетной записи</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png -->
...@@ -28,6 +28,10 @@ ...@@ -28,6 +28,10 @@
<string name="chat_message_quantity_5">сообщений</string> <string name="chat_message_quantity_5">сообщений</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_message.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_message.png -->
<string name="chat_status">%1$d %2$s от %3$d %4$s</string> <string name="chat_status">%1$d %2$s от %3$d %4$s</string>
<string name="chat_messages_from_contact">%1$d %2$s от %3$s</string>
<string name="chat_contact_and_message">%1$s: %2$s</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png -->
<string name="connection_state_connected_1">%1$d из %2$d %3$s подключена </string> <string name="connection_state_connected_1">%1$d из %2$d %3$s подключена </string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png -->
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"> <resources>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png -->
<string name="account_quantity_1">account</string> <string name="account_quantity_1">account</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png -->
...@@ -28,6 +28,10 @@ ...@@ -28,6 +28,10 @@
<string name="chat_message_quantity_5">-</string> <string name="chat_message_quantity_5">-</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_message.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_message.png -->
<string name="chat_status">%1$d %2$s from %3$d %4$s</string> <string name="chat_status">%1$d %2$s from %3$d %4$s</string>
<string name="chat_messages_from_contact">%1$d %2$s from %3$s</string>
<string name="chat_contact_and_message">%1$s: %2$s</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png -->
<string name="connection_state_connected_1">%1$d of %2$d %3$s online</string> <string name="connection_state_connected_1">%1$d of %2$d %3$s online</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/notification_bar_connected.png -->
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment