diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/de/gultsch/chat/entities/Contact.java | 33 | ||||
-rw-r--r-- | src/de/gultsch/chat/entities/Presences.java | 76 | ||||
-rw-r--r-- | src/de/gultsch/chat/persistance/DatabaseBackend.java | 13 | ||||
-rw-r--r-- | src/de/gultsch/chat/services/XmppConnectionService.java | 159 | ||||
-rw-r--r-- | src/de/gultsch/chat/ui/ConversationActivity.java | 7 | ||||
-rw-r--r-- | src/de/gultsch/chat/ui/ConversationFragment.java | 8 | ||||
-rw-r--r-- | src/de/gultsch/chat/ui/DialogContactDetails.java | 82 | ||||
-rw-r--r-- | src/de/gultsch/chat/ui/NewConversationActivity.java | 13 |
8 files changed, 310 insertions, 81 deletions
diff --git a/src/de/gultsch/chat/entities/Contact.java b/src/de/gultsch/chat/entities/Contact.java index 6079d9bb..da3c0810 100644 --- a/src/de/gultsch/chat/entities/Contact.java +++ b/src/de/gultsch/chat/entities/Contact.java @@ -1,6 +1,7 @@ package de.gultsch.chat.entities; import java.io.Serializable; +import java.util.Hashtable; import android.content.ContentValues; import android.database.Cursor; @@ -16,7 +17,7 @@ public class Contact extends AbstractEntity implements Serializable { public static final String SYSTEMACCOUNT = "systemaccount"; public static final String PHOTOURI = "photouri"; public static final String OPENPGPKEY = "pgpkey"; - public static final String LASTPRESENCE = "presence"; + public static final String PRESENCES = "presences"; public static final String ACCOUNT = "accountUuid"; protected String accountUuid; @@ -26,7 +27,7 @@ public class Contact extends AbstractEntity implements Serializable { protected int systemAccount; protected String photoUri; protected String openPGPKey; - protected long lastPresence; + protected Presences presences = new Presences(); protected Account account; @@ -44,7 +45,7 @@ public class Contact extends AbstractEntity implements Serializable { public Contact(String uuid, String account, String displayName, String jid, String subscription, String photoUri, int systemAccount, - String pgpKey, long lastseen) { + String pgpKey,String presences) { this.uuid = uuid; this.accountUuid = account; this.displayName = displayName; @@ -53,7 +54,7 @@ public class Contact extends AbstractEntity implements Serializable { this.photoUri = photoUri; this.systemAccount = systemAccount; this.openPGPKey = pgpKey; - this.lastPresence = lastseen; + this.presences = Presences.fromJsonString(presences); } public String getDisplayName() { @@ -84,7 +85,7 @@ public class Contact extends AbstractEntity implements Serializable { values.put(SYSTEMACCOUNT, systemAccount); values.put(PHOTOURI, photoUri); values.put(OPENPGPKEY, openPGPKey); - values.put(LASTPRESENCE, lastPresence); + values.put(PRESENCES, presences.toJsonString()); return values; } @@ -97,12 +98,16 @@ public class Contact extends AbstractEntity implements Serializable { cursor.getString(cursor.getColumnIndex(PHOTOURI)), cursor.getInt(cursor.getColumnIndex(SYSTEMACCOUNT)), cursor.getString(cursor.getColumnIndex(OPENPGPKEY)), - cursor.getLong(cursor.getColumnIndex(LASTPRESENCE))); + cursor.getString(cursor.getColumnIndex(PRESENCES))); } public void setSubscription(String subscription) { this.subscription = subscription; } + + public String getSubscription() { + return this.subscription; + } public void setSystemAccount(int account) { this.systemAccount = account; @@ -136,4 +141,20 @@ public class Contact extends AbstractEntity implements Serializable { } } } + + public Hashtable<String, Integer> getPresences() { + return this.presences.getPresences(); + } + + public void updatePresence(String resource, int status) { + this.presences.updatePresence(resource, status); + } + + public void removePresence(String resource) { + this.presences.removePresence(resource); + } + + public int getMostAvailableStatus() { + return this.presences.getMostAvailableStatus(); + } } diff --git a/src/de/gultsch/chat/entities/Presences.java b/src/de/gultsch/chat/entities/Presences.java new file mode 100644 index 00000000..aabc8440 --- /dev/null +++ b/src/de/gultsch/chat/entities/Presences.java @@ -0,0 +1,76 @@ +package de.gultsch.chat.entities; + +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; + +public class Presences { + + public static final int CHAT = -1; + public static final int ONLINE = 0; + public static final int AWAY = 1; + public static final int XA = 2; + public static final int DND = 3; + public static final int OFFLINE = 4; + + private Hashtable<String, Integer> presences = new Hashtable<String, Integer>(); + + public Hashtable<String, Integer> getPresences() { + return this.presences; + } + + public void updatePresence(String resource, int status) { + this.presences.put(resource, status); + } + + public void removePresence(String resource) { + this.presences.remove(resource); + } + + public int getMostAvailableStatus() { + int status = OFFLINE; + Iterator<Entry<String, Integer>> it = presences.entrySet().iterator(); + while (it.hasNext()) { + Entry<String, Integer> entry = it.next(); + if (entry.getValue()<status) status = entry.getValue(); + } + 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; + } +} diff --git a/src/de/gultsch/chat/persistance/DatabaseBackend.java b/src/de/gultsch/chat/persistance/DatabaseBackend.java index ecf7152b..135296a6 100644 --- a/src/de/gultsch/chat/persistance/DatabaseBackend.java +++ b/src/de/gultsch/chat/persistance/DatabaseBackend.java @@ -8,10 +8,12 @@ import de.gultsch.chat.entities.Account; import de.gultsch.chat.entities.Contact; import de.gultsch.chat.entities.Conversation; import de.gultsch.chat.entities.Message; +import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; +import android.os.Bundle; import android.util.Log; public class DatabaseBackend extends SQLiteOpenHelper { @@ -53,7 +55,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.execSQL("create table " + Contact.TABLENAME + "(" + Contact.UUID + " TEXT PRIMARY KEY, " + Contact.ACCOUNT + " TEXT, " + Contact.DISPLAYNAME + " TEXT," + Contact.JID + " TEXT," - + Contact.LASTPRESENCE + " NUMBER, " + Contact.OPENPGPKEY + + Contact.PRESENCES + " TEXT, " + Contact.OPENPGPKEY + " TEXT," + Contact.PHOTOURI + " TEXT," + Contact.SUBSCRIPTION + " TEXT," + Contact.SYSTEMACCOUNT + " NUMBER, " + "FOREIGN KEY(" + Contact.ACCOUNT + ") REFERENCES " @@ -199,6 +201,15 @@ public class DatabaseBackend extends SQLiteOpenHelper { + "=?", 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++) { diff --git a/src/de/gultsch/chat/services/XmppConnectionService.java b/src/de/gultsch/chat/services/XmppConnectionService.java index eafb121c..3a316fbb 100644 --- a/src/de/gultsch/chat/services/XmppConnectionService.java +++ b/src/de/gultsch/chat/services/XmppConnectionService.java @@ -8,6 +8,7 @@ import de.gultsch.chat.entities.Account; import de.gultsch.chat.entities.Contact; import de.gultsch.chat.entities.Conversation; import de.gultsch.chat.entities.Message; +import de.gultsch.chat.entities.Presences; import de.gultsch.chat.persistance.DatabaseBackend; import de.gultsch.chat.ui.OnAccountListChangedListener; import de.gultsch.chat.ui.OnConversationListChangedListener; @@ -58,56 +59,46 @@ public class XmppConnectionService extends Service { @Override public void onMessagePacketReceived(Account account, MessagePacket packet) { - Conversation conversation = null; - String fullJid = packet.getFrom(); - String counterPart = null; - if (packet.getType() == MessagePacket.TYPE_CHAT) { - String jid = fullJid.split("/")[0]; - counterPart = fullJid; - Contact contact = findOrCreateContact(account,jid); - conversation = findOrCreateConversation(account, contact,false); - } else if (packet.getType() == MessagePacket.TYPE_GROUPCHAT) { - String[] fromParts = fullJid.split("/"); - if (fromParts.length != 2) { - return; - } - if (packet.hasChild("subject")) { - return; - } - if (packet.hasChild("delay")) { + if ((packet.getType() == MessagePacket.TYPE_CHAT) + || (packet.getType() == MessagePacket.TYPE_GROUPCHAT)) { + boolean notify = true; + if (!packet.hasChild("body")) { 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; + Conversation conversation = null; + String fullJid = packet.getFrom(); + String[] fromParts = fullJid.split("/"); + String jid = fromParts[0]; + Contact contact = findOrCreateContact(account, jid); + boolean muc = (packet.getType() == MessagePacket.TYPE_GROUPCHAT); + String counterPart = null; + int status = Message.STATUS_RECIEVED; + conversation = findOrCreateConversation(account, contact, muc); + if (muc) { + if ((fromParts.length==1)||(packet.hasChild("subject"))||(packet.hasChild("delay"))) { + return; } + counterPart = fromParts[1]; + if (counterPart.equals(account.getUsername())) { + status = Message.STATUS_SEND; + notify = false; + } + } else { + counterPart = fullJid; } - 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, - Message.STATUS_RECIEVED); + packet.getBody(), Message.ENCRYPTION_NONE, status); conversation.getMessages().add(message); databaseBackend.createMessage(message); if (convChangedListener != null) { convChangedListener.onConversationListChanged(); } else { - NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - mNotificationManager.notify(2342, UIHelper - .getUnreadMessageNotification( - getApplicationContext(), conversation)); + if (notify) { + NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + mNotificationManager.notify(2342, UIHelper + .getUnreadMessageNotification( + getApplicationContext(), conversation)); + } } } } @@ -120,19 +111,45 @@ public class XmppConnectionService extends Service { accountChangedListener.onAccountListChangedListener(); } if (account.getStatus() == Account.STATUS_ONLINE) { + databaseBackend.clearPresences(account); connectMultiModeConversations(account); } } }; - + private OnPresencePacketReceived presenceListener = new OnPresencePacketReceived() { - + @Override - public void onPresencePacketReceived(Account account, PresencePacket packet) { - String jid = packet.getAttribute("from"); + public void onPresencePacketReceived(Account account, + PresencePacket packet) { + String[] fromParts = packet.getAttribute("from").split("/"); + Contact contact = findOrCreateContact(account, fromParts[0]); + if (contact.getUuid()==null) { + //most likely muc, self or roster not synced + Log.d(LOGTAG,"got presence for non contact "+packet.toString()); + } String type = packet.getAttribute("type"); - if (type==null) { - //Log.d(LOGTAG,"online presence from "+jid); + if (type == null) { + Element show = packet.findChild("show"); + if (show==null) { + contact.updatePresence(fromParts[1],Presences.ONLINE); + } else if (show.getContent().equals("away")) { + contact.updatePresence(fromParts[1],Presences.AWAY); + } else if (show.getContent().equals("xa")) { + contact.updatePresence(fromParts[1],Presences.XA); + } else if (show.getContent().equals("chat")) { + contact.updatePresence(fromParts[1],Presences.CHAT); + } else if (show.getContent().equals("dnd")) { + contact.updatePresence(fromParts[1],Presences.DND); + } + databaseBackend.updateContact(contact); + } else if (type.equals("unavailable")) { + if (fromParts.length!=2) { + Log.d(LOGTAG,"received presence with no resource "+packet.toString()); + } else { + contact.removePresence(fromParts[1]); + databaseBackend.updateContact(contact); + } } } }; @@ -176,11 +193,6 @@ public class XmppConnectionService extends Service { return connection; } - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - public void sendMessage(final Account account, final Message message) { Log.d(LOGTAG, "sending message for " + account.getJid() + " to: " + message.getCounterpart()); @@ -194,14 +206,17 @@ public class XmppConnectionService extends Service { packet.setTo(message.getCounterpart()); packet.setFrom(account.getJid()); packet.setBody(message.getBody()); - connections.get(account).sendMessagePacket(packet); - message.setStatus(Message.STATUS_SEND); - databaseBackend.updateMessage(message); + if (account.getStatus()==Account.STATUS_ONLINE) { + connections.get(account).sendMessagePacket(packet); + message.setStatus(Message.STATUS_SEND); + databaseBackend.updateMessage(message); + } } - - public void getRoster(Account account, final OnRosterFetchedListener listener) { + + public void getRoster(Account account, + final OnRosterFetchedListener listener) { List<Contact> contacts = databaseBackend.getContacts(account); - for(int i=0; i < contacts.size(); ++i) { + for (int i = 0; i < contacts.size(); ++i) { contacts.get(i).setAccount(account); } if (listener != null) { @@ -278,7 +293,8 @@ public class XmppConnectionService extends Service { jid, phoneContact .getString("photouri")); - contact.setSystemAccount(phoneContact.getInt("phoneid")); + contact.setSystemAccount(phoneContact + .getInt("phoneid")); } else { if (name == null) { name = jid.split("@")[0]; @@ -331,18 +347,19 @@ public class XmppConnectionService extends Service { public List<Message> getMessages(Conversation conversation) { return databaseBackend.getMessages(conversation, 100); } - + public Contact findOrCreateContact(Account account, String jid) { - Contact contact = databaseBackend.findContact(account,jid); - if (contact!=null) { + Contact contact = databaseBackend.findContact(account, jid); + if (contact != null) { + contact.setAccount(account); return contact; } else { - return new Contact(account,jid.split("@")[0], jid, null); + return new Contact(account, jid.split("@")[0], jid, null); } } public Conversation findOrCreateConversation(Account account, - Contact contact,boolean muc) { + Contact contact, boolean muc) { for (Conversation conv : this.getConversations()) { if ((conv.getAccount().equals(account)) && (conv.getContactJid().equals(contact.getJid()))) { @@ -356,7 +373,7 @@ public class XmppConnectionService extends Service { conversation.setAccount(account); if (muc) { conversation.setMode(Conversation.MODE_MULTI); - if (account.getStatus()==Account.STATUS_ONLINE) { + if (account.getStatus() == Account.STATUS_ONLINE) { joinMuc(account, conversation); } } else { @@ -368,7 +385,7 @@ public class XmppConnectionService extends Service { conversation = new Conversation(contact.getDisplayName(), contact.getProfilePhoto(), account, contact.getJid(), Conversation.MODE_MULTI); - if (account.getStatus()==Account.STATUS_ONLINE) { + if (account.getStatus() == Account.STATUS_ONLINE) { joinMuc(account, conversation); } } else { @@ -463,7 +480,7 @@ public class XmppConnectionService extends Service { } } } - + public void joinMuc(Account account, Conversation conversation) { String muc = conversation.getContactJid(); PresencePacket packet = new PresencePacket(); @@ -471,11 +488,15 @@ public class XmppConnectionService extends Service { Element x = new Element("x"); x.setAttribute("xmlns", "http://jabber.org/protocol/muc"); packet.addChild(x); - connections.get(conversation.getAccount()).sendPresencePacket( - packet); + connections.get(conversation.getAccount()).sendPresencePacket(packet); } public void disconnectMultiModeConversations() { } -} + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } +}
\ No newline at end of file diff --git a/src/de/gultsch/chat/ui/ConversationActivity.java b/src/de/gultsch/chat/ui/ConversationActivity.java index 7e4cd34d..37a988fb 100644 --- a/src/de/gultsch/chat/ui/ConversationActivity.java +++ b/src/de/gultsch/chat/ui/ConversationActivity.java @@ -7,6 +7,7 @@ import java.util.List; import de.gultsch.chat.R; import de.gultsch.chat.R.id; +import de.gultsch.chat.entities.Contact; import de.gultsch.chat.entities.Conversation; import de.gultsch.chat.utils.UIHelper; import android.net.Uri; @@ -257,6 +258,12 @@ public class ConversationActivity extends XmppActivity { xmppConnectionService.archiveConversation(conv); selectedConversation = conversationList.get(0); break; + case R.id.action_details: + DialogContactDetails details = new DialogContactDetails(); + Contact contact = xmppConnectionService.findOrCreateContact(this.getSelectedConversation().getAccount(),this.getSelectedConversation().getContactJid()); + details.setContact(contact); + details.show(getFragmentManager(), "details"); + break; default: break; } diff --git a/src/de/gultsch/chat/ui/ConversationFragment.java b/src/de/gultsch/chat/ui/ConversationFragment.java index 319c3a31..2da0940b 100644 --- a/src/de/gultsch/chat/ui/ConversationFragment.java +++ b/src/de/gultsch/chat/ui/ConversationFragment.java @@ -59,7 +59,9 @@ public class ConversationFragment extends Fragment { conversation.getMessages().add(message); chatMsg.setText(""); - messageList.add(message); + if (conversation.getMode()==Conversation.MODE_SINGLE) { + messageList.add(message); + } activity.updateConversationList(); @@ -155,9 +157,6 @@ public class ConversationFragment extends Fragment { @Override public void onStart() { super.onStart(); - - Log.d("gultsch","conversationfragment onStart"); - final ConversationActivity activity = (ConversationActivity) getActivity(); if (activity.xmppConnectionServiceBound) { @@ -174,7 +173,6 @@ public class ConversationFragment extends Fragment { } public void onBackendConnected() { - Log.d("gultsch","calling on backend connected in conversation fragment"); final ConversationActivity activity = (ConversationActivity) getActivity(); this.conversation = activity.getSelectedConversation(); updateMessages(); diff --git a/src/de/gultsch/chat/ui/DialogContactDetails.java b/src/de/gultsch/chat/ui/DialogContactDetails.java new file mode 100644 index 00000000..7af8db70 --- /dev/null +++ b/src/de/gultsch/chat/ui/DialogContactDetails.java @@ -0,0 +1,82 @@ +package de.gultsch.chat.ui; + +import de.gultsch.chat.R; +import de.gultsch.chat.entities.Contact; +import de.gultsch.chat.entities.Presences; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.CheckBox; +import android.widget.TextView; + +public class DialogContactDetails extends DialogFragment { + + private Contact contact = null; + boolean displayingInRoster = false; + + public void setContact(Contact contact) { + this.contact = contact; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + LayoutInflater inflater = getActivity().getLayoutInflater(); + View view = inflater.inflate(R.layout.dialog_contact_details, null); + TextView contactJid = (TextView) view.findViewById(R.id.details_contact_jid); + TextView accountJid = (TextView) view.findViewById(R.id.details_account); + TextView status = (TextView) view.findViewById(R.id.details_contact_status); + CheckBox send = (CheckBox) view.findViewById(R.id.details_send_presence); + CheckBox receive = (CheckBox) view.findViewById(R.id.details_receive_presence); + + boolean subscriptionSend = false; + boolean subscriptionReceive = false; + if (contact.getSubscription().equals("both")) { + subscriptionReceive = true; + subscriptionSend = true; + } else if (contact.getSubscription().equals("from")) { + subscriptionSend = true; + } else if (contact.getSubscription().equals("to")) { + subscriptionReceive = true; + } + + switch (contact.getMostAvailableStatus()) { + case Presences.CHAT: + status.setText("free to chat"); + break; + case Presences.ONLINE: + status.setText("online"); + break; + case Presences.AWAY: + status.setText("away"); + break; + case Presences.XA: + status.setText("extended away"); + break; + case Presences.DND: + status.setText("do not disturb"); + break; + case Presences.OFFLINE: + status.setText("offline"); + break; + default: + status.setText("offline"); + break; + } + + send.setChecked(subscriptionSend); + receive.setChecked(subscriptionReceive); + contactJid.setText(contact.getJid()); + accountJid.setText(contact.getAccount().getJid()); + + builder.setView(view); + builder.setTitle(contact.getDisplayName()); + + builder.setNeutralButton("Done", null); + builder.setPositiveButton("Remove from roster", null); + return builder.create(); + } +} diff --git a/src/de/gultsch/chat/ui/NewConversationActivity.java b/src/de/gultsch/chat/ui/NewConversationActivity.java index c5f9695e..4e2628a6 100644 --- a/src/de/gultsch/chat/ui/NewConversationActivity.java +++ b/src/de/gultsch/chat/ui/NewConversationActivity.java @@ -24,6 +24,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; +import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ListView; @@ -185,6 +186,18 @@ public class NewConversationActivity extends XmppActivity { } } }); + contactsView.setOnItemLongClickListener(new OnItemLongClickListener() { + + @Override + public boolean onItemLongClick(AdapterView<?> arg0, View arg1, + int pos, long arg3) { + Contact clickedContact = aggregatedContacts.get(pos); + DialogContactDetails dialog = new DialogContactDetails(); + dialog.setContact(clickedContact); + dialog.show(getFragmentManager(), "details"); + return true; + } + }); } public void showIsMucDialogIfNeeded(final Contact clickedContact) { |