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     /* package */ 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 destination */
     65     private final long mDataId;
     66     private final boolean mIsDivider;
     67 
     68     private final Uri mPhotoThumbnailUri;
     69 
     70     private boolean mIsValid;
     71     /**
     72      * This can be updated after this object being constructed, when the photo is fetched
     73      * from remote directories.
     74      */
     75     private byte[] mPhotoBytes;
     76 
     77     private RecipientEntry(int entryType, String displayName, String destination,
     78             int destinationType, String destinationLabel, long contactId, long dataId,
     79             Uri photoThumbnailUri, boolean isFirstLevel, boolean isValid) {
     80         mEntryType = entryType;
     81         mIsFirstLevel = isFirstLevel;
     82         mDisplayName = displayName;
     83         mDestination = destination;
     84         mDestinationType = destinationType;
     85         mDestinationLabel = destinationLabel;
     86         mContactId = contactId;
     87         mDataId = dataId;
     88         mPhotoThumbnailUri = photoThumbnailUri;
     89         mPhotoBytes = null;
     90         mIsDivider = false;
     91         mIsValid = isValid;
     92     }
     93 
     94     public boolean isValid() {
     95         return mIsValid;
     96     }
     97 
     98     /**
     99      * Determine if this was a RecipientEntry created from recipient info or
    100      * an entry from contacts.
    101      */
    102     public static boolean isCreatedRecipient(long id) {
    103         return id == RecipientEntry.INVALID_CONTACT || id == RecipientEntry.GENERATED_CONTACT;
    104     }
    105 
    106     /**
    107      * Construct a RecipientEntry from just an address that has been entered.
    108      * This address has not been resolved to a contact and therefore does not
    109      * have a contact id or photo.
    110      */
    111     public static RecipientEntry constructFakeEntry(final String address, final boolean isValid) {
    112         final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
    113         final String tokenizedAddress = tokens.length > 0 ? tokens[0].getAddress() : address;
    114 
    115         return new RecipientEntry(ENTRY_TYPE_PERSON, tokenizedAddress, tokenizedAddress,
    116                 INVALID_DESTINATION_TYPE, null,
    117                 INVALID_CONTACT, INVALID_CONTACT, null, true, isValid);
    118     }
    119 
    120     /**
    121      * Construct a RecipientEntry from just a phone number.
    122      */
    123     public static RecipientEntry constructFakePhoneEntry(final String phoneNumber,
    124             final boolean isValid) {
    125         return new RecipientEntry(ENTRY_TYPE_PERSON, phoneNumber, phoneNumber,
    126                 INVALID_DESTINATION_TYPE, null,
    127                 INVALID_CONTACT, INVALID_CONTACT, null, true, isValid);
    128     }
    129 
    130     /**
    131      * @return the display name for the entry.  If the display name source is larger than
    132      * {@link DisplayNameSources#PHONE} we use the contact's display name, but if not,
    133      * i.e. the display name came from an email address or a phone number, we don't use it
    134      * to avoid confusion and just use the destination instead.
    135      */
    136     private static String pickDisplayName(int displayNameSource, String displayName,
    137             String destination) {
    138         return (displayNameSource > DisplayNameSources.PHONE) ? displayName : destination;
    139     }
    140 
    141     /**
    142      * Construct a RecipientEntry from just an address that has been entered
    143      * with both an associated display name. This address has not been resolved
    144      * to a contact and therefore does not have a contact id or photo.
    145      */
    146     public static RecipientEntry constructGeneratedEntry(String display, String address,
    147             boolean isValid) {
    148         return new RecipientEntry(ENTRY_TYPE_PERSON, display, address, INVALID_DESTINATION_TYPE,
    149                 null, GENERATED_CONTACT, GENERATED_CONTACT, null, true, isValid);
    150     }
    151 
    152     public static RecipientEntry constructTopLevelEntry(String displayName, int displayNameSource,
    153             String destination, int destinationType, String destinationLabel, long contactId,
    154             long dataId, Uri photoThumbnailUri, boolean isValid) {
    155         return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource,
    156                 displayName, destination), destination, destinationType, destinationLabel,
    157                 contactId, dataId, photoThumbnailUri, true, isValid);
    158     }
    159 
    160     public static RecipientEntry constructTopLevelEntry(String displayName, int displayNameSource,
    161             String destination, int destinationType, String destinationLabel, long contactId,
    162             long dataId, String thumbnailUriAsString, boolean isValid) {
    163         return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource,
    164                 displayName, destination), destination, destinationType, destinationLabel,
    165                 contactId, dataId, (thumbnailUriAsString != null ? Uri.parse(thumbnailUriAsString)
    166                         : null), true, isValid);
    167     }
    168 
    169     public static RecipientEntry constructSecondLevelEntry(String displayName,
    170             int displayNameSource, String destination, int destinationType,
    171             String destinationLabel, long contactId, long dataId, String thumbnailUriAsString,
    172             boolean isValid) {
    173         return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource,
    174                 displayName, destination), destination, destinationType, destinationLabel,
    175                 contactId, dataId, (thumbnailUriAsString != null ? Uri.parse(thumbnailUriAsString)
    176                         : null), false, isValid);
    177     }
    178 
    179     public int getEntryType() {
    180         return mEntryType;
    181     }
    182 
    183     public String getDisplayName() {
    184         return mDisplayName;
    185     }
    186 
    187     public String getDestination() {
    188         return mDestination;
    189     }
    190 
    191     public int getDestinationType() {
    192         return mDestinationType;
    193     }
    194 
    195     public String getDestinationLabel() {
    196         return mDestinationLabel;
    197     }
    198 
    199     public long getContactId() {
    200         return mContactId;
    201     }
    202 
    203     public long getDataId() {
    204         return mDataId;
    205     }
    206 
    207     public boolean isFirstLevel() {
    208         return mIsFirstLevel;
    209     }
    210 
    211     public Uri getPhotoThumbnailUri() {
    212         return mPhotoThumbnailUri;
    213     }
    214 
    215     /** This can be called outside main Looper thread. */
    216     public synchronized void setPhotoBytes(byte[] photoBytes) {
    217         mPhotoBytes = photoBytes;
    218     }
    219 
    220     /** This can be called outside main Looper thread. */
    221     public synchronized byte[] getPhotoBytes() {
    222         return mPhotoBytes;
    223     }
    224 
    225     public boolean isSeparator() {
    226         return mIsDivider;
    227     }
    228 
    229     public boolean isSelectable() {
    230         return mEntryType == ENTRY_TYPE_PERSON;
    231     }
    232 
    233     @Override
    234     public String toString() {
    235         return mDisplayName + " <" + mDestination + ">, isValid=" + mIsValid;
    236     }
    237 }