Merge branch 'development' of https://github.com/siacs/Conversations into development

kruks23 created

Change summary

res/menu/newconversation.xml                                        |   6 
src/eu/siacs/conversations/crypto/PgpEngine.java                    |   1 
src/eu/siacs/conversations/entities/Account.java                    |   9 
src/eu/siacs/conversations/entities/Contact.java                    | 123 
src/eu/siacs/conversations/entities/Conversation.java               |  20 
src/eu/siacs/conversations/entities/Presences.java                  |  37 
src/eu/siacs/conversations/entities/Roster.java                     |  63 
src/eu/siacs/conversations/persistance/DatabaseBackend.java         | 152 
src/eu/siacs/conversations/services/XmppConnectionService.java      | 300 
src/eu/siacs/conversations/ui/ContactDetailsActivity.java           |  90 
src/eu/siacs/conversations/ui/ContactsActivity.java                 |  58 
src/eu/siacs/conversations/ui/ConversationActivity.java             |   8 
src/eu/siacs/conversations/ui/ConversationFragment.java             | 104 
src/eu/siacs/conversations/ui/ShareWithActivity.java                |  22 
src/eu/siacs/conversations/utils/OnPhoneContactsLoadedListener.java |   4 
src/eu/siacs/conversations/utils/PhoneHelper.java                   |  23 
src/eu/siacs/conversations/utils/UIHelper.java                      |   7 
17 files changed, 385 insertions(+), 642 deletions(-)

Detailed changes

res/menu/newconversation.xml 🔗

@@ -1,11 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <menu xmlns:android="http://schemas.android.com/apk/res/android" >
-    <item
-        android:id="@+id/action_refresh_contacts"
-        android:orderInCategory="10"
-        android:showAsAction="always"
-        android:icon="@drawable/ic_action_refresh"
-        android:title="@string/action_refresh" />
     <item
         android:id="@+id/action_accounts"
         android:orderInCategory="90"

src/eu/siacs/conversations/crypto/PgpEngine.java 🔗

@@ -221,7 +221,6 @@ public class PgpEngine {
 				return 0;
 			}
 		case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
