1/* 2 * Copyright (C) 2015 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 */ 16package com.android.car.dialer; 17 18import android.content.Context; 19import android.database.Cursor; 20import android.provider.ContactsContract; 21import android.support.annotation.Nullable; 22import android.text.TextUtils; 23import android.util.Log; 24 25import com.android.car.dialer.telecom.PhoneLoader; 26import com.android.car.dialer.telecom.TelecomUtils; 27 28/** 29 * Encapsulates data about a phone Contact entry. Typically loaded from the local Contact store. 30 */ 31// TODO: Refactor to use Builder design pattern. 32public class ContactEntry implements Comparable<ContactEntry> { 33 private final Context mContext; 34 35 /** 36 * An unique primary key for searching an entry. 37 */ 38 private int mId; 39 40 /** 41 * Whether this contact entry is starred by user. 42 */ 43 private boolean mIsStarred; 44 45 /** 46 * Contact-specific information about whether or not a contact has been pinned by the user at 47 * a particular position within the system contact application's user interface. 48 */ 49 private int mPinnedPosition; 50 51 /** 52 * Phone number. 53 */ 54 private String mNumber; 55 56 /** 57 * The display name. 58 */ 59 @Nullable 60 private String mDisplayName; 61 62 /** 63 * A URI that can be used to retrieve a thumbnail of the contact's photo. 64 */ 65 private String mAvatarThumbnailUri; 66 67 /** 68 * A URI that can be used to retrieve the contact's full-size photo. 69 */ 70 private String mAvatarUri; 71 72 /** 73 * An opaque value that contains hints on how to find the contact if its row id changed 74 * as a result of a sync or aggregation 75 */ 76 private String mLookupKey; 77 78 /** 79 * The type of data, for example Home or Work. 80 */ 81 private int mType; 82 83 /** 84 * The user defined label for the the contact method. 85 */ 86 private String mLabel; 87 88 /** 89 * Parses a Contact entry for a Cursor loaded from the OS Strequents DB. 90 */ 91 public static ContactEntry fromCursor(Cursor cursor, Context context) { 92 int idColumnIndex = PhoneLoader.getIdColumnIndex(cursor); 93 int starredColumn = cursor.getColumnIndex(ContactsContract.Contacts.STARRED); 94 int pinnedColumn = cursor.getColumnIndex("pinned"); 95 int displayNameColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME); 96 int avatarUriColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_URI); 97 int avatarThumbnailColumnIndex = cursor.getColumnIndex( 98 ContactsContract.Contacts.PHOTO_THUMBNAIL_URI); 99 int lookupKeyColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY); 100 int typeColumnIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DATA2); 101 int labelColumnIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DATA3); 102 103 String name = cursor.getString(displayNameColumnIndex); 104 String number = PhoneLoader.getPhoneNumber(cursor, context.getContentResolver()); 105 int starred = cursor.getInt(starredColumn); 106 int pinnedPosition = cursor.getInt(pinnedColumn); 107 ContactEntry contactEntry = new ContactEntry(context, name, number, starred > 0, 108 pinnedPosition); 109 contactEntry.setId(cursor.getInt(idColumnIndex)); 110 contactEntry.setAvatarUri(cursor.getString(avatarUriColumnIndex)); 111 contactEntry.setAvatarThumbnailUri(cursor.getString(avatarThumbnailColumnIndex)); 112 contactEntry.setLookupKey(cursor.getString(lookupKeyColumnIndex)); 113 contactEntry.setType(cursor.getInt(typeColumnIndex)); 114 contactEntry.setLabel(cursor.getString(labelColumnIndex)); 115 return contactEntry; 116 } 117 118 public ContactEntry( 119 Context context, String name, String number, boolean isStarred, int pinnedPosition) { 120 mContext = context; 121 this.mDisplayName = name; 122 this.mNumber = number; 123 this.mIsStarred = isStarred; 124 this.mPinnedPosition = pinnedPosition; 125 } 126 127 /** 128 * Retrieves a best-effort contact name ready for display to the user. 129 * It takes into account the number associated with a name for fail cases. 130 */ 131 public String getDisplayName() { 132 if (!TextUtils.isEmpty(mDisplayName)) { 133 return mDisplayName; 134 } 135 if (isVoicemail()) { 136 return mContext.getResources().getString(R.string.voicemail); 137 } else { 138 String displayName = TelecomUtils.getFormattedNumber(mContext, mNumber); 139 if (TextUtils.isEmpty(displayName)) { 140 displayName = mContext.getString(R.string.unknown); 141 } 142 return displayName; 143 } 144 } 145 146 public boolean isVoicemail() { 147 return mNumber.equals(TelecomUtils.getVoicemailNumber(mContext)); 148 } 149 150 @Override 151 public int compareTo(ContactEntry strequentContactEntry) { 152 if (mIsStarred == strequentContactEntry.mIsStarred) { 153 if (mPinnedPosition == strequentContactEntry.mPinnedPosition) { 154 if (mDisplayName == strequentContactEntry.mDisplayName) { 155 return compare(mNumber, strequentContactEntry.mNumber); 156 } 157 return compare(mDisplayName, strequentContactEntry.mDisplayName); 158 } else { 159 if (mPinnedPosition > 0 && strequentContactEntry.mPinnedPosition > 0) { 160 return mPinnedPosition - strequentContactEntry.mPinnedPosition; 161 } 162 163 if (mPinnedPosition > 0) { 164 return -1; 165 } 166 167 return 1; 168 } 169 } 170 171 if (mIsStarred) { 172 return -1; 173 } 174 175 return 1; 176 } 177 178 @Override 179 public boolean equals(Object obj) { 180 if (obj instanceof ContactEntry) { 181 ContactEntry other = (ContactEntry) obj; 182 if (compare(mDisplayName, other.mDisplayName) == 0 183 && compare(mNumber, other.mNumber) == 0 184 && mIsStarred == other.mIsStarred 185 && mPinnedPosition == other.mPinnedPosition) { 186 return true; 187 } 188 } 189 return false; 190 } 191 192 @Override 193 public int hashCode() { 194 int result = 17; 195 result = 31 * result + (mIsStarred ? 1 : 0); 196 result = 31 * result + mPinnedPosition; 197 result = 31 * result + (mDisplayName == null ? 0 : mDisplayName.hashCode()); 198 result = 31 * result + (mNumber == null ? 0 : mNumber.hashCode()); 199 return result; 200 } 201 202 private int compare(final String one, final String two) { 203 if (one == null ^ two == null) { 204 return (one == null) ? -1 : 1; 205 } 206 207 if (one == null && two == null) { 208 return 0; 209 } 210 211 return one.compareTo(two); 212 } 213 214 public int getId() { 215 return mId; 216 } 217 218 private void setId(int id) { 219 mId = id; 220 } 221 222 public String getAvatarUri() { 223 return mAvatarUri; 224 } 225 226 private void setAvatarUri(String avatarUri) { 227 mAvatarUri = avatarUri; 228 } 229 230 public String getLookupKey() { 231 return mLookupKey; 232 } 233 234 private void setLookupKey(String lookupKey) { 235 mLookupKey = lookupKey; 236 } 237 238 public int getType() { 239 return mType; 240 } 241 242 private void setType(int type) { 243 mType = type; 244 } 245 246 public String getLabel() { 247 return mLabel; 248 } 249 250 private void setLabel(String label) { 251 mLabel = label; 252 } 253 254 public String getAvatarThumbnailUri() { 255 return mAvatarThumbnailUri; 256 } 257 258 private void setAvatarThumbnailUri(String avatarThumbnailUri) { 259 mAvatarThumbnailUri = avatarThumbnailUri; 260 } 261 262 public String getNumber() { 263 return mNumber; 264 } 265 266 public boolean isStarred() { 267 return mIsStarred; 268 } 269 270 public int getPinnedPosition() { 271 return mPinnedPosition; 272 } 273 274} 275