aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md4
-rw-r--r--art/message_bubble_received.svg2
-rw-r--r--build.gradle7
-rw-r--r--src/main/java/eu/siacs/conversations/Config.java6
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/OtrService.java2
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java170
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/CryptoFailedException.java7
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java28
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Conversation.java7
-rw-r--r--src/main/java/eu/siacs/conversations/entities/MucOptions.java9
-rw-r--r--src/main/java/eu/siacs/conversations/generator/MessageGenerator.java23
-rw-r--r--src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java1
-rw-r--r--src/main/java/eu/siacs/conversations/parser/MessageParser.java36
-rw-r--r--src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java10
-rw-r--r--src/main/java/eu/siacs/conversations/persistance/FileBackend.java18
-rw-r--r--src/main/java/eu/siacs/conversations/services/NotificationService.java12
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java42
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java22
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java8
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationActivity.java22
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationFragment.java19
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java31
-rw-r--r--src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java6
-rw-r--r--src/main/java/eu/siacs/conversations/ui/XmppActivity.java38
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java2
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/OnKeyStatusUpdated.java5
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java5
-rw-r--r--src/main/res/drawable-hdpi/message_bubble_received.9.pngbin760 -> 765 bytes
-rw-r--r--src/main/res/drawable-hdpi/message_bubble_sent.9.pngbin687 -> 687 bytes
-rw-r--r--src/main/res/drawable-mdpi/message_bubble_received.9.pngbin588 -> 594 bytes
-rw-r--r--src/main/res/drawable-mdpi/message_bubble_sent.9.pngbin558 -> 558 bytes
-rw-r--r--src/main/res/drawable-xhdpi/message_bubble_received.9.pngbin917 -> 929 bytes
-rw-r--r--src/main/res/drawable-xhdpi/message_bubble_sent.9.pngbin857 -> 857 bytes
-rw-r--r--src/main/res/drawable-xxhdpi/message_bubble_received.9.pngbin1309 -> 1334 bytes
-rw-r--r--src/main/res/drawable-xxhdpi/message_bubble_sent.9.pngbin1190 -> 1190 bytes
-rw-r--r--src/main/res/drawable-xxxhdpi/message_bubble_received.9.pngbin1695 -> 1714 bytes
-rw-r--r--src/main/res/drawable-xxxhdpi/message_bubble_sent.9.pngbin1499 -> 1499 bytes
-rw-r--r--src/main/res/layout/account_row.xml19
-rw-r--r--src/main/res/layout/activity_edit_account.xml260
-rw-r--r--src/main/res/layout/activity_muc_details.xml307
-rw-r--r--src/main/res/layout/contact.xml15
-rw-r--r--src/main/res/layout/conversation_list_row.xml12
-rw-r--r--src/main/res/layout/message_received.xml20
-rw-r--r--src/main/res/layout/message_sent.xml20
-rw-r--r--src/main/res/layout/message_status.xml20
-rw-r--r--src/main/res/menu/muc_details_context.xml4
-rw-r--r--src/main/res/values/colors.xml1
-rw-r--r--src/main/res/values/strings.xml6
-rw-r--r--src/main/res/xml/preferences.xml2
49 files changed, 728 insertions, 500 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2fe238334..4fbbaf833 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
###Changelog
+####Version 1.5.1
+* fixed rare crashes
+* improved otr support
+
####Version 1.5.0
* upload files to HTTP host and share them in MUCs. requires new [HttpUploadComponent](https://github.com/siacs/HttpUploadComponent) on server side
diff --git a/art/message_bubble_received.svg b/art/message_bubble_received.svg
index 4f4158616..815892ed3 100644
--- a/art/message_bubble_received.svg
+++ b/art/message_bubble_received.svg
@@ -140,7 +140,7 @@
transform="translate(0,-2)">
<g
id="g3759"
- style="fill:#259b24;fill-opacity:1;stroke:none;fill-rule:nonzero;filter:url(#filter3811)">
+ style="fill:#4b9b4a;fill-opacity:1;stroke:none;fill-rule:nonzero;filter:url(#filter3811)">
<path
style="display:none"
d="m 8,6 c 2,2 4,6 4,10 L 16,6 z"
diff --git a/build.gradle b/build.gradle
index e7574ef2e..e6f6f4b07 100644
--- a/build.gradle
+++ b/build.gradle
@@ -38,6 +38,7 @@ dependencies {
compile 'me.leolin:ShortcutBadger:1.1.1@aar'
compile 'com.kyleduo.switchbutton:library:1.2.8'
compile 'org.whispersystems:axolotl-android:1.3.4'
+ compile 'com.makeramen:roundedimageview:2.1.1'
}
android {
@@ -47,9 +48,9 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 21
- versionCode 78
- versionName "1.5.0"
-}
+ versionCode 80
+ versionName "1.5.2"
+ }
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java
index 19db7fe58..f752b5b15 100644
--- a/src/main/java/eu/siacs/conversations/Config.java
+++ b/src/main/java/eu/siacs/conversations/Config.java
@@ -19,6 +19,10 @@ public final class Config {
public static final int AVATAR_SIZE = 384;
public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.WEBP;
+ public static final int IMAGE_SIZE = 1920;
+ public static final Bitmap.CompressFormat IMAGE_FORMAT = Bitmap.CompressFormat.WEBP;
+ public static final int IMAGE_QUALITY = 75;
+
public static final int MESSAGE_MERGE_WINDOW = 20;
public static final int PAGE_SIZE = 50;
@@ -33,6 +37,8 @@ public final class Config {
public static final boolean ENCRYPT_ON_HTTP_UPLOADED = false;
+ public static final boolean SHOW_REGENERATE_AXOLOTL_KEYS_BUTTON = false;
+
public static final long MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000;
public static final long MAM_MAX_CATCHUP = MILLISECONDS_IN_DAY / 2;
public static final int MAM_MAX_MESSAGES = 500;
diff --git a/src/main/java/eu/siacs/conversations/crypto/OtrService.java b/src/main/java/eu/siacs/conversations/crypto/OtrService.java
index f81c9865b..1b296cc4e 100644
--- a/src/main/java/eu/siacs/conversations/crypto/OtrService.java
+++ b/src/main/java/eu/siacs/conversations/crypto/OtrService.java
@@ -182,7 +182,7 @@ public class OtrService extends OtrCryptoEngineImpl implements OtrEngineHost {
packet.addChild("private", "urn:xmpp:carbons:2");
packet.addChild("no-copy", "urn:xmpp:hints");
packet.addChild("no-permanent-store", "urn:xmpp:hints");
-
+ packet.addChild("no-permanent-storage", "urn:xmpp:hints");
try {
Jid jid = Jid.fromSessionID(session);
Conversation conversation = mXmppConnectionService.find(account,jid);
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
index 72d1d14a0..c6f74538a 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
@@ -4,6 +4,7 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.whispersystems.libaxolotl.AxolotlAddress;
import org.whispersystems.libaxolotl.DuplicateMessageException;
import org.whispersystems.libaxolotl.IdentityKey;
@@ -30,6 +31,7 @@ import org.whispersystems.libaxolotl.state.SessionRecord;
import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
import org.whispersystems.libaxolotl.util.KeyHelper;
+import java.security.Security;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
@@ -51,7 +53,6 @@ import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
-import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
public class AxolotlService {
@@ -68,7 +69,7 @@ public class AxolotlService {
private final SQLiteAxolotlStore axolotlStore;
private final SessionMap sessions;
private final Map<Jid, Set<Integer>> deviceIds;
- private final Map<String, MessagePacket> messageCache;
+ private final Map<String, XmppAxolotlMessage> messageCache;
private final FetchStatusMap fetchStatusMap;
private final SerialSingleThreadExecutor executor;
@@ -98,26 +99,53 @@ public class AxolotlService {
private int currentPreKeyId = 0;
public enum Trust {
- UNDECIDED, // 0
- TRUSTED,
- UNTRUSTED,
- COMPROMISED;
+ UNDECIDED(0),
+ TRUSTED(1),
+ UNTRUSTED(2),
+ COMPROMISED(3),
+ INACTIVE(4);
+
+ private static final Map<Integer, Trust> 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";
+ return "Trust undecided "+getCode();
case TRUSTED:
- return "Trusted";
+ return "Trusted "+getCode();
+ case COMPROMISED:
+ return "Compromised "+getCode();
+ case INACTIVE:
+ return "Inactive "+getCode();
case UNTRUSTED:
default:
- return "Untrusted";
+ return "Untrusted "+getCode();
}
}
public static Trust fromBoolean(Boolean trusted) {
return trusted?TRUSTED:UNTRUSTED;
}
+
+ public static Trust fromCode(int code) {
+ return trustsByValue.get(code);
+ }
};
private static IdentityKeyPair generateIdentityKeyPair() {
@@ -515,15 +543,22 @@ public class AxolotlService {
return fingerprint;
}
- private SQLiteAxolotlStore.Trust getTrust() {
+ protected void setTrust(SQLiteAxolotlStore.Trust trust) {
+ sqLiteAxolotlStore.setFingerprintTrust(fingerprint, trust);
+ }
+
+ protected SQLiteAxolotlStore.Trust getTrust() {
return sqLiteAxolotlStore.getFingerprintTrust(fingerprint);
}
@Nullable
public byte[] processReceiving(XmppAxolotlMessage.XmppAxolotlMessageHeader incomingHeader) {
byte[] plaintext = null;
- switch (getTrust()) {
+ SQLiteAxolotlStore.Trust trust = getTrust();
+ switch (trust) {
+ case INACTIVE:
case UNDECIDED:
+ case UNTRUSTED:
case TRUSTED:
try {
try {
@@ -550,10 +585,13 @@ public class AxolotlService {
Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Error decrypting axolotl header, "+e.getClass().getName()+": " + e.getMessage());
}
+ if (plaintext != null && trust == SQLiteAxolotlStore.Trust.INACTIVE) {
+ setTrust(SQLiteAxolotlStore.Trust.TRUSTED);
+ }
+
break;
case COMPROMISED:
- case UNTRUSTED:
default:
// ignore
break;
@@ -639,21 +677,28 @@ public class AxolotlService {
this.fillMap(store);
}
+ private void putDevicesForJid(String bareJid, List<Integer> deviceIds, SQLiteAxolotlStore store) {
+ for (Integer deviceId : deviceIds) {
+ AxolotlAddress axolotlAddress = new AxolotlAddress(bareJid, deviceId);
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Building session for remote address: "+axolotlAddress.toString());
+ String fingerprint = store.loadSession(axolotlAddress).getSessionState().getRemoteIdentityKey().getFingerprint().replaceAll("\\s", "");
+ this.put(axolotlAddress, new XmppAxolotlSession(account, store, axolotlAddress, fingerprint));
+ }
+ }
+
private void fillMap(SQLiteAxolotlStore store) {
+ List<Integer> deviceIds = store.getSubDeviceSessions(account.getJid().toBareJid().toString());
+ putDevicesForJid(account.getJid().toBareJid().toString(), deviceIds, store);
for (Contact contact : account.getRoster().getContacts()) {
Jid bareJid = contact.getJid().toBareJid();
if (bareJid == null) {
continue; // FIXME: handle this?
}
String address = bareJid.toString();
- List<Integer> deviceIDs = store.getSubDeviceSessions(address);
- for (Integer deviceId : deviceIDs) {
- AxolotlAddress axolotlAddress = new AxolotlAddress(address, deviceId);
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Building session for remote address: "+axolotlAddress.toString());
- String fingerprint = store.loadSession(axolotlAddress).getSessionState().getRemoteIdentityKey().getFingerprint().replaceAll("\\s", "");
- this.put(axolotlAddress, new XmppAxolotlSession(account, store, axolotlAddress, fingerprint));
- }
+ deviceIds = store.getSubDeviceSessions(address);
+ putDevicesForJid(address, deviceIds, store);
}
+
}
@Override
@@ -678,6 +723,9 @@ public class AxolotlService {
}
public AxolotlService(Account account, XmppConnectionService connectionService) {
+ if (Security.getProvider("BC") == null) {
+ Security.addProvider(new BouncyCastleProvider());
+ }
this.mXmppConnectionService = connectionService;
this.account = account;
this.axolotlStore = new SQLiteAxolotlStore(this.account, this.mXmppConnectionService);
@@ -741,15 +789,40 @@ public class AxolotlService {
return this.deviceIds.get(account.getJid().toBareJid());
}
- public void registerDevices(final Jid jid, @NonNull final Set<Integer> deviceIds) {
- if(deviceIds.contains(getOwnDeviceId())) {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Skipping own Device ID:"+ jid + ":"+getOwnDeviceId());
- deviceIds.remove(getOwnDeviceId());
+ private void setTrustOnSessions(final Jid jid, @NonNull final Set<Integer> deviceIds,
+ final SQLiteAxolotlStore.Trust from,
+ final SQLiteAxolotlStore.Trust to) {
+ for(Integer deviceId:deviceIds) {
+ AxolotlAddress address = new AxolotlAddress(jid.toBareJid().toString(), deviceId);
+ XmppAxolotlSession session = sessions.get(address);
+ if (session != null && session.getFingerprint() != null
+ && session.getTrust() == from) {
+ session.setTrust(to);
+ }
}
- for(Integer i:deviceIds) {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Adding Device ID:"+ jid + ":"+i);
+ }
+
+ public void registerDevices(final Jid jid, @NonNull final Set<Integer> deviceIds) {
+ if(jid.toBareJid().equals(account.getJid().toBareJid())) {
+ if (deviceIds.contains(getOwnDeviceId())) {
+ deviceIds.remove(getOwnDeviceId());
+ }
+ for(Integer deviceId : deviceIds) {
+ AxolotlAddress ownDeviceAddress = new AxolotlAddress(jid.toBareJid().toString(),deviceId);
+ if(sessions.get(ownDeviceAddress) == null) {
+ buildSessionFromPEP(null, ownDeviceAddress, false);
+ }
+ }
}
+ Set<Integer> expiredDevices = new HashSet<>(axolotlStore.getSubDeviceSessions(jid.toBareJid().toString()));
+ expiredDevices.removeAll(deviceIds);
+ setTrustOnSessions(jid, expiredDevices, SQLiteAxolotlStore.Trust.TRUSTED,
+ SQLiteAxolotlStore.Trust.INACTIVE);
+ Set<Integer> newDevices = new HashSet<>(deviceIds);
+ setTrustOnSessions(jid, newDevices, SQLiteAxolotlStore.Trust.INACTIVE,
+ SQLiteAxolotlStore.Trust.TRUSTED);
this.deviceIds.put(jid, deviceIds);
+ mXmppConnectionService.keyStatusUpdated();
publishOwnDeviceIdIfNeeded();
}
@@ -911,11 +984,10 @@ public class AxolotlService {
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Retrieving bundle: " + bundlesPacket);
mXmppConnectionService.sendIqPacket(account, bundlesPacket, new OnIqPacketReceived() {
private void finish() {
- AxolotlAddress ownAddress = new AxolotlAddress(conversation.getAccount().getJid().toBareJid().toString(),0);
- AxolotlAddress foreignAddress = new AxolotlAddress(conversation.getJid().toBareJid().toString(),0);
+ AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(),0);
if (!fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)
- && !fetchStatusMap.getAll(foreignAddress).containsValue(FetchStatus.PENDING)) {
- if (flushWaitingQueueAfterFetch) {
+ && !fetchStatusMap.getAll(address).containsValue(FetchStatus.PENDING)) {
+ if (flushWaitingQueueAfterFetch && conversation != null) {
conversation.findUnsentMessagesWithEncryption(Message.ENCRYPTION_AXOLOTL,
new Conversation.OnMessageFound() {
@Override
@@ -924,7 +996,7 @@ public class AxolotlService {
}
});
}
- mXmppConnectionService.newKeysAvailable();
+ mXmppConnectionService.keyStatusUpdated();
}
}
@@ -1050,11 +1122,17 @@ public class AxolotlService {
final String content;
if (message.hasFileOnRemoteHost()) {
content = message.getFileParams().url.toString();
- } else {
- content = message.getBody();
- }
- final XmppAxolotlMessage axolotlMessage = new XmppAxolotlMessage(message.getContact().getJid().toBareJid(),
- getOwnDeviceId(), content);
+ } else {
+ content = message.getBody();
+ }
+ final XmppAxolotlMessage axolotlMessage;
+ try {
+ axolotlMessage = new XmppAxolotlMessage(message.getContact().getJid().toBareJid(),
+ getOwnDeviceId(), content);
+ } catch (CryptoFailedException e) {
+ Log.w(Config.LOGTAG, getLogprefix(account) + "Failed to encrypt message: " + e.getMessage());
+ return null;
+ }
if(findSessionsforContact(message.getContact()).isEmpty()) {
return null;
@@ -1085,14 +1163,13 @@ public class AxolotlService {
executor.execute(new Runnable() {
@Override
public void run() {
- MessagePacket packet = mXmppConnectionService.getMessageGenerator()
- .generateAxolotlChat(message);
- if (packet == null) {
+ XmppAxolotlMessage axolotlMessage = encrypt(message);
+ if (axolotlMessage == null) {
mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED);
//mXmppConnectionService.updateConversationUi();
} else {
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Generated message, caching: " + message.getUuid());
- messageCache.put(message.getUuid(), packet);
+ messageCache.put(message.getUuid(), axolotlMessage);
mXmppConnectionService.resendMessage(message,delay);
}
}
@@ -1108,15 +1185,15 @@ public class AxolotlService {
}
}
- public MessagePacket fetchPacketFromCache(Message message) {
- MessagePacket packet = messageCache.get(message.getUuid());
- if (packet != null) {
+ public XmppAxolotlMessage fetchAxolotlMessageFromCache(Message message) {
+ XmppAxolotlMessage axolotlMessage = messageCache.get(message.getUuid());
+ if (axolotlMessage != null) {
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Cache hit: " + message.getUuid());
messageCache.remove(message.getUuid());
} else {
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Cache miss: " + message.getUuid());
}
- return packet;
+ return axolotlMessage;
}
public XmppAxolotlMessage.XmppAxolotlPlaintextMessage processReceiving(XmppAxolotlMessage message) {
@@ -1144,7 +1221,12 @@ public class AxolotlService {
byte[] payloadKey = session.processReceiving(header);
if (payloadKey != null) {
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Got payload key from axolotl header. Decrypting message...");
- plaintextMessage = message.decrypt(session, payloadKey, session.getFingerprint());
+ try{
+ plaintextMessage = message.decrypt(session, payloadKey, session.getFingerprint());
+ } catch (CryptoFailedException e) {
+ Log.w(Config.LOGTAG, getLogprefix(account) + "Failed to decrypt message: " + e.getMessage());
+ break;
+ }
}
Integer preKeyId = session.getPreKeyId();
if (preKeyId != null) {
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/CryptoFailedException.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/CryptoFailedException.java
new file mode 100644
index 000000000..5796ef30e
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/CryptoFailedException.java
@@ -0,0 +1,7 @@
+package eu.siacs.conversations.crypto.axolotl;
+
+public class CryptoFailedException extends Exception {
+ public CryptoFailedException(Exception e){
+ super(e);
+ }
+}
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java
index ec068ec7e..24afeaeae 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java
@@ -6,6 +6,8 @@ import android.util.Base64;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
import java.util.HashSet;
import java.util.Set;
@@ -107,26 +109,30 @@ public class XmppAxolotlMessage {
}
}
- public XmppAxolotlMessage(Jid from, int sourceDeviceId, String plaintext) {
+ public XmppAxolotlMessage(Jid from, int sourceDeviceId, String plaintext) throws CryptoFailedException{
this.from = from;
this.sourceDeviceId = sourceDeviceId;
this.headers = new HashSet<>();
this.encrypt(plaintext);
}
- private void encrypt(String plaintext) {
+ private void encrypt(String plaintext) throws CryptoFailedException {
try {
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(128);
SecretKey secretKey = generator.generateKey();
- Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
- cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+ SecureRandom random = new SecureRandom();
+ this.iv = new byte[16];
+ random.nextBytes(iv);
+ IvParameterSpec ivSpec = new IvParameterSpec(iv);
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
this.innerKey = secretKey.getEncoded();
- this.iv = cipher.getIV();
this.ciphertext = cipher.doFinal(plaintext.getBytes());
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
- | IllegalBlockSizeException | BadPaddingException e) {
-
+ | IllegalBlockSizeException | BadPaddingException | NoSuchProviderException
+ | InvalidAlgorithmParameterException e) {
+ throw new CryptoFailedException(e);
}
}
@@ -174,11 +180,11 @@ public class XmppAxolotlMessage {
}
- public XmppAxolotlPlaintextMessage decrypt(AxolotlService.XmppAxolotlSession session, byte[] key, String fingerprint) {
+ public XmppAxolotlPlaintextMessage decrypt(AxolotlService.XmppAxolotlSession session, byte[] key, String fingerprint) throws CryptoFailedException {
XmppAxolotlPlaintextMessage plaintextMessage = null;
try {
- Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
@@ -189,8 +195,8 @@ public class XmppAxolotlMessage {
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
| InvalidAlgorithmParameterException | IllegalBlockSizeException
- | BadPaddingException e) {
- throw new AssertionError(e);
+ | BadPaddingException | NoSuchProviderException e) {
+ throw new CryptoFailedException(e);
}
return plaintextMessage;
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java
index 2efd8a290..6d99e3588 100644
--- a/src/main/java/eu/siacs/conversations/entities/Conversation.java
+++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java
@@ -519,6 +519,13 @@ public class Conversation extends AbstractEntity implements Blockable {
return getContact().getOtrFingerprints().contains(getOtrFingerprint());
}
+ /**
+ * short for is Private and Non-anonymous
+ */
+ public boolean isPnNA() {
+ return mode == MODE_SINGLE || (getMucOptions().membersOnly() && getMucOptions().nonanonymous());
+ }
+
public synchronized MucOptions getMucOptions() {
if (this.mucOptions == null) {
this.mucOptions = new MucOptions(this);
diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
index 6ff6b8c9a..52a862efa 100644
--- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
@@ -264,6 +264,15 @@ public class MucOptions {
users.add(user);
}
+ public boolean isUserInRoom(String name) {
+ for (int i = 0; i < users.size(); ++i) {
+ if (users.get(i).getName().equals(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public void processPacket(PresencePacket packet, PgpEngine pgp) {
final Jid from = packet.getFrom();
if (!from.isBareJid()) {
diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
index d3c35789e..045916725 100644
--- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
@@ -1,7 +1,5 @@
package eu.siacs.conversations.generator;
-import android.util.Log;
-
import net.java.otr4j.OtrException;
import net.java.otr4j.session.Session;
@@ -10,8 +8,6 @@ import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
-import eu.siacs.conversations.Config;
-import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
@@ -62,11 +58,8 @@ public class MessageGenerator extends AbstractGenerator {
delay.setAttribute("stamp", mDateFormat.format(date));
}
- public MessagePacket generateAxolotlChat(Message message) {
+ public MessagePacket generateAxolotlChat(Message message, XmppAxolotlMessage axolotlMessage) {
MessagePacket packet = preparePacket(message);
- AxolotlService service = message.getConversation().getAccount().getAxolotlService();
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(message.getConversation().getAccount())+"Submitting message to axolotl service for send processing...");
- XmppAxolotlMessage axolotlMessage = service.encrypt(message);
if (axolotlMessage == null) {
return null;
}
@@ -83,6 +76,7 @@ public class MessageGenerator extends AbstractGenerator {
packet.addChild("private", "urn:xmpp:carbons:2");
packet.addChild("no-copy", "urn:xmpp:hints");
packet.addChild("no-permanent-store", "urn:xmpp:hints");
+ packet.addChild("no-permanent-storage", "urn:xmpp:hints");
try {
String content;
if (message.hasFileOnRemoteHost()) {
@@ -121,15 +115,18 @@ public class MessageGenerator extends AbstractGenerator {
public MessagePacket generateChatState(Conversation conversation) {
final Account account = conversation.getAccount();
MessagePacket packet = new MessagePacket();
+ packet.setType(MessagePacket.TYPE_CHAT);
packet.setTo(conversation.getJid().toBareJid());
packet.setFrom(account.getJid());
packet.addChild(ChatState.toElement(conversation.getOutgoingChatState()));
+ packet.addChild("no-store", "urn:xmpp:hints");
+ packet.addChild("no-storage", "urn:xmpp:hints"); //wrong! don't copy this. Its *store*
return packet;
}
public MessagePacket confirm(final Account account, final Jid to, final String id) {
MessagePacket packet = new MessagePacket();
- packet.setType(MessagePacket.TYPE_NORMAL);
+ packet.setType(MessagePacket.TYPE_CHAT);
packet.setTo(to);
packet.setFrom(account.getJid());
Element received = packet.addChild("displayed","urn:xmpp:chat-markers:0");
@@ -137,8 +134,7 @@ public class MessageGenerator extends AbstractGenerator {
return packet;
}
- public MessagePacket conferenceSubject(Conversation conversation,
- String subject) {
+ public MessagePacket conferenceSubject(Conversation conversation,String subject) {
MessagePacket packet = new MessagePacket();
packet.setType(MessagePacket.TYPE_GROUPCHAT);
packet.setTo(conversation.getJid().toBareJid());
@@ -172,10 +168,9 @@ public class MessageGenerator extends AbstractGenerator {
return packet;
}
- public MessagePacket received(Account account,
- MessagePacket originalMessage, String namespace) {
+ public MessagePacket received(Account account, MessagePacket originalMessage, String namespace, int type) {
MessagePacket receivedPacket = new MessagePacket();
- receivedPacket.setType(MessagePacket.TYPE_NORMAL);
+ receivedPacket.setType(type);
receivedPacket.setTo(originalMessage.getFrom());
receivedPacket.setFrom(account.getJid());
Element received = receivedPacket.addChild("received", namespace);
diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
index d7487af9d..30d9a393a 100644
--- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
+++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
@@ -35,7 +35,6 @@ public class HttpDownloadConnection implements Transferable {
private int mStatus = Transferable.STATUS_UNKNOWN;
private boolean acceptedAutomatically = false;
private int mProgress = 0;
- private long mLastGuiRefresh = 0;
public HttpDownloadConnection(HttpConnectionManager manager) {
this.mHttpConnectionManager = manager;
diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
index 38e0f98af..6e7b3276d 100644
--- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
@@ -70,18 +70,18 @@ public class MessageParser extends AbstractParser implements
try {
conversation.setLastReceivedOtrMessageId(id);
Session otrSession = conversation.getOtrSession();
- SessionStatus before = otrSession.getSessionStatus();
body = otrSession.transformReceiving(body);
- SessionStatus after = otrSession.getSessionStatus();
- if ((before != after) && (after == SessionStatus.ENCRYPTED)) {
+ SessionStatus status = otrSession.getSessionStatus();
+ if (body == null && status == SessionStatus.ENCRYPTED) {
conversation.setNextEncryption(Message.ENCRYPTION_OTR);
mXmppConnectionService.onOtrSessionEstablished(conversation);
- } else if ((before != after) && (after == SessionStatus.FINISHED)) {
+ return null;
+ } else if (body == null && status == SessionStatus.FINISHED) {
conversation.setNextEncryption(Message.ENCRYPTION_NONE);
conversation.resetOtrSession();
mXmppConnectionService.updateConversationUi();
- }
- if ((body == null) || (body.isEmpty())) {
+ return null;
+ } else if (body == null || (body.isEmpty())) {
return null;
}
if (body.startsWith(CryptoHelper.FILETRANSFER)) {
@@ -202,7 +202,13 @@ public class MessageParser extends AbstractParser implements
if (packet.getType() == MessagePacket.TYPE_ERROR) {
Jid from = packet.getFrom();
if (from != null) {
- mXmppConnectionService.markMessage(account, from.toBareJid(), packet.getId(), Message.STATUS_SEND_FAILED);
+ Message message = mXmppConnectionService.markMessage(account,
+ from.toBareJid(),
+ packet.getId(),
+ Message.STATUS_SEND_FAILED);
+ if (message != null && message.getEncryption() == Message.ENCRYPTION_OTR) {
+ message.getConversation().endOtrIfNeeded();
+ }
}
return true;
}
@@ -257,7 +263,7 @@ public class MessageParser extends AbstractParser implements
timestamp = AbstractParser.getTimestamp(packet, System.currentTimeMillis());
}
final String body = packet.getBody();
- final Element mucUserElement = packet.findChild("x","http://jabber.org/protocol/muc#user");
+ final Element mucUserElement = packet.findChild("x", "http://jabber.org/protocol/muc#user");
final String pgpEncrypted = packet.findChildContent("x", "jabber:x:encrypted");
final Element axolotlEncrypted = packet.findChild("axolotl_message", AxolotlService.PEP_PREFIX);
int status;
@@ -363,15 +369,19 @@ public class MessageParser extends AbstractParser implements
mXmppConnectionService.updateConversationUi();
}
- if (mXmppConnectionService.confirmMessages() && remoteMsgId != null && !isForwarded) {
+ if (mXmppConnectionService.confirmMessages() && remoteMsgId != null && !isForwarded && !isTypeGroupChat) {
if (packet.hasChild("markable", "urn:xmpp:chat-markers:0")) {
- MessagePacket receipt = mXmppConnectionService
- .getMessageGenerator().received(account, packet, "urn:xmpp:chat-markers:0");
+ MessagePacket receipt = mXmppConnectionService.getMessageGenerator().received(account,
+ packet,
+ "urn:xmpp:chat-markers:0",
+ MessagePacket.TYPE_CHAT);
mXmppConnectionService.sendMessagePacket(account, receipt);
}
if (packet.hasChild("request", "urn:xmpp:receipts")) {
- MessagePacket receipt = mXmppConnectionService
- .getMessageGenerator().received(account, packet, "urn:xmpp:receipts");
+ MessagePacket receipt = mXmppConnectionService.getMessageGenerator().received(account,
+ packet,
+ "urn:xmpp:receipts",
+ packet.getType());
mXmppConnectionService.sendMessagePacket(account, receipt);
}
}
diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
index 6091b352e..3120c0085 100644
--- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
@@ -845,7 +845,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
while(cursor.moveToNext()) {
if ( trust != null &&
cursor.getInt(cursor.getColumnIndex(AxolotlService.SQLiteAxolotlStore.TRUSTED))
- != trust.ordinal()) {
+ != trust.getCode()) {
continue;
}
try {
@@ -864,7 +864,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
String[] args = {
account.getUuid(),
name,
- String.valueOf(AxolotlService.SQLiteAxolotlStore.Trust.TRUSTED.ordinal())
+ String.valueOf(AxolotlService.SQLiteAxolotlStore.Trust.TRUSTED.getCode())
};
return DatabaseUtils.queryNumEntries(db, AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME,
AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ?"
@@ -886,7 +886,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
values.put(AxolotlService.SQLiteAxolotlStore.OWN, own ? 1 : 0);
values.put(AxolotlService.SQLiteAxolotlStore.FINGERPRINT, fingerprint);
values.put(AxolotlService.SQLiteAxolotlStore.KEY, base64Serialized);
- values.put(AxolotlService.SQLiteAxolotlStore.TRUSTED, trusted.ordinal());
+ values.put(AxolotlService.SQLiteAxolotlStore.TRUSTED, trusted.getCode());
db.insert(AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME, null, values);
}
@@ -896,7 +896,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
if (cursor.getCount() > 0) {
cursor.moveToFirst();
int trustValue = cursor.getInt(cursor.getColumnIndex(AxolotlService.SQLiteAxolotlStore.TRUSTED));
- trust = AxolotlService.SQLiteAxolotlStore.Trust.values()[trustValue];
+ trust = AxolotlService.SQLiteAxolotlStore.Trust.fromCode(trustValue);
}
cursor.close();
return trust;
@@ -909,7 +909,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
fingerprint
};
ContentValues values = new ContentValues();
- values.put(AxolotlService.SQLiteAxolotlStore.TRUSTED, trust.ordinal());
+ values.put(AxolotlService.SQLiteAxolotlStore.TRUSTED, trust.getCode());
int rows = db.update(AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME, values,
AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ? AND "
+ AxolotlService.SQLiteAxolotlStore.FINGERPRINT + " = ? ",
diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
index 9b05885d7..3a8248f16 100644
--- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
@@ -184,8 +184,18 @@ public class FileBackend {
return this.copyImageToPrivateStorage(message, image, 0);
}
- private DownloadableFile copyImageToPrivateStorage(Message message,
- Uri image, int sampleSize) throws FileCopyException {
+ private DownloadableFile copyImageToPrivateStorage(Message message,Uri image, int sampleSize) throws FileCopyException {
+ switch(Config.IMAGE_FORMAT) {
+ case JPEG:
+ message.setRelativeFilePath(message.getUuid()+".jpg");
+ break;
+ case PNG:
+ message.setRelativeFilePath(message.getUuid()+".png");
+ break;
+ case WEBP:
+ message.setRelativeFilePath(message.getUuid()+".webp");
+ break;
+ }
DownloadableFile file = getFile(message);
file.getParentFile().mkdirs();
InputStream is = null;
@@ -205,13 +215,13 @@ public class FileBackend {
if (originalBitmap == null) {
throw new FileCopyException(R.string.error_not_an_image_file);
}
- Bitmap scaledBitmap = resize(originalBitmap, IMAGE_SIZE);
+ Bitmap scaledBitmap = resize(originalBitmap, Config.IMAGE_SIZE);
int rotation = getRotation(image);
if (rotation > 0) {
scaledBitmap = rotate(scaledBitmap, rotation);
}
- boolean success = scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 75, os);
+ boolean success = scaledBitmap.compress(Config.IMAGE_FORMAT, Config.IMAGE_QUALITY, os);
if (!success) {
throw new FileCopyException(R.string.error_compressing_image);
}
diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java
index ec68c07a6..b99069a64 100644
--- a/src/main/java/eu/siacs/conversations/services/NotificationService.java
+++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java
@@ -62,12 +62,12 @@ public class NotificationService {
public boolean notify(final Message message) {
return (message.getStatus() == Message.STATUS_RECEIVED)
- && notificationsEnabled()
- && !message.getConversation().isMuted()
- && (message.getConversation().getMode() == Conversation.MODE_SINGLE
- || conferenceNotificationsEnabled()
- || wasHighlightedOrPrivate(message)
- );
+ && notificationsEnabled()
+ && !message.getConversation().isMuted()
+ && (message.getConversation().isPnNA()
+ || conferenceNotificationsEnabled()
+ || wasHighlightedOrPrivate(message)
+ );
}
public void notifyPebble(final Message message) {
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index e43b25368..fa0a87096 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -52,6 +52,7 @@ import de.duenndns.ssl.MemorizingTrustManager;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
+import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Blockable;
import eu.siacs.conversations.entities.Bookmark;
@@ -85,7 +86,7 @@ import eu.siacs.conversations.xmpp.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.OnMessageAcknowledged;
import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
-import eu.siacs.conversations.xmpp.OnNewKeysAvailable;
+import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.OnPresencePacketReceived;
import eu.siacs.conversations.xmpp.OnStatusChanged;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
@@ -308,8 +309,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
private int rosterChangedListenerCount = 0;
private OnMucRosterUpdate mOnMucRosterUpdate = null;
private int mucRosterChangedListenerCount = 0;
- private OnNewKeysAvailable mOnNewKeysAvailable = null;
- private int newKeysAvailableListenerCount = 0;
+ private OnKeyStatusUpdated mOnKeyStatusUpdated = null;
+ private int keyStatusUpdatedListenerCount = 0;
private SecureRandom mRandom;
private OpenPgpServiceConnection pgpServiceConnection;
private PgpEngine mPgpEngine = null;
@@ -765,10 +766,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
break;
}
} else {
- packet = account.getAxolotlService().fetchPacketFromCache(message);
- if (packet == null) {
+ XmppAxolotlMessage axolotlMessage = account.getAxolotlService().fetchAxolotlMessageFromCache(message);
+ if (axolotlMessage == null) {
account.getAxolotlService().prepareMessage(message,delay);
message.setAxolotlFingerprint(account.getAxolotlService().getOwnPublicKey().getFingerprint().replaceAll("\\s", ""));
+ } else {
+ packet = mMessageGenerator.generateAxolotlChat(message, axolotlMessage);
}
}
break;
@@ -839,7 +842,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
@Override
public void onMessageFound(Message message) {
- resendMessage(message,true);
+ resendMessage(message, true);
}
});
}
@@ -1369,30 +1372,31 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
- public void setOnNewKeysAvailableListener(final OnNewKeysAvailable listener) {
+ public void setOnKeyStatusUpdatedListener(final OnKeyStatusUpdated listener) {
synchronized (this) {
if (checkListeners()) {
switchToForeground();
}
- this.mOnNewKeysAvailable = listener;
- if (this.newKeysAvailableListenerCount < 2) {
- this.newKeysAvailableListenerCount++;
+ this.mOnKeyStatusUpdated = listener;
+ if (this.keyStatusUpdatedListenerCount < 2) {
+ this.keyStatusUpdatedListenerCount++;
}
}
}
public void removeOnNewKeysAvailableListener() {
synchronized (this) {
- this.newKeysAvailableListenerCount--;
- if (this.newKeysAvailableListenerCount <= 0) {
- this.newKeysAvailableListenerCount = 0;
- this.mOnNewKeysAvailable = null;
+ this.keyStatusUpdatedListenerCount--;
+ if (this.keyStatusUpdatedListenerCount <= 0) {
+ this.keyStatusUpdatedListenerCount = 0;
+ this.mOnKeyStatusUpdated = null;
if (checkListeners()) {
switchToBackground();
}
}
}
}
+
public void setOnMucRosterUpdateListener(OnMucRosterUpdate listener) {
synchronized (this) {
if (checkListeners()) {
@@ -1424,7 +1428,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
&& this.mOnRosterUpdate == null
&& this.mOnUpdateBlocklist == null
&& this.mOnShowErrorToast == null
- && this.mOnNewKeysAvailable == null);
+ && this.mOnKeyStatusUpdated == null);
}
private void switchToForeground() {
@@ -1851,7 +1855,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
} else {
MessagePacket outPacket = mMessageGenerator.generateOtrChat(message);
if (outPacket != null) {
- mMessageGenerator.addDelay(outPacket,message.getTimeSent());
+ mMessageGenerator.addDelay(outPacket, message.getTimeSent());
message.setStatus(Message.STATUS_SEND);
databaseBackend.updateMessage(message);
sendMessagePacket(account, outPacket);
@@ -2313,9 +2317,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
- public void newKeysAvailable() {
- if(mOnNewKeysAvailable != null) {
- mOnNewKeysAvailable.onNewKeysAvailable();
+ public void keyStatusUpdated() {
+ if(mOnKeyStatusUpdated != null) {
+ mOnKeyStatusUpdated.onKeyStatusUpdated();
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
index dbe881a01..7720459bc 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
@@ -265,14 +265,16 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
final User self = mConversation.getMucOptions().getSelf();
this.mSelectedUser = user;
String name;
+ final Contact contact = user.getContact();
+ if (contact != null) {
+ name = contact.getDisplayName();
+ } else if (user.getJid() != null){
+ name = user.getJid().toBareJid().toString();
+ } else {
+ name = user.getName();
+ }
+ menu.setHeaderTitle(name);
if (user.getJid() != null) {
- final Contact contact = user.getContact();
- if (contact != null) {
- name = contact.getDisplayName();
- } else {
- name = user.getJid().toBareJid().toString();
- }
- menu.setHeaderTitle(name);
MenuItem showContactDetails = menu.findItem(R.id.action_contact_details);
MenuItem startConversation = menu.findItem(R.id.start_conversation);
MenuItem giveMembership = menu.findItem(R.id.give_membership);
@@ -303,6 +305,9 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
removeAdminPrivileges.setVisible(true);
}
}
+ } else {
+ MenuItem sendPrivateMessage = menu.findItem(R.id.send_private_message);
+ sendPrivateMessage.setVisible(true);
}
}
@@ -340,6 +345,9 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
xmppConnectionService.changeAffiliationInConference(mConversation,mSelectedUser.getJid(), MucOptions.Affiliation.OUTCAST,this);
xmppConnectionService.changeRoleInConference(mConversation,mSelectedUser.getName(), MucOptions.Role.NONE,this);
return true;
+ case R.id.send_private_message:
+ privateMsgInMuc(mConversation,mSelectedUser.getName());
+ return true;
default:
return super.onContextItemSelected(item);
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
index 554634776..435293582 100644
--- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -43,12 +43,13 @@ import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
-public class ContactDetailsActivity extends XmppActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist {
+public class ContactDetailsActivity extends XmppActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist, OnKeyStatusUpdated {
public static final String ACTION_VIEW_CONTACT = "view_contact";
private Contact contact;
@@ -469,4 +470,9 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
populateView();
}
}
+
+ @Override
+ public void onKeyStatusUpdated() {
+ refreshUi();
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
index bf1ac2e20..9980d3bab 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
@@ -51,6 +51,8 @@ import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
import eu.siacs.conversations.ui.adapter.ConversationAdapter;
import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
+import eu.siacs.conversations.xmpp.jid.InvalidJidException;
+import eu.siacs.conversations.xmpp.jid.Jid;
public class ConversationActivity extends XmppActivity
implements OnAccountUpdate, OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, XmppConnectionService.OnShowErrorToast {
@@ -62,6 +64,7 @@ public class ConversationActivity extends XmppActivity
public static final String MESSAGE = "messageUuid";
public static final String TEXT = "text";
public static final String NICK = "nick";
+ public static final String PRIVATE_MESSAGE = "pm";
public static final int REQUEST_SEND_MESSAGE = 0x0201;
public static final int REQUEST_DECRYPT_PGP = 0x0202;
@@ -465,7 +468,7 @@ public class ConversationActivity extends XmppActivity
conversation.setNextCounterpart(null);
callback.onPresenceSelected();
} else {
- selectPresence(conversation,callback);
+ selectPresence(conversation, callback);
}
}
@@ -475,7 +478,7 @@ public class ConversationActivity extends XmppActivity
if (intent.resolveActivity(getPackageManager()) != null) {
return intent;
} else {
- intent.setData(Uri.parse("http://play.google.com/store/apps/details?id="+packageId));
+ intent.setData(Uri.parse("http://play.google.com/store/apps/details?id=" + packageId));
return intent;
}
}
@@ -832,7 +835,7 @@ public class ConversationActivity extends XmppActivity
}
conversation.setMutedTill(till);
ConversationActivity.this.xmppConnectionService.databaseBackend
- .updateConversation(conversation);
+ .updateConversation(conversation);
updateConversationList();
ConversationActivity.this.mConversationFragment.updateMessages();
invalidateOptionsMenu();
@@ -996,10 +999,21 @@ public class ConversationActivity extends XmppActivity
final String downloadUuid = intent.getStringExtra(MESSAGE);
final String text = intent.getStringExtra(TEXT);
final String nick = intent.getStringExtra(NICK);
+ final boolean pm = intent.getBooleanExtra(PRIVATE_MESSAGE,false);
if (selectConversationByUuid(uuid)) {
this.mConversationFragment.reInit(getSelectedConversation());
if (nick != null) {
- this.mConversationFragment.highlightInConference(nick);
+ if (pm) {
+ Jid jid = getSelectedConversation().getJid();
+ try {
+ Jid next = Jid.fromParts(jid.getLocalpart(),jid.getDomainpart(),nick);
+ this.mConversationFragment.privateMessageWith(next);
+ } catch (final InvalidJidException ignored) {
+ //do nothing
+ }
+ } else {
+ this.mConversationFragment.highlightInConference(nick);
+ }
} else {
this.mConversationFragment.appendText(text);
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index cccad16ad..842447c1f 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -385,11 +385,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
if (message.getStatus() <= Message.STATUS_RECEIVED) {
if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
if (message.getCounterpart() != null) {
- if (!message.getCounterpart().isBareJid()) {
- highlightInConference(message.getCounterpart().getResourcepart());
- } else {
- highlightInConference(message.getCounterpart().toString());
+ String user = message.getCounterpart().isBareJid() ? message.getCounterpart().toString() : message.getCounterpart().getResourcepart();
+ if (!message.getConversation().getMucOptions().isUserInRoom(user)) {
+ Toast.makeText(activity,activity.getString(R.string.user_has_left_conference,user),Toast.LENGTH_SHORT).show();
}
+ highlightInConference(user);
}
} else {
activity.switchToContactDetails(message.getContact());
@@ -410,7 +410,14 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
if (message.getStatus() <= Message.STATUS_RECEIVED) {
if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
if (message.getCounterpart() != null) {
- privateMessageWith(message.getCounterpart());
+ String user = message.getCounterpart().getResourcepart();
+ if (user != null) {
+ if (message.getConversation().getMucOptions().isUserInRoom(user)) {
+ privateMessageWith(message.getCounterpart());
+ } else {
+ Toast.makeText(activity, activity.getString(R.string.user_has_left_conference, user), Toast.LENGTH_SHORT).show();
+ }
+ }
}
}
} else {
@@ -571,7 +578,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
private void downloadFile(Message message) {
activity.xmppConnectionService.getHttpConnectionManager()
- .createNewDownloadConnection(message);
+ .createNewDownloadConnection(message,true);
}
private void cancelTransmission(Message message) {
diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index 02596550f..f65485b11 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -29,18 +29,20 @@ import org.whispersystems.libaxolotl.IdentityKey;
import java.util.Set;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.XmppConnection.Features;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
import eu.siacs.conversations.xmpp.pep.Avatar;
-public class EditAccountActivity extends XmppActivity implements OnAccountUpdate{
+public class EditAccountActivity extends XmppActivity implements OnAccountUpdate, OnKeyStatusUpdated {
private AutoCompleteTextView mAccountJid;
private EditText mPassword;
@@ -546,16 +548,18 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
}
}
});
- this.mRegenerateAxolotlKeyButton
- .setVisibility(View.VISIBLE);
- this.mRegenerateAxolotlKeyButton
- .setOnClickListener(new View.OnClickListener() {
-
- @Override
- public void onClick(final View v) {
- showRegenerateAxolotlKeyDialog();
- }
- });
+ if (Config.SHOW_REGENERATE_AXOLOTL_KEYS_BUTTON) {
+ this.mRegenerateAxolotlKeyButton
+ .setVisibility(View.VISIBLE);
+ this.mRegenerateAxolotlKeyButton
+ .setOnClickListener(new View.OnClickListener() {
+
+ @Override
+ public void onClick(final View v) {
+ showRegenerateAxolotlKeyDialog();
+ }
+ });
+ }
} else {
this.mAxolotlFingerprintBox.setVisibility(View.GONE);
}
@@ -618,4 +622,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
});
builder.create().show();
}
+
+ @Override
+ public void onKeyStatusUpdated() {
+ refreshUi();
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
index ccdef9c39..1bf07f3ea 100644
--- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
@@ -20,11 +20,11 @@ import eu.siacs.conversations.crypto.axolotl.AxolotlService.SQLiteAxolotlStore.T
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
-import eu.siacs.conversations.xmpp.OnNewKeysAvailable;
+import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
-public class TrustKeysActivity extends XmppActivity implements OnNewKeysAvailable {
+public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdated {
private Jid accountJid;
private Jid contactJid;
private boolean hasOtherTrustedKeys = false;
@@ -215,7 +215,7 @@ public class TrustKeysActivity extends XmppActivity implements OnNewKeysAvailabl
}
@Override
- public void onNewKeysAvailable() {
+ public void onKeyStatusUpdated() {
final Account account = xmppConnectionService.findAccountByJid(accountJid);
hasPendingFetches = false;
getFingerprints(account);
diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
index 197836278..835685107 100644
--- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
@@ -83,7 +83,7 @@ import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinde
import eu.siacs.conversations.ui.widget.Switch;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.ExceptionHelper;
-import eu.siacs.conversations.xmpp.OnNewKeysAvailable;
+import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
@@ -99,6 +99,7 @@ public abstract class XmppActivity extends Activity {
protected int mPrimaryTextColor;
protected int mSecondaryTextColor;
+ protected int mTertiaryTextColor;
protected int mPrimaryBackgroundColor;
protected int mSecondaryBackgroundColor;
protected int mColorRed;
@@ -294,8 +295,8 @@ public abstract class XmppActivity extends Activity {
if (this instanceof XmppConnectionService.OnShowErrorToast) {
this.xmppConnectionService.setOnShowErrorToastListener((XmppConnectionService.OnShowErrorToast) this);
}
- if (this instanceof OnNewKeysAvailable) {
- this.xmppConnectionService.setOnNewKeysAvailableListener((OnNewKeysAvailable) this);
+ if (this instanceof OnKeyStatusUpdated) {
+ this.xmppConnectionService.setOnKeyStatusUpdatedListener((OnKeyStatusUpdated) this);
}
}
@@ -318,7 +319,7 @@ public abstract class XmppActivity extends Activity {
if (this instanceof XmppConnectionService.OnShowErrorToast) {
this.xmppConnectionService.removeOnShowErrorToastListener();
}
- if (this instanceof OnNewKeysAvailable) {
+ if (this instanceof OnKeyStatusUpdated) {
this.xmppConnectionService.removeOnNewKeysAvailableListener();
}
}
@@ -349,6 +350,7 @@ public abstract class XmppActivity extends Activity {
ExceptionHelper.init(getApplicationContext());
mPrimaryTextColor = getResources().getColor(R.color.black87);
mSecondaryTextColor = getResources().getColor(R.color.black54);
+ mTertiaryTextColor = getResources().getColor(R.color.black12);
mColorRed = getResources().getColor(R.color.red500);
mColorOrange = getResources().getColor(R.color.orange500);
mColorGreen = getResources().getColor(R.color.green500);
@@ -384,14 +386,18 @@ public abstract class XmppActivity extends Activity {
public void switchToConversation(Conversation conversation, String text,
boolean newTask) {
- switchToConversation(conversation,text,null,newTask);
+ switchToConversation(conversation,text,null,false,newTask);
}
public void highlightInMuc(Conversation conversation, String nick) {
- switchToConversation(conversation, null, nick, false);
+ switchToConversation(conversation, null, nick, false, false);
}
- private void switchToConversation(Conversation conversation, String text, String nick, boolean newTask) {
+ public void privateMsgInMuc(Conversation conversation, String nick) {
+ switchToConversation(conversation, null, nick, true, false);
+ }
+
+ private void switchToConversation(Conversation conversation, String text, String nick, boolean pm, boolean newTask) {
Intent viewConversationIntent = new Intent(this,
ConversationActivity.class);
viewConversationIntent.setAction(Intent.ACTION_VIEW);
@@ -402,6 +408,7 @@ public abstract class XmppActivity extends Activity {
}
if (nick != null) {
viewConversationIntent.putExtra(ConversationActivity.NICK, nick);
+ viewConversationIntent.putExtra(ConversationActivity.PRIVATE_MESSAGE,pm);
}
viewConversationIntent.setType(ConversationActivity.VIEW_CONVERSATION);
if (newTask) {
@@ -456,7 +463,7 @@ public abstract class XmppActivity extends Activity {
@Override
public void userInputRequried(PendingIntent pi,
- Account account) {
+ Account account) {
try {
startIntentSenderForResult(pi.getIntentSender(),
REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
@@ -663,10 +670,21 @@ public abstract class XmppActivity extends Activity {
case TRUSTED:
trustToggle.setChecked(trust == AxolotlService.SQLiteAxolotlStore.Trust.TRUSTED, false);
trustToggle.setEnabled(true);
+ 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:
+ trustToggle.setOnClickListener(null);
+ trustToggle.setChecked(true, false);
+ trustToggle.setEnabled(false);
+ key.setTextColor(getTertiaryTextColor());
+ keyType.setTextColor(getTertiaryTextColor());
break;
}
@@ -819,6 +837,10 @@ public abstract class XmppActivity extends Activity {
}
};
+ public int getTertiaryTextColor() {
+ return this.mTertiaryTextColor;
+ }
+
public int getSecondaryTextColor() {
return this.mSecondaryTextColor;
}
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
index 8fa83cec7..083b78d2d 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -573,7 +573,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
Toast.LENGTH_SHORT).show();
}
} else if (message.treatAsDownloadable() != Message.Decision.NEVER) {
- activity.xmppConnectionService.getHttpConnectionManager().createNewDownloadConnection(message);
+ activity.xmppConnectionService.getHttpConnectionManager().createNewDownloadConnection(message,true);
}
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/OnKeyStatusUpdated.java b/src/main/java/eu/siacs/conversations/xmpp/OnKeyStatusUpdated.java
new file mode 100644
index 000000000..65ae133d5
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/xmpp/OnKeyStatusUpdated.java
@@ -0,0 +1,5 @@
+package eu.siacs.conversations.xmpp;
+
+public interface OnKeyStatusUpdated {
+ public void onKeyStatusUpdated();
+}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java b/src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java
index 59dc1c1ea..e69de29bb 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java
@@ -1,5 +0,0 @@
-package eu.siacs.conversations.xmpp;
-
-public interface OnNewKeysAvailable {
- public void onNewKeysAvailable();
-}
diff --git a/src/main/res/drawable-hdpi/message_bubble_received.9.png b/src/main/res/drawable-hdpi/message_bubble_received.9.png
index 20647f9f5..7433cd581 100644
--- a/src/main/res/drawable-hdpi/message_bubble_received.9.png
+++ b/src/main/res/drawable-hdpi/message_bubble_received.9.png
Binary files differ
diff --git a/src/main/res/drawable-hdpi/message_bubble_sent.9.png b/src/main/res/drawable-hdpi/message_bubble_sent.9.png
index 6cc8e81e5..9f8a1c074 100644
--- a/src/main/res/drawable-hdpi/message_bubble_sent.9.png
+++ b/src/main/res/drawable-hdpi/message_bubble_sent.9.png
Binary files differ
diff --git a/src/main/res/drawable-mdpi/message_bubble_received.9.png b/src/main/res/drawable-mdpi/message_bubble_received.9.png
index 6525d6c0f..fd67e2450 100644
--- a/src/main/res/drawable-mdpi/message_bubble_received.9.png
+++ b/src/main/res/drawable-mdpi/message_bubble_received.9.png
Binary files differ
diff --git a/src/main/res/drawable-mdpi/message_bubble_sent.9.png b/src/main/res/drawable-mdpi/message_bubble_sent.9.png
index 72cda8202..315c18d77 100644
--- a/src/main/res/drawable-mdpi/message_bubble_sent.9.png
+++ b/src/main/res/drawable-mdpi/message_bubble_sent.9.png
Binary files differ
diff --git a/src/main/res/drawable-xhdpi/message_bubble_received.9.png b/src/main/res/drawable-xhdpi/message_bubble_received.9.png
index d543043ad..56f39294c 100644
--- a/src/main/res/drawable-xhdpi/message_bubble_received.9.png
+++ b/src/main/res/drawable-xhdpi/message_bubble_received.9.png
Binary files differ
diff --git a/src/main/res/drawable-xhdpi/message_bubble_sent.9.png b/src/main/res/drawable-xhdpi/message_bubble_sent.9.png
index 12b4a2431..293d64f81 100644
--- a/src/main/res/drawable-xhdpi/message_bubble_sent.9.png
+++ b/src/main/res/drawable-xhdpi/message_bubble_sent.9.png
Binary files differ
diff --git a/src/main/res/drawable-xxhdpi/message_bubble_received.9.png b/src/main/res/drawable-xxhdpi/message_bubble_received.9.png
index 9bbdd98cf..42a7d69b3 100644
--- a/src/main/res/drawable-xxhdpi/message_bubble_received.9.png
+++ b/src/main/res/drawable-xxhdpi/message_bubble_received.9.png
Binary files differ
diff --git a/src/main/res/drawable-xxhdpi/message_bubble_sent.9.png b/src/main/res/drawable-xxhdpi/message_bubble_sent.9.png
index 3b9977593..762bcd916 100644
--- a/src/main/res/drawable-xxhdpi/message_bubble_sent.9.png
+++ b/src/main/res/drawable-xxhdpi/message_bubble_sent.9.png
Binary files differ
diff --git a/src/main/res/drawable-xxxhdpi/message_bubble_received.9.png b/src/main/res/drawable-xxxhdpi/message_bubble_received.9.png
index 498277659..41d52aa73 100644
--- a/src/main/res/drawable-xxxhdpi/message_bubble_received.9.png
+++ b/src/main/res/drawable-xxxhdpi/message_bubble_received.9.png
Binary files differ
diff --git a/src/main/res/drawable-xxxhdpi/message_bubble_sent.9.png b/src/main/res/drawable-xxxhdpi/message_bubble_sent.9.png
index 74601a370..1b9604b38 100644
--- a/src/main/res/drawable-xxxhdpi/message_bubble_sent.9.png
+++ b/src/main/res/drawable-xxxhdpi/message_bubble_sent.9.png
Binary files differ
diff --git a/src/main/res/layout/account_row.xml b/src/main/res/layout/account_row.xml
index fc8aae09a..f0d0c903d 100644
--- a/src/main/res/layout/account_row.xml
+++ b/src/main/res/layout/account_row.xml
@@ -1,13 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/activatedBackgroundIndicator"
- android:paddingLeft="8dp"
- android:paddingBottom="8dp"
- android:paddingTop="8dp">
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/activatedBackgroundIndicator"
+ android:paddingLeft="8dp"
+ android:paddingBottom="8dp"
+ android:paddingTop="8dp">
- <ImageView
+ <com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/account_image"
android:layout_width="48dp"
android:layout_height="48dp"
@@ -15,8 +16,8 @@
android:src="@drawable/ic_profile"
android:contentDescription="@string/account_image_description"
android:background="@drawable/message_border"
- android:padding="1dp">
- </ImageView>
+ android:padding="1dp"
+ app:riv_corner_radius="2dp" />
<LinearLayout
android:layout_width="fill_parent"
diff --git a/src/main/res/layout/activity_edit_account.xml b/src/main/res/layout/activity_edit_account.xml
index fb02f7bf4..8ffb79767 100644
--- a/src/main/res/layout/activity_edit_account.xml
+++ b/src/main/res/layout/activity_edit_account.xml
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/grey200" >
+ android:background="@color/grey200">
<ScrollView
android:layout_width="fill_parent"
@@ -27,14 +28,17 @@
android:background="@drawable/infocard_border"
android:orientation="vertical"
android:padding="@dimen/infocard_padding">
- <ImageView android:id="@+id/avater"
+
+ <com.makeramen.roundedimageview.RoundedImageView
+ android:id="@+id/avater"
android:layout_width="300dp"
android:layout_height="300dp"
- android:contentDescription="@string/account_image_description"
- android:background="@drawable/message_border"
- android:padding="1dp"
android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true" />
+ android:layout_marginRight="16dp"
+ android:layout_centerHorizontal="true"
+ android:contentDescription="@string/account_image_description"
+ app:riv_corner_radius="2dp"/>
+
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@@ -43,74 +47,74 @@
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="16dp">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/account_settings_jabber_id"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody" />
-
- <AutoCompleteTextView
- android:id="@+id/account_jid"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="@string/account_settings_example_jabber_id"
- android:inputType="textEmailAddress"
- android:textColor="@color/black87"
- android:textColorHint="@color/black54"
- android:textSize="?attr/TextSizeBody" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:text="@string/account_settings_password"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody" />
-
- <EditText
- android:id="@+id/account_password"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="@string/password"
- android:inputType="textPassword"
- android:textColor="@color/black87"
- android:textColorHint="@color/black54"
- android:textSize="?attr/TextSizeBody" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/account_settings_jabber_id"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody" />
- <CheckBox
- android:id="@+id/account_register_new"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:text="@string/register_account"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody" />
+ <AutoCompleteTextView
+ android:id="@+id/account_jid"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/account_settings_example_jabber_id"
+ android:inputType="textEmailAddress"
+ android:textColor="@color/black87"
+ android:textColorHint="@color/black54"
+ android:textSize="?attr/TextSizeBody" />
- <TextView
- android:id="@+id/account_confirm_password_desc"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/account_settings_confirm_password"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody"
- android:visibility="gone" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/account_settings_password"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody" />
+
+ <EditText
+ android:id="@+id/account_password"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/password"
+ android:inputType="textPassword"
+ android:textColor="@color/black87"
+ android:textColorHint="@color/black54"
+ android:textSize="?attr/TextSizeBody" />
+
+ <CheckBox
+ android:id="@+id/account_register_new"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/register_account"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody" />
- <EditText
- android:id="@+id/account_password_confirm"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:hint="@string/confirm_password"
- android:inputType="textPassword"
- android:visibility="gone"
- android:textColor="@color/black87"
- android:textColorHint="@color/black54"
- android:textSize="?attr/TextSizeBody" />
+ <TextView
+ android:id="@+id/account_confirm_password_desc"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/account_settings_confirm_password"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody"
+ android:visibility="gone" />
+
+ <EditText
+ android:id="@+id/account_password_confirm"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:hint="@string/confirm_password"
+ android:inputType="textPassword"
+ android:visibility="gone"
+ android:textColor="@color/black87"
+ android:textColorHint="@color/black54"
+ android:textSize="?attr/TextSizeBody" />
</LinearLayout>
</RelativeLayout>
- <LinearLayout
+ <LinearLayout
android:id="@+id/stats"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
@@ -348,65 +352,65 @@
android:visibility="visible"
android:contentDescription="@string/copy_otr_clipboard_description"/>
</RelativeLayout>
- <RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:id="@+id/axolotl_fingerprint_box"
- android:layout_marginTop="32dp">
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_toLeftOf="@+id/axolotl_actions"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/axolotl_fingerprint"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody"
- android:typeface="monospace"
- android:fontFamily="monospace"/>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@color/black54"
- android:textSize="?attr/TextSizeInfo"
- android:text="@string/this_device_axolotl_fingerprint"/>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/axolotl_actions"
- android:layout_centerVertical="true"
- android:layout_alignParentRight="true"
- android:orientation="vertical">
-
- <ImageButton
- android:id="@+id/action_copy_axolotl_to_clipboard"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="?android:selectableItemBackground"
- android:padding="@dimen/image_button_padding"
- android:src="?attr/icon_copy"
- android:visibility="visible"
- android:contentDescription="@string/copy_axolotl_clipboard_description"/>
- <ImageButton
- android:id="@+id/action_regenerate_axolotl_key"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="?android:selectableItemBackground"
- android:padding="@dimen/image_button_padding"
- android:src="?attr/icon_refresh"
- android:visibility="visible"
- android:contentDescription="@string/regenerate_axolotl_key"/>
-
- </LinearLayout>
- </RelativeLayout>
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/axolotl_fingerprint_box"
+ android:layout_marginTop="32dp">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_toLeftOf="@+id/axolotl_actions"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/axolotl_fingerprint"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody"
+ android:typeface="monospace"
+ android:fontFamily="monospace"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/black54"
+ android:textSize="?attr/TextSizeInfo"
+ android:text="@string/this_device_axolotl_fingerprint"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/axolotl_actions"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:orientation="vertical">
+
+ <ImageButton
+ android:id="@+id/action_copy_axolotl_to_clipboard"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="?android:selectableItemBackground"
+ android:padding="@dimen/image_button_padding"
+ android:src="?attr/icon_copy"
+ android:visibility="visible"
+ android:contentDescription="@string/copy_axolotl_clipboard_description"/>
+ <ImageButton
+ android:id="@+id/action_regenerate_axolotl_key"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="?android:selectableItemBackground"
+ android:padding="@dimen/image_button_padding"
+ android:src="?attr/icon_refresh"
+ android:visibility="gone"
+ android:contentDescription="@string/regenerate_axolotl_key"/>
+
+ </LinearLayout>
+ </RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/other_device_keys_card"
@@ -479,4 +483,4 @@
android:textColor="@color/black54" />
</LinearLayout>
-</RelativeLayout>
+</RelativeLayout> \ No newline at end of file
diff --git a/src/main/res/layout/activity_muc_details.xml b/src/main/res/layout/activity_muc_details.xml
index 671215eaa..b096b257e 100644
--- a/src/main/res/layout/activity_muc_details.xml
+++ b/src/main/res/layout/activity_muc_details.xml
@@ -1,157 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/grey200">
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/activity_vertical_margin"
+ android:layout_marginLeft="@dimen/activity_horizontal_margin"
+ android:layout_marginRight="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/activity_vertical_margin"
+ android:background="@drawable/infocard_border"
+ android:orientation="vertical"
+ android:padding="@dimen/infocard_padding">
+
+ <TextView
+ android:id="@+id/muc_jabberid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:text="@string/account_settings_example_jabber_id"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeHeadline"
+ android:textStyle="bold" />
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="32dp">
+
+ <com.makeramen.roundedimageview.RoundedImageView
+ android:id="@+id/your_photo"
+ android:layout_width="72dp"
+ android:layout_height="72dp"
+ android:layout_alignParentEnd="false"
+ android:layout_alignParentLeft="true"
+ android:background="@drawable/message_border"
+ android:padding="1dp"
+ android:src="@drawable/ic_profile"
+ app:riv_corner_radius="2dp" />
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toRightOf="@+id/your_photo"
+ android:orientation="vertical"
+ android:paddingLeft="8dp">
+
+ <TextView
+ android:id="@+id/muc_your_nick"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeHeadline" />
+
+ <TextView
+ android:id="@+id/muc_role"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody" />
+ </LinearLayout>
+
+ <ImageButton
+ android:id="@+id/edit_nick_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:background="?android:selectableItemBackground"
+ android:padding="@dimen/image_button_padding"
+ android:src="?attr/icon_edit_dark" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/muc_conference_type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_toLeftOf="@+id/change_conference_button"
+ android:text="@string/private_conference"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody" />
+
+ <ImageButton
+ android:id="@+id/change_conference_button"
+ style="?android:attr/buttonStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:layout_gravity="center_horizontal"
+ android:background="?android:selectableItemBackground"
+ android:padding="@dimen/image_button_padding"
+ android:src="?attr/icon_settings" />
+ </RelativeLayout>
+
+ <TextView
+ android:id="@+id/details_account"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:layout_marginTop="32dp"
+ android:text="@string/using_account"
+ android:textColor="@color/black54"
+ android:textSize="?attr/TextSizeInfo" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/muc_more_details"
android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@color/grey200">
-
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/activity_horizontal_margin"
- android:layout_marginRight="@dimen/activity_horizontal_margin"
- android:layout_marginTop="@dimen/activity_vertical_margin"
- android:layout_marginBottom="@dimen/activity_vertical_margin"
- android:background="@drawable/infocard_border"
- android:orientation="vertical"
- android:padding="@dimen/infocard_padding">
-
- <TextView
- android:id="@+id/muc_jabberid"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="16dp"
- android:text="@string/account_settings_example_jabber_id"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeHeadline"
- android:textStyle="bold"/>
-
- <RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="32dp">
-
- <ImageView
- android:id="@+id/your_photo"
- android:layout_width="72dp"
- android:layout_height="72dp"
- android:layout_alignParentLeft="true"
- android:src="@drawable/ic_profile"
- android:background="@drawable/message_border"
- android:padding="1dp"
- android:layout_alignParentEnd="false">
- </ImageView>
-
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_toRightOf="@+id/your_photo"
- android:orientation="vertical"
- android:paddingLeft="8dp">
-
- <TextView
- android:id="@+id/muc_your_nick"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeHeadline"/>
-
- <TextView
- android:id="@+id/muc_role"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody"/>
- </LinearLayout>
-
- <ImageButton
- android:id="@+id/edit_nick_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_centerVertical="true"
- android:background="?android:selectableItemBackground"
- android:padding="@dimen/image_button_padding"
- android:src="?attr/icon_edit_dark"/>
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <TextView
- android:id="@+id/muc_conference_type"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/private_conference"
- android:layout_centerVertical="true"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody"
- android:layout_alignParentLeft="true"
- android:layout_toLeftOf="@+id/change_conference_button"
- />
- <ImageButton
- android:id="@+id/change_conference_button"
- style="?android:attr/buttonStyleSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_alignParentRight="true"
- android:layout_centerVertical="true"
- android:background="?android:selectableItemBackground"
- android:padding="@dimen/image_button_padding"
- android:src="?attr/icon_settings"/>
- </RelativeLayout>
-
- <TextView
- android:id="@+id/details_account"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="right"
- android:layout_marginTop="32dp"
- android:text="@string/using_account"
- android:textColor="@color/black54"
- android:textSize="?attr/TextSizeInfo"/>
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/muc_more_details"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/activity_horizontal_margin"
- android:layout_marginRight="@dimen/activity_horizontal_margin"
- android:layout_marginTop="@dimen/activity_vertical_margin"
- android:layout_marginBottom="@dimen/activity_vertical_margin"
- android:background="@drawable/infocard_border"
- android:orientation="vertical"
- android:padding="@dimen/infocard_padding">
-
-
- <LinearLayout
- android:id="@+id/muc_members"
- android:layout_width="fill_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:divider="?android:dividerHorizontal"
- android:orientation="vertical"
- android:showDividers="middle">
- </LinearLayout>
-
- <Button
- android:id="@+id/invite"
- style="?android:attr/buttonStyleSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_marginTop="24dp"
- android:text="@string/invite_contact"/>
- </LinearLayout>
-
- </LinearLayout>
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/activity_vertical_margin"
+ android:layout_marginLeft="@dimen/activity_horizontal_margin"
+ android:layout_marginRight="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/activity_vertical_margin"
+ android:background="@drawable/infocard_border"
+ android:orientation="vertical"
+ android:padding="@dimen/infocard_padding">
+
+
+ <LinearLayout
+ android:id="@+id/muc_members"
+ android:layout_width="fill_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:divider="?android:dividerHorizontal"
+ android:orientation="vertical"
+ android:showDividers="middle"></LinearLayout>
+
+ <Button
+ android:id="@+id/invite"
+ style="?android:attr/buttonStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="24dp"
+ android:text="@string/invite_contact" />
+ </LinearLayout>
+
+ </LinearLayout>
</ScrollView> \ No newline at end of file
diff --git a/src/main/res/layout/contact.xml b/src/main/res/layout/contact.xml
index ccc013fcc..8d2e0b9bf 100644
--- a/src/main/res/layout/contact.xml
+++ b/src/main/res/layout/contact.xml
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/activatedBackgroundIndicator"
- android:padding="8dp" >
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/activatedBackgroundIndicator"
+ android:padding="8dp">
- <ImageView
+ <com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/contact_photo"
android:layout_width="56dp"
android:layout_height="56dp"
@@ -13,8 +14,8 @@
android:scaleType="centerCrop"
android:src="@drawable/ic_profile"
android:background="@drawable/message_border"
- android:padding="1dp">
- </ImageView>
+ android:padding="1dp"
+ app:riv_corner_radius="2dp" />
<LinearLayout
android:layout_width="wrap_content"
diff --git a/src/main/res/layout/conversation_list_row.xml b/src/main/res/layout/conversation_list_row.xml
index 5f1c5047d..446c65874 100644
--- a/src/main/res/layout/conversation_list_row.xml
+++ b/src/main/res/layout/conversation_list_row.xml
@@ -1,7 +1,8 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:descendantFocusability="blocksDescendants">
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:descendantFocusability="blocksDescendants">
<View
android:layout_width="fill_parent"
@@ -21,14 +22,15 @@
android:orientation="horizontal"
android:padding="8dp" >
- <ImageView
+ <com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/conversation_image"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_alignParentLeft="true"
android:scaleType="centerCrop"
android:background="@drawable/message_border"
- android:padding="1dp" />
+ android:padding="1dp"
+ app:riv_corner_radius="2dp" />
<RelativeLayout
android:layout_width="fill_parent"
diff --git a/src/main/res/layout/message_received.xml b/src/main/res/layout/message_received.xml
index ab1a02434..e310e3d78 100644
--- a/src/main/res/layout/message_received.xml
+++ b/src/main/res/layout/message_received.xml
@@ -1,21 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingBottom="3dp"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:paddingTop="3dp">
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="3dp"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:paddingTop="3dp">
- <ImageView
+ <com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/message_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:scaleType="fitXY"
- android:src="@drawable/ic_profile" />
+ android:src="@drawable/ic_profile"
+ app:riv_corner_radius="2dp" />
<LinearLayout
android:id="@+id/message_box"
diff --git a/src/main/res/layout/message_sent.xml b/src/main/res/layout/message_sent.xml
index b14462399..ac8ccfd93 100644
--- a/src/main/res/layout/message_sent.xml
+++ b/src/main/res/layout/message_sent.xml
@@ -1,14 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingBottom="3dp"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:paddingTop="3dp">
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="3dp"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:paddingTop="3dp">
- <ImageView
+ <com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/message_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -17,7 +18,8 @@
android:src="@drawable/ic_profile"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"/>
+ android:layout_alignParentEnd="true"
+ app:riv_corner_radius="2dp" />
<LinearLayout
android:id="@+id/message_box"
diff --git a/src/main/res/layout/message_status.xml b/src/main/res/layout/message_status.xml
index 6a7dfcfe9..2f14cbf54 100644
--- a/src/main/res/layout/message_status.xml
+++ b/src/main/res/layout/message_status.xml
@@ -1,14 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingBottom="5dp"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:paddingTop="5dp" >
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="5dp"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:paddingTop="5dp">
- <ImageView
+ <com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/message_photo"
android:layout_width="32dp"
android:layout_height="32dp"
@@ -18,7 +19,8 @@
android:padding="1dp"
android:scaleType="fitXY"
android:src="@drawable/ic_profile"
- android:background="@drawable/message_border" />
+ android:background="@drawable/message_border"
+ app:riv_corner_radius="1dp"/>
<TextView
android:id="@+id/status_message"
diff --git a/src/main/res/menu/muc_details_context.xml b/src/main/res/menu/muc_details_context.xml
index 713378942..b409860c5 100644
--- a/src/main/res/menu/muc_details_context.xml
+++ b/src/main/res/menu/muc_details_context.xml
@@ -13,6 +13,10 @@
android:title="@string/action_contact_details"
android:visible="false"/>
<item
+ android:id="@+id/send_private_message"
+ android:title="@string/send_private_message"
+ android:visible="false"/>
+ <item
android:id="@+id/give_membership"
android:title="@string/grant_membership"
android:visible="false"/>
diff --git a/src/main/res/values/colors.xml b/src/main/res/values/colors.xml
index 3a778a210..85a442c84 100644
--- a/src/main/res/values/colors.xml
+++ b/src/main/res/values/colors.xml
@@ -5,6 +5,7 @@
<color name="accent">#ff0091ea</color>
<color name="black87">#de000000</color>
<color name="black54">#8a000000</color>
+ <color name="black26">#42000000</color>
<color name="black12">#1f000000</color>
<color name="white">#ffffffff</color>
<color name="white70">#b2ffffff</color>
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 02321ddc4..a0cac6ea6 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -108,8 +108,8 @@
<string name="pref_vibrate_summary">Also vibrate when a new message arrives</string>
<string name="pref_sound">Sound</string>
<string name="pref_sound_summary">Play ringtone with notification</string>
- <string name="pref_conference_notifications">Conference notifications</string>
- <string name="pref_conference_notifications_summary">Always notify when a new conference message arrives instead of only when highlighted</string>
+ <string name="pref_conference_notifications">Notifications in Public Conferences</string>
+ <string name="pref_conference_notifications_summary">Always notify when a message arrives in a public conference instead of only when highlighted</string>
<string name="pref_notification_grace_period">Notification grace period</string>
<string name="pref_notification_grace_period_summary">Disable notifications for a short time after a carbon copy was received</string>
<string name="pref_advanced_options">Advanced Options</string>
@@ -497,4 +497,6 @@
<string name="choose_quick_action">Choose quick action</string>
<string name="file_not_found_on_remote_host">File not found on remote server</string>
<string name="search_for_contacts_or_groups">Search for contacts or groups</string>
+ <string name="send_private_message">Send private message</string>
+ <string name="user_has_left_conference">%s has left the conference!</string>
</resources>
diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml
index 388f5089b..8dbcd3f8e 100644
--- a/src/main/res/xml/preferences.xml
+++ b/src/main/res/xml/preferences.xml
@@ -83,7 +83,7 @@
android:title="@string/pref_sound" />
<CheckBoxPreference
- android:defaultValue="true"
+ android:defaultValue="false"
android:dependency="show_notification"
android:key="always_notify_in_conference"
android:summary="@string/pref_conference_notifications_summary"