From 2ab65609e49c4356e7e80d5416a4f700e76f3f6a Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 9 Oct 2019 20:40:42 +0200 Subject: [PATCH 01/25] always show 'contact details' on avatar long press in non-anon --- .../ui/util/MucDetailsContextMenuHelper.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/util/MucDetailsContextMenuHelper.java b/src/main/java/eu/siacs/conversations/ui/util/MucDetailsContextMenuHelper.java index c3e874310..04efcc0c5 100644 --- a/src/main/java/eu/siacs/conversations/ui/util/MucDetailsContextMenuHelper.java +++ b/src/main/java/eu/siacs/conversations/ui/util/MucDetailsContextMenuHelper.java @@ -13,6 +13,7 @@ import android.view.View; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.MucOptions; @@ -71,8 +72,8 @@ public final class MucDetailsContextMenuHelper { startConversation.setVisible(true); final Contact contact = user.getContact(); final User self = conversation.getMucOptions().getSelf(); - if (contact != null && contact.showInRoster()) { - showContactDetails.setVisible(!contact.isSelf()); + if ((contact != null && contact.showInRoster()) || mucOptions.isPrivateAndNonAnonymous()) { + showContactDetails.setVisible(contact == null || !contact.isSelf()); } if ((activity instanceof ConferenceDetailsActivity || activity instanceof MucUsersActivity) && user.getRole() == MucOptions.Role.NONE) { invite.setVisible(true); @@ -135,7 +136,9 @@ public final class MucDetailsContextMenuHelper { Jid jid = user.getRealJid(); switch (item.getItemId()) { case R.id.action_contact_details: - Contact contact = user.getContact(); + final Jid realJid = user.getRealJid(); + final Account account = conversation.getAccount(); + final Contact contact = realJid == null ? null : account.getRoster().getContact(realJid); if (contact != null) { activity.switchToContactDetails(contact, fingerprint); } From ddffe198c6b257356c2e031d7948d9bca90c4102 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 10 Oct 2019 12:54:43 +0200 Subject: [PATCH 02/25] change background if no results found in channel search. fixes #3559 --- .../ui/ChannelDiscoveryActivity.java | 9 +++- .../no_results_primary_background_dark.xml | 41 +++++++++++++++++++ .../no_results_primary_background_light.xml | 41 +++++++++++++++++++ src/main/res/values/attrs.xml | 1 + src/main/res/values/themes.xml | 2 + 5 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/main/res/drawable/no_results_primary_background_dark.xml create mode 100644 src/main/res/drawable/no_results_primary_background_light.xml diff --git a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java index b1684473d..e019b426e 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java @@ -32,6 +32,7 @@ import eu.siacs.conversations.services.ChannelDiscoveryService; import eu.siacs.conversations.ui.adapter.ChannelSearchResultAdapter; import eu.siacs.conversations.ui.util.PendingItem; import eu.siacs.conversations.ui.util.SoftKeyboardUtils; +import eu.siacs.conversations.ui.util.StyledAttributes; import eu.siacs.conversations.utils.AccountUtils; import rocks.xmpp.addr.Jid; @@ -128,6 +129,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O private void toggleLoadingScreen() { adapter.submitList(Collections.emptyList()); binding.progressBar.setVisibility(View.VISIBLE); + binding.list.setBackgroundColor(StyledAttributes.getColor(this, R.attr.color_background_primary)); } @Override @@ -172,11 +174,16 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O } @Override - public void onChannelSearchResultsFound(List results) { + public void onChannelSearchResultsFound(final List results) { runOnUiThread(() -> { adapter.submitList(results); binding.list.setVisibility(View.VISIBLE); binding.progressBar.setVisibility(View.GONE); + if (results.size() == 0) { + binding.list.setBackground(StyledAttributes.getDrawable(this, R.attr.activity_primary_background_no_results)); + } else { + binding.list.setBackgroundColor(StyledAttributes.getColor(this, R.attr.color_background_primary)); + } }); } diff --git a/src/main/res/drawable/no_results_primary_background_dark.xml b/src/main/res/drawable/no_results_primary_background_dark.xml new file mode 100644 index 000000000..48597d05c --- /dev/null +++ b/src/main/res/drawable/no_results_primary_background_dark.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + diff --git a/src/main/res/drawable/no_results_primary_background_light.xml b/src/main/res/drawable/no_results_primary_background_light.xml new file mode 100644 index 000000000..efe31413a --- /dev/null +++ b/src/main/res/drawable/no_results_primary_background_light.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + diff --git a/src/main/res/values/attrs.xml b/src/main/res/values/attrs.xml index 1f78b19a2..ce15d0013 100644 --- a/src/main/res/values/attrs.xml +++ b/src/main/res/values/attrs.xml @@ -22,6 +22,7 @@ + diff --git a/src/main/res/values/themes.xml b/src/main/res/values/themes.xml index b03c2476e..6ebf7505c 100644 --- a/src/main/res/values/themes.xml +++ b/src/main/res/values/themes.xml @@ -18,6 +18,7 @@ @drawable/search_background_light @drawable/no_results_background_light + @drawable/no_results_primary_background_light @drawable/list_item_background_light @color/black @@ -127,6 +128,7 @@ @color/black26 @drawable/search_background_dark @drawable/no_results_background_dark + @drawable/no_results_primary_background_dark @drawable/list_item_background_dark @color/red_a100 From e0b5010f24d55ca4c973e83fdba33760e9c7a84a Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 11 Oct 2019 15:37:41 +0200 Subject: [PATCH 03/25] =?UTF-8?q?don=E2=80=99t=20mark=20pgp=20encrypted=20?= =?UTF-8?q?files=20received=20from=20dino=20as=20deleted?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../siacs/conversations/crypto/PgpDecryptionService.java | 3 +++ .../conversations/services/XmppConnectionService.java | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java b/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java index 2989f356a..29d286a71 100644 --- a/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java +++ b/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java @@ -201,6 +201,9 @@ public class PgpDecryptionService { if (fixedFile.getParentFile().mkdirs()) { Log.d(Config.LOGTAG,"created parent directories for "+fixedFile.getAbsolutePath()); } + synchronized (mXmppConnectionService.FILENAMES_TO_IGNORE_DELETION) { + mXmppConnectionService.FILENAMES_TO_IGNORE_DELETION.add(outputFile.getAbsolutePath()); + } if (outputFile.renameTo(fixedFile)) { Log.d(Config.LOGTAG, "renamed " + outputFile.getAbsolutePath() + " to " + fixedFile.getAbsolutePath()); message.setRelativeFilePath(path); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 5eef556e2..4400e21a2 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -277,6 +277,9 @@ public class XmppConnectionService extends Service { private final Object LISTENER_LOCK = new Object(); + public final Set FILENAMES_TO_IGNORE_DELETION = new HashSet<>(); + + private final OnBindListener mOnBindListener = new OnBindListener() { @Override @@ -1831,6 +1834,12 @@ public class XmppConnectionService extends Service { } private void markFileDeleted(final String path) { + synchronized (FILENAMES_TO_IGNORE_DELETION) { + if (FILENAMES_TO_IGNORE_DELETION.remove(path)) { + Log.d(Config.LOGTAG,"ignored deletion of "+path); + return; + } + } final File file = new File(path); final boolean isInternalFile = fileBackend.isInternalFile(file); final List uuids = databaseBackend.markFileAsDeleted(file, isInternalFile); From 9bea8074aba331e959a5dd41fc40277c9e799631 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 11 Oct 2019 19:39:45 +0200 Subject: [PATCH 04/25] fixed loading channel results from cache --- .../eu/siacs/conversations/ui/ChannelDiscoveryActivity.java | 5 ++--- src/main/res/layout/activity_channel_discovery.xml | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java index e019b426e..8834e22eb 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java @@ -166,10 +166,10 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (optedIn) { + toggleLoadingScreen(); + SoftKeyboardUtils.hideSoftKeyboard(this); xmppConnectionService.discoverChannels(v.getText().toString(), this); } - toggleLoadingScreen(); - SoftKeyboardUtils.hideSoftKeyboard(this); return true; } @@ -177,7 +177,6 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O public void onChannelSearchResultsFound(final List results) { runOnUiThread(() -> { adapter.submitList(results); - binding.list.setVisibility(View.VISIBLE); binding.progressBar.setVisibility(View.GONE); if (results.size() == 0) { binding.list.setBackground(StyledAttributes.getDrawable(this, R.attr.activity_primary_background_no_results)); diff --git a/src/main/res/layout/activity_channel_discovery.xml b/src/main/res/layout/activity_channel_discovery.xml index 055b9aff2..34b680622 100644 --- a/src/main/res/layout/activity_channel_discovery.xml +++ b/src/main/res/layout/activity_channel_discovery.xml @@ -34,7 +34,6 @@ android:background="?attr/color_background_primary" android:orientation="vertical" android:scrollbars="vertical" - android:visibility="gone" app:layoutManager="android.support.v7.widget.LinearLayoutManager" /> From 537c8bb300f86564cd7e654dfde202f31906324d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 15 Oct 2019 11:04:12 +0000 Subject: [PATCH 05/25] recommend ejabberd in FAQ --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6a63d59c8..145b04888 100644 --- a/README.md +++ b/README.md @@ -125,11 +125,13 @@ Using your own domain not only gives you a more recognizable Jabber ID, it also Learn more about [conversations.im Jabber/XMPP domain hosting](https://account.conversations.im/domain/). ##### Running your own -If you already have a server somewhere and are willing and able to put the necessary work in, one alternative-in the spirit of federation-is to run your own. We recommend either [Prosody](https://prosody.im/) or [ejabberd](https://www.ejabberd.im/). Both of which have their own strengths. Ejabberd is slightly more mature nowadays but Prosody is arguably easier to set up. +If you already have a server somewhere and are willing and able to put the necessary work in you can run your own XMPP server. -For Prosody you need a couple of so called [community modules](https://modules.prosody.im/) most of which are maintained by the same people that develop Prosody. +As of 2019 we recommend you use [ejabberd](https://ejabberd.im). The default configuration file already enables everything you need to pass the [Conversations Compliance Suite](https://compliance.conversations.im). Make sure your Linux distribution ships a fairly recent version. -If you pick ejabberd make sure you use the latest version. Linux Distributions might bundle some very old versions of it. +With a little bit of effort [Prosody](https://prosody.im) can be configured to support all necessary extensions as well. However you will have to rely on so called [Community Modules](https://modules.prosody.im/) of varying quality. Prosody can be interesting to people who like to modify their server and create / prototype own modules. + +Performance wise - for small deployments - both ejabberd and Prosody should be fine. #### Where can I set up a custom hostname / port Conversations will automatically look up the SRV records for your domain name From 7e37a325a032401cb4e73902755d0e9dffb5ad15 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 15 Oct 2019 20:46:23 +0200 Subject: [PATCH 06/25] updated btc address in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 145b04888..3ff20ede1 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ about bank transfer (SEPA). ##### Crypto currencies -Bitcoin: `1AeqNAcg85APAZj9BZfAjdFCC5zesqXp2B` +Bitcoin: `3KAD8vew6tPZDjiUJNnZ3YUoUxrCEVNwFL` Bitcoin Cash: `16ABkXzYAwWz8Y5DcWFfbBRqL63g3hzEaU` From 574ec6612322acc18625be1cdb484e3718236c26 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 18 Oct 2019 10:33:27 +0000 Subject: [PATCH 07/25] add github sponsors --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 8ade90d85..2cebde6f9 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,3 @@ +github: inputmice liberapay: inputmice custom: https://paypal.me/ConversationsIM From 9c24ebd57bbacd35375d54b7391951d58ed7329d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 21 Oct 2019 19:23:21 +0000 Subject: [PATCH 08/25] README: removed personal JID and ref website instead --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ff20ede1..07414ad93 100644 --- a/README.md +++ b/README.md @@ -210,7 +210,7 @@ section of this document. #### I need professional support with Conversations or setting up my server -I'm available for hire. Contact me at `inputmice@siacs.eu`. +I'm available for hire. Contact information can be found on [my website](https://gultsch.de). #### How does the address book integration work? From 2f59d66fd16ace3572230ab93d7106b80ee63a23 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 23 Oct 2019 22:33:51 +0200 Subject: [PATCH 09/25] catch dead system exception when creating error notification --- .../services/NotificationService.java | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 79f1dd526..4d31bfb6a 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -563,14 +563,16 @@ public class NotificationService { if (addedActionsCount < 3) { final Message firstLocationMessage = getFirstLocationMessage(messages); if (firstLocationMessage != null) { - String label = mXmppConnectionService.getResources().getString(R.string.show_location); - PendingIntent pendingShowLocationIntent = createShowLocationIntent(firstLocationMessage); - NotificationCompat.Action locationAction = new NotificationCompat.Action.Builder( - R.drawable.ic_room_white_24dp, - label, - pendingShowLocationIntent).build(); - mBuilder.addAction(locationAction); - ++addedActionsCount; + final PendingIntent pendingShowLocationIntent = createShowLocationIntent(firstLocationMessage); + if (pendingShowLocationIntent != null) { + final String label = mXmppConnectionService.getResources().getString(R.string.show_location); + NotificationCompat.Action locationAction = new NotificationCompat.Action.Builder( + R.drawable.ic_room_white_24dp, + label, + pendingShowLocationIntent).build(); + mBuilder.addAction(locationAction); + ++addedActionsCount; + } } } if (addedActionsCount < 3) { @@ -766,7 +768,7 @@ public class NotificationService { return PendingIntent.getActivity(mXmppConnectionService, generateRequestCode(message.getConversation(), 18), intent, PendingIntent.FLAG_UPDATE_CURRENT); } } - return createOpenConversationsIntent(); + return null; } private PendingIntent createContentIntent(final String conversationUuid, final String downloadMessageUuid) { @@ -906,7 +908,10 @@ public class NotificationService { } } mBuilder.setContentText(mXmppConnectionService.getString(R.string.connected_accounts, connected, enabled)); - mBuilder.setContentIntent(createOpenConversationsIntent()); + final PendingIntent openIntent = createOpenConversationsIntent(); + if (openIntent != null) { + mBuilder.setContentIntent(openIntent); + } mBuilder.setWhen(0); mBuilder.setPriority(Notification.PRIORITY_MIN); mBuilder.setSmallIcon(connected > 0 ? R.drawable.ic_link_white_24dp : R.drawable.ic_link_off_white_24dp); @@ -920,7 +925,11 @@ public class NotificationService { } private PendingIntent createOpenConversationsIntent() { - return PendingIntent.getActivity(mXmppConnectionService, 0, new Intent(mXmppConnectionService, ConversationsActivity.class), 0); + try { + return PendingIntent.getActivity(mXmppConnectionService, 0, new Intent(mXmppConnectionService, ConversationsActivity.class), 0); + } catch (RuntimeException e) { + return null; + } } void updateErrorNotification() { From ab516299e7b210977a0a711e8a101bc41961afb4 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 23 Oct 2019 22:34:25 +0200 Subject: [PATCH 10/25] catch all exceptions when closing closable --- .../java/eu/siacs/conversations/persistance/FileBackend.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index 37168016a..3c049bf48 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -356,7 +356,8 @@ public class FileBackend { if (stream != null) { try { stream.close(); - } catch (IOException e) { + } catch (Exception e) { + Log.d(Config.LOGTAG, "unable to close stream", e); } } } @@ -366,6 +367,7 @@ public class FileBackend { try { socket.close(); } catch (IOException e) { + Log.d(Config.LOGTAG, "unable to close socket", e); } } } @@ -375,6 +377,7 @@ public class FileBackend { try { socket.close(); } catch (IOException e) { + Log.d(Config.LOGTAG, "unable to close server socket", e); } } } From db3ca3f165f07d3ed6d5e75448efeec0335d5b9b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 23 Oct 2019 22:34:43 +0200 Subject: [PATCH 11/25] store message bodies up to 1MB --- src/main/java/eu/siacs/conversations/Config.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index f757af494..b4d7d506e 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -90,7 +90,7 @@ public final class Config { public static final int REFRESH_UI_INTERVAL = 500; public static final int MAX_DISPLAY_MESSAGE_CHARS = 4096; - public static final int MAX_STORAGE_MESSAGE_CHARS = 1024 * 1024 * 1024; + public static final int MAX_STORAGE_MESSAGE_CHARS = 1024 * 1024; //1MB public static final long MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000; From 2bed0dad127905dd0b04cdd56e3cebed5c5c6687 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 26 Oct 2019 13:23:27 +0200 Subject: [PATCH 12/25] attempt to fix some rare crashes --- .../java/eu/siacs/conversations/entities/MucOptions.java | 2 +- .../conversations/services/XmppConnectionService.java | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index 81463d9e9..116906fef 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -335,7 +335,7 @@ public class MucOptions { } public boolean isContactInRoom(Contact contact) { - return findUserByRealJid(contact.getJid().asBareJid()) != null; + return contact != null && findUserByRealJid(contact.getJid().asBareJid()) != null; } public boolean isUserInRoom(Jid jid) { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 4400e21a2..dbf6a1af4 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1960,9 +1960,13 @@ public class XmppConnectionService extends Service { * This will find all conferences with the contact as member and also the conference that is the contact (that 'fake' contact is used to store the avatar) */ public List findAllConferencesWith(Contact contact) { - ArrayList results = new ArrayList<>(); + final ArrayList results = new ArrayList<>(); for (final Conversation c : conversations) { - if (c.getMode() == Conversation.MODE_MULTI && (c.getJid().asBareJid().equals(contact.getJid().asBareJid()) || c.getMucOptions().isContactInRoom(contact))) { + if (c.getMode() != Conversation.MODE_MULTI) { + continue; + } + final MucOptions mucOptions = c.getMucOptions(); + if (c.getJid().asBareJid().equals(contact.getJid().asBareJid()) || (mucOptions != null && mucOptions.isContactInRoom(contact))) { results.add(c); } } From c83caad3f574591798923ccffb0a87c51480c08b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 26 Oct 2019 14:11:14 +0200 Subject: [PATCH 13/25] changed explanation for grace period --- src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 0aa3f5418..799ee5071 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -119,7 +119,7 @@ Ringtone Play sound when a new message arrives Grace Period - The length of time Conversations keeps quiet after seeing activity on another device + The length of time notifications are silenced after detecting activity on one of your other devices. Advanced Never send crash reports By sending in stack traces you are helping the ongoing development of Conversations From ecad9cbe3cedd2029faa58053ddbdf6a231d91fa Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 1 Nov 2019 10:40:17 +0100 Subject: [PATCH 14/25] =?UTF-8?q?catch=20security=20exception=20when=20pas?= =?UTF-8?q?sing=20on=20share=20intent=20that=20didn=E2=80=99t=20give=20us?= =?UTF-8?q?=20permission?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/ChooseAccountForProfilePictureActivity.java | 8 +++++++- .../java/eu/siacs/conversations/ui/ShareWithActivity.java | 7 ++++++- src/main/res/values/strings.xml | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java index cfb4f05fb..fca082c42 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java @@ -5,6 +5,7 @@ import android.net.Uri; import android.os.Bundle; import android.support.v7.app.ActionBar; import android.widget.ListView; +import android.widget.Toast; import java.util.ArrayList; import java.util.List; @@ -78,7 +79,12 @@ public class ChooseAccountForProfilePictureActivity extends XmppActivity { intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toString()); intent.setData(uri); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - startActivity(intent); + try { + startActivity(intent); + } catch (SecurityException e) { + Toast.makeText(this, R.string.sharing_application_not_grant_permission, Toast.LENGTH_SHORT).show(); + return; + } } finish(); } diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java index 0ec7abd9a..dd4ea40a2 100644 --- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java @@ -200,7 +200,12 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer intent.putExtra(Intent.EXTRA_TEXT, share.text); intent.putExtra(ConversationsActivity.EXTRA_AS_QUOTE, share.asQuote); } - startActivity(intent); + try { + startActivity(intent); + } catch (SecurityException e) { + Toast.makeText(this, R.string.sharing_application_not_grant_permission, Toast.LENGTH_SHORT).show(); + return; + } finish(); } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 799ee5071..3674aab53 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -878,4 +878,5 @@ Please enter the password for this account Unable to perform this action Join public channel… + The sharing application did not grant permission to access this file. From adfbe59e5785e4858718d4ad5113f51ae37c91b9 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 1 Nov 2019 11:03:54 +0100 Subject: [PATCH 15/25] mark silent notifications as local only this will prevent silent notifications (for example those supressed by grace period) showing up on my smart watch --- src/main/java/eu/siacs/conversations/parser/MessageParser.java | 3 +++ .../eu/siacs/conversations/services/NotificationService.java | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index b9bedec1a..84bee6408 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -827,6 +827,9 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece final Jid sender = InvalidJid.getNullForInvalid(displayed.getAttributeAsJid("sender")); if (packet.fromAccount(account) && !selfAddressed) { dismissNotification(account, counterpart, query); + if (query == null) { + activateGracePeriod(account); + } } else if (isTypeGroupChat) { Conversation conversation = mXmppConnectionService.find(account, counterpart.asBareJid()); if (conversation != null && id != null && sender != null) { diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 4d31bfb6a..e61a6b296 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -442,6 +442,8 @@ public class NotificationService { } catch (SecurityException e) { Log.d(Config.LOGTAG, "unable to use custom notification sound " + uri.toString()); } + } else { + mBuilder.setLocalOnly(true); } if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mBuilder.setCategory(Notification.CATEGORY_MESSAGE); From 07786d457664efee11afced9df65213cbfbf1626 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 2 Nov 2019 09:43:37 +0100 Subject: [PATCH 16/25] optionally search local muc rooms instead of jabber.network --- .../eu/siacs/conversations/entities/Room.java | 90 +++++++ .../conversations/generator/IqGenerator.java | 14 ++ .../http/services/MuclumbusService.java | 56 +---- .../siacs/conversations/parser/IqParser.java | 55 ++++ .../conversations/services/AvatarService.java | 7 +- .../services/ChannelDiscoveryService.java | 148 ++++++++++- .../services/XmppConnectionService.java | 14 +- .../ui/ChannelDiscoveryActivity.java | 53 ++-- .../adapter/ChannelSearchResultAdapter.java | 23 +- .../conversations/utils/AccountUtils.java | 8 +- .../eu/siacs/conversations/xml/Namespace.java | 2 + .../res/menu/channel_discovery_activity.xml | 18 +- src/main/res/values/arrays.xml | 10 + src/main/res/values/defaults.xml | 1 + src/main/res/values/strings.xml | 5 + src/main/res/xml/preferences.xml | 235 +++++++++--------- 16 files changed, 513 insertions(+), 226 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/entities/Room.java diff --git a/src/main/java/eu/siacs/conversations/entities/Room.java b/src/main/java/eu/siacs/conversations/entities/Room.java new file mode 100644 index 000000000..74ce07c91 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/entities/Room.java @@ -0,0 +1,90 @@ +package eu.siacs.conversations.entities; + +import com.google.common.base.Objects; +import com.google.common.base.Strings; +import com.google.common.collect.ComparisonChain; + +import java.util.Comparator; + +import eu.siacs.conversations.services.AvatarService; +import eu.siacs.conversations.utils.LanguageUtils; +import eu.siacs.conversations.utils.UIHelper; +import rocks.xmpp.addr.Jid; + +public class Room implements AvatarService.Avatarable, Comparable { + + public String address; + public String name; + public String description; + public String language; + public int nusers; + + public Room(String address, String name, String description, String language, int nusers) { + this.address = address; + this.name = name; + this.description = description; + this.language = language; + this.nusers = nusers; + } + + public Room() { + + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public Jid getRoom() { + try { + return Jid.of(address); + } catch (IllegalArgumentException e) { + return null; + } + } + + public String getLanguage() { + return LanguageUtils.convert(language); + } + + @Override + public int getAvatarBackgroundColor() { + Jid room = getRoom(); + return UIHelper.getColorForName(room != null ? room.asBareJid().toEscapedString() : name); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Room room = (Room) o; + return Objects.equal(address, room.address) && + Objects.equal(name, room.name) && + Objects.equal(description, room.description); + } + + @Override + public int hashCode() { + return Objects.hashCode(address, name, description); + } + + + public boolean contains(String needle) { + return Strings.nullToEmpty(name).contains(needle) + || Strings.nullToEmpty(description).contains(needle) + || Strings.nullToEmpty(address).contains(needle); + } + + @Override + public int compareTo(Room o) { + return ComparisonChain.start() + .compare(o.nusers, nusers) + .compare(Strings.nullToEmpty(name), Strings.nullToEmpty(o.name)) + .compare(Strings.nullToEmpty(address), Strings.nullToEmpty(o.address)) + .result(); + } +} \ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 7c7456776..1f9de7e6c 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -565,4 +565,18 @@ public class IqGenerator extends AbstractGenerator { } return packet; } + + public IqPacket queryDiscoItems(Jid jid) { + IqPacket packet = new IqPacket(IqPacket.TYPE.GET); + packet.setTo(jid); + packet.addChild("query",Namespace.DISCO_ITEMS); + return packet; + } + + public IqPacket queryDiscoInfo(Jid jid) { + IqPacket packet = new IqPacket(IqPacket.TYPE.GET); + packet.setTo(jid); + packet.addChild("query",Namespace.DISCO_INFO); + return packet; + } } diff --git a/src/main/java/eu/siacs/conversations/http/services/MuclumbusService.java b/src/main/java/eu/siacs/conversations/http/services/MuclumbusService.java index 89a8e0ec4..9fae92319 100644 --- a/src/main/java/eu/siacs/conversations/http/services/MuclumbusService.java +++ b/src/main/java/eu/siacs/conversations/http/services/MuclumbusService.java @@ -1,20 +1,15 @@ package eu.siacs.conversations.http.services; -import com.google.common.base.Objects; - import java.util.Collections; import java.util.List; import java.util.Set; -import eu.siacs.conversations.services.AvatarService; -import eu.siacs.conversations.utils.LanguageUtils; -import eu.siacs.conversations.utils.UIHelper; +import eu.siacs.conversations.entities.Room; import retrofit2.Call; import retrofit2.http.Body; import retrofit2.http.GET; import retrofit2.http.POST; import retrofit2.http.Query; -import rocks.xmpp.addr.Jid; public interface MuclumbusService { @@ -31,55 +26,6 @@ public interface MuclumbusService { public List items; } - class Room implements AvatarService.Avatarable { - - public String address; - public String name; - public String description; - public String language; - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - - public Jid getRoom() { - try { - return Jid.of(address); - } catch (IllegalArgumentException e) { - return null; - } - } - - public String getLanguage() { - return LanguageUtils.convert(language); - } - - @Override - public int getAvatarBackgroundColor() { - Jid room = getRoom(); - return UIHelper.getColorForName(room != null ? room.asBareJid().toEscapedString() : name); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Room room = (Room) o; - return Objects.equal(address, room.address) && - Objects.equal(name, room.name) && - Objects.equal(description, room.description); - } - - @Override - public int hashCode() { - return Objects.hashCode(address, name, description); - } - } - class SearchRequest { public final Set keywords; diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java index 3042e510f..e5ef662bb 100644 --- a/src/main/java/eu/siacs/conversations/parser/IqParser.java +++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java @@ -1,6 +1,7 @@ package eu.siacs.conversations.parser; import android.support.annotation.NonNull; +import android.text.TextUtils; import android.util.Base64; import android.util.Log; import android.util.Pair; @@ -27,12 +28,15 @@ import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Room; +import eu.siacs.conversations.services.ChannelDiscoveryService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.InvalidJid; import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; +import eu.siacs.conversations.xmpp.forms.Data; import eu.siacs.conversations.xmpp.stanzas.IqPacket; import rocks.xmpp.addr.Jid; @@ -417,4 +421,55 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { } } + + public static List items(IqPacket packet) { + ArrayList items = new ArrayList<>(); + final Element query = packet.findChild("query", Namespace.DISCO_ITEMS); + if (query == null) { + return items; + } + for(Element child : query.getChildren()) { + if ("item".equals(child.getName())) { + Jid jid = child.getAttributeAsJid("jid"); + if (jid != null) { + items.add(jid); + } + } + } + return items; + } + + public static Room parseRoom(IqPacket packet) { + final Element query = packet.findChild("query", Namespace.DISCO_INFO); + if(query == null) { + return null; + } + final Element x = query.findChild("x"); + if (x == null) { + return null; + } + final Element identity = query.findChild("identity"); + Data data = Data.parse(x); + String address = packet.getFrom().toEscapedString(); + String name = identity == null ? null : identity.getAttribute("name"); + String roomName = data.getValue("muc#roomconfig_roomname");; + String description = data.getValue("muc#roominfo_description"); + String language = data.getValue("muc#roominfo_lang"); + String occupants = data.getValue("muc#roominfo_occupants"); + int nusers; + try { + nusers = occupants == null ? 0 : Integer.parseInt(occupants); + } catch (NumberFormatException e) { + nusers = 0; + } + + return new Room( + address, + TextUtils.isEmpty(roomName) ? name : roomName, + description, + language, + nusers + ); + } + } diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java index 0e349e508..ca2d534b2 100644 --- a/src/main/java/eu/siacs/conversations/services/AvatarService.java +++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java @@ -38,6 +38,7 @@ import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.RawBlockable; +import eu.siacs.conversations.entities.Room; import eu.siacs.conversations.http.services.MuclumbusService; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded; @@ -81,14 +82,14 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { return get((ListItem) avatarable, size, cachedOnly); } else if (avatarable instanceof MucOptions.User) { return get((MucOptions.User) avatarable, size, cachedOnly); - } else if (avatarable instanceof MuclumbusService.Room) { - return get((MuclumbusService.Room) avatarable, size, cachedOnly); + } else if (avatarable instanceof Room) { + return get((Room) avatarable, size, cachedOnly); } throw new AssertionError("AvatarService does not know how to generate avatar from "+avatarable.getClass().getName()); } - private Bitmap get(final MuclumbusService.Room result, final int size, boolean cacheOnly) { + private Bitmap get(final Room result, final int size, boolean cacheOnly) { final Jid room = result.getRoom(); Conversation conversation = room != null ? mXmppConnectionService.findFirstMuc(room) : null; if (conversation != null) { diff --git a/src/main/java/eu/siacs/conversations/services/ChannelDiscoveryService.java b/src/main/java/eu/siacs/conversations/services/ChannelDiscoveryService.java index f5dd08485..f01bd72cc 100644 --- a/src/main/java/eu/siacs/conversations/services/ChannelDiscoveryService.java +++ b/src/main/java/eu/siacs/conversations/services/ChannelDiscoveryService.java @@ -7,14 +7,27 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.io.IOException; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import eu.siacs.conversations.Config; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Room; import eu.siacs.conversations.http.HttpConnectionManager; import eu.siacs.conversations.http.services.MuclumbusService; +import eu.siacs.conversations.parser.IqParser; +import eu.siacs.conversations.utils.LanguageUtils; +import eu.siacs.conversations.utils.UIHelper; +import eu.siacs.conversations.xmpp.OnIqPacketReceived; +import eu.siacs.conversations.xmpp.XmppConnection; +import eu.siacs.conversations.xmpp.stanzas.IqPacket; import okhttp3.OkHttpClient; import okhttp3.ResponseBody; import retrofit2.Call; @@ -22,6 +35,7 @@ import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; +import rocks.xmpp.addr.Jid; public class ChannelDiscoveryService { @@ -30,7 +44,7 @@ public class ChannelDiscoveryService { private MuclumbusService muclumbusService; - private final Cache> cache; + private final Cache> cache; ChannelDiscoveryService(XmppConnectionService service) { this.service = service; @@ -56,21 +70,28 @@ public class ChannelDiscoveryService { this.muclumbusService = retrofit.create(MuclumbusService.class); } - void discover(String query, OnChannelSearchResultsFound onChannelSearchResultsFound) { - final boolean all = query == null || query.trim().isEmpty(); - List result = cache.getIfPresent(all ? "" : query); + void cleanCache() { + cache.invalidateAll(); + } + + void discover(@NonNull final String query, Method method, OnChannelSearchResultsFound onChannelSearchResultsFound) { + List result = cache.getIfPresent(key(method, query)); if (result != null) { onChannelSearchResultsFound.onChannelSearchResultsFound(result); return; } - if (all) { - discoverChannels(onChannelSearchResultsFound); + if (method == Method.LOCAL_SERVER) { + discoverChannelsLocalServers(query, onChannelSearchResultsFound); } else { - discoverChannels(query, onChannelSearchResultsFound); + if (query.isEmpty()) { + discoverChannelsJabberNetwork(onChannelSearchResultsFound); + } else { + discoverChannelsJabberNetwork(query, onChannelSearchResultsFound); + } } } - private void discoverChannels(OnChannelSearchResultsFound listener) { + private void discoverChannelsJabberNetwork(OnChannelSearchResultsFound listener) { Call call = muclumbusService.getRooms(1); try { call.enqueue(new Callback() { @@ -82,7 +103,7 @@ public class ChannelDiscoveryService { logError(response); return; } - cache.put("", body.items); + cache.put(key(Method.JABBER_NETWORK, ""), body.items); listener.onChannelSearchResultsFound(body.items); } @@ -97,7 +118,7 @@ public class ChannelDiscoveryService { } } - private void discoverChannels(final String query, OnChannelSearchResultsFound listener) { + private void discoverChannelsJabberNetwork(final String query, OnChannelSearchResultsFound listener) { MuclumbusService.SearchRequest searchRequest = new MuclumbusService.SearchRequest(query); Call searchResultCall = muclumbusService.search(searchRequest); @@ -110,7 +131,7 @@ public class ChannelDiscoveryService { logError(response); return; } - cache.put(query, body.result.items); + cache.put(key(Method.JABBER_NETWORK, query), body.result.items); listener.onChannelSearchResultsFound(body.result.items); } @@ -122,6 +143,102 @@ public class ChannelDiscoveryService { }); } + private void discoverChannelsLocalServers(final String query, final OnChannelSearchResultsFound listener) { + final Map localMucService = getLocalMucServices(); + Log.d(Config.LOGTAG, "checking with " + localMucService.size() + " muc services"); + if (localMucService.size() == 0) { + listener.onChannelSearchResultsFound(Collections.emptyList()); + return; + } + if (!query.isEmpty()) { + final List cached = cache.getIfPresent(key(Method.LOCAL_SERVER, "")); + if (cached != null) { + final List results = copyMatching(cached, query); + cache.put(key(Method.LOCAL_SERVER, query), results); + listener.onChannelSearchResultsFound(results); + } + } + final AtomicInteger queriesInFlight = new AtomicInteger(); + final List rooms = new ArrayList<>(); + for (Map.Entry entry : localMucService.entrySet()) { + IqPacket itemsRequest = service.getIqGenerator().queryDiscoItems(entry.getKey()); + queriesInFlight.incrementAndGet(); + service.sendIqPacket(entry.getValue(), itemsRequest, (account, itemsResponse) -> { + if (itemsResponse.getType() == IqPacket.TYPE.RESULT) { + final List items = IqParser.items(itemsResponse); + for (Jid item : items) { + IqPacket infoRequest = service.getIqGenerator().queryDiscoInfo(item); + queriesInFlight.incrementAndGet(); + service.sendIqPacket(account, infoRequest, new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(Account account, IqPacket infoResponse) { + if (infoResponse.getType() == IqPacket.TYPE.RESULT) { + final Room room = IqParser.parseRoom(infoResponse); + if (room != null) { + rooms.add(room); + } + if (queriesInFlight.decrementAndGet() <= 0) { + finishDiscoSearch(rooms, query, listener); + } + } else { + queriesInFlight.decrementAndGet(); + } + } + }); + } + } + if (queriesInFlight.decrementAndGet() <= 0) { + finishDiscoSearch(rooms, query, listener); + } + }); + } + } + + private void finishDiscoSearch(List rooms, String query, OnChannelSearchResultsFound listener) { + Collections.sort(rooms); + cache.put(key(Method.LOCAL_SERVER, ""), rooms); + if (query.isEmpty()) { + listener.onChannelSearchResultsFound(rooms); + } else { + List results = copyMatching(rooms, query); + cache.put(key(Method.LOCAL_SERVER, query), results); + listener.onChannelSearchResultsFound(rooms); + } + } + + private static List copyMatching(List haystack, String needle) { + ArrayList result = new ArrayList<>(); + for (Room room : haystack) { + if (room.contains(needle)) { + result.add(room); + } + } + return result; + } + + private Map getLocalMucServices() { + final HashMap localMucServices = new HashMap<>(); + for (Account account : service.getAccounts()) { + if (account.isEnabled()) { + final XmppConnection xmppConnection = account.getXmppConnection(); + if (xmppConnection == null) { + continue; + } + for (final String mucService : xmppConnection.getMucServers()) { + Jid jid = Jid.of(mucService); + if (!localMucServices.containsKey(jid)) { + localMucServices.put(jid, account); + } + } + } + } + return localMucServices; + } + + private static String key(Method method, String query) { + return String.format("%s\00%s", method, query); + } + private static void logError(final Response response) { final ResponseBody errorBody = response.errorBody(); Log.d(Config.LOGTAG, "code from muclumbus=" + response.code()); @@ -129,13 +246,18 @@ public class ChannelDiscoveryService { return; } try { - Log.d(Config.LOGTAG,"error body="+errorBody.string()); + Log.d(Config.LOGTAG, "error body=" + errorBody.string()); } catch (IOException e) { //ignored } } public interface OnChannelSearchResultsFound { - void onChannelSearchResultsFound(List results); + void onChannelSearchResultsFound(List results); + } + + public enum Method { + JABBER_NETWORK, + LOCAL_SERVER } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index dbf6a1af4..e79a0bfaa 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -34,6 +34,7 @@ import android.provider.ContactsContract; import android.security.KeyChain; import android.support.annotation.BoolRes; import android.support.annotation.IntegerRes; +import android.support.annotation.NonNull; import android.support.v4.app.RemoteInput; import android.support.v4.content.ContextCompat; import android.text.TextUtils; @@ -42,6 +43,8 @@ import android.util.Log; import android.util.LruCache; import android.util.Pair; +import com.google.common.base.Strings; + import org.conscrypt.Conscrypt; import org.openintents.openpgp.IOpenPgpService2; import org.openintents.openpgp.util.OpenPgpApi; @@ -857,8 +860,8 @@ public class XmppConnectionService extends Service { mChannelDiscoveryService.initializeMuclumbusService(); } - public void discoverChannels(String query, ChannelDiscoveryService.OnChannelSearchResultsFound onChannelSearchResultsFound) { - mChannelDiscoveryService.discover(query, onChannelSearchResultsFound); + public void discoverChannels(String query, ChannelDiscoveryService.Method method, ChannelDiscoveryService.OnChannelSearchResultsFound onChannelSearchResultsFound) { + mChannelDiscoveryService.discover(Strings.nullToEmpty(query).trim(), method, onChannelSearchResultsFound); } public boolean isDataSaverDisabled() { @@ -2244,6 +2247,7 @@ public class XmppConnectionService extends Service { getNotificationService().updateErrorNotification(); toggleForegroundService(); syncEnabledAccountSetting(); + mChannelDiscoveryService.cleanCache(); return true; } else { return false; @@ -3086,9 +3090,7 @@ public class XmppConnectionService extends Service { } public void fetchConferenceConfiguration(final Conversation conversation, final OnConferenceConfigurationFetched callback) { - IqPacket request = new IqPacket(IqPacket.TYPE.GET); - request.setTo(conversation.getJid().asBareJid()); - request.query("http://jabber.org/protocol/disco#info"); + IqPacket request = mIqGenerator.queryDiscoInfo(conversation.getJid().asBareJid()); sendIqPacket(conversation.getAccount(), request, new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { @@ -4437,7 +4439,7 @@ public class XmppConnectionService extends Service { request.setTo(jid); final String node = presence.getNode(); final String ver = presence.getVer(); - final Element query = request.query("http://jabber.org/protocol/disco#info"); + final Element query = request.query(Namespace.DISCO_INFO); if (node != null && ver != null) { query.setAttribute("node", node + "#" + ver); } diff --git a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java index 8834e22eb..f09263ea3 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java @@ -7,6 +7,7 @@ import android.content.SharedPreferences; import android.databinding.DataBindingUtil; import android.net.Uri; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.v7.widget.Toolbar; import android.text.Html; import android.view.KeyEvent; @@ -27,7 +28,7 @@ import eu.siacs.conversations.databinding.ActivityChannelDiscoveryBinding; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Bookmark; import eu.siacs.conversations.entities.Conversation; -import eu.siacs.conversations.http.services.MuclumbusService; +import eu.siacs.conversations.entities.Room; import eu.siacs.conversations.services.ChannelDiscoveryService; import eu.siacs.conversations.ui.adapter.ChannelSearchResultAdapter; import eu.siacs.conversations.ui.util.PendingItem; @@ -46,6 +47,8 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O private MenuItem mMenuSearchView; private EditText mSearchEditText; + private ChannelDiscoveryService.Method method = ChannelDiscoveryService.Method.LOCAL_SERVER; + private boolean optedIn = false; @Override @@ -55,14 +58,15 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O @Override void onBackendConnected() { - if (optedIn) { - String query; + if (optedIn || method == ChannelDiscoveryService.Method.LOCAL_SERVER) { + final String query; if (mMenuSearchView != null && mMenuSearchView.isActionViewExpanded()) { query = mSearchEditText.getText().toString(); } else { query = mInitialSearchValue.peek(); } - xmppConnectionService.discoverChannels(query, this); + toggleLoadingScreen(); + xmppConnectionService.discoverChannels(query, this.method, this); } } @@ -74,29 +78,39 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O configureActionBar(getSupportActionBar(), true); binding.list.setAdapter(this.adapter); this.adapter.setOnChannelSearchResultSelectedListener(this); - optedIn = getPreferences().getBoolean(CHANNEL_DISCOVERY_OPT_IN, false); + this.optedIn = getPreferences().getBoolean(CHANNEL_DISCOVERY_OPT_IN, false); final String search = savedInstanceState == null ? null : savedInstanceState.getString("search"); if (search != null) { mInitialSearchValue.push(search); } + } + private static ChannelDiscoveryService.Method getMethod(final Context c) { + final SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(c); + final String m = p.getString("channel_discovery_method", c.getString(R.string.default_channel_discovery)); + try { + return ChannelDiscoveryService.Method.valueOf(m); + } catch (IllegalArgumentException e) { + return ChannelDiscoveryService.Method.JABBER_NETWORK; + } } @Override public boolean onCreateOptionsMenu(final Menu menu) { - getMenuInflater().inflate(R.menu.muc_users_activity, menu); + getMenuInflater().inflate(R.menu.channel_discovery_activity, menu); + AccountUtils.showHideMenuItems(menu); mMenuSearchView = menu.findItem(R.id.action_search); final View mSearchView = mMenuSearchView.getActionView(); mSearchEditText = mSearchView.findViewById(R.id.search_field); mSearchEditText.setHint(R.string.search_channels); - String initialSearchValue = mInitialSearchValue.pop(); + final String initialSearchValue = mInitialSearchValue.pop(); if (initialSearchValue != null) { mMenuSearchView.expandActionView(); mSearchEditText.append(initialSearchValue); mSearchEditText.requestFocus(); - if (optedIn && xmppConnectionService != null) { - xmppConnectionService.discoverChannels(initialSearchValue, this); + if ((optedIn || method == ChannelDiscoveryService.Method.LOCAL_SERVER) && xmppConnectionService != null) { + xmppConnectionService.discoverChannels(initialSearchValue, this.method, this); } } mSearchEditText.setOnEditorActionListener(this); @@ -120,8 +134,8 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY); mSearchEditText.setText(""); toggleLoadingScreen(); - if (optedIn) { - xmppConnectionService.discoverChannels(null, this); + if (optedIn || method == ChannelDiscoveryService.Method.LOCAL_SERVER) { + xmppConnectionService.discoverChannels(null, this.method, this); } return true; } @@ -135,7 +149,8 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O @Override public void onStart() { super.onStart(); - if (!optedIn) { + this.method = getMethod(this); + if (!optedIn && method == ChannelDiscoveryService.Method.JABBER_NETWORK) { final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.channel_discovery_opt_in_title); builder.setMessage(Html.fromHtml(getString(R.string.channel_discover_opt_in_message))); @@ -160,21 +175,21 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O SharedPreferences preferences = getPreferences(); preferences.edit().putBoolean(CHANNEL_DISCOVERY_OPT_IN, true).apply(); optedIn = true; - xmppConnectionService.discoverChannels(null, this); + xmppConnectionService.discoverChannels(null, this.method, this); } @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (optedIn) { + if (optedIn || method == ChannelDiscoveryService.Method.LOCAL_SERVER) { toggleLoadingScreen(); SoftKeyboardUtils.hideSoftKeyboard(this); - xmppConnectionService.discoverChannels(v.getText().toString(), this); + xmppConnectionService.discoverChannels(v.getText().toString(), this.method, this); } return true; } @Override - public void onChannelSearchResultsFound(final List results) { + public void onChannelSearchResultsFound(final List results) { runOnUiThread(() -> { adapter.submitList(results); binding.progressBar.setVisibility(View.GONE); @@ -188,7 +203,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O } @Override - public void onChannelSearchResult(final MuclumbusService.Room result) { + public void onChannelSearchResult(final Room result) { List accounts = AccountUtils.getEnabledAccounts(xmppConnectionService); if (accounts.size() == 1) { joinChannelSearchResult(accounts.get(0), result); @@ -206,7 +221,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O @Override public boolean onContextItemSelected(MenuItem item) { - final MuclumbusService.Room room = adapter.getCurrent(); + final Room room = adapter.getCurrent(); if (room != null) { switch (item.getItemId()) { case R.id.share_with: @@ -224,7 +239,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O return false; } - public void joinChannelSearchResult(String selectedAccount, MuclumbusService.Room result) { + public void joinChannelSearchResult(String selectedAccount, Room result) { final Jid jid = Config.DOMAIN_LOCK == null ? Jid.of(selectedAccount) : Jid.of(selectedAccount, Config.DOMAIN_LOCK, null); final boolean syncAutoJoin = getBooleanPreference("autojoin", R.bool.autojoin); final Account account = xmppConnectionService.findAccountByJid(jid); diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java index 5ba28c446..0f452e0b1 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java @@ -16,26 +16,26 @@ import java.util.Locale; import eu.siacs.conversations.R; import eu.siacs.conversations.databinding.SearchResultItemBinding; -import eu.siacs.conversations.http.services.MuclumbusService; +import eu.siacs.conversations.entities.Room; import eu.siacs.conversations.ui.XmppActivity; import eu.siacs.conversations.ui.util.AvatarWorkerTask; import rocks.xmpp.addr.Jid; -public class ChannelSearchResultAdapter extends ListAdapter implements View.OnCreateContextMenuListener { +public class ChannelSearchResultAdapter extends ListAdapter implements View.OnCreateContextMenuListener { - private static final DiffUtil.ItemCallback DIFF = new DiffUtil.ItemCallback() { + private static final DiffUtil.ItemCallback DIFF = new DiffUtil.ItemCallback() { @Override - public boolean areItemsTheSame(@NonNull MuclumbusService.Room a, @NonNull MuclumbusService.Room b) { + public boolean areItemsTheSame(@NonNull Room a, @NonNull Room b) { return a.address != null && a.address.equals(b.address); } @Override - public boolean areContentsTheSame(@NonNull MuclumbusService.Room a, @NonNull MuclumbusService.Room b) { + public boolean areContentsTheSame(@NonNull Room a, @NonNull Room b) { return a.equals(b); } }; private OnChannelSearchResultSelected listener; - private MuclumbusService.Room current; + private Room current; public ChannelSearchResultAdapter() { super(DIFF); @@ -49,7 +49,7 @@ public class ChannelSearchResultAdapter extends ListAdapter + xmlns:app="http://schemas.android.com/apk/res-auto"> + android:title="@string/search" + app:actionLayout="@layout/actionview_search" + app:showAsAction="collapseActionView|always" /> + + diff --git a/src/main/res/values/arrays.xml b/src/main/res/values/arrays.xml index 54e122dad..e59254b18 100644 --- a/src/main/res/values/arrays.xml +++ b/src/main/res/values/arrays.xml @@ -124,4 +124,14 @@ @string/video_720p @string/video_original + + + @string/jabber_network + @string/local_server + + + + JABBER_NETWORK + LOCAL_SERVER + diff --git a/src/main/res/values/defaults.xml b/src/main/res/values/defaults.xml index b5e32a639..d17c8c277 100644 --- a/src/main/res/values/defaults.xml +++ b/src/main/res/values/defaults.xml @@ -43,4 +43,5 @@ false false 360 + JABBER_NETWORK diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 3674aab53..8c03dcada 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -879,4 +879,9 @@ Unable to perform this action Join public channel… The sharing application did not grant permission to access this file. + + jabber.network + Local server + Most users should choose ‘jabber.network’ for better suggestions from the entirety of the public XMPP ecosystem. + Channel discovery method diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml index 4b93528f4..efea33a2c 100644 --- a/src/main/res/xml/preferences.xml +++ b/src/main/res/xml/preferences.xml @@ -16,6 +16,22 @@ + + + + - - - - - - - - - - + android:key="notification_category" + android:title="@string/pref_notification_settings"> - + - - - + + + - + + + + + + + - + - + + + + - - - - + + + - - - @@ -212,11 +210,6 @@ android:key="btbv" android:summary="@string/pref_blind_trust_before_verification_summary" android:title="@string/pref_blind_trust_before_verification" /> - - + + + android:key="group_chats" + android:title="@string/group_chats_and_channels"> + + + + + + - - - + From f7b7464a65591efd393d746686ffa36e68731da1 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 2 Nov 2019 17:00:23 +0100 Subject: [PATCH 17/25] fixed links in privacy warning in channel discovery. fixes #3577 --- .../siacs/conversations/ui/ChannelDiscoveryActivity.java | 8 ++++++++ .../java/eu/siacs/conversations/ui/text/FixedURLSpan.java | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java index f09263ea3..d98fa48e7 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java @@ -10,6 +10,7 @@ import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v7.widget.Toolbar; import android.text.Html; +import android.text.method.LinkMovementMethod; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; @@ -158,6 +159,13 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O builder.setPositiveButton(R.string.confirm, (dialog, which) -> optIn()); builder.setOnCancelListener(dialog -> finish()); final AlertDialog dialog = builder.create(); + dialog.setOnShowListener(d -> { + final TextView textView = dialog.findViewById(android.R.id.message); + if (textView == null) { + return; + } + textView.setMovementMethod(LinkMovementMethod.getInstance()); + }); dialog.setCanceledOnTouchOutside(false); dialog.show(); } diff --git a/src/main/java/eu/siacs/conversations/ui/text/FixedURLSpan.java b/src/main/java/eu/siacs/conversations/ui/text/FixedURLSpan.java index 0843c214f..eb45feebe 100644 --- a/src/main/java/eu/siacs/conversations/ui/text/FixedURLSpan.java +++ b/src/main/java/eu/siacs/conversations/ui/text/FixedURLSpan.java @@ -70,8 +70,8 @@ public class FixedURLSpan extends URLSpan { public void onClick(View widget) { final Uri uri = Uri.parse(getURL()); final Context context = widget.getContext(); - final boolean candidateToProcessDirecty = "xmpp".equals(uri.getScheme()) || ("https".equals(uri.getScheme()) && "conversations.im".equals(uri.getHost()) && uri.getPathSegments().size() > 1 && Arrays.asList("j","i").contains(uri.getPathSegments().get(0))); - if (candidateToProcessDirecty && context instanceof ConversationsActivity) { + final boolean candidateToProcessDirectly = "xmpp".equals(uri.getScheme()) || ("https".equals(uri.getScheme()) && "conversations.im".equals(uri.getHost()) && uri.getPathSegments().size() > 1 && Arrays.asList("j","i").contains(uri.getPathSegments().get(0))); + if (candidateToProcessDirectly && context instanceof ConversationsActivity) { if (((ConversationsActivity) context).onXmppUriClicked(uri)) { widget.playSoundEffect(0); return; From 7f25d91d333f4923f49767e57a36d01689787b7e Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 3 Nov 2019 22:03:46 +0100 Subject: [PATCH 18/25] do not validate port if hostname is empty. closes #3578 --- .../conversations/ui/EditAccountActivity.java | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index d8c208dd4..1a24077ad 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -228,20 +228,22 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat removeErrorsOnAllBut(binding.hostnameLayout); return; } - try { - numericPort = Integer.parseInt(port); - if (numericPort < 0 || numericPort > 65535) { + if (!hostname.isEmpty()) { + try { + numericPort = Integer.parseInt(port); + if (numericPort < 0 || numericPort > 65535) { + binding.portLayout.setError(getString(R.string.not_a_valid_port)); + removeErrorsOnAllBut(binding.portLayout); + binding.port.requestFocus(); + return; + } + + } catch (NumberFormatException e) { binding.portLayout.setError(getString(R.string.not_a_valid_port)); removeErrorsOnAllBut(binding.portLayout); binding.port.requestFocus(); return; } - - } catch (NumberFormatException e) { - binding.portLayout.setError(getString(R.string.not_a_valid_port)); - removeErrorsOnAllBut(binding.portLayout); - binding.port.requestFocus(); - return; } } @@ -477,8 +479,13 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat } private void updatePortLayout() { - String hostname = this.binding.hostname.getText().toString(); - this.binding.portLayout.setEnabled(!TextUtils.isEmpty(hostname)); + final String hostname = this.binding.hostname.getText().toString(); + if (TextUtils.isEmpty(hostname)) { + this.binding.portLayout.setEnabled(false); + this.binding.portLayout.setError(null); + } else { + this.binding.portLayout.setEnabled(true); + } } protected void updateSaveButton() { @@ -613,7 +620,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat } private void refreshAvatar() { - AvatarWorkerTask.loadAvatar(mAccount,binding.avater,R.dimen.avatar_on_details_screen_size); + AvatarWorkerTask.loadAvatar(mAccount, binding.avater, R.dimen.avatar_on_details_screen_size); } @Override @@ -683,9 +690,9 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat } boolean init = intent.getBooleanExtra("init", false); boolean openedFromNotification = intent.getBooleanExtra(EXTRA_OPENED_FROM_NOTIFICATION, false); - Log.d(Config.LOGTAG,"extras "+intent.getExtras()); - this.mForceRegister = intent.hasExtra(EXTRA_FORCE_REGISTER) ? intent.getBooleanExtra(EXTRA_FORCE_REGISTER,false) : null; - Log.d(Config.LOGTAG,"force register="+mForceRegister); + Log.d(Config.LOGTAG, "extras " + intent.getExtras()); + this.mForceRegister = intent.hasExtra(EXTRA_FORCE_REGISTER) ? intent.getBooleanExtra(EXTRA_FORCE_REGISTER, false) : null; + Log.d(Config.LOGTAG, "force register=" + mForceRegister); this.mInitMode = init || this.jidToEdit == null; this.messageFingerprint = intent.getStringExtra("fingerprint"); if (!mInitMode) { @@ -975,7 +982,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat if (!mInitMode) { this.binding.avater.setVisibility(View.VISIBLE); - AvatarWorkerTask.loadAvatar(mAccount,binding.avater,R.dimen.avatar_on_details_screen_size); + AvatarWorkerTask.loadAvatar(mAccount, binding.avater, R.dimen.avatar_on_details_screen_size); } else { this.binding.avater.setVisibility(View.GONE); } From 333f629b32ab89b0111dc480b5c0ccb5d20dd86b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 8 Nov 2019 11:54:03 +0100 Subject: [PATCH 19/25] clarify image compression setting --- src/main/res/values/arrays.xml | 2 +- src/main/res/values/strings.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/res/values/arrays.xml b/src/main/res/values/arrays.xml index e59254b18..50ca38c6e 100644 --- a/src/main/res/values/arrays.xml +++ b/src/main/res/values/arrays.xml @@ -62,7 +62,7 @@ @string/never - @string/automatically + @string/large_images_only @string/always diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 8c03dcada..47bd247ab 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -512,9 +512,9 @@ Notifications disabled Notifications paused Image Compression - Resize and compress images + Hint: Use ‘Choose file’ instead of ‘Choose picture’ to send individual images uncompressed regardless of this setting. Always - Automatically + Large images only Battery optimizations enabled Your device is doing some heavy battery optimizations on Conversations that might lead to delayed notifications or even message loss.\nIt is recommended to disable those. Your device is doing some heavy battery optimizations on Conversations that might lead to delayed notifications or even message loss.\n\nYou will now be asked to disable those. From abc1cb5a89d07ebd4b14cbb478f467cd5c57768f Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 8 Nov 2019 12:06:38 +0100 Subject: [PATCH 20/25] remove 'indicate received' setting and default to true --- .../eu/siacs/conversations/generator/MessageGenerator.java | 6 ++---- .../siacs/conversations/services/XmppConnectionService.java | 4 ---- .../eu/siacs/conversations/ui/adapter/MessageAdapter.java | 6 +----- src/main/res/values/defaults.xml | 1 - src/main/res/values/strings.xml | 2 -- src/main/res/xml/preferences.xml | 5 ----- 6 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java index dbf8e7cb2..56445e0d6 100644 --- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java @@ -37,16 +37,14 @@ public class MessageGenerator extends AbstractGenerator { if (conversation.getMode() == Conversation.MODE_SINGLE) { packet.setTo(message.getCounterpart()); packet.setType(MessagePacket.TYPE_CHAT); - if (this.mXmppConnectionService.indicateReceived() && !isWithSelf) { + if (!isWithSelf) { packet.addChild("request", "urn:xmpp:receipts"); } } else if (message.isPrivateMessage()) { packet.setTo(message.getCounterpart()); packet.setType(MessagePacket.TYPE_CHAT); packet.addChild("x", "http://jabber.org/protocol/muc#user"); - if (this.mXmppConnectionService.indicateReceived()) { - packet.addChild("request", "urn:xmpp:receipts"); - } + packet.addChild("request", "urn:xmpp:receipts"); } else { packet.setTo(message.getCounterpart().asBareJid()); packet.setType(MessagePacket.TYPE_GROUPCHAT); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index e79a0bfaa..df2aaec19 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -3906,10 +3906,6 @@ public class XmppConnectionService extends Service { return getBooleanPreference("autojoin", R.bool.autojoin); } - public boolean indicateReceived() { - return getBooleanPreference("indicate_received", R.bool.indicate_received); - } - public boolean useTorToConnect() { return QuickConversationsService.isConversations() && getBooleanPreference("use_tor", R.bool.use_tor); } diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index 40cc740c0..a8a93d4e8 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -89,7 +89,6 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie private DisplayMetrics metrics; private OnContactPictureClicked mOnContactPictureClickedListener; private OnContactPictureLongClicked mOnContactPictureLongClickedListener; - private boolean mIndicateReceived = false; private boolean mUseGreenBackground = false; private OnQuoteListener onQuoteListener; public MessageAdapter(XmppActivity activity, List messages) { @@ -208,9 +207,7 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie break; case Message.STATUS_SEND_RECEIVED: case Message.STATUS_SEND_DISPLAYED: - if (mIndicateReceived) { - viewHolder.indicatorReceived.setVisibility(View.VISIBLE); - } + viewHolder.indicatorReceived.setVisibility(View.VISIBLE); break; case Message.STATUS_SEND_FAILED: final String errorMessage = message.getErrorMessage(); @@ -910,7 +907,6 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie public void updatePreferences() { SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(activity); - this.mIndicateReceived = p.getBoolean("indicate_received", activity.getResources().getBoolean(R.bool.indicate_received)); this.mUseGreenBackground = p.getBoolean("use_green_background", activity.getResources().getBoolean(R.bool.use_green_background)); } diff --git a/src/main/res/values/defaults.xml b/src/main/res/values/defaults.xml index d17c8c277..a41fcbae2 100644 --- a/src/main/res/values/defaults.xml +++ b/src/main/res/values/defaults.xml @@ -32,7 +32,6 @@ false false true - false false false false diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 47bd247ab..46a6f0311 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -282,8 +282,6 @@ Enable quiet hours Notifications will be silenced during quiet hours Send button indicates status - Request message receipts - Received messages will be marked with a green tick if supported Colorize send button to indicate contact status Other Synchronize with bookmarks diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml index efea33a2c..ed67e1be8 100644 --- a/src/main/res/xml/preferences.xml +++ b/src/main/res/xml/preferences.xml @@ -328,11 +328,6 @@ - Date: Fri, 8 Nov 2019 12:18:39 +0100 Subject: [PATCH 21/25] fixed spinning wheel when switching between local and jabber.network discovery --- .../siacs/conversations/ui/ChannelDiscoveryActivity.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java index d98fa48e7..5dfcf9bdc 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java @@ -168,9 +168,16 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O }); dialog.setCanceledOnTouchOutside(false); dialog.show(); + holdLoading(); } } + private void holdLoading() { + adapter.submitList(Collections.emptyList()); + binding.progressBar.setVisibility(View.GONE); + binding.list.setBackgroundColor(StyledAttributes.getColor(this, R.attr.color_background_primary)); + } + @Override public void onSaveInstanceState(Bundle savedInstanceState) { if (mMenuSearchView != null && mMenuSearchView.isActionViewExpanded()) { @@ -183,6 +190,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O SharedPreferences preferences = getPreferences(); preferences.edit().putBoolean(CHANNEL_DISCOVERY_OPT_IN, true).apply(); optedIn = true; + toggleLoadingScreen(); xmppConnectionService.discoverChannels(null, this.method, this); } From 7cc2478f5c4c608aaa3244e0af66168706d987cd Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 8 Nov 2019 12:23:06 +0100 Subject: [PATCH 22/25] remove 'send indicate' setting and default to true --- .../java/eu/siacs/conversations/ui/ConversationFragment.java | 3 +-- src/main/res/values/defaults.xml | 1 - src/main/res/values/strings.xml | 2 -- src/main/res/xml/preferences.xml | 5 ----- 4 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index c0ec6d790..1eaa1861f 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -2267,7 +2267,6 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke public void updateSendButton() { boolean hasAttachments = mediaPreviewAdapter != null && mediaPreviewAdapter.hasAttachments(); - boolean useSendButtonToIndicateStatus = activity != null && PreferenceManager.getDefaultSharedPreferences(activity).getBoolean("send_button_status", getResources().getBoolean(R.bool.send_button_status)); final Conversation c = this.conversation; final Presence.Status status; final String text = this.binding.textinput == null ? "" : this.binding.textinput.getText().toString(); @@ -2277,7 +2276,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke } else { action = SendButtonTool.getAction(getActivity(), c, text); } - if (useSendButtonToIndicateStatus && c.getAccount().getStatus() == Account.State.ONLINE) { + if (c.getAccount().getStatus() == Account.State.ONLINE) { if (activity != null && activity.xmppConnectionService != null && activity.xmppConnectionService.getMessageArchiveService().isCatchingUp(c)) { status = Presence.Status.OFFLINE; } else if (c.getMode() == Conversation.MODE_SINGLE) { diff --git a/src/main/res/values/defaults.xml b/src/main/res/values/defaults.xml index a41fcbae2..bfe8ae953 100644 --- a/src/main/res/values/defaults.xml +++ b/src/main/res/values/defaults.xml @@ -19,7 +19,6 @@ auto light true - false recent false true diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 46a6f0311..75a929e3f 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -281,8 +281,6 @@ End time Enable quiet hours Notifications will be silenced during quiet hours - Send button indicates status - Colorize send button to indicate contact status Other Synchronize with bookmarks Join and leave group chats according to auto-join flag in your bookmarks. diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml index ed67e1be8..b071233aa 100644 --- a/src/main/res/xml/preferences.xml +++ b/src/main/res/xml/preferences.xml @@ -156,11 +156,6 @@ android:key="use_green_background" android:summary="@string/pref_use_green_background_summary" android:title="@string/pref_use_green_background" /> - Date: Fri, 8 Nov 2019 14:14:28 +0100 Subject: [PATCH 23/25] move foreground setting and backup setting to main settings screen --- .../conversations/utils/Compatibility.java | 2 +- src/main/res/values/strings.xml | 2 ++ src/main/res/xml/preferences.xml | 31 ++++++++++--------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/utils/Compatibility.java b/src/main/java/eu/siacs/conversations/utils/Compatibility.java index 9e63ee3c3..4a2a14111 100644 --- a/src/main/java/eu/siacs/conversations/utils/Compatibility.java +++ b/src/main/java/eu/siacs/conversations/utils/Compatibility.java @@ -93,7 +93,7 @@ public class Compatibility { public static void removeUnusedPreferences(SettingsFragment settingsFragment) { List categories = Arrays.asList( (PreferenceCategory) settingsFragment.findPreference("notification_category"), - (PreferenceCategory) settingsFragment.findPreference("other_expert_category")); + (PreferenceCategory) settingsFragment.findPreference("advanced")); for (String key : (runsTwentySix() ? UNUSED_SETTINGS_POST_TWENTYSIX : UNUESD_SETTINGS_PRE_TWENTYSIX)) { Preference preference = settingsFragment.findPreference(key); if (preference != null) { diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 75a929e3f..d9b957ec1 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -880,4 +880,6 @@ Local server Most users should choose ‘jabber.network’ for better suggestions from the entirety of the public XMPP ecosystem. Channel discovery method + Backup + About diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml index b071233aa..31c2f8b08 100644 --- a/src/main/res/xml/preferences.xml +++ b/src/main/res/xml/preferences.xml @@ -184,6 +184,14 @@ android:summary="@string/pref_font_size_summary" android:title="@string/pref_font_size" /> + + + @@ -193,6 +201,12 @@ android:summary="@string/pref_never_send_crash_summary" android:title="@string/pref_never_send_crash" /> + + - - - - - + + + From b6ce3d9175b088d574860635575c5e98ddede183 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 8 Nov 2019 14:14:56 +0100 Subject: [PATCH 24/25] bump okhttp library --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e3d5a0c77..8ae6e4e49 100644 --- a/build.gradle +++ b/build.gradle @@ -68,7 +68,7 @@ dependencies { implementation "com.leinardi.android:speed-dial:2.0.1" implementation 'com.squareup.retrofit2:retrofit:2.6.1' implementation 'com.squareup.retrofit2:converter-gson:2.6.1' - implementation 'com.squareup.okhttp3:okhttp:3.12.5' + implementation 'com.squareup.okhttp3:okhttp:3.12.6' implementation 'com.google.guava:guava:27.1-android' quicksyImplementation 'io.michaelrocks:libphonenumber-android:8.10.16' } From 63cc5f96edd53598a68059d3450eb93c938b1325 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 8 Nov 2019 14:42:44 +0100 Subject: [PATCH 25/25] version bump to 2.6.0-beta + changelog --- CHANGELOG.md | 6 ++++++ build.gradle | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9e9d087c..98f7cb83d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +### Version 2.6.0 +* Introduce expert setting to perform channel discovery on local server instead of [search.jabber.network](https://search.jabber.network) +* Enable delivery check marks by default and remove setting +* Enable ‘Send button indicates status’ by default and remove setting +* Move Backup and Foreground Service settings to main screen + ### Version 2.5.12 * Jingle file transfer fixes * Fixed OMEMO self healing (after backup restore) on servers w/o MAM diff --git a/build.gradle b/build.gradle index 8ae6e4e49..06463931f 100644 --- a/build.gradle +++ b/build.gradle @@ -84,8 +84,8 @@ android { defaultConfig { minSdkVersion 16 targetSdkVersion 28 - versionCode 346 - versionName "2.5.12" + versionCode 347 + versionName "2.6.0-beta" archivesBaseName += "-$versionName" applicationId "eu.siacs.conversations" resValue "string", "applicationId", applicationId