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 
ConversationListItemData()72     public ConversationListItemData() {
73     }
74 
bind(final Cursor cursor)75     public void bind(final Cursor cursor) {
76         bind(cursor, false);
77     }
78 
bind(final Cursor cursor, final boolean ignoreDraft)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 
getConversationId()125     public String getConversationId() {
126         return mConversationId;
127     }
128 
getName()129     public String getName() {
130         return mName;
131     }
132 
getIcon()133     public String getIcon() {
134         return mIcon;
135     }
136 
getIsRead()137     public boolean getIsRead() {
138         return mIsRead;
139     }
140 
getFormattedTimestamp()141     public String getFormattedTimestamp() {
142         return Dates.getConversationTimeString(mTimestamp).toString();
143     }
144 
getTimestamp()145     public long getTimestamp() {
146         return mTimestamp;
147     }
148 
getSnippetText()149     public String getSnippetText() {
150         return mSnippetText;
151     }
152 
getPreviewUri()153     public Uri getPreviewUri() {
154         return mPreviewUri;
155     }
156 
getPreviewContentType()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       */
getParticipantContactId()165     public long getParticipantContactId() {
166         return mParticipantContactId;
167     }
168 
169     /**
170      * @see ConversationColumns#IS_ENTERPRISE
171      * @return whether the conversation is enterprise.
172      */
isEnterprise()173     public boolean isEnterprise() {
174         return mIsEnterprise;
175     }
176 
getParticipantLookupKey()177     public String getParticipantLookupKey() {
178         return mParticipantLookupKey;
179     }
180 
getOtherParticipantNormalizedDestination()181     public String getOtherParticipantNormalizedDestination() {
182         return mOtherParticipantNormalizedDestination;
183     }
184 
getSelfId()185     public String getSelfId() {
186         return mSelfId;
187     }
188 
getParticipantCount()189     public int getParticipantCount() {
190         return mParticipantCount;
191     }
192 
getIsGroup()193     public boolean getIsGroup() {
194         // Participant count excludes self
195         return (mParticipantCount > 1);
196     }
197 
getIncludeEmailAddress()198     public boolean getIncludeEmailAddress() {
199         return mIncludeEmailAddress;
200     }
201 
getNotificationEnabled()202     public boolean getNotificationEnabled() {
203         return mNotificationEnabled;
204     }
205 
getNotificationSoundUri()206     public String getNotificationSoundUri() {
207         return mNotificationSoundUri;
208     }
209 
getNotifiationVibrate()210     public boolean getNotifiationVibrate() {
211         return mNotificationVibrate;
212     }
213 
getIsFailedStatus()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 
getIsSendRequested()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 
getIsMessageTypeOutgoing()228     public boolean getIsMessageTypeOutgoing() {
229         return !MessageData.getIsIncoming(mMessageStatus);
230     }
231 
getMessageRawTelephonyStatus()232     public int getMessageRawTelephonyStatus() {
233         return mMessageRawTelephonyStatus;
234     }
235 
getMessageStatus()236     public int getMessageStatus() {
237         return mMessageStatus;
238     }
239 
getShowDraft()240     public boolean getShowDraft() {
241         return mShowDraft;
242     }
243 
getDraftSnippetText()244     public String getDraftSnippetText() {
245         return mDraftSnippetText;
246     }
247 
getDraftPreviewUri()248     public Uri getDraftPreviewUri() {
249         return mDraftPreviewUri;
250     }
251 
getDraftPreviewContentType()252     public String getDraftPreviewContentType() {
253         return mDraftPreviewContentType;
254     }
255 
getIsArchived()256     public boolean getIsArchived() {
257         return mIsArchived;
258     }
259 
getSubject()260     public String getSubject() {
261         return mSubject;
262     }
263 
getDraftSubject()264     public String getDraftSubject() {
265         return mDraftSubject;
266     }
267 
getSnippetSenderName()268     public String getSnippetSenderName() {
269         if (!TextUtils.isEmpty(mSnippetSenderFirstName)) {
270             return mSnippetSenderFirstName;
271         }
272         return mSnippetSenderDisplayDestination;
273     }
274 
deleteConversation()275     public void deleteConversation() {
276         DeleteConversationAction.deleteConversation(mConversationId, mTimestamp);
277     }
278 
279     /**
280      * Get the name of the view for this data item
281      */
getConversationListView()282     public static final String getConversationListView() {
283         return CONVERSATION_LIST_VIEW;
284     }
285 
getConversationListViewSql()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 
hasAnyEnterpriseContact( final List<ParticipantData> participants)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      */
getExistingConversation(final DatabaseWrapper dbWrapper, final String conversationId)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 
generateConversationName(final List<ParticipantData> participants)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