[go: nahoru, domu]

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
17package com.android.ex.chips;
18
19import android.net.Uri;
20import android.provider.ContactsContract.CommonDataKinds.Email;
21import android.provider.ContactsContract.DisplayNameSources;
22import android.support.annotation.DrawableRes;
23import android.text.util.Rfc822Token;
24import android.text.util.Rfc822Tokenizer;
25
26/**
27 * Represents one entry inside recipient auto-complete list.
28 */
29public class RecipientEntry {
30    /* package */ static final int INVALID_CONTACT = -1;
31    /**
32     * A GENERATED_CONTACT is one that was created based entirely on
33     * information passed in to the RecipientEntry from an external source
34     * that is not a real contact.
35     */
36    /* package */ static final int GENERATED_CONTACT = -2;
37
38    /** Used when {@link #mDestinationType} is invalid and thus shouldn't be used for display. */
39    public static final int INVALID_DESTINATION_TYPE = -1;
40
41    public static final int ENTRY_TYPE_PERSON = 0;
42
43    /**
44     * Entry of this type represents the item in auto-complete that asks user to grant permissions
45     * to the app. This permission model is introduced in M platform.
46     *
47     * <p>Entries of this type should have {@link #mPermissions} set as well.
48     */
49    public static final int ENTRY_TYPE_PERMISSION_REQUEST = 1;
50
51    public static final int ENTRY_TYPE_SIZE = 2;
52
53    private final int mEntryType;
54
55    /**
56     * True when this entry is the first entry in a group, which should have a photo and display
57     * name, while the second or later entries won't.
58     */
59    private boolean mIsFirstLevel;
60    private final String mDisplayName;
61
62    /** Destination for this contact entry. Would be an email address or a phone number. */
63    private final String mDestination;
64    /** Type of the destination like {@link Email#TYPE_HOME} */
65    private final int mDestinationType;
66    /**
67     * Label of the destination which will be used when type was {@link Email#TYPE_CUSTOM}.
68     * Can be null when {@link #mDestinationType} is {@link #INVALID_DESTINATION_TYPE}.
69     */
70    private final String mDestinationLabel;
71    /** ID for the person */
72    private final long mContactId;
73    /** ID for the directory this contact came from, or <code>null</code> */
74    private final Long mDirectoryId;
75    /** ID for the destination */
76    private final long mDataId;
77
78    private final Uri mPhotoThumbnailUri;
79
80    private boolean mIsValid;
81    /**
82     * This can be updated after this object being constructed, when the photo is fetched
83     * from remote directories.
84     */
85    private byte[] mPhotoBytes;
86
87    @DrawableRes private int mIndicatorIconId;
88    private String mIndicatorText;
89
90    /** See {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} */
91    private final String mLookupKey;
92
93    /** Should be used when type is {@link #ENTRY_TYPE_PERMISSION_REQUEST}. */
94    private final String[] mPermissions;
95
96    protected RecipientEntry(int entryType, String displayName, String destination,
97            int destinationType, String destinationLabel, long contactId, Long directoryId,
98            long dataId, Uri photoThumbnailUri, boolean isFirstLevel, boolean isValid,
99            String lookupKey, String[] permissions) {
100        mEntryType = entryType;
101        mIsFirstLevel = isFirstLevel;
102        mDisplayName = displayName;
103        mDestination = destination;
104        mDestinationType = destinationType;
105        mDestinationLabel = destinationLabel;
106        mContactId = contactId;
107        mDirectoryId = directoryId;
108        mDataId = dataId;
109        mPhotoThumbnailUri = photoThumbnailUri;
110        mPhotoBytes = null;
111        mIsValid = isValid;
112        mLookupKey = lookupKey;
113        mIndicatorIconId = 0;
114        mIndicatorText = null;
115        mPermissions = permissions;
116    }
117
118    protected RecipientEntry(int entryType, String displayName, String destination,
119            int destinationType, String destinationLabel, long contactId, Long directoryId,
120            long dataId, Uri photoThumbnailUri, boolean isFirstLevel, boolean isValid,
121            String lookupKey) {
122        this(entryType, displayName, destination, destinationType, destinationLabel,
123                contactId, directoryId, dataId, photoThumbnailUri, isFirstLevel, isValid,
124                lookupKey, null);
125    }
126
127    public boolean isValid() {
128        return mIsValid;
129    }
130
131    /**
132     * Determine if this was a RecipientEntry created from recipient info or
133     * an entry from contacts.
134     */
135    public static boolean isCreatedRecipient(long id) {
136        return id == RecipientEntry.INVALID_CONTACT || id == RecipientEntry.GENERATED_CONTACT;
137    }
138
139    /**
140     * Construct a RecipientEntry from just an address that has been entered.
141     * This address has not been resolved to a contact and therefore does not
142     * have a contact id or photo.
143     */
144    public static RecipientEntry constructFakeEntry(final String address, final boolean isValid) {
145        final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
146        final String tokenizedAddress = tokens.length > 0 ? tokens[0].getAddress() : address;
147
148        return new RecipientEntry(ENTRY_TYPE_PERSON, tokenizedAddress, tokenizedAddress,
149                INVALID_DESTINATION_TYPE, null, INVALID_CONTACT, null /* directoryId */,
150                INVALID_CONTACT, null, true, isValid, null /* lookupKey */, null /* permissions */);
151    }
152
153    /**
154     * Construct a RecipientEntry from just a phone number.
155     */
156    public static RecipientEntry constructFakePhoneEntry(final String phoneNumber,
157            final boolean isValid) {
158        return new RecipientEntry(ENTRY_TYPE_PERSON, phoneNumber, phoneNumber,
159                INVALID_DESTINATION_TYPE, null, INVALID_CONTACT, null /* directoryId */,
160                INVALID_CONTACT, null, true, isValid, null /* lookupKey */, null /* permissions */);
161    }
162
163    /**
164     * Construct a RecipientEntry from just an address that has been entered
165     * with both an associated display name. This address has not been resolved
166     * to a contact and therefore does not have a contact id or photo.
167     */
168    public static RecipientEntry constructGeneratedEntry(String display, String address,
169            boolean isValid) {
170        return new RecipientEntry(ENTRY_TYPE_PERSON, display, address, INVALID_DESTINATION_TYPE,
171                null, GENERATED_CONTACT, null /* directoryId */, GENERATED_CONTACT, null, true,
172                isValid, null /* lookupKey */, null /* permissions */);
173    }
174
175    public static RecipientEntry constructTopLevelEntry(String displayName, int displayNameSource,
176            String destination, int destinationType, String destinationLabel, long contactId,
177            Long directoryId, long dataId, Uri photoThumbnailUri, boolean isValid,
178            String lookupKey) {
179        return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource,
180                displayName, destination), destination, destinationType, destinationLabel,
181                contactId, directoryId, dataId, photoThumbnailUri, true, isValid, lookupKey,
182                null /* permissions */);
183    }
184
185    public static RecipientEntry constructTopLevelEntry(String displayName, int displayNameSource,
186            String destination, int destinationType, String destinationLabel, long contactId,
187            Long directoryId, long dataId, String thumbnailUriAsString, boolean isValid,
188            String lookupKey) {
189        return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource,
190                displayName, destination), destination, destinationType, destinationLabel,
191                contactId, directoryId, dataId, (thumbnailUriAsString != null
192                ? Uri.parse(thumbnailUriAsString) : null), true, isValid, lookupKey,
193                null /* permissions */);
194    }
195
196    public static RecipientEntry constructSecondLevelEntry(String displayName,
197            int displayNameSource, String destination, int destinationType,
198            String destinationLabel, long contactId, Long directoryId, long dataId,
199            String thumbnailUriAsString, boolean isValid, String lookupKey) {
200        return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource,
201                displayName, destination), destination, destinationType, destinationLabel,
202                contactId, directoryId, dataId, (thumbnailUriAsString != null
203                ? Uri.parse(thumbnailUriAsString) : null), false, isValid, lookupKey,
204                null /* permissions */);
205    }
206
207    public static RecipientEntry constructPermissionEntry(String[] permissions) {
208        return new RecipientEntry(
209                ENTRY_TYPE_PERMISSION_REQUEST,
210                "" /* displayName */,
211                "" /* destination */,
212                Email.TYPE_CUSTOM,
213                "" /* destinationLabel */,
214                INVALID_CONTACT,
215                null /* directoryId */,
216                INVALID_CONTACT,
217                null /* photoThumbnailUri */,
218                true /* isFirstLevel*/,
219                false /* isValid */,
220                null /* lookupKey */,
221                permissions);
222    }
223
224    /**
225     * @return the display name for the entry.  If the display name source is larger than
226     * {@link DisplayNameSources#PHONE} we use the contact's display name, but if not,
227     * i.e. the display name came from an email address or a phone number, we don't use it
228     * to avoid confusion and just use the destination instead.
229     */
230    private static String pickDisplayName(int displayNameSource, String displayName,
231            String destination) {
232        return (displayNameSource > DisplayNameSources.PHONE) ? displayName : destination;
233    }
234
235    public int getEntryType() {
236        return mEntryType;
237    }
238
239    public String getDisplayName() {
240        return mDisplayName;
241    }
242
243    public String getDestination() {
244        return mDestination;
245    }
246
247    public int getDestinationType() {
248        return mDestinationType;
249    }
250
251    public String getDestinationLabel() {
252        return mDestinationLabel;
253    }
254
255    public long getContactId() {
256        return mContactId;
257    }
258
259    public Long getDirectoryId() {
260        return mDirectoryId;
261    }
262
263    public long getDataId() {
264        return mDataId;
265    }
266
267    public boolean isFirstLevel() {
268        return mIsFirstLevel;
269    }
270
271    public Uri getPhotoThumbnailUri() {
272        return mPhotoThumbnailUri;
273    }
274
275    /** This can be called outside main Looper thread. */
276    public synchronized void setPhotoBytes(byte[] photoBytes) {
277        mPhotoBytes = photoBytes;
278    }
279
280    /** This can be called outside main Looper thread. */
281    public synchronized byte[] getPhotoBytes() {
282        return mPhotoBytes;
283    }
284
285    /**
286     * Used together with {@link #ENTRY_TYPE_PERMISSION_REQUEST} and indicates what permissions we
287     * need to ask user to grant.
288     */
289    public String[] getPermissions() {
290        return mPermissions;
291    }
292
293    public String getLookupKey() {
294        return mLookupKey;
295    }
296
297    public boolean isSelectable() {
298        return mEntryType == ENTRY_TYPE_PERSON || mEntryType == ENTRY_TYPE_PERMISSION_REQUEST;
299    }
300
301    @Override
302    public String toString() {
303        return mDisplayName + " <" + mDestination + ">, isValid=" + mIsValid;
304    }
305
306    /**
307     * Returns if entry represents the same person as this instance. The default implementation
308     * checks whether the contact ids are the same, and subclasses may opt to override this.
309     */
310    public boolean isSamePerson(final RecipientEntry entry) {
311        return entry != null && mContactId == entry.mContactId;
312    }
313
314    /**
315     * Returns the resource ID for the indicator icon, or 0 if no icon should be displayed.
316     */
317    @DrawableRes
318    public int getIndicatorIconId() {
319        return mIndicatorIconId;
320    }
321
322    /**
323     * Sets the indicator icon to the given resource ID.  Set to 0 to display no icon.
324     */
325    public void setIndicatorIconId(@DrawableRes int indicatorIconId) {
326        mIndicatorIconId = indicatorIconId;
327    }
328
329    /**
330     * Get the indicator text, or null if no text should be displayed.
331     */
332    public String getIndicatorText() {
333        return mIndicatorText;
334    }
335
336    /**
337     * Set the indicator text.  Set to null for no text to be displayed.
338     */
339    public void setIndicatorText(String indicatorText) {
340        mIndicatorText = indicatorText;
341    }
342}
343