basic muc support. reworked contact list stuff

This commit is contained in:
Daniel Gultsch 2014-02-05 22:33:39 +01:00
parent 4670585e7a
commit aa42eb544a
12 changed files with 395 additions and 175 deletions

View File

@ -25,9 +25,14 @@
android:windowSoftInputMode="stateHidden"> android:windowSoftInputMode="stateHidden">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="android.intent.action.SENDTO" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="imto" />
<data android:host="jabber" />
</intent-filter>
</activity> </activity>
<activity <activity
android:name="de.gultsch.chat.ui.SettingsActivity" android:name="de.gultsch.chat.ui.SettingsActivity"

View File

@ -29,6 +29,9 @@ public class Contact extends AbstractEntity implements Serializable {
protected String openPGPKey; protected String openPGPKey;
protected long lastOnlinePresence; protected long lastOnlinePresence;
protected Account account;
public Contact(Account account, String displayName, String jid, String photoUri) { public Contact(Account account, String displayName, String jid, String photoUri) {
if (account == null) { if (account == null) {
this.accountUuid = null; this.accountUuid = null;
@ -95,4 +98,25 @@ public class Contact extends AbstractEntity implements Serializable {
cursor.getLong(cursor.getColumnIndex(LASTONLINEPRESENCE)) cursor.getLong(cursor.getColumnIndex(LASTONLINEPRESENCE))
); );
} }
public void setSubscription(String subscription) {
this.subscription = subscription;
}
public void setSystemAccount(int account) {
this.systemAccount = account;
}
public void setAccount(Account account) {
this.account = account;
this.accountUuid = account.getUuid();
}
public Account getAccount() {
return this.account;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
} }

View File

@ -17,12 +17,16 @@ public class Conversation extends AbstractEntity {
public static final int STATUS_ARCHIVED = 1; public static final int STATUS_ARCHIVED = 1;
public static final int STATUS_DELETED = 2; public static final int STATUS_DELETED = 2;
public static final int MODE_MULTI = 1;
public static final int MODE_SINGLE = 0;
public static final String NAME = "name"; public static final String NAME = "name";
public static final String PHOTO_URI = "profilePhotoUri"; public static final String PHOTO_URI = "profilePhotoUri";
public static final String ACCOUNT = "accountUuid"; public static final String ACCOUNT = "accountUuid";
public static final String CONTACT = "contactJid"; public static final String CONTACT = "contactJid";
public static final String STATUS = "status"; public static final String STATUS = "status";
public static final String CREATED = "created"; public static final String CREATED = "created";
public static final String MODE = "mode";
private String name; private String name;
private String profilePhotoUri; private String profilePhotoUri;
@ -30,19 +34,20 @@ public class Conversation extends AbstractEntity {
private String contactJid; private String contactJid;
private int status; private int status;
private long created; private long created;
private int mode;
private transient List<Message> messages = null; private transient List<Message> messages = null;
private transient Account account = null; private transient Account account = null;
public Conversation(String name, String profilePhoto, Account account, public Conversation(String name, String profilePhoto, Account account,
String contactJid) { String contactJid, int mode) {
this(java.util.UUID.randomUUID().toString(), name, profilePhoto, account.getUuid(), contactJid, System this(java.util.UUID.randomUUID().toString(), name, profilePhoto, account.getUuid(), contactJid, System
.currentTimeMillis(), STATUS_AVAILABLE); .currentTimeMillis(), STATUS_AVAILABLE,mode);
this.account = account; this.account = account;
} }
public Conversation(String uuid, String name, String profilePhoto, public Conversation(String uuid, String name, String profilePhoto,
String accountUuid, String contactJid, long created, int status) { String accountUuid, String contactJid, long created, int status, int mode) {
this.uuid = uuid; this.uuid = uuid;
this.name = name; this.name = name;
this.profilePhotoUri = profilePhoto; this.profilePhotoUri = profilePhoto;
@ -50,6 +55,7 @@ public class Conversation extends AbstractEntity {
this.contactJid = contactJid; this.contactJid = contactJid;
this.created = created; this.created = created;
this.status = status; this.status = status;
this.mode = mode;
} }
public List<Message> getMessages() { public List<Message> getMessages() {
@ -132,6 +138,7 @@ public class Conversation extends AbstractEntity {
values.put(CONTACT, contactJid); values.put(CONTACT, contactJid);
values.put(CREATED, created); values.put(CREATED, created);
values.put(STATUS, status); values.put(STATUS, status);
values.put(MODE,mode);
return values; return values;
} }
@ -142,10 +149,15 @@ public class Conversation extends AbstractEntity {
cursor.getString(cursor.getColumnIndex(ACCOUNT)), cursor.getString(cursor.getColumnIndex(ACCOUNT)),
cursor.getString(cursor.getColumnIndex(CONTACT)), cursor.getString(cursor.getColumnIndex(CONTACT)),
cursor.getLong(cursor.getColumnIndex(CREATED)), cursor.getLong(cursor.getColumnIndex(CREATED)),
cursor.getInt(cursor.getColumnIndex(STATUS))); cursor.getInt(cursor.getColumnIndex(STATUS)),
cursor.getInt(cursor.getColumnIndex(MODE)));
} }
public void setStatus(int status) { public void setStatus(int status) {
this.status = status; this.status = status;
} }
public int getMode() {
return this.mode;
}
} }

