Add new class EmergencyContactManager

This refactor moves functionality related to reading, adding or removing
contacts to the list of emergency contacts to EmergencyContactManager.
Change-Id: I186fd48b30abd0f817ab73e4b19373761cb22508
diff --git a/src/com/android/emergency/EmergencyContactManager.java b/src/com/android/emergency/EmergencyContactManager.java
new file mode 100644
index 0000000..a295dc2
--- /dev/null
+++ b/src/com/android/emergency/EmergencyContactManager.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2016 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.emergency;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.util.ArraySet;
+
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Manages emergency contacts of the user.
+ */
+public class EmergencyContactManager {
+    private final SharedPreferences mSharedPreferences;
+    private final String mKey;
+    private final Context mContext;
+
+    /**
+     * Creates a new instance initialized with context and the shared preferences used to store the
+     * emergency contacts under the specified key.
+     */
+    public EmergencyContactManager(Context context, SharedPreferences sharedPreferences,
+                                   String key) {
+        mContext = context;
+        mSharedPreferences = sharedPreferences;
+        mKey = key;
+    }
+
+    /**
+     * Adds a new contact to the emergency contacts. */
+    public void addContact(Uri contactUri) {
+        // TODO: Consider refactoring this to use always setContacts() rather than
+        // addContact()/removeContact()
+        Set<Uri> emergencyContacts = getEmergencyContacts();
+        if (emergencyContacts.add(contactUri)) {
+            setEmergencyContacts(emergencyContacts);
+        }
+    }
+
+    /** Removes the specified contact from the list of emergency contacts. */
+    public void removeContact(Uri contactUri) {
+        // TODO: Consider refactoring this to use always setContacts() rather than
+        // addContact()/removeContact()
+        Set<Uri> emergencyContacts = getEmergencyContacts();
+        if (emergencyContacts.remove(contactUri)) {
+            setEmergencyContacts(emergencyContacts);
+        }
+    }
+
+    public Set<Uri> getEmergencyContacts() {
+        Set<String> emergencyContactStrings = mSharedPreferences.getStringSet(mKey,
+                Collections.<String>emptySet());
+        Set<Uri> emergencyContacts = new ArraySet<Uri>(emergencyContactStrings.size());
+        for (String emergencyContact : emergencyContactStrings) {
+            Uri contactUri = Uri.parse(emergencyContact);
+            if (isValidEmergencyContact(contactUri)) {
+                emergencyContacts.add(contactUri);
+            }
+        }
+        // If not all contacts were added, then we need to overwrite the emergency contacts stored
+        // in shared preferences. This deals with emergency contacts being deleted from contacts:
+        // currently we have no way to being notified when this happens.
+        if (emergencyContacts.size() != emergencyContactStrings.size()) {
+            setEmergencyContacts(emergencyContacts);
+        }
+        return emergencyContacts;
+    }
+
+    /** Returns the display name of the contact. */
+    public static String getName(Context context, Uri contactUri) {
+        Cursor cursor = context.getContentResolver().query(contactUri, null, null, null, null);
+        try {
+            if (cursor != null && cursor.moveToFirst()) {
+                return cursor.getString(cursor.getColumnIndex(
+                        ContactsContract.Contacts.DISPLAY_NAME));
+            }
+        } finally {
+            cursor.close();
+        }
+        return null;
+    }
+
+    private static boolean contactExists(Context context, Uri contactUri) {
+        Cursor cursor = context.getContentResolver().query(contactUri, null, null, null, null);
+        try {
+            if (cursor != null && cursor.moveToFirst()) {
+                return true;
+            }
+        } finally {
+            cursor.close();
+        }
+        return false;
+    }
+
+    /** Returns the phone number of the contact. */
+    public static String getNumber(Context context, Uri contactUri) {
+        // TODO: Investigate if this can be done in 1 query instead of 2.
+        ContentResolver contentResolver = context.getContentResolver();
+        Cursor contactCursor = contentResolver.query(contactUri, null, null, null, null);
+        try {
+            if (contactCursor != null && contactCursor.moveToFirst()) {
+                String id = contactCursor.getString(
+                        contactCursor.getColumnIndex(ContactsContract.Contacts._ID));
+                if (contactCursor.getInt(contactCursor.getColumnIndex(
+                        ContactsContract.Contacts.HAS_PHONE_NUMBER)) != 0) {
+                    Cursor phoneCursor = contentResolver.query(
+                            ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
+                            ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
+                            new String[]{id}, null);
+                    try {
+                        if (phoneCursor != null && phoneCursor.moveToFirst()) {
+                            return phoneCursor.getString(
+                                    phoneCursor.getColumnIndex(
+                                            ContactsContract.CommonDataKinds.Phone.NUMBER));
+                        }
+                    } finally {
+                        phoneCursor.close();
+                    }
+                }
+            }
+        } finally {
+            contactCursor.close();
+        }
+        return null;
+    }
+
+    /** Returns whether the contact uri is not null and corresponds to an existing contact. */
+    private boolean isValidEmergencyContact(Uri contactUri) {
+        return contactUri != null && contactExists(mContext, contactUri);
+    }
+
+    private void setEmergencyContacts(Set<Uri> emergencyContacts) {
+        Set<String> emergencyContactStrings = new ArraySet<String>(emergencyContacts.size());
+        for (Uri contactUri : emergencyContacts) {
+            emergencyContactStrings.add(contactUri.toString());
+        }
+        mSharedPreferences.edit().putStringSet(mKey, emergencyContactStrings).commit();
+    }
+}