diff options
12 files changed, 97 insertions, 64 deletions
diff --git a/.travis.yml b/.travis.yml index 0b3dd195b..e26ccaa42 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,3 +15,5 @@ android: - extra-google-google_play_services licenses: - '.+' +script: + - ./gradlew assembleFreeRelease diff --git a/build.gradle b/build.gradle index f99ad1cfb..1f1f47d7c 100644 --- a/build.gradle +++ b/build.gradle @@ -62,10 +62,11 @@ android { minSdkVersion 14 targetSdkVersion 23 - versionCode 124 - versionName "1.10.0-beta" + versionCode 127 + versionName "1.10.0" archivesBaseName += "-$versionName" + applicationId "eu.siacs.conversations" } compileOptions { diff --git a/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java b/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java index 624d1b139..0afcb9e10 100644 --- a/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java +++ b/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java @@ -37,25 +37,24 @@ public class PgpEngine { this.mXmppConnectionService = service; } - public void decrypt(final Message message, - final UiCallback<Message> callback) { + public void decrypt(final Message message, final UiCallback<Message> callback) { Intent params = new Intent(); params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY); + final String uuid = message.getUuid(); if (message.getType() == Message.TYPE_TEXT) { - InputStream is = new ByteArrayInputStream(message.getBody() - .getBytes()); + InputStream is = new ByteArrayInputStream(message.getBody().getBytes()); final OutputStream os = new ByteArrayOutputStream(); api.executeApiAsync(params, is, os, new IOpenPgpCallback() { @Override public void onReturn(Intent result) { notifyPgpDecryptionService(message.getConversation().getAccount(), OpenPgpApi.ACTION_DECRYPT_VERIFY, result); - switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, - OpenPgpApi.RESULT_CODE_ERROR)) { + switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { case OpenPgpApi.RESULT_CODE_SUCCESS: try { os.flush(); - if (message.getEncryption() == Message.ENCRYPTION_PGP) { + if (message.getEncryption() == Message.ENCRYPTION_PGP + && message.getUuid().equals(uuid)) { message.setBody(os.toString()); message.setEncryption(Message.ENCRYPTION_DECRYPTED); final HttpConnectionManager manager = mXmppConnectionService.getHttpConnectionManager(); diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index aba9a8091..9887d3ef1 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -45,7 +45,7 @@ public class Contact implements ListItem, Blockable { protected String photoUri; protected JSONObject keys = new JSONObject(); protected JSONArray groups = new JSONArray(); - protected Presences presences = new Presences(); + protected final Presences presences = new Presences(); protected Account account; protected Avatar avatar; @@ -222,10 +222,6 @@ public class Contact implements ListItem, Blockable { return this.presences; } - public void setPresences(Presences pres) { - this.presences = pres; - } - public void updatePresence(final String resource, final Presence presence) { this.presences.updatePresence(resource, presence); } @@ -386,11 +382,13 @@ public class Contact implements ListItem, Blockable { this.resetOption(Options.TO); this.setOption(Options.FROM); this.resetOption(Options.PREEMPTIVE_GRANT); + this.resetOption(Options.PENDING_SUBSCRIPTION_REQUEST); break; case "both": this.setOption(Options.TO); this.setOption(Options.FROM); this.resetOption(Options.PREEMPTIVE_GRANT); + this.resetOption(Options.PENDING_SUBSCRIPTION_REQUEST); break; case "none": this.resetOption(Options.FROM); diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index 00d7ae592..d23041416 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -91,22 +91,26 @@ public class MucOptions { } } - public static final int ERROR_NO_ERROR = 0; - public static final int ERROR_NICK_IN_USE = 1; - public static final int ERROR_UNKNOWN = 2; - public static final int ERROR_PASSWORD_REQUIRED = 3; - public static final int ERROR_BANNED = 4; - public static final int ERROR_MEMBERS_ONLY = 5; - public static final int ERROR_NO_RESPONSE = 6; - - public static final int KICKED_FROM_ROOM = 9; + public enum Error { + NO_RESPONSE, + NONE, + NICK_IN_USE, + PASSWORD_REQUIRED, + BANNED, + MEMBERS_ONLY, + KICKED, + SHUTDOWN, + UNKNOWN + } public static final String STATUS_CODE_ROOM_CONFIG_CHANGED = "104"; public static final String STATUS_CODE_SELF_PRESENCE = "110"; public static final String STATUS_CODE_BANNED = "301"; public static final String STATUS_CODE_CHANGED_NICK = "303"; public static final String STATUS_CODE_KICKED = "307"; - public static final String STATUS_CODE_LOST_MEMBERSHIP = "321"; + public static final String STATUS_CODE_AFFILIATION_CHANGE = "321"; + public static final String STATUS_CODE_LOST_MEMBERSHIP = "322"; + public static final String STATUS_CODE_SHUTDOWN = "332"; private interface OnEventListener { void onSuccess(); @@ -245,7 +249,7 @@ public class MucOptions { private Data form = new Data(); private Conversation conversation; private boolean isOnline = false; - private int error = ERROR_NO_RESPONSE; + private Error error = Error.NONE; public OnRenameListener onRenameListener = null; private User self; private String subject = null; @@ -282,7 +286,9 @@ public class MucOptions { } public boolean participating() { - return !online() || self.getRole().ranks(Role.PARTICIPANT); + return !online() + || self.getRole().ranks(Role.PARTICIPANT) + || hasFeature("muc_unmoderated"); } public boolean membersOnly() { @@ -322,8 +328,8 @@ public class MucOptions { return findUser(name) != null; } - public void setError(int error) { - this.isOnline = isOnline && error == ERROR_NO_ERROR; + public void setError(Error error) { + this.isOnline = isOnline && error == Error.NONE; this.error = error; } @@ -377,7 +383,7 @@ public class MucOptions { return this.isOnline; } - public int getError() { + public Error getError() { return this.error; } @@ -387,7 +393,7 @@ public class MucOptions { public void setOffline() { this.users.clear(); - this.error = ERROR_NO_RESPONSE; + this.error = Error.NO_RESPONSE; this.isOnline = false; } diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index f01e7ce1f..43edb2c38 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -411,6 +411,7 @@ public class MessageParser extends AbstractParser implements replacedMessage.markUnread(); } mXmppConnectionService.updateMessage(replacedMessage, uuid); + mXmppConnectionService.getNotificationService().updateNotification(false); if (mXmppConnectionService.confirmMessages() && remoteMsgId != null && !isForwarded && !isTypeGroupChat) { sendMessageReceipts(account, packet); } diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index dc02eda8f..63d28c97b 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -63,7 +63,7 @@ public class PresenceParser extends AbstractParser implements if (x != null) { Element item = x.findChild("item"); if (item != null && !from.isBareJid()) { - mucOptions.setError(MucOptions.ERROR_NO_ERROR); + mucOptions.setError(MucOptions.Error.NONE); MucOptions.User user = new MucOptions.User(mucOptions,from); user.setAffiliation(item.getAttribute("affiliation")); user.setRole(item.getAttribute("role")); @@ -109,13 +109,17 @@ public class PresenceParser extends AbstractParser implements if (codes.contains(MucOptions.STATUS_CODE_CHANGED_NICK)) { mucOptions.mNickChangingInProgress = true; } else if (codes.contains(MucOptions.STATUS_CODE_KICKED)) { - mucOptions.setError(MucOptions.KICKED_FROM_ROOM); + mucOptions.setError(MucOptions.Error.KICKED); } else if (codes.contains(MucOptions.STATUS_CODE_BANNED)) { - mucOptions.setError(MucOptions.ERROR_BANNED); + mucOptions.setError(MucOptions.Error.BANNED); } else if (codes.contains(MucOptions.STATUS_CODE_LOST_MEMBERSHIP)) { - mucOptions.setError(MucOptions.ERROR_MEMBERS_ONLY); + mucOptions.setError(MucOptions.Error.MEMBERS_ONLY); + } else if (codes.contains(MucOptions.STATUS_CODE_AFFILIATION_CHANGE)) { + mucOptions.setError(MucOptions.Error.MEMBERS_ONLY); + } else if (codes.contains(MucOptions.STATUS_CODE_SHUTDOWN)) { + mucOptions.setError(MucOptions.Error.SHUTDOWN); } else { - mucOptions.setError(MucOptions.ERROR_UNKNOWN); + mucOptions.setError(MucOptions.Error.UNKNOWN); Log.d(Config.LOGTAG, "unknown error in conference: " + packet); } } else if (!from.isBareJid()){ @@ -132,14 +136,14 @@ public class PresenceParser extends AbstractParser implements mucOptions.onRenameListener.onFailure(); } } else { - mucOptions.setError(MucOptions.ERROR_NICK_IN_USE); + mucOptions.setError(MucOptions.Error.NICK_IN_USE); } } else if (error != null && error.hasChild("not-authorized")) { - mucOptions.setError(MucOptions.ERROR_PASSWORD_REQUIRED); + mucOptions.setError(MucOptions.Error.PASSWORD_REQUIRED); } else if (error != null && error.hasChild("forbidden")) { - mucOptions.setError(MucOptions.ERROR_BANNED); + mucOptions.setError(MucOptions.Error.BANNED); } else if (error != null && error.hasChild("registration-required")) { - mucOptions.setError(MucOptions.ERROR_MEMBERS_ONLY); + mucOptions.setError(MucOptions.Error.BANNED); } } } diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index 165c7c2a8..e8616bd8f 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -189,6 +189,10 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { } } + public boolean queryInProgress(Conversation conversation) { + return queryInProgress(conversation, null); + } + public void processFin(Element fin, Jid from) { if (fin == null) { return; @@ -223,7 +227,6 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { this.execute(nextQuery); this.finalizeQuery(query, false); synchronized (this.queries) { - this.queries.remove(query); this.queries.add(nextQuery); } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index b836e780a..ec13d6dc2 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1772,6 +1772,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa account.pendingConferenceLeaves.remove(conversation); if (account.getStatus() == Account.State.ONLINE) { conversation.resetMucOptions(); + conversation.setHasMessagesLeftOnServer(false); fetchConferenceConfiguration(conversation, new OnConferenceConfigurationFetched() { private void join(Conversation conversation) { @@ -1806,7 +1807,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa conversation.setContactJid(joinJid); databaseBackend.updateConversation(conversation); } - conversation.setHasMessagesLeftOnServer(false); if (conversation.getMucOptions().mamSupport()) { getMessageArchiveService().catchupMUC(conversation); } @@ -1824,9 +1824,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa fetchConferenceConfiguration(conversation); } }); - + updateConversationUi(); } else { account.pendingConferenceJoins.add(conversation); + conversation.resetMucOptions(); + conversation.setHasMessagesLeftOnServer(false); + updateConversationUi(); } } diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index 7d49aa114..9769295e2 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -14,7 +14,6 @@ import android.provider.ContactsContract; import android.provider.ContactsContract.CommonDataKinds; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.Intents; -import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index a16f8c8df..22e0e5c3c 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -53,6 +53,7 @@ import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.Presence; import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.entities.TransferablePlaceholder; +import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.ui.XmppActivity.OnPresenceSelected; import eu.siacs.conversations.ui.XmppActivity.OnValueEdited; @@ -808,27 +809,29 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa && !conversation.getMucOptions().online() && account.getStatus() == Account.State.ONLINE) { switch (conversation.getMucOptions().getError()) { - case MucOptions.ERROR_NICK_IN_USE: + case NICK_IN_USE: showSnackbar(R.string.nick_in_use, R.string.edit, clickToMuc); break; - case MucOptions.ERROR_NO_RESPONSE: - showSnackbar(R.string.conference_not_found, R.string.leave, leaveMuc); + case NO_RESPONSE: + showSnackbar(R.string.joining_conference, 0, null); break; - case MucOptions.ERROR_PASSWORD_REQUIRED: + case PASSWORD_REQUIRED: showSnackbar(R.string.conference_requires_password, R.string.enter_password, enterPassword); break; - case MucOptions.ERROR_BANNED: + case BANNED: showSnackbar(R.string.conference_banned, R.string.leave, leaveMuc); break; - case MucOptions.ERROR_MEMBERS_ONLY: + case MEMBERS_ONLY: showSnackbar(R.string.conference_members_only, R.string.leave, leaveMuc); break; - case MucOptions.KICKED_FROM_ROOM: - //showSnackbar(R.string.conference_kicked, R.string.join, joinMuc); - activity.xmppConnectionService.joinMuc(conversation); + case KICKED: + showSnackbar(R.string.conference_kicked, R.string.join, joinMuc); break; - case MucOptions.ERROR_UNKNOWN: - showSnackbar(R.string.conference_unknown_error, R.string.try_again, joinMuc); + case UNKNOWN: + showSnackbar(R.string.conference_unknown_error, R.string.join, joinMuc); + break; + case SHUTDOWN: + showSnackbar(R.string.conference_shutdown, R.string.join, joinMuc); break; default: break; @@ -1053,10 +1056,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa protected void updateStatusMessages() { synchronized (this.messageList) { - final XmppConnection connection = conversation.getAccount().getXmppConnection(); - if (conversation.getLastClearHistory() != 0 - && connection != null - && connection.getFeatures().mam()) { + if (showLoadMoreMessages(conversation)) { this.messageList.add(0, Message.createLoadMoreMessage(conversation)); } if (conversation.getMode() == Conversation.MODE_SINGLE) { @@ -1082,14 +1082,30 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } } - protected void showSnackbar(final int message, final int action, - final OnClickListener clickListener) { + private boolean showLoadMoreMessages(final Conversation c) { + final boolean mam = hasMamSupport(c); + final MessageArchiveService service = activity.xmppConnectionService.getMessageArchiveService(); + return mam && (c.getLastClearHistory() != 0 || (c.countMessages() == 0 && c.hasMessagesLeftOnServer() && !service.queryInProgress(c))); + } + + private boolean hasMamSupport(final Conversation c) { + if (c.getMode() == Conversation.MODE_SINGLE) { + final XmppConnection connection = c.getAccount().getXmppConnection(); + return connection != null && connection.getFeatures().mam(); + } else { + return c.getMucOptions().mamSupport(); + } + } + + protected void showSnackbar(final int message, final int action, final OnClickListener clickListener) { snackbar.setVisibility(View.VISIBLE); snackbar.setOnClickListener(null); snackbarMessage.setText(message); snackbarMessage.setOnClickListener(null); - snackbarAction.setVisibility(View.VISIBLE); - snackbarAction.setText(action); + snackbarAction.setVisibility(clickListener == null ? View.GONE : View.VISIBLE); + if (action != 0) { + snackbarAction.setText(action); + } snackbarAction.setOnClickListener(clickListener); } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 982c3ab84..f97e59bd3 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -241,8 +241,7 @@ <string name="bookmark_already_exists">This bookmark already exists</string> <string name="you">You</string> <string name="action_edit_subject">Edit conference subject</string> - <string name="conference_not_found">Conference not found</string> - <string name="conference_unknown_error">Unknown error received</string>2 + <string name="joining_conference">Joining conferenceā¦</string> <string name="leave">Leave</string> <string name="contact_added_you">Contact added you to contact list</string> <string name="add_back">Add back</string> @@ -341,6 +340,8 @@ <string name="conference_banned">You are banned from this conference</string> <string name="conference_members_only">This conference is members only</string> <string name="conference_kicked">You have been kicked from this conference</string> + <string name="conference_shutdown">The conference was shut down</string> + <string name="conference_unknown_error">You are no longer in this conference</string> <string name="using_account">using account %s</string> <string name="checking_x">Checking %s on HTTP host</string> <string name="not_connected_try_again">You are not connected. Try again later</string> |