From b93a4f7aa95eb2ee652c47f1badcb0993803f693 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 30 May 2016 21:11:34 +0200 Subject: [PATCH 1/8] remove unicode control chars before sending --- src/main/java/eu/siacs/conversations/utils/XmlHelper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/eu/siacs/conversations/utils/XmlHelper.java b/src/main/java/eu/siacs/conversations/utils/XmlHelper.java index 4dee07cf7..198ce28b9 100644 --- a/src/main/java/eu/siacs/conversations/utils/XmlHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/XmlHelper.java @@ -7,6 +7,7 @@ public class XmlHelper { content = content.replace(">", ">"); content = content.replace("\"", """); content = content.replace("'", "'"); + content = content.replaceAll("\\p{Cc}", ""); return content; } } From 5cee3000f90dd4d1463d276fe6f3d941b4ca6182 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 30 May 2016 21:12:04 +0200 Subject: [PATCH 2/8] handle app links for conferences --- src/main/AndroidManifest.xml | 3 ++- .../services/XmppConnectionService.java | 10 +++++++++ .../ui/StartConversationActivity.java | 21 +++++++++++++------ .../eu/siacs/conversations/utils/XmppUri.java | 1 + 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 90727b8c0..963b138da 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -82,7 +82,8 @@ - + + diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 7eebe0696..757e29b52 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -3124,6 +3124,16 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return contacts; } + public Conversation findFirstMuc(Jid jid) { + for(Conversation conversation : getConversations()) { + if (conversation.getJid().toBareJid().equals(jid.toBareJid()) + && conversation.getMode() == Conversation.MODE_MULTI) { + return conversation; + } + } + return null; + } + public NotificationService getNotificationService() { return this.mNotificationService; } diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index 548682dfb..17f9944fd 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -846,7 +846,16 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU private boolean handleJid(Invite invite) { List contacts = xmppConnectionService.findContacts(invite.getJid()); - if (contacts.size() == 0) { + if (invite.isMuc()) { + Conversation muc = xmppConnectionService.findFirstMuc(invite.getJid()); + if (muc != null) { + switchToConversation(muc); + return true; + } else { + showJoinConferenceDialog(invite.getJid().toBareJid().toString()); + return false; + } + } else if (contacts.size() == 0) { showCreateContactDialog(invite.getJid().toString(),invite.getFingerprint()); return false; } else if (contacts.size() == 1) { @@ -1020,13 +1029,13 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU boolean invite() { if (jid != null) { - if (muc) { - showJoinConferenceDialog(jid); - } else { - return handleJid(this); - } + return handleJid(this); } return false; } + + public boolean isMuc() { + return muc; + } } } diff --git a/src/main/java/eu/siacs/conversations/utils/XmppUri.java b/src/main/java/eu/siacs/conversations/utils/XmppUri.java index 7a56d38f7..15a6c9a12 100644 --- a/src/main/java/eu/siacs/conversations/utils/XmppUri.java +++ b/src/main/java/eu/siacs/conversations/utils/XmppUri.java @@ -47,6 +47,7 @@ public class XmppUri { // sample : https://conversations.im/i/foo/bar.com jid = segments.get(1) + "@" + segments.get(2); } + muc = segments.size() > 1 && "j".equalsIgnoreCase(segments.get(0)); } else if ("xmpp".equalsIgnoreCase(scheme)) { // sample: xmpp:foo@bar.com muc = "join".equalsIgnoreCase(uri.getQuery()); From 6e7e9131378ccacdc2ae8d1375cfc8f822546834 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 30 May 2016 21:12:19 +0200 Subject: [PATCH 3/8] use whitespace as message seperator --- src/main/java/eu/siacs/conversations/entities/Message.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 3a924e530..21837386d 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -19,7 +19,7 @@ public class Message extends AbstractEntity { public static final String TABLENAME = "messages"; - public static final String MERGE_SEPARATOR = "\n\u0004\n"; + public static final String MERGE_SEPARATOR = "\n\u200B\n"; public static final int STATUS_RECEIVED = 0; public static final int STATUS_UNSEND = 1; From 1280b5a0f31c4ab1462762856ba03e480df58abf Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 30 May 2016 21:16:04 +0200 Subject: [PATCH 4/8] pulled translation from transifex --- src/main/res/values-ro-rRO/strings.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/res/values-ro-rRO/strings.xml b/src/main/res/values-ro-rRO/strings.xml index c37584936..3e988ae03 100644 --- a/src/main/res/values-ro-rRO/strings.xml +++ b/src/main/res/values-ro-rRO/strings.xml @@ -80,6 +80,7 @@ Dupa, incheie conversatia Alege prezenta pentru a contacta Trimite mesaje necriptate + Trimite mesaj catre %s Trimite mesaj criptat cu OTR Trimite mesaj criptat cu OMEMO Trimite mesaj criptat cu v\\OMEMO @@ -248,6 +249,7 @@ Acest semn de carte exista Tu Editeaza titlul conferintei + Subiectul acestei conferinte Alatura-te conferintei Paraseste Contactul a fost adaugat in lista @@ -611,4 +613,10 @@ Emitent O parola sigura a fost generata Dispozitivul dumneavoastra nu suporta dezactivarea optimizarii de baterie pentru aceasta aplicatie Arata parola + Inregistrarea a esuat: Incercati mai tarziu + Creeaza conferinta + Alatura-te sau creeaza conferinta + Subiect + Alege participanti + Se creeaza conferinta... From e49b45995d2da6c121c50ff9dbb75d88422243fe Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 30 May 2016 21:16:14 +0200 Subject: [PATCH 5/8] version bump to 1.12.8 --- CHANGELOG.md | 3 +++ build.gradle | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2f4c5c9a..b671f6e17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ###Changelog +####Version 1.12.8 +* more bug fixes :-( + ####Version 1.12.7 * bug fixes diff --git a/build.gradle b/build.gradle index 57a3021bc..4ba719c45 100644 --- a/build.gradle +++ b/build.gradle @@ -54,8 +54,8 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 23 - versionCode 148 - versionName "1.12.7" + versionCode 149 + versionName "1.12.8" archivesBaseName += "-$versionName" applicationId "eu.siacs.conversations" } From 17bce5437b47d33244f76cafceff811d8130074d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 31 May 2016 16:44:59 +0200 Subject: [PATCH 6/8] don't scroll to pos 0 when uuid wasn't found --- .../siacs/conversations/ui/ConversationFragment.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 5d5e4c297..8e0b30a88 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -13,6 +13,7 @@ import android.os.Bundle; import android.os.Handler; import android.support.annotation.Nullable; import android.text.InputType; +import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Gravity; @@ -157,7 +158,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa ConversationFragment.this.conversation.populateWithMessages(ConversationFragment.this.messageList); updateStatusMessages(); messageListAdapter.notifyDataSetChanged(); - int pos = getIndexOf(uuid,messageList); + int pos = Math.max(getIndexOf(uuid,messageList),0); messagesView.setSelectionFromTop(pos, pxOffset); messagesLoaded = true; if (messageLoaderToast != null) { @@ -210,7 +211,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } } - return 0; + return -1; } private final int KEYCHAIN_UNLOCK_NOT_REQUIRED = 0; @@ -802,11 +803,13 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa this.messagesLoaded = true; synchronized (this.messageList) { final Message first = conversation.getFirstUnreadMessage(); + final int bottom = Math.max(0, this.messageList.size() - 1); final int pos; if (first == null) { - pos = Math.max(0,this.messageList.size() - 1); + pos = bottom; } else { - pos = getIndexOf(first.getUuid(), this.messageList); + int i = getIndexOf(first.getUuid(), this.messageList); + pos = i < 0 ? bottom : i; } messagesView.setSelection(pos); } From a73fa531a972c7947b94dbe9ceb04e8c279a8d3c Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 31 May 2016 17:19:56 +0200 Subject: [PATCH 7/8] log failure reason in http upload on wrong response code --- .../java/eu/siacs/conversations/http/HttpUploadConnection.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java index e337509b5..87c6fc4aa 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java @@ -215,6 +215,7 @@ public class HttpUploadConnection implements Transferable { mXmppConnectionService.resendMessage(message, delayed); } } else { + Log.d(Config.LOGTAG,"http upload failed because response code was "+code); fail(); } } catch (IOException e) { From 0979f89c98c47678318c68f969621e3a81d51898 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 31 May 2016 17:20:21 +0200 Subject: [PATCH 8/8] execute phone contact changes in singlethreadexecutor --- .../services/XmppConnectionService.java | 97 +++++++++---------- .../conversations/utils/PhoneHelper.java | 4 +- .../ReplacingSerialSingleThreadExecutor.java | 14 +++ .../utils/SerialSingleThreadExecutor.java | 19 +++- 4 files changed, 79 insertions(+), 55 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/utils/ReplacingSerialSingleThreadExecutor.java diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 757e29b52..fa8ac0edd 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -96,6 +96,7 @@ import eu.siacs.conversations.utils.ExceptionHelper; import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener; import eu.siacs.conversations.utils.PRNGFixes; import eu.siacs.conversations.utils.PhoneHelper; +import eu.siacs.conversations.utils.ReplacingSerialSingleThreadExecutor; import eu.siacs.conversations.utils.SerialSingleThreadExecutor; import eu.siacs.conversations.utils.Xmlns; import eu.siacs.conversations.xml.Element; @@ -123,7 +124,7 @@ import eu.siacs.conversations.xmpp.stanzas.MessagePacket; import eu.siacs.conversations.xmpp.stanzas.PresencePacket; import me.leolin.shortcutbadger.ShortcutBadger; -public class XmppConnectionService extends Service implements OnPhoneContactsLoadedListener { +public class XmppConnectionService extends Service { public static final String ACTION_CLEAR_NOTIFICATION = "clear_notification"; public static final String ACTION_DISABLE_FOREGROUND = "disable_foreground"; @@ -135,6 +136,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa public static final String ACTION_GCM_MESSAGE_RECEIVED = "gcm_message_received"; private final SerialSingleThreadExecutor mFileAddingExecutor = new SerialSingleThreadExecutor(); private final SerialSingleThreadExecutor mDatabaseExecutor = new SerialSingleThreadExecutor(); + private ReplacingSerialSingleThreadExecutor mContactMergerExecutor = new ReplacingSerialSingleThreadExecutor(true); private final IBinder mBinder = new XmppConnectionBinder(); private final List conversations = new CopyOnWriteArrayList<>(); private final IqGenerator mIqGenerator = new IqGenerator(this); @@ -350,7 +352,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa private WakeLock wakeLock; private PowerManager pm; private LruCache mBitmapCache; - private Thread mPhoneContactMergerThread; private EventReceiver mEventReceiver = new EventReceiver(); private boolean mRestoredFromDatabase = false; @@ -1152,53 +1153,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa sendIqPacket(account, iqPacket, mDefaultIqHandler); } - public void onPhoneContactsLoaded(final List phoneContacts) { - if (mPhoneContactMergerThread != null) { - mPhoneContactMergerThread.interrupt(); - } - mPhoneContactMergerThread = new Thread(new Runnable() { - @Override - public void run() { - Log.d(Config.LOGTAG, "start merging phone contacts with roster"); - for (Account account : accounts) { - List withSystemAccounts = account.getRoster().getWithSystemAccounts(); - for (Bundle phoneContact : phoneContacts) { - if (Thread.interrupted()) { - Log.d(Config.LOGTAG, "interrupted merging phone contacts"); - return; - } - Jid jid; - try { - jid = Jid.fromString(phoneContact.getString("jid")); - } catch (final InvalidJidException e) { - continue; - } - final Contact contact = account.getRoster().getContact(jid); - String systemAccount = phoneContact.getInt("phoneid") - + "#" - + phoneContact.getString("lookup"); - contact.setSystemAccount(systemAccount); - if (contact.setPhotoUri(phoneContact.getString("photouri"))) { - getAvatarService().clear(contact); - } - contact.setSystemName(phoneContact.getString("displayname")); - withSystemAccounts.remove(contact); - } - for (Contact contact : withSystemAccounts) { - contact.setSystemAccount(null); - contact.setSystemName(null); - if (contact.setPhotoUri(null)) { - getAvatarService().clear(contact); - } - } - } - Log.d(Config.LOGTAG, "finished merging phone contacts"); - updateAccountUi(); - } - }); - mPhoneContactMergerThread.start(); - } - private void restoreFromDatabase() { synchronized (this.conversations) { final Map accountLookupTable = new Hashtable<>(); @@ -1219,7 +1173,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa account.initAccountServices(XmppConnectionService.this); //roster needs to be loaded at this stage } getBitmapCache().evictAll(); - Looper.prepare(); loadPhoneContacts(); Log.d(Config.LOGTAG, "restoring messages"); for (Conversation conversation : conversations) { @@ -1243,9 +1196,47 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public void loadPhoneContacts() { - PhoneHelper.loadPhoneContacts(getApplicationContext(), - new CopyOnWriteArrayList(), - XmppConnectionService.this); + mContactMergerExecutor.execute(new Runnable() { + @Override + public void run() { + PhoneHelper.loadPhoneContacts(XmppConnectionService.this, new OnPhoneContactsLoadedListener() { + @Override + public void onPhoneContactsLoaded(List phoneContacts) { + Log.d(Config.LOGTAG, "start merging phone contacts with roster"); + for (Account account : accounts) { + List withSystemAccounts = account.getRoster().getWithSystemAccounts(); + for (Bundle phoneContact : phoneContacts) { + Jid jid; + try { + jid = Jid.fromString(phoneContact.getString("jid")); + } catch (final InvalidJidException e) { + continue; + } + final Contact contact = account.getRoster().getContact(jid); + String systemAccount = phoneContact.getInt("phoneid") + + "#" + + phoneContact.getString("lookup"); + contact.setSystemAccount(systemAccount); + if (contact.setPhotoUri(phoneContact.getString("photouri"))) { + getAvatarService().clear(contact); + } + contact.setSystemName(phoneContact.getString("displayname")); + withSystemAccounts.remove(contact); + } + for (Contact contact : withSystemAccounts) { + contact.setSystemAccount(null); + contact.setSystemName(null); + if (contact.setPhotoUri(null)) { + getAvatarService().clear(contact); + } + } + } + Log.d(Config.LOGTAG, "finished merging phone contacts"); + updateAccountUi(); + } + }); + } + }); } public List getConversations() { diff --git a/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java b/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java index 6c1b4bef5..e3a24fcfa 100644 --- a/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java @@ -13,12 +13,14 @@ import android.os.Bundle; import android.provider.ContactsContract; import android.provider.ContactsContract.Profile; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.RejectedExecutionException; public class PhoneHelper { - public static void loadPhoneContacts(Context context, final List phoneContacts, final OnPhoneContactsLoadedListener listener) { + public static void loadPhoneContacts(Context context, final OnPhoneContactsLoadedListener listener) { + final List phoneContacts = new ArrayList<>(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { listener.onPhoneContactsLoaded(phoneContacts); diff --git a/src/main/java/eu/siacs/conversations/utils/ReplacingSerialSingleThreadExecutor.java b/src/main/java/eu/siacs/conversations/utils/ReplacingSerialSingleThreadExecutor.java new file mode 100644 index 000000000..dc8a0a825 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/utils/ReplacingSerialSingleThreadExecutor.java @@ -0,0 +1,14 @@ +package eu.siacs.conversations.utils; + +public class ReplacingSerialSingleThreadExecutor extends SerialSingleThreadExecutor { + + public ReplacingSerialSingleThreadExecutor(boolean prepareLooper) { + super(prepareLooper); + } + + @Override + public synchronized void execute(final Runnable r) { + tasks.clear(); + super.execute(r); + } +} diff --git a/src/main/java/eu/siacs/conversations/utils/SerialSingleThreadExecutor.java b/src/main/java/eu/siacs/conversations/utils/SerialSingleThreadExecutor.java index bfb4668db..55489ee30 100644 --- a/src/main/java/eu/siacs/conversations/utils/SerialSingleThreadExecutor.java +++ b/src/main/java/eu/siacs/conversations/utils/SerialSingleThreadExecutor.java @@ -1,5 +1,7 @@ package eu.siacs.conversations.utils; +import android.os.Looper; + import java.util.ArrayDeque; import java.util.Queue; import java.util.concurrent.Executor; @@ -8,9 +10,24 @@ import java.util.concurrent.Executors; public class SerialSingleThreadExecutor implements Executor { final Executor executor = Executors.newSingleThreadExecutor(); - final Queue tasks = new ArrayDeque(); + protected final Queue tasks = new ArrayDeque(); Runnable active; + public SerialSingleThreadExecutor() { + this(false); + } + + public SerialSingleThreadExecutor(boolean prepareLooper) { + if (prepareLooper) { + execute(new Runnable() { + @Override + public void run() { + Looper.prepare(); + } + }); + } + } + public synchronized void execute(final Runnable r) { tasks.offer(new Runnable() { public void run() {