From 3765d552926951452b34fb024e8d50f000c6baab Mon Sep 17 00:00:00 2001 From: Christian Schneppe Date: Thu, 17 Nov 2016 20:48:13 +0100 Subject: refactore trust enum to be FingerprintStatus class with trust and active --- .../messenger/crypto/axolotl/AxolotlService.java | 105 ++-- .../crypto/axolotl/FingerprintStatus.java | 122 ++++ .../crypto/axolotl/SQLiteAxolotlStore.java | 22 +- .../crypto/axolotl/XmppAxolotlSession.java | 156 +---- .../java/de/pixart/messenger/entities/Message.java | 6 +- .../messenger/persistance/DatabaseBackend.java | 200 +++--- .../messenger/ui/ContactDetailsActivity.java | 84 +-- .../pixart/messenger/ui/ConversationActivity.java | 6 +- .../de/pixart/messenger/ui/TrustKeysActivity.java | 16 +- .../java/de/pixart/messenger/ui/XmppActivity.java | 184 +++--- .../messenger/ui/adapter/MessageAdapter.java | 694 ++++++++++----------- 11 files changed, 813 insertions(+), 782 deletions(-) create mode 100644 src/main/java/de/pixart/messenger/crypto/axolotl/FingerprintStatus.java (limited to 'src/main/java/de/pixart/messenger') diff --git a/src/main/java/de/pixart/messenger/crypto/axolotl/AxolotlService.java b/src/main/java/de/pixart/messenger/crypto/axolotl/AxolotlService.java index a7503c089..384a19067 100644 --- a/src/main/java/de/pixart/messenger/crypto/axolotl/AxolotlService.java +++ b/src/main/java/de/pixart/messenger/crypto/axolotl/AxolotlService.java @@ -185,8 +185,8 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { } private void fillMap(SQLiteAxolotlStore store) { - List deviceIds = store.getSubDeviceSessions(account.getJid().toBareJid().toPreppedString()); - putDevicesForJid(account.getJid().toBareJid().toPreppedString(), deviceIds, store); + List deviceIds = store.getSubDeviceSessions(account.getJid().toBareJid().toPreppedString()); + putDevicesForJid(account.getJid().toBareJid().toPreppedString(), deviceIds, store); for (Contact contact : account.getRoster().getContacts()) { Jid bareJid = contact.getJid().toBareJid(); String address = bareJid.toString(); @@ -256,18 +256,18 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { return axolotlStore.getIdentityKeyPair().getPublicKey().getFingerprint().replaceAll("\\s", ""); } - public Set getKeysWithTrust(XmppAxolotlSession.Trust trust) { - return axolotlStore.getContactKeysWithTrust(account.getJid().toBareJid().toPreppedString(), trust); + public Set getKeysWithTrust(FingerprintStatus status) { + return axolotlStore.getContactKeysWithTrust(account.getJid().toBareJid().toPreppedString(), status); } - public Set getKeysWithTrust(XmppAxolotlSession.Trust trust, Jid jid) { - return axolotlStore.getContactKeysWithTrust(jid.toBareJid().toPreppedString(), trust); + public Set getKeysWithTrust(FingerprintStatus status, Jid jid) { + return axolotlStore.getContactKeysWithTrust(jid.toBareJid().toPreppedString(), status); } - public Set getKeysWithTrust(XmppAxolotlSession.Trust trust, List jids) { + public Set getKeysWithTrust(FingerprintStatus status, List jids) { Set keys = new HashSet<>(); for(Jid jid : jids) { - keys.addAll(axolotlStore.getContactKeysWithTrust(jid.toPreppedString(), trust)); + keys.addAll(axolotlStore.getContactKeysWithTrust(jid.toPreppedString(), status)); } return keys; } @@ -355,19 +355,6 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { return this.deviceIds.get(account.getJid().toBareJid()); } - private void setTrustOnSessions(final Jid jid, @NonNull final Set deviceIds, - final XmppAxolotlSession.Trust from, - final XmppAxolotlSession.Trust to) { - for (Integer deviceId : deviceIds) { - AxolotlAddress address = new AxolotlAddress(jid.toBareJid().toPreppedString(), deviceId); - XmppAxolotlSession session = sessions.get(address); - if (session != null && session.getFingerprint() != null - && session.getTrust() == from) { - session.setTrust(to); - } - } - } - public void registerDevices(final Jid jid, @NonNull final Set deviceIds) { if (jid.toBareJid().equals(account.getJid().toBareJid())) { if (!deviceIds.isEmpty()) { @@ -389,23 +376,25 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { } Set expiredDevices = new HashSet<>(axolotlStore.getSubDeviceSessions(jid.toBareJid().toPreppedString())); expiredDevices.removeAll(deviceIds); - setTrustOnSessions(jid, expiredDevices, XmppAxolotlSession.Trust.TRUSTED, - XmppAxolotlSession.Trust.INACTIVE_TRUSTED); - setTrustOnSessions(jid, expiredDevices, XmppAxolotlSession.Trust.TRUSTED_X509, - XmppAxolotlSession.Trust.INACTIVE_TRUSTED_X509); - setTrustOnSessions(jid, expiredDevices, XmppAxolotlSession.Trust.UNDECIDED, - XmppAxolotlSession.Trust.INACTIVE_UNDECIDED); - setTrustOnSessions(jid, expiredDevices, XmppAxolotlSession.Trust.UNTRUSTED, - XmppAxolotlSession.Trust.INACTIVE_UNTRUSTED); + for (Integer deviceId : expiredDevices) { + AxolotlAddress address = new AxolotlAddress(jid.toBareJid().toPreppedString(), deviceId); + XmppAxolotlSession session = sessions.get(address); + if (session != null && session.getFingerprint() != null) { + if (session.getTrust().isActive()) { + session.setTrust(session.getTrust().toInactive()); + } + } + } Set newDevices = new HashSet<>(deviceIds); - setTrustOnSessions(jid, newDevices, XmppAxolotlSession.Trust.INACTIVE_TRUSTED, - XmppAxolotlSession.Trust.TRUSTED); - setTrustOnSessions(jid, newDevices, XmppAxolotlSession.Trust.INACTIVE_TRUSTED_X509, - XmppAxolotlSession.Trust.TRUSTED_X509); - setTrustOnSessions(jid, newDevices, XmppAxolotlSession.Trust.INACTIVE_UNDECIDED, - XmppAxolotlSession.Trust.UNDECIDED); - setTrustOnSessions(jid, newDevices, XmppAxolotlSession.Trust.INACTIVE_UNTRUSTED, - XmppAxolotlSession.Trust.UNTRUSTED); + for (Integer deviceId : newDevices) { + AxolotlAddress address = new AxolotlAddress(jid.toBareJid().toPreppedString(), deviceId); + XmppAxolotlSession session = sessions.get(address); + if (session != null && session.getFingerprint() != null) { + if (!session.getTrust().isActive()) { + session.setTrust(session.getTrust().toActive()); + } + } + } this.deviceIds.put(jid, deviceIds); mXmppConnectionService.keyStatusUpdated(null); } @@ -428,7 +417,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { } public void purgeKey(final String fingerprint) { - axolotlStore.setFingerprintTrust(fingerprint.replaceAll("\\s", ""), XmppAxolotlSession.Trust.COMPROMISED); + axolotlStore.setFingerprintTrust(fingerprint.replaceAll("\\s", ""), FingerprintStatus.createCompromised()); } public void publishOwnDeviceIdIfNeeded() { @@ -660,24 +649,24 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { } public Pair isConversationAxolotlCapableDetailed(Conversation conversation) { - if (conversation.getMode() == Conversation.MODE_SINGLE || (conversation.getMucOptions().membersOnly() && conversation.getMucOptions().nonanonymous())) { - final List jids = getCryptoTargets(conversation); - for(Jid jid : jids) { - if (!hasAny(jid) && (!deviceIds.containsKey(jid) || deviceIds.get(jid).isEmpty())) { - if (conversation.getAccount().getRoster().getContact(jid).mutualPresenceSubscription()) { - return new Pair<>(AxolotlCapability.MISSING_KEYS,jid); - } else { - return new Pair<>(AxolotlCapability.MISSING_PRESENCE,jid); - } + if (conversation.getMode() == Conversation.MODE_SINGLE || (conversation.getMucOptions().membersOnly() && conversation.getMucOptions().nonanonymous())) { + final List jids = getCryptoTargets(conversation); + for(Jid jid : jids) { + if (!hasAny(jid) && (!deviceIds.containsKey(jid) || deviceIds.get(jid).isEmpty())) { + if (conversation.getAccount().getRoster().getContact(jid).mutualPresenceSubscription()) { + return new Pair<>(AxolotlCapability.MISSING_KEYS,jid); + } else { + return new Pair<>(AxolotlCapability.MISSING_PRESENCE,jid); + } } } - if (jids.size() > 0) { - return new Pair<>(AxolotlCapability.FULL, null); + if (jids.size() > 0) { + return new Pair<>(AxolotlCapability.FULL, null); } else { return new Pair<>(AxolotlCapability.NO_MEMBERS, null); } - } else { - return new Pair<>(AxolotlCapability.WRONG_CONFIGURATION, null); + } else { + return new Pair<>(AxolotlCapability.WRONG_CONFIGURATION, null); } } @@ -691,16 +680,16 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { return jids; } - public XmppAxolotlSession.Trust getFingerprintTrust(String fingerprint) { - return axolotlStore.getFingerprintTrust(fingerprint); + public FingerprintStatus getFingerprintTrust(String fingerprint) { + return axolotlStore.getFingerprintStatus(fingerprint); } public X509Certificate getFingerprintCertificate(String fingerprint) { return axolotlStore.getFingerprintCertificate(fingerprint); } - public void setFingerprintTrust(String fingerprint, XmppAxolotlSession.Trust trust) { - axolotlStore.setFingerprintTrust(fingerprint, trust); + public void setFingerprintTrust(String fingerprint, FingerprintStatus status) { + axolotlStore.setFingerprintTrust(fingerprint, status); } private void verifySessionWithPEP(final XmppAxolotlSession session) { @@ -723,7 +712,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { mXmppConnectionService.getMemorizingTrustManager().getNonInteractive().checkClientTrusted(verification.first, "RSA"); String fingerprint = session.getFingerprint(); Log.d(Config.LOGTAG, "verified session with x.509 signature. fingerprint was: "+fingerprint); - setFingerprintTrust(fingerprint, XmppAxolotlSession.Trust.TRUSTED_X509); + setFingerprintTrust(fingerprint, FingerprintStatus.createActiveVerified(true)); axolotlStore.setFingerprintCertificate(fingerprint, verification.first[0]); fetchStatusMap.put(address, FetchStatus.SUCCESS_VERIFIED); Bundle information = CryptoHelper.extractCertificateInformation(verification.first[0]); @@ -920,8 +909,8 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { sessions.addAll(findOwnSessions()); boolean verified = false; for(XmppAxolotlSession session : sessions) { - if (session.getTrust().trusted()) { - if (session.getTrust() == XmppAxolotlSession.Trust.TRUSTED_X509) { + if (session.getTrust().isTrustedAndActive()) { + if (session.getTrust().getTrust() == FingerprintStatus.Trust.VERIFIED_X509) { verified = true; } else { return false; diff --git a/src/main/java/de/pixart/messenger/crypto/axolotl/FingerprintStatus.java b/src/main/java/de/pixart/messenger/crypto/axolotl/FingerprintStatus.java new file mode 100644 index 000000000..38aef325e --- /dev/null +++ b/src/main/java/de/pixart/messenger/crypto/axolotl/FingerprintStatus.java @@ -0,0 +1,122 @@ +package de.pixart.messenger.crypto.axolotl; + +import android.content.ContentValues; +import android.database.Cursor; + +public class FingerprintStatus { + + private Trust trust = Trust.UNTRUSTED; + private boolean active = false; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + FingerprintStatus that = (FingerprintStatus) o; + + return active == that.active && trust == that.trust; + } + + @Override + public int hashCode() { + int result = trust.hashCode(); + result = 31 * result + (active ? 1 : 0); + return result; + } + + private FingerprintStatus() { + + + } + + public ContentValues toContentValues() { + final ContentValues contentValues = new ContentValues(); + contentValues.put(SQLiteAxolotlStore.TRUST,trust.toString()); + contentValues.put(SQLiteAxolotlStore.ACTIVE,active ? 1 : 0); + return contentValues; + } + + public static FingerprintStatus fromCursor(Cursor cursor) { + final FingerprintStatus status = new FingerprintStatus(); + try { + status.trust = Trust.valueOf(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.TRUST))); + } catch(IllegalArgumentException e) { + status.trust = Trust.UNTRUSTED; + } + status.active = cursor.getInt(cursor.getColumnIndex(SQLiteAxolotlStore.ACTIVE)) > 0; + return status; + } + + public static FingerprintStatus createActiveUndecided() { + final FingerprintStatus status = new FingerprintStatus(); + status.trust = Trust.UNDECIDED; + status.active = true; + return status; + } + + public static FingerprintStatus createActiveVerified(boolean x509) { + final FingerprintStatus status = new FingerprintStatus(); + status.trust = x509 ? Trust.VERIFIED_X509 : Trust.VERIFIED; + status.active = true; + return status; + } + + public static FingerprintStatus createActive(boolean trusted) { + final FingerprintStatus status = new FingerprintStatus(); + status.trust = trusted ? Trust.TRUSTED : Trust.UNTRUSTED; + status.active = true; + return status; + } + + public boolean isTrustedAndActive() { + return active && isTrusted(); + } + + public boolean isTrusted() { + return trust == Trust.TRUSTED || trust == Trust.VERIFIED || trust == Trust.VERIFIED_X509; + } + + public boolean isCompromised() { + return trust == Trust.COMPROMISED; + } + + public boolean isActive() { + return active; + } + + public FingerprintStatus toActive() { + FingerprintStatus status = new FingerprintStatus(); + status.trust = trust; + status.active = true; + return status; + } + + public FingerprintStatus toInactive() { + FingerprintStatus status = new FingerprintStatus(); + status.trust = trust; + status.active = false; + return status; + } + + public Trust getTrust() { + return trust; + } + + public static FingerprintStatus createCompromised() { + FingerprintStatus status = new FingerprintStatus(); + status.active = false; + status.trust = Trust.COMPROMISED; + return status; + } + + public enum Trust { + COMPROMISED, + UNDECIDED, + UNTRUSTED, + TRUSTED, + VERIFIED, + VERIFIED_X509 + } + +} \ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/crypto/axolotl/SQLiteAxolotlStore.java b/src/main/java/de/pixart/messenger/crypto/axolotl/SQLiteAxolotlStore.java index 7f28ad09e..66786084d 100644 --- a/src/main/java/de/pixart/messenger/crypto/axolotl/SQLiteAxolotlStore.java +++ b/src/main/java/de/pixart/messenger/crypto/axolotl/SQLiteAxolotlStore.java @@ -35,7 +35,9 @@ public class SQLiteAxolotlStore implements AxolotlStore { public static final String KEY = "key"; public static final String FINGERPRINT = "fingerprint"; public static final String NAME = "name"; - public static final String TRUSTED = "trusted"; + public static final String TRUSTED = "trusted"; //no longer used + public static final String TRUST = "trust"; + public static final String ACTIVE = "active"; public static final String OWN = "ownkey"; public static final String CERTIFICATE = "certificate"; @@ -51,11 +53,11 @@ public class SQLiteAxolotlStore implements AxolotlStore { private int localRegistrationId; private int currentPreKeyId = 0; - private final LruCache trustCache = - new LruCache(NUM_TRUSTS_TO_CACHE) { + private final LruCache trustCache = + new LruCache(NUM_TRUSTS_TO_CACHE) { @Override - protected XmppAxolotlSession.Trust create(String fingerprint) { - return mXmppConnectionService.databaseBackend.isIdentityKeyTrusted(account, fingerprint); + protected FingerprintStatus create(String fingerprint) { + return mXmppConnectionService.databaseBackend.getFingerprintStatus(account, fingerprint); } }; @@ -208,12 +210,12 @@ public class SQLiteAxolotlStore implements AxolotlStore { return true; } - public XmppAxolotlSession.Trust getFingerprintTrust(String fingerprint) { + public FingerprintStatus getFingerprintStatus(String fingerprint) { return (fingerprint == null)? null : trustCache.get(fingerprint); } - public void setFingerprintTrust(String fingerprint, XmppAxolotlSession.Trust trust) { - mXmppConnectionService.databaseBackend.setIdentityKeyTrust(account, fingerprint, trust); + public void setFingerprintTrust(String fingerprint, FingerprintStatus status) { + mXmppConnectionService.databaseBackend.setIdentityKeyTrust(account, fingerprint, status); trustCache.remove(fingerprint); } @@ -225,8 +227,8 @@ public class SQLiteAxolotlStore implements AxolotlStore { return mXmppConnectionService.databaseBackend.getIdentityKeyCertifcate(account, fingerprint); } - public Set getContactKeysWithTrust(String bareJid, XmppAxolotlSession.Trust trust) { - return mXmppConnectionService.databaseBackend.loadIdentityKeys(account, bareJid, trust); + public Set getContactKeysWithTrust(String bareJid, FingerprintStatus status) { + return mXmppConnectionService.databaseBackend.loadIdentityKeys(account, bareJid, status); } public long getContactNumTrustedKeys(String bareJid) { diff --git a/src/main/java/de/pixart/messenger/crypto/axolotl/XmppAxolotlSession.java b/src/main/java/de/pixart/messenger/crypto/axolotl/XmppAxolotlSession.java index c2cb2a3e7..a98583ac2 100644 --- a/src/main/java/de/pixart/messenger/crypto/axolotl/XmppAxolotlSession.java +++ b/src/main/java/de/pixart/messenger/crypto/axolotl/XmppAxolotlSession.java @@ -19,9 +19,6 @@ import org.whispersystems.libaxolotl.protocol.CiphertextMessage; import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; import org.whispersystems.libaxolotl.protocol.WhisperMessage; -import java.util.HashMap; -import java.util.Map; - import de.pixart.messenger.Config; import de.pixart.messenger.entities.Account; @@ -34,76 +31,6 @@ public class XmppAxolotlSession { private Integer preKeyId = null; private boolean fresh = true; - public enum Trust { - UNDECIDED(0), - TRUSTED(1), - UNTRUSTED(2), - COMPROMISED(3), - INACTIVE_TRUSTED(4), - INACTIVE_UNDECIDED(5), - INACTIVE_UNTRUSTED(6), - TRUSTED_X509(7), - INACTIVE_TRUSTED_X509(8); - - private static final Map trustsByValue = new HashMap<>(); - - static { - for (Trust trust : Trust.values()) { - trustsByValue.put(trust.getCode(), trust); - } - } - - private final int code; - - Trust(int code) { - this.code = code; - } - - public int getCode() { - return this.code; - } - - public String toString() { - switch (this) { - case UNDECIDED: - return "Trust undecided " + getCode(); - case TRUSTED: - return "Trusted " + getCode(); - case COMPROMISED: - return "Compromised " + getCode(); - case INACTIVE_TRUSTED: - return "Inactive (Trusted)" + getCode(); - case INACTIVE_UNDECIDED: - return "Inactive (Undecided)" + getCode(); - case INACTIVE_UNTRUSTED: - return "Inactive (Untrusted)" + getCode(); - case TRUSTED_X509: - return "Trusted (X509) " + getCode(); - case INACTIVE_TRUSTED_X509: - return "Inactive (Trusted (X509)) " + getCode(); - case UNTRUSTED: - default: - return "Untrusted " + getCode(); - } - } - - public static Trust fromBoolean(Boolean trusted) { - return trusted ? TRUSTED : UNTRUSTED; - } - - public static Trust fromCode(int code) { - return trustsByValue.get(code); - } - - public boolean trusted() { - return this == TRUSTED_X509 || this == TRUSTED; - } - - public boolean trustedInactive() { - return this == INACTIVE_TRUSTED_X509 || this == INACTIVE_TRUSTED; - } - } - public XmppAxolotlSession(Account account, SQLiteAxolotlStore store, AxolotlAddress remoteAddress, IdentityKey identityKey) { this(account, store, remoteAddress); this.identityKey = identityKey; @@ -145,75 +72,60 @@ public class XmppAxolotlSession { this.fresh = false; } - protected void setTrust(Trust trust) { - sqLiteAxolotlStore.setFingerprintTrust(getFingerprint(), trust); + protected void setTrust(FingerprintStatus status) { + sqLiteAxolotlStore.setFingerprintTrust(getFingerprint(), status); } - protected Trust getTrust() { - Trust trust = sqLiteAxolotlStore.getFingerprintTrust(getFingerprint()); - return (trust == null) ? Trust.UNDECIDED : trust; + protected FingerprintStatus getTrust() { + FingerprintStatus status = sqLiteAxolotlStore.getFingerprintStatus(getFingerprint()); + return (status == null) ? FingerprintStatus.createActiveUndecided() : status; } @Nullable public byte[] processReceiving(byte[] encryptedKey) { byte[] plaintext = null; - Trust trust = getTrust(); - switch (trust) { - case INACTIVE_TRUSTED: - case UNDECIDED: - case UNTRUSTED: - case TRUSTED: - case INACTIVE_TRUSTED_X509: - case TRUSTED_X509: + FingerprintStatus status = getTrust(); + if (!status.isCompromised()) { + try { try { - try { - PreKeyWhisperMessage message = new PreKeyWhisperMessage(encryptedKey); - if (!message.getPreKeyId().isPresent()) { - Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "PreKeyWhisperMessage did not contain a PreKeyId"); - break; - } - Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "PreKeyWhisperMessage received, new session ID:" + message.getSignedPreKeyId() + "/" + message.getPreKeyId()); - IdentityKey msgIdentityKey = message.getIdentityKey(); - if (this.identityKey != null && !this.identityKey.equals(msgIdentityKey)) { - Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Had session with fingerprint " + this.getFingerprint() + ", received message with fingerprint " + msgIdentityKey.getFingerprint()); - } else { - this.identityKey = msgIdentityKey; - plaintext = cipher.decrypt(message); - preKeyId = message.getPreKeyId().get(); - } - } catch (InvalidMessageException | InvalidVersionException e) { - Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "WhisperMessage received"); - WhisperMessage message = new WhisperMessage(encryptedKey); + PreKeyWhisperMessage message = new PreKeyWhisperMessage(encryptedKey); + if (!message.getPreKeyId().isPresent()) { + Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "PreKeyWhisperMessage did not contain a PreKeyId"); + return null; + } + Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "PreKeyWhisperMessage received, new session ID:" + message.getSignedPreKeyId() + "/" + message.getPreKeyId()); + IdentityKey msgIdentityKey = message.getIdentityKey(); + if (this.identityKey != null && !this.identityKey.equals(msgIdentityKey)) { + Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Had session with fingerprint " + this.getFingerprint() + ", received message with fingerprint " + msgIdentityKey.getFingerprint()); + } else { + this.identityKey = msgIdentityKey; plaintext = cipher.decrypt(message); - } catch (InvalidKeyException | InvalidKeyIdException | UntrustedIdentityException e) { - Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Error decrypting axolotl header, " + e.getClass().getName() + ": " + e.getMessage()); + preKeyId = message.getPreKeyId().get(); } - } catch (LegacyMessageException | InvalidMessageException | DuplicateMessageException | NoSessionException e) { + } catch (InvalidMessageException | InvalidVersionException e) { + Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "WhisperMessage received"); + WhisperMessage message = new WhisperMessage(encryptedKey); + plaintext = cipher.decrypt(message); + } catch (InvalidKeyException | InvalidKeyIdException | UntrustedIdentityException e) { Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Error decrypting axolotl header, " + e.getClass().getName() + ": " + e.getMessage()); } + } catch (LegacyMessageException | InvalidMessageException | DuplicateMessageException | NoSessionException e) { + Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Error decrypting axolotl header, " + e.getClass().getName() + ": " + e.getMessage()); + } - if (plaintext != null) { - if (trust == Trust.INACTIVE_TRUSTED) { - setTrust(Trust.TRUSTED); - } else if (trust == Trust.INACTIVE_TRUSTED_X509) { - setTrust(Trust.TRUSTED_X509); - } + if (plaintext != null) { + if (!status.isActive()) { + setTrust(status.toActive()); } - - break; - - case COMPROMISED: - default: - // ignore - break; + } } return plaintext; } @Nullable public byte[] processSending(@NonNull byte[] outgoingMessage) { - Trust trust = getTrust(); - if (trust.trusted()) { + FingerprintStatus status = getTrust(); + if (status.isTrustedAndActive()) { CiphertextMessage ciphertextMessage = cipher.encrypt(outgoingMessage); return ciphertextMessage.serialize(); } else { diff --git a/src/main/java/de/pixart/messenger/entities/Message.java b/src/main/java/de/pixart/messenger/entities/Message.java index e3dc68ce9..9cdf57922 100644 --- a/src/main/java/de/pixart/messenger/entities/Message.java +++ b/src/main/java/de/pixart/messenger/entities/Message.java @@ -8,7 +8,7 @@ import java.net.MalformedURLException; import java.net.URL; import de.pixart.messenger.Config; -import de.pixart.messenger.crypto.axolotl.XmppAxolotlSession; +import de.pixart.messenger.crypto.axolotl.FingerprintStatus; import de.pixart.messenger.utils.CryptoHelper; import de.pixart.messenger.utils.GeoHelper; import de.pixart.messenger.utils.MimeUtils; @@ -817,8 +817,8 @@ public class Message extends AbstractEntity { } public boolean isTrusted() { - XmppAxolotlSession.Trust t = conversation.getAccount().getAxolotlService().getFingerprintTrust(axolotlFingerprint); - return t != null && t.trusted(); + FingerprintStatus s = conversation.getAccount().getAxolotlService().getFingerprintTrust(axolotlFingerprint); + return s != null && s.isTrustedAndActive(); } private int getPreviousEncryption() { diff --git a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java index 812339a46..ada5bf71b 100644 --- a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java +++ b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java @@ -28,16 +28,18 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import de.pixart.messenger.Config; import de.pixart.messenger.crypto.axolotl.AxolotlService; +import de.pixart.messenger.crypto.axolotl.FingerprintStatus; import de.pixart.messenger.crypto.axolotl.SQLiteAxolotlStore; -import de.pixart.messenger.crypto.axolotl.XmppAxolotlSession; import de.pixart.messenger.entities.Account; import de.pixart.messenger.entities.Contact; import de.pixart.messenger.entities.Conversation; @@ -53,7 +55,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { private static DatabaseBackend instance = null; public static final String DATABASE_NAME = "history"; - public static final int DATABASE_VERSION = 30; + public static final int DATABASE_VERSION = 31; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -128,7 +130,8 @@ public class DatabaseBackend extends SQLiteOpenHelper { + SQLiteAxolotlStore.OWN + " INTEGER, " + SQLiteAxolotlStore.FINGERPRINT + " TEXT, " + SQLiteAxolotlStore.CERTIFICATE + " BLOB, " - + SQLiteAxolotlStore.TRUSTED + " INTEGER, " + + SQLiteAxolotlStore.TRUST + " TEXT, " + + SQLiteAxolotlStore.ACTIVE + " NUMBER, " + SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY(" + SQLiteAxolotlStore.ACCOUNT + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, " @@ -138,10 +141,10 @@ public class DatabaseBackend extends SQLiteOpenHelper { + ") ON CONFLICT IGNORE" + ");"; - private static String START_TIMES_TABLE = "start_times"; - private static String CREATE_START_TIMES_TABLE = "create table "+START_TIMES_TABLE+" (timestamp NUMBER);"; + private static String START_TIMES_TABLE = "start_times"; + private static String CREATE_START_TIMES_TABLE = "create table "+START_TIMES_TABLE+" (timestamp NUMBER);"; - private DatabaseBackend(Context context) { + private DatabaseBackend(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @@ -183,7 +186,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { + Message.EDITED + " TEXT, " + Message.READ + " NUMBER DEFAULT 1, " + Message.OOB + " INTEGER, " - + Message.ERROR_MESSAGE + " TEXT," + + Message.ERROR_MESSAGE + " TEXT," + Message.REMOTE_MSG_ID + " TEXT, FOREIGN KEY(" + Message.CONVERSATION + ") REFERENCES " + Conversation.TABLENAME + "(" + Conversation.UUID @@ -196,7 +199,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.execSQL(CREATE_SIGNED_PREKEYS_STATEMENT); db.execSQL(CREATE_IDENTITIES_STATEMENT); db.execSQL(CREATE_PRESENCE_TEMPLATES_STATEMENT); - db.execSQL(CREATE_START_TIMES_TABLE); + db.execSQL(CREATE_START_TIMES_TABLE); } @Override @@ -295,7 +298,16 @@ public class DatabaseBackend extends SQLiteOpenHelper { deleteSession(db, account, ownAddress); IdentityKeyPair identityKeyPair = loadOwnIdentityKeyPair(db, account); if (identityKeyPair != null) { - setIdentityKeyTrust(db, account, identityKeyPair.getPublicKey().getFingerprint().replaceAll("\\s", ""), XmppAxolotlSession.Trust.TRUSTED); + String[] selectionArgs = { + account.getUuid(), + identityKeyPair.getPublicKey().getFingerprint().replaceAll("\\s", "") + }; + ContentValues values = new ContentValues(); + values.put(SQLiteAxolotlStore.TRUSTED, 2); + db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME, values, + SQLiteAxolotlStore.ACCOUNT + " = ? AND " + + SQLiteAxolotlStore.FINGERPRINT + " = ? ", + selectionArgs); } else { Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not load own identity key pair"); } @@ -338,13 +350,39 @@ public class DatabaseBackend extends SQLiteOpenHelper { canonicalizeJids(db); } - if (oldVersion < 29 && newVersion >= 29) { - db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.ERROR_MESSAGE + " TEXT"); - } + if (oldVersion < 29 && newVersion >= 29) { + db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.ERROR_MESSAGE + " TEXT"); + } - if (oldVersion < 30 && newVersion >= 30) { - db.execSQL(CREATE_START_TIMES_TABLE); - } + if (oldVersion < 30 && newVersion >= 30) { + db.execSQL(CREATE_START_TIMES_TABLE); + } + if (oldVersion < 31 && newVersion >= 31) { + db.execSQL("ALTER TABLE "+ SQLiteAxolotlStore.IDENTITIES_TABLENAME + " ADD COLUMN "+SQLiteAxolotlStore.TRUST + " TEXT"); + db.execSQL("ALTER TABLE "+ SQLiteAxolotlStore.IDENTITIES_TABLENAME + " ADD COLUMN "+SQLiteAxolotlStore.ACTIVE + " NUMBER"); + HashMap migration = new HashMap<>(); + migration.put(0,createFingerprintStatusContentValues(FingerprintStatus.Trust.UNDECIDED,true)); + migration.put(1,createFingerprintStatusContentValues(FingerprintStatus.Trust.TRUSTED, true)); + migration.put(2,createFingerprintStatusContentValues(FingerprintStatus.Trust.UNTRUSTED, true)); + migration.put(3,createFingerprintStatusContentValues(FingerprintStatus.Trust.COMPROMISED, false)); + migration.put(4,createFingerprintStatusContentValues(FingerprintStatus.Trust.TRUSTED, false)); + migration.put(5,createFingerprintStatusContentValues(FingerprintStatus.Trust.UNDECIDED, false)); + migration.put(6,createFingerprintStatusContentValues(FingerprintStatus.Trust.UNTRUSTED, false)); + migration.put(7,createFingerprintStatusContentValues(FingerprintStatus.Trust.VERIFIED_X509, true)); + migration.put(8,createFingerprintStatusContentValues(FingerprintStatus.Trust.VERIFIED_X509, false)); + for(Map.Entry entry : migration.entrySet()) { + String whereClause = SQLiteAxolotlStore.TRUSTED+"=?"; + String[] where = {String.valueOf(entry.getKey())}; + db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME,entry.getValue(),whereClause,where); + } + } + } + + private static ContentValues createFingerprintStatusContentValues(FingerprintStatus.Trust trust, boolean active) { + ContentValues values = new ContentValues(); + values.put(SQLiteAxolotlStore.TRUST,trust.toString()); + values.put(SQLiteAxolotlStore.ACTIVE,active ? 1 : 0); + return values; } private void canonicalizeJids(SQLiteDatabase db) { @@ -741,32 +779,32 @@ public class DatabaseBackend extends SQLiteOpenHelper { } } - public Pair getLastClearDate(Account account) { - SQLiteDatabase db = this.getReadableDatabase(); - String[] columns = {Conversation.ATTRIBUTES}; - String selection = Conversation.ACCOUNT + "=?"; - String[] args = {account.getUuid()}; - Cursor cursor = db.query(Conversation.TABLENAME, columns, selection, args, null, null, null); - long maxClearDate = 0; - while (cursor.moveToNext()) { - try { - final JSONObject jsonObject = new JSONObject(cursor.getString(0)); - maxClearDate = Math.max(maxClearDate, jsonObject.getLong(Conversation.ATTRIBUTE_LAST_CLEAR_HISTORY)); - } catch (Exception e) { - //ignored - } - } - cursor.close(); - return new Pair<>(maxClearDate, null); - } + public Pair getLastClearDate(Account account) { + SQLiteDatabase db = this.getReadableDatabase(); + String[] columns = {Conversation.ATTRIBUTES}; + String selection = Conversation.ACCOUNT + "=?"; + String[] args = {account.getUuid()}; + Cursor cursor = db.query(Conversation.TABLENAME, columns, selection, args, null, null, null); + long maxClearDate = 0; + while (cursor.moveToNext()) { + try { + final JSONObject jsonObject = new JSONObject(cursor.getString(0)); + maxClearDate = Math.max(maxClearDate, jsonObject.getLong(Conversation.ATTRIBUTE_LAST_CLEAR_HISTORY)); + } catch (Exception e) { + //ignored + } + } + cursor.close(); + return new Pair<>(maxClearDate, null); + } private Cursor getCursorForSession(Account account, AxolotlAddress contact) { final SQLiteDatabase db = this.getReadableDatabase(); String[] selectionArgs = {account.getUuid(), contact.getName(), Integer.toString(contact.getDeviceId())}; - return db.query(SQLiteAxolotlStore.SESSION_TABLENAME, - null, + return db.query(SQLiteAxolotlStore.SESSION_TABLENAME, + null, SQLiteAxolotlStore.ACCOUNT + " = ? AND " + SQLiteAxolotlStore.NAME + " = ? AND " + SQLiteAxolotlStore.DEVICE_ID + " = ? ", @@ -1005,7 +1043,8 @@ public class DatabaseBackend extends SQLiteOpenHelper { } private Cursor getIdentityKeyCursor(SQLiteDatabase db, Account account, String name, Boolean own, String fingerprint) { - String[] columns = {SQLiteAxolotlStore.TRUSTED, + String[] columns = {SQLiteAxolotlStore.TRUST, + SQLiteAxolotlStore.ACTIVE, SQLiteAxolotlStore.KEY}; ArrayList selectionArgs = new ArrayList<>(4); selectionArgs.add(account.getUuid()); @@ -1057,14 +1096,12 @@ public class DatabaseBackend extends SQLiteOpenHelper { return loadIdentityKeys(account, name, null); } - public Set loadIdentityKeys(Account account, String name, XmppAxolotlSession.Trust trust) { + public Set loadIdentityKeys(Account account, String name, FingerprintStatus status) { Set identityKeys = new HashSet<>(); Cursor cursor = getIdentityKeyCursor(account, name, false); while (cursor.moveToNext()) { - if (trust != null && - cursor.getInt(cursor.getColumnIndex(SQLiteAxolotlStore.TRUSTED)) - != trust.getCode()) { + if (status != null && !FingerprintStatus.fromCursor(cursor).equals(status)) { continue; } try { @@ -1083,22 +1120,24 @@ public class DatabaseBackend extends SQLiteOpenHelper { String[] args = { account.getUuid(), name, - String.valueOf(XmppAxolotlSession.Trust.TRUSTED.getCode()), - String.valueOf(XmppAxolotlSession.Trust.TRUSTED_X509.getCode()) + FingerprintStatus.Trust.TRUSTED.toString(), + FingerprintStatus.Trust.VERIFIED.toString(), + FingerprintStatus.Trust.VERIFIED_X509.toString() }; return DatabaseUtils.queryNumEntries(db, SQLiteAxolotlStore.IDENTITIES_TABLENAME, SQLiteAxolotlStore.ACCOUNT + " = ?" + " AND " + SQLiteAxolotlStore.NAME + " = ?" - + " AND (" + SQLiteAxolotlStore.TRUSTED + " = ? OR " + SQLiteAxolotlStore.TRUSTED + " = ?)", + + " AND (" + SQLiteAxolotlStore.TRUST + " = ? OR " + SQLiteAxolotlStore.TRUST + " = ? OR " +SQLiteAxolotlStore.TRUST +" = ?)" + + " AND " +SQLiteAxolotlStore.ACTIVE + " > 0", args ); } private void storeIdentityKey(Account account, String name, boolean own, String fingerprint, String base64Serialized) { - storeIdentityKey(account, name, own, fingerprint, base64Serialized, XmppAxolotlSession.Trust.UNDECIDED); + storeIdentityKey(account, name, own, fingerprint, base64Serialized, FingerprintStatus.createActiveUndecided()); } - private void storeIdentityKey(Account account, String name, boolean own, String fingerprint, String base64Serialized, XmppAxolotlSession.Trust trusted) { + private void storeIdentityKey(Account account, String name, boolean own, String fingerprint, String base64Serialized, FingerprintStatus status) { SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(SQLiteAxolotlStore.ACCOUNT, account.getUuid()); @@ -1106,35 +1145,34 @@ public class DatabaseBackend extends SQLiteOpenHelper { values.put(SQLiteAxolotlStore.OWN, own ? 1 : 0); values.put(SQLiteAxolotlStore.FINGERPRINT, fingerprint); values.put(SQLiteAxolotlStore.KEY, base64Serialized); - values.put(SQLiteAxolotlStore.TRUSTED, trusted.getCode()); + values.putAll(status.toContentValues()); db.insert(SQLiteAxolotlStore.IDENTITIES_TABLENAME, null, values); } - public XmppAxolotlSession.Trust isIdentityKeyTrusted(Account account, String fingerprint) { + public FingerprintStatus getFingerprintStatus(Account account, String fingerprint) { Cursor cursor = getIdentityKeyCursor(account, fingerprint); - XmppAxolotlSession.Trust trust = null; + final FingerprintStatus status; if (cursor.getCount() > 0) { cursor.moveToFirst(); - int trustValue = cursor.getInt(cursor.getColumnIndex(SQLiteAxolotlStore.TRUSTED)); - trust = XmppAxolotlSession.Trust.fromCode(trustValue); + status = FingerprintStatus.fromCursor(cursor); + } else { + status = null; } cursor.close(); - return trust; + return status; } - public boolean setIdentityKeyTrust(Account account, String fingerprint, XmppAxolotlSession.Trust trust) { + public boolean setIdentityKeyTrust(Account account, String fingerprint, FingerprintStatus fingerprintStatus) { SQLiteDatabase db = this.getWritableDatabase(); - return setIdentityKeyTrust(db, account, fingerprint, trust); + return setIdentityKeyTrust(db, account, fingerprint, fingerprintStatus); } - private boolean setIdentityKeyTrust(SQLiteDatabase db, Account account, String fingerprint, XmppAxolotlSession.Trust trust) { + private boolean setIdentityKeyTrust(SQLiteDatabase db, Account account, String fingerprint, FingerprintStatus status) { String[] selectionArgs = { account.getUuid(), fingerprint }; - ContentValues values = new ContentValues(); - values.put(SQLiteAxolotlStore.TRUSTED, trust.getCode()); - int rows = db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME, values, + int rows = db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME, status.toContentValues(), SQLiteAxolotlStore.ACCOUNT + " = ? AND " + SQLiteAxolotlStore.FINGERPRINT + " = ? ", selectionArgs); @@ -1193,7 +1231,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { } public void storeOwnIdentityKeyPair(Account account, IdentityKeyPair identityKeyPair) { - storeIdentityKey(account, account.getJid().toBareJid().toPreppedString(), true, identityKeyPair.getPublicKey().getFingerprint().replaceAll("\\s", ""), Base64.encodeToString(identityKeyPair.serialize(), Base64.DEFAULT), XmppAxolotlSession.Trust.TRUSTED); + storeIdentityKey(account, account.getJid().toBareJid().toPreppedString(), true, identityKeyPair.getPublicKey().getFingerprint().replaceAll("\\s", ""), Base64.encodeToString(identityKeyPair.serialize(), Base64.DEFAULT), FingerprintStatus.createActiveVerified(false)); } public void recreateAxolotlDb(SQLiteDatabase db) { @@ -1229,27 +1267,27 @@ public class DatabaseBackend extends SQLiteOpenHelper { deleteArgs); } - public boolean startTimeCountExceedsThreshold() { - SQLiteDatabase db = this.getWritableDatabase(); - long cleanBeforeTimestamp = System.currentTimeMillis() - Config.FREQUENT_RESTARTS_DETECTION_WINDOW; - db.execSQL("delete from "+START_TIMES_TABLE+" where timestamp < "+cleanBeforeTimestamp); - ContentValues values = new ContentValues(); - values.put("timestamp",System.currentTimeMillis()); - db.insert(START_TIMES_TABLE,null,values); - String[] columns = new String[]{"count(timestamp)"}; - Cursor cursor = db.query(START_TIMES_TABLE,columns,null,null,null,null,null); - int count; - if (cursor.moveToFirst()) { - count = cursor.getInt(0); - } else { - count = 0; - } - cursor.close(); - return count >= Config.FREQUENT_RESTARTS_THRESHOLD; - } - - public void clearStartTimeCounter() { - SQLiteDatabase db = this.getWritableDatabase(); - db.execSQL("delete from " + START_TIMES_TABLE); - } + public boolean startTimeCountExceedsThreshold() { + SQLiteDatabase db = this.getWritableDatabase(); + long cleanBeforeTimestamp = System.currentTimeMillis() - Config.FREQUENT_RESTARTS_DETECTION_WINDOW; + db.execSQL("delete from "+START_TIMES_TABLE+" where timestamp < "+cleanBeforeTimestamp); + ContentValues values = new ContentValues(); + values.put("timestamp",System.currentTimeMillis()); + db.insert(START_TIMES_TABLE,null,values); + String[] columns = new String[]{"count(timestamp)"}; + Cursor cursor = db.query(START_TIMES_TABLE,columns,null,null,null,null,null); + int count; + if (cursor.moveToFirst()) { + count = cursor.getInt(0); + } else { + count = 0; + } + cursor.close(); + return count >= Config.FREQUENT_RESTARTS_THRESHOLD; + } + + public void clearStartTimeCounter() { + SQLiteDatabase db = this.getWritableDatabase(); + db.execSQL("delete from " + START_TIMES_TABLE); + } } diff --git a/src/main/java/de/pixart/messenger/ui/ContactDetailsActivity.java b/src/main/java/de/pixart/messenger/ui/ContactDetailsActivity.java index 9fc302c47..c3992c179 100644 --- a/src/main/java/de/pixart/messenger/ui/ContactDetailsActivity.java +++ b/src/main/java/de/pixart/messenger/ui/ContactDetailsActivity.java @@ -40,7 +40,7 @@ import de.pixart.messenger.Config; import de.pixart.messenger.R; import de.pixart.messenger.crypto.PgpEngine; import de.pixart.messenger.crypto.axolotl.AxolotlService; -import de.pixart.messenger.crypto.axolotl.XmppAxolotlSession; +import de.pixart.messenger.crypto.axolotl.FingerprintStatus; import de.pixart.messenger.entities.Account; import de.pixart.messenger.entities.Contact; import de.pixart.messenger.entities.Conversation; @@ -71,14 +71,14 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd @Override public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { + boolean isChecked) { if (isChecked) { if (contact .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { xmppConnectionService.sendPresencePacket(contact - .getAccount(), + .getAccount(), xmppConnectionService.getPresenceGenerator() - .sendPresenceUpdatesTo(contact)); + .sendPresenceUpdatesTo(contact)); } else { contact.setOption(Contact.Options.PREEMPTIVE_GRANT); } @@ -86,7 +86,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd contact.resetOption(Contact.Options.PREEMPTIVE_GRANT); xmppConnectionService.sendPresencePacket(contact.getAccount(), xmppConnectionService.getPresenceGenerator() - .stopPresenceUpdatesTo(contact)); + .stopPresenceUpdatesTo(contact)); } } }; @@ -94,15 +94,15 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd @Override public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { + boolean isChecked) { if (isChecked) { xmppConnectionService.sendPresencePacket(contact.getAccount(), xmppConnectionService.getPresenceGenerator() - .requestPresenceUpdatesFrom(contact)); + .requestPresenceUpdatesFrom(contact)); } else { xmppConnectionService.sendPresencePacket(contact.getAccount(), xmppConnectionService.getPresenceGenerator() - .stopPresenceUpdatesFrom(contact)); + .stopPresenceUpdatesFrom(contact)); } } }; @@ -226,18 +226,18 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd } } - @Override - public void onStart() { - super.onStart(); - final int theme = findTheme(); - if (this.mTheme != theme) { - recreate(); - } else { - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - this.showDynamicTags = preferences.getBoolean("show_dynamic_tags", false); - this.showLastSeen = preferences.getBoolean("last_activity", false); - } - } + @Override + public void onStart() { + super.onStart(); + final int theme = findTheme(); + if (this.mTheme != theme) { + recreate(); + } else { + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + this.showDynamicTags = preferences.getBoolean("show_dynamic_tags", false); + this.showLastSeen = preferences.getBoolean("last_activity", false); + } + } @Override public boolean onOptionsItemSelected(final MenuItem menuItem) { @@ -252,11 +252,11 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd break; case R.id.action_delete_contact: builder.setTitle(getString(R.string.action_delete_contact)) - .setMessage( - getString(R.string.remove_contact_text, - contact.getDisplayJid())) - .setPositiveButton(getString(R.string.delete), - removeFromRoster).create().show(); + .setMessage( + getString(R.string.remove_contact_text, + contact.getDisplayJid())) + .setPositiveButton(getString(R.string.delete), + removeFromRoster).create().show(); break; case R.id.action_edit_contact: Uri systemAccount = contact.getSystemAccount(); @@ -267,7 +267,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd public void onValueEdited(String value) { contact.setServerName(value); ContactDetailsActivity.this.xmppConnectionService - .pushContactToServer(contact); + .pushContactToServer(contact); populateView(); } }); @@ -320,18 +320,18 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd if (contact == null) { return; } - if (getActionBar() != null) { - final ActionBar ab = getActionBar(); - ab.setCustomView(R.layout.ab_title); - ab.setDisplayShowCustomEnabled(true); - TextView abtitle = (TextView) findViewById(android.R.id.text1); - TextView absubtitle = (TextView) findViewById(android.R.id.text2); - abtitle.setText(contact.getDisplayName()); - abtitle.setSelected(true); - abtitle.setClickable(false); - absubtitle.setVisibility(View.GONE); - absubtitle.setClickable(false); - } + if (getActionBar() != null) { + final ActionBar ab = getActionBar(); + ab.setCustomView(R.layout.ab_title); + ab.setDisplayShowCustomEnabled(true); + TextView abtitle = (TextView) findViewById(android.R.id.text1); + TextView absubtitle = (TextView) findViewById(android.R.id.text2); + abtitle.setText(contact.getDisplayName()); + abtitle.setSelected(true); + abtitle.setClickable(false); + absubtitle.setVisibility(View.GONE); + absubtitle.setClickable(false); + } invalidateOptionsMenu(); setTitle(contact.getDisplayName()); @@ -485,7 +485,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd @Override public void onClick(View v) { PgpEngine pgp = ContactDetailsActivity.this.xmppConnectionService - .getPgpEngine(); + .getPgpEngine(); if (pgp != null) { PendingIntent intent = pgp.getIntentForKey(contact); if (intent != null) { @@ -524,8 +524,8 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd } private void onOmemoKeyClicked(Account account, String fingerprint) { - final XmppAxolotlSession.Trust trust = account.getAxolotlService().getFingerprintTrust(fingerprint); - if (Config.X509_VERIFICATION && trust != null && trust == XmppAxolotlSession.Trust.TRUSTED_X509) { + FingerprintStatus status = account.getAxolotlService().getFingerprintTrust(fingerprint); + if (Config.X509_VERIFICATION && status != null && status.getTrust() == FingerprintStatus.Trust.VERIFIED_X509) { X509Certificate x509Certificate = account.getAxolotlService().getFingerprintCertificate(fingerprint); if (x509Certificate != null) { showCertificateInformationDialog(CryptoHelper.extractCertificateInformation(x509Certificate)); @@ -581,7 +581,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd public void onBackendConnected() { if ((accountJid != null) && (contactJid != null)) { Account account = xmppConnectionService - .findAccountByJid(accountJid); + .findAccountByJid(accountJid); if (account == null) { return; } diff --git a/src/main/java/de/pixart/messenger/ui/ConversationActivity.java b/src/main/java/de/pixart/messenger/ui/ConversationActivity.java index be7514b2c..1fb23ff69 100644 --- a/src/main/java/de/pixart/messenger/ui/ConversationActivity.java +++ b/src/main/java/de/pixart/messenger/ui/ConversationActivity.java @@ -61,7 +61,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import de.pixart.messenger.Config; import de.pixart.messenger.R; import de.pixart.messenger.crypto.axolotl.AxolotlService; -import de.pixart.messenger.crypto.axolotl.XmppAxolotlSession; +import de.pixart.messenger.crypto.axolotl.FingerprintStatus; import de.pixart.messenger.entities.Account; import de.pixart.messenger.entities.Blockable; import de.pixart.messenger.entities.Contact; @@ -2139,8 +2139,8 @@ public class ConversationActivity extends XmppActivity AxolotlService axolotlService = mSelectedConversation.getAccount().getAxolotlService(); final List targets = axolotlService.getCryptoTargets(mSelectedConversation); boolean hasUnaccepted = !mSelectedConversation.getAcceptedCryptoTargets().containsAll(targets); - boolean hasUndecidedOwn = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED).isEmpty(); - boolean hasUndecidedContacts = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, targets).isEmpty(); + boolean hasUndecidedOwn = !axolotlService.getKeysWithTrust(FingerprintStatus.createActiveUndecided()).isEmpty(); + boolean hasUndecidedContacts = !axolotlService.getKeysWithTrust(FingerprintStatus.createActiveUndecided(), targets).isEmpty(); boolean hasPendingKeys = !axolotlService.findDevicesWithoutSession(mSelectedConversation).isEmpty(); boolean hasNoTrustedKeys = axolotlService.anyTargetHasNoTrustedKeys(targets); if(hasUndecidedOwn || hasUndecidedContacts || hasPendingKeys || hasNoTrustedKeys || hasUnaccepted) { diff --git a/src/main/java/de/pixart/messenger/ui/TrustKeysActivity.java b/src/main/java/de/pixart/messenger/ui/TrustKeysActivity.java index 5b274d102..b737e17f1 100644 --- a/src/main/java/de/pixart/messenger/ui/TrustKeysActivity.java +++ b/src/main/java/de/pixart/messenger/ui/TrustKeysActivity.java @@ -20,7 +20,7 @@ import java.util.Set; import de.pixart.messenger.R; import de.pixart.messenger.crypto.axolotl.AxolotlService; -import de.pixart.messenger.crypto.axolotl.XmppAxolotlSession; +import de.pixart.messenger.crypto.axolotl.FingerprintStatus; import de.pixart.messenger.entities.Account; import de.pixart.messenger.entities.Conversation; import de.pixart.messenger.xmpp.OnKeyStatusUpdated; @@ -108,7 +108,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate for(final String fingerprint : ownKeysToTrust.keySet()) { hasOwnKeys = true; addFingerprintRowWithListeners(ownKeys, mAccount, fingerprint, false, - XmppAxolotlSession.Trust.fromBoolean(ownKeysToTrust.get(fingerprint)), false, + FingerprintStatus.createActive(ownKeysToTrust.get(fingerprint)), false, new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { @@ -133,7 +133,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate final Map fingerprints = entry.getValue(); for (final String fingerprint : fingerprints.keySet()) { addFingerprintRowWithListeners(keysContainer, mAccount, fingerprint, false, - XmppAxolotlSession.Trust.fromBoolean(fingerprints.get(fingerprint)), false, + FingerprintStatus.createActive(fingerprints.get(fingerprint)), false, new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { @@ -184,7 +184,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate List acceptedTargets = mConversation == null ? new ArrayList() : mConversation.getAcceptedCryptoTargets(); ownKeysToTrust.clear(); AxolotlService service = this.mAccount.getAxolotlService(); - Set ownKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED); + Set ownKeysSet = service.getKeysWithTrust(FingerprintStatus.createActiveUndecided()); for(final IdentityKey identityKey : ownKeysSet) { if(!ownKeysToTrust.containsKey(identityKey)) { ownKeysToTrust.put(identityKey.getFingerprint().replaceAll("\\s", ""), false); @@ -193,9 +193,9 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate synchronized (this.foreignKeysToTrust) { foreignKeysToTrust.clear(); for (Jid jid : contactJids) { - Set foreignKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, jid); + Set foreignKeysSet = service.getKeysWithTrust(FingerprintStatus.createActiveUndecided(), jid); if (hasNoOtherTrustedKeys(jid) && ownKeysSet.size() == 0) { - foreignKeysSet.addAll(service.getKeysWithTrust(XmppAxolotlSession.Trust.UNTRUSTED, jid)); + foreignKeysSet.addAll(service.getKeysWithTrust(FingerprintStatus.createActive(false), jid)); } Map foreignFingerprints = new HashMap<>(); for (final IdentityKey identityKey : foreignKeysSet) { @@ -280,7 +280,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate for(final String fingerprint :ownKeysToTrust.keySet()) { mAccount.getAxolotlService().setFingerprintTrust( fingerprint, - XmppAxolotlSession.Trust.fromBoolean(ownKeysToTrust.get(fingerprint))); + FingerprintStatus.createActive(ownKeysToTrust.get(fingerprint))); } List acceptedTargets = mConversation == null ? new ArrayList() : mConversation.getAcceptedCryptoTargets(); synchronized (this.foreignKeysToTrust) { @@ -293,7 +293,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate for (final String fingerprint : value.keySet()) { mAccount.getAxolotlService().setFingerprintTrust( fingerprint, - XmppAxolotlSession.Trust.fromBoolean(value.get(fingerprint))); + FingerprintStatus.createActive(value.get(fingerprint))); } } } diff --git a/src/main/java/de/pixart/messenger/ui/XmppActivity.java b/src/main/java/de/pixart/messenger/ui/XmppActivity.java index 2abfbc1e4..c4a92c44c 100644 --- a/src/main/java/de/pixart/messenger/ui/XmppActivity.java +++ b/src/main/java/de/pixart/messenger/ui/XmppActivity.java @@ -76,7 +76,7 @@ import java.util.concurrent.atomic.AtomicInteger; import de.pixart.messenger.Config; import de.pixart.messenger.R; -import de.pixart.messenger.crypto.axolotl.XmppAxolotlSession; +import de.pixart.messenger.crypto.axolotl.FingerprintStatus; import de.pixart.messenger.entities.Account; import de.pixart.messenger.entities.Contact; import de.pixart.messenger.entities.Conversation; @@ -126,7 +126,7 @@ public abstract class XmppActivity extends Activity { protected Toast mToast; - protected void hideToast() { + protected void hideToast() { if (mToast != null) { mToast.cancel(); } @@ -142,13 +142,13 @@ public abstract class XmppActivity extends Activity { mToast.show(); } - public void showProgress() { + public void showProgress() { - } + } - public void closeProgress() { + public void closeProgress() { - } + } protected Runnable onOpenPGPKeyPublished = new Runnable() { @Override @@ -380,18 +380,18 @@ public abstract class XmppActivity extends Activity { case R.id.action_invite_user: inviteUser(); break; - case R.id.action_create_issue: - createIssue(); - break; + case R.id.action_create_issue: + createIssue(); + break; case R.id.action_settings: startActivity(new Intent(this, SettingsActivity.class)); break; case R.id.action_check_updates: if (xmppConnectionService.hasInternetConnection()) { - startActivity(new Intent(this, UpdaterActivity.class)); - } else { - Toast.makeText(this, R.string.account_status_no_internet, Toast.LENGTH_LONG).show(); - } + startActivity(new Intent(this, UpdaterActivity.class)); + } else { + Toast.makeText(this, R.string.account_status_no_internet, Toast.LENGTH_LONG).show(); + } break; case R.id.action_accounts: final Intent intent = new Intent(getApplicationContext(), EditAccountActivity.class); @@ -443,15 +443,15 @@ public abstract class XmppActivity extends Activity { } } - protected boolean isAffectedByDataSaver() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); - return cm.isActiveNetworkMetered() - && cm.getRestrictBackgroundStatus() == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; - } else { - return false; - } - } + protected boolean isAffectedByDataSaver() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + return cm.isActiveNetworkMetered() + && cm.getRestrictBackgroundStatus() == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; + } else { + return false; + } + } protected boolean usingEnterKey() { return getPreferences().getBoolean("display_enter_key", false); @@ -581,7 +581,7 @@ public abstract class XmppActivity extends Activity { xmppConnectionService.sendPresence(account); if (conversation != null) { conversation.setNextEncryption(Message.ENCRYPTION_PGP); - xmppConnectionService.updateConversation(conversation); + xmppConnectionService.updateConversation(conversation); refreshUi(); } if (onSuccess != null) { @@ -591,14 +591,14 @@ public abstract class XmppActivity extends Activity { @Override public void error(int error, Account account) { - if (error == 0 && account != null) { - account.setPgpSignId(0); - account.unsetPgpSignature(); - xmppConnectionService.databaseBackend.updateAccount(account); - choosePgpSignId(account); - } else { - displayErrorDialog(error); - } + if (error == 0 && account != null) { + account.setPgpSignId(0); + account.unsetPgpSignature(); + xmppConnectionService.databaseBackend.updateAccount(account); + choosePgpSignId(account); + } else { + displayErrorDialog(error); + } } }); } @@ -776,25 +776,21 @@ public abstract class XmppActivity extends Activity { } protected boolean addFingerprintRow(LinearLayout keys, final Account account, final String fingerprint, boolean highlight, View.OnClickListener onKeyClickedListener) { - final XmppAxolotlSession.Trust trust = account.getAxolotlService() - .getFingerprintTrust(fingerprint); - if (trust == null) { + final FingerprintStatus status = account.getAxolotlService().getFingerprintTrust(fingerprint); + if (status == null) { return false; } - return addFingerprintRowWithListeners(keys, account, fingerprint, highlight, trust, true, + return addFingerprintRowWithListeners(keys, account, fingerprint, highlight, status, true, new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - account.getAxolotlService().setFingerprintTrust(fingerprint, - (isChecked) ? XmppAxolotlSession.Trust.TRUSTED : - XmppAxolotlSession.Trust.UNTRUSTED); + account.getAxolotlService().setFingerprintTrust(fingerprint,FingerprintStatus.createActive(isChecked)); } }, new View.OnClickListener() { @Override public void onClick(View v) { - account.getAxolotlService().setFingerprintTrust(fingerprint, - XmppAxolotlSession.Trust.UNTRUSTED); + account.getAxolotlService().setFingerprintTrust(fingerprint,FingerprintStatus.createActive(true)); v.setEnabled(true); } }, @@ -806,13 +802,13 @@ public abstract class XmppActivity extends Activity { protected boolean addFingerprintRowWithListeners(LinearLayout keys, final Account account, final String fingerprint, boolean highlight, - XmppAxolotlSession.Trust trust, + FingerprintStatus status, boolean showTag, CompoundButton.OnCheckedChangeListener onCheckedChangeListener, View.OnClickListener onClickListener, View.OnClickListener onKeyClickedListener) { - if (trust == XmppAxolotlSession.Trust.COMPROMISED) { + if (status.isCompromised()) { return false; } View view = getLayoutInflater().inflate(R.layout.contact_key, keys, false); @@ -822,8 +818,6 @@ public abstract class XmppActivity extends Activity { keyType.setOnClickListener(onKeyClickedListener); Switch trustToggle = (Switch) view.findViewById(R.id.tgl_trust); trustToggle.setVisibility(View.VISIBLE); - trustToggle.setOnCheckedChangeListener(onCheckedChangeListener); - trustToggle.setOnClickListener(onClickListener); final View.OnLongClickListener purge = new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { @@ -831,85 +825,59 @@ public abstract class XmppActivity extends Activity { return true; } }; - boolean active = true; view.setOnLongClickListener(purge); key.setOnLongClickListener(purge); keyType.setOnLongClickListener(purge); - boolean x509 = Config.X509_VERIFICATION - && (trust == XmppAxolotlSession.Trust.TRUSTED_X509 || trust == XmppAxolotlSession.Trust.INACTIVE_TRUSTED_X509); - switch (trust) { - case UNTRUSTED: - case TRUSTED: - case TRUSTED_X509: - trustToggle.setChecked(trust.trusted(), false); - trustToggle.setEnabled(!Config.X509_VERIFICATION || trust != XmppAxolotlSession.Trust.TRUSTED_X509); - if (Config.X509_VERIFICATION && trust == XmppAxolotlSession.Trust.TRUSTED_X509) { - trustToggle.setOnClickListener(null); - } - key.setTextColor(getPrimaryTextColor()); - keyType.setTextColor(getSecondaryTextColor()); - break; - case UNDECIDED: - trustToggle.setChecked(false, false); - trustToggle.setEnabled(false); - key.setTextColor(getPrimaryTextColor()); - keyType.setTextColor(getSecondaryTextColor()); - break; - case INACTIVE_UNTRUSTED: - case INACTIVE_UNDECIDED: - trustToggle.setOnClickListener(null); - trustToggle.setChecked(false, false); + boolean x509 = Config.X509_VERIFICATION && status.getTrust() == FingerprintStatus.Trust.VERIFIED_X509; + final View.OnClickListener toast; + if (status.isActive()) { + key.setTextColor(getPrimaryTextColor()); + keyType.setTextColor(getSecondaryTextColor()); + trustToggle.setOnCheckedChangeListener(onCheckedChangeListener); + if (status.getTrust() == FingerprintStatus.Trust.UNDECIDED) { + trustToggle.setOnClickListener(onClickListener); trustToggle.setEnabled(false); - key.setTextColor(getTertiaryTextColor()); - keyType.setTextColor(getTertiaryTextColor()); - active = false; - break; - case INACTIVE_TRUSTED: - case INACTIVE_TRUSTED_X509: + } else { trustToggle.setOnClickListener(null); - trustToggle.setChecked(true, false); - trustToggle.setEnabled(false); - key.setTextColor(getTertiaryTextColor()); - keyType.setTextColor(getTertiaryTextColor()); - active = false; - break; - } - - if (showTag) { - keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint)); - } else { - keyType.setVisibility(View.GONE); - } - if (highlight) { - keyType.setTextColor(getResources().getColor(R.color.accent)); - keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509_selected_message : R.string.omemo_fingerprint_selected_message)); - } else { - keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint)); - } - - key.setText(CryptoHelper.prettifyFingerprint(fingerprint.substring(2))); - - final View.OnClickListener toast; - if (!active) { + trustToggle.setChecked(status.isTrusted(), false); + trustToggle.setEnabled(true); + } toast = new View.OnClickListener() { @Override public void onClick(View v) { - replaceToast(getString(R.string.this_device_is_no_longer_in_use), false); + hideToast(); } }; - trustToggle.setOnClickListener(toast); } else { + key.setTextColor(getTertiaryTextColor()); + keyType.setTextColor(getTertiaryTextColor()); + trustToggle.setOnClickListener(null); + trustToggle.setEnabled(false); + trustToggle.setChecked(status.isTrusted(), false); toast = new View.OnClickListener() { @Override public void onClick(View v) { - hideToast(); + replaceToast(getString(R.string.this_device_is_no_longer_in_use), false); } }; + trustToggle.setOnClickListener(toast); } view.setOnClickListener(toast); key.setOnClickListener(toast); keyType.setOnClickListener(toast); + if (showTag) { + keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint)); + } else { + keyType.setVisibility(View.GONE); + } + if (highlight) { + keyType.setTextColor(getResources().getColor(R.color.accent)); + keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509_selected_message : R.string.omemo_fingerprint_selected_message)); + } else { + keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint)); + } + key.setText(CryptoHelper.prettifyFingerprint(fingerprint.substring(2))); keys.addView(view); return true; } @@ -1210,12 +1178,12 @@ public abstract class XmppActivity extends Activity { startActivity(Intent.createChooser(intent, getString(R.string.invite_contact))); } - private void createIssue() { - String IssueURL = Config.ISSUE_URL; - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(IssueURL)); - startActivity(intent); - } + private void createIssue() { + String IssueURL = Config.ISSUE_URL; + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(IssueURL)); + startActivity(intent); + } protected void shareUri() { String uri = getShareableUri(); diff --git a/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java index 3cfc4cfa7..1a93c7f68 100644 --- a/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java +++ b/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java @@ -52,7 +52,7 @@ import java.util.regex.Pattern; import de.pixart.messenger.Config; import de.pixart.messenger.R; -import de.pixart.messenger.crypto.axolotl.XmppAxolotlSession; +import de.pixart.messenger.crypto.axolotl.FingerprintStatus; import de.pixart.messenger.entities.Account; import de.pixart.messenger.entities.Conversation; import de.pixart.messenger.entities.DownloadableFile; @@ -87,14 +87,14 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie private DisplayMetrics metrics; - private AudioWife audioWife; + private AudioWife audioWife; private OnContactPictureClicked mOnContactPictureClickedListener; private OnContactPictureLongClicked mOnContactPictureLongClickedListener; private boolean mIndicateReceived = false; - private final ListSelectionManager listSelectionManager = new ListSelectionManager(); - private HashMap audioPlayer; + private final ListSelectionManager listSelectionManager = new ListSelectionManager(); + private HashMap audioPlayer; private boolean mUseWhiteBackground = false; public MessageAdapter(ConversationActivity activity, List messages) { @@ -111,7 +111,7 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie public void setOnContactPictureLongClicked( OnContactPictureLongClicked listener) { this.mOnContactPictureLongClickedListener = listener; - } + } @Override public int getViewTypeCount() { @@ -158,7 +158,7 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie } } boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI - && message.getMergedStatus() <= Message.STATUS_RECEIVED; + && message.getMergedStatus() <= Message.STATUS_RECEIVED; if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE || message.getTransferable() != null) { FileParams params = message.getFileParams(); if (params.size > (1 * 1024 * 1024)) { @@ -218,11 +218,11 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie } else { viewHolder.indicator.setVisibility(View.VISIBLE); if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) { - XmppAxolotlSession.Trust trust = message.getConversation() + FingerprintStatus status = message.getConversation() .getAccount().getAxolotlService().getFingerprintTrust( message.getFingerprint()); - if(trust == null || (!trust.trusted() && !trust.trustedInactive())) { + if(status == null || (!status.isTrustedAndActive())) { viewHolder.indicator.setColorFilter(activity.getWarningTextColor()); viewHolder.indicator.setAlpha(1.0f); } else { @@ -274,9 +274,9 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie private void displayInfoMessage(ViewHolder viewHolder, String text, boolean darkBackground) { viewHolder.aw_player.setVisibility(View.GONE); - if (viewHolder.download_button != null) { - viewHolder.download_button.setVisibility(View.GONE); - } + if (viewHolder.download_button != null) { + viewHolder.download_button.setVisibility(View.GONE); + } viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.VISIBLE); viewHolder.messageBody.setText(text); @@ -287,9 +287,9 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie private void displayDecryptionFailed(ViewHolder viewHolder, boolean darkBackground) { viewHolder.aw_player.setVisibility(View.GONE); - if (viewHolder.download_button != null) { - viewHolder.download_button.setVisibility(View.GONE); - } + if (viewHolder.download_button != null) { + viewHolder.download_button.setVisibility(View.GONE); + } viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.VISIBLE); viewHolder.messageBody.setText(getContext().getString( @@ -301,9 +301,9 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie private void displayHeartMessage(final ViewHolder viewHolder, final String body) { viewHolder.aw_player.setVisibility(View.GONE); - if (viewHolder.download_button != null) { - viewHolder.download_button.setVisibility(View.GONE); - } + if (viewHolder.download_button != null) { + viewHolder.download_button.setVisibility(View.GONE); + } viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.VISIBLE); viewHolder.messageBody.setIncludeFontPadding(false); @@ -313,61 +313,61 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie viewHolder.messageBody.setText(span); } - private void displayXmppMessage(final ViewHolder viewHolder, final String body) { - String contact = body.toLowerCase(); - contact = contact.split(":")[1]; - contact = contact.split("\\?")[0]; - String add_contact = activity.getString(R.string.add_to_contact_list) + " (" + contact + ")"; - viewHolder.aw_player.setVisibility(View.GONE); - viewHolder.download_button.setVisibility(View.VISIBLE); - viewHolder.download_button.setText(add_contact); - viewHolder.download_button.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(body)); - activity.startActivity(intent); - } - }); - viewHolder.image.setVisibility(View.GONE); - viewHolder.messageBody.setVisibility(View.GONE); - - } + private void displayXmppMessage(final ViewHolder viewHolder, final String body) { + String contact = body.toLowerCase(); + contact = contact.split(":")[1]; + contact = contact.split("\\?")[0]; + String add_contact = activity.getString(R.string.add_to_contact_list) + " (" + contact + ")"; + viewHolder.aw_player.setVisibility(View.GONE); + viewHolder.download_button.setVisibility(View.VISIBLE); + viewHolder.download_button.setText(add_contact); + viewHolder.download_button.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(body)); + activity.startActivity(intent); + } + }); + viewHolder.image.setVisibility(View.GONE); + viewHolder.messageBody.setVisibility(View.GONE); + + } private void displayTextMessage(final ViewHolder viewHolder, final Message message, boolean darkBackground) { - if (viewHolder.download_button != null) { - viewHolder.download_button.setVisibility(View.GONE); - } + if (viewHolder.download_button != null) { + viewHolder.download_button.setVisibility(View.GONE); + } viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.VISIBLE); viewHolder.messageBody.setIncludeFontPadding(true); if (message.getBody() != null) { final String nick = UIHelper.getMessageDisplayName(message); - SpannableStringBuilder body = message.getMergedBody(); - boolean hasMeCommand = message.hasMeCommand(); - if (hasMeCommand) { - body = body.replace(0, Message.ME_COMMAND.length(), nick + " "); + SpannableStringBuilder body = message.getMergedBody(); + boolean hasMeCommand = message.hasMeCommand(); + if (hasMeCommand) { + body = body.replace(0, Message.ME_COMMAND.length(), nick + " "); } if (body.length() > Config.MAX_DISPLAY_MESSAGE_CHARS) { - body = new SpannableStringBuilder(body, 0, Config.MAX_DISPLAY_MESSAGE_CHARS); - body.append("\u2026"); + body = new SpannableStringBuilder(body, 0, Config.MAX_DISPLAY_MESSAGE_CHARS); + body.append("\u2026"); } - Message.MergeSeparator[] mergeSeparators = body.getSpans(0, body.length(), Message.MergeSeparator.class); - for (Message.MergeSeparator mergeSeparator : mergeSeparators) { - int start = body.getSpanStart(mergeSeparator); - int end = body.getSpanEnd(mergeSeparator); - body.setSpan(new RelativeSizeSpan(0.3f), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + Message.MergeSeparator[] mergeSeparators = body.getSpans(0, body.length(), Message.MergeSeparator.class); + for (Message.MergeSeparator mergeSeparator : mergeSeparators) { + int start = body.getSpanStart(mergeSeparator); + int end = body.getSpanEnd(mergeSeparator); + body.setSpan(new RelativeSizeSpan(0.3f), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } if (message.getType() != Message.TYPE_PRIVATE) { if (hasMeCommand) { - body.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, nick.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + body.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, nick.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } else { String privateMarker; if (message.getStatus() <= Message.STATUS_RECEIVED) { privateMarker = activity - .getString(R.string.private_message); + .getString(R.string.private_message); } else { final String to; if (message.getCounterpart() != null) { @@ -377,25 +377,25 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie } privateMarker = activity.getString(R.string.private_message_to, to); } - body.insert(0, privateMarker); - int privateMarkerIndex = privateMarker.length(); - body.insert(privateMarkerIndex, " "); - body.setSpan(new ForegroundColorSpan(getMessageTextColor(darkBackground, false)), 0, privateMarkerIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - body.setSpan(new StyleSpan(Typeface.BOLD), 0, privateMarkerIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - if (hasMeCommand) { - body.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), privateMarkerIndex + 1, privateMarkerIndex + 1 + nick.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + body.insert(0, privateMarker); + int privateMarkerIndex = privateMarker.length(); + body.insert(privateMarkerIndex, " "); + body.setSpan(new ForegroundColorSpan(getMessageTextColor(darkBackground, false)), 0, privateMarkerIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + body.setSpan(new StyleSpan(Typeface.BOLD), 0, privateMarkerIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + if (hasMeCommand) { + body.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), privateMarkerIndex + 1, privateMarkerIndex + 1 + nick.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } - Linkify.addLinks(body, Linkify.WEB_URLS); - Linkify.addLinks(body, XMPP_PATTERN, "xmpp"); - Linkify.addLinks(body, GeoHelper.GEO_URI, "geo"); + Linkify.addLinks(body, Linkify.WEB_URLS); + Linkify.addLinks(body, XMPP_PATTERN, "xmpp"); + Linkify.addLinks(body, GeoHelper.GEO_URI, "geo"); viewHolder.messageBody.setAutoLinkMask(0); - viewHolder.messageBody.setText(body); - viewHolder.messageBody.setTextIsSelectable(true); - viewHolder.messageBody.setMovementMethod(ClickableMovementMethod.getInstance()); - listSelectionManager.onUpdate(viewHolder.messageBody, message); + viewHolder.messageBody.setText(body); + viewHolder.messageBody.setTextIsSelectable(true); + viewHolder.messageBody.setMovementMethod(ClickableMovementMethod.getInstance()); + listSelectionManager.onUpdate(viewHolder.messageBody, message); - } else { + } else { viewHolder.messageBody.setText(""); viewHolder.messageBody.setTextIsSelectable(false); } @@ -421,116 +421,116 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie }); } - private void displayAudioMessage(ViewHolder viewHolder, final Message message, int position) { - if (audioPlayer == null) audioPlayer = new HashMap<>(); - viewHolder.image.setVisibility(View.GONE); - viewHolder.messageBody.setVisibility(View.GONE); - if (viewHolder.download_button != null) { - viewHolder.download_button.setVisibility(View.GONE); - } - viewHolder.aw_player.setVisibility(View.VISIBLE); - Uri audioFile = Uri.fromFile(activity.xmppConnectionService.getFileBackend().getFile(message)); - - audioWife = audioPlayer.get(position); - if (audioWife == null) { - audioWife = new AudioWife(); - audioWife.init(getContext(), audioFile); - audioPlayer.put(position, audioWife); - RelativeLayout vg = new RelativeLayout(activity); - LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - audioWife.useDefaultUi(vg, layoutInflater); - viewHolder.aw_player.addView(audioWife.getPlayerUi()); - } else { - audioWife.cleanPlayerUi(); - viewHolder.aw_player.addView(audioWife.getPlayerUi()); - } - } + private void displayAudioMessage(ViewHolder viewHolder, final Message message, int position) { + if (audioPlayer == null) audioPlayer = new HashMap<>(); + viewHolder.image.setVisibility(View.GONE); + viewHolder.messageBody.setVisibility(View.GONE); + if (viewHolder.download_button != null) { + viewHolder.download_button.setVisibility(View.GONE); + } + viewHolder.aw_player.setVisibility(View.VISIBLE); + Uri audioFile = Uri.fromFile(activity.xmppConnectionService.getFileBackend().getFile(message)); + + audioWife = audioPlayer.get(position); + if (audioWife == null) { + audioWife = new AudioWife(); + audioWife.init(getContext(), audioFile); + audioPlayer.put(position, audioWife); + RelativeLayout vg = new RelativeLayout(activity); + LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + audioWife.useDefaultUi(vg, layoutInflater); + viewHolder.aw_player.addView(audioWife.getPlayerUi()); + } else { + audioWife.cleanPlayerUi(); + viewHolder.aw_player.addView(audioWife.getPlayerUi()); + } + } private void displayOpenableMessage(ViewHolder viewHolder,final Message message) { viewHolder.aw_player.setVisibility(View.GONE); viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.GONE); - viewHolder.download_button.setVisibility(View.VISIBLE); - String mimeType = message.getMimeType(); - String fullName = ""; - if (mimeType != null) { - if (message.getMimeType().contains("pdf")) { - viewHolder.download_button.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_file_pdf_grey600_48dp,0,0,0); - } else if (message.getMimeType().contains("vcard")) { - File file = new File(activity.xmppConnectionService.getFileBackend().getFile(message).toString()); - VCard vcard = null; - String name = null; - String version = null; - try { - vcard = Ezvcard.parse(file).first(); - } catch (IOException e) { - e.printStackTrace(); - } - if (vcard != null) { - version = vcard.getVersion().toString(); - Log.d(Config.LOGTAG, "VCard version: " + version); - name = vcard.getFormattedName().getValue(); - fullName = " (" + name + ")"; - } - viewHolder.download_button.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_account_card_details_grey600_48dp,0,0,0); - } else if (message.getMimeType().contains("calendar")) { - viewHolder.download_button.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_calendar_grey600_48dp,0,0,0); - } else { - viewHolder.download_button.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_file_grey600_48dp,0,0,0); - } - } - viewHolder.download_button.setText(activity.getString(R.string.open_x_file, UIHelper.getFileDescriptionString(activity, message) + fullName)); - viewHolder.download_button.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - openDownloadable(message); - } - }); - } - - private void displayLocationMessage(ViewHolder viewHolder, final Message message) { - viewHolder.aw_player.setVisibility(View.GONE); - viewHolder.messageBody.setVisibility(View.GONE); - String url = GeoHelper.MapPreviewUri(message); - viewHolder.image.setVisibility(View.VISIBLE); - viewHolder.image.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - showLocation(message); - } - }); - Glide - .with(activity) - .load(Uri.parse(url)) - .asBitmap() - .diskCacheStrategy(DiskCacheStrategy.ALL) - .fitCenter() - .placeholder(R.drawable.ic_map_marker_grey600_48dp) - .error(R.drawable.ic_map_marker_grey600_48dp) - .into(viewHolder.image); - viewHolder.image.setMaxWidth(500); - viewHolder.image.setAdjustViewBounds(true); - viewHolder.download_button.setVisibility(View.GONE); - viewHolder.download_button.setText(R.string.show_location); - viewHolder.download_button.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_map_marker_grey600_48dp, 0, 0, 0); - viewHolder.download_button.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - showLocation(message); - } - }); - - } + viewHolder.download_button.setVisibility(View.VISIBLE); + String mimeType = message.getMimeType(); + String fullName = ""; + if (mimeType != null) { + if (message.getMimeType().contains("pdf")) { + viewHolder.download_button.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_file_pdf_grey600_48dp,0,0,0); + } else if (message.getMimeType().contains("vcard")) { + File file = new File(activity.xmppConnectionService.getFileBackend().getFile(message).toString()); + VCard vcard = null; + String name = null; + String version = null; + try { + vcard = Ezvcard.parse(file).first(); + } catch (IOException e) { + e.printStackTrace(); + } + if (vcard != null) { + version = vcard.getVersion().toString(); + Log.d(Config.LOGTAG, "VCard version: " + version); + name = vcard.getFormattedName().getValue(); + fullName = " (" + name + ")"; + } + viewHolder.download_button.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_account_card_details_grey600_48dp,0,0,0); + } else if (message.getMimeType().contains("calendar")) { + viewHolder.download_button.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_calendar_grey600_48dp,0,0,0); + } else { + viewHolder.download_button.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_file_grey600_48dp,0,0,0); + } + } + viewHolder.download_button.setText(activity.getString(R.string.open_x_file, UIHelper.getFileDescriptionString(activity, message) + fullName)); + viewHolder.download_button.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + openDownloadable(message); + } + }); + } + + private void displayLocationMessage(ViewHolder viewHolder, final Message message) { + viewHolder.aw_player.setVisibility(View.GONE); + viewHolder.messageBody.setVisibility(View.GONE); + String url = GeoHelper.MapPreviewUri(message); + viewHolder.image.setVisibility(View.VISIBLE); + viewHolder.image.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + showLocation(message); + } + }); + Glide + .with(activity) + .load(Uri.parse(url)) + .asBitmap() + .diskCacheStrategy(DiskCacheStrategy.ALL) + .fitCenter() + .placeholder(R.drawable.ic_map_marker_grey600_48dp) + .error(R.drawable.ic_map_marker_grey600_48dp) + .into(viewHolder.image); + viewHolder.image.setMaxWidth(500); + viewHolder.image.setAdjustViewBounds(true); + viewHolder.download_button.setVisibility(View.GONE); + viewHolder.download_button.setText(R.string.show_location); + viewHolder.download_button.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_map_marker_grey600_48dp, 0, 0, 0); + viewHolder.download_button.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + showLocation(message); + } + }); + + } private void displayImageMessage(ViewHolder viewHolder, - final Message message) { + final Message message) { viewHolder.aw_player.setVisibility(View.GONE); - if (viewHolder.download_button != null) { - viewHolder.download_button.setVisibility(View.GONE); - } + if (viewHolder.download_button != null) { + viewHolder.download_button.setVisibility(View.GONE); + } viewHolder.messageBody.setVisibility(View.GONE); viewHolder.image.setVisibility(View.VISIBLE); FileParams params = message.getFileParams(); @@ -565,7 +565,7 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie private void loadMoreMessages(Conversation conversation) { conversation.setLastClearHistory(0); - activity.xmppConnectionService.updateConversation(conversation); + activity.xmppConnectionService.updateConversation(conversation); conversation.setHasMessagesLeftOnServer(true); conversation.setFirstMamReference(null); long timestamp = conversation.getLastMessageTransmitted(); @@ -584,79 +584,79 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie final Conversation conversation = message.getConversation(); final Account account = conversation.getAccount(); final int type = getItemViewType(position); - ViewHolder viewHolder; - View view; - viewHolder = new ViewHolder(); - switch (type) { - case SENT: - view = activity.getLayoutInflater().inflate( - R.layout.message_sent, parent, false); - viewHolder.message_box = (LinearLayout) view - .findViewById(R.id.message_box); - viewHolder.contact_picture = (ImageView) view - .findViewById(R.id.message_photo); - viewHolder.aw_player = (ViewGroup) view.findViewById(R.id.aw_player); + ViewHolder viewHolder; + View view; + viewHolder = new ViewHolder(); + switch (type) { + case SENT: + view = activity.getLayoutInflater().inflate( + R.layout.message_sent, parent, false); + viewHolder.message_box = (LinearLayout) view + .findViewById(R.id.message_box); + viewHolder.contact_picture = (ImageView) view + .findViewById(R.id.message_photo); + viewHolder.aw_player = (ViewGroup) view.findViewById(R.id.aw_player); viewHolder.download_button = (Button) view .findViewById(R.id.download_button); - viewHolder.indicator = (ImageView) view - .findViewById(R.id.security_indicator); - viewHolder.edit_indicator = (ImageView) view.findViewById(R.id.edit_indicator); - viewHolder.image = (ImageView) view - .findViewById(R.id.message_image); - viewHolder.messageBody = (CopyTextView) view - .findViewById(R.id.message_body); - viewHolder.time = (TextView) view - .findViewById(R.id.message_time); - viewHolder.indicatorReceived = (ImageView) view - .findViewById(R.id.indicator_received); - viewHolder.indicatorRead = (ImageView) view - .findViewById(R.id.indicator_read); - break; - case RECEIVED: - view = activity.getLayoutInflater().inflate( - R.layout.message_received, parent, false); - viewHolder.message_box = (LinearLayout) view - .findViewById(R.id.message_box); - viewHolder.contact_picture = (ImageView) view - .findViewById(R.id.message_photo); - viewHolder.aw_player = (ViewGroup) view.findViewById(R.id.aw_player); + viewHolder.indicator = (ImageView) view + .findViewById(R.id.security_indicator); + viewHolder.edit_indicator = (ImageView) view.findViewById(R.id.edit_indicator); + viewHolder.image = (ImageView) view + .findViewById(R.id.message_image); + viewHolder.messageBody = (CopyTextView) view + .findViewById(R.id.message_body); + viewHolder.time = (TextView) view + .findViewById(R.id.message_time); + viewHolder.indicatorReceived = (ImageView) view + .findViewById(R.id.indicator_received); + viewHolder.indicatorRead = (ImageView) view + .findViewById(R.id.indicator_read); + break; + case RECEIVED: + view = activity.getLayoutInflater().inflate( + R.layout.message_received, parent, false); + viewHolder.message_box = (LinearLayout) view + .findViewById(R.id.message_box); + viewHolder.contact_picture = (ImageView) view + .findViewById(R.id.message_photo); + viewHolder.aw_player = (ViewGroup) view.findViewById(R.id.aw_player); viewHolder.download_button = (Button) view .findViewById(R.id.download_button); - viewHolder.indicator = (ImageView) view - .findViewById(R.id.security_indicator); - viewHolder.edit_indicator = (ImageView) view.findViewById(R.id.edit_indicator); - viewHolder.image = (ImageView) view - .findViewById(R.id.message_image); - viewHolder.messageBody = (CopyTextView) view - .findViewById(R.id.message_body); - viewHolder.time = (TextView) view - .findViewById(R.id.message_time); - viewHolder.indicatorReceived = (ImageView) view - .findViewById(R.id.indicator_received); - viewHolder.encryption = (TextView) view.findViewById(R.id.message_encryption); - break; - case STATUS: - view = activity.getLayoutInflater().inflate(R.layout.message_status, parent, false); - viewHolder.contact_picture = (ImageView) view.findViewById(R.id.message_photo); - viewHolder.status_message = (TextView) view.findViewById(R.id.status_message); - viewHolder.load_more_messages = (Button) view.findViewById(R.id.load_more_messages); - break; - default: - view = new View(getContext()); - viewHolder = null; - break; - } - if (viewHolder.messageBody != null) { - listSelectionManager.onCreate(viewHolder.messageBody); - viewHolder.messageBody.setCopyHandler(this); - } - view.setTag(viewHolder); - if (viewHolder == null) { - return view; - } - - - boolean darkBackground = (type == SENT && (!isInValidSession || !mUseWhiteBackground)); + viewHolder.indicator = (ImageView) view + .findViewById(R.id.security_indicator); + viewHolder.edit_indicator = (ImageView) view.findViewById(R.id.edit_indicator); + viewHolder.image = (ImageView) view + .findViewById(R.id.message_image); + viewHolder.messageBody = (CopyTextView) view + .findViewById(R.id.message_body); + viewHolder.time = (TextView) view + .findViewById(R.id.message_time); + viewHolder.indicatorReceived = (ImageView) view + .findViewById(R.id.indicator_received); + viewHolder.encryption = (TextView) view.findViewById(R.id.message_encryption); + break; + case STATUS: + view = activity.getLayoutInflater().inflate(R.layout.message_status, parent, false); + viewHolder.contact_picture = (ImageView) view.findViewById(R.id.message_photo); + viewHolder.status_message = (TextView) view.findViewById(R.id.status_message); + viewHolder.load_more_messages = (Button) view.findViewById(R.id.load_more_messages); + break; + default: + view = new View(getContext()); + viewHolder = null; + break; + } + if (viewHolder.messageBody != null) { + listSelectionManager.onCreate(viewHolder.messageBody); + viewHolder.messageBody.setCopyHandler(this); + } + view.setTag(viewHolder); + if (viewHolder == null) { + return view; + } + + + boolean darkBackground = (type == SENT && (!isInValidSession || !mUseWhiteBackground)); if (type == STATUS) { if ("LOAD_MORE".equals(message.getBody())) { @@ -687,31 +687,31 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie } viewHolder.contact_picture - .setOnClickListener(new OnClickListener() { + .setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (MessageAdapter.this.mOnContactPictureClickedListener != null) { - MessageAdapter.this.mOnContactPictureClickedListener - .onContactPictureClicked(message); - } + @Override + public void onClick(View v) { + if (MessageAdapter.this.mOnContactPictureClickedListener != null) { + MessageAdapter.this.mOnContactPictureClickedListener + .onContactPictureClicked(message); + } - } - }); + } + }); viewHolder.contact_picture - .setOnLongClickListener(new OnLongClickListener() { - - @Override - public boolean onLongClick(View v) { - if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) { - MessageAdapter.this.mOnContactPictureLongClickedListener - .onContactPictureLongClicked(message); - return true; - } else { - return false; + .setOnLongClickListener(new OnLongClickListener() { + + @Override + public boolean onLongClick(View v) { + if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) { + MessageAdapter.this.mOnContactPictureLongClickedListener + .onContactPictureLongClicked(message); + return true; + } else { + return false; + } } - } - }); + }); final Transferable transferable = message.getTransferable(); String mimeType = message.getMimeType(); @@ -733,7 +733,7 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie if (message.getMimeType().startsWith("audio/")) { displayAudioMessage(viewHolder, message, position); } else displayOpenableMessage(viewHolder, message); - } else displayOpenableMessage(viewHolder, message); + } else displayOpenableMessage(viewHolder, message); } } else if (message.getEncryption() == Message.ENCRYPTION_PGP) { if (account.isPgpDecryptionServiceConnected()) { @@ -746,24 +746,24 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie displayInfoMessage(viewHolder,activity.getString(R.string.install_openkeychain),darkBackground); if (viewHolder != null) { viewHolder.message_box - .setOnClickListener(new OnClickListener() { + .setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - activity.showInstallPgpDialog(); - } - }); + @Override + public void onClick(View v) { + activity.showInstallPgpDialog(); + } + }); } } } else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { displayDecryptionFailed(viewHolder,darkBackground); } else { if (GeoHelper.isGeoUri(message.getBody())) { - displayLocationMessage(viewHolder,message); + displayLocationMessage(viewHolder,message); } else if (message.bodyIsHeart()) { displayHeartMessage(viewHolder, message.getBody().trim()); - } else if (message.bodyIsXmpp()) { - displayXmppMessage(viewHolder, message.getBody().trim()); + } else if (message.bodyIsXmpp()) { + displayXmppMessage(viewHolder, message.getBody().trim()); } else if (message.treatAsDownloadable() == Message.Decision.MUST || message.treatAsDownloadable() == Message.Decision.SHOULD) { try { @@ -808,73 +808,73 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie return view; } - @Override - public void notifyDataSetChanged() { - listSelectionManager.onBeforeNotifyDataSetChanged(); - super.notifyDataSetChanged(); - listSelectionManager.onAfterNotifyDataSetChanged(); - } - - @Override - public String transformTextForCopy(CharSequence text, int start, int end) { - return text.toString().substring(start, end); - } - - public void openDownloadable(Message message) { - DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); - if (!file.exists()) { - Toast.makeText(activity, R.string.file_deleted, Toast.LENGTH_SHORT).show(); - return; - } - String mime = file.getMimeType(); - if (mime.startsWith("image/")) { - Intent intent = new Intent(getContext(), ShowFullscreenMessageActivity.class); - intent.putExtra("image", Uri.fromFile(file)); - try { - activity.startActivity(intent); - return; - } catch (ActivityNotFoundException e) { - //ignored - } - } else if (mime.startsWith("video/")) { - Intent intent = new Intent(getContext(), ShowFullscreenMessageActivity.class); - intent.putExtra("video", Uri.fromFile(file)); - try { - activity.startActivity(intent); - return; - } catch (ActivityNotFoundException e) { - //ignored - } - } - Intent openIntent = new Intent(Intent.ACTION_VIEW); - if (mime == null) { - mime = "*/*"; - } - Uri uri; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - try { - uri = FileProvider.getUriForFile(activity, FileBackend.CONVERSATIONS_FILE_PROVIDER, file); - } catch (IllegalArgumentException e) { - Toast.makeText(activity,activity.getString(R.string.no_permission_to_access_x,file.getAbsolutePath()), Toast.LENGTH_SHORT).show(); - return; - } - openIntent.setDataAndType(uri, mime); - openIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - } else { - uri = Uri.fromFile(file); - } - openIntent.setDataAndType(uri, mime); - PackageManager manager = activity.getPackageManager(); - List info = manager.queryIntentActivities(openIntent, 0); - if (info.size() == 0) { - openIntent.setDataAndType(Uri.fromFile(file),"*/*"); - } - try { - getContext().startActivity(openIntent); - } catch (ActivityNotFoundException e) { - Toast.makeText(activity,R.string.no_application_found_to_open_file,Toast.LENGTH_SHORT).show(); - } - } + @Override + public void notifyDataSetChanged() { + listSelectionManager.onBeforeNotifyDataSetChanged(); + super.notifyDataSetChanged(); + listSelectionManager.onAfterNotifyDataSetChanged(); + } + + @Override + public String transformTextForCopy(CharSequence text, int start, int end) { + return text.toString().substring(start, end); + } + + public void openDownloadable(Message message) { + DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); + if (!file.exists()) { + Toast.makeText(activity, R.string.file_deleted, Toast.LENGTH_SHORT).show(); + return; + } + String mime = file.getMimeType(); + if (mime.startsWith("image/")) { + Intent intent = new Intent(getContext(), ShowFullscreenMessageActivity.class); + intent.putExtra("image", Uri.fromFile(file)); + try { + activity.startActivity(intent); + return; + } catch (ActivityNotFoundException e) { + //ignored + } + } else if (mime.startsWith("video/")) { + Intent intent = new Intent(getContext(), ShowFullscreenMessageActivity.class); + intent.putExtra("video", Uri.fromFile(file)); + try { + activity.startActivity(intent); + return; + } catch (ActivityNotFoundException e) { + //ignored + } + } + Intent openIntent = new Intent(Intent.ACTION_VIEW); + if (mime == null) { + mime = "*/*"; + } + Uri uri; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + try { + uri = FileProvider.getUriForFile(activity, FileBackend.CONVERSATIONS_FILE_PROVIDER, file); + } catch (IllegalArgumentException e) { + Toast.makeText(activity,activity.getString(R.string.no_permission_to_access_x,file.getAbsolutePath()), Toast.LENGTH_SHORT).show(); + return; + } + openIntent.setDataAndType(uri, mime); + openIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } else { + uri = Uri.fromFile(file); + } + openIntent.setDataAndType(uri, mime); + PackageManager manager = activity.getPackageManager(); + List info = manager.queryIntentActivities(openIntent, 0); + if (info.size() == 0) { + openIntent.setDataAndType(Uri.fromFile(file),"*/*"); + } + try { + getContext().startActivity(openIntent); + } catch (ActivityNotFoundException e) { + Toast.makeText(activity,R.string.no_application_found_to_open_file,Toast.LENGTH_SHORT).show(); + } + } public void showLocation(Message message) { for(Intent intent : GeoHelper.createGeoIntentsFromMessage(message)) { @@ -891,14 +891,14 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie this.mUseWhiteBackground = activity.useWhiteBackground(); } - public TextView getMessageBody(View view) { - final Object tag = view.getTag(); - if (tag instanceof ViewHolder) { - final ViewHolder viewHolder = (ViewHolder) tag; - return viewHolder.messageBody; - } - return null; - } + public TextView getMessageBody(View view) { + final Object tag = view.getTag(); + if (tag instanceof ViewHolder) { + final ViewHolder viewHolder = (ViewHolder) tag; + return viewHolder.messageBody; + } + return null; + } public interface OnContactPictureClicked { void onContactPictureClicked(Message message); -- cgit v1.2.3