View File

@ -2,6 +2,7 @@ package de.gultsch.chat.persistance;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import de.gultsch.chat.entities.Account; import de.gultsch.chat.entities.Account;
import de.gultsch.chat.entities.Contact; import de.gultsch.chat.entities.Contact;
@ -37,9 +38,10 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ " TEXT, " + Conversation.PHOTO_URI + " TEXT, " + " TEXT, " + Conversation.PHOTO_URI + " TEXT, "
+ Conversation.ACCOUNT + " TEXT, " + Conversation.CONTACT + Conversation.ACCOUNT + " TEXT, " + Conversation.CONTACT
+ " TEXT, " + Conversation.CREATED + " NUMBER, " + " TEXT, " + Conversation.CREATED + " NUMBER, "
+ Conversation.STATUS + " NUMBER," + "FOREIGN KEY(" + Conversation.STATUS + " NUMBER," + Conversation.MODE
+ Conversation.ACCOUNT + ") REFERENCES " + Account.TABLENAME + " NUMBER," + "FOREIGN KEY(" + Conversation.ACCOUNT
+ "(" + Account.UUID + ") ON DELETE CASCADE);"); + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID
+ ") ON DELETE CASCADE);");
db.execSQL("create table " + Message.TABLENAME + "( " + Message.UUID db.execSQL("create table " + Message.TABLENAME + "( " + Message.UUID
+ " TEXT PRIMARY KEY, " + Message.CONVERSATION + " TEXT, " + " TEXT PRIMARY KEY, " + Message.CONVERSATION + " TEXT, "
+ Message.TIME_SENT + " NUMBER, " + Message.COUNTERPART + Message.TIME_SENT + " NUMBER, " + Message.COUNTERPART
@ -87,6 +89,11 @@ public class DatabaseBackend extends SQLiteOpenHelper {
db.insert(Account.TABLENAME, null, account.getContentValues()); db.insert(Account.TABLENAME, null, account.getContentValues());
} }
public void createContact(Contact contact) {
SQLiteDatabase db = this.getWritableDatabase();
db.insert(Contact.TABLENAME, null, contact.getContentValues());
}
public int getConversationCount() { public int getConversationCount() {
SQLiteDatabase db = this.getReadableDatabase(); SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("select count(uuid) as count from " Cursor cursor = db.rawQuery("select count(uuid) as count from "
@ -184,4 +191,52 @@ public class DatabaseBackend extends SQLiteOpenHelper {
db.update(Message.TABLENAME, message.getContentValues(), Message.UUID db.update(Message.TABLENAME, message.getContentValues(), Message.UUID
+ "=?", args); + "=?", args);
} }
public void updateContact(Contact contact) {
SQLiteDatabase db = this.getWritableDatabase();
String[] args = { contact.getUuid() };
db.update(Contact.TABLENAME, contact.getContentValues(), Contact.UUID
+ "=?", 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};
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);
} else {
contact.setUuid(UUID.randomUUID().toString());
createContact(contact);
}
}
}
public List<Contact> getContacts() {
List<Contact> list = new ArrayList<Contact>();
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(Contact.TABLENAME, null, null, 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);
}
} }

View File

