Home | History | Annotate | Download | only in chips
      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     public 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 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;
     69 
     70     private final Uri mPhotoThumbnailUri;
     71 
     72     private boolean mIsValid;
     73     /**
     74      * This can be updated after this object being constructed, when the photo is fetched
     75      * from remote directories.
     76      */
     77     private byte[] mPhotoBytes;
     78 
     79     /** See {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} */
     80     private final String mLookupKey;
     81 
     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,
     85             String lookupKey) {
     86         mEntryType = entryType;
     87         mIsFirstLevel = isFirstLevel;
     88         mDisplayName = displayName;
     89         mDestination = destination;
     90         mDestinationType = destinationType;
     91         mDestinationLabel = destinationLabel;
     92         mContactId = contactId;
     93         mDirectoryId = directoryId;
     94         mDataId = dataId;
     95         mPhotoThumbnailUri = photoThumbnailUri;
     96         mPhotoBytes = null;
     97         mIsDivider = false;
     98         mIsValid = isValid;
     99         mLookupKey = lookupKey;
    100     }
    101 
    102     public boolean isValid() {
    103         return mIsValid;
    104     }
    105 
    106     /**
    107      * Determine if this was a RecipientEntry created from recipient info or
    108      * an entry from contacts.
    109      */
    110     public static boolean isCreatedRecipient(long id) {
    111         return id == RecipientEntry.INVALID_CONTACT || id == RecipientEntry.GENERATED_CONTACT;
    112     }
    113 
    114     /**
    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.
    118      */
    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;
    122 
    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 */);
    126     }
    127 
    128     /**
    129      * Construct a RecipientEntry from just a phone number.
    130      */
    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 */);
    136     }
    137 
    138     /**
    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.
    143      */
    144     private static String pickDisplayName(int displayNameSource, String displayName,
    145             String destination) {
    146         return (displayNameSource > DisplayNameSources.PHONE) ? displayName : destination;
    147     }
    148 
    149     /**
    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.
    153      */
    154     public static RecipientEntry constructGeneratedEntry(String display, String address,
    155             boolean isValid) {
    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 */);
    159     }
    160 
    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,
    164             String lookupKey) {
    165         return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource,
    166                 displayName, destination), destination, destinationType, destinationLabel,
    167                 contactId, directoryId, dataId, photoThumbnailUri, true, isValid, lookupKey);
    168     }
    169 
    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,
    173             String lookupKey) {
    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);
    178     }
    179 
    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);
    188     }
    189 
    190     public int getEntryType() {
    191         return mEntryType;
    192     }
    193 
    194     public String getDisplayName() {
    195         return mDisplayName;
    196     }
    197 
    198     public String getDestination() {
    199         return mDestination;
    200     }
    201 
    202     public int getDestinationType() {
    203         return mDestinationType;
    204     }
    205 
    206     public String getDestinationLabel() {
    207         return mDestinationLabel;
    208     }
    209 
    210     public long getContactId() {
    211         return mContactId;
    212     }
    213 
    214     public Long getDirectoryId() {
    215         return mDirectoryId;
    216     }
    217 
    218     public long getDataId() {
    219         return mDataId;
    220     }
    221 
    222     public boolean isFirstLevel() {
    223         return mIsFirstLevel;
    224     }
    225 
    226     public Uri getPhotoThumbnailUri() {
    227         return mPhotoThumbnailUri;
    228     }
    229 
    230     /** This can be called outside main Looper thread. */
    231     public synchronized void setPhotoBytes(byte[] photoBytes) {
    232         mPhotoBytes = photoBytes;
    233     }
    234 
    235     /** This can be called outside main Looper thread. */
    236     public synchronized byte[] getPhotoBytes() {
    237         return mPhotoBytes;
    238     }
    239 
    240     public boolean isSeparator() {
    241         return mIsDivider;
    242     }
    243 
    244     public boolean isSelectable() {
    245         return mEntryType == ENTRY_TYPE_PERSON;
    246     }
    247 
    248     public String getLookupKey() {
    249         return mLookupKey;
    250     }
    251 
    252     @Override
    253     public String toString() {
    254         return mDisplayName + " <" + mDestination + ">, isValid=" + mIsValid;
    255     }
    256 
    257     /**
    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.
    260      */
    261     public boolean isSamePerson(final RecipientEntry entry) {
    262         return entry != null && mContactId == entry.mContactId;
    263     }
    264 }