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