aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/eu')
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java1
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Account.java19
-rw-r--r--src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java1
-rw-r--r--src/main/java/eu/siacs/conversations/generator/IqGenerator.java6
-rw-r--r--src/main/java/eu/siacs/conversations/parser/MessageParser.java2
-rw-r--r--src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java6
-rw-r--r--src/main/java/eu/siacs/conversations/services/AvatarService.java21
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java43
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java109
-rw-r--r--src/main/java/eu/siacs/conversations/utils/CryptoHelper.java15
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java6
11 files changed, 204 insertions, 25 deletions
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 ab3aefac..e15a73ba 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
@@ -515,6 +515,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
if (changed) {
if (account.getPrivateKeyAlias() != null && Config.X509_VERIFICATION) {
+ mXmppConnectionService.publishDisplayName(account);
publishDeviceVerificationAndBundle(signedPreKeyRecord, preKeyRecords, announce, wipe);
} else {
publishDeviceBundle(signedPreKeyRecord, preKeyRecords, announce, wipe);
diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java
index 06f2264b..fbee5b8a 100644
--- a/src/main/java/eu/siacs/conversations/entities/Account.java
+++ b/src/main/java/eu/siacs/conversations/entities/Account.java
@@ -38,6 +38,7 @@ public class Account extends AbstractEntity {
public static final String ROSTERVERSION = "rosterversion";
public static final String KEYS = "keys";
public static final String AVATAR = "avatar";
+ public static final String DISPLAY_NAME = "display_name";
public static final String PINNED_MECHANISM_KEY = "pinned_mechanism";
@@ -50,6 +51,14 @@ public class Account extends AbstractEntity {
return xmppConnection != null && xmppConnection.getFeatures().httpUpload();
}
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
public static enum State {
DISABLED,
OFFLINE,
@@ -125,6 +134,7 @@ public class Account extends AbstractEntity {
protected State status = State.OFFLINE;
protected JSONObject keys = new JSONObject();
protected String avatar;
+ protected String displayName = null;
protected boolean online = false;
private OtrService mOtrService = null;
private AxolotlService axolotlService = null;
@@ -142,12 +152,12 @@ public class Account extends AbstractEntity {
public Account(final Jid jid, final String password) {
this(java.util.UUID.randomUUID().toString(), jid,
- password, 0, null, "", null);
+ password, 0, null, "", null, null);
}
public Account(final String uuid, final Jid jid,
final String password, final int options, final String rosterVersion, final String keys,
- final String avatar) {
+ final String avatar, String displayName) {
this.uuid = uuid;
this.jid = jid;
if (jid.isBareJid()) {
@@ -162,6 +172,7 @@ public class Account extends AbstractEntity {
this.keys = new JSONObject();
}
this.avatar = avatar;
+ this.displayName = displayName;
}
public static Account fromCursor(final Cursor cursor) {
@@ -177,7 +188,8 @@ public class Account extends AbstractEntity {
cursor.getInt(cursor.getColumnIndex(OPTIONS)),
cursor.getString(cursor.getColumnIndex(ROSTERVERSION)),
cursor.getString(cursor.getColumnIndex(KEYS)),
- cursor.getString(cursor.getColumnIndex(AVATAR)));
+ cursor.getString(cursor.getColumnIndex(AVATAR)),
+ cursor.getString(cursor.getColumnIndex(DISPLAY_NAME)));
}
public boolean isOptionSet(final int option) {
@@ -289,6 +301,7 @@ public class Account extends AbstractEntity {
values.put(KEYS, this.keys.toString());
values.put(ROSTERVERSION, rosterVersion);
values.put(AVATAR, avatar);
+ values.put(DISPLAY_NAME, displayName);
return values;
}
diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
index 879a5680..5741af53 100644
--- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
@@ -27,6 +27,7 @@ public abstract class AbstractGenerator {
"http://jabber.org/protocol/caps",
"http://jabber.org/protocol/disco#info",
"urn:xmpp:avatar:metadata+notify",
+ "http://jabber.org/protocol/nick+notify",
"urn:xmpp:ping",
"jabber:iq:version",
"http://jabber.org/protocol/chatstates",
diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
index 7457cad8..345f68ae 100644
--- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
@@ -82,6 +82,12 @@ public class IqGenerator extends AbstractGenerator {
return packet;
}
+ public IqPacket publishNick(String nick) {
+ final Element item = new Element("item");
+ item.addChild("nick","http://jabber.org/protocol/nick").setContent(nick);
+ return publish("http://jabber.org/protocol/nick", item);
+ }
+
public IqPacket publishAvatar(Avatar avatar) {
final Element item = new Element("item");
item.setAttribute("id", avatar.sha1sum);
diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
index c534a417..58ca5135 100644
--- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
@@ -191,7 +191,7 @@ public class MessageParser extends AbstractParser implements
} else if ("http://jabber.org/protocol/nick".equals(node)) {
Element i = items.findChild("item");
Element nick = i == null ? null : i.findChild("nick", "http://jabber.org/protocol/nick");
- if (nick != null) {
+ if (nick != null && nick.getContent() != null) {
Contact contact = account.getRoster().getContact(from);
contact.setPresenceName(nick.getContent());
mXmppConnectionService.getAvatarService().clear(account);
diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
index 07071323..707237a1 100644
--- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
@@ -43,7 +43,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
private static DatabaseBackend instance = null;
private static final String DATABASE_NAME = "history";
- private static final int DATABASE_VERSION = 18;
+ private static final int DATABASE_VERSION = 19;
private static String CREATE_CONTATCS_STATEMENT = "create table "
+ Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, "
@@ -121,6 +121,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
db.execSQL("create table " + Account.TABLENAME + "(" + Account.UUID
+ " TEXT PRIMARY KEY," + Account.USERNAME + " TEXT,"
+ Account.SERVER + " TEXT," + Account.PASSWORD + " TEXT,"
+ + Account.DISPLAY_NAME + " TEXT, "
+ Account.ROSTERVERSION + " TEXT," + Account.OPTIONS
+ " NUMBER, " + Account.AVATAR + " TEXT, " + Account.KEYS
+ " TEXT)");
@@ -324,6 +325,9 @@ public class DatabaseBackend extends SQLiteOpenHelper {
if (oldVersion < 18 && newVersion >= 18) {
db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "+ Message.READ+ " NUMBER DEFAULT 1");
}
+ if (oldVersion < 19 && newVersion >= 19) {
+ db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN "+ Account.DISPLAY_NAME+ " TEXT");
+ }
}
public static synchronized DatabaseBackend getInstance(Context context) {
diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java
index 7412eb93..3cd32d79 100644
--- a/src/main/java/eu/siacs/conversations/services/AvatarService.java
+++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java
@@ -16,6 +16,7 @@ import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.ListItem;
+import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.utils.UIHelper;
@@ -179,9 +180,13 @@ public class AvatarService {
}
public Bitmap get(Account account, int size) {
+ return get(account, size, false);
+ }
+
+ public Bitmap get(Account account, int size, boolean cachedOnly) {
final String KEY = key(account, size);
Bitmap avatar = mXmppConnectionService.getBitmapCache().get(KEY);
- if (avatar != null) {
+ if (avatar != null || cachedOnly) {
return avatar;
}
avatar = mXmppConnectionService.getFileBackend().getAvatar(
@@ -193,6 +198,19 @@ public class AvatarService {
return avatar;
}
+ public Bitmap get(Message message, int size, boolean cachedOnly) {
+ if (message.getStatus() == Message.STATUS_RECEIVED) {
+ Contact contact = message.getContact();
+ if (contact != null) {
+ return get(contact, size, cachedOnly);
+ } else {
+ return get(UIHelper.getMessageDisplayName(message), size, cachedOnly);
+ }
+ } else {
+ return get(message.getConversation().getAccount(), size, cachedOnly);
+ }
+ }
+
public void clear(Account account) {
synchronized (this.sizes) {
for (Integer size : sizes) {
@@ -291,5 +309,4 @@ public class AvatarService {
Rect dst = new Rect(dstleft, dsttop, dstright, dstbottom);
canvas.drawBitmap(bm, null, dst, null);
}
-
}
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 613a5758..9abacbd1 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -1344,6 +1344,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
Account account = new Account(info.first, "");
account.setPrivateKeyAlias(alias);
account.setOption(Account.OPTION_DISABLED, true);
+ account.setDisplayName(info.second);
createAccount(account);
callback.onAccountCreated(account);
if (Config.X509_VERIFICATION) {
@@ -1372,6 +1373,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
Pair<Jid, String> info = CryptoHelper.extractJidAndName(chain[0]);
if (account.getJid().toBareJid().equals(info.first)) {
account.setPrivateKeyAlias(alias);
+ account.setDisplayName(info.second);
databaseBackend.updateAccount(account);
if (Config.X509_VERIFICATION) {
try {
@@ -1428,7 +1430,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (account.getXmppConnection() != null) {
this.disconnect(account, true);
}
- databaseBackend.deleteAccount(account);
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ databaseBackend.deleteAccount(account);
+ }
+ };
+ mDatabaseExecutor.execute(runnable);
this.accounts.remove(account);
updateAccountUi();
getNotificationService().updateErrorNotification();
@@ -2628,8 +2636,17 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void markRead(final Conversation conversation) {
mNotificationService.clear(conversation);
- for (Message message : conversation.markRead()) {
- databaseBackend.updateMessage(message);
+ final List<Message> readMessages = conversation.markRead();
+ if (readMessages.size() > 0) {
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ for (Message message : readMessages) {
+ databaseBackend.updateMessage(message);
+ }
+ }
+ };
+ mDatabaseExecutor.execute(runnable);
}
updateUnreadCountBadge();
}
@@ -2845,12 +2862,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
conversation.clearMessages();
conversation.setHasMessagesLeftOnServer(false); //avoid messages getting loaded through mam
conversation.resetLastMessageTransmitted();
- new Thread(new Runnable() {
+ Runnable runnable = new Runnable() {
@Override
public void run() {
databaseBackend.deleteMessagesInConversation(conversation);
}
- }).start();
+ };
+ mDatabaseExecutor.execute(runnable);
}
public void sendBlockRequest(final Blockable blockable) {
@@ -2884,6 +2902,21 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
+ public void publishDisplayName(Account account) {
+ String displayName = account.getDisplayName();
+ if (displayName != null && !displayName.isEmpty()) {
+ IqPacket publish = mIqGenerator.publishNick(displayName);
+ sendIqPacket(account, publish, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ if (packet.getType() == IqPacket.TYPE.ERROR) {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not publish nick");
+ }
+ }
+ });
+ }
+ }
+
public interface OnAccountCreated {
void onAccountCreated(Account account);
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 ec7ff73d..019b83d3 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -4,8 +4,13 @@ import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
import android.graphics.Typeface;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.AsyncTask;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
@@ -24,7 +29,9 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
+import java.lang.ref.WeakReference;
import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
@@ -36,6 +43,7 @@ import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Message.FileParams;
import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.ui.ConversationActivity;
+import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.GeoHelper;
import eu.siacs.conversations.utils.UIHelper;
@@ -462,6 +470,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
.findViewById(R.id.message_time);
viewHolder.indicatorReceived = (ImageView) view
.findViewById(R.id.indicator_received);
+ viewHolder.encryption = (TextView) view.findViewById(R.id.message_encryption);
break;
case STATUS:
view = activity.getLayoutInflater().inflate(R.layout.message_status, parent, false);
@@ -491,17 +500,8 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.status_message.setText(message.getBody());
}
return view;
- } else if (type == RECEIVED) {
- Contact contact = message.getContact();
- if (contact != null) {
- viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(contact, activity.getPixel(48)));
- } else if (conversation.getMode() == Conversation.MODE_MULTI) {
- viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(
- UIHelper.getMessageDisplayName(message),
- activity.getPixel(48)));
- }
- } else if (type == SENT) {
- viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(account, activity.getPixel(48)));
+ } else {
+ loadAvatar(message,viewHolder.contact_picture);
}
viewHolder.contact_picture
@@ -589,8 +589,11 @@ public class MessageAdapter extends ArrayAdapter<Message> {
} else {
viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received);
}
+ viewHolder.encryption.setVisibility(View.GONE);
} else {
viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received_warning);
+ viewHolder.encryption.setVisibility(View.VISIBLE);
+ viewHolder.encryption.setText(CryptoHelper.encryptionTypeToText(message.getEncryption()));
}
}
@@ -671,5 +674,89 @@ public class MessageAdapter extends ArrayAdapter<Message> {
protected TextView messageBody;
protected ImageView contact_picture;
protected TextView status_message;
+ protected TextView encryption;
+ }
+
+ class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> {
+ private final WeakReference<ImageView> imageViewReference;
+ private Message message = null;
+
+ public BitmapWorkerTask(ImageView imageView) {
+ imageViewReference = new WeakReference<>(imageView);
+ }
+
+ @Override
+ protected Bitmap doInBackground(Message... params) {
+ return activity.avatarService().get(params[0], activity.getPixel(48), isCancelled());
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap bitmap) {
+ if (bitmap != null) {
+ final ImageView imageView = imageViewReference.get();
+ if (imageView != null) {
+ imageView.setImageBitmap(bitmap);
+ imageView.setBackgroundColor(0x00000000);
+ }
+ }
+ }
+ }
+
+ public void loadAvatar(Message message, ImageView imageView) {
+ if (cancelPotentialWork(message, imageView)) {
+ final Bitmap bm = activity.avatarService().get(message, activity.getPixel(48), true);
+ if (bm != null) {
+ imageView.setImageBitmap(bm);
+ imageView.setBackgroundColor(0x00000000);
+ } else {
+ imageView.setBackgroundColor(UIHelper.getColorForName(UIHelper.getMessageDisplayName(message)));
+ imageView.setImageDrawable(null);
+ final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
+ final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task);
+ imageView.setImageDrawable(asyncDrawable);
+ try {
+ task.execute(message);
+ } catch (final RejectedExecutionException ignored) {
+ }
+ }
+ }
+ }
+
+ public static boolean cancelPotentialWork(Message message, ImageView imageView) {
+ final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
+
+ if (bitmapWorkerTask != null) {
+ final Message oldMessage = bitmapWorkerTask.message;
+ if (oldMessage == null || message != oldMessage) {
+ bitmapWorkerTask.cancel(true);
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
+ if (imageView != null) {
+ final Drawable drawable = imageView.getDrawable();
+ if (drawable instanceof AsyncDrawable) {
+ final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
+ return asyncDrawable.getBitmapWorkerTask();
+ }
+ }
+ return null;
+ }
+
+ static class AsyncDrawable extends BitmapDrawable {
+ private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
+
+ public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
+ super(res, bitmap);
+ bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask);
+ }
+
+ public BitmapWorkerTask getBitmapWorkerTask() {
+ return bitmapWorkerTaskReference.get();
+ }
}
}
diff --git a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
index 8091a996..ab407249 100644
--- a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
@@ -23,6 +23,8 @@ import java.util.LinkedHashSet;
import java.util.List;
import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
@@ -164,4 +166,17 @@ public final class CryptoHelper {
return null;
}
}
+
+ public static int encryptionTypeToText(int encryption) {
+ switch (encryption) {
+ case Message.ENCRYPTION_OTR:
+ return R.string.encryption_choice_otr;
+ case Message.ENCRYPTION_AXOLOTL:
+ return R.string.encryption_choice_omemo;
+ case Message.ENCRYPTION_NONE:
+ return R.string.encryption_choice_unencrypted;
+ default:
+ return R.string.encryption_choice_pgp;
+ }
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
index 1549aeb5..04c0f625 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -360,7 +360,8 @@ public class XmppConnection implements Runnable {
String.valueOf(saslMechanism.getPriority()));
tagReader.reset();
sendStartStream();
- if (tagReader.readTag().isStart("stream")) {
+ final Tag tag = tagReader.readTag();
+ if (tag != null && tag.isStart("stream")) {
processStream();
} else {
throw new IOException("server didn't restart stream after successful auth");
@@ -647,7 +648,8 @@ public class XmppConnection implements Runnable {
sendStartStream();
Log.d(Config.LOGTAG, account.getJid().toBareJid()+ ": TLS connection established");
features.encryptionEnabled = true;
- if (tagReader.readTag().isStart("stream")) {
+ final Tag tag = tagReader.readTag();
+ if (tag != null && tag.isStart("stream")) {
processStream();
} else {
throw new IOException("server didn't restart stream after STARTTLS");