summaryrefslogtreecommitdiffstats
path: root/chips/src/com/android/ex/chips/RecipientEntry.java
blob: 44bc767d3433c454a7ffa5124dbfe18b57e95ffc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.ex.chips;

import android.net.Uri;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.DisplayNameSources;
import android.text.util.Rfc822Token;
import android.text.util.Rfc822Tokenizer;

/**
 * Represents one entry inside recipient auto-complete list.
 */
public class RecipientEntry {
    /* package */ static final int INVALID_CONTACT = -1;
    /**
     * A GENERATED_CONTACT is one that was created based entirely on
     * information passed in to the RecipientEntry from an external source
     * that is not a real contact.
     */
    /* package */ static final int GENERATED_CONTACT = -2;

    /** Used when {@link #mDestinationType} is invalid and thus shouldn't be used for display. */
    /* package */ static final int INVALID_DESTINATION_TYPE = -1;

    public static final int ENTRY_TYPE_PERSON = 0;

    public static final int ENTRY_TYPE_SIZE = 1;

    private final int mEntryType;

    /**
     * True when this entry is the first entry in a group, which should have a photo and display
     * name, while the second or later entries won't.
     */
    private boolean mIsFirstLevel;
    private final String mDisplayName;

    /** Destination for this contact entry. Would be an email address or a phone number. */
    private final String mDestination;
    /** Type of the destination like {@link Email#TYPE_HOME} */
    private final int mDestinationType;
    /**
     * Label of the destination which will be used when type was {@link Email#TYPE_CUSTOM}.
     * Can be null when {@link #mDestinationType} is {@link #INVALID_DESTINATION_TYPE}.
     */
    private final String mDestinationLabel;
    /** ID for the person */
    private final long mContactId;
    /** ID for the destination */
    private final long mDataId;
    private final boolean mIsDivider;

    private final Uri mPhotoThumbnailUri;

    private boolean mIsValid;
    /**
     * This can be updated after this object being constructed, when the photo is fetched
     * from remote directories.
     */
    private byte[] mPhotoBytes;

    private RecipientEntry(int entryType, String displayName, String destination,
            int destinationType, String destinationLabel, long contactId, long dataId,
            Uri photoThumbnailUri, boolean isFirstLevel, boolean isValid) {
        mEntryType = entryType;
        mIsFirstLevel = isFirstLevel;
        mDisplayName = displayName;
        mDestination = destination;
        mDestinationType = destinationType;
        mDestinationLabel = destinationLabel;
        mContactId = contactId;
        mDataId = dataId;
        mPhotoThumbnailUri = photoThumbnailUri;
        mPhotoBytes = null;
        mIsDivider = false;
        mIsValid = isValid;
    }

    public boolean isValid() {
        return mIsValid;
    }

    /**
     * Determine if this was a RecipientEntry created from recipient info or
     * an entry from contacts.
     */
    public static boolean isCreatedRecipient(long id) {
        return id == RecipientEntry.INVALID_CONTACT || id == RecipientEntry.GENERATED_CONTACT;
    }

    /**
     * Construct a RecipientEntry from just an address that has been entered.
     * This address has not been resolved to a contact and therefore does not
     * have a contact id or photo.
     */
    public static RecipientEntry constructFakeEntry(final String address, final boolean isValid) {
        final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
        final String tokenizedAddress = tokens.length > 0 ? tokens[0].getAddress() : address;

        return new RecipientEntry(ENTRY_TYPE_PERSON, tokenizedAddress, tokenizedAddress,
                INVALID_DESTINATION_TYPE, null,
                INVALID_CONTACT, INVALID_CONTACT, null, true, isValid);
    }

    /**
     * Construct a RecipientEntry from just a phone number.
     */
    public static RecipientEntry constructFakePhoneEntry(final String phoneNumber,
            final boolean isValid) {
        return new RecipientEntry(ENTRY_TYPE_PERSON, phoneNumber, phoneNumber,
                INVALID_DESTINATION_TYPE, null,
                INVALID_CONTACT, INVALID_CONTACT, null, true, isValid);
    }

    /**
     * @return the display name for the entry.  If the display name source is larger than
     * {@link DisplayNameSources#PHONE} we use the contact's display name, but if not,
     * i.e. the display name came from an email address or a phone number, we don't use it
     * to avoid confusion and just use the destination instead.
     */
    private static String pickDisplayName(int displayNameSource, String displayName,
            String destination) {
        return (displayNameSource > DisplayNameSources.PHONE) ? displayName : destination;
    }

    /**
     * Construct a RecipientEntry from just an address that has been entered
     * with both an associated display name. This address has not been resolved
     * to a contact and therefore does not have a contact id or photo.
     */
    public static RecipientEntry constructGeneratedEntry(String display, String address,
            boolean isValid) {
        return new RecipientEntry(ENTRY_TYPE_PERSON, display, address, INVALID_DESTINATION_TYPE,
                null, GENERATED_CONTACT, GENERATED_CONTACT, null, true, isValid);
    }

    public static RecipientEntry constructTopLevelEntry(String displayName, int displayNameSource,
            String destination, int destinationType, String destinationLabel, long contactId,
            long dataId, Uri photoThumbnailUri, boolean isValid) {
        return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource,
                displayName, destination), destination, destinationType, destinationLabel,
                contactId, dataId, photoThumbnailUri, true, isValid);
    }

    public static RecipientEntry constructTopLevelEntry(String displayName, int displayNameSource,
            String destination, int destinationType, String destinationLabel, long contactId,
            long dataId, String thumbnailUriAsString, boolean isValid) {
        return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource,
                displayName, destination), destination, destinationType, destinationLabel,
                contactId, dataId, (thumbnailUriAsString != null ? Uri.parse(thumbnailUriAsString)
                        : null), true, isValid);
    }

    public static RecipientEntry constructSecondLevelEntry(String displayName,
            int displayNameSource, String destination, int destinationType,
            String destinationLabel, long contactId, long dataId, String thumbnailUriAsString,
            boolean isValid) {
        return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource,
                displayName, destination), destination, destinationType, destinationLabel,
                contactId, dataId, (thumbnailUriAsString != null ? Uri.parse(thumbnailUriAsString)
                        : null), false, isValid);
    }

    public int getEntryType() {
        return mEntryType;
    }

    public String getDisplayName() {
        return mDisplayName;
    }

    public String getDestination() {
        return mDestination;
    }

    public int getDestinationType() {
        return mDestinationType;
    }

    public String getDestinationLabel() {
        return mDestinationLabel;
    }

    public long getContactId() {
        return mContactId;
    }

    public long getDataId() {
        return mDataId;
    }

    public boolean isFirstLevel() {
        return mIsFirstLevel;
    }

    public Uri getPhotoThumbnailUri() {
        return mPhotoThumbnailUri;
    }

    /** This can be called outside main Looper thread. */
    public synchronized void setPhotoBytes(byte[] photoBytes) {
        mPhotoBytes = photoBytes;
    }

    /** This can be called outside main Looper thread. */
    public synchronized byte[] getPhotoBytes() {
        return mPhotoBytes;
    }

    public boolean isSeparator() {
        return mIsDivider;
    }

    public boolean isSelectable() {
        return mEntryType == ENTRY_TYPE_PERSON;
    }

    @Override
    public String toString() {
        return mDisplayName + " <" + mDestination + ">, isValid=" + mIsValid;
    }
}