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