Issue
Background
I've found that there is a way to open a specific contact conversation screen on WhatsApp, here .
Not only that, but I've found that an app called "href="https://play.google.com/store/apps/details?id=mobi.drupe.app&hl=en" rel="nofollow noreferrer">Drupe" does the same, and maybe even more :
The problem
I can't find any official API of opening it this way, so I'm not sure how safe it is.
I've found SDKs, but not intents instructions.
The questions
I'd like to know more about what's available for various social-networks and chatting apps :
- Facebook Messenger
- Viber
- Line
- Telegram
- Hangouts
Possible features may be:
- open the conversation of a contact, when input is his phone number
- have a new text that will be ready to be sent in the new screen
- for Facebook, maybe also be able to open using the Facebook-ID of the person (meaning this is the input), instead of a phone number.
Are such features available for each of those social networks and chatting apps?
Solution
For Facebook-messenger, I've found this (from https://developers.facebook.com/docs/messenger-platform/discovery/m-me-links#format):
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://m.me/" + facebookId));
It works, but I wonder if there is another way to access it (using phone number, for example).
For WhatsApp, I've found this (from here) :
final String formattedPhoneNumber = getFormattedPhoneNumber(this, phone);
final String contactId = getContactIdFromPhoneNumber(phone);
final String contactMimeTypeDataId = getContactMimeTypeDataId(contactId, "vnd.android.cursor.item/vnd.com.whatsapp.profile");
if (contactMimeTypeDataId != null) {
intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:" + formattedPhoneNumber));
intent.setPackage("com.whatsapp");
} else
Toast.makeText(this, "cannot find this contact on whatsapp", Toast.LENGTH_SHORT).show();
public static String getFormattedPhoneNumber(Context context, String input) {
final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
String normalizedPhone = input.replaceAll("[^0-9+]", "");
try {
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
String countryCode = tm.getSimCountryIso();
final PhoneNumber phoneNumber = phoneNumberUtil.parse(normalizedPhone, countryCode.toUpperCase());
final String formattedPhoneNumber = phoneNumberUtil.format(phoneNumber, PhoneNumberFormat.E164).replaceAll("[^0-9]", "");
return formattedPhoneNumber;
} catch (NumberParseException e) {
e.printStackTrace();
}
return null;
}
private String getContactIdFromPhoneNumber(String phone) {
if (TextUtils.isEmpty(phone))
return null;
final Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phone));
final ContentResolver contentResolver = getContentResolver();
final Cursor phoneQueryCursor = contentResolver.query(uri, new String[]{PhoneLookup._ID}, null, null, null);
if (phoneQueryCursor != null) {
if (phoneQueryCursor.moveToFirst()) {
String result = phoneQueryCursor.getString(phoneQueryCursor.getColumnIndex(PhoneLookup._ID));
phoneQueryCursor.close();
return result;
}
phoneQueryCursor.close();
}
return null;
}
public String getContactMimeTypeDataId(@NonNull Context context, String contactId, @NonNull String mimeType) {
if (TextUtils.isEmpty(mimeType))
return null;
ContentResolver cr = context.getContentResolver();
Cursor cursor = cr.query(ContactsContract.Data.CONTENT_URI, new String[]{Data._ID}, Data.MIMETYPE + "= ? AND "
+ ContactsContract.Data.CONTACT_ID + "= ?", new String[]{mimeType, contactId}, null);
if (cursor == null)
return null;
if (!cursor.moveToFirst()) {
cursor.close();
return null;
}
String result = cursor.getString(cursor.getColumnIndex(Data._ID));
cursor.close();
return result;
}
It works, but it doesn't add the message. It also might say the contact doesn't have WhatsApp.
It's also possible to just use the phone number, as I wrote here.
For Viber, I've found this (from here) :
final String contactId = getContactIdFromPhoneNumber(phone);
final String contactMimeTypeDataId = getContactMimeTypeDataId(contactId, "vnd.android.cursor.item/vnd.com.viber.voip.viber_number_message");
if (contactMimeTypeDataId != null) {
intent = new Intent(Intent.ACTION_VIEW, Uri.parse("content://com.android.contacts/data/" + contactMimeTypeDataId));
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
intent.setPackage("com.viber.voip");
} else {
intent = new Intent("android.intent.action.VIEW", Uri.parse("tel:" + Uri.encode(formattedPhoneNumber)));
intent.setClassName("com.viber.voip", "com.viber.voip.WelcomeActivity");
}
private String getContactIdFromPhoneNumber(String phone) {
final Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phone));
final ContentResolver contentResolver = getContentResolver();
final Cursor phoneQueryCursor = contentResolver.query(uri, new String[]{PhoneLookup._ID}, null, null, null);
if (phoneQueryCursor != null) {
if (phoneQueryCursor.moveToFirst()) {
String result = phoneQueryCursor.getString(phoneQueryCursor.getColumnIndex(PhoneLookup._ID));
phoneQueryCursor.close();
return result;
}
phoneQueryCursor.close();
}
return null;
}
For Hangouts, it seems it's similar to Viber, but with this mimetype: "vnd.android.cursor.item/vnd.googleplus.profile.comm". Yet, it doesn't work as it probably needs additional steps (setting G+ to keep contacts updated and have the contacts in the G+ circles). However, I've somehow succeeded to open the video chat of a person:
intent =new Intent(Intent.ACTION_VIEW,Uri.parse("content://com.android.contacts/data/"+contactMimeTypeDataId));
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT |Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
For Telegram, someone (here) suggested using the next code, but it doesn't work:
intent = new Intent(android.content.Intent.ACTION_SENDUri.parse("http://telegram.me/"+profile)));
intent.setPackage("org.telegram.messenger");
It's also possible to just use the phone number, as I wrote here.
For Line, I've found these (based on here and here), but none work:
Intent intent = new Intent("jp.naver.line.android.intent.action.LINESHORTCUT");
intent.putExtra("shortcutType", "chatmid");
intent.putExtra("shortcutTargetId", target);
intent.putExtra("shortcutTargetName", "");
intent.putExtra("shortcutFromOS", false);
startActivity(intent);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse("line://msg/text/" + getMongon()));
skype: this one works (found from various links, here, for example):
final String skypeUserName = getSkypeUserName(phone);
intent = new Intent(Intent.ACTION_VIEW, Uri.parse("skype:" + skypeUserName + "?chat"));
public String getSkypeUserName(String phoneNumber) {
if (TextUtils.isEmpty(phoneNumber))
return null;
ContentResolver cr = getContentResolver();
final Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
Cursor cursor = cr.query(uri, new String[]{PhoneLookup.LOOKUP_KEY}, null, null, null);
if (cursor == null)
return null;
final Set<String> contactKeys = new HashSet<>();
// get contact keys
{
final int contactKeyIdx = cursor.getColumnIndex(PhoneLookup.LOOKUP_KEY);
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
String contactKey = cursor.getString(contactKeyIdx);
contactKeys.add(contactKey);
}
cursor.close();
}
if (contactKeys.isEmpty())
return null;
//get raw ids
final Set<String> contactRawIdsSet = new HashSet<>();
{
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < contactKeys.size(); ++i)
sb.append(sb.length() == 0 ? "?" : ",?");
String inParameters = sb.toString();
final String[] selectionArgs = contactKeys.toArray(new String[contactKeys.size()]);
cursor = cr.query(ContactsContract.Data.CONTENT_URI, new String[]{ContactsContract.Data.RAW_CONTACT_ID}, ContactsContract.Data.LOOKUP_KEY + " IN (" + inParameters + ")", selectionArgs, null);
if (cursor == null)
return null;
final int rawContactColIdx = cursor.getColumnIndex(ContactsContract.Data.RAW_CONTACT_ID);
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
String rawContactId = cursor.getString(rawContactColIdx);
contactRawIdsSet.add(rawContactId);
}
cursor.close();
}
if (contactRawIdsSet.isEmpty())
return null;
//find the skype name
//TODO think of a better way to query, as it looks weird to search within a set of ids...
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < contactRawIdsSet.size(); ++i)
sb.append(sb.length() == 0 ? "?" : ",?");
String inParameters = sb.toString();
final String[] selectionArgs = new String[2 + contactRawIdsSet.size()];
selectionArgs[0] = "com.skype.contacts.sync";
selectionArgs[1] = "vnd.android.cursor.item/name";
int i = 2;
for (String rawId : contactRawIdsSet)
selectionArgs[i++] = rawId;
cursor = cr.query(ContactsContract.Data.CONTENT_URI, new String[]{RawContacts.SOURCE_ID}, ContactsContract.RawContacts.ACCOUNT_TYPE + " = ? AND " + Data.MIMETYPE + " = ? AND " +
ContactsContract.Data.CONTACT_ID + " IN (" + inParameters + ")", selectionArgs, null);
if (cursor == null)
return null;
if (!cursor.moveToFirst()) {
cursor.close();
return null;
}
String result = cursor.getString(cursor.getColumnIndex(RawContacts.SOURCE_ID));
cursor.close();
return result;
}
Answered By - android developer
Answer Checked By - Cary Denson (JavaFixing Admin)