Show commands for XMPP video chat for Google Talk
Change-Id: I8ff105ff42ffa89b81500f386db3279ffde5fe80
diff --git a/res/drawable-mdpi/sym_action_audiochat.png b/res/drawable-mdpi/sym_action_audiochat.png
new file mode 100644
index 0000000..9bbaa37
--- /dev/null
+++ b/res/drawable-mdpi/sym_action_audiochat.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_action_videochat.png b/res/drawable-mdpi/sym_action_videochat.png
new file mode 100644
index 0000000..84e1b98
--- /dev/null
+++ b/res/drawable-mdpi/sym_action_videochat.png
Binary files differ
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
index 68e7c6a..2bc2721 100644
--- a/src/com/android/contacts/ContactsUtils.java
+++ b/src/com/android/contacts/ContactsUtils.java
@@ -16,7 +16,6 @@
package com.android.contacts;
-
import com.android.contacts.model.ContactsSource;
import com.android.contacts.util.Constants;
@@ -238,33 +237,104 @@
return null;
}
+ public static final class ImActions {
+ private final Intent mPrimaryIntent;
+ private final Intent mSecondaryIntent;
+ private final int mPrimaryActionIcon;
+ private final int mSecondaryActionIcon;
+
+ private ImActions(Intent primaryIntent, Intent secondaryIntent, int primaryActionIcon,
+ int secondaryActionIcon) {
+ mPrimaryIntent = primaryIntent;
+ mSecondaryIntent = secondaryIntent;
+ mPrimaryActionIcon = primaryActionIcon;
+ mSecondaryActionIcon = secondaryActionIcon;
+ }
+
+ public Intent getPrimaryIntent() {
+ return mPrimaryIntent;
+ }
+
+ public Intent getSecondaryIntent() {
+ return mSecondaryIntent;
+ }
+
+ public int getPrimaryActionIcon() {
+ return mPrimaryActionIcon;
+ }
+
+ public int getSecondaryActionIcon() {
+ return mSecondaryActionIcon;
+ }
+ }
+
/**
* Build {@link Intent} to launch an action for the given {@link Im} or
- * {@link Email} row. Returns null when missing protocol or data.
+ * {@link Email} row. If the result is non-null, it either contains one or two Intents
+ * (e.g. [Text, Videochat] or just [Text])
+ * Returns null when missing protocol or data.
*/
- public static Intent buildImIntent(ContentValues values) {
+ public static ImActions buildImActions(ContentValues values) {
final boolean isEmail = Email.CONTENT_ITEM_TYPE.equals(values.getAsString(Data.MIMETYPE));
if (!isEmail && !isProtocolValid(values)) {
return null;
}
+ final String data = values.getAsString(isEmail ? Email.DATA : Im.DATA);
+ if (TextUtils.isEmpty(data)) return null;
+
final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK : values.getAsInteger(Im.PROTOCOL);
- String host = values.getAsString(Im.CUSTOM_PROTOCOL);
- String data = values.getAsString(isEmail ? Email.DATA : Im.DATA);
- if (protocol != Im.PROTOCOL_CUSTOM) {
- // Try bringing in a well-known host for specific protocols
- host = ContactsUtils.lookupProviderNameFromId(protocol);
- }
-
- if (!TextUtils.isEmpty(host) && !TextUtils.isEmpty(data)) {
- final String authority = host.toLowerCase();
- final Uri imUri = new Uri.Builder().scheme(Constants.SCHEME_IMTO).authority(
- authority).appendPath(data).build();
- return new Intent(Intent.ACTION_SENDTO, imUri);
+ if (protocol == Im.PROTOCOL_GOOGLE_TALK) {
+ final Integer chatCapabilityObj = values.getAsInteger(Im.CHAT_CAPABILITY);
+ final int chatCapability = chatCapabilityObj == null ? 0 : chatCapabilityObj;
+ if ((chatCapability & Im.CAPABILITY_HAS_CAMERA) != 0) {
+ // Allow Video chat and Texting
+ return new ImActions(
+ new Intent(Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?message")),
+ new Intent(Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?call")),
+ android.R.drawable.sym_action_chat,
+ R.drawable.sym_action_videochat
+ );
+ } else if ((chatCapability & Im.CAPABILITY_HAS_VOICE) != 0) {
+ // Allow Talking and Texting
+ return new ImActions(
+ new Intent(Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?message")),
+ new Intent(Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?call")),
+ android.R.drawable.sym_action_chat,
+ R.drawable.sym_action_audiochat
+ );
+ } else {
+ return new ImActions(
+ new Intent(Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?message")),
+ null,
+ android.R.drawable.sym_action_chat,
+ -1
+ );
+ }
} else {
- return null;
+ // Build an IM Intent
+ String host = values.getAsString(Im.CUSTOM_PROTOCOL);
+
+ if (protocol != Im.PROTOCOL_CUSTOM) {
+ // Try bringing in a well-known host for specific protocols
+ host = ContactsUtils.lookupProviderNameFromId(protocol);
+ }
+
+ if (!TextUtils.isEmpty(host)) {
+ final String authority = host.toLowerCase();
+ final Uri imUri = new Uri.Builder().scheme(Constants.SCHEME_IMTO).authority(
+ authority).appendPath(data).build();
+ return new ImActions(
+ new Intent(Intent.ACTION_SENDTO, imUri),
+ null,
+ android.R.drawable.sym_action_chat,
+ -1
+ );
+ } else {
+ return null;
+ }
}
}
diff --git a/src/com/android/contacts/views/ContactLoader.java b/src/com/android/contacts/views/ContactLoader.java
index f3666a8..1cb003e 100644
--- a/src/com/android/contacts/views/ContactLoader.java
+++ b/src/com/android/contacts/views/ContactLoader.java
@@ -250,12 +250,12 @@
GroupMembership.GROUP_SOURCE_ID,
Data.PRESENCE,
+ Data.CHAT_CAPABILITY,
Data.STATUS,
Data.STATUS_RES_PACKAGE,
Data.STATUS_ICON,
Data.STATUS_LABEL,
- Data.STATUS_TIMESTAMP,
-
+ Data.STATUS_TIMESTAMP
};
public final static int NAME_RAW_CONTACT_ID = 0;
@@ -315,7 +315,8 @@
public final static int GROUP_SOURCE_ID = 51;
public final static int PRESENCE = 52;
- public final static int STATUS = 53;
+ public final static int CHAT_CAPABILITY = 53;
+ public final static int STATUS = 54;
}
private final class LoadContactTask extends AsyncTask<Void, Void, Result> {
@@ -510,6 +511,7 @@
cursorColumnToContentValues(cursor, cv, ContactQuery.MIMETYPE);
cursorColumnToContentValues(cursor, cv, ContactQuery.RES_PACKAGE);
cursorColumnToContentValues(cursor, cv, ContactQuery.GROUP_SOURCE_ID);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.CHAT_CAPABILITY);
return cv;
}
diff --git a/src/com/android/contacts/views/detail/ContactDetailFragment.java b/src/com/android/contacts/views/detail/ContactDetailFragment.java
index b838f74..d61b346 100644
--- a/src/com/android/contacts/views/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/views/detail/ContactDetailFragment.java
@@ -20,6 +20,7 @@
import com.android.contacts.ContactOptionsActivity;
import com.android.contacts.ContactPresenceIconUtil;
import com.android.contacts.ContactsUtils;
+import com.android.contacts.ContactsUtils.ImActions;
import com.android.contacts.R;
import com.android.contacts.TypePrecedence;
import com.android.contacts.Collapser.Collapsible;
@@ -33,7 +34,6 @@
import com.android.internal.telephony.ITelephony;
import android.app.Activity;
-import android.app.Dialog;
import android.app.Fragment;
import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
@@ -41,7 +41,6 @@
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Entity;
import android.content.Intent;
import android.content.Loader;
@@ -353,7 +352,13 @@
imMime, mContext, ContactsSource.LEVEL_MIMETYPES);
final ViewEntry imEntry = ViewEntry.fromValues(mContext,
imMime, imKind, rawContactId, dataId, entryValues);
- imEntry.intent = ContactsUtils.buildImIntent(entryValues);
+ final ImActions imActions = ContactsUtils.buildImActions(entryValues);
+ if (imActions != null) {
+ imEntry.actionIcon = imActions.getPrimaryActionIcon();
+ imEntry.secondaryActionIcon = imActions.getSecondaryActionIcon();
+ imEntry.intent = imActions.getPrimaryIntent();
+ imEntry.secondaryIntent = imActions.getSecondaryIntent();
+ }
imEntry.applyStatus(status, false);
mImEntries.add(imEntry);
}
@@ -364,7 +369,13 @@
mPostalEntries.add(entry);
} else if (Im.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
// Build IM entries
- entry.intent = ContactsUtils.buildImIntent(entryValues);
+ final ImActions imActions = ContactsUtils.buildImActions(entryValues);
+ if (imActions != null) {
+ entry.actionIcon = imActions.getPrimaryActionIcon();
+ entry.secondaryActionIcon = imActions.getSecondaryActionIcon();
+ entry.intent = imActions.getPrimaryIntent();
+ entry.secondaryIntent = imActions.getSecondaryIntent();
+ }
if (TextUtils.isEmpty(entry.label)) {
entry.label = mContext.getString(R.string.chat).toLowerCase();
}
@@ -883,13 +894,6 @@
mListener.onItemClicked(intent);
}
- private final DialogInterface.OnClickListener mDeleteListener =
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- mContext.getContentResolver().delete(mContactData.getLookupUri(), null, null);
- }
- };
-
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
diff --git a/tests/src/com/android/contacts/ContactLoaderTest.java b/tests/src/com/android/contacts/ContactLoaderTest.java
index a33d4ed..3ef109d 100644
--- a/tests/src/com/android/contacts/ContactLoaderTest.java
+++ b/tests/src/com/android/contacts/ContactLoaderTest.java
@@ -291,7 +291,7 @@
GroupMembership.GROUP_SOURCE_ID,
- Data.PRESENCE,
+ Data.PRESENCE, Data.CHAT_CAPABILITY,
Data.STATUS, Data.STATUS_RES_PACKAGE, Data.STATUS_ICON,
Data.STATUS_LABEL, Data.STATUS_TIMESTAMP,
})
@@ -323,7 +323,7 @@
"groupId",
- StatusUpdates.INVISIBLE,
+ StatusUpdates.INVISIBLE, null,
"Having dinner", "mockPkg3", 0,
20, 0
);
diff --git a/tests/src/com/android/contacts/ContactsUtilsTests.java b/tests/src/com/android/contacts/ContactsUtilsTests.java
index 8e18044..7e85c32 100644
--- a/tests/src/com/android/contacts/ContactsUtilsTests.java
+++ b/tests/src/com/android/contacts/ContactsUtilsTests.java
@@ -16,6 +16,8 @@
package com.android.contacts;
+import com.android.contacts.ContactsUtils.ImActions;
+
import android.content.ContentValues;
import android.content.Intent;
import android.net.Uri;
@@ -34,24 +36,63 @@
private static final String TEST_PROTOCOL = "prot%col";
public void testImIntent() throws Exception {
- // Normal IM is appended as path
+ // Test GTalk XMPP URI. No chat capabilities provided
final ContentValues values = new ContentValues();
values.put(Im.MIMETYPE, Im.CONTENT_ITEM_TYPE);
values.put(Im.TYPE, Im.TYPE_HOME);
values.put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
values.put(Im.DATA, TEST_ADDRESS);
- final Intent intent = ContactsUtils.buildImIntent(values);
+ final ImActions imActions = ContactsUtils.buildImActions(values);
+ final Intent intent = imActions.getPrimaryIntent();
assertEquals(Intent.ACTION_SENDTO, intent.getAction());
+ assertEquals("xmpp:" + TEST_ADDRESS + "?message", intent.getData().toString());
- final Uri data = intent.getData();
- assertEquals("imto", data.getScheme());
- assertEquals("gtalk", data.getAuthority());
- assertEquals(TEST_ADDRESS, data.getPathSegments().get(0));
+ assertNull(imActions.getSecondaryIntent());
+ }
+
+ public void testImIntentWithAudio() throws Exception {
+ // Test GTalk XMPP URI. Audio chat capabilities provided
+ final ContentValues values = new ContentValues();
+ values.put(Im.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ values.put(Im.TYPE, Im.TYPE_HOME);
+ values.put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
+ values.put(Im.DATA, TEST_ADDRESS);
+ values.put(Im.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO);
+
+ final ImActions imActions = ContactsUtils.buildImActions(values);
+ final Intent primaryIntent = imActions.getPrimaryIntent();
+ assertEquals(Intent.ACTION_SENDTO, primaryIntent.getAction());
+ assertEquals("xmpp:" + TEST_ADDRESS + "?message", primaryIntent.getData().toString());
+
+ final Intent secondaryIntent = imActions.getSecondaryIntent();
+ assertEquals(Intent.ACTION_SENDTO, secondaryIntent.getAction());
+ assertEquals("xmpp:" + TEST_ADDRESS + "?call", secondaryIntent.getData().toString());
+ }
+
+ public void testImIntentWithVideo() throws Exception {
+ // Test GTalk XMPP URI. Video chat capabilities provided
+ final ContentValues values = new ContentValues();
+ values.put(Im.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ values.put(Im.TYPE, Im.TYPE_HOME);
+ values.put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
+ values.put(Im.DATA, TEST_ADDRESS);
+ values.put(Im.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO |
+ Im.CAPABILITY_HAS_VOICE);
+
+ final ImActions imActions = ContactsUtils.buildImActions(values);
+ final Intent primaryIntent = imActions.getPrimaryIntent();
+ assertEquals(Intent.ACTION_SENDTO, primaryIntent.getAction());
+ assertEquals("xmpp:" + TEST_ADDRESS + "?message", primaryIntent.getData().toString());
+
+ final Intent secondaryIntent = imActions.getSecondaryIntent();
+ assertEquals(Intent.ACTION_SENDTO, secondaryIntent.getAction());
+ assertEquals("xmpp:" + TEST_ADDRESS + "?call", secondaryIntent.getData().toString());
}
public void testImIntentCustom() throws Exception {
- // Custom IM types have encoded authority
+ // Custom IM types have encoded authority. We send the imto Intent here, because
+ // legacy third party apps might not accept xmpp yet
final ContentValues values = new ContentValues();
values.put(Im.MIMETYPE, Im.CONTENT_ITEM_TYPE);
values.put(Im.TYPE, Im.TYPE_HOME);
@@ -59,29 +100,37 @@
values.put(Im.CUSTOM_PROTOCOL, TEST_PROTOCOL);
values.put(Im.DATA, TEST_ADDRESS);
- final Intent intent = ContactsUtils.buildImIntent(values);
+ final ImActions actions = ContactsUtils.buildImActions(values);
+ final Intent intent = actions.getPrimaryIntent();
assertEquals(Intent.ACTION_SENDTO, intent.getAction());
final Uri data = intent.getData();
assertEquals("imto", data.getScheme());
assertEquals(TEST_PROTOCOL, data.getAuthority());
assertEquals(TEST_ADDRESS, data.getPathSegments().get(0));
+
+ assertNull(actions.getSecondaryIntent());
}
public void testImEmailIntent() throws Exception {
// Email addresses are treated as Google Talk entries
+ // This test only tests the VIDEO+CAMERA case. The other cases have been addressed by the
+ // Im tests
final ContentValues values = new ContentValues();
values.put(Email.MIMETYPE, Email.CONTENT_ITEM_TYPE);
values.put(Email.TYPE, Email.TYPE_HOME);
values.put(Email.DATA, TEST_ADDRESS);
+ values.put(Email.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO |
+ Im.CAPABILITY_HAS_VOICE);
- final Intent intent = ContactsUtils.buildImIntent(values);
- assertEquals(Intent.ACTION_SENDTO, intent.getAction());
+ final ImActions imActions = ContactsUtils.buildImActions(values);
+ final Intent primaryIntent = imActions.getPrimaryIntent();
+ assertEquals(Intent.ACTION_SENDTO, primaryIntent.getAction());
+ assertEquals("xmpp:" + TEST_ADDRESS + "?message", primaryIntent.getData().toString());
- final Uri data = intent.getData();
- assertEquals("imto", data.getScheme());
- assertEquals("gtalk", data.getAuthority());
- assertEquals(TEST_ADDRESS, data.getPathSegments().get(0));
+ final Intent secondaryIntent = imActions.getSecondaryIntent();
+ assertEquals(Intent.ACTION_SENDTO, secondaryIntent.getAction());
+ assertEquals("xmpp:" + TEST_ADDRESS + "?call", secondaryIntent.getData().toString());
}
public void testIsGraphicNull() throws Exception {