@ -19,14 +19,21 @@ import de.gultsch.chat.xmpp.MessagePacket;
import de.gultsch.chat.xmpp.OnIqPacketReceived; import de.gultsch.chat.xmpp.OnIqPacketReceived;
import de.gultsch.chat.xmpp.OnMessagePacketReceived; import de.gultsch.chat.xmpp.OnMessagePacketReceived;
import de.gultsch.chat.xmpp.OnStatusChanged; import de.gultsch.chat.xmpp.OnStatusChanged;
import de.gultsch.chat.xmpp.PresencePacket;
import de.gultsch.chat.xmpp.XmppConnection; import de.gultsch.chat.xmpp.XmppConnection;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.Service; import android.app.Service;
import android.content.Context; import android.content.Context;
import android.content.CursorLoader;
import android.content.Intent; import android.content.Intent;
import android.content.Loader;
import android.content.Loader.OnLoadCompleteListener;
import android.database.Cursor;
import android.os.Binder; import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.PowerManager; import android.os.PowerManager;
import android.provider.ContactsContract;
import android.util.Log; import android.util.Log;
public class XmppConnectionService extends Service { public class XmppConnectionService extends Service {
@ -50,15 +57,45 @@ public class XmppConnectionService extends Service {
@Override @Override
public void onMessagePacketReceived(Account account, public void onMessagePacketReceived(Account account,
MessagePacket packet) { MessagePacket packet) {
Conversation conversation = null;
String fullJid = packet.getFrom();
String counterPart = null;
if (packet.getType() == MessagePacket.TYPE_CHAT) { if (packet.getType() == MessagePacket.TYPE_CHAT) {
String fullJid = packet.getFrom();
String jid = fullJid.split("/")[0]; String jid = fullJid.split("/")[0];
String name = jid.split("@")[0]; counterPart = fullJid;
Contact contact = new Contact(account, name, jid, null); // dummy Contact contact = findOrCreateContact(account,jid);
// contact conversation = findOrCreateConversation(account, contact);
Conversation conversation = findOrCreateConversation(account, } else if (packet.getType() == MessagePacket.TYPE_GROUPCHAT) {
contact); String[] fromParts = fullJid.split("/");
Message message = new Message(conversation, fullJid, if (fromParts.length != 2) {
return;
}
if (packet.hasChild("subject")) {
return;
}
if (packet.hasChild("delay")) {
return;
}
String muc = fromParts[0];
counterPart = fromParts[1];
if (counterPart.equals(account.getUsername())) {
return;
}
for (int i = 0; i < conversations.size(); ++i) {
if (conversations.get(i).getContactJid().equals(muc)) {
conversation = conversations.get(i);
break;
}
}
if (conversation == null) {
Log.d(LOGTAG, "couldnt find muc");
}
}
if (conversation != null) {
Log.d(LOGTAG, packet.toString());
Message message = new Message(conversation, counterPart,
packet.getBody(), Message.ENCRYPTION_NONE, packet.getBody(), Message.ENCRYPTION_NONE,
Message.STATUS_RECIEVED); Message.STATUS_RECIEVED);
conversation.getMessages().add(message); conversation.getMessages().add(message);
@ -78,10 +115,12 @@ public class XmppConnectionService extends Service {
@Override @Override
public void onStatusChanged(Account account) { public void onStatusChanged(Account account) {
Log.d(LOGTAG,account.getJid()+" changed status to "+account.getStatus());
if (accountChangedListener != null) { if (accountChangedListener != null) {
accountChangedListener.onAccountListChangedListener(); accountChangedListener.onAccountListChangedListener();
} }
if (account.getStatus() == Account.STATUS_ONLINE) {
connectMultiModeConversations(account);
}
} }
}; };
@ -96,9 +135,11 @@ public class XmppConnectionService extends Service {
for (Account account : accounts) { for (Account account : accounts) {
if (!connections.containsKey(account)) { if (!connections.containsKey(account)) {
if (!account.isOptionSet(Account.OPTION_DISABLED)) { if (!account.isOptionSet(Account.OPTION_DISABLED)) {
this.connections.put(account, this.createConnection(account)); this.connections.put(account,
this.createConnection(account));
} else { } else {
Log.d(LOGTAG,account.getJid()+": not starting because it's disabled"); Log.d(LOGTAG, account.getJid()
+ ": not starting because it's disabled");
} }
} }
} }
@ -114,9 +155,8 @@ public class XmppConnectionService extends Service {
public XmppConnection createConnection(Account account) { public XmppConnection createConnection(Account account) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
XmppConnection connection = new XmppConnection(account, pm); XmppConnection connection = new XmppConnection(account, pm);
connection connection.setOnMessagePacketReceivedListener(this.messageListener);
.setOnMessagePacketReceivedListener(this.messageListener); connection.setOnStatusChangedListener(this.statusListener);
connection.setOnStatusChangedListener(this.statusListener );
Thread thread = new Thread(connection); Thread thread = new Thread(connection);
thread.start(); thread.start();
return connection; return connection;
@ -132,7 +172,11 @@ public class XmppConnectionService extends Service {
+ message.getCounterpart()); + message.getCounterpart());
databaseBackend.createMessage(message); databaseBackend.createMessage(message);
MessagePacket packet = new MessagePacket(); MessagePacket packet = new MessagePacket();
packet.setType(MessagePacket.TYPE_CHAT); if (message.getConversation().getMode() == Conversation.MODE_SINGLE) {
packet.setType(MessagePacket.TYPE_CHAT);
} else if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
packet.setType(MessagePacket.TYPE_GROUPCHAT);
}
packet.setTo(message.getCounterpart()); packet.setTo(message.getCounterpart());
packet.setFrom(account.getJid()); packet.setFrom(account.getJid());
packet.setBody(message.getBody()); packet.setBody(message.getBody());
@ -141,36 +185,108 @@ public class XmppConnectionService extends Service {
databaseBackend.updateMessage(message); databaseBackend.updateMessage(message);
} }
public void getRoster(final Account account, public void getRoster(final OnRosterFetchedListener listener) {
final OnRosterFetchedListener listener) { List<Contact> contacts = databaseBackend.getContacts();
IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET); if (listener != null) {
Element query = new Element("query"); listener.onRosterFetched(contacts);
query.setAttribute("xmlns", "jabber:iq:roster"); }
query.setAttribute("ver", ""); }
iqPacket.addChild(query);
connections.get(account).sendIqPacket(iqPacket,
new OnIqPacketReceived() {
@Override public void updateRoster(final Account account,
public void onIqPacketReceived(Account account, final OnRosterFetchedListener listener) {
IqPacket packet) {
Element roster = packet.findChild("query"); final Hashtable<String, Bundle> phoneContacts = new Hashtable<String, Bundle>();
List<Contact> contacts = new ArrayList<Contact>(); final List<Contact> contacts = new ArrayList<Contact>();
for (Element item : roster.getChildren()) {
String name = item.getAttribute("name"); final String[] PROJECTION = new String[] {
String jid = item.getAttribute("jid"); ContactsContract.Data.CONTACT_ID,
if (name == null) { ContactsContract.Data.DISPLAY_NAME,
name = jid.split("@")[0]; ContactsContract.Data.PHOTO_THUMBNAIL_URI,
ContactsContract.CommonDataKinds.Im.DATA };
final String SELECTION = "(" + ContactsContract.Data.MIMETYPE + "=\""
+ ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE
+ "\") AND (" + ContactsContract.CommonDataKinds.Im.PROTOCOL
+ "=\"" + ContactsContract.CommonDataKinds.Im.PROTOCOL_JABBER
+ "\")";
CursorLoader mCursorLoader = new CursorLoader(this,
ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, null,
null);
mCursorLoader.registerListener(0, new OnLoadCompleteListener<Cursor>() {
@Override
public void onLoadComplete(Loader<Cursor> arg0, Cursor cursor) {
while (cursor.moveToNext()) {
Bundle contact = new Bundle();
contact.putInt("phoneid", cursor.getInt(cursor
.getColumnIndex(ContactsContract.Data.CONTACT_ID)));
contact.putString(
"displayname",
cursor.getString(cursor
.getColumnIndex(ContactsContract.Data.DISPLAY_NAME)));
contact.putString(
"photouri",
cursor.getString(cursor
.getColumnIndex(ContactsContract.Data.PHOTO_THUMBNAIL_URI)));
phoneContacts.put(
cursor.getString(cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)),
contact);
}
IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
Element query = new Element("query");
query.setAttribute("xmlns", "jabber:iq:roster");
query.setAttribute("ver", "");
iqPacket.addChild(query);
connections.get(account).sendIqPacket(iqPacket,
new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account,
IqPacket packet) {
Element roster = packet.findChild("query");
if (roster != null) {
for (Element item : roster.getChildren()) {
Contact contact;
Log.d(LOGTAG, item.toString());
String name = item.getAttribute("name");
String jid = item.getAttribute("jid");
if (phoneContacts.containsKey(jid)) {
Bundle phoneContact = phoneContacts
.get(jid);
contact = new Contact(
account,
phoneContact
.getString("displayname"),
jid,
phoneContact
.getString("photouri"));
contact.setSystemAccount(phoneContact.getInt("phoneid"));
} else {
if (name == null) {
name = jid.split("@")[0];
}
contact = new Contact(account,
name, jid, null);
}
contact.setAccount(account);
contact.setSubscription(item
.getAttribute("subscription"));
contacts.add(contact);
}
databaseBackend.mergeContacts(contacts);
if (listener != null) {
listener.onRosterFetched(contacts);
}
}
} }
Contact contact = new Contact(account, name, jid, });
null);
contacts.add(contact); }
} });
if (listener != null) { mCursorLoader.startLoading();
listener.onRosterFetched(contacts);
}
}
});
} }
public void addConversation(Conversation conversation) { public void addConversation(Conversation conversation) {
@ -200,6 +316,15 @@ public class XmppConnectionService extends Service {
return databaseBackend.getMessages(conversation, 100); return databaseBackend.getMessages(conversation, 100);
} }
public Contact findOrCreateContact(Account account, String jid) {
Contact contact = databaseBackend.findContact(account,jid);
if (contact!=null) {
return contact;
} else {
return new Contact(account,jid.split("@")[0], jid, null);
}
}
public Conversation findOrCreateConversation(Account account, public Conversation findOrCreateConversation(Account account,
Contact contact) { Contact contact) {
// Log.d(LOGTAG,"was asked to find conversation for "+contact.getJid()); // Log.d(LOGTAG,"was asked to find conversation for "+contact.getJid());
@ -220,7 +345,8 @@ public class XmppConnectionService extends Service {
} else { } else {
Log.d(LOGTAG, "didnt find one in archive. create new one"); Log.d(LOGTAG, "didnt find one in archive. create new one");
conversation = new Conversation(contact.getDisplayName(), conversation = new Conversation(contact.getDisplayName(),
contact.getProfilePhoto(), account, contact.getJid()); contact.getProfilePhoto(), account, contact.getJid(),
Conversation.MODE_SINGLE);
this.databaseBackend.createConversation(conversation); this.databaseBackend.createConversation(conversation);
} }
this.conversations.add(conversation); this.conversations.add(conversation);
@ -246,7 +372,8 @@ public class XmppConnectionService extends Service {
databaseBackend.createAccount(account); databaseBackend.createAccount(account);
this.accounts.add(account); this.accounts.add(account);
this.connections.put(account, this.createConnection(account)); this.connections.put(account, this.createConnection(account));
if (accountChangedListener!=null) accountChangedListener.onAccountListChangedListener(); if (accountChangedListener != null)
accountChangedListener.onAccountListChangedListener();
} }
public void updateAccount(Account account) { public void updateAccount(Account account) {
@ -259,21 +386,24 @@ public class XmppConnectionService extends Service {
if (!account.isOptionSet(Account.OPTION_DISABLED)) { if (!account.isOptionSet(Account.OPTION_DISABLED)) {
this.connections.put(account, this.createConnection(account)); this.connections.put(account, this.createConnection(account));
} else { } else {
Log.d(LOGTAG,account.getJid()+": not starting because it's disabled"); Log.d(LOGTAG, account.getJid()
+ ": not starting because it's disabled");
} }
if (accountChangedListener!=null) accountChangedListener.onAccountListChangedListener(); if (accountChangedListener != null)
accountChangedListener.onAccountListChangedListener();
} }
public void deleteAccount(Account account) { public void deleteAccount(Account account) {
Log.d(LOGTAG,"called delete account"); Log.d(LOGTAG, "called delete account");
if (this.connections.containsKey(account)) { if (this.connections.containsKey(account)) {
Log.d(LOGTAG,"found connection. disconnecting"); Log.d(LOGTAG, "found connection. disconnecting");
this.connections.get(account).disconnect(); this.connections.get(account).disconnect();
this.connections.remove(account); this.connections.remove(account);
this.accounts.remove(account); this.accounts.remove(account);
} }
databaseBackend.deleteAccount(account); databaseBackend.deleteAccount(account);
if (accountChangedListener!=null) accountChangedListener.onAccountListChangedListener(); if (accountChangedListener != null)
accountChangedListener.onAccountListChangedListener();
} }
public void setOnConversationListChangedListener( public void setOnConversationListChangedListener(
@ -285,11 +415,37 @@ public class XmppConnectionService extends Service {
this.convChangedListener = null; this.convChangedListener = null;
} }
public void setOnAccountListChangedListener(OnAccountListChangedListener listener) { public void setOnAccountListChangedListener(
OnAccountListChangedListener listener) {
this.accountChangedListener = listener; this.accountChangedListener = listener;
} }
public void removeOnAccountListChangedListener() { public void removeOnAccountListChangedListener() {
this.accountChangedListener = null; this.accountChangedListener = null;
} }
public void connectMultiModeConversations(Account account) {
List<Conversation> conversations = getConversations();
for (int i = 0; i < conversations.size(); i++) {
Conversation conversation = conversations.get(i);
if ((conversation.getMode() == Conversation.MODE_MULTI)
&& (conversation.getAccount() == account)) {
String muc = conversation.getContactJid();
Log.d(LOGTAG,
"join muc " + muc + " with account " + account.getJid());
PresencePacket packet = new PresencePacket();
packet.setAttribute("to", muc + "/" + account.getUsername());
Element x = new Element("x");
x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
packet.addChild(x);
connections.get(conversation.getAccount()).sendPresencePacket(
packet);
}
}
}
public void disconnectMultiModeConversations() {
}
} }

View File

@ -283,17 +283,28 @@ public class ConversationActivity extends XmppActivity {
super.onStart(); super.onStart();
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancelAll(); nm.cancelAll();
if (conversationList.size()>=1) {
onConvChanged.onConversationListChanged();
}
} }
@Override /*@Override
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
if (xmppConnectionServiceBound) { if (xmppConnectionServiceBound) {
Log.d("xmppService","called on stop. remove listener");
xmppConnectionService.removeOnConversationListChangedListener(); xmppConnectionService.removeOnConversationListChangedListener();
unbindService(mConnection); unbindService(mConnection);
xmppConnectionServiceBound = false; xmppConnectionServiceBound = false;
} }
}*/
@Override
protected void onStop() {
Log.d("gultsch","called on stop in conversation activity");
if (xmppConnectionServiceBound) {
xmppConnectionService.removeOnConversationListChangedListener();
}
super.onStop();
} }
@Override @Override
@ -302,7 +313,6 @@ public class ConversationActivity extends XmppActivity {
xmppConnectionService.setOnConversationListChangedListener(this.onConvChanged); xmppConnectionService.setOnConversationListChangedListener(this.onConvChanged);
if (conversationList.size()==0) { if (conversationList.size()==0) {
Log.d("gultsch","conversation list is empty fetch new");
conversationList.clear(); conversationList.clear();
conversationList.addAll(xmppConnectionService conversationList.addAll(xmppConnectionService
.getConversations()); .getConversations());

View File

@ -115,11 +115,19 @@ public class ConversationFragment extends Fragment {
} }
ImageView imageView = (ImageView) view.findViewById(R.id.message_photo); ImageView imageView = (ImageView) view.findViewById(R.id.message_photo);
if (type == RECIEVED) { if (type == RECIEVED) {
Uri uri = item.getConversation().getProfilePhotoUri(); if(item.getConversation().getMode()==Conversation.MODE_SINGLE) {
if (uri!=null) { Uri uri = item.getConversation().getProfilePhotoUri();
imageView.setImageURI(uri); if (uri!=null) {
} else { imageView.setImageURI(uri);
imageView.setImageBitmap(UIHelper.getUnknownContactPicture(item.getConversation().getName(), 200)); } else {
imageView.setImageBitmap(UIHelper.getUnknownContactPicture(item.getConversation().getName(), 200));
}
} else if (item.getConversation().getMode()==Conversation.MODE_MULTI) {
if (item.getCounterpart()!=null) {
imageView.setImageBitmap(UIHelper.getUnknownContactPicture(item.getCounterpart(), 200));
} else {
imageView.setImageBitmap(UIHelper.getUnknownContactPicture(item.getConversation().getName(), 200));
}
} }
} else { } else {
imageView.setImageURI(profilePicture); imageView.setImageURI(profilePicture);
@ -152,12 +160,9 @@ public class ConversationFragment extends Fragment {
final ConversationActivity activity = (ConversationActivity) getActivity(); final ConversationActivity activity = (ConversationActivity) getActivity();
// TODO check if bond and get data back
if (activity.xmppConnectionServiceBound) { if (activity.xmppConnectionServiceBound) {
this.conversation = activity.getConversationList().get(activity.getSelectedConversation()); this.conversation = activity.getConversationList().get(activity.getSelectedConversation());
this.messageList.clear(); updateMessages();
this.messageList.addAll(this.conversation.getMessages());
// rendering complete. now go tell activity to close pane // rendering complete. now go tell activity to close pane
if (!activity.shouldPaneBeOpen()) { if (!activity.shouldPaneBeOpen()) {
activity.getSlidingPaneLayout().closePane(); activity.getSlidingPaneLayout().closePane();
@ -165,18 +170,14 @@ public class ConversationFragment extends Fragment {
activity.getActionBar().setTitle(conversation.getName()); activity.getActionBar().setTitle(conversation.getName());
activity.invalidateOptionsMenu(); activity.invalidateOptionsMenu();
} }
int size = this.messageList.size();
if (size >= 1)
messagesView.setSelection(size - 1);
} }
} }
public void onBackendConnected() { public void onBackendConnected() {
Log.d("gultsch","calling on backend connected in conversation fragment");
final ConversationActivity activity = (ConversationActivity) getActivity(); final ConversationActivity activity = (ConversationActivity) getActivity();
this.conversation = activity.getConversationList().get(activity.getSelectedConversation()); this.conversation = activity.getConversationList().get(activity.getSelectedConversation());
this.messageList.clear(); updateMessages();
this.messageList.addAll(this.conversation.getMessages());
// rendering complete. now go tell activity to close pane // rendering complete. now go tell activity to close pane
if (!activity.shouldPaneBeOpen()) { if (!activity.shouldPaneBeOpen()) {
activity.getSlidingPaneLayout().closePane(); activity.getSlidingPaneLayout().closePane();
@ -190,5 +191,8 @@ public class ConversationFragment extends Fragment {
this.messageList.clear(); this.messageList.clear();
this.messageList.addAll(this.conversation.getMessages()); this.messageList.addAll(this.conversation.getMessages());
this.messageListAdapter.notifyDataSetChanged(); this.messageListAdapter.notifyDataSetChanged();
int size = this.messageList.size();
if (size >= 1)
messagesView.setSelection(size - 1);
} }
} }

View File

@ -152,12 +152,10 @@ public class ManageAccountActivity extends XmppActivity implements ActionMode.Ca
@Override @Override
protected void onStop() { protected void onStop() {
super.onStop();
if (xmppConnectionServiceBound) { if (xmppConnectionServiceBound) {
xmppConnectionService.removeOnAccountListChangedListener(); xmppConnectionService.removeOnAccountListChangedListener();
unbindService(mConnection);
xmppConnectionServiceBound = false;
} }
super.onStop();
} }
@Override @Override

View File

@ -57,10 +57,6 @@ public class NewConversationActivity extends XmppActivity {
protected void updateAggregatedContacts() { protected void updateAggregatedContacts() {
aggregatedContacts.clear(); aggregatedContacts.clear();
for (Contact contact : phoneContacts) {
if (contact.match(searchString))
aggregatedContacts.add(contact);
}
for (Contact contact : rosterContacts) { for (Contact contact : rosterContacts) {
if (contact.match(searchString)) if (contact.match(searchString))
aggregatedContacts.add(contact); aggregatedContacts.add(contact);
@ -71,7 +67,8 @@ public class NewConversationActivity extends XmppActivity {
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
@Override @Override
public int compare(Contact lhs, Contact rhs) { public int compare(Contact lhs, Contact rhs) {
return lhs.getDisplayName().toLowerCase().compareTo(rhs.getDisplayName().toLowerCase()); return lhs.getDisplayName().toLowerCase()
.compareTo(rhs.getDisplayName().toLowerCase());
} }
}); });
@ -79,7 +76,7 @@ public class NewConversationActivity extends XmppActivity {
if (Validator.isValidJid(searchString)) { if (Validator.isValidJid(searchString)) {
String name = searchString.split("@")[0]; String name = searchString.split("@")[0];
Contact newContact = new Contact(null,name, searchString,null); Contact newContact = new Contact(null, name, searchString, null);
aggregatedContacts.add(newContact); aggregatedContacts.add(newContact);
contactsHeader.setText("Create new contact"); contactsHeader.setText("Create new contact");
} else { } else {
@ -93,19 +90,6 @@ public class NewConversationActivity extends XmppActivity {
contactsView.setScrollX(0); contactsView.setScrollX(0);
} }
static final String[] PROJECTION = new String[] {
ContactsContract.Data.CONTACT_ID,
ContactsContract.Data.DISPLAY_NAME,
ContactsContract.Data.PHOTO_THUMBNAIL_URI,
ContactsContract.CommonDataKinds.Im.DATA };
// This is the select criteria
static final String SELECTION = "(" + ContactsContract.Data.MIMETYPE
+ "=\"" + ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE
+ "\") AND (" + ContactsContract.CommonDataKinds.Im.PROTOCOL
+ "=\"" + ContactsContract.CommonDataKinds.Im.PROTOCOL_JABBER
+ "\")";
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -154,11 +138,13 @@ public class NewConversationActivity extends XmppActivity {
((TextView) view.findViewById(R.id.contact_jid)) ((TextView) view.findViewById(R.id.contact_jid))
.setText(getItem(position).getJid()); .setText(getItem(position).getJid());
String profilePhoto = getItem(position).getProfilePhoto(); String profilePhoto = getItem(position).getProfilePhoto();
ImageView imageView = (ImageView) view.findViewById(R.id.contact_photo); ImageView imageView = (ImageView) view
if (profilePhoto!=null) { .findViewById(R.id.contact_photo);
if (profilePhoto != null) {
imageView.setImageURI(Uri.parse(profilePhoto)); imageView.setImageURI(Uri.parse(profilePhoto));
} else { } else {
imageView.setImageBitmap(UIHelper.getUnknownContactPicture(getItem(position).getDisplayName(),90)); imageView.setImageBitmap(UIHelper.getUnknownContactPicture(
getItem(position).getDisplayName(), 90));
} }
return view; return view;
} }
@ -168,24 +154,26 @@ public class NewConversationActivity extends XmppActivity {
contactsView.setOnItemClickListener(new OnItemClickListener() { contactsView.setOnItemClickListener(new OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> arg0, final View view, int pos, public void onItemClick(AdapterView<?> arg0, final View view,
long arg3) { int pos, long arg3) {
final Contact clickedContact = aggregatedContacts.get(pos); final Contact clickedContact = aggregatedContacts.get(pos);
Log.d("gultsch", Log.d("gultsch",
"clicked on " + clickedContact.getDisplayName()); "clicked on " + clickedContact.getDisplayName());
final List<Account> accounts = xmppConnectionService.getAccounts(); final List<Account> accounts = xmppConnectionService
.getAccounts();
if (accounts.size() == 1) { if (accounts.size() == 1) {
startConversation(clickedContact, accounts.get(0)); startConversation(clickedContact, accounts.get(0));
} else { } else {
String[] accountList = new String[accounts.size()]; String[] accountList = new String[accounts.size()];
for(int i = 0; i < accounts.size(); ++i) { for (int i = 0; i < accounts.size(); ++i) {
accountList[i] = accounts.get(i).getJid(); accountList[i] = accounts.get(i).getJid();
} }
AlertDialog.Builder builder = new AlertDialog.Builder(activity); AlertDialog.Builder builder = new AlertDialog.Builder(
activity);
builder.setTitle("Choose account"); builder.setTitle("Choose account");
builder.setItems(accountList,new OnClickListener() { builder.setItems(accountList, new OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
@ -203,51 +191,17 @@ public class NewConversationActivity extends XmppActivity {
Conversation conversation = xmppConnectionService Conversation conversation = xmppConnectionService
.findOrCreateConversation(account, contact); .findOrCreateConversation(account, contact);
Intent viewConversationIntent = new Intent(this,ConversationActivity.class); Intent viewConversationIntent = new Intent(this,
ConversationActivity.class);
viewConversationIntent.setAction(Intent.ACTION_VIEW); viewConversationIntent.setAction(Intent.ACTION_VIEW);
viewConversationIntent.putExtra( viewConversationIntent.putExtra(ConversationActivity.CONVERSATION,
ConversationActivity.CONVERSATION,
conversation.getUuid()); conversation.getUuid());
viewConversationIntent viewConversationIntent.setType(ConversationActivity.VIEW_CONVERSATION);
.setType(ConversationActivity.VIEW_CONVERSATION); viewConversationIntent.setFlags(viewConversationIntent.getFlags()
viewConversationIntent.setFlags(viewConversationIntent | Intent.FLAG_ACTIVITY_CLEAR_TOP);
.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(viewConversationIntent); startActivity(viewConversationIntent);
} }
@Override
public void onStart() {
super.onStart();
CursorLoader mCursorLoader = new CursorLoader(this,
ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, null,
null);
mCursorLoader.registerListener(0, new OnLoadCompleteListener<Cursor>() {
@Override
public void onLoadComplete(Loader<Cursor> arg0, Cursor cursor) {
phoneContacts.clear();
while (cursor.moveToNext()) {
String profilePhoto = cursor.getString(cursor
.getColumnIndex(ContactsContract.Data.PHOTO_THUMBNAIL_URI));
/*if (profilePhoto == null) {
profilePhoto = DEFAULT_PROFILE_PHOTO;
}*/
Contact contact = new Contact(null,
cursor.getString(cursor
.getColumnIndex(ContactsContract.Data.DISPLAY_NAME)),
cursor.getString(cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)),
profilePhoto);
phoneContacts.add(contact);
}
updateAggregatedContacts();
}
});
mCursorLoader.startLoading();
}
@Override @Override
void onBackendConnected() { void onBackendConnected() {
if (xmppConnectionService.getConversationCount() == 0) { if (xmppConnectionService.getConversationCount() == 0) {
@ -256,23 +210,21 @@ public class NewConversationActivity extends XmppActivity {
} }
this.accounts = xmppConnectionService.getAccounts(); this.accounts = xmppConnectionService.getAccounts();
this.rosterContacts.clear(); this.rosterContacts.clear();
for(Account account : this.accounts) { xmppConnectionService.getRoster(new OnRosterFetchedListener() {
xmppConnectionService.getRoster(account, new OnRosterFetchedListener() {
@Override @Override
public void onRosterFetched(List<Contact> roster) { public void onRosterFetched(List<Contact> roster) {
rosterContacts.addAll(roster); rosterContacts.addAll(roster);
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
updateAggregatedContacts(); updateAggregatedContacts();
} }
}); });
} }
}); });
}
} }
@Override @Override

View File

@ -46,13 +46,11 @@ public class UIHelper {
public static Bitmap getUnknownContactPicture(String name, int size) { public static Bitmap getUnknownContactPicture(String name, int size) {
String firstLetter = name.substring(0, 1).toUpperCase(); String firstLetter = name.substring(0, 1).toUpperCase();
String centerLetter = name.substring(name.length() / 2,
(name.length() / 2) + 1);
int holoColors[] = { 0xFF1da9da, 0xFFb368d9, 0xFF83b600, 0xFFffa713, int holoColors[] = { 0xFF1da9da, 0xFFb368d9, 0xFF83b600, 0xFFffa713,
0xFFe92727 }; 0xFFe92727 };
int color = holoColors[centerLetter.charAt(0) % holoColors.length]; int color = holoColors[Math.abs(name.hashCode()) % holoColors.length];
Bitmap bitmap = Bitmap Bitmap bitmap = Bitmap
.createBitmap(size, size, Bitmap.Config.ARGB_8888); .createBitmap(size, size, Bitmap.Config.ARGB_8888);

View File

@ -6,6 +6,7 @@ public class MessagePacket extends Element {
public static final int TYPE_CHAT = 0; public static final int TYPE_CHAT = 0;
public static final int TYPE_UNKNOWN = 1; public static final int TYPE_UNKNOWN = 1;
public static final int TYPE_NO = 2; public static final int TYPE_NO = 2;
public static final int TYPE_GROUPCHAT = 3;
private MessagePacket(String name) { private MessagePacket(String name) {
super(name); super(name);
@ -51,7 +52,9 @@ public class MessagePacket extends Element {
case TYPE_CHAT: case TYPE_CHAT:
this.setAttribute("type","chat"); this.setAttribute("type","chat");
break; break;
case TYPE_GROUPCHAT:
this.setAttribute("type", "groupchat");
break;
default: default:
this.setAttribute("type","chat"); this.setAttribute("type","chat");
break; break;
@ -65,6 +68,8 @@ public class MessagePacket extends Element {
} }
if (type.equals("chat")) { if (type.equals("chat")) {
return TYPE_CHAT; return TYPE_CHAT;
} else if (type.equals("groupchat")) {
return TYPE_GROUPCHAT;
} else { } else {
return TYPE_UNKNOWN; return TYPE_UNKNOWN;
} }

View File

@ -340,6 +340,7 @@ public class XmppConnection implements Runnable {
public void sendPresencePacket(PresencePacket packet) { public void sendPresencePacket(PresencePacket packet) {
tagWriter.writeElement(packet); tagWriter.writeElement(packet);
Log.d(LOGTAG,account.getJid()+": sending: "+packet.toString());
} }
public void setOnMessagePacketReceivedListener(OnMessagePacketReceived listener) { public void setOnMessagePacketReceivedListener(OnMessagePacketReceived listener) {