Home | History | Annotate | Download | only in data
      1 /*
      2  * Copyright (C) 2015 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.messaging.datamodel.data;
     18 
     19 import android.database.Cursor;
     20 import android.net.Uri;
     21 import android.provider.BaseColumns;
     22 import android.text.TextUtils;
     23 
     24 import com.android.messaging.datamodel.DatabaseHelper;
     25 import com.android.messaging.datamodel.DatabaseHelper.ConversationColumns;
     26 import com.android.messaging.datamodel.DatabaseHelper.MessageColumns;
     27 import com.android.messaging.datamodel.DatabaseHelper.ParticipantColumns;
     28 import com.android.messaging.datamodel.DatabaseWrapper;
     29 import com.android.messaging.datamodel.action.DeleteConversationAction;
     30 import com.android.messaging.util.Assert;
     31 import com.android.messaging.util.ContactUtil;
     32 import com.android.messaging.util.Dates;
     33 import com.google.common.base.Joiner;
     34 
     35 import java.util.ArrayList;
     36 import java.util.List;
     37 
     38 /**
     39  * Class wrapping the conversation list view used to display each item in conversation list
     40  */
     41 public class ConversationListItemData {
     42     private String mConversationId;
     43     private String mName;
     44     private String mIcon;
     45     private boolean mIsRead;
     46     private long mTimestamp;
     47     private String mSnippetText;
     48     private Uri mPreviewUri;
     49     private String mPreviewContentType;
     50     private long mParticipantContactId;
     51     private String mParticipantLookupKey;
     52     private String mOtherParticipantNormalizedDestination;
     53     private String mSelfId;
     54     private int mParticipantCount;
     55     private boolean mNotificationEnabled;
     56     private String mNotificationSoundUri;
     57     private boolean mNotificationVibrate;
     58     private boolean mIncludeEmailAddress;
     59     private int mMessageStatus;
     60     private int mMessageRawTelephonyStatus;
     61     private boolean mShowDraft;
     62     private Uri mDraftPreviewUri;
     63     private String mDraftPreviewContentType;
     64     private String mDraftSnippetText;
     65     private boolean mIsArchived;
     66     private String mSubject;
     67     private String mDraftSubject;
     68     private String mSnippetSenderFirstName;
     69     private String mSnippetSenderDisplayDestination;
     70     private boolean mIsEnterprise;
     71 
     72     public ConversationListItemData() {
     73     }
     74 
     75     public void bind(final Cursor cursor) {
     76         bind(cursor, false);
     77     }
     78 
     79     public void bind(final Cursor cursor, final boolean ignoreDraft) {
     80         mConversationId = cursor.getString(INDEX_ID);
     81         mName = cursor.getString(INDEX_CONVERSATION_NAME);
     82         mIcon = cursor.getString(INDEX_CONVERSATION_ICON);
     83         mSnippetText = cursor.getString(INDEX_SNIPPET_TEXT);
     84         mTimestamp = cursor.getLong(INDEX_SORT_TIMESTAMP);
     85         mIsRead = cursor.getInt(INDEX_READ) == 1;
     86         final String previewUriString = cursor.getString(INDEX_PREVIEW_URI);
     87         mPreviewUri = TextUtils.isEmpty(previewUriString) ? null : Uri.parse(previewUriString);
     88         mPreviewContentType = cursor.getString(INDEX_PREVIEW_CONTENT_TYPE);
     89         mParticipantContactId = cursor.getLong(INDEX_PARTICIPANT_CONTACT_ID);
     90         mParticipantLookupKey = cursor.getString(INDEX_PARTICIPANT_LOOKUP_KEY);
     91         mOtherParticipantNormalizedDestination = cursor.getString(
     92                 INDEX_OTHER_PARTICIPANT_NORMALIZED_DESTINATION);
     93         mSelfId = cursor.getString(INDEX_SELF_ID);
     94         mParticipantCount = cursor.getInt(INDEX_PARTICIPANT_COUNT);
     95         mNotificationEnabled = cursor.getInt(INDEX_NOTIFICATION_ENABLED) == 1;
     96         mNotificationSoundUri = cursor.getString(INDEX_NOTIFICATION_SOUND_URI);
     97         mNotificationVibrate = cursor.getInt(INDEX_NOTIFICATION_VIBRATION) == 1;
     98         mIncludeEmailAddress = cursor.getInt(INDEX_INCLUDE_EMAIL_ADDRESS) == 1;
     99         mMessageStatus = cursor.getInt(INDEX_MESSAGE_STATUS);
    100         mMessageRawTelephonyStatus = cursor.getInt(INDEX_MESSAGE_RAW_TELEPHONY_STATUS);
    101         if (!ignoreDraft) {
    102             mShowDraft = cursor.getInt(INDEX_SHOW_DRAFT) == 1;
    103             final String draftPreviewUriString = cursor.getString(INDEX_DRAFT_PREVIEW_URI);
    104             mDraftPreviewUri = TextUtils.isEmpty(draftPreviewUriString) ?
    105                     null : Uri.parse(draftPreviewUriString);
    106             mDraftPreviewContentType = cursor.getString(INDEX_DRAFT_PREVIEW_CONTENT_TYPE);
    107             mDraftSnippetText = cursor.getString(INDEX_DRAFT_SNIPPET_TEXT);
    108             mDraftSubject = cursor.getString(INDEX_DRAFT_SUBJECT_TEXT);
    109         } else {
    110             mShowDraft = false;
    111             mDraftPreviewUri = null;
    112             mDraftPreviewContentType = null;
    113             mDraftSnippetText = null;
    114             mDraftSubject = null;
    115         }
    116 
    117         mIsArchived = cursor.getInt(INDEX_ARCHIVE_STATUS) == 1;
    118         mSubject = cursor.getString(INDEX_SUBJECT_TEXT);
    119         mSnippetSenderFirstName = cursor.getString(INDEX_SNIPPET_SENDER_FIRST_NAME);
    120         mSnippetSenderDisplayDestination =
    121                 cursor.getString(INDEX_SNIPPET_SENDER_DISPLAY_DESTINATION);
    122         mIsEnterprise = cursor.getInt(INDEX_IS_ENTERPRISE) == 1;
    123     }
    124 
    125     public String getConversationId() {
    126         return mConversationId;
    127     }
    128 
    129     public String getName() {
    130         return mName;
    131     }
    132 
    133     public String getIcon() {
    134         return mIcon;
    135     }
    136 
    137     public boolean getIsRead() {
    138         return mIsRead;
    139     }
    140 
    141     public String getFormattedTimestamp() {
    142         return Dates.getConversationTimeString(mTimestamp).toString();
    143     }
    144 
    145     public long getTimestamp() {
    146         return mTimestamp;
    147     }
    148 
    149     public String getSnippetText() {
    150         return mSnippetText;
    151     }
    152 
    153     public Uri getPreviewUri() {
    154         return mPreviewUri;
    155     }
    156 
    157     public String getPreviewContentType() {
    158         return mPreviewContentType;
    159     }
    160 
    161     /**
    162       * @see ConversationColumns#PARTICIPANT_CONTACT_ID
    163       * @return the contact id of the participant if it is a 1:1 conversation, -1 for group.
    164       */
    165     public long getParticipantContactId() {
    166         return mParticipantContactId;
    167     }
    168 
    169     /**
    170      * @see ConversationColumns#IS_ENTERPRISE
    171      * @return whether the conversation is enterprise.
    172      */
    173     public boolean isEnterprise() {
    174         return mIsEnterprise;
    175     }
    176 
    177     public String getParticipantLookupKey() {
    178         return mParticipantLookupKey;
    179     }
    180 
    181     public String getOtherParticipantNormalizedDestination() {
    182         return mOtherParticipantNormalizedDestination;
    183     }
    184 
    185     public String getSelfId() {
    186         return mSelfId;
    187     }
    188 
    189     public int getParticipantCount() {
    190         return mParticipantCount;
    191     }
    192 
    193     public boolean getIsGroup() {
    194         // Participant count excludes self
    195         return (mParticipantCount > 1);
    196     }
    197 
    198     public boolean getIncludeEmailAddress() {
    199         return mIncludeEmailAddress;
    200     }
    201 
    202     public boolean getNotificationEnabled() {
    203         return mNotificationEnabled;
    204     }
    205 
    206     public String getNotificationSoundUri() {
    207         return mNotificationSoundUri;
    208     }
    209 
    210     public boolean getNotifiationVibrate() {
    211         return mNotificationVibrate;
    212     }
    213 
    214     public final boolean getIsFailedStatus() {
    215         return (mMessageStatus == MessageData.BUGLE_STATUS_OUTGOING_FAILED ||
    216                 mMessageStatus == MessageData.BUGLE_STATUS_OUTGOING_FAILED_EMERGENCY_NUMBER ||
    217                 mMessageStatus == MessageData.BUGLE_STATUS_INCOMING_DOWNLOAD_FAILED ||
    218                 mMessageStatus == MessageData.BUGLE_STATUS_INCOMING_EXPIRED_OR_NOT_AVAILABLE);
    219     }
    220 
    221     public final boolean getIsSendRequested() {
    222         return (mMessageStatus == MessageData.BUGLE_STATUS_OUTGOING_YET_TO_SEND ||
    223                 mMessageStatus == MessageData.BUGLE_STATUS_OUTGOING_AWAITING_RETRY ||
    224                 mMessageStatus == MessageData.BUGLE_STATUS_OUTGOING_SENDING ||
    225                 mMessageStatus == MessageData.BUGLE_STATUS_OUTGOING_RESENDING);
    226     }
    227 
    228     public boolean getIsMessageTypeOutgoing() {
    229         return !MessageData.getIsIncoming(mMessageStatus);
    230     }
    231 
    232     public int getMessageRawTelephonyStatus() {
    233         return mMessageRawTelephonyStatus;
    234     }
    235 
    236     public int getMessageStatus() {
    237         return mMessageStatus;
    238     }
    239 
    240     public boolean getShowDraft() {
    241         return mShowDraft;
    242     }
    243 
    244     public String getDraftSnippetText() {
    245         return mDraftSnippetText;
    246     }
    247 
    248     public Uri getDraftPreviewUri() {
    249         return mDraftPreviewUri;
    250     }
    251 
    252     public String getDraftPreviewContentType() {
    253         return mDraftPreviewContentType;
    254     }
    255 
    256     public boolean getIsArchived() {
    257         return mIsArchived;
    258     }
    259 
    260     public String getSubject() {
    261         return mSubject;
    262     }
    263 
    264     public String getDraftSubject() {
    265         return mDraftSubject;
    266     }
    267 
    268     public String getSnippetSenderName() {
    269         if (!TextUtils.isEmpty(mSnippetSenderFirstName)) {
    270             return mSnippetSenderFirstName;
    271         }
    272         return mSnippetSenderDisplayDestination;
    273     }
    274 
    275     public void deleteConversation() {
    276         DeleteConversationAction.deleteConversation(mConversationId, mTimestamp);
    277     }
    278 
    279     /**
    280      * Get the name of the view for this data item
    281      */
    282     public static final String getConversationListView() {
    283         return CONVERSATION_LIST_VIEW;
    284     }
    285 
    286     public static final String getConversationListViewSql() {
    287         return CONVERSATION_LIST_VIEW_SQL;
    288     }
    289 
    290     private static final String CONVERSATION_LIST_VIEW = "conversation_list_view";
    291 
    292     private static final String CONVERSATION_LIST_VIEW_PROJECTION =
    293             DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns._ID
    294             + " as " + ConversationListViewColumns._ID + ", "
    295             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.NAME
    296             + " as " + ConversationListViewColumns.NAME + ", "
    297             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.CURRENT_SELF_ID
    298             + " as " + ConversationListViewColumns.CURRENT_SELF_ID + ", "
    299             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.ARCHIVE_STATUS
    300             + " as " + ConversationListViewColumns.ARCHIVE_STATUS + ", "
    301             + DatabaseHelper.MESSAGES_TABLE + '.' + MessageColumns.READ
    302             + " as " + ConversationListViewColumns.READ + ", "
    303             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.ICON
    304             + " as " + ConversationListViewColumns.ICON + ", "
    305             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.PARTICIPANT_CONTACT_ID
    306             + " as " + ConversationListViewColumns.PARTICIPANT_CONTACT_ID + ", "
    307             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.PARTICIPANT_LOOKUP_KEY
    308             + " as " + ConversationListViewColumns.PARTICIPANT_LOOKUP_KEY + ", "
    309             + DatabaseHelper.CONVERSATIONS_TABLE + '.'
    310                     + ConversationColumns.OTHER_PARTICIPANT_NORMALIZED_DESTINATION
    311             + " as " + ConversationListViewColumns.OTHER_PARTICIPANT_NORMALIZED_DESTINATION + ", "
    312             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.SORT_TIMESTAMP
    313             + " as " + ConversationListViewColumns.SORT_TIMESTAMP + ", "
    314             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.SHOW_DRAFT
    315             + " as " + ConversationListViewColumns.SHOW_DRAFT + ", "
    316             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.DRAFT_SNIPPET_TEXT
    317             + " as " + ConversationListViewColumns.DRAFT_SNIPPET_TEXT + ", "
    318             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.DRAFT_PREVIEW_URI
    319             + " as " + ConversationListViewColumns.DRAFT_PREVIEW_URI + ", "
    320             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.DRAFT_SUBJECT_TEXT
    321             + " as " + ConversationListViewColumns.DRAFT_SUBJECT_TEXT + ", "
    322             + DatabaseHelper.CONVERSATIONS_TABLE + '.'
    323                     + ConversationColumns.DRAFT_PREVIEW_CONTENT_TYPE
    324             + " as " + ConversationListViewColumns.DRAFT_PREVIEW_CONTENT_TYPE + ", "
    325             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.PREVIEW_URI
    326             + " as " + ConversationListViewColumns.PREVIEW_URI + ", "
    327             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.PREVIEW_CONTENT_TYPE
    328             + " as " + ConversationListViewColumns.PREVIEW_CONTENT_TYPE + ", "
    329             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.PARTICIPANT_COUNT
    330             + " as " + ConversationListViewColumns.PARTICIPANT_COUNT + ", "
    331             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.NOTIFICATION_ENABLED
    332             + " as " + ConversationListViewColumns.NOTIFICATION_ENABLED + ", "
    333             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.NOTIFICATION_SOUND_URI
    334             + " as " + ConversationListViewColumns.NOTIFICATION_SOUND_URI + ", "
    335             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.NOTIFICATION_VIBRATION
    336             + " as " + ConversationListViewColumns.NOTIFICATION_VIBRATION + ", "
    337             + DatabaseHelper.CONVERSATIONS_TABLE + '.' +
    338                     ConversationColumns.INCLUDE_EMAIL_ADDRESS
    339             + " as " + ConversationListViewColumns.INCLUDE_EMAIL_ADDRESS + ", "
    340             + DatabaseHelper.MESSAGES_TABLE + '.' + MessageColumns.STATUS
    341             + " as " + ConversationListViewColumns.MESSAGE_STATUS + ", "
    342             + DatabaseHelper.MESSAGES_TABLE + '.' + MessageColumns.RAW_TELEPHONY_STATUS
    343             + " as " + ConversationListViewColumns.MESSAGE_RAW_TELEPHONY_STATUS + ", "
    344             + DatabaseHelper.MESSAGES_TABLE + '.' + MessageColumns._ID
    345             + " as " + ConversationListViewColumns.MESSAGE_ID + ", "
    346             + DatabaseHelper.PARTICIPANTS_TABLE + '.' + ParticipantColumns.FIRST_NAME
    347             + " as " + ConversationListViewColumns.SNIPPET_SENDER_FIRST_NAME + ", "
    348             + DatabaseHelper.PARTICIPANTS_TABLE + '.' + ParticipantColumns.DISPLAY_DESTINATION
    349             + " as " + ConversationListViewColumns.SNIPPET_SENDER_DISPLAY_DESTINATION + ", "
    350             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.IS_ENTERPRISE
    351             + " as " + ConversationListViewColumns.IS_ENTERPRISE;
    352 
    353     private static final String JOIN_PARTICIPANTS =
    354             " LEFT JOIN " + DatabaseHelper.PARTICIPANTS_TABLE + " ON ("
    355             + DatabaseHelper.MESSAGES_TABLE + '.' + MessageColumns.SENDER_PARTICIPANT_ID
    356             + '=' + DatabaseHelper.PARTICIPANTS_TABLE + '.' + DatabaseHelper.ParticipantColumns._ID
    357             + ") ";
    358 
    359     // View that makes latest message read flag available with rest of conversation data.
    360     private static final String CONVERSATION_LIST_VIEW_SQL = "CREATE VIEW " +
    361             CONVERSATION_LIST_VIEW + " AS SELECT "
    362             + CONVERSATION_LIST_VIEW_PROJECTION + ", "
    363             // Snippet not part of the base projection shared with search view
    364             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.SNIPPET_TEXT
    365             + " as " + ConversationListViewColumns.SNIPPET_TEXT + ", "
    366             + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.SUBJECT_TEXT
    367             + " as " + ConversationListViewColumns.SUBJECT_TEXT + " "
    368             + " FROM " + DatabaseHelper.CONVERSATIONS_TABLE
    369             + " LEFT JOIN " + DatabaseHelper.MESSAGES_TABLE + " ON ("
    370             + DatabaseHelper.CONVERSATIONS_TABLE + '.' +  ConversationColumns.LATEST_MESSAGE_ID
    371             + '=' + DatabaseHelper.MESSAGES_TABLE + '.' + MessageColumns._ID + ") "
    372             + JOIN_PARTICIPANTS
    373             + "ORDER BY " + DatabaseHelper.CONVERSATIONS_TABLE + '.'
    374             + ConversationColumns.SORT_TIMESTAMP + " DESC";
    375 
    376     public static class ConversationListViewColumns implements BaseColumns {
    377         public static final String _ID = ConversationColumns._ID;
    378         static final String NAME = ConversationColumns.NAME;
    379         static final String ARCHIVE_STATUS = ConversationColumns.ARCHIVE_STATUS;
    380         static final String READ = MessageColumns.READ;
    381         static final String SORT_TIMESTAMP = ConversationColumns.SORT_TIMESTAMP;
    382         static final String PREVIEW_URI = ConversationColumns.PREVIEW_URI;
    383         static final String PREVIEW_CONTENT_TYPE = ConversationColumns.PREVIEW_CONTENT_TYPE;
    384         static final String SNIPPET_TEXT = ConversationColumns.SNIPPET_TEXT;
    385         static final String SUBJECT_TEXT = ConversationColumns.SUBJECT_TEXT;
    386         static final String ICON = ConversationColumns.ICON;
    387         static final String SHOW_DRAFT = ConversationColumns.SHOW_DRAFT;
    388         static final String DRAFT_SUBJECT_TEXT = ConversationColumns.DRAFT_SUBJECT_TEXT;
    389         static final String DRAFT_PREVIEW_URI = ConversationColumns.DRAFT_PREVIEW_URI;
    390         static final String DRAFT_PREVIEW_CONTENT_TYPE =
    391                 ConversationColumns.DRAFT_PREVIEW_CONTENT_TYPE;
    392         static final String DRAFT_SNIPPET_TEXT = ConversationColumns.DRAFT_SNIPPET_TEXT;
    393         static final String PARTICIPANT_CONTACT_ID = ConversationColumns.PARTICIPANT_CONTACT_ID;
    394         static final String PARTICIPANT_LOOKUP_KEY = ConversationColumns.PARTICIPANT_LOOKUP_KEY;
    395         static final String OTHER_PARTICIPANT_NORMALIZED_DESTINATION =
    396                 ConversationColumns.OTHER_PARTICIPANT_NORMALIZED_DESTINATION;
    397         static final String CURRENT_SELF_ID = ConversationColumns.CURRENT_SELF_ID;
    398         static final String PARTICIPANT_COUNT = ConversationColumns.PARTICIPANT_COUNT;
    399         static final String NOTIFICATION_ENABLED = ConversationColumns.NOTIFICATION_ENABLED;
    400         static final String NOTIFICATION_SOUND_URI = ConversationColumns.NOTIFICATION_SOUND_URI;
    401         static final String NOTIFICATION_VIBRATION = ConversationColumns.NOTIFICATION_VIBRATION;
    402         static final String INCLUDE_EMAIL_ADDRESS =
    403                 ConversationColumns.INCLUDE_EMAIL_ADDRESS;
    404         static final String MESSAGE_STATUS = MessageColumns.STATUS;
    405         static final String MESSAGE_RAW_TELEPHONY_STATUS = MessageColumns.RAW_TELEPHONY_STATUS;
    406         static final String MESSAGE_ID = "message_id";
    407         static final String SNIPPET_SENDER_FIRST_NAME = "snippet_sender_first_name";
    408         static final String SNIPPET_SENDER_DISPLAY_DESTINATION =
    409                 "snippet_sender_display_destination";
    410         static final String IS_ENTERPRISE = ConversationColumns.IS_ENTERPRISE;
    411     }
    412 
    413     public static final String[] PROJECTION = {
    414         ConversationListViewColumns._ID,
    415         ConversationListViewColumns.NAME,
    416         ConversationListViewColumns.ICON,
    417         ConversationListViewColumns.SNIPPET_TEXT,
    418         ConversationListViewColumns.SORT_TIMESTAMP,
    419         ConversationListViewColumns.READ,
    420         ConversationListViewColumns.PREVIEW_URI,
    421         ConversationListViewColumns.PREVIEW_CONTENT_TYPE,
    422         ConversationListViewColumns.PARTICIPANT_CONTACT_ID,
    423         ConversationListViewColumns.PARTICIPANT_LOOKUP_KEY,
    424         ConversationListViewColumns.OTHER_PARTICIPANT_NORMALIZED_DESTINATION,
    425         ConversationListViewColumns.PARTICIPANT_COUNT,
    426         ConversationListViewColumns.CURRENT_SELF_ID,
    427         ConversationListViewColumns.NOTIFICATION_ENABLED,
    428         ConversationListViewColumns.NOTIFICATION_SOUND_URI,
    429         ConversationListViewColumns.NOTIFICATION_VIBRATION,
    430         ConversationListViewColumns.INCLUDE_EMAIL_ADDRESS,
    431         ConversationListViewColumns.MESSAGE_STATUS,
    432         ConversationListViewColumns.SHOW_DRAFT,
    433         ConversationListViewColumns.DRAFT_PREVIEW_URI,
    434         ConversationListViewColumns.DRAFT_PREVIEW_CONTENT_TYPE,
    435         ConversationListViewColumns.DRAFT_SNIPPET_TEXT,
    436         ConversationListViewColumns.ARCHIVE_STATUS,
    437         ConversationListViewColumns.MESSAGE_ID,
    438         ConversationListViewColumns.SUBJECT_TEXT,
    439         ConversationListViewColumns.DRAFT_SUBJECT_TEXT,
    440         ConversationListViewColumns.MESSAGE_RAW_TELEPHONY_STATUS,
    441         ConversationListViewColumns.SNIPPET_SENDER_FIRST_NAME,
    442         ConversationListViewColumns.SNIPPET_SENDER_DISPLAY_DESTINATION,
    443         ConversationListViewColumns.IS_ENTERPRISE,
    444     };
    445 
    446     private static final int INDEX_ID = 0;
    447     private static final int INDEX_CONVERSATION_NAME = 1;
    448     private static final int INDEX_CONVERSATION_ICON = 2;
    449     private static final int INDEX_SNIPPET_TEXT = 3;
    450     private static final int INDEX_SORT_TIMESTAMP = 4;
    451     private static final int INDEX_READ = 5;
    452     private static final int INDEX_PREVIEW_URI = 6;
    453     private static final int INDEX_PREVIEW_CONTENT_TYPE = 7;
    454     private static final int INDEX_PARTICIPANT_CONTACT_ID = 8;
    455     private static final int INDEX_PARTICIPANT_LOOKUP_KEY = 9;
    456     private static final int INDEX_OTHER_PARTICIPANT_NORMALIZED_DESTINATION = 10;
    457     private static final int INDEX_PARTICIPANT_COUNT = 11;
    458     private static final int INDEX_SELF_ID = 12;
    459     private static final int INDEX_NOTIFICATION_ENABLED = 13;
    460     private static final int INDEX_NOTIFICATION_SOUND_URI = 14;
    461     private static final int INDEX_NOTIFICATION_VIBRATION = 15;
    462     private static final int INDEX_INCLUDE_EMAIL_ADDRESS = 16;
    463     private static final int INDEX_MESSAGE_STATUS = 17;
    464     private static final int INDEX_SHOW_DRAFT = 18;
    465     private static final int INDEX_DRAFT_PREVIEW_URI = 19;
    466     private static final int INDEX_DRAFT_PREVIEW_CONTENT_TYPE = 20;
    467     private static final int INDEX_DRAFT_SNIPPET_TEXT = 21;
    468     private static final int INDEX_ARCHIVE_STATUS = 22;
    469     private static final int INDEX_MESSAGE_ID = 23;
    470     private static final int INDEX_SUBJECT_TEXT = 24;
    471     private static final int INDEX_DRAFT_SUBJECT_TEXT = 25;
    472     private static final int INDEX_MESSAGE_RAW_TELEPHONY_STATUS = 26;
    473     private static final int INDEX_SNIPPET_SENDER_FIRST_NAME = 27;
    474     private static final int INDEX_SNIPPET_SENDER_DISPLAY_DESTINATION = 28;
    475     private static final int INDEX_IS_ENTERPRISE = 29;
    476 
    477     private static final String DIVIDER_TEXT = ", ";
    478 
    479     public static boolean hasAnyEnterpriseContact(
    480              final List<ParticipantData> participants) {
    481          for (final ParticipantData participant : participants) {
    482              if (ContactUtil.isEnterpriseContactId(participant.getContactId())) {
    483                  return true;
    484              }
    485          }
    486          return false;
    487      }
    488 
    489     /**
    490      * Get a conversation from the local DB based on the conversation id.
    491      *
    492      * @param dbWrapper       The database
    493      * @param conversationId  The conversation Id to read
    494      * @return The existing conversation or null
    495      */
    496     public static ConversationListItemData getExistingConversation(final DatabaseWrapper dbWrapper,
    497             final String conversationId) {
    498         ConversationListItemData conversation = null;
    499 
    500         // Look for an existing conversation in the db with this conversation id
    501         Cursor cursor = null;
    502         try {
    503             // TODO: Should we be able to read a row from just the conversation table?
    504             cursor = dbWrapper.query(getConversationListView(),
    505                     PROJECTION,
    506                     ConversationColumns._ID + "=?",
    507                     new String[] { conversationId },
    508                     null, null, null);
    509             Assert.inRange(cursor.getCount(), 0, 1);
    510             if (cursor.moveToFirst()) {
    511                 conversation = new ConversationListItemData();
    512                 conversation.bind(cursor);
    513             }
    514         } finally {
    515             if (cursor != null) {
    516                 cursor.close();
    517             }
    518         }
    519 
    520         return conversation;
    521     }
    522 
    523     public static String generateConversationName(final List<ParticipantData>
    524             participants) {
    525         if (participants.size() == 1) {
    526             // Prefer full name over first name for 1:1 conversation
    527             return participants.get(0).getDisplayName(true);
    528         }
    529 
    530         final ArrayList<String> participantNames = new ArrayList<String>();
    531         for (final ParticipantData participant : participants) {
    532             // Prefer first name over full name for group conversation
    533             participantNames.add(participant.getDisplayName(false));
    534         }
    535 
    536         final Joiner joiner = Joiner.on(DIVIDER_TEXT).skipNulls();
    537         return joiner.join(participantNames);
    538     }
    539 
    540 }
    541