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.common.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.common.Collapser;
     40 import com.android.contacts.common.MoreContactUtils;
     41 import com.android.contacts.common.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         }
     92 
     93         // generic
     94         return new DataItem(values);
     95     }
     96 
     97     public ContentValues getContentValues() {
     98         return mContentValues;
     99     }
    100 
    101     public void setRawContactId(long rawContactId) {
    102         mContentValues.put(Data.RAW_CONTACT_ID, rawContactId);
    103     }
    104 
    105     public Long getRawContactId() {
    106         return mContentValues.getAsLong(Data.RAW_CONTACT_ID);
    107     }
    108 
    109     /**
    110      * Returns the data id.
    111      */
    112     public long getId() {
    113         return mContentValues.getAsLong(Data._ID);
    114     }
    115 
    116     /**
    117      * Returns the mimetype of the data.
    118      */
    119     public String getMimeType() {
    120         return mContentValues.getAsString(Data.MIMETYPE);
    121     }
    122 
    123     public void setMimeType(String mimeType) {
    124         mContentValues.put(Data.MIMETYPE, mimeType);
    125     }
    126 
    127     public boolean isPrimary() {
    128         Integer primary = mContentValues.getAsInteger(Data.IS_PRIMARY);
    129         return primary != null && primary != 0;
    130     }
    131 
    132     public boolean isSuperPrimary() {
    133         Integer superPrimary = mContentValues.getAsInteger(Data.IS_SUPER_PRIMARY);
    134         return superPrimary != null && superPrimary != 0;
    135     }
    136 
    137     public boolean hasKindTypeColumn(DataKind kind) {
    138         final String key = kind.typeColumn;
    139         return key != null && mContentValues.containsKey(key) &&
    140             mContentValues.getAsInteger(key) != null;
    141     }
    142 
    143     public int getKindTypeColumn(DataKind kind) {
    144         final String key = kind.typeColumn;
    145         return mContentValues.getAsInteger(key);
    146     }
    147 
    148     /**
    149      * Indicates the carrier presence value for the current {@link DataItem}.
    150      *
    151      * @return {@link Data#CARRIER_PRESENCE_VT_CAPABLE} if the {@link DataItem} supports carrier
    152      *      video calling, {@code 0} otherwise.
    153      */
    154     public int getCarrierPresence() {
    155         final Integer value = mContentValues.getAsInteger(Data.CARRIER_PRESENCE);
    156         return value != null ? value.intValue() : 0;
    157     }
    158 
    159     /**
    160      * This builds the data string depending on the type of data item by using the generic
    161      * DataKind object underneath.
    162      */
    163     public String buildDataString(Context context, DataKind kind) {
    164         if (kind.actionBody == null) {
    165             return null;
    166         }
    167         CharSequence actionBody = kind.actionBody.inflateUsing(context, mContentValues);
    168         return actionBody == null ? null : actionBody.toString();
    169     }
    170 
    171     /**
    172      * This builds the data string(intended for display) depending on the type of data item. It
    173      * returns the same value as {@link #buildDataString} by default, but certain data items can
    174      * override it to provide their version of formatted data strings.
    175      *
    176      * @return Data string representing the data item, possibly formatted for display
    177      */
    178     public String buildDataStringForDisplay(Context context, DataKind kind) {
    179         return buildDataString(context, kind);
    180     }
    181 
    182     public void setDataKind(DataKind kind) {
    183         mKind = kind;
    184     }
    185 
    186     public DataKind getDataKind() {
    187         return mKind;
    188     }
    189 
    190     public Integer getTimesUsed() {
    191         return mContentValues.getAsInteger(Entity.TIMES_USED);
    192     }
    193 
    194     public Long getLastTimeUsed() {
    195         return mContentValues.getAsLong(Entity.LAST_TIME_USED);
    196     }
    197 
    198     @Override
    199     public void collapseWith(DataItem that) {
    200         DataKind thisKind = getDataKind();
    201         DataKind thatKind = that.getDataKind();
    202         // If this does not have a type and that does, or if that's type is higher precedence,
    203         // use that's type
    204         if ((!hasKindTypeColumn(thisKind) && that.hasKindTypeColumn(thatKind)) ||
    205                 that.hasKindTypeColumn(thatKind) &&
    206                 RawContactModifier.getTypePrecedence(thisKind, getKindTypeColumn(thisKind))
    207                 >
    208                 RawContactModifier.getTypePrecedence(thatKind, that.getKindTypeColumn(thatKind))) {
    209             mContentValues.put(thatKind.typeColumn, that.getKindTypeColumn(thatKind));
    210             mKind = thatKind;
    211         }
    212 
    213         // Choose the max of the maxLines and maxLabelLines values.
    214         mKind.maxLinesForDisplay = Math.max(thisKind.maxLinesForDisplay,
    215                 thatKind.maxLinesForDisplay);
    216 
    217         // If any of the collapsed entries are super primary make the whole thing super primary.
    218         if (isSuperPrimary() || that.isSuperPrimary()) {
    219             mContentValues.put(Data.IS_SUPER_PRIMARY, 1);
    220             mContentValues.put(Data.IS_PRIMARY, 1);
    221         }
    222 
    223         // If any of the collapsed entries are primary make the whole thing primary.
    224         if (isPrimary() || that.isPrimary()) {
    225             mContentValues.put(Data.IS_PRIMARY, 1);
    226         }
    227 
    228         // Add up the times used
    229         mContentValues.put(Entity.TIMES_USED, (getTimesUsed() == null ? 0 : getTimesUsed()) +
    230                 (that.getTimesUsed() == null ? 0 : that.getTimesUsed()));
    231 
    232         // Use the most recent time
    233         mContentValues.put(Entity.LAST_TIME_USED,
    234                 Math.max(getLastTimeUsed() == null ? 0 : getLastTimeUsed(),
    235                         that.getLastTimeUsed() == null ? 0 : that.getLastTimeUsed()));
    236     }
    237 
    238     @Override
    239     public boolean shouldCollapseWith(DataItem t, Context context) {
    240         if (mKind == null || t.getDataKind() == null) {
    241             return false;
    242         }
    243         return MoreContactUtils.shouldCollapse(getMimeType(), buildDataString(context, mKind),
    244                 t.getMimeType(), t.buildDataString(context, t.getDataKind()));
    245     }
    246 }
    247