diff --git a/src/de/gultsch/chat/entities/Contact.java b/src/de/gultsch/chat/entities/Contact.java index eff46e53b..a01e20b0a 100644 --- a/src/de/gultsch/chat/entities/Contact.java +++ b/src/de/gultsch/chat/entities/Contact.java @@ -9,6 +9,8 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import de.gultsch.chat.xml.Element; + import android.content.ContentValues; import android.database.Cursor; @@ -29,7 +31,7 @@ public class Contact extends AbstractEntity implements Serializable { protected String accountUuid; protected String displayName; protected String jid; - protected String subscription; + protected int subscription = 0; protected String systemAccount; protected String photoUri; protected JSONObject keys = new JSONObject(); @@ -52,7 +54,7 @@ public class Contact extends AbstractEntity implements Serializable { } public Contact(String uuid, String account, String displayName, String jid, - String subscription, String photoUri, String systemAccount, + int subscription, String photoUri, String systemAccount, String keys, String presences) { this.uuid = uuid; this.accountUuid = account; @@ -109,18 +111,14 @@ public class Contact extends AbstractEntity implements Serializable { cursor.getString(cursor.getColumnIndex(ACCOUNT)), cursor.getString(cursor.getColumnIndex(DISPLAYNAME)), cursor.getString(cursor.getColumnIndex(JID)), - cursor.getString(cursor.getColumnIndex(SUBSCRIPTION)), + cursor.getInt(cursor.getColumnIndex(SUBSCRIPTION)), cursor.getString(cursor.getColumnIndex(PHOTOURI)), cursor.getString(cursor.getColumnIndex(SYSTEMACCOUNT)), cursor.getString(cursor.getColumnIndex(KEYS)), cursor.getString(cursor.getColumnIndex(PRESENCES))); } - - public void setSubscription(String subscription) { - this.subscription = subscription; - } - - public String getSubscription() { + + public int getSubscription() { return this.subscription; } @@ -220,4 +218,48 @@ public class Contact extends AbstractEntity implements Serializable { } } + + public void setSubscriptionOption(int option) { + this.subscription |= 1 << option; + } + + public void resetSubscriptionOption(int option) { + this.subscription &= ~(1 << option); + } + + public boolean getSubscriptionOption(int option) { + return ((this.subscription & (1 << option)) != 0); + } + + public void parseSubscriptionFromElement(Element item) { + String ask = item.getAttribute("ask"); + String subscription = item.getAttribute("subscription"); + + if (subscription!=null) { + if (subscription.equals("to")) { + this.resetSubscriptionOption(Contact.Subscription.FROM); + this.setSubscriptionOption(Contact.Subscription.TO); + } else if (subscription.equals("from")) { + this.resetSubscriptionOption(Contact.Subscription.TO); + this.setSubscriptionOption(Contact.Subscription.FROM); + } else if (subscription.equals("both")) { + this.setSubscriptionOption(Contact.Subscription.TO); + this.setSubscriptionOption(Contact.Subscription.FROM); + } + } + + if ((ask!=null)&&(ask.equals("subscribe"))) { + this.setSubscriptionOption(Contact.Subscription.ASKING); + } else { + this.resetSubscriptionOption(Contact.Subscription.ASKING); + } + } + + + public class Subscription { + 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; + } } diff --git a/src/de/gultsch/chat/persistance/DatabaseBackend.java b/src/de/gultsch/chat/persistance/DatabaseBackend.java index caee4e8f6..18fad7c42 100644 --- a/src/de/gultsch/chat/persistance/DatabaseBackend.java +++ b/src/de/gultsch/chat/persistance/DatabaseBackend.java @@ -58,7 +58,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { + Contact.DISPLAYNAME + " TEXT," + Contact.JID + " TEXT," + Contact.PRESENCES + " TEXT, " + Contact.KEYS + " TEXT," + Contact.PHOTOURI + " TEXT," + Contact.SUBSCRIPTION - + " TEXT," + Contact.SYSTEMACCOUNT + " NUMBER, " + + " NUMBER," + Contact.SYSTEMACCOUNT + " NUMBER, " + "FOREIGN KEY(" + Contact.ACCOUNT + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE);"); diff --git a/src/de/gultsch/chat/services/XmppConnectionService.java b/src/de/gultsch/chat/services/XmppConnectionService.java index 2bff2af42..a3e5d7cd7 100644 --- a/src/de/gultsch/chat/services/XmppConnectionService.java +++ b/src/de/gultsch/chat/services/XmppConnectionService.java @@ -200,6 +200,20 @@ public class XmppConnectionService extends Service { contact.removePresence(fromParts[1]); databaseBackend.updateContact(contact); } + } else if (type.equals("subscribe")) { + Log.d(LOGTAG,account.getJid()+": "+contact.getJid()+" asked to subscribe"); + if (contact.getSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT)) { + Log.d(LOGTAG,"preemptive grant existed. granting"); + sendPresenceUpdatesTo(contact); + contact.setSubscriptionOption(Contact.Subscription.FROM); + contact.resetSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT); + replaceContactInConversation(contact.getJid(), contact); + databaseBackend.updateContact(contact); + } else { + //TODO: ask user to handle it maybe + } + } else { + Log.d(LOGTAG,packet.toString()); } replaceContactInConversation(contact.getJid(),contact); } @@ -227,19 +241,21 @@ public class XmppConnectionService extends Service { String subscription = item.getAttribute("subscription"); Contact contact = databaseBackend.findContact(account, jid); if (contact == null) { - String name = item.getAttribute("name"); - if (name == null) { - name = jid.split("@")[0]; + 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 = new Contact(account, name, jid, null); - contact.setSubscription(subscription); - databaseBackend.createContact(contact); } else { if (subscription.equals("remove")) { databaseBackend.deleteContact(contact); replaceContactInConversation(contact.getJid(), null); } else { - contact.setSubscription(subscription); + contact.parseSubscriptionFromElement(item); databaseBackend.updateContact(contact); replaceContactInConversation(contact.getJid(),contact); } @@ -506,12 +522,14 @@ public class XmppConnectionService extends Service { contact.setDisplayName(phoneContact .getString("displayname")); databaseBackend.updateContact(contact); + replaceContactInConversation(contact.getJid(), contact); } else { if ((contact.getSystemAccount() != null) || (contact.getProfilePhoto() != null)) { contact.setSystemAccount(null); contact.setPhotoUri(null); databaseBackend.updateContact(contact); + replaceContactInConversation(contact.getJid(), contact); } } } @@ -545,7 +563,11 @@ public class XmppConnectionService extends Service { } public Contact findContact(Account account, String jid) { - return databaseBackend.findContact(account, jid); + Contact contact = databaseBackend.findContact(account, jid); + if (contact!=null) { + contact.setAccount(account); + } + return contact; } public Conversation findOrCreateConversation(Account account, String jid, @@ -766,4 +788,44 @@ public class XmppConnectionService extends Service { replaceContactInConversation(contact.getJid(), contact); databaseBackend.createContact(contact); } + + public void requestPresenceUpdatesFrom(Contact contact) { + //Requesting a Subscription type=subscribe + PresencePacket packet = new PresencePacket(); + packet.setAttribute("type", "subscribe"); + packet.setAttribute("to", contact.getJid()); + packet.setAttribute("from",contact.getAccount().getJid()); + Log.d(LOGTAG,packet.toString()); + contact.getAccount().getXmppConnection().sendPresencePacket(packet); + } + + public void stopPresenceUpdatesFrom(Contact contact) { + //Unsubscribing type='unsubscribe' + PresencePacket packet = new PresencePacket(); + packet.setAttribute("type", "unsubscribe"); + packet.setAttribute("to", contact.getJid()); + packet.setAttribute("from",contact.getAccount().getJid()); + Log.d(LOGTAG,packet.toString()); + contact.getAccount().getXmppConnection().sendPresencePacket(packet); + } + + public void stopPresenceUpdatesTo(Contact contact) { + //Canceling a Subscription type=unsubscribed + PresencePacket packet = new PresencePacket(); + packet.setAttribute("type", "unsubscribed"); + packet.setAttribute("to", contact.getJid()); + packet.setAttribute("from",contact.getAccount().getJid()); + Log.d(LOGTAG,packet.toString()); + contact.getAccount().getXmppConnection().sendPresencePacket(packet); + } + + public void sendPresenceUpdatesTo(Contact contact) { + //type='subscribed' + PresencePacket packet = new PresencePacket(); + packet.setAttribute("type", "subscribed"); + packet.setAttribute("to", contact.getJid()); + packet.setAttribute("from",contact.getAccount().getJid()); + Log.d(LOGTAG,packet.toString()); + contact.getAccount().getXmppConnection().sendPresencePacket(packet); + } } \ No newline at end of file diff --git a/src/de/gultsch/chat/ui/DialogContactDetails.java b/src/de/gultsch/chat/ui/DialogContactDetails.java index 20be4b397..8983a8730 100644 --- a/src/de/gultsch/chat/ui/DialogContactDetails.java +++ b/src/de/gultsch/chat/ui/DialogContactDetails.java @@ -13,6 +13,7 @@ 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.View; import android.view.View.OnClickListener; @@ -28,6 +29,9 @@ public class DialogContactDetails extends DialogFragment { private DialogContactDetails mDetailsDialog = this; private XmppActivity activity; + private CheckBox send; + private CheckBox receive; + private DialogInterface.OnClickListener askRemoveFromRoster = new DialogInterface.OnClickListener() { @Override @@ -64,6 +68,58 @@ public class DialogContactDetails extends DialogFragment { } }; + private DialogInterface.OnClickListener updateSubscriptions = new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + boolean needsUpdating = false; + if (contact.getSubscriptionOption(Contact.Subscription.FROM)) { + if (!send.isChecked()) { + contact.resetSubscriptionOption(Contact.Subscription.FROM); + contact.resetSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT); + activity.xmppConnectionService.stopPresenceUpdatesTo(contact); + needsUpdating=true; + } + } else { + if (contact.getSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT)) { + if (!send.isChecked()) { + contact.resetSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT); + needsUpdating=true; + } + } else { + if (send.isChecked()) { + contact.setSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT); + needsUpdating=true; + } + } + } + if (contact.getSubscriptionOption(Contact.Subscription.TO)) { + if (!receive.isChecked()) { + contact.resetSubscriptionOption(Contact.Subscription.TO); + activity.xmppConnectionService.stopPresenceUpdatesFrom(contact); + needsUpdating=true; + } + } else { + if (contact.getSubscriptionOption(Contact.Subscription.ASKING)) { + if (!receive.isChecked()) { + contact.resetSubscriptionOption(Contact.Subscription.ASKING); + activity.xmppConnectionService.stopPresenceUpdatesFrom(contact); + needsUpdating=true; + } + } else { + if (receive.isChecked()) { + contact.setSubscriptionOption(Contact.Subscription.ASKING); + activity.xmppConnectionService.requestPresenceUpdatesFrom(contact); + needsUpdating=true; + } + } + } + if (needsUpdating) { + activity.xmppConnectionService.updateContact(contact); + } + } + }; + public void setContact(Contact contact) { this.contact = contact; } @@ -77,21 +133,29 @@ public class DialogContactDetails extends DialogFragment { TextView contactJid = (TextView) view.findViewById(R.id.details_contactjid); TextView accountJid = (TextView) view.findViewById(R.id.details_account); TextView status = (TextView) view.findViewById(R.id.details_contactstatus); - CheckBox send = (CheckBox) view.findViewById(R.id.details_send_presence); - CheckBox receive = (CheckBox) view.findViewById(R.id.details_receive_presence); + send = (CheckBox) view.findViewById(R.id.details_send_presence); + receive = (CheckBox) view.findViewById(R.id.details_receive_presence); //ImageView contactPhoto = (ImageView) view.findViewById(R.id.details_contact_picture); QuickContactBadge badge = (QuickContactBadge) view.findViewById(R.id.details_contact_badge); - boolean subscriptionSend = false; - boolean subscriptionReceive = false; - if (contact.getSubscription()!=null) { - 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; + if (contact.getSubscriptionOption(Contact.Subscription.FROM)) { + send.setChecked(true); + } else { + send.setText("Preemptively grant subscription request"); + if (contact.getSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT)) { + send.setChecked(true); + } else { + send.setChecked(false); + } + } + if (contact.getSubscriptionOption(Contact.Subscription.TO)) { + receive.setChecked(true); + } else { + receive.setText("Request presence updates"); + if (contact.getSubscriptionOption(Contact.Subscription.ASKING)) { + receive.setChecked(true); + } else { + receive.setChecked(false); } } @@ -125,9 +189,6 @@ public class DialogContactDetails extends DialogFragment { status.setTextColor(0xFFe92727); break; } - - send.setChecked(subscriptionSend); - receive.setChecked(subscriptionReceive); contactJid.setText(contact.getJid()); accountJid.setText(contact.getAccount().getJid()); @@ -151,7 +212,7 @@ public class DialogContactDetails extends DialogFragment { builder.setView(view); builder.setTitle(contact.getDisplayName()); - builder.setNeutralButton("Done", null); + builder.setNeutralButton("Done", this.updateSubscriptions); builder.setPositiveButton("Remove from roster", this.askRemoveFromRoster); return builder.create(); }