Home | History | Annotate | Download | only in dataitem
      1 /*
      2  * Copyright (C) 2012 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.contacts.model.dataitem;
     18 
     19 import android.content.ContentValues;
     20 import android.content.Context;
     21 import android.provider.ContactsContract.CommonDataKinds.Email;
     22 import android.provider.ContactsContract.CommonDataKinds.Event;
     23 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
     24 import android.provider.ContactsContract.CommonDataKinds.Identity;
     25 import android.provider.ContactsContract.CommonDataKinds.Im;
     26 import android.provider.ContactsContract.CommonDataKinds.Nickname;
     27 import android.provider.ContactsContract.CommonDataKinds.Note;
     28 import android.provider.ContactsContract.CommonDataKinds.Organization;
     29 import android.provider.ContactsContract.CommonDataKinds.Phone;
     30 import android.provider.ContactsContract.CommonDataKinds.Photo;
     31 import android.provider.ContactsContract.CommonDataKinds.Relation;
     32 import android.provider.ContactsContract.CommonDataKinds.SipAddress;
     33 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
     34 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
     35 import android.provider.ContactsContract.CommonDataKinds.Website;
     36 import android.provider.ContactsContract.Contacts.Data;
     37 import android.provider.ContactsContract.Contacts.Entity;
     38 
     39 import com.android.contacts.Collapser;
     40 import com.android.contacts.MoreContactUtils;
     41 import com.android.contacts.model.RawContactModifier;
     42 
     43 /**
     44  * This is the base class for data items, which represents a row from the Data table.
     45  */
     46 public class DataItem implements Collapser.Collapsible<DataItem> {
     47 
     48     private final ContentValues mContentValues;
     49     protected DataKind mKind;
     50 
     51     protected DataItem(ContentValues values) {
     52         mContentValues = values;
     53     }
     54 
     55     /**
     56      * Factory for creating subclasses of DataItem objects based on the mimetype in the
     57      * content values.  Raw contact is the raw contact that this data item is associated with.
     58      */
     59     public static DataItem createFrom(ContentValues values) {
     60         final String mimeType = values.getAsString(Data.MIMETYPE);
     61         if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
     62             return new GroupMembershipDataItem(values);
     63         } else if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
     64             return new StructuredNameDataItem(values);
     65         } else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
     66             return new PhoneDataItem(values);
     67         } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
     68             return new EmailDataItem(values);
     69         } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) {
     70             return new StructuredPostalDataItem(values);
     71         } else if (Im.CONTENT_ITEM_TYPE.equals(mimeType)) {
     72             return new ImDataItem(values);
     73         } else if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
     74             return new OrganizationDataItem(values);
     75         } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {
     76             return new NicknameDataItem(values);
     77         } else if (Note.CONTENT_ITEM_TYPE.equals(mimeType)) {
     78             return new NoteDataItem(values);
     79         } else if (Website.CONTENT_ITEM_TYPE.equals(mimeType)) {
     80             return new WebsiteDataItem(values);
     81         } else if (SipAddress.CONTENT_ITEM_TYPE.equals(mimeType)) {
     82             return new SipAddressDataItem(values);
     83         } else if (Event.CONTENT_ITEM_TYPE.equals(mimeType)) {
     84             return new EventDataItem(values);
     85         } else if (Relation.CONTENT_ITEM_TYPE.equals(mimeType)) {
     86             return new RelationDataItem(values);
     87         } else if (Identity.CONTENT_ITEM_TYPE.equals(mimeType)) {
     88             return new IdentityDataItem(values);
     89         } else if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
     90             return new PhotoDataItem(values);
     91         } else if (CustomDataItem.MIMETYPE_CUSTOM_FIELD.equals(mimeType)) {
     92             return new CustomDataItem(values);
     93         }
     94 
     95         // generic
     96         return new DataItem(values);
     97     }
     98 
     99     public ContentValues getContentValues() {
    100         return mContentValues;
    101     }
    102 
    103     public void setRawContactId(long rawContactId) {
    104         mContentValues.put(Data.RAW_CONTACT_ID, rawContactId);
    105     }
    106 
    107     public Long getRawContactId() {
    108         return mContentValues.getAsLong(Data.RAW_CONTACT_ID);
    109     }
    110 
    111     /**
    112      * Returns the data id.
    113      */
    114     public long getId() {
    115         return mContentValues.getAsLong(Data._ID);
    116     }
    117 
    118     /**
    119      * Returns the mimetype of the data.
    120      */
    121     public String getMimeType() {
    122         return mContentValues.getAsString(Data.MIMETYPE);
    123     }
    124 
    125     public void setMimeType(String mimeType) {
    126         mContentValues.put(Data.MIMETYPE, mimeType);
    127     }
    128 
    129     public boolean isPrimary() {
    130         Integer primary = mContentValues.getAsInteger(Data.IS_PRIMARY);
    131         return primary != null && primary != 0;
    132     }
    133 
    134     public boolean isSuperPrimary() {
    135         Integer superPrimary = mContentValues.getAsInteger(Data.IS_SUPER_PRIMARY);
    136         return superPrimary != null && superPrimary != 0;
    137     }
    138 
    139     public boolean hasKindTypeColumn(DataKind kind) {
    140         final String key = kind.typeColumn;
    141         return key != null && mContentValues.containsKey(key) &&
    142             mContentValues.getAsInteger(key) != null;
    143     }
    144 
    145     public int getKindTypeColumn(DataKind kind) {
    146         final String key = kind.typeColumn;
    147         return mContentValues.getAsInteger(key);
    148     }
    149 
    150     /**
    151      * Indicates the carrier presence value for the current {@link DataItem}.
    152      *
    153      * @return {@link Data#CARRIER_PRESENCE_VT_CAPABLE} if the {@link DataItem} supports carrier
    154      *      video calling, {@code 0} otherwise.
    155      */
    156     public int getCarrierPresence() {
    157         final Integer value = mContentValues.getAsInteger(Data.CARRIER_PRESENCE);
    158         return value != null ? value.intValue() : 0;
    159     }
    160 
    161     /**
    162      * This builds the data string depending on the type of data item by using the generic
    163      * DataKind object underneath.
    164      */
    165     public String buildDataString(Context context, DataKind kind) {
    166         if (kind.actionBody == null) {
    167             return null;
    168         }
    169         CharSequence actionBody = kind.actionBody.inflateUsing(context, mContentValues);
    170         return actionBody == null ? null : actionBody.toString();
    171     }
    172 
    173     /**
    174      * This builds the data string(intended for display) depending on the type of data item. It
    175      * returns the same value as {@link #buildDataString} by default, but certain data items can
    176      * override it to provide their version of formatted data strings.
    177      *
    178      * @return Data string representing the data item, possibly formatted for display
    179      */
    180     public String buildDataStringForDisplay(Context context, DataKind kind) {
    181         return buildDataString(context, kind);
    182     }
    183 
    184     public void setDataKind(DataKind kind) {
    185         mKind = kind;
    186     }
    187 
    188     public DataKind getDataKind() {
    189         return mKind;
    190     }
    191 
    192     public Integer getTimesUsed() {
    193         return mContentValues.getAsInteger(Entity.TIMES_USED);
    194     }
    195 
    196     public Long getLastTimeUsed() {
    197         return mContentValues.getAsLong(Entity.LAST_TIME_USED);
    198     }
    199 
    200     @Override
    201     public void collapseWith(DataItem that) {
    202         DataKind thisKind = getDataKind();
    203         DataKind thatKind = that.getDataKind();
    204         // If this does not have a type and that does, or if that's type is higher precedence,
    205         // use that's type
    206         if ((!hasKindTypeColumn(thisKind) && that.hasKindTypeColumn(thatKind)) ||
    207                 that.hasKindTypeColumn(thatKind) &&
    208                 RawContactModifier.getTypePrecedence(thisKind, getKindTypeColumn(thisKind))
    209                 >
    210                 RawContactModifier.getTypePrecedence(thatKind, that.getKindTypeColumn(thatKind))) {
    211             mContentValues.put(thatKind.typeColumn, that.getKindTypeColumn(thatKind));
    212             mKind = thatKind;
    213         }
    214 
    215         // Choose the max of the maxLines and maxLabelLines values.
    216         mKind.maxLinesForDisplay = Math.max(thisKind.maxLinesForDisplay,
    217                 thatKind.maxLinesForDisplay);
    218 
    219         // If any of the collapsed entries are super primary make the whole thing super primary.
    220         if (isSuperPrimary() || that.isSuperPrimary()) {
    221             mContentValues.put(Data.IS_SUPER_PRIMARY, 1);
    222             mContentValues.put(Data.IS_PRIMARY, 1);
    223         }
    224 
    225         // If any of the collapsed entries are primary make the whole thing primary.
    226         if (isPrimary() || that.isPrimary()) {
    227             mContentValues.put(Data.IS_PRIMARY, 1);
    228         }
    229 
    230         // Add up the times used
    231         mContentValues.put(Entity.TIMES_USED, (getTimesUsed() == null ? 0 : getTimesUsed()) +
    232                 (that.getTimesUsed() == null ? 0 : that.getTimesUsed()));
    233 
    234         // Use the most recent time
    235         mContentValues.put(Entity.LAST_TIME_USED,
    236                 Math.max(getLastTimeUsed() == null ? 0 : getLastTimeUsed(),
    237                         that.getLastTimeUsed() == null ? 0 : that.getLastTimeUsed()));
    238     }
    239 
    240     @Override
    241     public boolean shouldCollapseWith(DataItem t, Context context) {
    242         if (mKind == null || t.getDataKind() == null) {
    243             return false;
    244         }
    245         return MoreContactUtils.shouldCollapse(getMimeType(), buildDataString(context, mKind),
    246                 t.getMimeType(), t.buildDataString(context, t.getDataKind()));
    247     }
    248 }
    249