-			Log.d("xmppService","openpgp user interaction requeried");
 			return 0;
 		case OpenPgpApi.RESULT_CODE_ERROR:
 			Log.d("xmppService","openpgp error: "+((OpenPgpError) result

src/eu/siacs/conversations/entities/Account.java 🔗

@@ -65,6 +65,8 @@ public class Account  extends AbstractEntity{
 
 	private String otrFingerprint;
 	
+	private Roster roster = null;
+	
 	public Account() {
 		this.uuid = "0";
 	}
@@ -287,4 +289,11 @@ public class Account  extends AbstractEntity{
 			return null;
 		}
 	}
+	
+	public Roster getRoster() {
+		if (this.roster==null) {
+			this.roster = new Roster(this);
+		}
+		return this.roster;
+	}
 }

src/eu/siacs/conversations/entities/Contact.java 🔗

@@ -4,33 +4,30 @@ import java.io.Serializable;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Set;
-
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
-
 import eu.siacs.conversations.xml.Element;
-
 import android.content.ContentValues;
 import android.database.Cursor;
-import android.util.Log;
 
 public class Contact extends AbstractEntity implements Serializable {
 	private static final long serialVersionUID = -4570817093119419962L;
 
 	public static final String TABLENAME = "contacts";
 
-	public static final String DISPLAYNAME = "name";
+	public static final String SYSTEMNAME = "systemname";
+	public static final String SERVERNAME = "servername";
 	public static final String JID = "jid";
-	public static final String SUBSCRIPTION = "subscription";
+	public static final String OPTIONS = "options";
 	public static final String SYSTEMACCOUNT = "systemaccount";
 	public static final String PHOTOURI = "photouri";
 	public static final String KEYS = "pgpkey";
-	public static final String PRESENCES = "presences";
 	public static final String ACCOUNT = "accountUuid";
 
 	protected String accountUuid;
-	protected String displayName;
+	protected String systemName;
+	protected String serverName;
 	protected String jid;
 	protected int subscription = 0;
 	protected String systemAccount;
@@ -42,26 +39,13 @@ public class Contact extends AbstractEntity implements Serializable {
 
 	protected boolean inRoster = true;
 
-	public Contact(Account account, String displayName, String jid,
-			String photoUri) {
-		if (account == null) {
-			this.accountUuid = null;
-		} else {
-			this.accountUuid = account.getUuid();
-		}
-		this.account = account;
-		this.displayName = displayName;
-		this.jid = jid;
-		this.photoUri = photoUri;
-		this.uuid = java.util.UUID.randomUUID().toString();
-	}
-
-	public Contact(String uuid, String account, String displayName, String jid,
-			int subscription, String photoUri, String systemAccount,
-			String keys, String presences) {
+	public Contact(String uuid, String account, String systemName,
+			String serverName, String jid, int subscription, String photoUri,
+			String systemAccount, String keys) {
 		this.uuid = uuid;
 		this.accountUuid = account;
-		this.displayName = displayName;
+		this.systemName = systemName;
+		this.serverName = serverName;
 		this.jid = jid;
 		this.subscription = subscription;
 		this.photoUri = photoUri;
@@ -74,11 +58,20 @@ public class Contact extends AbstractEntity implements Serializable {
 		} catch (JSONException e) {
 			this.keys = new JSONObject();
 		}
-		this.presences = Presences.fromJsonString(presences);
+	}
+
+	public Contact(String jid) {
+		this.jid = jid;
 	}
 
 	public String getDisplayName() {
-		return this.displayName;
+		if (this.systemName != null) {
+			return this.systemName;
+		} else if (this.serverName != null) {
+			return this.serverName;
+		} else {
+			return this.jid.split("@")[0];
+		}
 	}
 
 	public String getProfilePhoto() {
@@ -90,7 +83,7 @@ public class Contact extends AbstractEntity implements Serializable {
 	}
 
 	public boolean match(String needle) {
-		return (jid.toLowerCase().contains(needle.toLowerCase()) || (displayName
+		return (jid.toLowerCase().contains(needle.toLowerCase()) || (getDisplayName()
 				.toLowerCase().contains(needle.toLowerCase())));
 	}
 
@@ -99,26 +92,26 @@ public class Contact extends AbstractEntity implements Serializable {
 		ContentValues values = new ContentValues();
 		values.put(UUID, uuid);
 		values.put(ACCOUNT, accountUuid);
-		values.put(DISPLAYNAME, displayName);
+		values.put(SYSTEMNAME, systemName);
+		values.put(SERVERNAME, serverName);
 		values.put(JID, jid);
-		values.put(SUBSCRIPTION, subscription);
+		values.put(OPTIONS, subscription);
 		values.put(SYSTEMACCOUNT, systemAccount);
 		values.put(PHOTOURI, photoUri);
 		values.put(KEYS, keys.toString());
-		values.put(PRESENCES, presences.toJsonString());
 		return values;
 	}
 
 	public static Contact fromCursor(Cursor cursor) {
 		return new Contact(cursor.getString(cursor.getColumnIndex(UUID)),
 				cursor.getString(cursor.getColumnIndex(ACCOUNT)),
-				cursor.getString(cursor.getColumnIndex(DISPLAYNAME)),
+				cursor.getString(cursor.getColumnIndex(SYSTEMNAME)),
+				cursor.getString(cursor.getColumnIndex(SERVERNAME)),
 				cursor.getString(cursor.getColumnIndex(JID)),
-				cursor.getInt(cursor.getColumnIndex(SUBSCRIPTION)),
+				cursor.getInt(cursor.getColumnIndex(OPTIONS)),
 				cursor.getString(cursor.getColumnIndex(PHOTOURI)),
 				cursor.getString(cursor.getColumnIndex(SYSTEMACCOUNT)),
-				cursor.getString(cursor.getColumnIndex(KEYS)),
-				cursor.getString(cursor.getColumnIndex(PRESENCES)));
+				cursor.getString(cursor.getColumnIndex(KEYS)));
 	}
 
 	public int getSubscription() {
@@ -154,8 +147,8 @@ public class Contact extends AbstractEntity implements Serializable {
 				return (domainParts[0].equals("conf")
 						|| domainParts[0].equals("conference")
 						|| domainParts[0].equals("muc")
-						|| domainParts[0].equals("sala")
-						|| domainParts[0].equals("salas"));
+						|| domainParts[0].equals("sala") || domainParts[0]
+							.equals("salas"));
 			}
 		}
 	}
@@ -188,8 +181,12 @@ public class Contact extends AbstractEntity implements Serializable {
 		this.photoUri = uri;
 	}
 
-	public void setDisplayName(String name) {
-		this.displayName = name;
+	public void setServerName(String serverName) {
+		this.serverName = serverName;
+	}
+
+	public void setSystemName(String systemName) {
+		this.systemName = systemName;
 	}
 
 	public String getSystemAccount() {
@@ -249,15 +246,15 @@ public class Contact extends AbstractEntity implements Serializable {
 		}
 	}
 
-	public void setSubscriptionOption(int option) {
+	public void setOption(int option) {
 		this.subscription |= 1 << option;
 	}
 
-	public void resetSubscriptionOption(int option) {
+	public void resetOption(int option) {
 		this.subscription &= ~(1 << option);
 	}
 
-	public boolean getSubscriptionOption(int option) {
+	public boolean getOption(int option) {
 		return ((this.subscription & (1 << option)) != 0);
 	}
 
@@ -267,40 +264,38 @@ public class Contact extends AbstractEntity implements Serializable {
 
 		if (subscription != null) {
 			if (subscription.equals("to")) {
-				this.resetSubscriptionOption(Contact.Subscription.FROM);
-				this.setSubscriptionOption(Contact.Subscription.TO);
+				this.resetOption(Contact.Options.FROM);
+				this.setOption(Contact.Options.TO);
 			} else if (subscription.equals("from")) {
-				this.resetSubscriptionOption(Contact.Subscription.TO);
-				this.setSubscriptionOption(Contact.Subscription.FROM);
+				this.resetOption(Contact.Options.TO);
+				this.setOption(Contact.Options.FROM);
 			} else if (subscription.equals("both")) {
-				this.setSubscriptionOption(Contact.Subscription.TO);
-				this.setSubscriptionOption(Contact.Subscription.FROM);
+				this.setOption(Contact.Options.TO);
+				this.setOption(Contact.Options.FROM);
 			}
 		}
 
 		if ((ask != null) && (ask.equals("subscribe"))) {
-			this.setSubscriptionOption(Contact.Subscription.ASKING);
+			this.setOption(Contact.Options.ASKING);
 		} else {
-			this.resetSubscriptionOption(Contact.Subscription.ASKING);
+			this.resetOption(Contact.Options.ASKING);
+		}
+	}
+
+	public Element asElement() {
+		Element item = new Element("item");
+		item.setAttribute("jid", this.jid);
+		if (this.serverName != null) {
+			item.setAttribute("name", this.serverName);
 		}
+		return item;
 	}
 
-	public class Subscription {
+	public class Options {
 		public static final int TO = 0;
 		public static final int FROM = 1;
 		public static final int ASKING = 2;
 		public static final int PREEMPTIVE_GRANT = 4;
-	}
-
-	public void flagAsNotInRoster() {
-		this.inRoster = false;
-	}
-
-	public boolean isInRoster() {
-		return this.inRoster;
-	}
-
-	public String getAccountUuid() {
-		return this.accountUuid;
+		public static final int IN_ROSTER = 8;
 	}
 }

src/eu/siacs/conversations/entities/Conversation.java 🔗

@@ -49,7 +49,6 @@ public class Conversation extends AbstractEntity {
 
 	private transient List<Message> messages = null;
 	private transient Account account = null;
-	private transient Contact contact;
 
 	private transient SessionImpl otrSession;
 
@@ -129,19 +128,13 @@ public class Conversation extends AbstractEntity {
 	public String getName(boolean useSubject) {
 		if ((getMode() == MODE_MULTI) && (getMucOptions().getSubject() != null) && useSubject) {
 			return getMucOptions().getSubject();
-		} else if (this.contact != null) {
-			return this.contact.getDisplayName();
 		} else {
-			return this.name;
+			return this.getContact().getDisplayName();
 		}
 	}
 
 	public String getProfilePhotoString() {
-		if (this.contact == null) {
-			return null;
-		} else {
-			return this.contact.getProfilePhoto();
-		}
+		return this.getContact().getProfilePhoto();
 	}
 
 	public String getAccountUuid() {
@@ -153,14 +146,7 @@ public class Conversation extends AbstractEntity {
 	}
 
 	public Contact getContact() {
-		return this.contact;
-	}
-
-	public void setContact(Contact contact) {
-		this.contact = contact;
-		if (contact != null) {
-			this.contactUuid = contact.getUuid();
-		}
+		return this.account.getRoster().getContact(this.contactJid);
 	}
 
 	public void setAccount(Account account) {

src/eu/siacs/conversations/entities/Presences.java 🔗

@@ -4,10 +4,6 @@ import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.Map.Entry;
 
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
 import eu.siacs.conversations.xml.Element;
 
 public class Presences {
@@ -47,39 +43,6 @@ public class Presences {
 		return status;
 	}
 
-	public String toJsonString() {
-		JSONArray json = new JSONArray();
-		Iterator<Entry<String, Integer>> it = presences.entrySet().iterator();
-
-		while (it.hasNext()) {
-			Entry<String, Integer> entry = it.next();
-			JSONObject jObj = new JSONObject();
-			try {
-				jObj.put("resource", entry.getKey());
-				jObj.put("status", entry.getValue());
-			} catch (JSONException e) {
-				
-			}
-			json.put(jObj);
-		}
-		return json.toString();
-	}
-
-	public static Presences fromJsonString(String jsonString) {
-		Presences presences = new Presences();
-		try {
-			JSONArray json = new JSONArray(jsonString);
-			for (int i = 0; i < json.length(); ++i) {
-				JSONObject jObj = json.getJSONObject(i);
-				presences.updatePresence(jObj.getString("resource"),
-						jObj.getInt("status"));
-			}
-		} catch (JSONException e1) {
-
-		}
-		return presences;
-	}
-
 	public static int parseShow(Element show) {
 		if (show == null) {
 			return Presences.ONLINE;

src/eu/siacs/conversations/entities/Roster.java 🔗

@@ -0,0 +1,63 @@
+package eu.siacs.conversations.entities;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class Roster {
+	Account account;
+	HashMap<String, Contact> contacts = new HashMap<String, Contact>();
+	private String version = null;
+	
+	public Roster(Account account) {
+		this.account = account;
+	}
+	
+	public boolean hasContact(String jid) {
+		String cleanJid = jid.split("/")[0];
+		return contacts.containsKey(cleanJid);
+	}
+	
+	public Contact getContact(String jid) {
+		String cleanJid = jid.split("/")[0];
+		if (contacts.containsKey(cleanJid)) {
+			return contacts.get(cleanJid);
+		} else {
+			Contact contact = new Contact(cleanJid);
+			contact.setAccount(account);
+			contacts.put(cleanJid, contact);
+			return contact;
+		}
+	}
+
+	public void clearPresences() {
+		// TODO Auto-generated method stub
+		
+	}
+	
+	public void markAllAsNotInRoster() {
+		
+	}
+
+	public List<Contact> getContacts() {
+		return new ArrayList<Contact>(this.contacts.values());
+	}
+
+	public void initContact(Contact contact) {
+		contact.setAccount(account);
+		contact.setOption(Contact.Options.IN_ROSTER);
+		contacts.put(contact.getJid(),contact);
+	}
+
+	public void setVersion(String version) {
+		this.version = version;
+	}
+	
+	public String getVersion() {
+		return this.version;
+	}
+
+	public Account getAccount() {
+		return this.account;
+	}
+}

src/eu/siacs/conversations/persistance/DatabaseBackend.java 🔗

@@ -10,6 +10,7 @@ import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.entities.Presences;
+import eu.siacs.conversations.entities.Roster;
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
@@ -23,7 +24,16 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 	private static DatabaseBackend instance = null;
 
 	private static final String DATABASE_NAME = "history";
-	private static final int DATABASE_VERSION = 3;
+	private static final int DATABASE_VERSION = 5;
+
+	private static String CREATE_CONTATCS_STATEMENT = "create table "
+			+ Contact.TABLENAME + "(" + Contact.UUID + " TEXT PRIMARY KEY, "
+			+ Contact.ACCOUNT + " TEXT, " + Contact.SERVERNAME + " TEXT, "
+			+ Contact.SYSTEMNAME + " TEXT," + Contact.JID + " TEXT,"
+			+ Contact.KEYS + " TEXT," + Contact.PHOTOURI + " TEXT,"
+			+ Contact.OPTIONS + " NUMBER," + Contact.SYSTEMACCOUNT
+			+ " NUMBER, " + "FOREIGN KEY(" + Contact.ACCOUNT + ") REFERENCES "
+			+ Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE);";
 
 	public DatabaseBackend(Context context) {
 		super(context, DATABASE_NAME, null, DATABASE_VERSION);
@@ -36,7 +46,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 				+ " TEXT PRIMARY KEY," + Account.USERNAME + " TEXT,"
 				+ Account.SERVER + " TEXT," + Account.PASSWORD + " TEXT,"
 				+ Account.ROSTERVERSION + " TEXT," + Account.OPTIONS
-				+ " NUMBER, "+Account.KEYS+" TEXT)");
+				+ " NUMBER, " + Account.KEYS + " TEXT)");
 		db.execSQL("create table " + Conversation.TABLENAME + " ("
 				+ Conversation.UUID + " TEXT PRIMARY KEY, " + Conversation.NAME
 				+ " TEXT, " + Conversation.CONTACT + " TEXT, "
@@ -50,31 +60,28 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 				+ " TEXT PRIMARY KEY, " + Message.CONVERSATION + " TEXT, "
 				+ Message.TIME_SENT + " NUMBER, " + Message.COUNTERPART
 				+ " TEXT, " + Message.BODY + " TEXT, " + Message.ENCRYPTION
-				+ " NUMBER, " + Message.STATUS + " NUMBER," +Message.TYPE +" NUMBER, FOREIGN KEY("
-				+ Message.CONVERSATION + ") REFERENCES "
-				+ Conversation.TABLENAME + "(" + Conversation.UUID
-				+ ") ON DELETE CASCADE);");
-		db.execSQL("create table " + Contact.TABLENAME + "(" + Contact.UUID
-				+ " TEXT PRIMARY KEY, " + Contact.ACCOUNT + " TEXT, "
-				+ Contact.DISPLAYNAME + " TEXT," + Contact.JID + " TEXT,"
-				+ Contact.PRESENCES + " TEXT, " + Contact.KEYS
-				+ " TEXT," + Contact.PHOTOURI + " TEXT," + Contact.SUBSCRIPTION
-				+ " NUMBER," + Contact.SYSTEMACCOUNT + " NUMBER, "
-				+ "FOREIGN KEY(" + Contact.ACCOUNT + ") REFERENCES "
-				+ Account.TABLENAME + "(" + Account.UUID
-				+ ") ON DELETE CASCADE);");
+				+ " NUMBER, " + Message.STATUS + " NUMBER," + Message.TYPE
+				+ " NUMBER, FOREIGN KEY(" + Message.CONVERSATION
+				+ ") REFERENCES " + Conversation.TABLENAME + "("
+				+ Conversation.UUID + ") ON DELETE CASCADE);");
+
+		db.execSQL(CREATE_CONTATCS_STATEMENT);
 	}
 
 	@Override
 	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 		if (oldVersion < 2 && newVersion >= 2) {
-			// enable compression by default.
-			db.execSQL("update " + Account.TABLENAME
-				+ " set " + Account.OPTIONS + " = " + Account.OPTIONS + " | 8");
+			db.execSQL("update " + Account.TABLENAME + " set "
+					+ Account.OPTIONS + " = " + Account.OPTIONS + " | 8");
 		}
 		if (oldVersion < 3 && newVersion >= 3) {
-			//add field type to message
-			db.execSQL("ALTER TABLE "+Message.TABLENAME+" ADD COLUMN "+Message.TYPE+" NUMBER");;
+			db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
+					+ Message.TYPE + " NUMBER");
+		}
+		if (oldVersion < 5 && newVersion >= 5) {
+			db.execSQL("DROP TABLE "+Contact.TABLENAME);
+			db.execSQL(CREATE_CONTATCS_STATEMENT);
+			db.execSQL("UPDATE "+Account.TABLENAME+ " SET "+Account.ROSTERVERSION+" = NULL");
 		}
 	}
 
@@ -99,7 +106,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 		SQLiteDatabase db = this.getWritableDatabase();
 		db.insert(Account.TABLENAME, null, account.getContentValues());
 	}
-	
+
 	public void createContact(Contact contact) {
 		SQLiteDatabase db = this.getWritableDatabase();
 		db.insert(Contact.TABLENAME, null, contact.getContentValues());
@@ -145,10 +152,10 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 
 	public Conversation findConversation(Account account, String contactJid) {
 		SQLiteDatabase db = this.getReadableDatabase();
-		String[] selectionArgs = { account.getUuid(), contactJid+"%" };
+		String[] selectionArgs = { account.getUuid(), contactJid + "%" };
 		Cursor cursor = db.query(Conversation.TABLENAME, null,
-				Conversation.ACCOUNT + "=? AND " + Conversation.CONTACTJID + " like ?",
-				selectionArgs, null, null, null);
+				Conversation.ACCOUNT + "=? AND " + Conversation.CONTACTJID
+						+ " like ?", selectionArgs, null, null, null);
 		if (cursor.getCount() == 0)
 			return null;
 		cursor.moveToFirst();
@@ -200,87 +207,20 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 		db.update(Message.TABLENAME, message.getContentValues(), Message.UUID
 				+ "=?", args);
 	}
-	
-	public void updateContact(Contact contact, boolean updatePresences) {
-		SQLiteDatabase db = this.getWritableDatabase();
-		String[] args = { contact.getUuid() };
-		ContentValues values = contact.getContentValues();
-		if (!updatePresences) {
-			values.remove(Contact.PRESENCES);
-		} else {
-			values.remove(Contact.DISPLAYNAME);
-			values.remove(Contact.PHOTOURI);
-			values.remove(Contact.SYSTEMACCOUNT);
-		}
-		db.update(Contact.TABLENAME, contact.getContentValues(), Contact.UUID
-				+ "=?", args);
-	}
-	
-	public void clearPresences(Account account) {
-		SQLiteDatabase db = this.getWritableDatabase();
-		String[] args = { account.getUuid() };
-		ContentValues values = new ContentValues();
-		values.put(Contact.PRESENCES,"[]");
-		db.update(Contact.TABLENAME, values, Contact.ACCOUNT
-				+ "=?", args);
-	}
-	
-	public void mergeContacts(List<Contact> contacts) {
-		SQLiteDatabase db = this.getWritableDatabase();
-		for (int i = 0; i < contacts.size(); i++) {
-			Contact contact = contacts.get(i);
-			String[] columns = {Contact.UUID, Contact.PRESENCES};
-			String[] args = {contact.getAccount().getUuid(), contact.getJid()};
-			Cursor cursor = db.query(Contact.TABLENAME, columns,Contact.ACCOUNT+"=? AND "+Contact.JID+"=?", args, null, null, null);
-			if (cursor.getCount()>=1) {
-				cursor.moveToFirst();
-				contact.setUuid(cursor.getString(0));
-				updateContact(contact,false);
-			} else {
-				contact.setUuid(UUID.randomUUID().toString());
-				createContact(contact);
-			}
-		}
-	}
 
-	public List<Contact> getContactsByAccount(Account account) {
-		List<Contact> list = new ArrayList<Contact>();
+	public void readRoster(Roster roster) {
 		SQLiteDatabase db = this.getReadableDatabase();
 		Cursor cursor;
-		if (account==null) {
-			cursor = db.query(Contact.TABLENAME, null, null, null, null,
-					null, null);
-		} else {
-			String args[] = {account.getUuid()};
-			cursor = db.query(Contact.TABLENAME, null, Contact.ACCOUNT+"=?", args, null,
-					null, null);
-		}
+		String args[] = { roster.getAccount().getUuid() };
+		cursor = db.query(Contact.TABLENAME, null, Contact.ACCOUNT + "=?",
+				args, null, null, null);
 		while (cursor.moveToNext()) {
-			list.add(Contact.fromCursor(cursor));
+			roster.initContact(Contact.fromCursor(cursor));
 		}
-		return list;
 	}
 	
-	public List<Contact> getContacts(String where) {
-		List<Contact> list = new ArrayList<Contact>();
-		SQLiteDatabase db = this.getReadableDatabase();
-		Cursor cursor = db.query(Contact.TABLENAME, null, where, null, null, null, null);
-		while (cursor.moveToNext()) {
-			list.add(Contact.fromCursor(cursor));
-		}
-		return list;
-	}
-
-	public Contact findContact(Account account, String jid) {
-		SQLiteDatabase db = this.getReadableDatabase();
-		String[] selectionArgs = { account.getUuid(), jid };
-		Cursor cursor = db.query(Contact.TABLENAME, null,
-				Contact.ACCOUNT + "=? AND " + Contact.JID + "=?",
-				selectionArgs, null, null, null);
-		if (cursor.getCount() == 0)
-			return null;
-		cursor.moveToFirst();
-		return Contact.fromCursor(cursor);
+	public void writeRoster(Roster roster) {
+		
 	}
 
 	public void deleteMessage(Message message) {
@@ -288,7 +228,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 		String[] args = { message.getUuid() };
 		db.delete(Message.TABLENAME, Message.UUID + "=?", args);
 	}
-	
+
 	public void deleteMessagesInConversation(Conversation conversation) {
 		SQLiteDatabase db = this.getWritableDatabase();
 		String[] args = { conversation.getUuid() };
@@ -304,7 +244,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 	public Contact getContact(String uuid) {
 		SQLiteDatabase db = this.getWritableDatabase();
 		String[] args = { uuid };
-		Cursor cursor = db.query(Contact.TABLENAME, null, Contact.UUID + "=?", args, null, null, null);
+		Cursor cursor = db.query(Contact.TABLENAME, null, Contact.UUID + "=?",
+				args, null, null, null);
 		if (cursor.getCount() == 0) {
 			return null;
 		}
@@ -315,7 +256,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 	public Conversation findConversationByUuid(String conversationUuid) {
 		SQLiteDatabase db = this.getReadableDatabase();
 		String[] selectionArgs = { conversationUuid };
-		Cursor cursor = db.query(Conversation.TABLENAME, null, Conversation.UUID + "=?", selectionArgs, null, null, null);
+		Cursor cursor = db.query(Conversation.TABLENAME, null,
+				Conversation.UUID + "=?", selectionArgs, null, null, null);
 		if (cursor.getCount() == 0) {
 			return null;
 		}
@@ -326,18 +268,20 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 	public Message findMessageByUuid(String messageUuid) {
 		SQLiteDatabase db = this.getReadableDatabase();
 		String[] selectionArgs = { messageUuid };
-		Cursor cursor = db.query(Message.TABLENAME, null, Message.UUID + "=?", selectionArgs, null, null, null);
+		Cursor cursor = db.query(Message.TABLENAME, null, Message.UUID + "=?",
+				selectionArgs, null, null, null);
 		if (cursor.getCount() == 0) {
 			return null;
 		}
 		cursor.moveToFirst();
 		return Message.fromCursor(cursor);
 	}
-	
+
 	public Account findAccountByUuid(String accountUuid) {
 		SQLiteDatabase db = this.getReadableDatabase();
 		String[] selectionArgs = { accountUuid };
-		Cursor cursor = db.query(Account.TABLENAME, null, Account.UUID + "=?", selectionArgs, null, null, null);
+		Cursor cursor = db.query(Account.TABLENAME, null, Account.UUID + "=?",
+				selectionArgs, null, null, null);
 		if (cursor.getCount() == 0) {
 			return null;
 		}

src/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -27,10 +27,8 @@ import eu.siacs.conversations.entities.Presences;
 import eu.siacs.conversations.parser.MessageParser;
 import eu.siacs.conversations.persistance.DatabaseBackend;
 import eu.siacs.conversations.persistance.FileBackend;
-import eu.siacs.conversations.persistance.OnPhoneContactsMerged;
 import eu.siacs.conversations.ui.OnAccountListChangedListener;
 import eu.siacs.conversations.ui.OnConversationListChangedListener;
-import eu.siacs.conversations.ui.OnRosterFetchedListener;
 import eu.siacs.conversations.ui.UiCallback;
 import eu.siacs.conversations.utils.ExceptionHelper;
 import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener;
@@ -57,13 +55,13 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.database.ContentObserver;
-import android.database.DatabaseUtils;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
 import android.os.SystemClock;
@@ -84,6 +82,8 @@ public class XmppConnectionService extends Service {
 	private static final int PING_TIMEOUT = 5;
 	private static final int CONNECT_TIMEOUT = 60;
 	private static final long CARBON_GRACE_PERIOD = 60000L;
+	
+	private static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
 
 	private MessageParser mMessageParser = new MessageParser(this);
 
@@ -110,8 +110,9 @@ public class XmppConnectionService extends Service {
 		@Override
 		public void onChange(boolean selfChange) {
 			super.onChange(selfChange);
-			Log.d(LOGTAG, "contact list has changed");
-			mergePhoneContactsWithRoster(null);
+			Intent intent = new Intent(getApplicationContext(), XmppConnectionService.class);
+			intent.setAction(ACTION_MERGE_PHONE_CONTACTS);
+			startService(intent);
 		}
 	};
 
@@ -300,17 +301,14 @@ public class XmppConnectionService extends Service {
 					}
 
 				} else {
-					Contact contact = findContact(account, fromParts[0]);
-					if (contact == null) {
-						if ("subscribe".equals(type)) {
-							account.getXmppConnection().addPendingSubscription(
-									fromParts[0]);
-						} else {
-							// Log.d(LOGTAG,packet.getFrom()+
-							// " could not be found");
-						}
-						return;
-					}
+					Contact contact = account.getRoster().getContact(
+							packet.getFrom());
+					/*
+					 * if (contact == null) { if ("subscribe".equals(type)) {
+					 * account.getXmppConnection().addPendingSubscription(
+					 * fromParts[0]); } else { // Log.d(LOGTAG,packet.getFrom()+
+					 * // " could not be found"); } return; }
+					 */
 					if (type == null) {
 						if (fromParts.length == 2) {
 							contact.updatePresence(fromParts[1], Presences
@@ -337,9 +335,6 @@ public class XmppConnectionService extends Service {
 													+ contact.getPgpKeyId());
 								}
 							}
-							replaceContactInConversation(account,
-									contact.getJid(), contact);
-							databaseBackend.updateContact(contact, true);
 						} else {
 							// Log.d(LOGTAG,"presence without resource "+packet.toString());
 						}
@@ -349,25 +344,16 @@ public class XmppConnectionService extends Service {
 						} else {
 							contact.removePresence(fromParts[1]);
 						}
-						replaceContactInConversation(account, contact.getJid(),
-								contact);
-						databaseBackend.updateContact(contact, true);
 					} else if (type.equals("subscribe")) {
 						Log.d(LOGTAG, "received subscribe packet from "
 								+ packet.getFrom());
-						if (contact
-								.getSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT)) {
+						if (contact.getOption(Contact.Options.PREEMPTIVE_GRANT)) {
 							Log.d(LOGTAG, "preemptive grant; granting");
 							sendPresenceUpdatesTo(contact);
-							contact.setSubscriptionOption(Contact.Subscription.FROM);
-							contact.resetSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT);
-							replaceContactInConversation(account,
-									contact.getJid(), contact);
-							databaseBackend.updateContact(contact, false);
-							if ((contact
-									.getSubscriptionOption(Contact.Subscription.ASKING))
-									&& (!contact
-											.getSubscriptionOption(Contact.Subscription.TO))) {
+							contact.setOption(Contact.Options.FROM);
+							contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
+							if ((contact.getOption(Contact.Options.ASKING))
+									&& (!contact.getOption(Contact.Options.TO))) {
 								requestPresenceUpdatesFrom(contact);
 							}
 						} else {
@@ -391,7 +377,6 @@ public class XmppConnectionService extends Service {
 				if ((from == null) || (from.equals(account.getJid()))) {
 					Element query = packet.findChild("query");
 					processRosterItems(account, query);
-					mergePhoneContactsWithRoster(null);
 				} else {
 					Log.d(LOGTAG, "unauthorized roster push from: " + from);
 				}
@@ -508,51 +493,25 @@ public class XmppConnectionService extends Service {
 	private void processRosterItems(Account account, Element elements) {
 		String version = elements.getAttribute("ver");
 		if (version != null) {
-			account.setRosterVersion(version);
-			databaseBackend.updateAccount(account);
+			account.getRoster().setVersion(version);
 		}
 		for (Element item : elements.getChildren()) {
 			if (item.getName().equals("item")) {
 				String jid = item.getAttribute("jid");
+				String name = item.getAttribute("name");
 				String subscription = item.getAttribute("subscription");
-				Contact contact = databaseBackend.findContact(account, jid);
-				if (contact == null) {
-					if (!subscription.equals("remove")) {
-						String name = item.getAttribute("name");
-						if (name == null) {
-							name = jid.split("@")[0];
-						}
-						contact = new Contact(account, name, jid, null);
-						contact.parseSubscriptionFromElement(item);
-						databaseBackend.createContact(contact);
-					}
+				Contact contact = account.getRoster().getContact(jid);
+				contact.setServerName(name);
+				if (subscription.equals("remove")) {
+					contact.resetOption(Contact.Options.IN_ROSTER);
 				} else {
-					if (subscription.equals("remove")) {
-						databaseBackend.deleteContact(contact);
-						replaceContactInConversation(account, contact.getJid(),
-								null);
-					} else {
-						contact.parseSubscriptionFromElement(item);
-						databaseBackend.updateContact(contact, false);
-						replaceContactInConversation(account, contact.getJid(),
-								contact);
-					}
+					contact.setOption(Contact.Options.IN_ROSTER);
+					contact.parseSubscriptionFromElement(item);
 				}
 			}
 		}
 	}
 
-	private void replaceContactInConversation(Account account, String jid,
-			Contact contact) {
-		List<Conversation> conversations = getConversations();
-		for (Conversation c : conversations) {
-			if (c.getContactJid().equals(jid) && (c.getAccount() == account)) {
-				c.setContact(contact);
-				break;
-			}
-		}
-	}
-
 	public class XmppConnectionBinder extends Binder {
 		public XmppConnectionService getService() {
 			return XmppConnectionService.this;
@@ -562,7 +521,9 @@ public class XmppConnectionService extends Service {
 	@Override
 	public int onStartCommand(Intent intent, int flags, int startId) {
 		this.wakeLock.acquire();
-		// Log.d(LOGTAG,"calling start service. caller was:"+intent.getAction());
+		if ((intent.getAction()!=null)&&(intent.getAction().equals(ACTION_MERGE_PHONE_CONTACTS))) {
+			mergePhoneContactsWithRoster();
+		}
 		ConnectivityManager cm = (ConnectivityManager) getApplicationContext()
 				.getSystemService(Context.CONNECTIVITY_SERVICE);
 		NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
@@ -636,6 +597,10 @@ public class XmppConnectionService extends Service {
 		this.fileBackend = new FileBackend(getApplicationContext());
 		this.accounts = databaseBackend.getAccounts();
 
+		for (Account account : this.accounts) {
+			this.databaseBackend.readRoster(account.getRoster());
+		}
+		this.mergePhoneContactsWithRoster();
 		this.getConversations();
 
 		getContentResolver().registerContentObserver(
@@ -654,6 +619,7 @@ public class XmppConnectionService extends Service {
 		Log.d(LOGTAG, "stopping service");
 		super.onDestroy();
 		for (Account account : accounts) {
+			databaseBackend.writeRoster(account.getRoster());
 			if (account.getXmppConnection() != null) {
 				disconnect(account, true);
 			}
@@ -725,10 +691,10 @@ public class XmppConnectionService extends Service {
 		connection.setOnBindListener(new OnBindListener() {
 
 			@Override
-			public void onBind(Account account) {
-				databaseBackend.clearPresences(account); //contact presences
+			public void onBind(final Account account) {
+				account.getRoster().clearPresences();
 				account.clearPresences(); // self presences
-				updateRoster(account, null);
+				fetchRosterFromServer(account);
 				sendPresence(account);
 				connectMultiModeConversations(account);
 				if (convChangedListener != null) {
@@ -887,27 +853,7 @@ public class XmppConnectionService extends Service {
 		return packet;
 	}
 
-	private void getRoster(Account account,
-			final OnRosterFetchedListener listener) {
-		List<Contact> contacts = databaseBackend.getContactsByAccount(account);
-		for (int i = 0; i < contacts.size(); ++i) {
-			contacts.get(i).setAccount(account);
-		}
-		if (listener != null) {
-			listener.onRosterFetched(contacts);
-		}
-	}
-
-	public List<Contact> getRoster(Account account) {
-		List<Contact> contacts = databaseBackend.getContactsByAccount(account);
-		for (int i = 0; i < contacts.size(); ++i) {
-			contacts.get(i).setAccount(account);
-		}
-		return contacts;
-	}
-
-	public void updateRoster(final Account account,
-			final OnRosterFetchedListener listener) {
+	public void fetchRosterFromServer(Account account) {
 		IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
 		if (!"".equals(account.getRosterVersion())) {
 			Log.d(LOGTAG, account.getJid() + ": fetching roster version "
@@ -925,62 +871,23 @@ public class XmppConnectionService extends Service {
 							IqPacket packet) {
 						Element roster = packet.findChild("query");
 						if (roster != null) {
-							Log.d(LOGTAG, account.getJid()
-									+ ": processing roster");
+							account.getRoster().markAllAsNotInRoster();
 							processRosterItems(account, roster);
-							StringBuilder mWhere = new StringBuilder();
-							mWhere.append("jid NOT IN(");
-							List<Element> items = roster.getChildren();
-							for (int i = 0; i < items.size(); ++i) {
-								mWhere.append(DatabaseUtils
-										.sqlEscapeString(items.get(i)
-												.getAttribute("jid")));
-								if (i != items.size() - 1) {
-									mWhere.append(",");
-								}
-							}
-							mWhere.append(") and accountUuid = \"");
-							mWhere.append(account.getUuid());
-							mWhere.append("\"");
-							List<Contact> contactsToDelete = databaseBackend
-									.getContacts(mWhere.toString());
-							for (Contact contact : contactsToDelete) {
-								databaseBackend.deleteContact(contact);
-								replaceContactInConversation(account,
-										contact.getJid(), null);
-							}
-
-						} else {
-							Log.d(LOGTAG, account.getJid()
-									+ ": empty roster returend");
 						}
-						mergePhoneContactsWithRoster(new OnPhoneContactsMerged() {
-
-							@Override
-							public void phoneContactsMerged() {
-								if (listener != null) {
-									getRoster(account, listener);
-								}
-							}
-						});
 					}
 				});
 	}
 
-	public void mergePhoneContactsWithRoster(
-			final OnPhoneContactsMerged listener) {
+	private void mergePhoneContactsWithRoster() {
 		PhoneHelper.loadPhoneContacts(getApplicationContext(),
 				new OnPhoneContactsLoadedListener() {
 					@Override
-					public void onPhoneContactsLoaded(
-							Hashtable<String, Bundle> phoneContacts) {
-						List<Contact> contacts = databaseBackend
-								.getContactsByAccount(null);
-						for (int i = 0; i < contacts.size(); ++i) {
-							Contact contact = contacts.get(i);
-							if (phoneContacts.containsKey(contact.getJid())) {
-								Bundle phoneContact = phoneContacts.get(contact
-										.getJid());
+					public void onPhoneContactsLoaded(List<Bundle> phoneContacts) {
+						for (Bundle phoneContact : phoneContacts) {
+							for (Account account : accounts) {
+								String jid = phoneContact.getString("jid");
+								Contact contact = account.getRoster()
+										.getContact(jid);
 								String systemAccount = phoneContact
 										.getInt("phoneid")
 										+ "#"
@@ -988,28 +895,10 @@ public class XmppConnectionService extends Service {
 								contact.setSystemAccount(systemAccount);
 								contact.setPhotoUri(phoneContact
 										.getString("photouri"));
-								contact.setDisplayName(phoneContact
+								contact.setSystemName(phoneContact
 										.getString("displayname"));
-								databaseBackend.updateContact(contact, false);
-								replaceContactInConversation(
-										contact.getAccount(), contact.getJid(),
-										contact);
-							} else {
-								if ((contact.getSystemAccount() != null)
-										|| (contact.getProfilePhoto() != null)) {
-									contact.setSystemAccount(null);
-									contact.setPhotoUri(null);
-									databaseBackend.updateContact(contact,
-											false);
-									replaceContactInConversation(
-											contact.getAccount(),
-											contact.getJid(), contact);
-								}
 							}
 						}
-						if (listener != null) {
-							listener.phoneContactsMerged();
-						}
 					}
 				});
 	}
@@ -1025,7 +914,6 @@ public class XmppConnectionService extends Service {
 			for (Conversation conv : this.conversations) {
 				Account account = accountLookupTable.get(conv.getAccountUuid());
 				conv.setAccount(account);
-				conv.setContact(findContact(account, conv.getContactJid()));
 				conv.setMessages(databaseBackend.getMessages(conv, 50));
 			}
 		}
@@ -1043,14 +931,6 @@ public class XmppConnectionService extends Service {
 		return this.accounts;
 	}
 
-	public Contact findContact(Account account, String jid) {
-		Contact contact = databaseBackend.findContact(account, jid);
-		if (contact != null) {
-			contact.setAccount(account);
-		}
-		return contact;
-	}
-
 	public Conversation findOrCreateConversation(Account account, String jid,
 			boolean muc) {
 		for (Conversation conv : this.getConversations()) {
@@ -1072,11 +952,9 @@ public class XmppConnectionService extends Service {
 			conversation.setMessages(databaseBackend.getMessages(conversation,
 					50));
 			this.databaseBackend.updateConversation(conversation);
-			conversation.setContact(findContact(account,
-					conversation.getContactJid()));
 		} else {
 			String conversationName;
-			Contact contact = findContact(account, jid);
+			Contact contact = account.getRoster().getContact(jid);
 			if (contact != null) {
 				conversationName = contact.getDisplayName();
 			} else {
@@ -1089,7 +967,6 @@ public class XmppConnectionService extends Service {
 				conversation = new Conversation(conversationName, account, jid,
 						Conversation.MODE_SINGLE);
 			}
-			conversation.setContact(contact);
 			this.databaseBackend.createConversation(conversation);
 		}
 		this.conversations.add(conversation);
@@ -1137,17 +1014,6 @@ public class XmppConnectionService extends Service {
 			accountChangedListener.onAccountListChangedListener();
 	}
 
-	public void deleteContact(Contact contact) {
-		IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
-		Element query = iq.query("jabber:iq:roster");
-		query.addChild("item").setAttribute("jid", contact.getJid())
-				.setAttribute("subscription", "remove");
-		contact.getAccount().getXmppConnection().sendIqPacket(iq, null);
-		replaceContactInConversation(contact.getAccount(), contact.getJid(),
-				null);
-		databaseBackend.deleteContact(contact);
-	}
-
 	public void updateAccount(Account account) {
 		this.statusListener.onStatusChanged(account);
 		databaseBackend.updateAccount(account);
@@ -1308,12 +1174,6 @@ public class XmppConnectionService extends Service {
 		return mBinder;
 	}
 
-	public void updateContact(Contact contact) {
-		databaseBackend.updateContact(contact, false);
-		replaceContactInConversation(contact.getAccount(), contact.getJid(),
-				contact);
-	}
-
 	public void updateMessage(Message message) {
 		databaseBackend.updateMessage(message);
 	}
@@ -1322,30 +1182,34 @@ public class XmppConnectionService extends Service {
 		SharedPreferences sharedPref = getPreferences();
 		boolean autoGrant = sharedPref.getBoolean("grant_new_contacts", true);
 		if (autoGrant) {
-			contact.setSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT);
-			contact.setSubscriptionOption(Contact.Subscription.ASKING);
+			contact.setOption(Contact.Options.PREEMPTIVE_GRANT);
+			contact.setOption(Contact.Options.ASKING);
 		}
-		databaseBackend.createContact(contact);
-		IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
-		Element query = new Element("query");
-		query.setAttribute("xmlns", "jabber:iq:roster");
-		Element item = new Element("item");
-		item.setAttribute("jid", contact.getJid());
-		item.setAttribute("name", contact.getJid());
-		query.addChild(item);
-		iq.addChild(query);
-		Account account = contact.getAccount();
-		account.getXmppConnection().sendIqPacket(iq, null);
+		pushContactToServer(contact);
 		if (autoGrant) {
 			requestPresenceUpdatesFrom(contact);
-			if (account.getXmppConnection().hasPendingSubscription(
+			if (contact.getAccount().getXmppConnection().hasPendingSubscription(
 					contact.getJid())) {
 				Log.d("xmppService", "contact had pending subscription");
 				sendPresenceUpdatesTo(contact);
 			}
 		}
-		replaceContactInConversation(contact.getAccount(), contact.getJid(),
-				contact);
+	}
+	
+	public void pushContactToServer(Contact contact) {
+		IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
+		iq.query("jabber:iq:roster").addChild(contact.asElement());
+		Account account = contact.getAccount();
+		account.getXmppConnection().sendIqPacket(iq, null);
+	}
+	
+	public void deleteContactOnServer(Contact contact) {
+		IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
+		Element item = iq.query("jabber:iq:roster").addChild("item");
+		item.setAttribute("jid", contact.getJid());
+		item.setAttribute("subscription", "remove");
+		Account account = contact.getAccount();
+		account.getXmppConnection().sendIqPacket(iq, null);
 	}
 
 	public void requestPresenceUpdatesFrom(Contact contact) {
@@ -1392,11 +1256,10 @@ public class XmppConnectionService extends Service {
 		PresencePacket packet = new PresencePacket();
 		packet.setAttribute("from", account.getFullJid());
 		String sig = account.getPgpSignature();
-		if (sig!=null) {
+		if (sig != null) {
 			packet.addChild("status").setContent("online");
-			packet.addChild("x","jabber:x:signed").setContent(sig);
+			packet.addChild("x", "jabber:x:signed").setContent(sig);
 		}
-		Log.d(LOGTAG,packet.toString());
 		account.getXmppConnection().sendPresencePacket(packet);
 	}
 
@@ -1404,18 +1267,6 @@ public class XmppConnectionService extends Service {
 		this.databaseBackend.updateConversation(conversation);
 	}
 
-	public Contact findContact(String uuid) {
-		Contact contact = this.databaseBackend.getContact(uuid);
-		if (contact != null) {
-			for (Account account : getAccounts()) {
-				if (contact.getAccountUuid().equals(account.getUuid())) {
-					contact.setAccount(account);
-				}
-			}
-		}
-		return contact;
-	}
-
 	public void removeOnTLSExceptionReceivedListener() {
 		this.tlsException = null;
 	}
@@ -1517,4 +1368,13 @@ public class XmppConnectionService extends Service {
 					getConversations(), conversation, notify);
 		}
 	}
+	
+	public Account findAccountByJid(String accountJid) {
+		for (Account account : this.accounts) {
+			if (account.getJid().equals(accountJid)) {
+				return account;
+			}
+		}
+		return null;
+	}
 }

src/eu/siacs/conversations/ui/ContactDetailsActivity.java 🔗

@@ -1,8 +1,6 @@
 package eu.siacs.conversations.ui;
 
-import java.math.BigInteger;
 import java.util.Iterator;
-import java.util.Locale;
 
 import org.openintents.openpgp.util.OpenPgpUtils;
 
@@ -17,7 +15,6 @@ import android.os.Bundle;
 import android.provider.ContactsContract.CommonDataKinds;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Intents;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -31,6 +28,7 @@ import android.widget.TextView;
 import android.widget.Toast;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.crypto.PgpEngine;
+import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Presences;
 import eu.siacs.conversations.utils.UIHelper;
@@ -40,12 +38,14 @@ public class ContactDetailsActivity extends XmppActivity {
 
 	protected ContactDetailsActivity activity = this;
 
-	private String uuid;
 	private Contact contact;
-
+	
+	private String accountJid;
+	private String contactJid;
+	
 	private EditText name;
-	private TextView contactJid;
-	private TextView accountJid;
+	private TextView contactJidTv;
+	private TextView accountJidTv;
 	private TextView status;
 	private TextView askAgain;
 	private CheckBox send;
@@ -56,7 +56,7 @@ public class ContactDetailsActivity extends XmppActivity {
 
 		@Override
 		public void onClick(DialogInterface dialog, int which) {
-			activity.xmppConnectionService.deleteContact(contact);
+			activity.xmppConnectionService.deleteContactOnServer(contact);
 			activity.finish();
 		}
 	};
@@ -65,8 +65,8 @@ public class ContactDetailsActivity extends XmppActivity {
 
 		@Override
 		public void onClick(DialogInterface dialog, int which) {
-			contact.setDisplayName(name.getText().toString());
-			activity.xmppConnectionService.updateContact(contact);
+			contact.setServerName(name.getText().toString());
+			activity.xmppConnectionService.pushContactToServer(contact);
 			populateView();
 		}
 	};
@@ -104,12 +104,13 @@ public class ContactDetailsActivity extends XmppActivity {
 	protected void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 		if (getIntent().getAction().equals(ACTION_VIEW_CONTACT)) {
-			this.uuid = getIntent().getExtras().getString("uuid");
+			this.accountJid = getIntent().getExtras().getString("account");
+			this.contactJid = getIntent().getExtras().getString("contact");
 		}
 		setContentView(R.layout.activity_contact_details);
 
-		contactJid = (TextView) findViewById(R.id.details_contactjid);
-		accountJid = (TextView) findViewById(R.id.details_account);
+		contactJidTv = (TextView) findViewById(R.id.details_contactjid);
+		accountJidTv = (TextView) findViewById(R.id.details_account);
 		status = (TextView) findViewById(R.id.details_contactstatus);
 		send = (CheckBox) findViewById(R.id.details_send_presence);
 		receive = (CheckBox) findViewById(R.id.details_receive_presence);
@@ -170,18 +171,18 @@ public class ContactDetailsActivity extends XmppActivity {
 
 	private void populateView() {
 		setTitle(contact.getDisplayName());
-		if (contact.getSubscriptionOption(Contact.Subscription.FROM)) {
+		if (contact.getOption(Contact.Options.FROM)) {
 			send.setChecked(true);
 		} else {
 			send.setText(R.string.preemptively_grant);
 			if (contact
-					.getSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT)) {
+					.getOption(Contact.Options.PREEMPTIVE_GRANT)) {
 				send.setChecked(true);
 			} else {
 				send.setChecked(false);
 			}
 		}
-		if (contact.getSubscriptionOption(Contact.Subscription.TO)) {
+		if (contact.getOption(Contact.Options.TO)) {
 			receive.setChecked(true);
 		} else {
 			receive.setText(R.string.ask_for_presence_updates);
@@ -195,7 +196,7 @@ public class ContactDetailsActivity extends XmppActivity {
 					
 				}
 			});
-			if (contact.getSubscriptionOption(Contact.Subscription.ASKING)) {
+			if (contact.getOption(Contact.Options.ASKING)) {
 				receive.setChecked(true);
 			} else {
 				receive.setChecked(false);
@@ -233,11 +234,11 @@ public class ContactDetailsActivity extends XmppActivity {
 			break;
 		}
 		if (contact.getPresences().size() > 1) {
-			contactJid.setText(contact.getJid()+" ("+contact.getPresences().size()+")");
+			contactJidTv.setText(contact.getJid()+" ("+contact.getPresences().size()+")");
 		} else {
-			contactJid.setText(contact.getJid());
+			contactJidTv.setText(contact.getJid());
 		}
-		accountJid.setText(contact.getAccount().getJid());
+		accountJidTv.setText(contact.getAccount().getJid());
 
 		UIHelper.prepareContactBadge(this, badge, contact, getApplicationContext());
 
@@ -286,65 +287,66 @@ public class ContactDetailsActivity extends XmppActivity {
 
 	@Override
 	public void onBackendConnected() {
-		if (uuid != null) {
-			this.contact = xmppConnectionService.findContact(uuid);
-			if (this.contact != null) {
-				populateView();
+		if ((accountJid != null)&&(contactJid != null)) {
+			Account account = xmppConnectionService.findAccountByJid(accountJid);
+			if (account==null) {
+				return;
 			}
+			this.contact = account.getRoster().getContact(contactJid);
+			populateView();
 		}
 	}
 
 	@Override
 	protected void onStop() {
 		super.onStop();
-		boolean needsUpdating = false;
-		if (contact.getSubscriptionOption(Contact.Subscription.FROM)) {
+		boolean updated = false;
+		if (contact.getOption(Contact.Options.FROM)) {
 			if (!send.isChecked()) {
-				contact.resetSubscriptionOption(Contact.Subscription.FROM);
-				contact.resetSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT);
+				contact.resetOption(Contact.Options.FROM);
+				contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
 				activity.xmppConnectionService.stopPresenceUpdatesTo(contact);
-				needsUpdating = true;
+				updated = true;
 			}
 		} else {
 			if (contact
-					.getSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT)) {
+					.getOption(Contact.Options.PREEMPTIVE_GRANT)) {
 				if (!send.isChecked()) {
-					contact.resetSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT);
-					needsUpdating = true;
+					contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
+					updated = true;
 				}
 			} else {
 				if (send.isChecked()) {
-					contact.setSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT);
-					needsUpdating = true;
+					contact.setOption(Contact.Options.PREEMPTIVE_GRANT);
+					updated = true;
 				}
 			}
 		}
-		if (contact.getSubscriptionOption(Contact.Subscription.TO)) {
+		if (contact.getOption(Contact.Options.TO)) {
 			if (!receive.isChecked()) {
-				contact.resetSubscriptionOption(Contact.Subscription.TO);
+				contact.resetOption(Contact.Options.TO);
 				activity.xmppConnectionService.stopPresenceUpdatesFrom(contact);
-				needsUpdating = true;
+				updated = true;
 			}
 		} else {
-			if (contact.getSubscriptionOption(Contact.Subscription.ASKING)) {
+			if (contact.getOption(Contact.Options.ASKING)) {
 				if (!receive.isChecked()) {
-					contact.resetSubscriptionOption(Contact.Subscription.ASKING);
+					contact.resetOption(Contact.Options.ASKING);
 					activity.xmppConnectionService
 							.stopPresenceUpdatesFrom(contact);
-					needsUpdating = true;
+					updated = true;
 				}
 			} else {
 				if (receive.isChecked()) {
-					contact.setSubscriptionOption(Contact.Subscription.ASKING);
+					contact.setOption(Contact.Options.ASKING);
 					activity.xmppConnectionService
 							.requestPresenceUpdatesFrom(contact);
-					needsUpdating = true;
+					updated = true;
 				}
 			}
 		}
-		if (needsUpdating) {
+		if (updated) {
 			Toast.makeText(getApplicationContext(), "Subscription updated", Toast.LENGTH_SHORT).show();
-			activity.xmppConnectionService.updateContact(contact);
 		}
 	}
 

src/eu/siacs/conversations/ui/ContactsActivity.java 🔗

@@ -18,7 +18,6 @@ import android.os.Bundle;
 import android.preference.PreferenceManager;
 import android.text.Editable;
 import android.text.TextWatcher;
-import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.view.ActionMode;
 import android.view.LayoutInflater;
@@ -34,13 +33,11 @@ import android.widget.AdapterView.OnItemLongClickListener;
 import android.widget.ArrayAdapter;
 import android.widget.EditText;
 import android.widget.ListView;
-import android.widget.ProgressBar;
 import android.widget.TextView;
 import android.widget.ImageView;
 import android.widget.Toast;
 import android.annotation.SuppressLint;
 import android.app.AlertDialog;
-import android.app.AlertDialog.Builder;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.SharedPreferences;
@@ -130,8 +127,10 @@ public class ContactsActivity extends XmppActivity {
 				Intent intent = new Intent(getApplicationContext(),
 						ContactDetailsActivity.class);
 				intent.setAction(ContactDetailsActivity.ACTION_VIEW_CONTACT);
-				intent.putExtra("uuid", selectedContacts.get(0).getUuid());
+				intent.putExtra("account", selectedContacts.get(0).getAccount().getJid());
+				intent.putExtra("contact",selectedContacts.get(0).getJid());
 				startActivity(intent);
+				finish();
 				break;
 			case R.id.action_invite:
 				invite();
@@ -270,7 +269,7 @@ public class ContactsActivity extends XmppActivity {
 
 		aggregatedContacts.clear();
 		for (Contact contact : rosterContacts) {
-			if (contact.match(searchString))
+			if (contact.match(searchString)&&(contact.getOption(Contact.Options.IN_ROSTER)))
 				aggregatedContacts.add(contact);
 		}
 
@@ -287,9 +286,8 @@ public class ContactsActivity extends XmppActivity {
 		if (aggregatedContacts.size() == 0) {
 
 			if (Validator.isValidJid(searchString)) {
-				String name = searchString.split("@")[0];
-				Contact newContact = new Contact(null, name, searchString, null);
-				newContact.flagAsNotInRoster();
+				Contact newContact = new Contact(searchString);
+				newContact.resetOption(Contact.Options.IN_ROSTER);
 				aggregatedContacts.add(newContact);
 				contactsHeader.setText("Create new contact");
 			} else {
@@ -463,7 +461,7 @@ public class ContactsActivity extends XmppActivity {
 	}
 
 	public void startConversation(Contact contact, Account account, boolean muc) {
-		if (!contact.isInRoster()&&(!muc)) {
+		if (!contact.getOption(Contact.Options.IN_ROSTER)&&(!muc)) {
 			xmppConnectionService.createContact(contact);
 		}
 		Conversation conversation = xmppConnectionService
@@ -517,7 +515,7 @@ public class ContactsActivity extends XmppActivity {
 		this.rosterContacts.clear();
 		for(Account account : accounts) {
 			if (account.getStatus() != Account.STATUS_DISABLED) {
-				rosterContacts.addAll(xmppConnectionService.getRoster(account));
+				rosterContacts.addAll(account.getRoster().getContacts());
 			}
 		}
 		updateAggregatedContacts();
@@ -533,52 +531,12 @@ public class ContactsActivity extends XmppActivity {
 	@Override
 	public boolean onOptionsItemSelected(MenuItem item) {
 		switch (item.getItemId()) {
-		case R.id.action_refresh_contacts:
-			refreshContacts();
-			break;
 		default:
 			break;
 		}
 		return super.onOptionsItemSelected(item);
 	}
 
-	private void refreshContacts() {
-		final ProgressBar progress = (ProgressBar) findViewById(R.id.progressBar1);
-		final EditText searchBar = (EditText) findViewById(R.id.new_conversation_search);
-		final TextView contactsHeader = (TextView) findViewById(R.id.contacts_header);
-		final ListView contactList = (ListView) findViewById(R.id.contactList);
-		searchBar.setVisibility(View.GONE);
-		contactsHeader.setVisibility(View.GONE);
-		contactList.setVisibility(View.GONE);
-		progress.setVisibility(View.VISIBLE);
-		this.accounts = xmppConnectionService.getAccounts();
-		this.rosterContacts.clear();
-		for (int i = 0; i < accounts.size(); ++i) {
-			if (accounts.get(i).getStatus() == Account.STATUS_ONLINE) {
-				xmppConnectionService.updateRoster(accounts.get(i),
-						new OnRosterFetchedListener() {
-
-							@Override
-							public void onRosterFetched(
-									final List<Contact> roster) {
-								runOnUiThread(new Runnable() {
-
-									@Override
-									public void run() {
-										rosterContacts.addAll(roster);
-										progress.setVisibility(View.GONE);
-										searchBar.setVisibility(View.VISIBLE);
-										contactList.setVisibility(View.VISIBLE);
-										contactList.setVisibility(View.VISIBLE);
-										updateAggregatedContacts();
-									}
-								});
-							}
-						});
-			}
-		}
-	}
-
 	@Override
 	public void onActionModeStarted(ActionMode mode) {
 		super.onActionModeStarted(mode);

src/eu/siacs/conversations/ui/ConversationActivity.java 🔗

@@ -474,10 +474,11 @@ public class ConversationActivity extends XmppActivity {
 			break;
 		case R.id.action_contact_details:
 			Contact contact = this.getSelectedConversation().getContact();
-			if (contact != null) {
+			if (contact.getOption(Contact.Options.IN_ROSTER)) {
 				Intent intent = new Intent(this, ContactDetailsActivity.class);
 				intent.setAction(ContactDetailsActivity.ACTION_VIEW_CONTACT);
-				intent.putExtra("uuid", contact.getUuid());
+				intent.putExtra("account", this.getSelectedConversation().getAccount().getJid());
+				intent.putExtra("contact",contact.getJid());
 				startActivity(intent);
 			} else {
 				showAddToRosterDialog(getSelectedConversation());
@@ -874,8 +875,7 @@ public class ConversationActivity extends XmppActivity {
 			public void onClick(DialogInterface dialog, int which) {
 				String jid = conversation.getContactJid();
 				Account account = getSelectedConversation().getAccount();
-				String name = jid.split("@")[0];
-				Contact contact = new Contact(account, name, jid, null);
+				Contact contact = account.getRoster().getContact(jid);
 				xmppConnectionService.createContact(contact);
 			}
 		});

src/eu/siacs/conversations/ui/ConversationFragment.java 🔗

@@ -263,7 +263,7 @@ public class ConversationFragment extends Fragment {
 			}
 
 			private void displayInfoMessage(ViewHolder viewHolder, int r) {
-				if (viewHolder.download_button!=null) {
+				if (viewHolder.download_button != null) {
 					viewHolder.download_button.setVisibility(View.GONE);
 				}
 				viewHolder.image.setVisibility(View.GONE);
@@ -329,7 +329,8 @@ public class ConversationFragment extends Fragment {
 					@Override
 					public void onClick(View v) {
 						Intent intent = new Intent(Intent.ACTION_VIEW);
-						intent.setDataAndType(ImageProvider.getContentUri(message), "image/*");
+						intent.setDataAndType(
+								ImageProvider.getContentUri(message), "image/*");
 						startActivity(intent);
 					}
 				});
@@ -486,7 +487,7 @@ public class ConversationFragment extends Fragment {
 	@Override
 	public void onStop() {
 		super.onStop();
-		if (this.conversation!=null) {
+		if (this.conversation != null) {
 			this.conversation.setNextMessage(chatMsg.getText().toString());
 		}
 	}
@@ -577,13 +578,15 @@ public class ConversationFragment extends Fragment {
 	}
 
 	public void updateMessages() {
-		if (getView()==null) {
+		if (getView() == null) {
 			return;
 		}
 		ConversationActivity activity = (ConversationActivity) getActivity();
 		if (this.conversation != null) {
 			for (Message message : this.conversation.getMessages()) {
-				if ((message.getEncryption() == Message.ENCRYPTION_PGP)&&((message.getStatus() == Message.STATUS_RECIEVED)||(message.getStatus() == Message.STATUS_SEND))) {
+				if ((message.getEncryption() == Message.ENCRYPTION_PGP)
+						&& ((message.getStatus() == Message.STATUS_RECIEVED) || (message
+								.getStatus() == Message.STATUS_SEND))) {
 					decryptMessage(message);
 					break;
 				}
@@ -623,31 +626,26 @@ public class ConversationFragment extends Fragment {
 	protected void makeFingerprintWarning(int latestEncryption) {
 		final LinearLayout fingerprintWarning = (LinearLayout) getView()
 				.findViewById(R.id.new_fingerprint);
-		if (conversation.getContact() != null) {
-			Set<String> knownFingerprints = conversation.getContact()
-					.getOtrFingerprints();
-			if ((latestEncryption == Message.ENCRYPTION_OTR)
-					&& (conversation.hasValidOtrSession()
-							&& (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
-								.contains(conversation.getOtrFingerprint())))) {
-				fingerprintWarning.setVisibility(View.VISIBLE);
-				TextView fingerprint = (TextView) getView().findViewById(
-						R.id.otr_fingerprint);
-				fingerprint.setText(conversation.getOtrFingerprint());
-				fingerprintWarning.setOnClickListener(new OnClickListener() {
+		Set<String> knownFingerprints = conversation.getContact()
+				.getOtrFingerprints();
+		if ((latestEncryption == Message.ENCRYPTION_OTR)
+				&& (conversation.hasValidOtrSession()
+						&& (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
+							.contains(conversation.getOtrFingerprint())))) {
+			fingerprintWarning.setVisibility(View.VISIBLE);
+			TextView fingerprint = (TextView) getView().findViewById(
+					R.id.otr_fingerprint);
+			fingerprint.setText(conversation.getOtrFingerprint());
+			fingerprintWarning.setOnClickListener(new OnClickListener() {
 
-					@Override
-					public void onClick(View v) {
-						AlertDialog dialog = UIHelper
-								.getVerifyFingerprintDialog(
-										(ConversationActivity) getActivity(),
-										conversation, fingerprintWarning);
-						dialog.show();
-					}
-				});
-			} else {
-				fingerprintWarning.setVisibility(View.GONE);
-			}
+				@Override
+				public void onClick(View v) {
+					AlertDialog dialog = UIHelper.getVerifyFingerprintDialog(
+							(ConversationActivity) getActivity(), conversation,
+							fingerprintWarning);
+					dialog.show();
+				}
+			});
 		} else {
 			fingerprintWarning.setVisibility(View.GONE);
 		}
@@ -666,35 +664,31 @@ public class ConversationFragment extends Fragment {
 		final Contact contact = message.getConversation().getContact();
 		if (activity.hasPgp()) {
 			if (contact.getPgpKeyId() != 0) {
-				xmppService.getPgpEngine().hasKey(contact,
-						new UiCallback() {
-
-							@Override
-							public void userInputRequried(PendingIntent pi) {
-								activity.runIntent(
-										pi,
-										ConversationActivity.REQUEST_ENCRYPT_MESSAGE);
-							}
+				xmppService.getPgpEngine().hasKey(contact, new UiCallback() {
 
-							@Override
-							public void success() {
-								activity.encryptTextMessage();
-							}
+					@Override
+					public void userInputRequried(PendingIntent pi) {
+						activity.runIntent(pi,
+								ConversationActivity.REQUEST_ENCRYPT_MESSAGE);
+					}
 
-							@Override
-							public void error(int error) {
-								
-							}
-						});
+					@Override
+					public void success() {
+						activity.encryptTextMessage();
+					}
+
+					@Override
+					public void error(int error) {
+
+					}
+				});
 
 			} else {
 				showNoPGPKeyDialog(new DialogInterface.OnClickListener() {
 
 					@Override
-					public void onClick(DialogInterface dialog,
-							int which) {
-						conversation
-								.setNextEncryption(Message.ENCRYPTION_NONE);
+					public void onClick(DialogInterface dialog, int which) {
+						conversation.setNextEncryption(Message.ENCRYPTION_NONE);
 						message.setEncryption(Message.ENCRYPTION_NONE);
 						xmppService.sendMessage(message, null);
 						chatMsg.setText("");
@@ -703,15 +697,15 @@ public class ConversationFragment extends Fragment {
 			}
 		}
 	}
-	
+
 	public void showNoPGPKeyDialog(DialogInterface.OnClickListener listener) {
-		AlertDialog.Builder builder = new AlertDialog.Builder(
-				getActivity());
+		AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
 		builder.setTitle(getString(R.string.no_pgp_key));
 		builder.setIconAttribute(android.R.attr.alertDialogIcon);
 		builder.setMessage(getText(R.string.contact_has_no_pgp_key));
 		builder.setNegativeButton(getString(R.string.cancel), null);
-		builder.setPositiveButton(getString(R.string.send_unencrypted),listener);
+		builder.setPositiveButton(getString(R.string.send_unencrypted),
+				listener);
 		builder.create().show();
 	}
 

src/eu/siacs/conversations/ui/ShareWithActivity.java 🔗

@@ -17,7 +17,6 @@ import android.content.SharedPreferences;
 import android.graphics.Bitmap;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
-import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.ImageView;
@@ -29,15 +28,6 @@ public class ShareWithActivity extends XmppActivity {
 	private LinearLayout conversations;
 	private LinearLayout contacts;
 	
-	private OnClickListener click = new OnClickListener() {
-		
-		@Override
-		public void onClick(View v) {
-			// TODO Auto-generated method stub
-			
-		}
-	};
-	
 	@Override
 	protected void onCreate(Bundle savedInstanceState) {
 
@@ -71,7 +61,7 @@ public class ShareWithActivity extends XmppActivity {
 		SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
 		boolean useSubject = preferences.getBoolean("use_subject_in_muc", true);
 		
-		Set<String> displayedContacts = new HashSet<String>();
+		Set<Contact> displayedContacts = new HashSet<Contact>();
 		conversations.removeAllViews();
 		List<Conversation> convList = xmppConnectionService.getConversations();
 		Collections.sort(convList, new Comparator<Conversation>() {
@@ -95,15 +85,13 @@ public class ShareWithActivity extends XmppActivity {
 				}
 			});
 			conversations.addView(view);
-			if (conversation.getContact() != null) {
-				displayedContacts.add(conversation.getContact().getUuid());
-			}
+			displayedContacts.add(conversation.getContact());
 		}
 		contacts.removeAllViews();
-		final List<Contact> contactsList = new ArrayList<Contact>();
+		List<Contact> contactsList = new ArrayList<Contact>();
 		for(Account account : xmppConnectionService.getAccounts()) {
-			for(final Contact contact : xmppConnectionService.getRoster(account)) {
-				if (!displayedContacts.contains(contact.getUuid())) {
+			for(Contact contact : account.getRoster().getContacts()) {
+				if (!displayedContacts.contains(contact)&&(contact.getOption(Contact.Options.IN_ROSTER))) {
 					contactsList.add(contact);
 				}
 			}

src/eu/siacs/conversations/utils/OnPhoneContactsLoadedListener.java 🔗

@@ -1,9 +1,9 @@
 package eu.siacs.conversations.utils;
 
-import java.util.Hashtable;
+import java.util.List;
 
 import android.os.Bundle;
 
 public interface OnPhoneContactsLoadedListener {
-	public void onPhoneContactsLoaded(Hashtable<String, Bundle> phoneContacts);
+	public void onPhoneContactsLoaded(List<Bundle> phoneContacts);
 }

src/eu/siacs/conversations/utils/PhoneHelper.java 🔗

@@ -1,8 +1,8 @@
 package eu.siacs.conversations.utils;
 
-import java.util.Hashtable;
+import java.util.ArrayList;
+import java.util.List;
 
-import android.app.Activity;
 import android.content.Context;
 import android.content.CursorLoader;
 import android.content.Loader;
@@ -10,21 +10,15 @@ import android.content.Loader.OnLoadCompleteListener;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.Looper;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Profile;
-import android.provider.MediaStore;
 
 public class PhoneHelper {
 
 	public static void loadPhoneContacts(Context context,
 			final OnPhoneContactsLoadedListener listener) {
-		if (Looper.myLooper() == null) {
-			Looper.prepare();
-		}
-		final Looper mLooper = Looper.myLooper();
-		final Hashtable<String, Bundle> phoneContacts = new Hashtable<String, Bundle>();
-
+		final List<Bundle> phoneContacts = new ArrayList<Bundle>();
+		
 		final String[] PROJECTION = new String[] { ContactsContract.Data._ID,
 				ContactsContract.Data.DISPLAY_NAME,
 				ContactsContract.Data.PHOTO_THUMBNAIL_URI,
@@ -58,15 +52,14 @@ public class PhoneHelper {
 									.getColumnIndex(ContactsContract.Data.PHOTO_THUMBNAIL_URI)));
 					contact.putString("lookup", cursor.getString(cursor
 							.getColumnIndex(ContactsContract.Data.LOOKUP_KEY)));
-					phoneContacts.put(
-							cursor.getString(cursor
-									.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)),
-							contact);
+					
+					contact.putString("jid",cursor.getString(cursor
+									.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)));
+					phoneContacts.add(contact);
 				}
 				if (listener != null) {
 					listener.onPhoneContactsLoaded(phoneContacts);
 				}
-				mLooper.quit();
 			}
 		});
 		mCursorLoader.startLoading();

src/eu/siacs/conversations/utils/UIHelper.java 🔗

@@ -247,13 +247,8 @@ public class UIHelper {
 
 	public static Bitmap getContactPicture(Conversation conversation, int dpSize, Context context, boolean notification) {
 		if(conversation.getMode() == Conversation.MODE_SINGLE) {
-			if (conversation.getContact() != null){
 				return getContactPicture(conversation.getContact(), dpSize,
 						context, notification);
-			} else {
-				return getContactPicture(conversation.getName(false), dpSize,
-						context, notification);
-			}
 		} else{
 			int fgColor = UIHelper.FG_COLOR,
 				bgColor = (notification) ?
@@ -506,7 +501,7 @@ public class UIHelper {
 			public void onClick(DialogInterface dialog, int which) {
 				contact.addOtrFingerprint(conversation.getOtrFingerprint());
 				msg.setVisibility(View.GONE);
-				activity.xmppConnectionService.updateContact(contact);
+				//activity.xmppConnectionService.updateContact(contact);
 			}
 		});
 		builder.setView(view);