1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.emergency; 17 18 import android.content.ContentUris; 19 import android.content.Context; 20 import android.database.Cursor; 21 import android.graphics.Bitmap; 22 import android.graphics.BitmapFactory; 23 import com.android.internal.logging.MetricsLogger; 24 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 25 import android.net.Uri; 26 import android.provider.ContactsContract; 27 import android.util.Log; 28 29 import java.io.ByteArrayInputStream; 30 31 /** 32 * Provides methods to read name, phone number, photo, etc. from contacts. 33 */ 34 public class EmergencyContactManager { 35 private static final String TAG = "EmergencyContactManager"; 36 37 /** 38 * Returns a {@link Contact} that contains all the relevant information of the contact indexed 39 * by {@code @phoneUri}. 40 */ getContact(Context context, Uri phoneUri)41 public static Contact getContact(Context context, Uri phoneUri) { 42 String phoneNumber = null; 43 String phoneType = null; 44 String name = null; 45 Bitmap photo = null; 46 final Uri contactLookupUri = 47 ContactsContract.Contacts.getLookupUri(context.getContentResolver(), 48 phoneUri); 49 Cursor cursor = context.getContentResolver().query( 50 phoneUri, 51 new String[]{ContactsContract.Contacts.DISPLAY_NAME, 52 ContactsContract.CommonDataKinds.Phone.NUMBER, 53 ContactsContract.CommonDataKinds.Phone.TYPE, 54 ContactsContract.CommonDataKinds.Phone.LABEL, 55 ContactsContract.CommonDataKinds.Photo.PHOTO_ID}, 56 null, null, null); 57 try { 58 if (cursor.moveToNext()) { 59 name = cursor.getString(0); 60 phoneNumber = cursor.getString(1); 61 phoneType = ContactsContract.CommonDataKinds.Phone.getTypeLabel( 62 context.getResources(), 63 cursor.getInt(2), 64 cursor.getString(3)).toString(); 65 Long photoId = cursor.getLong(4); 66 if (photoId != null && photoId > 0) { 67 Uri photoUri = ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, 68 photoId); 69 Cursor cursor2 = context.getContentResolver().query( 70 photoUri, 71 new String[]{ContactsContract.Contacts.Photo.PHOTO}, 72 null, null, null); 73 try { 74 if (cursor2.moveToNext()) { 75 byte[] data = cursor2.getBlob(0); 76 if (data != null) { 77 photo = BitmapFactory.decodeStream(new ByteArrayInputStream(data)); 78 } 79 } 80 } finally { 81 if (cursor2 != null) { 82 cursor2.close(); 83 } 84 } 85 } 86 } 87 } finally { 88 if (cursor != null) { 89 cursor.close(); 90 } 91 } 92 return new Contact(contactLookupUri, phoneUri, name, phoneNumber, phoneType, photo); 93 } 94 95 /** Returns whether the phone uri is not null and corresponds to an existing phone number. */ isValidEmergencyContact(Context context, Uri phoneUri)96 public static boolean isValidEmergencyContact(Context context, Uri phoneUri) { 97 return phoneUri != null && phoneExists(context, phoneUri); 98 } 99 phoneExists(Context context, Uri phoneUri)100 private static boolean phoneExists(Context context, Uri phoneUri) { 101 Cursor cursor = null; 102 try { 103 cursor = context.getContentResolver().query(phoneUri, null, null, null, null); 104 if (cursor != null && cursor.moveToFirst()) { 105 MetricsLogger.action(context, MetricsEvent.ACTION_PHONE_EXISTS, 1); 106 return true; 107 } 108 } catch (SecurityException e) { 109 Log.w(TAG, "Unable to read contact information", e); 110 MetricsLogger.action(context, MetricsEvent.ACTION_PHONE_EXISTS, 2); 111 return false; 112 } finally { 113 if (cursor != null) { 114 cursor.close(); 115 } 116 } 117 MetricsLogger.action(context, MetricsEvent.ACTION_PHONE_EXISTS, 0); 118 return false; 119 } 120 121 /** Wrapper for a contact with a phone number. */ 122 public static class Contact { 123 /** The lookup uri is necessary to display the contact. */ 124 private final Uri mContactLookupUri; 125 /** 126 * The contact uri is associated to a particular phone number and can be used to reload that 127 * number and keep the number displayed in the preferences fresh. 128 */ 129 private final Uri mPhoneUri; 130 /** The display name of the contact. */ 131 private final String mName; 132 /** The emergency contact's phone number selected by the user. */ 133 private final String mPhoneNumber; 134 /** The emergency contact's phone number type (mobile, work, home, etc). */ 135 private final String mPhoneType; 136 /** The contact's photo. */ 137 private final Bitmap mPhoto; 138 139 /** Constructs a new contact. */ Contact(Uri contactLookupUri, Uri phoneUri, String name, String phoneNumber, String phoneType, Bitmap photo)140 public Contact(Uri contactLookupUri, 141 Uri phoneUri, 142 String name, 143 String phoneNumber, 144 String phoneType, 145 Bitmap photo) { 146 mContactLookupUri = contactLookupUri; 147 mPhoneUri = phoneUri; 148 mName = name; 149 mPhoneNumber = phoneNumber; 150 mPhoneType = phoneType; 151 mPhoto = photo; 152 } 153 154 /** Returns the contact's CONTENT_LOOKUP_URI. Use this to display the contact. */ getContactLookupUri()155 public Uri getContactLookupUri() { 156 return mContactLookupUri; 157 } 158 159 /** 160 * The phone uri as defined in ContactsContract.CommonDataKinds.Phone.CONTENT_URI. Use 161 * this to reload the contact. This links to a particular phone number of the emergency 162 * contact. 163 */ getPhoneUri()164 public Uri getPhoneUri() { 165 return mPhoneUri; 166 } 167 168 /** Returns the display name of the contact. */ getName()169 public String getName() { 170 return mName; 171 } 172 173 /** Returns the phone number selected by the user. */ getPhoneNumber()174 public String getPhoneNumber() { 175 return mPhoneNumber; 176 } 177 178 /** Returns the phone type (e.g. mobile, work, home, etc.) . */ getPhoneType()179 public String getPhoneType() { 180 return mPhoneType; 181 } 182 183 /** Returns the photo assigned to this contact. */ getPhoto()184 public Bitmap getPhoto() { 185 return mPhoto; 186 } 187 } 188 } 189