diff --git a/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java b/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java index 762dfbb42..8b0f22eb8 100644 --- a/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java +++ b/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java @@ -46,7 +46,7 @@ public class ShareViaAccountActivity extends XmppActivity { try { final Jid contact = Jid.of(getIntent().getStringExtra(EXTRA_CONTACT)); final Conversation conversation = xmppConnectionService.findOrCreateConversation( - account, contact, false, false); + account, contact, null, false, false, false, null); switchToConversation(conversation, body); } catch (IllegalArgumentException e) { // ignore error @@ -76,7 +76,7 @@ public class ShareViaAccountActivity extends XmppActivity { try { final Jid contact = Jid.of(getIntent().getStringExtra(EXTRA_CONTACT)); final Conversation conversation = xmppConnectionService.findOrCreateConversation( - account, contact, false, false); + account, contact, null, false, false, false, null); switchToConversation(conversation, body); } catch (IllegalArgumentException e) { // ignore error diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java index 05ffdbdca..2cab10373 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -1532,8 +1532,18 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { if (contact.showInRoster() || contact.isSelf()) { return true; } - final Conversation conversation = mXmppConnectionService.find(account, jid); - return conversation != null && conversation.sentMessagesCount() > 0; + + Conversation conversation = mXmppConnectionService.find(account, jid, null); + if (conversation != null && conversation.sentMessagesCount() > 0) { + return true; + } + + conversation = mXmppConnectionService.find(account, jid, jid); + if (conversation != null && conversation.sentMessagesCount() > 0) { + return true; + } + + return false; } private void completeSession(XmppAxolotlSession session) { diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index e11577bd4..e5592609f 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -14,11 +14,13 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.ListIterator; +import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import eu.siacs.conversations.Config; @@ -51,6 +53,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl public static final String CREATED = "created"; public static final String MODE = "mode"; public static final String ATTRIBUTES = "attributes"; + public static final String NEXT_COUNTERPART = "next_counterpart"; public static final String ATTRIBUTE_MUTED_TILL = "muted_till"; public static final String ATTRIBUTE_ALWAYS_NOTIFY = "always_notify"; @@ -86,17 +89,19 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl private String mFirstMamReference = null; protected Message replyTo = null; + private WeakReference parentConversation = null; + public Conversation(final String name, final Account account, final Jid contactJid, - final int mode) { + final int mode, Jid nextCounterpart) { this(java.util.UUID.randomUUID().toString(), name, null, account .getUuid(), contactJid, System.currentTimeMillis(), - STATUS_AVAILABLE, mode, ""); + STATUS_AVAILABLE, mode, "", nextCounterpart); this.account = account; } public Conversation(final String uuid, final String name, final String contactUuid, final String accountUuid, final Jid contactJid, final long created, final int status, - final int mode, final String attributes) { + final int mode, final String attributes, Jid nextCounterpart) { this.uuid = uuid; this.name = name; this.contactUuid = contactUuid; @@ -110,9 +115,19 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl } catch (JSONException e) { this.attributes = new JSONObject(); } + this.nextCounterpart = nextCounterpart; + } + + public String getContactUuid() { + return contactUuid; + } + + public JSONObject getAttributes() { + return attributes; } public static Conversation fromCursor(Cursor cursor) { + String counterpart = cursor.getString(cursor.getColumnIndex(NEXT_COUNTERPART)); return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)), cursor.getString(cursor.getColumnIndex(NAME)), cursor.getString(cursor.getColumnIndex(CONTACT)), @@ -121,7 +136,8 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl cursor.getLong(cursor.getColumnIndex(CREATED)), cursor.getInt(cursor.getColumnIndex(STATUS)), cursor.getInt(cursor.getColumnIndex(MODE)), - cursor.getString(cursor.getColumnIndex(ATTRIBUTES))); + cursor.getString(cursor.getColumnIndex(ATTRIBUTES)), + counterpart == null ? null : JidHelper.parseOrFallbackToInvalid(counterpart)); } public static Message getLatestMarkableMessage(final List messages, boolean isPrivateAndNonAnonymousMuc) { @@ -215,6 +231,17 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl return null; } + public Conversation getParentConversation() { + if (parentConversation == null) { + return null; + } + + return parentConversation.get(); + } + + public void setParentConversation(Conversation c) { + this.parentConversation = new WeakReference<>(c); + } public Message findUnsentMessageWithUuid(String uuid) { synchronized (this.messages) { @@ -641,6 +668,10 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl return this.accountUuid; } + public Jid getContactJid() { + return contactJid; + } + public Account getAccount() { return this.account; } @@ -680,6 +711,11 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl values.put(CREATED, created); values.put(STATUS, status); values.put(MODE, mode); + + if (nextCounterpart != null) { + values.put(NEXT_COUNTERPART, nextCounterpart.toString()); + } + synchronized (this.attributes) { values.put(ATTRIBUTES, attributes.toString()); } @@ -706,6 +742,12 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl } public synchronized MucOptions getMucOptions() { + Conversation parent = parentConversation == null ? null : parentConversation.get(); + + if (parent != null) { + this.mucOptions = parent.getMucOptions(); + } + if (this.mucOptions == null) { this.mucOptions = new MucOptions(this); } @@ -984,22 +1026,69 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl } public void add(Message message) { - synchronized (this.messages) { - this.messages.add(message); + String res1 = message.getCounterpart() == null ? null : message.getCounterpart().getResource(); + String res2 = nextCounterpart == null ? null : nextCounterpart.getResource(); + + if (nextCounterpart == null) { + if (!message.isPrivateMessage()) { + synchronized (this.messages) { + this.messages.add(message); + } + } + } else { + if (message.isPrivateMessage() && Objects.equals(res1, res2)) { + synchronized (this.messages) { + this.messages.add(message); + } + } } } public void prepend(int offset, Message message) { - synchronized (this.messages) { - this.messages.add(Math.min(offset, this.messages.size()), message); + String res1 = message.getCounterpart() == null ? null : message.getCounterpart().getResource(); + String res2 = nextCounterpart == null ? null : nextCounterpart.getResource(); + + if (nextCounterpart == null) { + if (!message.isPrivateMessage()) { + synchronized (this.messages) { + this.messages.add(Math.min(offset, this.messages.size()), message); + } + } + } else { + if (message.isPrivateMessage() && Objects.equals(res1, res2)) { + synchronized (this.messages) { + this.messages.add(Math.min(offset, this.messages.size()), message); + } + } } } public void addAll(int index, List messages) { - synchronized (this.messages) { - this.messages.addAll(index, messages); + ArrayList newM = new ArrayList<>(); + + if (nextCounterpart == null) { + for(Message m : messages) { + if (!m.isPrivateMessage()) { + newM.add(m); + } + } + + } else { + for(Message m : messages) { + String res1 = m.getCounterpart() == null ? null : m.getCounterpart().getResource(); + String res2 = nextCounterpart == null ? null : nextCounterpart.getResource(); + + + if (m.isPrivateMessage() && Objects.equals(res1, res2)) { + newM.add(m); + } + } + } - account.getPgpDecryptionService().decrypt(messages); + synchronized (this.messages) { + this.messages.addAll(index, newM); + } + account.getPgpDecryptionService().decrypt(newM); } public void expireOldMessages(long timestamp) { diff --git a/src/main/java/eu/siacs/conversations/entities/Conversational.java b/src/main/java/eu/siacs/conversations/entities/Conversational.java index 58af42213..87661e2c8 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversational.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversational.java @@ -45,4 +45,6 @@ public interface Conversational { int getMode(); String getUuid(); + + Jid getNextCounterpart(); } diff --git a/src/main/java/eu/siacs/conversations/entities/StubConversation.java b/src/main/java/eu/siacs/conversations/entities/StubConversation.java index 79f4e80b4..aea549c07 100644 --- a/src/main/java/eu/siacs/conversations/entities/StubConversation.java +++ b/src/main/java/eu/siacs/conversations/entities/StubConversation.java @@ -39,11 +39,14 @@ public class StubConversation implements Conversational { private final Jid jid; private final int mode; - public StubConversation(Account account, String uuid, Jid jid, int mode) { + private final Jid nexCounterpart; + + public StubConversation(Account account, String uuid, Jid jid, int mode, Jid nextCounterpart) { this.account = account; this.uuid = uuid; this.jid = jid; this.mode = mode; + this.nexCounterpart = nextCounterpart; } @Override @@ -70,4 +73,9 @@ public class StubConversation implements Conversational { public String getUuid() { return uuid; } + + @Override + public Jid getNextCounterpart() { + return nexCounterpart; + } } diff --git a/src/main/java/eu/siacs/conversations/medialib/activities/EditActivity.kt b/src/main/java/eu/siacs/conversations/medialib/activities/EditActivity.kt index 09fc73c48..96a8c962d 100644 --- a/src/main/java/eu/siacs/conversations/medialib/activities/EditActivity.kt +++ b/src/main/java/eu/siacs/conversations/medialib/activities/EditActivity.kt @@ -269,7 +269,6 @@ class EditActivity : AppCompatActivity(), CropImageView.OnCropImageCompleteListe updateBackgroundBitmap(bitmap) layoutParams.width = bitmap.width layoutParams.height = bitmap.height - android.util.Log.e("31fd", bitmap.height.toString() + " " + height) translationY = max((height - bitmap.height) / 2f, 0f) requestLayout() diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 468498502..d081419aa 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -341,7 +341,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece final Element error = packet.findChild("error"); final boolean pingWorthyError = error != null && (error.hasChild("not-acceptable") || error.hasChild("remote-server-timeout") || error.hasChild("remote-server-not-found")); if (pingWorthyError) { - Conversation conversation = mXmppConnectionService.find(account, from); + Conversation conversation = mXmppConnectionService.find(account, from, null); if (conversation != null && conversation.getMode() == Conversational.MODE_MULTI) { if (conversation.getMucOptions().online()) { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": received ping worthy error for seemingly online muc at " + from); @@ -463,9 +463,16 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece } } + Jid nextCounterpart = null; + + final boolean conversationIsProbablyMuc = isTypeGroupChat || mucUserElement != null || account.getXmppConnection().getMucServersWithholdAccount().contains(counterpart.getDomain().toEscapedString()); + + if (conversationIsProbablyMuc && !isTypeGroupChat) { + nextCounterpart = counterpart; + } + if ((body != null || pgpEncrypted != null || (axolotlEncrypted != null && axolotlEncrypted.hasChild("payload")) || oobUrl != null) && !isMucStatusMessage) { - final boolean conversationIsProbablyMuc = isTypeGroupChat || mucUserElement != null || account.getXmppConnection().getMucServersWithholdAccount().contains(counterpart.getDomain().toEscapedString()); - final Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), conversationIsProbablyMuc, false, query, false); + final Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), null, conversationIsProbablyMuc, nextCounterpart != null, false, nextCounterpart); final boolean conversationMultiMode = conversation.getMode() == Conversation.MODE_MULTI; if (serverMsgId == null) { @@ -545,7 +552,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece message = trial; } if (message == null) { - if (query == null && extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid()), isTypeGroupChat, packet)) { + if (query == null && extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid(), nextCounterpart), isTypeGroupChat, packet)) { mXmppConnectionService.updateConversationUi(); } if (query != null && status == Message.STATUS_SEND && remoteMsgId != null) { @@ -649,7 +656,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece if (replacedMessage.getStatus() == Message.STATUS_RECEIVED) { replacedMessage.markUnread(); } - extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid()), isTypeGroupChat, packet); + extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid(), nextCounterpart), isTypeGroupChat, packet); mXmppConnectionService.updateMessage(replacedMessage, uuid); if (mXmppConnectionService.confirmMessages() && replacedMessage.getStatus() == Message.STATUS_RECEIVED @@ -733,7 +740,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece } if (query == null) { - extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid()), isTypeGroupChat, packet); + extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid(), nextCounterpart), isTypeGroupChat, packet); mXmppConnectionService.updateConversationUi(); } @@ -759,7 +766,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece } } else if (!packet.hasChild("body")) { //no body - final Conversation conversation = mXmppConnectionService.find(account, from.asBareJid()); + final Conversation conversation = mXmppConnectionService.find(account, from.asBareJid(), nextCounterpart); if (axolotlEncrypted != null) { Jid origin; if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) { @@ -784,7 +791,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece } } - if (query == null && extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid()), isTypeGroupChat, packet)) { + if (query == null && extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid(), nextCounterpart), isTypeGroupChat, packet)) { mXmppConnectionService.updateConversationUi(); } @@ -864,7 +871,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece final Element description = child.findChild("description"); final String namespace = description == null ? null : description.getNamespace(); if (Namespace.JINGLE_APPS_RTP.equals(namespace)) { - final Conversation c = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), false, false); + final Conversation c = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), null, false, false, false, nextCounterpart); final Message preExistingMessage = c.findRtpSession(sessionId, status); if (preExistingMessage != null) { preExistingMessage.setServerMsgId(serverMsgId); @@ -885,7 +892,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece } } else if ("proceed".equals(action)) { //status needs to be flipped to find the original propose - final Conversation c = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), false, false); + final Conversation c = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), null, false, false, false, nextCounterpart); final int s = packet.fromAccount(account) ? Message.STATUS_RECEIVED : Message.STATUS_SEND; final Message message = c.findRtpSession(sessionId, s); if (message != null) { @@ -906,7 +913,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece final Element description = child.findChild("description"); final String namespace = description == null ? null : description.getNamespace(); if (Namespace.JINGLE_APPS_RTP.equals(namespace)) { - final Conversation c = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), false, false); + final Conversation c = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), null, false, false, false, nextCounterpart); final Message preExistingMessage = c.findRtpSession(sessionId, status); if (preExistingMessage != null) { preExistingMessage.setServerMsgId(serverMsgId); @@ -963,12 +970,12 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece final String id = displayed.getAttribute("id"); final Jid sender = InvalidJid.getNullForInvalid(displayed.getAttributeAsJid("sender")); if (packet.fromAccount(account) && !selfAddressed) { - dismissNotification(account, counterpart, query, id); + dismissNotification(account, counterpart, query, id, nextCounterpart); if (query == null) { activateGracePeriod(account); } } else if (isTypeGroupChat) { - final Conversation conversation = mXmppConnectionService.find(account, counterpart.asBareJid()); + final Conversation conversation = mXmppConnectionService.find(account, counterpart.asBareJid(), nextCounterpart); final Message message; if (conversation != null && id != null) { if (sender != null) { @@ -1004,7 +1011,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece message = message.prev(); } if (displayedMessage != null && selfAddressed) { - dismissNotification(account, counterpart, query, id); + dismissNotification(account, counterpart, query, id, nextCounterpart); } } } @@ -1033,8 +1040,8 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece } } - private void dismissNotification(Account account, Jid counterpart, MessageArchiveService.Query query, final String id) { - final Conversation conversation = mXmppConnectionService.find(account, counterpart.asBareJid()); + private void dismissNotification(Account account, Jid counterpart, MessageArchiveService.Query query, final String id, Jid nextCounterpart) { + final Conversation conversation = mXmppConnectionService.find(account, counterpart.asBareJid(), nextCounterpart); if (conversation != null && (query == null || query.isCatchup())) { final String displayableId = conversation.findMostRecentRemoteDisplayableId(); if (displayableId != null && displayableId.equals(id)) { @@ -1092,7 +1099,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece public boolean execute(Account account) { if (jid != null) { - Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, jid, true, false); + Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, jid, null, true, false, false, null); if (conversation.getMucOptions().online()) { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": received invite to " + jid + " but muc is considered to be online"); mXmppConnectionService.mucSelfPingAndRejoin(conversation); diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index 8ad582b17..0d797005c 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -36,8 +36,11 @@ public class PresenceParser extends AbstractParser implements } public void parseConferencePresence(PresencePacket packet, Account account) { - final Conversation conversation = packet.getFrom() == null ? null : mXmppConnectionService.find(account, packet.getFrom().asBareJid()); - if (conversation != null) { + final List res = packet.getFrom() == null ? null : mXmppConnectionService.findAll(account, packet.getFrom().asBareJid()); + + if (res == null) return; + + for (Conversation conversation : res) { final MucOptions mucOptions = conversation.getMucOptions(); boolean before = mucOptions.online(); int count = mucOptions.getUserCount(); @@ -362,7 +365,7 @@ public class PresenceParser extends AbstractParser implements } else { contact.setOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST); final Conversation conversation = mXmppConnectionService.findOrCreateConversation( - account, contact.getJid().asBareJid(), false, false); + account, contact.getJid().asBareJid(), null, false, false, false, null); final String statusMessage = packet.findChildContent("status"); if (statusMessage != null && !statusMessage.isEmpty() diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index e66afafb6..7e1b1ef70 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -64,7 +64,7 @@ import eu.siacs.conversations.xmpp.mam.MamReference; public class DatabaseBackend extends SQLiteOpenHelper { private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 52; + private static final int DATABASE_VERSION = 53; private static boolean requiresMessageIndexRebuild = false; private static DatabaseBackend instance = null; @@ -241,7 +241,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { + Conversation.ACCOUNT + " TEXT, " + Conversation.CONTACTJID + " TEXT, " + Conversation.CREATED + " NUMBER, " + Conversation.STATUS + " NUMBER, " + Conversation.MODE - + " NUMBER, " + Conversation.ATTRIBUTES + " TEXT, FOREIGN KEY(" + + " NUMBER, " + Conversation.NEXT_COUNTERPART + " TEXT, " + Conversation.ATTRIBUTES + " TEXT, FOREIGN KEY(" + Conversation.ACCOUNT + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE);"); db.execSQL("create table " + Message.TABLENAME + "( " + Message.UUID @@ -606,6 +606,10 @@ public class DatabaseBackend extends SQLiteOpenHelper { if (oldVersion < 52 && newVersion >= 52) { db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.PAYLOADS + " TEXT"); } + + if (oldVersion < 53 && newVersion >= 53) { + db.execSQL("ALTER TABLE " + Conversation.TABLENAME + " ADD COLUMN " + Conversation.NEXT_COUNTERPART + " TEXT"); + } } private void canonicalizeJids(SQLiteDatabase db) { @@ -803,26 +807,42 @@ public class DatabaseBackend extends SQLiteOpenHelper { SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor; if (timestamp == -1) { - String[] selectionArgs = {conversation.getUuid()}; - cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION - + "=?", selectionArgs, null, null, Message.TIME_SENT + if (conversation.getNextCounterpart() == null) { + String[] selectionArgs = {conversation.getUuid()}; + cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION + + "=?", selectionArgs, null, null, Message.TIME_SENT + + " DESC", String.valueOf(limit)); + } else { + String[] selectionArgs = {conversation.getUuid(), String.valueOf(Message.TYPE_PRIVATE), String.valueOf(Message.TYPE_PRIVATE_FILE), conversation.getNextCounterpart().toString()}; + cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION + + "=? and (" + Message.TYPE + "=? or " + Message.TYPE + "=?) and " + Message.COUNTERPART + "=?" , selectionArgs, null, null, Message.TIME_SENT + " DESC", String.valueOf(limit)); + } } else { - String[] selectionArgs = {conversation.getUuid(), - Long.toString(timestamp)}; - cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION - + "=? and " + Message.TIME_SENT + " users, int size) { diff --git a/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java b/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java index c18c94cf2..0dfb9d024 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java +++ b/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java @@ -102,6 +102,7 @@ public class MessageSearchTask implements Runnable, Cancellable { final int indexAccount = cursor.getColumnIndex(Conversation.ACCOUNT); final int indexContact = cursor.getColumnIndex(Conversation.CONTACTJID); final int indexMode = cursor.getColumnIndex(Conversation.MODE); + final int indexNextCounterpart = cursor.getColumnIndex(Conversation.NEXT_COUNTERPART); do { if (isCancelled) { Log.d(Config.LOGTAG, "canceled search task"); @@ -117,8 +118,9 @@ public class MessageSearchTask implements Runnable, Cancellable { if (conversation == null) { String accountUuid = cursor.getString(indexAccount); String contactJid = cursor.getString(indexContact); + String nextCounterpart = cursor.getString(indexNextCounterpart); int mode = cursor.getInt(indexMode); - conversation = findOrGenerateStub(conversationUuid, accountUuid, contactJid, mode); + conversation = findOrGenerateStub(conversationUuid, accountUuid, contactJid, mode, nextCounterpart); conversationCache.put(conversationUuid, conversation); } Message message = IndividualMessage.fromCursor(cursor, conversation); @@ -137,7 +139,7 @@ public class MessageSearchTask implements Runnable, Cancellable { } } - private Conversational findOrGenerateStub(String conversationUuid, String accountUuid, String contactJid, int mode) throws Exception { + private Conversational findOrGenerateStub(String conversationUuid, String accountUuid, String contactJid, int mode, String nextCounterpart) throws Exception { Conversation conversation = xmppConnectionService.findConversationByUuid(conversationUuid); if (conversation != null) { return conversation; @@ -145,7 +147,7 @@ public class MessageSearchTask implements Runnable, Cancellable { Account account = xmppConnectionService.findAccountByUuid(accountUuid); Jid jid = Jid.of(contactJid); if (account != null && jid != null) { - return new StubConversation(account, conversationUuid, jid.asBareJid(), mode); + return new StubConversation(account, conversationUuid, jid.asBareJid(), mode, Jid.of(nextCounterpart)); } throw new Exception("Unable to generate stub for " + contactJid); } diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 715cafe42..cbaecf444 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -463,7 +463,7 @@ public class NotificationService { final int failedDeliveries = conversation.countFailedDeliveries(); final Notification notification = new Builder(mXmppConnectionService, "delivery_failed") - .setContentTitle(conversation.getName()) + .setContentTitle(getConversationName(conversation)) .setAutoCancel(true) .setSmallIcon(R.drawable.ic_error_white_24dp) .setContentText( @@ -1104,7 +1104,7 @@ public class NotificationService { continue; } conversation = (Conversation) messages.get(0).getConversation(); - final String name = conversation.getName().toString(); + final String name = getConversationName(conversation); SpannableString styledString; if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) { int count = messages.size(); @@ -1166,7 +1166,7 @@ public class NotificationService { .get( conversation, AvatarService.getSystemUiAvatarSize(mXmppConnectionService))); - mBuilder.setContentTitle(conversation.getName()); + mBuilder.setContentTitle(getConversationName(conversation)); if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) { int count = messages.size(); mBuilder.setContentText( @@ -1375,7 +1375,7 @@ public class NotificationService { new NotificationCompat.MessagingStyle(me); final boolean multiple = conversation.getMode() == Conversation.MODE_MULTI; if (multiple) { - messagingStyle.setConversationTitle(conversation.getName()); + messagingStyle.setConversationTitle(getConversationName(conversation)); } for (Message message : messages) { final Person sender = @@ -1913,6 +1913,14 @@ public class NotificationService { } } + private String getConversationName(Conversation c) { + if (c.getNextCounterpart() == null) { + return c.getName().toString(); + } else { + return mXmppConnectionService.getResources().getString(R.string.muc_private_conversation_title, c.getNextCounterpart().getResource(), c.getName()); + } + } + private static class MissedCallsInfo { private int numberOfCalls; private long lastTime; diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 32973ed9d..60a2c0631 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -71,6 +71,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; @@ -642,16 +643,17 @@ public class XmppConnectionService extends Service { }); } - public Conversation find(Bookmark bookmark) { - return find(bookmark.getAccount(), bookmark.getJid()); + public Conversation find(final Account account, final Jid jid, final Jid counterpart) { + return find(getConversations(), account, jid, counterpart); } - public Conversation find(final Account account, final Jid jid) { - return find(getConversations(), account, jid); + public List findAll(final Account account, final Jid jid) { + return findAll(getConversations(), account, jid); } + public boolean isMuc(final Account account, final Jid jid) { - final Conversation c = find(account, jid); + final Conversation c = find(account, jid, null); return c != null && c.getMode() == Conversational.MODE_MULTI; } @@ -1817,7 +1819,7 @@ public class XmppConnectionService extends Service { } public void processDeletedBookmark(Account account, Jid jid) { - final Conversation conversation = find(account, jid); + final Conversation conversation = find(account, jid, null); if (conversation != null && conversation.getMucOptions().getError() == MucOptions.Error.DESTROYED) { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": archiving destroyed conference (" + conversation.getJid() + ") after receiving pep"); archiveConversation(conversation, false); @@ -1826,7 +1828,7 @@ public class XmppConnectionService extends Service { private void processModifiedBookmark(Bookmark bookmark, final boolean pep, final boolean synchronizeWithBookmarks) { final Account account = bookmark.getAccount(); - Conversation conversation = find(bookmark); + Conversation conversation = find(bookmark.getAccount(), bookmark.getJid(), null); if (conversation != null) { if (conversation.getMode() != Conversation.MODE_MULTI) { return; @@ -1847,7 +1849,7 @@ public class XmppConnectionService extends Service { } } } else if (synchronizeWithBookmarks && bookmark.autojoin()) { - conversation = findOrCreateConversation(account, bookmark.getFullJid(), true, true, false); + conversation = findOrCreateConversation(account, bookmark.getFullJid(), null, true, true, false, null); bookmark.setConversation(conversation); } } @@ -1939,6 +1941,17 @@ public class XmppConnectionService extends Service { }); } + private Map computeBareIdConversationsMap() { + Map res = new HashMap<>(); + for (Conversation c : this.conversations) { + if (c.getNextCounterpart() == null) { + res.put(c.getJid().asBareJid().toString(), c); + } + } + + return res; + } + private void restoreFromDatabase() { synchronized (this.conversations) { final Map accountLookupTable = new Hashtable<>(); @@ -1948,7 +1961,24 @@ public class XmppConnectionService extends Service { Log.d(Config.LOGTAG, "restoring conversations..."); final long startTimeConversationsRestore = SystemClock.elapsedRealtime(); this.conversations.addAll(databaseBackend.getConversations(Conversation.STATUS_AVAILABLE)); - for (Iterator iterator = conversations.listIterator(); iterator.hasNext(); ) { + + Map map = null; + + for (Conversation c : this.conversations) { + if (c.getNextCounterpart() != null) { + if (map == null) { + map = computeBareIdConversationsMap(); + } + + Conversation parent = map.get(c.getJid().asBareJid().toString()); + + if (parent != null) { + c.setParentConversation(parent); + } + } + } + + for (Iterator iterator = conversations.listIterator(); iterator.hasNext();) { Conversation conversation = iterator.next(); Account account = accountLookupTable.get(conversation.getAccountUuid()); if (account != null) { @@ -2140,7 +2170,9 @@ public class XmppConnectionService extends Service { if (messages.size() > 0) { conversation.addAll(0, messages); callback.onMoreMessagesLoaded(messages.size(), conversation); - } else if (conversation.hasMessagesLeftOnServer() + } else if ( + conversation.getNextCounterpart() == null + && conversation.hasMessagesLeftOnServer() && account.isOnlineAndConnected() && conversation.getLastClearHistory().getTimestamp() == 0) { final boolean mamAvailable; @@ -2195,19 +2227,52 @@ public class XmppConnectionService extends Service { return null; } - public Conversation find(final Iterable haystack, final Account account, final Jid jid) { + private Conversation find(final Iterable haystack, final Account account, final Jid jid, final Jid counterpart) { if (jid == null) { return null; } - for (final Conversation conversation : haystack) { - if ((account == null || conversation.getAccount() == account) - && (conversation.getJid().asBareJid().equals(jid.asBareJid()))) { - return conversation; + + if (counterpart != null) { + for (final Conversation conversation : haystack) { + if ((account == null || conversation.getAccount() == account) + && (conversation.getJid().asBareJid().equals(jid.asBareJid())) + && Objects.equal(conversation.getNextCounterpart(), counterpart) + ) { + return conversation; + } + } + } else { + for (final Conversation conversation : haystack) { + if ((account == null || conversation.getAccount() == account) + && (conversation.getJid().asBareJid().equals(jid.asBareJid())) + && conversation.getNextCounterpart() == null + ) { + return conversation; + } } } + return null; } + private List findAll(final Iterable haystack, final Account account, final Jid jid) { + if (jid == null) { + return null; + } + + List res = new ArrayList<>(); + + for (final Conversation conversation : haystack) { + if ((account == null || conversation.getAccount() == account) + && (conversation.getJid().asBareJid().equals(jid.asBareJid())) + ) { + res.add(conversation); + } + } + + return res; + } + public boolean isConversationsListEmpty(final Conversation ignore) { synchronized (this.conversations) { final int size = this.conversations.size(); @@ -2225,22 +2290,13 @@ public class XmppConnectionService extends Service { } return false; } - - public Conversation findOrCreateConversation(Account account, Jid jid, boolean muc, final boolean async) { - return this.findOrCreateConversation(account, jid, muc, false, async); - } - - public Conversation findOrCreateConversation(final Account account, final Jid jid, final boolean muc, final boolean joinAfterCreate, final boolean async) { - return this.findOrCreateConversation(account, jid, muc, joinAfterCreate, null, async); - } - - public Conversation findOrCreateConversation(final Account account, final Jid jid, final boolean muc, final boolean joinAfterCreate, final MessageArchiveService.Query query, final boolean async) { + public Conversation findOrCreateConversation(final Account account, final Jid jid, final MessageArchiveService.Query query, final boolean muc, final boolean joinAfterCreate, final boolean async, Jid counterpart) { synchronized (this.conversations) { - Conversation conversation = find(account, jid); + Conversation conversation = find(account, jid, counterpart); if (conversation != null) { return conversation; } - conversation = databaseBackend.findConversation(account, jid); + conversation = databaseBackend.findConversation(account, jid, counterpart); final boolean loadMessagesFromDb; if (conversation != null) { conversation.setStatus(Conversation.STATUS_AVAILABLE); @@ -2262,12 +2318,13 @@ public class XmppConnectionService extends Service { } else { conversationName = jid.getLocal(); } + if (muc) { conversation = new Conversation(conversationName, account, jid, - Conversation.MODE_MULTI); + Conversation.MODE_MULTI, counterpart); } else { conversation = new Conversation(conversationName, account, jid.asBareJid(), - Conversation.MODE_SINGLE); + Conversation.MODE_SINGLE, counterpart); } this.databaseBackend.createConversation(conversation); loadMessagesFromDb = false; @@ -2301,6 +2358,14 @@ public class XmppConnectionService extends Service { runnable.run(); } this.conversations.add(conversation); + + if (counterpart != null) { + Conversation parent = find(account, jid, null); + if (parent != null) { + conversation.setParentConversation(parent); + } + } + updateConversationUi(); return conversation; } @@ -3284,7 +3349,7 @@ public class XmppConnectionService extends Service { public void createPublicChannel(final Account account, final String name, final Jid address, final UiCallback callback) { - joinMuc(findOrCreateConversation(account, address, true, false, true), conversation -> { + joinMuc(findOrCreateConversation(account, address, null, true, false, true, null), conversation -> { final Bundle configuration = IqGenerator.defaultChannelConfiguration(); if (!TextUtils.isEmpty(name)) { configuration.putString("muc#roomconfig_roomname", name); @@ -3323,7 +3388,7 @@ public class XmppConnectionService extends Service { return false; } final Jid jid = Jid.of(CryptoHelper.pronounceable(), server, null); - final Conversation conversation = findOrCreateConversation(account, jid, true, false, true); + final Conversation conversation = findOrCreateConversation(account, jid, null, true, false, true, null); joinMuc(conversation, new OnConferenceJoined() { @Override public void onConferenceJoined(final Conversation conversation) { @@ -3971,7 +4036,7 @@ public class XmppConnectionService extends Service { } updateConversationUi(); } else { - Conversation conversation = find(account, avatar.owner.asBareJid()); + Conversation conversation = find(account, avatar.owner.asBareJid(), null); if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) { MucOptions.User user = conversation.getMucOptions().findUserByFullJid(avatar.owner); if (user != null) { @@ -4138,8 +4203,8 @@ public class XmppConnectionService extends Service { final Message message = conversation.findSentMessageWithUuidOrRemoteId(uuid); if (message != null) { markMessage(message, status, errorMessage); + return message; } - return message; } } return null; @@ -4371,7 +4436,7 @@ public class XmppConnectionService extends Service { public Conversation findUniqueConversationByJid(XmppUri xmppUri) { List findings = new ArrayList<>(); for (Conversation c : getConversations()) { - if (c.getAccount().isEnabled() && c.getJid().asBareJid().equals(xmppUri.getJid()) && ((c.getMode() == Conversational.MODE_MULTI) == xmppUri.isAction(XmppUri.ACTION_JOIN))) { + if (c.getAccount().isEnabled() && c.getJid().asBareJid().equals(xmppUri.getJid()) && c.getNextCounterpart() == null && ((c.getMode() == Conversational.MODE_MULTI) == xmppUri.isAction(XmppUri.ACTION_JOIN))) { findings.add(c); } } @@ -4626,7 +4691,7 @@ public class XmppConnectionService extends Service { public Conversation findFirstMuc(Jid jid) { for (Conversation conversation : getConversations()) { - if (conversation.getAccount().isEnabled() && conversation.getJid().asBareJid().equals(jid.asBareJid()) && conversation.getMode() == Conversation.MODE_MULTI) { + if (conversation.getAccount().isEnabled() && conversation.getJid().asBareJid().equals(jid.asBareJid()) && conversation.getNextCounterpart() == null && conversation.getMode() == Conversation.MODE_MULTI) { return conversation; } } diff --git a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java index 5cf9417e9..4568a5abe 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java @@ -271,7 +271,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O final Jid jid = Config.DOMAIN_LOCK == null ? Jid.ofEscaped(selectedAccount) : Jid.ofLocalAndDomainEscaped(selectedAccount, Config.DOMAIN_LOCK); final boolean syncAutoJoin = getBooleanPreference("autojoin", R.bool.autojoin); final Account account = xmppConnectionService.findAccountByJid(jid); - final Conversation conversation = xmppConnectionService.findOrCreateConversation(account, result.getRoom(), true, true, true); + final Conversation conversation = xmppConnectionService.findOrCreateConversation(account, result.getRoom(), null, true, true, true, null); Bookmark bookmark = conversation.getBookmark(); if (bookmark != null) { if (!bookmark.autojoin() && syncAutoJoin) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index ec4206ac7..13ba3f2bb 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -99,7 +99,17 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers public static void open(final Activity activity, final Conversation conversation) { Intent intent = new Intent(activity, ConferenceDetailsActivity.class); intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC); - intent.putExtra("uuid", conversation.getUuid()); + + Conversation parentConversation = conversation.getParentConversation(); + + String uuid; + if (parentConversation != null) { + uuid = parentConversation.getUuid(); + } else { + uuid = conversation.getUuid(); + } + + intent.putExtra("uuid", uuid); activity.startActivity(intent); } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 0013b8276..a7dc6715d 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -556,7 +556,6 @@ public class ConversationFragment extends XmppFragment binding.textinput.append(conversation.getDraftMessage()); conversation.setDraftMessage(null); } else if (conversation.getMode() == Conversation.MODE_MULTI) { - conversation.setNextCounterpart(null); binding.textinput.setText(""); } else { binding.textinput.setText(""); @@ -1008,12 +1007,15 @@ public class ConversationFragment extends XmppFragment this.binding.textInputHint.setVisibility(View.GONE); this.binding.textinput.setHint(R.string.send_corrected_message); } else if (multi && conversation.getNextCounterpart() != null) { - this.binding.textinput.setHint(R.string.send_unencrypted_message); + /*this.binding.textinput.setHint(R.string.send_unencrypted_message); this.binding.textInputHint.setVisibility(View.VISIBLE); this.binding.textInputHint.setText( getString( R.string.send_private_message_to, - conversation.getNextCounterpart().getResource())); + conversation.getNextCounterpart().getResource())); */ + this.binding.textInputHint.setVisibility(View.GONE); + this.binding.textinput.setHint(UIHelper.getMessageHint(getActivity(), conversation)); + getActivity().invalidateOptionsMenu(); } else if (multi && !conversation.getMucOptions().participating()) { this.binding.textInputHint.setVisibility(View.GONE); this.binding.textinput.setHint(R.string.you_are_not_participating); @@ -1651,7 +1653,7 @@ public class ConversationFragment extends XmppFragment activity.switchToContactDetails(conversation.getContact()); break; case R.id.action_muc_details: - ConferenceDetailsActivity.open(getActivity(), conversation); + ConferenceDetailsActivity.open(activity, conversation); break; case R.id.action_invite: startActivityForResult( @@ -2407,14 +2409,8 @@ public class ConversationFragment extends XmppFragment } public void privateMessageWith(final Jid counterpart) { - if (conversation.setOutgoingChatState(Config.DEFAULT_CHAT_STATE)) { - activity.xmppConnectionService.sendChatState(conversation); - } - this.binding.textinput.setText(""); - this.conversation.setNextCounterpart(counterpart); - updateChatMsgHint(); - updateSendButton(); - updateEditablity(); + Conversation c = activity.xmppConnectionService.findOrCreateConversation(conversation.getAccount(), conversation.getJid(), null, true, true, false, counterpart); + activity.switchToConversation(c); } private void correctMessage(Message message) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java index ba231c584..0c41af89d 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java @@ -630,7 +630,11 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio if (mainFragment instanceof ConversationFragment) { final Conversation conversation = ((ConversationFragment) mainFragment).getConversation(); if (conversation != null) { - actionBar.setTitle(conversation.getName()); + if (conversation.getNextCounterpart() != null) { + actionBar.setTitle(getString(R.string.muc_private_conversation_title, conversation.getNextCounterpart().getResource(), conversation.getName())); + } else { + actionBar.setTitle(conversation.getName()); + } actionBar.setDisplayHomeAsUpEnabled(true); ActionBarUtil.setActionBarOnClickListener( binding.toolbar, diff --git a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java index 1a853834e..e982d9054 100644 --- a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java @@ -246,7 +246,7 @@ public class RtpSessionActivity extends XmppActivity final Contact contact = getWith(); final Conversation conversation = xmppConnectionService.findOrCreateConversation( - contact.getAccount(), contact.getJid(), false, true); + contact.getAccount(), contact.getJid(), null, false, false, true, null); switchToConversation(conversation); } @@ -1361,7 +1361,7 @@ public class RtpSessionActivity extends XmppActivity final Account account = extractAccount(intent); final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH)); final Conversation conversation = - xmppConnectionService.findOrCreateConversation(account, with, false, true); + xmppConnectionService.findOrCreateConversation(account, with, null, false, false, true, null); final Intent launchIntent = new Intent(this, ConversationsActivity.class); launchIntent.setAction(ConversationsActivity.ACTION_VIEW_CONVERSATION); launchIntent.putExtra(ConversationsActivity.EXTRA_CONVERSATION, conversation.getUuid()); diff --git a/src/main/java/eu/siacs/conversations/ui/SearchActivity.java b/src/main/java/eu/siacs/conversations/ui/SearchActivity.java index ec279f58e..ecdd558f6 100644 --- a/src/main/java/eu/siacs/conversations/ui/SearchActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SearchActivity.java @@ -201,9 +201,12 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc } else { return xmppConnectionService.findOrCreateConversation(conversational.getAccount(), conversational.getJid(), + null, conversational.getMode() == Conversational.MODE_MULTI, + false, true, - true); + conversational.getNextCounterpart() + ); } } diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java index d03928c8c..185a15e11 100644 --- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java @@ -178,7 +178,7 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer } try { - conversation = xmppConnectionService.findOrCreateConversation(account, Jid.of(share.contact), false, true); + conversation = xmppConnectionService.findOrCreateConversation(account, Jid.of(share.contact), null, false, false, true, null); } catch (final IllegalArgumentException e) { return; } diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index 24326f048..cbb2140ca 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -93,6 +93,7 @@ import eu.siacs.conversations.ui.util.PendingItem; import eu.siacs.conversations.ui.util.SoftKeyboardUtils; import eu.siacs.conversations.ui.widget.SwipeRefreshListFragment; import eu.siacs.conversations.utils.AccountUtils; +import eu.siacs.conversations.utils.StringUtils; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.utils.XmppUri; import eu.siacs.conversations.xmpp.Jid; @@ -430,7 +431,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne } protected void openConversationForContact(Contact contact) { - Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), false, true); + Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), null, false, false, true, null); SoftKeyboardUtils.hideSoftKeyboard(this); switchToConversation(conversation); } @@ -467,7 +468,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne Toast.makeText(this, R.string.invalid_jid, Toast.LENGTH_SHORT).show(); return; } - Conversation conversation = xmppConnectionService.findOrCreateConversation(bookmark.getAccount(), jid, true, true, true); + Conversation conversation = xmppConnectionService.findOrCreateConversation(bookmark.getAccount(), jid, null, true, true, true, null); bookmark.setConversation(conversation); if (!bookmark.autojoin() && getPreferences().getBoolean("autojoin", getResources().getBoolean(R.bool.autojoin))) { bookmark.setAutojoin(true); @@ -580,13 +581,14 @@ public class StartConversationActivity extends XmppActivity implements XmppConne bookmark.setNick(nick); } xmppConnectionService.createBookmark(account, bookmark); + final Conversation conversation = xmppConnectionService - .findOrCreateConversation(account, contactJid, true, true, true); + .findOrCreateConversation(account, contactJid, null, true, true, true, null); bookmark.setConversation(conversation); switchToConversationDoNotAppend(conversation, invite == null ? null : invite.getBody()); } } else { - final Conversation conversation = xmppConnectionService.findOrCreateConversation(account, contactJid, true, true, true); + final Conversation conversation = xmppConnectionService.findOrCreateConversation(account, contactJid, null, true, true, true, null); switchToConversationDoNotAppend(conversation, invite == null ? null : invite.getBody()); } } else { @@ -669,13 +671,8 @@ public class StartConversationActivity extends XmppActivity implements XmppConne } } - protected void switchToConversation(Contact contact) { - Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), false, true); - switchToConversation(conversation); - } - protected void switchToConversationDoNotAppend(Contact contact, String body) { - Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), false, true); + Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), null, false, false, true, null); switchToConversationDoNotAppend(conversation, body); } @@ -1192,14 +1189,14 @@ public class StartConversationActivity extends XmppActivity implements XmppConne } xmppConnectionService.createBookmark(account, bookmark); final Conversation conversation = xmppConnectionService - .findOrCreateConversation(account, conferenceJid, true, true, true); + .findOrCreateConversation(account, conferenceJid, null, true, true, true, null); bookmark.setConversation(conversation); dialog.dismiss(); switchToConversation(conversation); } } else { final Conversation conversation = xmppConnectionService - .findOrCreateConversation(account, conferenceJid, true, true, true); + .findOrCreateConversation(account, conferenceJid, null, true, true, true, null); dialog.dismiss(); switchToConversation(conversation); } diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index adbf9ea01..27a9fb672 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -552,7 +552,7 @@ public abstract class XmppActivity extends ActionBarActivity { } protected void switchToConversationDoNotAppend(Contact contact, String body, String postInit) { - Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), false, true); + Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), null, false, false, true, null); switchToConversation(conversation, body, false, null, false, true, postInit); } diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java index 57f872fc1..139ca48c2 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java @@ -59,7 +59,12 @@ public class ConversationAdapter if (conversation == null) { return; } + CharSequence name = conversation.getName(); + if (conversation.getNextCounterpart() != null) { + name = viewHolder.binding.getRoot().getResources().getString(R.string.muc_private_conversation_title, conversation.getNextCounterpart().getResource(), conversation.getName()); + } + if (name instanceof Jid) { viewHolder.binding.conversationName.setText( IrregularUnicodeDetector.style(activity, (Jid) name)); 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 a47a5c1d8..7c8b9e418 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -523,7 +523,7 @@ public class MessageAdapter extends ArrayAdapter { Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } else { - String privateMarker; + /*String privateMarker; if (message.getStatus() <= Message.STATUS_RECEIVED) { privateMarker = activity.getString(R.string.private_message); } else { @@ -544,7 +544,7 @@ public class MessageAdapter extends ArrayAdapter { if (hasMeCommand) { body.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), privateMarkerIndex + 1, privateMarkerIndex + 1 + nick.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } + }*/ } if (message.getConversation().getMode() == Conversation.MODE_MULTI && message.getStatus() == Message.STATUS_RECEIVED) { if (message.getConversation() instanceof Conversation) { @@ -644,7 +644,7 @@ public class MessageAdapter extends ArrayAdapter { } private void toggleWhisperInfo(ViewHolder viewHolder, final Message message, final boolean darkBackground) { - if (message.isPrivateMessage()) { + if (false && message.isPrivateMessage()) { final String privateMarker; if (message.getStatus() <= Message.STATUS_RECEIVED) { privateMarker = activity.getString(R.string.private_message); 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 da1ac7a44..404630a3d 100644 --- a/src/main/java/eu/siacs/conversations/ui/util/MucDetailsContextMenuHelper.java +++ b/src/main/java/eu/siacs/conversations/ui/util/MucDetailsContextMenuHelper.java @@ -120,7 +120,8 @@ public final class MucDetailsContextMenuHelper { } } managePermissions.setVisible(managePermissionsVisible); - sendPrivateMessage.setVisible(!isGroupChat && mucOptions.allowPm() && user.getRole().ranks(MucOptions.Role.VISITOR)); + sendPrivateMessage.setVisible(true); + sendPrivateMessage.setEnabled(true); } else { sendPrivateMessage.setVisible(true); sendPrivateMessage.setEnabled(user != null && mucOptions.allowPm() && user.getRole().ranks(MucOptions.Role.VISITOR)); @@ -222,7 +223,7 @@ public final class MucDetailsContextMenuHelper { private static void startConversation(User user, XmppActivity activity) { if (user.getRealJid() != null) { - Conversation newConversation = activity.xmppConnectionService.findOrCreateConversation(user.getAccount(), user.getRealJid().asBareJid(), false, true); + Conversation newConversation = activity.xmppConnectionService.findOrCreateConversation(user.getAccount(), user.getRealJid().asBareJid(), null, false, false, true, null); activity.switchToConversation(newConversation); } } diff --git a/src/main/java/eu/siacs/conversations/ui/util/SendButtonTool.java b/src/main/java/eu/siacs/conversations/ui/util/SendButtonTool.java index 66a355fe4..8f118541b 100644 --- a/src/main/java/eu/siacs/conversations/ui/util/SendButtonTool.java +++ b/src/main/java/eu/siacs/conversations/ui/util/SendButtonTool.java @@ -59,7 +59,7 @@ public class SendButtonTool { } } else { if (empty) { - if (conference && c.getNextCounterpart() != null) { + if (false && conference && c.getNextCounterpart() != null) { return SendButtonAction.CANCEL; } else { String setting = preferences.getString("quick_action", activity.getResources().getString(R.string.quick_action)); diff --git a/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java b/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java index 16677ea8b..3416943a1 100644 --- a/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java @@ -89,7 +89,7 @@ public class ExceptionHelper { builder.setPositiveButton(activity.getText(R.string.send_now), (dialog, which) -> { Log.d(Config.LOGTAG, "using account=" + account.getJid().asBareJid() + " to send in stack trace"); - Conversation conversation = service.findOrCreateConversation(account, Config.BUG_REPORTS, false, true); + Conversation conversation = service.findOrCreateConversation(account, Config.BUG_REPORTS, null, false, false, true, null); Message message = new Message(conversation, report.toString(), Message.ENCRYPTION_NONE); service.sendMessage(message); }); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java index b39673fa5..2c359c7ec 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -297,7 +297,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { if ("proceed".equals(message.getName())) { final Conversation c = mXmppConnectionService.findOrCreateConversation( - account, id.with, false, false); + account, id.with, null, false, false, false, null); final Message previousBusy = c.findRtpSession(sessionId, Message.STATUS_RECEIVED); if (previousBusy != null) { previousBusy.setBody(new RtpSessionStatus(true, 0).toString()); @@ -503,7 +503,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { long timestamp) { final Conversation conversation = mXmppConnectionService.findOrCreateConversation( - account, with.asBareJid(), false, false); + account, with.asBareJid(), null, false, false, false, null); final Message message = new Message(conversation, Message.STATUS_SEND, Message.TYPE_RTP_SESSION, sessionId); message.setBody(new RtpSessionStatus(false, 0).toString()); @@ -520,7 +520,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { long timestamp) { final Conversation conversation = mXmppConnectionService.findOrCreateConversation( - account, with.asBareJid(), false, false); + account, with.asBareJid(), null, false, false, false, null); final Message message = new Message( conversation, Message.STATUS_RECEIVED, Message.TYPE_RTP_SESSION, sessionId); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java index c4ed04bd0..7c6892136 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java @@ -426,7 +426,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void init(JinglePacket packet) { //should move to deliverPacket //TODO if not 'OFFERED' reply with out-of-order this.mJingleStatus = JINGLE_STATUS_INITIATED; - final Conversation conversation = this.xmppConnectionService.findOrCreateConversation(id.account, id.with.asBareJid(), false, false); + final Conversation conversation = this.xmppConnectionService.findOrCreateConversation(id.account, id.with.asBareJid(), null, false, false, false, null); this.message = new Message(conversation, "", Message.ENCRYPTION_NONE); this.message.setStatus(Message.STATUS_RECEIVED); this.mStatus = Transferable.STATUS_OFFER; diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java index faa5725e2..b8630704f 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java @@ -180,7 +180,7 @@ public class JingleRtpConnection extends AbstractJingleConnection final Conversation conversation = jingleConnectionManager .getXmppConnectionService() - .findOrCreateConversation(id.account, id.with.asBareJid(), false, false); + .findOrCreateConversation(id.account, id.with.asBareJid(), null, false, false, false, null); this.message = new Message( conversation, diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index ba780b3da..3da2eee66 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -1045,4 +1045,5 @@ resize filter could_not_create_file + %1$s (%2$s)