Protect against IllegalArgumentExceptions when reading contacts.
Also rename contactUri to phoneUri.
Bug:35873712
Test: runtest --path packages/apps/EmergencyInfo/tests/src/com/android/emergency/
Change-Id: I667ac74caf027b19aeeac94bb563c3a6b1cbb416
diff --git a/src/com/android/emergency/EmergencyContactManager.java b/src/com/android/emergency/EmergencyContactManager.java
index b7cce21..0ce3501 100644
--- a/src/com/android/emergency/EmergencyContactManager.java
+++ b/src/com/android/emergency/EmergencyContactManager.java
@@ -36,18 +36,18 @@
/**
* Returns a {@link Contact} that contains all the relevant information of the contact indexed
- * by {@code @contactUri}.
+ * by {@code @phoneUri}.
*/
- public static Contact getContact(Context context, Uri contactUri) {
+ public static Contact getContact(Context context, Uri phoneUri) {
String phoneNumber = null;
String phoneType = null;
String name = null;
Bitmap photo = null;
final Uri contactLookupUri =
ContactsContract.Contacts.getLookupUri(context.getContentResolver(),
- contactUri);
+ phoneUri);
Cursor cursor = context.getContentResolver().query(
- contactUri,
+ phoneUri,
new String[]{ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.TYPE,
@@ -73,7 +73,9 @@
try {
if (cursor2.moveToNext()) {
byte[] data = cursor2.getBlob(0);
- photo = BitmapFactory.decodeStream(new ByteArrayInputStream(data));
+ if (data != null) {
+ photo = BitmapFactory.decodeStream(new ByteArrayInputStream(data));
+ }
}
} finally {
if (cursor2 != null) {
@@ -87,7 +89,7 @@
cursor.close();
}
}
- return new Contact(contactLookupUri, contactUri, name, phoneNumber, phoneType, photo);
+ return new Contact(contactLookupUri, phoneUri, name, phoneNumber, phoneType, photo);
}
/** Returns whether the phone uri is not null and corresponds to an existing phone number. */
@@ -96,7 +98,7 @@
}
private static boolean phoneExists(Context context, Uri phoneUri) {
- Cursor cursor = null;
+ Cursor cursor = null;
try {
cursor = context.getContentResolver().query(phoneUri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
@@ -124,7 +126,7 @@
* The contact uri is associated to a particular phone number and can be used to reload that
* number and keep the number displayed in the preferences fresh.
*/
- private final Uri mContactUri;
+ private final Uri mPhoneUri;
/** The display name of the contact. */
private final String mName;
/** The emergency contact's phone number selected by the user. */
@@ -136,13 +138,13 @@
/** Constructs a new contact. */
public Contact(Uri contactLookupUri,
- Uri contactUri,
+ Uri phoneUri,
String name,
String phoneNumber,
String phoneType,
Bitmap photo) {
mContactLookupUri = contactLookupUri;
- mContactUri = contactUri;
+ mPhoneUri = phoneUri;
mName = name;
mPhoneNumber = phoneNumber;
mPhoneType = phoneType;
@@ -155,12 +157,12 @@
}
/**
- * The contact uri as defined in ContactsContract.CommonDataKinds.Phone.CONTENT_URI. Use
+ * The phone uri as defined in ContactsContract.CommonDataKinds.Phone.CONTENT_URI. Use
* this to reload the contact. This links to a particular phone number of the emergency
- * contact
+ * contact.
*/
- public Uri getContactUri() {
- return mContactUri;
+ public Uri getPhoneUri() {
+ return mPhoneUri;
}
/** Returns the display name of the contact. */
diff --git a/src/com/android/emergency/edit/EditEmergencyContactsFragment.java b/src/com/android/emergency/edit/EditEmergencyContactsFragment.java
index 78c850d..85ded96 100644
--- a/src/com/android/emergency/edit/EditEmergencyContactsFragment.java
+++ b/src/com/android/emergency/edit/EditEmergencyContactsFragment.java
@@ -17,13 +17,14 @@
import android.app.Activity;
import android.app.Fragment;
+import android.content.ActivityNotFoundException;
import android.content.Intent;
-import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.provider.ContactsContract;
+import android.util.Log;
import android.widget.Toast;
import com.android.emergency.PreferenceKeys;
@@ -36,6 +37,7 @@
* Fragment that displays emergency contacts. These contacts can be added or removed.
*/
public class EditEmergencyContactsFragment extends PreferenceFragment {
+ private static final String TAG = "EditEmergencyContactsFragment";
/** Result code for contact picker */
private static final int CONTACT_PICKER_RESULT = 1001;
@@ -60,14 +62,11 @@
// The selected contact is guaranteed to have a name and phone number.
Intent contactPickerIntent = new Intent(Intent.ACTION_PICK,
ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
- List<ResolveInfo> infos =
- getContext().getPackageManager().queryIntentActivities(contactPickerIntent, 0);
- if (infos != null && !infos.isEmpty()) {
+ try {
startActivityForResult(contactPickerIntent, CONTACT_PICKER_RESULT);
return true;
- } else {
- // TODO: Consider trying to load the regular contact picker using:
- // ContactsContract.Contacts.CONTENT_URI
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "No contact app available to display the contacts", e);
Toast.makeText(getContext(),
getContext().getString(R.string.fail_load_contact_picker),
Toast.LENGTH_LONG).show();
@@ -94,8 +93,8 @@
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CONTACT_PICKER_RESULT && resultCode == Activity.RESULT_OK) {
- Uri uri = data.getData();
- mEmergencyContactsPreferenceCategory.addNewEmergencyContact(uri);
+ Uri phoneUri = data.getData();
+ mEmergencyContactsPreferenceCategory.addNewEmergencyContact(phoneUri);
}
}
diff --git a/src/com/android/emergency/preferences/ContactPreference.java b/src/com/android/emergency/preferences/ContactPreference.java
index e50e450..8cdb057 100644
--- a/src/com/android/emergency/preferences/ContactPreference.java
+++ b/src/com/android/emergency/preferences/ContactPreference.java
@@ -72,26 +72,25 @@
* Instantiates a ContactPreference that displays an emergency contact, taking in a Context and
* the Uri.
*/
- public ContactPreference(Context context, @NonNull Uri contactUri) {
+ public ContactPreference(Context context, @NonNull Uri phoneUri) {
super(context);
setOrder(DEFAULT_ORDER);
- setUri(contactUri);
+ setPhoneUri(phoneUri);
setWidgetLayoutResource(R.layout.preference_user_delete_widget);
setPersistent(false);
}
- public void setUri(@NonNull Uri contactUri) {
- if (mContact != null && !contactUri.equals(mContact.getContactUri()) &&
+ public void setPhoneUri(@NonNull Uri phoneUri) {
+ if (mContact != null && !phoneUri.equals(mContact.getPhoneUri()) &&
mRemoveContactDialog != null) {
mRemoveContactDialog.dismiss();
}
-
- mContact = EmergencyContactManager.getContact(getContext(), contactUri);
+ mContact = EmergencyContactManager.getContact(getContext(), phoneUri);
setTitle(mContact.getName());
- setKey(mContact.getContactUri().toString());
+ setKey(mContact.getPhoneUri().toString());
String summary = mContact.getPhoneType() == null ?
mContact.getPhoneNumber() :
String.format(
@@ -166,8 +165,8 @@
}
}
- public Uri getContactUri() {
- return mContact.getContactUri();
+ public Uri getPhoneUri() {
+ return mContact.getPhoneUri();
}
@VisibleForTesting
diff --git a/src/com/android/emergency/preferences/EmergencyContactsPreference.java b/src/com/android/emergency/preferences/EmergencyContactsPreference.java
index a87646d..d354ef3 100644
--- a/src/com/android/emergency/preferences/EmergencyContactsPreference.java
+++ b/src/com/android/emergency/preferences/EmergencyContactsPreference.java
@@ -23,6 +23,7 @@
import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.util.AttributeSet;
+import android.util.Log;
import android.widget.Toast;
import com.android.emergency.EmergencyContactManager;
@@ -47,6 +48,8 @@
implements ReloadablePreferenceInterface,
ContactPreference.RemoveContactPreferenceListener {
+ private static final String TAG = "EmergencyContactsPreference";
+
private static final String CONTACT_SEPARATOR = "|";
private static final String QUOTE_CONTACT_SEPARATOR = Pattern.quote(CONTACT_SEPARATOR);
@@ -84,10 +87,10 @@
@Override
public void onRemoveContactPreference(ContactPreference contactPreference) {
- Uri newContact = contactPreference.getContactUri();
- if (mEmergencyContacts.contains(newContact)) {
+ Uri phoneUriToRemove = contactPreference.getPhoneUri();
+ if (mEmergencyContacts.contains(phoneUriToRemove)) {
List<Uri> updatedContacts = new ArrayList<Uri>(mEmergencyContacts);
- if (updatedContacts.remove(newContact) && callChangeListener(updatedContacts)) {
+ if (updatedContacts.remove(phoneUriToRemove) && callChangeListener(updatedContacts)) {
MetricsLogger.action(getContext(), MetricsEvent.ACTION_DELETE_EMERGENCY_CONTACT);
setEmergencyContacts(updatedContacts);
}
@@ -95,21 +98,21 @@
}
/**
- * Adds a new emergency contact. The {@code contactUri} is the
+ * Adds a new emergency contact. The {@code phoneUri} is the
* ContactsContract.CommonDataKinds.Phone.CONTENT_URI corresponding to the
* contact's selected phone number.
*/
- public void addNewEmergencyContact(Uri contactUri) {
- if (mEmergencyContacts.contains(contactUri)) {
+ public void addNewEmergencyContact(Uri phoneUri) {
+ if (mEmergencyContacts.contains(phoneUri)) {
return;
}
- if (!EmergencyContactManager.isValidEmergencyContact(getContext(), contactUri)) {
+ if (!EmergencyContactManager.isValidEmergencyContact(getContext(), phoneUri)) {
Toast.makeText(getContext(), getContext().getString(R.string.fail_add_contact),
Toast.LENGTH_LONG).show();
return;
}
List<Uri> updatedContacts = new ArrayList<Uri>(mEmergencyContacts);
- if (updatedContacts.add(contactUri) && callChangeListener(updatedContacts)) {
+ if (updatedContacts.add(phoneUri) && callChangeListener(updatedContacts)) {
MetricsLogger.action(getContext(), MetricsEvent.ACTION_ADD_EMERGENCY_CONTACT);
setEmergencyContacts(updatedContacts);
}
@@ -138,21 +141,39 @@
// Reload the preferences or add new ones if necessary
Iterator<Uri> it = emergencyContacts.iterator();
int i = 0;
+ Uri phoneUri = null;
+ List<Uri> updatedEmergencyContacts = null;
while (it.hasNext()) {
- if (i < getPreferenceCount()) {
- ContactPreference contactPreference = (ContactPreference) getPreference(i);
- contactPreference.setUri(it.next());
- } else {
- addContactPreference(it.next());
+ ContactPreference contactPreference = null;
+ phoneUri = it.next();
+ // setPhoneUri may throw an IllegalArgumentException (also called in the constructor
+ // of ContactPreference)
+ try {
+ if (i < getPreferenceCount()) {
+ contactPreference = (ContactPreference) getPreference(i);
+ contactPreference.setPhoneUri(phoneUri);
+ i++;
+ } else {
+ contactPreference = new ContactPreference(getContext(), phoneUri);
+ onBindContactView(contactPreference);
+ addPreference(contactPreference);
+ }
+ MetricsLogger.action(getContext(), MetricsEvent.ACTION_GET_CONTACT, 0);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Caught IllegalArgumentException for phoneUri:"
+ + phoneUri == null ? "" : phoneUri.toString(), e);
+ MetricsLogger.action(getContext(), MetricsEvent.ACTION_GET_CONTACT, 1);
+ if (updatedEmergencyContacts == null) {
+ updatedEmergencyContacts = new ArrayList<>(emergencyContacts);
+ }
+ updatedEmergencyContacts.remove(phoneUri);
}
- i++;
}
- }
-
- private void addContactPreference(Uri contactUri) {
- final ContactPreference contactPreference = new ContactPreference(getContext(), contactUri);
- onBindContactView(contactPreference);
- addPreference(contactPreference);
+ if (updatedEmergencyContacts != null) {
+ // Set the contacts again: something went wrong when retrieving information about the
+ // stored phone Uris.
+ setEmergencyContacts(updatedEmergencyContacts);
+ }
}
/**
@@ -201,9 +222,9 @@
emergencyContactString.split(QUOTE_CONTACT_SEPARATOR);
List<Uri> filteredEmergencyContacts = new ArrayList<Uri>(emergencyContactsArray.length);
for (String emergencyContact : emergencyContactsArray) {
- Uri contactUri = Uri.parse(emergencyContact);
- if (EmergencyContactManager.isValidEmergencyContact(context, contactUri)) {
- filteredEmergencyContacts.add(contactUri);
+ Uri phoneUri = Uri.parse(emergencyContact);
+ if (EmergencyContactManager.isValidEmergencyContact(context, phoneUri)) {
+ filteredEmergencyContacts.add(phoneUri);
}
}
// If not all contacts were added, then we need to overwrite the emergency contacts stored
diff --git a/tests/src/com/android/emergency/preferences/ContactPreferenceTest.java b/tests/src/com/android/emergency/preferences/ContactPreferenceTest.java
index 5e8af28..39271a0 100644
--- a/tests/src/com/android/emergency/preferences/ContactPreferenceTest.java
+++ b/tests/src/com/android/emergency/preferences/ContactPreferenceTest.java
@@ -34,7 +34,7 @@
private static final String NAME = "Jake";
private static final String PHONE_NUMBER = "123456";
private ContactPreference mContactPreference;
- private Uri mContactUri;
+ private Uri mPhoneUri;
public ContactPreferenceTest() {
super(EditInfoActivity.class);
@@ -42,11 +42,11 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mContactUri =
+ mPhoneUri =
ContactTestUtils.createContact(getActivity().getContentResolver(),
NAME,
PHONE_NUMBER);
- mContactPreference = new ContactPreference(getActivity(), mContactUri);
+ mContactPreference = new ContactPreference(getActivity(), mPhoneUri);
}
@Override
@@ -58,7 +58,7 @@
}
public void testContactPreference() {
- assertEquals(mContactUri, mContactPreference.getContactUri());
+ assertEquals(mPhoneUri, mContactPreference.getPhoneUri());
assertEquals(NAME, mContactPreference.getContact().getName());
assertEquals(PHONE_NUMBER, mContactPreference.getContact().getPhoneNumber());
diff --git a/tests/src/com/android/emergency/preferences/EmergencyContactsPreferenceTest.java b/tests/src/com/android/emergency/preferences/EmergencyContactsPreferenceTest.java
index 672a73e..cf66b6f 100644
--- a/tests/src/com/android/emergency/preferences/EmergencyContactsPreferenceTest.java
+++ b/tests/src/com/android/emergency/preferences/EmergencyContactsPreferenceTest.java
@@ -87,12 +87,12 @@
final String name = "Jane";
final String phoneNumber = "456";
- final Uri emergencyContactUri =
+ final Uri phoneUri =
ContactTestUtils.createContact(mContentResolver, name, phoneNumber);
runTestOnUiThread(new Runnable() {
@Override
public void run() {
- mEmergencyContactsPreference.addNewEmergencyContact(emergencyContactUri);
+ mEmergencyContactsPreference.addNewEmergencyContact(phoneUri);
}
});
@@ -101,7 +101,7 @@
ContactPreference contactPreference = (ContactPreference)
mEmergencyContactsPreference.getPreference(0);
- assertEquals(emergencyContactUri, contactPreference.getContactUri());
+ assertEquals(phoneUri, contactPreference.getPhoneUri());
assertEquals(name, contactPreference.getTitle());
assertTrue(((String) contactPreference.getSummary()).contains(phoneNumber));
@@ -144,7 +144,7 @@
assertEquals(2, mEmergencyContactsPreference.getEmergencyContacts().size());
assertEquals(2, mEmergencyContactsPreference.getPreferenceCount());
- // Delete Jane from other app (e.g. contacts)
+ // Delete Jane from another app (e.g. contacts)
assertTrue(ContactTestUtils
.deleteContact(mContentResolver, nameJane, phoneNumberJane));
getInstrumentation().waitForIdleSync();
@@ -163,7 +163,7 @@
assertEquals(1, mEmergencyContactsPreference.getPreferenceCount());
ContactPreference contactPreference = (ContactPreference)
mEmergencyContactsPreference.getPreference(0);
- assertEquals(emergencyContactJohn, contactPreference.getContactUri());
+ assertEquals(emergencyContactJohn, contactPreference.getPhoneUri());
// Clean up the inserted contact
assertTrue(ContactTestUtils
@@ -174,12 +174,12 @@
final String name = "Jane";
final String phoneNumber = "456";
- final Uri emergencyContactUri =
+ final Uri emergencyPhoneUri =
ContactTestUtils.createContact(mContentResolver, name, phoneNumber);
runTestOnUiThread(new Runnable() {
@Override
public void run() {
- mEmergencyContactsPreference.addNewEmergencyContact(emergencyContactUri);
+ mEmergencyContactsPreference.addNewEmergencyContact(emergencyPhoneUri);
}
});
@@ -223,12 +223,12 @@
final String name = "Jane";
final String phoneNumber = "456";
- final Uri emergencyContactUri =
+ final Uri emergencyPhoneUri =
ContactTestUtils.createContact(mContentResolver, name, phoneNumber);
runTestOnUiThread(new Runnable() {
@Override
public void run() {
- mEmergencyContactsPreference.addNewEmergencyContact(emergencyContactUri);
+ mEmergencyContactsPreference.addNewEmergencyContact(emergencyPhoneUri);
}
});