1 /* 2 * Copyright (C) 2011 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 17 package com.android.ex.chips; 18 19 import android.net.Uri; 20 import android.provider.ContactsContract.CommonDataKinds.Email; 21 import android.provider.ContactsContract.DisplayNameSources; 22 import android.text.util.Rfc822Token; 23 import android.text.util.Rfc822Tokenizer; 24 25 /** 26 * Represents one entry inside recipient auto-complete list. 27 */ 28 public class RecipientEntry { 29 /* package */ static final int INVALID_CONTACT = -1; 30 /** 31 * A GENERATED_CONTACT is one that was created based entirely on 32 * information passed in to the RecipientEntry from an external source 33 * that is not a real contact. 34 */ 35 /* package */ static final int GENERATED_CONTACT = -2; 36 37 /** Used when {@link #mDestinationType} is invalid and thus shouldn't be used for display. */ 38 /* package */ static final int INVALID_DESTINATION_TYPE = -1; 39 40 public static final int ENTRY_TYPE_PERSON = 0; 41 42 public static final int ENTRY_TYPE_SIZE = 1; 43 44 private final int mEntryType; 45 46 /** 47 * True when this entry is the first entry in a group, which should have a photo and display 48 * name, while the second or later entries won't. 49 */ 50 private boolean mIsFirstLevel; 51 private final String mDisplayName; 52 53 /** Destination for this contact entry. Would be an email address or a phone number. */ 54 private final String mDestination; 55 /** Type of the destination like {@link Email#TYPE_HOME} */ 56 private final int mDestinationType; 57 /** 58 * Label of the destination which will be used when type was {@link Email#TYPE_CUSTOM}. 59 * Can be null when {@link #mDestinationType} is {@link #INVALID_DESTINATION_TYPE}. 60 */ 61 private final String mDestinationLabel; 62 /** ID for the person */ 63 private final long mContactId; 64 /** ID for the destination */ 65 private final long mDataId; 66 private final boolean mIsDivider; 67 68 private final Uri mPhotoThumbnailUri; 69 70 private boolean mIsValid; 71 /** 72 * This can be updated after this object being constructed, when the photo is fetched 73 * from remote directories. 74 */ 75 private byte[] mPhotoBytes; 76 77 private RecipientEntry(int entryType, String displayName, String destination, 78 int destinationType, String destinationLabel, long contactId, long dataId, 79 Uri photoThumbnailUri, boolean isFirstLevel, boolean isValid) { 80 mEntryType = entryType; 81 mIsFirstLevel = isFirstLevel; 82 mDisplayName = displayName; 83 mDestination = destination; 84 mDestinationType = destinationType; 85 mDestinationLabel = destinationLabel; 86 mContactId = contactId; 87 mDataId = dataId; 88 mPhotoThumbnailUri = photoThumbnailUri; 89 mPhotoBytes = null; 90 mIsDivider = false; 91 mIsValid = isValid; 92 } 93 94 public boolean isValid() { 95 return mIsValid; 96 } 97 98 /** 99 * Determine if this was a RecipientEntry created from recipient info or 100 * an entry from contacts. 101 */ 102 public static boolean isCreatedRecipient(long id) { 103 return id == RecipientEntry.INVALID_CONTACT || id == RecipientEntry.GENERATED_CONTACT; 104 } 105 106 /** 107 * Construct a RecipientEntry from just an address that has been entered. 108 * This address has not been resolved to a contact and therefore does not 109 * have a contact id or photo. 110 */ 111 public static RecipientEntry constructFakeEntry(final String address, final boolean isValid) { 112 final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address); 113 final String tokenizedAddress = tokens.length > 0 ? tokens[0].getAddress() : address; 114 115 return new RecipientEntry(ENTRY_TYPE_PERSON, tokenizedAddress, tokenizedAddress, 116 INVALID_DESTINATION_TYPE, null, 117 INVALID_CONTACT, INVALID_CONTACT, null, true, isValid); 118 } 119 120 /** 121 * Construct a RecipientEntry from just a phone number. 122 */ 123 public static RecipientEntry constructFakePhoneEntry(final String phoneNumber, 124 final boolean isValid) { 125 return new RecipientEntry(ENTRY_TYPE_PERSON, phoneNumber, phoneNumber, 126 INVALID_DESTINATION_TYPE, null, 127 INVALID_CONTACT, INVALID_CONTACT, null, true, isValid); 128 } 129 130 /** 131 * @return the display name for the entry. If the display name source is larger than 132 * {@link DisplayNameSources#PHONE} we use the contact's display name, but if not, 133 * i.e. the display name came from an email address or a phone number, we don't use it 134 * to avoid confusion and just use the destination instead. 135 */ 136 private static String pickDisplayName(int displayNameSource, String displayName, 137 String destination) { 138 return (displayNameSource > DisplayNameSources.PHONE) ? displayName : destination; 139 } 140 141 /** 142 * Construct a RecipientEntry from just an address that has been entered 143 * with both an associated display name. This address has not been resolved 144 * to a contact and therefore does not have a contact id or photo. 145 */ 146 public static RecipientEntry constructGeneratedEntry(String display, String address, 147 boolean isValid) { 148 return new RecipientEntry(ENTRY_TYPE_PERSON, display, address, INVALID_DESTINATION_TYPE, 149 null, GENERATED_CONTACT, GENERATED_CONTACT, null, true, isValid); 150 } 151 152 public static RecipientEntry constructTopLevelEntry(String displayName, int displayNameSource, 153 String destination, int destinationType, String destinationLabel, long contactId, 154 long dataId, Uri photoThumbnailUri, boolean isValid) { 155 return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource, 156 displayName, destination), destination, destinationType, destinationLabel, 157 contactId, dataId, photoThumbnailUri, true, isValid); 158 } 159 160 public static RecipientEntry constructTopLevelEntry(String displayName, int displayNameSource, 161 String destination, int destinationType, String destinationLabel, long contactId, 162 long dataId, String thumbnailUriAsString, boolean isValid) { 163 return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource, 164 displayName, destination), destination, destinationType, destinationLabel, 165 contactId, dataId, (thumbnailUriAsString != null ? Uri.parse(thumbnailUriAsString) 166 : null), true, isValid); 167 } 168 169 public static RecipientEntry constructSecondLevelEntry(String displayName, 170 int displayNameSource, String destination, int destinationType, 171 String destinationLabel, long contactId, long dataId, String thumbnailUriAsString, 172 boolean isValid) { 173 return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource, 174 displayName, destination), destination, destinationType, destinationLabel, 175 contactId, dataId, (thumbnailUriAsString != null ? Uri.parse(thumbnailUriAsString) 176 : null), false, isValid); 177 } 178 179 public int getEntryType() { 180 return mEntryType; 181 } 182 183 public String getDisplayName() { 184 return mDisplayName; 185 } 186 187 public String getDestination() { 188 return mDestination; 189 } 190 191 public int getDestinationType() { 192 return mDestinationType; 193 } 194 195 public String getDestinationLabel() { 196 return mDestinationLabel; 197 } 198 199 public long getContactId() { 200 return mContactId; 201 } 202 203 public long getDataId() { 204 return mDataId; 205 } 206 207 public boolean isFirstLevel() { 208 return mIsFirstLevel; 209 } 210 211 public Uri getPhotoThumbnailUri() { 212 return mPhotoThumbnailUri; 213 } 214 215 /** This can be called outside main Looper thread. */ 216 public synchronized void setPhotoBytes(byte[] photoBytes) { 217 mPhotoBytes = photoBytes; 218 } 219 220 /** This can be called outside main Looper thread. */ 221 public synchronized byte[] getPhotoBytes() { 222 return mPhotoBytes; 223 } 224 225 public boolean isSeparator() { 226 return mIsDivider; 227 } 228 229 public boolean isSelectable() { 230 return mEntryType == ENTRY_TYPE_PERSON; 231 } 232 233 @Override 234 public String toString() { 235 return mDisplayName + " <" + mDestination + ">, isValid=" + mIsValid; 236 } 237 }