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);
             }
         });