2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com
.android
.ex
.chips
;
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
;
26 * Represents one entry inside recipient auto-complete list.
28 public class RecipientEntry
{
29 /* package */ static final int INVALID_CONTACT
= -1;
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.
35 /* package */ static final int GENERATED_CONTACT
= -2;
37 /** Used when {@link #mDestinationType} is invalid and thus shouldn't be used for display. */
38 public static final int INVALID_DESTINATION_TYPE
= -1;
40 public static final int ENTRY_TYPE_PERSON
= 0;
42 public static final int ENTRY_TYPE_SIZE
= 1;
44 private final int mEntryType
;
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.
50 private boolean mIsFirstLevel
;
51 private final String mDisplayName
;
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
;
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}.
61 private final String mDestinationLabel
;
62 /** ID for the person */
63 private final long mContactId
;
64 /** ID for the directory this contact came from, or <code>null</code> */
65 private final Long mDirectoryId
;
66 /** ID for the destination */
67 private final long mDataId
;
68 private final boolean mIsDivider
;
70 private final Uri mPhotoThumbnailUri
;
72 private boolean mIsValid
;
74 * This can be updated after this object being constructed, when the photo is fetched
75 * from remote directories.
77 private byte[] mPhotoBytes
;
79 /** See {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} */
80 private final String mLookupKey
;
82 protected RecipientEntry(int entryType
, String displayName
, String destination
,
83 int destinationType
, String destinationLabel
, long contactId
, Long directoryId
,
84 long dataId
, Uri photoThumbnailUri
, boolean isFirstLevel
, boolean isValid
,
86 mEntryType
= entryType
;
87 mIsFirstLevel
= isFirstLevel
;
88 mDisplayName
= displayName
;
89 mDestination
= destination
;
90 mDestinationType
= destinationType
;
91 mDestinationLabel
= destinationLabel
;
92 mContactId
= contactId
;
93 mDirectoryId
= directoryId
;
95 mPhotoThumbnailUri
= photoThumbnailUri
;
99 mLookupKey
= lookupKey
;
102 public boolean isValid() {
107 * Determine if this was a RecipientEntry created from recipient info or
108 * an entry from contacts.
110 public static boolean isCreatedRecipient(long id
) {
111 return id
== RecipientEntry
.INVALID_CONTACT
|| id
== RecipientEntry
.GENERATED_CONTACT
;
115 * Construct a RecipientEntry from just an address that has been entered.
116 * This address has not been resolved to a contact and therefore does not
117 * have a contact id or photo.
119 public static RecipientEntry
constructFakeEntry(final String address
, final boolean isValid
) {
120 final Rfc822Token
[] tokens
= Rfc822Tokenizer
.tokenize(address
);
121 final String tokenizedAddress
= tokens
.length
> 0 ? tokens
[0].getAddress() : address
;
123 return new RecipientEntry(ENTRY_TYPE_PERSON
, tokenizedAddress
, tokenizedAddress
,
124 INVALID_DESTINATION_TYPE
, null, INVALID_CONTACT
, null /* directoryId */,
125 INVALID_CONTACT
, null, true, isValid
, null /* lookupKey */);
129 * Construct a RecipientEntry from just a phone number.
131 public static RecipientEntry
constructFakePhoneEntry(final String phoneNumber
,
132 final boolean isValid
) {
133 return new RecipientEntry(ENTRY_TYPE_PERSON
, phoneNumber
, phoneNumber
,
134 INVALID_DESTINATION_TYPE
, null, INVALID_CONTACT
, null /* directoryId */,
135 INVALID_CONTACT
, null, true, isValid
, null /* lookupKey */);
139 * @return the display name for the entry. If the display name source is larger than
140 * {@link DisplayNameSources#PHONE} we use the contact's display name, but if not,
141 * i.e. the display name came from an email address or a phone number, we don't use it
142 * to avoid confusion and just use the destination instead.
144 private static String
pickDisplayName(int displayNameSource
, String displayName
,
145 String destination
) {
146 return (displayNameSource
> DisplayNameSources
.PHONE
) ? displayName
: destination
;
150 * Construct a RecipientEntry from just an address that has been entered
151 * with both an associated display name. This address has not been resolved
152 * to a contact and therefore does not have a contact id or photo.
154 public static RecipientEntry
constructGeneratedEntry(String display
, String address
,
156 return new RecipientEntry(ENTRY_TYPE_PERSON
, display
, address
, INVALID_DESTINATION_TYPE
,
157 null, GENERATED_CONTACT
, null /* directoryId */, GENERATED_CONTACT
, null, true,
158 isValid
, null /* lookupKey */);
161 public static RecipientEntry
constructTopLevelEntry(String displayName
, int displayNameSource
,
162 String destination
, int destinationType
, String destinationLabel
, long contactId
,
163 Long directoryId
, long dataId
, Uri photoThumbnailUri
, boolean isValid
,
165 return new RecipientEntry(ENTRY_TYPE_PERSON
, pickDisplayName(displayNameSource
,
166 displayName
, destination
), destination
, destinationType
, destinationLabel
,
167 contactId
, directoryId
, dataId
, photoThumbnailUri
, true, isValid
, lookupKey
);
170 public static RecipientEntry
constructTopLevelEntry(String displayName
, int displayNameSource
,
171 String destination
, int destinationType
, String destinationLabel
, long contactId
,
172 Long directoryId
, long dataId
, String thumbnailUriAsString
, boolean isValid
,
174 return new RecipientEntry(ENTRY_TYPE_PERSON
, pickDisplayName(displayNameSource
,
175 displayName
, destination
), destination
, destinationType
, destinationLabel
,
176 contactId
, directoryId
, dataId
, (thumbnailUriAsString
!= null
177 ? Uri
.parse(thumbnailUriAsString
) : null), true, isValid
, lookupKey
);
180 public static RecipientEntry
constructSecondLevelEntry(String displayName
,
181 int displayNameSource
, String destination
, int destinationType
,
182 String destinationLabel
, long contactId
, Long directoryId
, long dataId
,
183 String thumbnailUriAsString
, boolean isValid
, String lookupKey
) {
184 return new RecipientEntry(ENTRY_TYPE_PERSON
, pickDisplayName(displayNameSource
,
185 displayName
, destination
), destination
, destinationType
, destinationLabel
,
186 contactId
, directoryId
, dataId
, (thumbnailUriAsString
!= null
187 ? Uri
.parse(thumbnailUriAsString
) : null), false, isValid
, lookupKey
);
190 public int getEntryType() {
194 public String
getDisplayName() {
198 public String
getDestination() {
202 public int getDestinationType() {
203 return mDestinationType
;
206 public String
getDestinationLabel() {
207 return mDestinationLabel
;
210 public long getContactId() {
214 public Long
getDirectoryId() {
218 public long getDataId() {
222 public boolean isFirstLevel() {
223 return mIsFirstLevel
;
226 public Uri
getPhotoThumbnailUri() {
227 return mPhotoThumbnailUri
;
230 /** This can be called outside main Looper thread. */
231 public synchronized void setPhotoBytes(byte[] photoBytes
) {
232 mPhotoBytes
= photoBytes
;
235 /** This can be called outside main Looper thread. */
236 public synchronized byte[] getPhotoBytes() {
240 public boolean isSeparator() {
244 public boolean isSelectable() {
245 return mEntryType
== ENTRY_TYPE_PERSON
;
248 public String
getLookupKey() {
253 public String
toString() {
254 return mDisplayName
+ " <" + mDestination
+ ">, isValid=" + mIsValid
;
258 * Returns if entry represents the same person as this instance. The default implementation
259 * checks whether the contact ids are the same, and subclasses may opt to override this.
261 public boolean isSamePerson(final RecipientEntry entry
) {
262 return entry
!= null && mContactId
== entry
.mContactId
;