diff options
Diffstat (limited to '')
16 files changed, 287 insertions, 49 deletions
diff --git a/src/main/java/de/pixart/messenger/entities/Account.java b/src/main/java/de/pixart/messenger/entities/Account.java index 4907d26b6..437dfa47a 100644 --- a/src/main/java/de/pixart/messenger/entities/Account.java +++ b/src/main/java/de/pixart/messenger/entities/Account.java @@ -183,7 +183,7 @@ public class Account extends AbstractEntity { case SESSION_FAILURE: return R.string.session_failure; case DOWNGRADE_ATTACK: - return R.string.downgrade_attack; + return R.string.sasl_downgrade; case HOST_UNKNOWN: return R.string.account_status_host_unknown; case POLICY_VIOLATION: diff --git a/src/main/java/de/pixart/messenger/entities/Presences.java b/src/main/java/de/pixart/messenger/entities/Presences.java index 3f3f670da..d57515392 100644 --- a/src/main/java/de/pixart/messenger/entities/Presences.java +++ b/src/main/java/de/pixart/messenger/entities/Presences.java @@ -144,6 +144,6 @@ public class Presences { } } } - return new Pair(typeMap, nameMap); + return new Pair<>(typeMap, nameMap); } } diff --git a/src/main/java/de/pixart/messenger/parser/AbstractParser.java b/src/main/java/de/pixart/messenger/parser/AbstractParser.java index 21da7fe67..8fd106922 100644 --- a/src/main/java/de/pixart/messenger/parser/AbstractParser.java +++ b/src/main/java/de/pixart/messenger/parser/AbstractParser.java @@ -22,18 +22,26 @@ public abstract class AbstractParser { } public static Long parseTimestamp(Element element, Long d) { - Element delay = element.findChild("delay", "urn:xmpp:delay"); - if (delay != null) { - String stamp = delay.getAttribute("stamp"); - if (stamp != null) { - try { - return AbstractParser.parseTimestamp(delay.getAttribute("stamp")); - } catch (ParseException e) { - return d; + long min = Long.MAX_VALUE; + boolean returnDefault = true; + for (Element child : element.getChildren()) { + if ("delay".equals(child.getName()) && "urn:xmpp:delay".equals(child.getNamespace())) { + String stamp = child.getAttribute("stamp"); + if (stamp != null) { + try { + min = Math.min(min, AbstractParser.parseTimestamp(stamp)); + returnDefault = false; + } catch (ParseException e) { + //ignore + } } } } - return d; + if (returnDefault) { + return d; + } else { + return min; + } } public static long parseTimestamp(Element element) { diff --git a/src/main/java/de/pixart/messenger/parser/IqParser.java b/src/main/java/de/pixart/messenger/parser/IqParser.java index bfb2fa71e..1783fed07 100644 --- a/src/main/java/de/pixart/messenger/parser/IqParser.java +++ b/src/main/java/de/pixart/messenger/parser/IqParser.java @@ -83,6 +83,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { } mXmppConnectionService.updateConversationUi(); mXmppConnectionService.updateRosterUi(); + mXmppConnectionService.getShortcutService().refresh(); } public String avatarData(final IqPacket packet) { diff --git a/src/main/java/de/pixart/messenger/parser/PresenceParser.java b/src/main/java/de/pixart/messenger/parser/PresenceParser.java index 8e1b0b006..a4534439e 100644 --- a/src/main/java/de/pixart/messenger/parser/PresenceParser.java +++ b/src/main/java/de/pixart/messenger/parser/PresenceParser.java @@ -213,12 +213,14 @@ public class PresenceParser extends AbstractParser implements final Element idle = packet.findChild("idle", Namespace.IDLE); if (idle != null) { - contact.flagInactive(); - final String since = idle.getAttribute("since"); try { + final String since = idle.getAttribute("since"); contact.setLastseen(AbstractParser.parseTimestamp(since)); + contact.flagInactive(); } catch (NullPointerException | ParseException e) { - contact.setLastseen(System.currentTimeMillis()); + if (contact.setLastseen(AbstractParser.parseTimestamp(packet))) { + contact.flagActive(); + } } } else { if (contact.setLastseen(AbstractParser.parseTimestamp(packet))) { diff --git a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java index ddf516f93..7b49eb376 100644 --- a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java +++ b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java @@ -48,6 +48,7 @@ import de.pixart.messenger.entities.Message; import de.pixart.messenger.entities.PresenceTemplate; import de.pixart.messenger.entities.Roster; import de.pixart.messenger.entities.ServiceDiscoveryResult; +import de.pixart.messenger.services.ShortcutService; import de.pixart.messenger.xmpp.jid.InvalidJidException; import de.pixart.messenger.xmpp.jid.Jid; import de.pixart.messenger.xmpp.mam.MamReference; @@ -1432,4 +1433,21 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.execSQL("delete from " + START_TIMES_TABLE); } } + + public List<ShortcutService.FrequentContact> getFrequentContacts(int days) { + SQLiteDatabase db = this.getReadableDatabase(); + final String SQL = "select " + Conversation.TABLENAME + "." + Conversation.ACCOUNT + "," + Conversation.TABLENAME + "." + Conversation.CONTACTJID + " from " + Conversation.TABLENAME + " join " + Message.TABLENAME + " on conversations.uuid=messages.conversationUuid where messages.status!=0 and carbon==0 and conversations.mode=0 and messages.timeSent>=? group by conversations.uuid order by count(body) desc limit 4;"; + String[] whereArgs = new String[]{String.valueOf(System.currentTimeMillis() - (Config.MILLISECONDS_IN_DAY * days))}; + Cursor cursor = db.rawQuery(SQL, whereArgs); + ArrayList<ShortcutService.FrequentContact> contacts = new ArrayList<>(); + while (cursor.moveToNext()) { + try { + contacts.add(new ShortcutService.FrequentContact(cursor.getString(0), Jid.fromString(cursor.getString(1)))); + } catch (Exception e) { + Log.d(Config.LOGTAG, e.getMessage()); + } + } + cursor.close(); + return contacts; + } } diff --git a/src/main/java/de/pixart/messenger/services/AvatarService.java b/src/main/java/de/pixart/messenger/services/AvatarService.java index 15c49940f..3d3af8d26 100644 --- a/src/main/java/de/pixart/messenger/services/AvatarService.java +++ b/src/main/java/de/pixart/messenger/services/AvatarService.java @@ -3,9 +3,12 @@ package de.pixart.messenger.services; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.Typeface; import android.net.Uri; +import android.util.DisplayMetrics; import android.util.Log; import java.util.ArrayList; @@ -69,6 +72,24 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { return avatar; } + public Bitmap getRoundedShortcut(final Contact contact) { + DisplayMetrics metrics = mXmppConnectionService.getResources().getDisplayMetrics(); + int size = Math.round(metrics.density * 48); + Bitmap bitmap = get(contact, size); + Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(output); + + final Paint paint = new Paint(); + final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); + + paint.setAntiAlias(true); + canvas.drawARGB(0, 0, 0, 0); + canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, bitmap.getWidth() / 2, paint); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + canvas.drawBitmap(bitmap, rect, rect, paint); + return output; + } + public Bitmap get(final MucOptions.User user, final int size, boolean cachedOnly) { Contact c = user.getContact(); if (c != null && (c.getProfilePhoto() != null || c.getAvatar() != null || user.getAvatar() == null)) { diff --git a/src/main/java/de/pixart/messenger/services/MessageArchiveService.java b/src/main/java/de/pixart/messenger/services/MessageArchiveService.java index e90bb8d07..b5ee9ac52 100644 --- a/src/main/java/de/pixart/messenger/services/MessageArchiveService.java +++ b/src/main/java/de/pixart/messenger/services/MessageArchiveService.java @@ -101,6 +101,22 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { } } + public boolean isCatchingUp(Conversation conversation) { + final Account account = conversation.getAccount(); + if (account.getXmppConnection().isWaitingForSmCatchup()) { + return true; + } else { + synchronized (this.queries) { + for (Query query : this.queries) { + if (query.getAccount() == account && query.isCatchup() && ((conversation.getMode() == Conversation.MODE_SINGLE && query.getWith() == null) || query.getConversation() == conversation)) { + return true; + } + } + } + return false; + } + } + public Query query(final Conversation conversation, long end, boolean allowCatchup) { return this.query(conversation, conversation.getLastMessageTransmitted(), end, allowCatchup); } diff --git a/src/main/java/de/pixart/messenger/services/NotificationService.java b/src/main/java/de/pixart/messenger/services/NotificationService.java index 917bc9c30..ace144942 100644 --- a/src/main/java/de/pixart/messenger/services/NotificationService.java +++ b/src/main/java/de/pixart/messenger/services/NotificationService.java @@ -52,13 +52,14 @@ import de.pixart.messenger.xmpp.XmppConnection; public class NotificationService { + public static final Object CATCHUP_LOCK = new Object(); + private static final String CONVERSATIONS_GROUP = "de.pixart.messenger"; + private final XmppConnectionService mXmppConnectionService; + private final LinkedHashMap<String, ArrayList<Message>> notifications = new LinkedHashMap<>(); private static final int NOTIFICATION_ID_MULTIPLIER = 1024 * 1024; public static final int NOTIFICATION_ID = 2 * NOTIFICATION_ID_MULTIPLIER; public static final int FOREGROUND_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 4; public static final int ERROR_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 6; - private static final String CONVERSATIONS_GROUP = "de.pixart.messenger"; - private final XmppConnectionService mXmppConnectionService; - private final LinkedHashMap<String, ArrayList<Message>> notifications = new LinkedHashMap<>(); private Conversation mOpenConversation; private boolean mIsInForeground; private long mLastNotification; @@ -179,7 +180,7 @@ public class NotificationService { } public void push(final Message message) { - synchronized (message.getConversation().getAccount()) { + synchronized (CATCHUP_LOCK) { final XmppConnection connection = message.getConversation().getAccount().getXmppConnection(); if (connection.isWaitingForSmCatchup()) { connection.incrementSmCatchupMessageCounter(); diff --git a/src/main/java/de/pixart/messenger/services/ShortcutService.java b/src/main/java/de/pixart/messenger/services/ShortcutService.java new file mode 100644 index 000000000..56345c663 --- /dev/null +++ b/src/main/java/de/pixart/messenger/services/ShortcutService.java @@ -0,0 +1,131 @@ +package de.pixart.messenger.services; + +import android.annotation.TargetApi; +import android.content.Intent; +import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager; +import android.graphics.drawable.Icon; +import android.net.Uri; +import android.os.Build; +import android.util.Log; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import de.pixart.messenger.Config; +import de.pixart.messenger.entities.Account; +import de.pixart.messenger.entities.Contact; +import de.pixart.messenger.ui.StartConversationActivity; +import de.pixart.messenger.utils.ReplacingSerialSingleThreadExecutor; +import de.pixart.messenger.xmpp.jid.Jid; + +public class ShortcutService { + private final XmppConnectionService xmppConnectionService; + private final ReplacingSerialSingleThreadExecutor replacingSerialSingleThreadExecutor = new ReplacingSerialSingleThreadExecutor(false); + + public ShortcutService(XmppConnectionService xmppConnectionService) { + this.xmppConnectionService = xmppConnectionService; + } + + public void refresh() { + refresh(false); + } + + public void refresh(final boolean forceUpdate) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + final Runnable r = new Runnable() { + @Override + public void run() { + refreshImpl(forceUpdate); + } + }; + replacingSerialSingleThreadExecutor.execute(r); + } + } + + @TargetApi(25) + public void report(Contact contact) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + ShortcutManager shortcutManager = xmppConnectionService.getSystemService(ShortcutManager.class); + shortcutManager.reportShortcutUsed(getShortcutId(contact)); + } + } + + @TargetApi(25) + private void refreshImpl(boolean forceUpdate) { + List<FrequentContact> frequentContacts = xmppConnectionService.databaseBackend.getFrequentContacts(30); + HashMap<String, Account> accounts = new HashMap<>(); + for (Account account : xmppConnectionService.getAccounts()) { + accounts.put(account.getUuid(), account); + } + List<Contact> contacts = new ArrayList<>(); + for (FrequentContact frequentContact : frequentContacts) { + Account account = accounts.get(frequentContact.account); + if (account != null) { + contacts.add(account.getRoster().getContact(frequentContact.contact)); + } + } + ShortcutManager shortcutManager = xmppConnectionService.getSystemService(ShortcutManager.class); + boolean needsUpdate = forceUpdate || contactsChanged(contacts, shortcutManager.getDynamicShortcuts()); + if (!needsUpdate) { + Log.d(Config.LOGTAG, "skipping shortcut update"); + return; + } + List<ShortcutInfo> newDynamicShortCuts = new ArrayList<>(); + for (Contact contact : contacts) { + ShortcutInfo shortcut = new ShortcutInfo.Builder(xmppConnectionService, getShortcutId(contact)) + .setShortLabel(contact.getDisplayName()) + .setIntent(getShortcutIntent(contact)) + .setIcon(Icon.createWithBitmap(xmppConnectionService.getAvatarService().getRoundedShortcut(contact))) + .build(); + newDynamicShortCuts.add(shortcut); + } + if (shortcutManager.setDynamicShortcuts(newDynamicShortCuts)) { + Log.d(Config.LOGTAG, "updated dynamic shortcuts"); + } else { + Log.d(Config.LOGTAG, "unable to update dynamic shortcuts"); + } + } + + private static boolean contactsChanged(List<Contact> needles, List<ShortcutInfo> haystack) { + for (Contact needle : needles) { + if (!contactExists(needle, haystack)) { + return true; + } + } + return needles.size() != haystack.size(); + } + + @TargetApi(25) + private static boolean contactExists(Contact needle, List<ShortcutInfo> haystack) { + for (ShortcutInfo shortcutInfo : haystack) { + if (getShortcutId(needle).equals(shortcutInfo.getId()) && needle.getDisplayName().equals(shortcutInfo.getShortLabel())) { + return true; + } + } + return false; + } + + private static String getShortcutId(Contact contact) { + return contact.getAccount().getJid().toBareJid().toPreppedString() + "#" + contact.getJid().toBareJid().toPreppedString(); + } + + private Intent getShortcutIntent(Contact contact) { + Intent intent = new Intent(xmppConnectionService, StartConversationActivity.class); + intent.setAction(Intent.ACTION_VIEW); + intent.setData(Uri.parse("xmpp:" + contact.getJid().toBareJid().toString())); + intent.putExtra("account", contact.getAccount().getJid().toBareJid().toString()); + return intent; + } + + public static class FrequentContact { + private final String account; + private final Jid contact; + + public FrequentContact(String account, Jid contact) { + this.account = account; + this.contact = contact; + } + } +} diff --git a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java index 61a9d2318..27412e1ea 100644 --- a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java +++ b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java @@ -70,6 +70,7 @@ import java.util.ListIterator; import java.util.Locale; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import de.duenndns.ssl.MemorizingTrustManager; @@ -189,8 +190,9 @@ public class XmppConnectionService extends Service { }; private FileBackend fileBackend = new FileBackend(this); private MemorizingTrustManager mMemorizingTrustManager; - private NotificationService mNotificationService = new NotificationService( - this); + private NotificationService mNotificationService = new NotificationService(this); + private ShortcutService mShortcutService = new ShortcutService(this); + private AtomicBoolean mInitialAddressbookSyncCompleted = new AtomicBoolean(false); private OnMessagePacketReceived mMessageParser = new MessageParser(this); private OnPresencePacketReceived mPresenceParser = new PresenceParser(this); private IqParser mIqParser = new IqParser(this); @@ -1663,6 +1665,7 @@ public class XmppConnectionService extends Service { } } Log.d(Config.LOGTAG, "finished merging phone contacts"); + mShortcutService.refresh(mInitialAddressbookSyncCompleted.compareAndSet(false, true)); updateAccountUi(); } }); @@ -3788,10 +3791,11 @@ public class XmppConnectionService extends Service { return this.mMessageArchiveService; } - public List<Contact> findContacts(Jid jid) { + public List<Contact> findContacts(Jid jid, String accountJid) { ArrayList<Contact> contacts = new ArrayList<>(); for (Account account : getAccounts()) { - if (!account.isOptionSet(Account.OPTION_DISABLED)) { + if (!account.isOptionSet(Account.OPTION_DISABLED) + && (accountJid == null || accountJid.equals(account.getJid().toBareJid().toString()))) { Contact contact = account.getRoster().getContactFromRoster(jid); if (contact != null) { contacts.add(contact); @@ -4176,6 +4180,10 @@ public class XmppConnectionService extends Service { } } + public ShortcutService getShortcutService() { + return mShortcutService; + } + public interface OnMamPreferencesFetched { void onPreferencesFetched(Element prefs); diff --git a/src/main/java/de/pixart/messenger/ui/ConversationActivity.java b/src/main/java/de/pixart/messenger/ui/ConversationActivity.java index 52899f21e..96645c1e7 100644 --- a/src/main/java/de/pixart/messenger/ui/ConversationActivity.java +++ b/src/main/java/de/pixart/messenger/ui/ConversationActivity.java @@ -901,6 +901,7 @@ public class ConversationActivity extends XmppActivity .findViewById(R.id.end_conversation_checkbox); if (conversation.getMode() == Conversation.MODE_SINGLE) { endConversationCheckBox.setVisibility(View.VISIBLE); + endConversationCheckBox.setChecked(true); } builder.setView(dialogView); builder.setNegativeButton(getString(R.string.cancel), null); diff --git a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java index 084c27a99..bfdcd41f1 100644 --- a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java +++ b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java @@ -1307,9 +1307,10 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa action = SendButtonAction.TEXT; } } - if (activity.useSendButtonToIndicateStatus() && c != null - && c.getAccount().getStatus() == Account.State.ONLINE) { - if (c.getMode() == Conversation.MODE_SINGLE) { + if (activity.useSendButtonToIndicateStatus() && c.getAccount().getStatus() == Account.State.ONLINE) { + if (activity.xmppConnectionService != null && activity.xmppConnectionService.getMessageArchiveService().isCatchingUp(c)) { + status = Presence.Status.OFFLINE; + } else if (c.getMode() == Conversation.MODE_SINGLE) { status = c.getContact().getShownStatus(); } else { status = c.getMucOptions().online() ? Presence.Status.ONLINE : Presence.Status.OFFLINE; diff --git a/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java b/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java index f3cbf7be9..73400dde3 100644 --- a/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java +++ b/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java @@ -831,7 +831,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU case Intent.ACTION_VIEW: Uri uri = intent.getData(); if (uri != null) { - return new Invite(intent.getData(), false).invite(); + Invite invite = new Invite(intent.getData(), false); + invite.account = intent.getStringExtra("account"); + return invite.invite(); } else { return false; } @@ -870,7 +872,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU finish(); return true; } - List<Contact> contacts = xmppConnectionService.findContacts(invite.getJid()); + List<Contact> contacts = xmppConnectionService.findContacts(invite.getJid(), invite.account); if (invite.isMuc()) { Conversation muc = xmppConnectionService.findFirstMuc(invite.getJid()); if (muc != null) { @@ -893,6 +895,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU Toast.makeText(this,R.string.verified_fingerprints,Toast.LENGTH_SHORT).show(); } } + if (invite.account != null) { + xmppConnectionService.getShortcutService().report(contact); + } switchToConversation(contact, invite.getBody()); } return true; @@ -1182,6 +1187,8 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU super(uri, safeSource); } + public String account; + boolean invite() { if (getJid() != null) { return handleJid(this); diff --git a/src/main/java/de/pixart/messenger/xml/XmlReader.java b/src/main/java/de/pixart/messenger/xml/XmlReader.java index efd4dcc95..440fdd2fe 100644 --- a/src/main/java/de/pixart/messenger/xml/XmlReader.java +++ b/src/main/java/de/pixart/messenger/xml/XmlReader.java @@ -65,11 +65,17 @@ public class XmlReader { wakeLock.acquire(); if (parser.getEventType() == XmlPullParser.START_TAG) { Tag tag = Tag.start(parser.getName()); + final String xmlns = parser.getNamespace(); for (int i = 0; i < parser.getAttributeCount(); ++i) { - tag.setAttribute(parser.getAttributeName(i), - parser.getAttributeValue(i)); + final String prefix = parser.getAttributePrefix(i); + String name; + if (prefix != null && !prefix.isEmpty()) { + name = prefix + ":" + parser.getAttributeName(i); + } else { + name = parser.getAttributeName(i); + } + tag.setAttribute(name, parser.getAttributeValue(i)); } - String xmlns = parser.getNamespace(); if (xmlns != null) { tag.setAttribute("xmlns", xmlns); } diff --git a/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java b/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java index 75eb63e5e..09b90b3ba 100644 --- a/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java +++ b/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java @@ -65,6 +65,7 @@ import de.pixart.messenger.entities.Account; import de.pixart.messenger.entities.Message; import de.pixart.messenger.entities.ServiceDiscoveryResult; import de.pixart.messenger.generator.IqGenerator; +import de.pixart.messenger.services.NotificationService; import de.pixart.messenger.services.XmppConnectionService; import de.pixart.messenger.ui.EditAccountActivity; import de.pixart.messenger.utils.DNSHelper; @@ -165,7 +166,8 @@ public class XmppConnection implements Runnable { @Override public String[] getClientAliases(String s, Principal[] principals) { - return new String[0]; + final String alias = account.getPrivateKeyAlias(); + return alias != null ? new String[]{alias} : new String[0]; } @Override @@ -226,26 +228,30 @@ public class XmppConnection implements Runnable { mXmppConnectionService = service; } - protected synchronized void changeStatus(final Account.State nextStatus) { - if (Thread.currentThread().isInterrupted()) { - Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": not changing status to " + nextStatus + " because thread was interrupted"); - return; - } - if (account.getStatus() != nextStatus) { - if ((nextStatus == Account.State.OFFLINE) - && (account.getStatus() != Account.State.CONNECTING) - && (account.getStatus() != Account.State.ONLINE) - && (account.getStatus() != Account.State.DISABLED)) { + protected void changeStatus(final Account.State nextStatus) { + synchronized (this) { + if (Thread.currentThread().isInterrupted()) { + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": not changing status to " + nextStatus + " because thread was interrupted"); return; } - if (nextStatus == Account.State.ONLINE) { - this.attempt = 0; - } - account.setStatus(nextStatus); - if (statusListener != null) { - statusListener.onStatusChanged(account); + if (account.getStatus() != nextStatus) { + if ((nextStatus == Account.State.OFFLINE) + && (account.getStatus() != Account.State.CONNECTING) + && (account.getStatus() != Account.State.ONLINE) + && (account.getStatus() != Account.State.DISABLED)) { + return; + } + if (nextStatus == Account.State.ONLINE) { + this.attempt = 0; + } + account.setStatus(nextStatus); + } else { + return; } } + if (statusListener != null) { + statusListener.onStatusChanged(account); + } } public void prepareNewConnection() { @@ -647,15 +653,20 @@ public class XmppConnection implements Runnable { final AckPacket ack = new AckPacket(this.stanzasReceived, smVersion); tagWriter.writeStanzaAsync(ack); } else if (nextTag.isStart("a")) { - synchronized (account) { + boolean accountUiNeedsRefresh = false; + synchronized (NotificationService.CATCHUP_LOCK) { if (mWaitingForSmCatchup.compareAndSet(true, false)) { int count = mSmCatchupMessageCounter.get(); Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": SM catchup complete (" + count + ")"); + accountUiNeedsRefresh = true; if (count > 0) { mXmppConnectionService.getNotificationService().finishBacklog(true, account); } } } + if (accountUiNeedsRefresh) { + mXmppConnectionService.updateAccountUi(); + } final Element ack = tagReader.readElement(nextTag); lastPacketReceived = SystemClock.elapsedRealtime(); try { @@ -1063,7 +1074,13 @@ public class XmppConnection implements Runnable { } else { Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure (" + packet.toString()); } - account.setResource(account.getResource().split("\\.")[0]); + final Element error = packet.findChild("error"); + final String resource = account.getResource().split("\\.")[0]; + if (packet.getType() == IqPacket.TYPE.ERROR && error != null && error.hasChild("conflict")) { + account.setResource(resource + "." + nextRandomId()); + } else { + account.setResource(resource); + } throw new StateChangingError(Account.State.BIND_FAILURE); } }); |