blob: 4898ab2438e0cb551aa11d89f2b104ef42153f1f [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.cts.verifier.notifications;
import static com.android.cts.verifier.notifications.MockListener.JSON_AMBIENT;
import static com.android.cts.verifier.notifications.MockListener.JSON_MATCHES_ZEN_FILTER;
import static com.android.cts.verifier.notifications.MockListener.JSON_TAG;
import android.app.Notification;
import android.content.ContentProviderOperation;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.service.notification.NotificationListenerService;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.android.cts.verifier.R;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class AttentionManagementVerifierActivity
extends InteractiveVerifierActivity {
private static final String TAG = "NoListenerAttentionVerifier";
private static final String ALICE = "Alice";
private static final String ALICE_PHONE = "+16175551212";
private static final String ALICE_EMAIL = "alice@_foo._bar";
private static final String BOB = "Bob";
private static final String BOB_PHONE = "+16505551212";;
private static final String BOB_EMAIL = "bob@_foo._bar";
private static final String CHARLIE = "Charlie";
private static final String CHARLIE_PHONE = "+13305551212";
private static final String CHARLIE_EMAIL = "charlie@_foo._bar";
private static final int MODE_NONE = 0;
private static final int MODE_URI = 1;
private static final int MODE_PHONE = 2;
private static final int MODE_EMAIL = 3;
private Uri mAliceUri;
private Uri mBobUri;
private Uri mCharlieUri;
@Override
int getTitleResource() {
return R.string.attention_test;
}
@Override
int getInstructionsResource() {
return R.string.attention_info;
}
// Test Setup
@Override
protected List<InteractiveTestCase> createTestItems() {
List<InteractiveTestCase> tests = new ArrayList<>(17);
tests.add(new IsEnabledTest());
tests.add(new ServiceStartedTest());
tests.add(new InsertContactsTest());
tests.add(new SetModeNoneTest());
tests.add(new NoneInterceptsAllTest());
tests.add(new SetModeAllTest());
tests.add(new SetModePriorityTest());
tests.add(new PriorityInterceptsSomeTest());
tests.add(new SetModeAllTest());
tests.add(new AllInterceptsNothingTest());
tests.add(new DefaultOrderTest());
tests.add(new PrioritytOrderTest());
tests.add(new InterruptionOrderTest());
tests.add(new AmbientBitsTest());
tests.add(new LookupUriOrderTest());
tests.add(new EmailOrderTest());
tests.add(new PhoneOrderTest());
tests.add(new DeleteContactsTest());
return tests;
}
// Tests
protected class InsertContactsTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createAutoItem(parent, R.string.attention_create_contacts);
}
@Override
void setUp() {
insertSingleContact(ALICE, ALICE_PHONE, ALICE_EMAIL, true);
insertSingleContact(BOB, BOB_PHONE, BOB_EMAIL, false);
// charlie is not in contacts
status = READY;
// wait for insertions to move through the system
delay();
}
@Override
void test() {
mAliceUri = lookupContact(ALICE_PHONE);
mBobUri = lookupContact(BOB_PHONE);
mCharlieUri = lookupContact(CHARLIE_PHONE);
status = PASS;
if (mAliceUri == null) { status = FAIL; }
if (mBobUri == null) { status = FAIL; }
if (mCharlieUri != null) { status = FAIL; }
next();
}
}
protected class DeleteContactsTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createAutoItem(parent, R.string.attention_delete_contacts);
}
@Override
void test() {
final ArrayList<ContentProviderOperation> operationList = new ArrayList<>();
operationList.add(ContentProviderOperation.newDelete(mAliceUri).build());
operationList.add(ContentProviderOperation.newDelete(mBobUri).build());
try {
mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList);
status = READY;
} catch (RemoteException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
status = FAIL;
} catch (OperationApplicationException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
status = FAIL;
}
status = PASS;
next();
}
}
protected class SetModeNoneTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createRetryItem(parent, R.string.attention_filter_none);
}
@Override
void test() {
MockListener.probeFilter(mContext,
new MockListener.IntegerResultCatcher() {
@Override
public void accept(int mode) {
if (mode == NotificationListenerService.INTERRUPTION_FILTER_NONE) {
status = PASS;
next();
} else {
Log.i("SetModeNoneTest", "waiting, current mode is: " + mode);
status = WAIT_FOR_USER;
}
}
});
}
@Override
void tearDown() {
mNm.cancelAll();
MockListener.resetListenerData(mContext);
delay();
}
}
protected class NoneInterceptsAllTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createAutoItem(parent, R.string.attention_all_are_filtered);
}
@Override
void setUp() {
sendNotifications(MODE_URI, false, false);
status = READY;
// wait for notifications to move through the system
delay();
}
@Override
void test() {
MockListener.probeListenerPayloads(mContext,
new MockListener.StringListResultCatcher() {
@Override
public void accept(List<String> result) {
Set<String> found = new HashSet<String>();
if (result == null || result.size() == 0) {
status = FAIL;
next();
return;
}
boolean pass = true;
for (String payloadData : result) {
try {
JSONObject payload = new JSONObject(payloadData);
String tag = payload.getString(JSON_TAG);
boolean zen = payload.getBoolean(JSON_MATCHES_ZEN_FILTER);
Log.e(TAG, tag + (zen ? "" : " not") + " intercepted");
if (found.contains(tag)) {
// multiple entries for same notification!
pass = false;
} else if (ALICE.equals(tag)) {
found.add(ALICE);
pass &= !zen;
} else if (BOB.equals(tag)) {
found.add(BOB);
pass &= !zen;
} else if (CHARLIE.equals(tag)) {
found.add(CHARLIE);
pass &= !zen;
}
} catch (JSONException e) {
pass = false;
Log.e(TAG, "failed to unpack data from mocklistener", e);
}
}
pass &= found.size() == 3;
status = pass ? PASS : FAIL;
next();
}
});
delay(); // in case the catcher never returns
}
@Override
void tearDown() {
mNm.cancelAll();
MockListener.resetListenerData(mContext);
delay();
}
}
protected class SetModeAllTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createRetryItem(parent, R.string.attention_filter_all);
}
@Override
void test() {
MockListener.probeFilter(mContext,
new MockListener.IntegerResultCatcher() {
@Override
public void accept(int mode) {
if (mode == NotificationListenerService.INTERRUPTION_FILTER_ALL) {
status = PASS;
next();
} else {
Log.i("SetModeAllTest", "waiting, current mode is: " + mode);
status = WAIT_FOR_USER;
}
}
});
}
}
protected class AllInterceptsNothingTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createAutoItem(parent, R.string.attention_none_are_filtered);
}
@Override
void setUp() {
sendNotifications(MODE_URI, false, false);
status = READY;
// wait for notifications to move through the system
delay();
}
@Override
void test() {
MockListener.probeListenerPayloads(mContext,
new MockListener.StringListResultCatcher() {
@Override
public void accept(List<String> result) {
Set<String> found = new HashSet<String>();
if (result == null || result.size() == 0) {
status = FAIL;
return;
}
boolean pass = true;
for (String payloadData : result) {
try {
JSONObject payload = new JSONObject(payloadData);
String tag = payload.getString(JSON_TAG);
boolean zen = payload.getBoolean(JSON_MATCHES_ZEN_FILTER);
Log.e(TAG, tag + (zen ? "" : " not") + " intercepted");
if (found.contains(tag)) {
// multiple entries for same notification!
pass = false;
} else if (ALICE.equals(tag)) {
found.add(ALICE);
pass &= zen;
} else if (BOB.equals(tag)) {
found.add(BOB);
pass &= zen;
} else if (CHARLIE.equals(tag)) {
found.add(CHARLIE);
pass &= zen;
}
} catch (JSONException e) {
pass = false;
Log.e(TAG, "failed to unpack data from mocklistener", e);
}
}
pass &= found.size() == 3;
status = pass ? PASS : FAIL;
next();
}
});
delay(); // in case the catcher never returns
}
@Override
void tearDown() {
mNm.cancelAll();
MockListener.resetListenerData(mContext);
delay();
}
}
protected class SetModePriorityTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createRetryItem(parent, R.string.attention_filter_priority);
}
@Override
void test() {
MockListener.probeFilter(mContext,
new MockListener.IntegerResultCatcher() {
@Override
public void accept(int mode) {
if (mode == NotificationListenerService.INTERRUPTION_FILTER_PRIORITY) {
status = PASS;
next();
} else {
Log.i("SetModePriorityTest", "waiting, current mode is: " + mode);
status = WAIT_FOR_USER;
}
}
});
}
}
protected class PriorityInterceptsSomeTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createAutoItem(parent, R.string.attention_some_are_filtered);
}
@Override
void setUp() {
sendNotifications(MODE_URI, false, false);
status = READY;
// wait for notifications to move through the system
delay();
}
@Override
void test() {
MockListener.probeListenerPayloads(mContext,
new MockListener.StringListResultCatcher() {
@Override
public void accept(List<String> result) {
Set<String> found = new HashSet<String>();
if (result == null || result.size() == 0) {
status = FAIL;
return;
}
boolean pass = true;
for (String payloadData : result) {
try {
JSONObject payload = new JSONObject(payloadData);
String tag = payload.getString(JSON_TAG);
boolean zen = payload.getBoolean(JSON_MATCHES_ZEN_FILTER);
Log.e(TAG, tag + (zen ? "" : " not") + " intercepted");
if (found.contains(tag)) {
// multiple entries for same notification!
pass = false;
} else if (ALICE.equals(tag)) {
found.add(ALICE);
pass &= zen;
} else if (BOB.equals(tag)) {
found.add(BOB);
pass &= !zen;
} else if (CHARLIE.equals(tag)) {
found.add(CHARLIE);
pass &= !zen;
}
} catch (JSONException e) {
pass = false;
Log.e(TAG, "failed to unpack data from mocklistener", e);
}
}
pass &= found.size() == 3;
status = pass ? PASS : FAIL;
next();
}
});
delay(); // in case the catcher never returns
}
@Override
void tearDown() {
mNm.cancelAll();
MockListener.resetListenerData(mContext);
delay();
}
}
// ordered by time: C, B, A
protected class DefaultOrderTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createAutoItem(parent, R.string.attention_default_order);
}
@Override
void setUp() {
sendNotifications(MODE_NONE, false, false);
status = READY;
// wait for notifications to move through the system
delay();
}
@Override
void test() {
MockListener.probeListenerOrder(mContext,
new MockListener.StringListResultCatcher() {
@Override
public void accept(List<String> orderedKeys) {
int rankA = findTagInKeys(ALICE, orderedKeys);
int rankB = findTagInKeys(BOB, orderedKeys);
int rankC = findTagInKeys(CHARLIE, orderedKeys);
if (rankC < rankB && rankB < rankA) {
status = PASS;
} else {
logFail(rankA + ", " + rankB + ", " + rankC);
status = FAIL;
}
next();
}
});
delay(); // in case the catcher never returns
}
@Override
void tearDown() {
mNm.cancelAll();
MockListener.resetListenerData(mContext);
delay();
}
}
// ordered by priority: B, C, A
protected class PrioritytOrderTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createAutoItem(parent, R.string.attention_priority_order);
}
@Override
void setUp() {
sendNotifications(MODE_NONE, true, false);
status = READY;
// wait for notifications to move through the system
delay();
}
@Override
void test() {
MockListener.probeListenerOrder(mContext,
new MockListener.StringListResultCatcher() {
@Override
public void accept(List<String> orderedKeys) {
int rankA = findTagInKeys(ALICE, orderedKeys);
int rankB = findTagInKeys(BOB, orderedKeys);
int rankC = findTagInKeys(CHARLIE, orderedKeys);
if (rankB < rankC && rankC < rankA) {
status = PASS;
} else {
logFail(rankA + ", " + rankB + ", " + rankC);
status = FAIL;
}
next();
}
});
delay(); // in case the catcher never returns
}
@Override
void tearDown() {
mNm.cancelAll();
MockListener.resetListenerData(mContext);
delay();
}
}
// A starts at the top then falls to the bottom
protected class InterruptionOrderTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createAutoItem(parent, R.string.attention_interruption_order);
}
@Override
void setUp() {
sendNotifications(MODE_NONE, false, true);
status = READY;
// wait for notifications to move through the system
delay();
}
@Override
void test() {
if (status == READY) {
MockListener.probeListenerOrder(mContext,
new MockListener.StringListResultCatcher() {
@Override
public void accept(List<String> orderedKeys) {
int rankA = findTagInKeys(ALICE, orderedKeys);
int rankB = findTagInKeys(BOB, orderedKeys);
int rankC = findTagInKeys(CHARLIE, orderedKeys);
if (rankA < rankB && rankA < rankC) {
status = RETEST;
delay(12000);
} else {
logFail("noisy notification did not sort to top.");
status = FAIL;
next();
}
}
});
delay(); // in case the catcher never returns
} else {
MockListener.probeListenerOrder(mContext,
new MockListener.StringListResultCatcher() {
@Override
public void accept(List<String> orderedKeys) {
int rankA = findTagInKeys(ALICE, orderedKeys);
int rankB = findTagInKeys(BOB, orderedKeys);
int rankC = findTagInKeys(CHARLIE, orderedKeys);
if (rankA > rankB && rankA > rankC) {
status = PASS;
} else {
logFail("noisy notification did not fade back into the list.");
status = FAIL;
}
next();
}
});
delay(); // in case the catcher never returns
}
}
@Override
void tearDown() {
mNm.cancelAll();
MockListener.resetListenerData(mContext);
delay();
}
}
// B & C above the fold, A below
protected class AmbientBitsTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createAutoItem(parent, R.string.attention_ambient_bit);
}
@Override
void setUp() {
sendNotifications(MODE_NONE, true, false);
status = READY;
// wait for notifications to move through the system
delay();
}
@Override
void test() {
MockListener.probeListenerPayloads(mContext,
new MockListener.StringListResultCatcher() {
@Override
public void accept(List<String> result) {
Set<String> found = new HashSet<String>();
if (result == null || result.size() == 0) {
status = FAIL;
return;
}
boolean pass = true;
for (String payloadData : result) {
try {
JSONObject payload = new JSONObject(payloadData);
String tag = payload.getString(JSON_TAG);
boolean ambient = payload.getBoolean(JSON_AMBIENT);
Log.e(TAG, tag + (ambient ? " is" : " isn't") + " ambient");
if (found.contains(tag)) {
// multiple entries for same notification!
pass = false;
} else if (ALICE.equals(tag)) {
found.add(ALICE);
pass &= ambient;
} else if (BOB.equals(tag)) {
found.add(BOB);
pass &= !ambient;
} else if (CHARLIE.equals(tag)) {
found.add(CHARLIE);
pass &= !ambient;
}
} catch (JSONException e) {
pass = false;
Log.e(TAG, "failed to unpack data from mocklistener", e);
}
}
pass &= found.size() == 3;
status = pass ? PASS : FAIL;
next();
}
});
delay(); // in case the catcher never returns
}
@Override
void tearDown() {
mNm.cancelAll();
MockListener.resetListenerData(mContext);
delay();
}
}
// ordered by contact affinity: A, B, C
protected class LookupUriOrderTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createAutoItem(parent, R.string.attention_lookup_order);
}
@Override
void setUp() {
sendNotifications(MODE_URI, false, false);
status = READY;
// wait for notifications to move through the system
delay();
}
@Override
void test() {
MockListener.probeListenerOrder(mContext,
new MockListener.StringListResultCatcher() {
@Override
public void accept(List<String> orderedKeys) {
int rankA = findTagInKeys(ALICE, orderedKeys);
int rankB = findTagInKeys(BOB, orderedKeys);
int rankC = findTagInKeys(CHARLIE, orderedKeys);
if (rankA < rankB && rankB < rankC) {
status = PASS;
} else {
logFail(rankA + ", " + rankB + ", " + rankC);
status = FAIL;
}
next();
}
});
delay(); // in case the catcher never returns
}
@Override
void tearDown() {
mNm.cancelAll();
MockListener.resetListenerData(mContext);
delay();
}
}
// ordered by contact affinity: A, B, C
protected class EmailOrderTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createAutoItem(parent, R.string.attention_email_order);
}
@Override
void setUp() {
sendNotifications(MODE_EMAIL, false, false);
status = READY;
// wait for notifications to move through the system
delay();
}
@Override
void test() {
MockListener.probeListenerOrder(mContext,
new MockListener.StringListResultCatcher() {
@Override
public void accept(List<String> orderedKeys) {
int rankA = findTagInKeys(ALICE, orderedKeys);
int rankB = findTagInKeys(BOB, orderedKeys);
int rankC = findTagInKeys(CHARLIE, orderedKeys);
if (rankA < rankB && rankB < rankC) {
status = PASS;
} else {
logFail(rankA + ", " + rankB + ", " + rankC);
status = FAIL;
}
next();
}
});
delay(); // in case the catcher never returns
}
@Override
void tearDown() {
mNm.cancelAll();
MockListener.resetListenerData(mContext);
delay();
}
}
// ordered by contact affinity: A, B, C
protected class PhoneOrderTest extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createAutoItem(parent, R.string.attention_phone_order);
}
@Override
void setUp() {
sendNotifications(MODE_PHONE, false, false);
status = READY;
// wait for notifications to move through the system
delay();
}
@Override
void test() {
MockListener.probeListenerOrder(mContext,
new MockListener.StringListResultCatcher() {
@Override
public void accept(List<String> orderedKeys) {
int rankA = findTagInKeys(ALICE, orderedKeys);
int rankB = findTagInKeys(BOB, orderedKeys);
int rankC = findTagInKeys(CHARLIE, orderedKeys);
if (rankA < rankB && rankB < rankC) {
status = PASS;
} else {
logFail(rankA + ", " + rankB + ", " + rankC);
status = FAIL;
}
next();
}
});
delay(); // in case the catcher never returns
}
@Override
void tearDown() {
mNm.cancelAll();
MockListener.resetListenerData(mContext);
delay();
}
}
// Utilities
// usePriorities true: B, C, A
// usePriorities false:
// MODE_NONE: C, B, A
// otherwise: A, B ,C
private void sendNotifications(int annotationMode, boolean usePriorities, boolean noisy) {
// TODO(cwren) Fixes flakey tests due to bug 17644321. Remove this line when it is fixed.
int baseId = NOTIFICATION_ID + (noisy ? 3 : 0);
// C, B, A when sorted by time. Times must be in the past.
long whenA = System.currentTimeMillis() - 4000000L;
long whenB = System.currentTimeMillis() - 2000000L;
long whenC = System.currentTimeMillis() - 1000000L;
// B, C, A when sorted by priorities
int priorityA = usePriorities ? Notification.PRIORITY_MIN : Notification.PRIORITY_DEFAULT;
int priorityB = usePriorities ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT;
int priorityC = usePriorities ? Notification.PRIORITY_LOW : Notification.PRIORITY_DEFAULT;
Notification.Builder alice = new Notification.Builder(mContext)
.setContentTitle(ALICE)
.setContentText(ALICE)
.setSmallIcon(R.drawable.ic_stat_alice)
.setPriority(priorityA)
.setCategory(Notification.CATEGORY_MESSAGE)
.setWhen(whenA);
alice.setDefaults(noisy ? Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE : 0);
addPerson(annotationMode, alice, mAliceUri, ALICE_PHONE, ALICE_EMAIL);
mNm.notify(ALICE, baseId + 1, alice.build());
Notification.Builder bob = new Notification.Builder(mContext)
.setContentTitle(BOB)
.setContentText(BOB)
.setSmallIcon(R.drawable.ic_stat_bob)
.setPriority(priorityB)
.setCategory(Notification.CATEGORY_MESSAGE)
.setWhen(whenB);
addPerson(annotationMode, bob, mBobUri, BOB_PHONE, BOB_EMAIL);
mNm.notify(BOB, baseId + 2, bob.build());
Notification.Builder charlie = new Notification.Builder(mContext)
.setContentTitle(CHARLIE)
.setContentText(CHARLIE)
.setSmallIcon(R.drawable.ic_stat_charlie)
.setPriority(priorityC)
.setCategory(Notification.CATEGORY_MESSAGE)
.setWhen(whenC);
addPerson(annotationMode, charlie, mCharlieUri, CHARLIE_PHONE, CHARLIE_EMAIL);
mNm.notify(CHARLIE, baseId + 3, charlie.build());
}
private void addPerson(int mode, Notification.Builder note,
Uri uri, String phone, String email) {
if (mode == MODE_URI && uri != null) {
note.addPerson(uri.toString());
} else if (mode == MODE_PHONE) {
note.addPerson(Uri.fromParts("tel", phone, null).toString());
} else if (mode == MODE_EMAIL) {
note.addPerson(Uri.fromParts("mailto", email, null).toString());
}
}
private void insertSingleContact(String name, String phone, String email, boolean starred) {
final ArrayList<ContentProviderOperation> operationList =
new ArrayList<ContentProviderOperation>();
ContentProviderOperation.Builder builder =
ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI);
builder.withValue(ContactsContract.RawContacts.STARRED, starred ? 1 : 0);
operationList.add(builder.build());
builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0);
builder.withValue(ContactsContract.Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
builder.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);
operationList.add(builder.build());
if (phone != null) {
builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
builder.withValue(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
builder.withValue(Phone.TYPE, Phone.TYPE_MOBILE);
builder.withValue(Phone.NUMBER, phone);
builder.withValue(ContactsContract.Data.IS_PRIMARY, 1);
operationList.add(builder.build());
}
if (email != null) {
builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(Email.RAW_CONTACT_ID, 0);
builder.withValue(ContactsContract.Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
builder.withValue(Email.TYPE, Email.TYPE_HOME);
builder.withValue(Email.DATA, email);
operationList.add(builder.build());
}
try {
mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList);
} catch (RemoteException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
} catch (OperationApplicationException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
}
}
private Uri lookupContact(String phone) {
Cursor c = null;
try {
Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(phone));
String[] projection = new String[] { ContactsContract.Contacts._ID,
ContactsContract.Contacts.LOOKUP_KEY };
c = mContext.getContentResolver().query(phoneUri, projection, null, null, null);
if (c != null && c.getCount() > 0) {
c.moveToFirst();
int lookupIdx = c.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY);
int idIdx = c.getColumnIndex(ContactsContract.Contacts._ID);
String lookupKey = c.getString(lookupIdx);
long contactId = c.getLong(idIdx);
return ContactsContract.Contacts.getLookupUri(contactId, lookupKey);
}
} catch (Throwable t) {
Log.w(TAG, "Problem getting content resolver or performing contacts query.", t);
} finally {
if (c != null) {
c.close();
}
}
return null;
}
/** Search a list of notification keys for a givcen tag. */
private int findTagInKeys(String tag, List<String> orderedKeys) {
for (int i = 0; i < orderedKeys.size(); i++) {
if (orderedKeys.get(i).contains(tag)) {
return i;
}
}
return -1;
}
}