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.content.ContentValues;
     20 import android.database.sqlite.SQLiteDatabase;
     21 import android.net.Uri;
     22 import android.provider.BaseColumns;
     23 import android.provider.ContactsContract.CommonDataKinds.Phone;
     24 import android.provider.ContactsContract.Contacts;
     25 import android.provider.MediaStore.Images.Media;
     26 
     27 import com.android.messaging.datamodel.BugleDatabaseOperations;
     28 import com.android.messaging.datamodel.DatabaseHelper;
     29 import com.android.messaging.datamodel.DatabaseHelper.ConversationColumns;
     30 import com.android.messaging.datamodel.DatabaseHelper.MessageColumns;
     31 import com.android.messaging.datamodel.DatabaseHelper.PartColumns;
     32 import com.android.messaging.datamodel.DatabaseHelper.ParticipantColumns;
     33 import com.android.messaging.datamodel.FakeCursor;
     34 import com.android.messaging.datamodel.data.ConversationListItemData.ConversationListViewColumns;
     35 import com.android.messaging.datamodel.data.ConversationMessageData.ConversationMessageViewColumns;
     36 import com.android.messaging.util.Assert;
     37 import com.android.messaging.util.ContactUtil;
     38 import com.android.messaging.util.ContentType;
     39 
     40 import java.util.Arrays;
     41 import java.util.List;
     42 
     43 /**
     44  * A factory for fake objects that can be useful for multiple tests.
     45  */
     46 public class TestDataFactory {
     47     private final static String[] sConversationListCursorColumns = new String[] {
     48         ConversationListViewColumns._ID,
     49         ConversationListViewColumns.NAME,
     50         ConversationListViewColumns.ICON,
     51         ConversationListViewColumns.SNIPPET_TEXT,
     52         ConversationListViewColumns.PREVIEW_URI,
     53         ConversationListViewColumns.SORT_TIMESTAMP,
     54         ConversationListViewColumns.READ,
     55         ConversationListViewColumns.PREVIEW_CONTENT_TYPE,
     56         ConversationListViewColumns.MESSAGE_STATUS,
     57     };
     58 
     59     private final static String[] sContactCursorColumns = new String[] {
     60             Phone.CONTACT_ID,
     61             Phone.DISPLAY_NAME_PRIMARY,
     62             Phone.PHOTO_THUMBNAIL_URI,
     63             Phone.NUMBER,
     64             Phone.TYPE,
     65             Phone.LABEL,
     66             Phone.LOOKUP_KEY,
     67             Phone._ID,
     68             Phone.SORT_KEY_PRIMARY,
     69     };
     70 
     71     private final static String[] sFrequentContactCursorColumns = new String[] {
     72             Contacts._ID,
     73             Contacts.DISPLAY_NAME,
     74             Contacts.PHOTO_URI,
     75             Phone.LOOKUP_KEY,
     76     };
     77 
     78     private final static String[] sConversationMessageCursorColumns = new String[] {
     79         ConversationMessageViewColumns._ID,
     80         ConversationMessageViewColumns.CONVERSATION_ID,
     81         ConversationMessageViewColumns.PARTICIPANT_ID,
     82         ConversationMessageViewColumns.SENT_TIMESTAMP,
     83         ConversationMessageViewColumns.RECEIVED_TIMESTAMP,
     84         ConversationMessageViewColumns.STATUS,
     85         ConversationMessageViewColumns.SENDER_FULL_NAME,
     86         ConversationMessageViewColumns.SENDER_PROFILE_PHOTO_URI,
     87         ConversationMessageViewColumns.PARTS_IDS,
     88         ConversationMessageViewColumns.PARTS_CONTENT_TYPES,
     89         ConversationMessageViewColumns.PARTS_CONTENT_URIS,
     90         ConversationMessageViewColumns.PARTS_WIDTHS,
     91         ConversationMessageViewColumns.PARTS_HEIGHTS,
     92         ConversationMessageViewColumns.PARTS_TEXTS,
     93         ConversationMessageViewColumns.PARTS_COUNT
     94     };
     95 
     96     private final static String[] sGalleryCursorColumns = new String[] {
     97         Media._ID,
     98         Media.DATA,
     99         Media.WIDTH,
    100         Media.HEIGHT,
    101         Media.MIME_TYPE
    102     };
    103 
    104     public static FakeCursor getConversationListCursor() {
    105         final Object[][] cursorData = new Object[][] {
    106                 new Object[] { Long.valueOf(1), "name1", "content://icon1",
    107                         "snippetText1", "content://snippetUri1", Long.valueOf(10), 1,
    108                         ContentType.IMAGE_JPEG, MessageData.BUGLE_STATUS_INCOMING_COMPLETE},
    109                 new Object[] { Long.valueOf(2), "name2", "content://icon2",
    110                         "snippetText2", "content://snippetUri2", Long.valueOf(20) + 24*60*60*1000,
    111                         0, ContentType.IMAGE_JPEG, MessageData.BUGLE_STATUS_INCOMING_COMPLETE},
    112                 new Object[] { Long.valueOf(3), "name3", "content://icon3",
    113                         "snippetText3", "content://snippetUri3", Long.valueOf(30) + 2*24*60*60*1000,
    114                         0, ContentType.IMAGE_JPEG, MessageData.BUGLE_STATUS_OUTGOING_COMPLETE}
    115         };
    116         return new FakeCursor(ConversationListItemData.PROJECTION, sConversationListCursorColumns,
    117                 cursorData);
    118     }
    119     public static final int CONVERSATION_LIST_CURSOR_READ_MESSAGE_INDEX = 0;
    120     public static final int CONVERSATION_LIST_CURSOR_UNREAD_MESSAGE_INDEX = 1;
    121 
    122     public static FakeCursor getEmptyConversationListCursor() {
    123         return new FakeCursor(ConversationListItemData.PROJECTION, sConversationListCursorColumns,
    124                 new Object[][] {});
    125     }
    126 
    127     public static FakeCursor getConversationMessageCursor() {
    128         final Object[][] cursorData = new Object[][] {
    129                 new Object[] { Long.valueOf(0), Long.valueOf(1), Long.valueOf(1),
    130                         Long.valueOf(10), Long.valueOf(10),
    131                         MessageData.BUGLE_STATUS_INCOMING_COMPLETE, "Alice", null,
    132                         "0", "text/plain", "''", -1, -1, "msg0", 1},
    133                 new Object[] { Long.valueOf(1), Long.valueOf(1), Long.valueOf(2),
    134                         Long.valueOf(20), Long.valueOf(20),
    135                         MessageData.BUGLE_STATUS_OUTGOING_COMPLETE, "Bob", null,
    136                         "1", "text/plain", "''", -1, -1, "msg1", 1},
    137                 new Object[] { Long.valueOf(2), Long.valueOf(1), Long.valueOf(1),
    138                         Long.valueOf(30), Long.valueOf(30),
    139                         MessageData.BUGLE_STATUS_OUTGOING_COMPLETE, "Alice", null,
    140                         "2", "contentType3", "'content://fakeUri3'", "0", "0", "msg1", 1},
    141                 new Object[] { Long.valueOf(3), Long.valueOf(1), Long.valueOf(1),
    142                         Long.valueOf(40), Long.valueOf(40),
    143                         MessageData.BUGLE_STATUS_OUTGOING_COMPLETE, "Alice", null,
    144                         "3|4", "'contentType4'|'text/plain'", "'content://fakeUri4'|''", "0|-1", "0|-1", "''|'msg3'", 2},
    145         };
    146         return new FakeCursor(
    147                 ConversationMessageData.getProjection(),
    148                 sConversationMessageCursorColumns,
    149                 cursorData);
    150     }
    151 
    152     public static String getMessageText(final FakeCursor messageCursor, final int row) {
    153         final String allPartsText = messageCursor.getAt(ConversationMessageViewColumns.PARTS_TEXTS, row)
    154                 .toString();
    155         final int partsCount = (Integer) messageCursor.getAt(
    156                 ConversationMessageViewColumns.PARTS_COUNT, row);
    157         final String messageId = messageCursor.getAt(
    158                 ConversationMessageViewColumns._ID, row).toString();
    159         final List<MessagePartData> parts = ConversationMessageData.makeParts(
    160                 messageCursor.getAt(ConversationMessageViewColumns.PARTS_IDS, row).toString(),
    161                 messageCursor.getAt(ConversationMessageViewColumns.PARTS_CONTENT_TYPES, row).toString(),
    162                 messageCursor.getAt(ConversationMessageViewColumns.PARTS_CONTENT_URIS, row).toString(),
    163                 messageCursor.getAt(ConversationMessageViewColumns.PARTS_WIDTHS, row).toString(),
    164                 messageCursor.getAt(ConversationMessageViewColumns.PARTS_HEIGHTS, row).toString(),
    165                 messageCursor.getAt(ConversationMessageViewColumns.PARTS_TEXTS, row).toString(),
    166                 partsCount,
    167                 messageId);
    168 
    169         for (final MessagePartData part : parts) {
    170             if (part.isText()) {
    171                 return part.getText();
    172             }
    173         }
    174         return null;
    175     }
    176 
    177     // Indexes where to find consecutive and non consecutive messages from same participant
    178     // (respect to index - 1).
    179     public static final int MESSAGE_WITH_SAME_PARTICIPANT_AS_PREVIOUS = 3;
    180     public static final int MESSAGE_WITH_DIFFERENT_PARTICIPANT_AS_PREVIOUS = 2;
    181 
    182     public static FakeCursor getConversationParticipantsCursor() {
    183         final String[] sConversationParticipantsCursorColumns = new String[] {
    184                 ParticipantColumns._ID,
    185                 ParticipantColumns.SUB_ID,
    186                 ParticipantColumns.NORMALIZED_DESTINATION,
    187                 ParticipantColumns.SEND_DESTINATION,
    188                 ParticipantColumns.FULL_NAME,
    189                 ParticipantColumns.FIRST_NAME,
    190                 ParticipantColumns.PROFILE_PHOTO_URI,
    191         };
    192 
    193         final Object[][] cursorData = new Object[][] {
    194                 new Object[] { 1, ParticipantData.OTHER_THAN_SELF_SUB_ID, "+15554567890",
    195                         "(555)456-7890", "alice in wonderland", "alice", "alice.png" },
    196                 new Object[] { 2, ParticipantData.OTHER_THAN_SELF_SUB_ID, "+15551011121",
    197                         "(555)101-1121", "bob the baker", "bob", "bob.png"},
    198                 new Object[] { 3, ParticipantData.OTHER_THAN_SELF_SUB_ID, "+15551314152",
    199                         "(555)131-4152", "charles in charge", "charles", "charles.png" },
    200         };
    201 
    202         return new FakeCursor(ParticipantData.ParticipantsQuery.PROJECTION,
    203                 sConversationParticipantsCursorColumns, cursorData);
    204     }
    205 
    206     public static final int CONTACT_LIST_CURSOR_FIRST_LEVEL_CONTACT_INDEX = 0;
    207     public static final int CONTACT_LIST_CURSOR_SECOND_LEVEL_CONTACT_INDEX = 2;
    208 
    209     /**
    210      * Returns a cursor for the all contacts list consumable by ContactPickerFragment.
    211      */
    212     public static FakeCursor getAllContactListCursor() {
    213         final Object[][] cursorData = new Object[][] {
    214                 new Object[] { Long.valueOf(0), "John Smith", "content://uri1",
    215                         "425-555-1234", Phone.TYPE_HOME, "", "0", Long.valueOf(0), 0 },
    216                 new Object[] { Long.valueOf(1), "Sun Woo Kong", "content://uri2",
    217                         "425-555-1235", Phone.TYPE_MOBILE, "", "1", Long.valueOf(1), 1 },
    218                 new Object[] { Long.valueOf(1), "Sun Woo Kong", "content://uri2",
    219                         "425-555-1238", Phone.TYPE_HOME, "", "1", Long.valueOf(2), 2 },
    220                 new Object[] { Long.valueOf(2), "Anna Kinney", "content://uri3",
    221                         "425-555-1236", Phone.TYPE_MAIN, "", "3", Long.valueOf(3), 3 },
    222                 new Object[] { Long.valueOf(3), "Mike Jones", "content://uri3",
    223                         "425-555-1236", Phone.TYPE_MAIN, "", "5", Long.valueOf(4), 4 },
    224         };
    225         return new FakeCursor(ContactUtil.PhoneQuery.PROJECTION, sContactCursorColumns,
    226                 cursorData);
    227     }
    228 
    229     /**
    230      * Returns a cursor for the frequent contacts list consumable by ContactPickerFragment.
    231      * Note: make it so that this cursor is the generated result of getStrequentContactsCursor()
    232      * and getAllContactListCursor(), i.e., expand the entries in getStrequentContactsCursor()
    233      * with the details from getAllContactListCursor()
    234      */
    235     public static FakeCursor getFrequentContactListCursor() {
    236         final Object[][] cursorData = new Object[][] {
    237                 new Object[] { Long.valueOf(2), "Anna Kinney", "content://uri3",
    238                         "425-555-1236", Phone.TYPE_MAIN, "", "3", Long.valueOf(3), 0 },
    239                 new Object[] { Long.valueOf(1), "Sun Woo Kong", "content://uri2",
    240                         "425-555-1235", Phone.TYPE_MOBILE, "", "1", Long.valueOf(1), 1},
    241                 new Object[] { Long.valueOf(1), "Sun Woo Kong", "content://uri2",
    242                         "425-555-1238", Phone.TYPE_HOME, "", "1", Long.valueOf(2), 2 },
    243                 new Object[] { Long.valueOf(0), "John Smith", "content://uri1",
    244                         "425-555-1234", Phone.TYPE_HOME, "", "0", Long.valueOf(0), 3 },
    245         };
    246         return new FakeCursor(ContactUtil.PhoneQuery.PROJECTION, sContactCursorColumns,
    247                 cursorData);
    248     }
    249 
    250     /**
    251      * Returns a strequent (starred + frequent) cursor (like the one produced by android contact
    252      * provider's CONTENT_STREQUENT_URI query) that's consumable by FrequentContactsCursorBuilder.
    253      */
    254     public static FakeCursor getStrequentContactsCursor() {
    255         final Object[][] cursorData = new Object[][] {
    256                 new Object[] { Long.valueOf(0), "Anna Kinney", "content://uri1", "3" },
    257                 new Object[] { Long.valueOf(1), "Sun Woo Kong", "content://uri2", "1" },
    258                 new Object[] { Long.valueOf(2), "John Smith", "content://uri3", "0" },
    259                 // Email-only entry that shouldn't be included in the result.
    260                 new Object[] { Long.valueOf(3), "Email Contact", "content://uri4", "100" },
    261         };
    262         return new FakeCursor(ContactUtil.FrequentContactQuery.PROJECTION,
    263                 sFrequentContactCursorColumns, cursorData);
    264     }
    265 
    266     public static final int SMS_MMS_THREAD_ID_CURSOR_VALUE = 123456789;
    267 
    268     public static FakeCursor getSmsMmsThreadIdCursor() {
    269         final String[] ID_PROJECTION = { BaseColumns._ID };
    270         final Object[][] cursorData = new Object[][] {
    271                 new Object[] { Long.valueOf(SMS_MMS_THREAD_ID_CURSOR_VALUE) },
    272         };
    273         return new FakeCursor(ID_PROJECTION, ID_PROJECTION, cursorData);
    274     }
    275 
    276     public static FakeCursor getGalleryGridCursor() {
    277         final Object[][] cursorData = new Object[][] {
    278                 new Object[] { Long.valueOf(0), "/sdcard/image1", 100, 100, "image/jpeg" },
    279                 new Object[] { Long.valueOf(1), "/sdcard/image2", 200, 200, "image/png" },
    280                 new Object[] { Long.valueOf(2), "/sdcard/image3", 300, 300, "image/jpeg" },
    281         };
    282         return new FakeCursor(GalleryGridItemData.IMAGE_PROJECTION, sGalleryCursorColumns,
    283                 cursorData);
    284     }
    285 
    286     public static final int NUM_TEST_CONVERSATIONS = 10;
    287 
    288     /**
    289      * Create test data in our db.
    290      *
    291      * Ideally this will create more realistic data with more variety.
    292      */
    293     public static void createTestData(final SQLiteDatabase db) {
    294         BugleDatabaseOperations.clearParticipantIdCache();
    295 
    296         // Timestamp for 1 day ago
    297         final long yesterday = System.currentTimeMillis() - (24 * 60 * 60 * 1000);
    298 
    299         final ContentValues conversationValues = new ContentValues();
    300         for (int i = 1; i <= NUM_TEST_CONVERSATIONS; i++) {
    301             conversationValues.put(ConversationColumns.NAME, "Conversation " + i);
    302             final long conversationId = db.insert(DatabaseHelper.CONVERSATIONS_TABLE, null,
    303                     conversationValues);
    304 
    305             final ContentValues messageValues = new ContentValues();
    306             for (int m = 1; m <= 25; m++) {
    307                 // Move forward ten minutes per conversation, 1 minute per message.
    308                 final long messageTime = yesterday + (i * 10 * 60 * 1000) + (m * 60 * 1000);
    309                 messageValues.put(MessageColumns.RECEIVED_TIMESTAMP, messageTime);
    310                 messageValues.put(MessageColumns.CONVERSATION_ID, conversationId);
    311                 messageValues.put(MessageColumns.SENDER_PARTICIPANT_ID,
    312                         Math.abs(("" + messageTime).hashCode()) % 2);
    313                 final long messageId = db.insert(DatabaseHelper.MESSAGES_TABLE, null, messageValues);
    314 
    315                 // Create a text part for this message
    316                 final ContentValues partValues = new ContentValues();
    317                 partValues.put(PartColumns.MESSAGE_ID, messageId);
    318                 partValues.put(PartColumns.CONVERSATION_ID, conversationId);
    319                 partValues.put(PartColumns.TEXT, "Conversation: " + conversationId +
    320                         " Message: " + m);
    321                 db.insert(DatabaseHelper.PARTS_TABLE, null, partValues);
    322 
    323                 // Update the snippet for this conversation to the latest message inserted
    324                 conversationValues.clear();
    325                 conversationValues.put(ConversationColumns.LATEST_MESSAGE_ID, messageId);
    326                 final int updatedCount = db.update(DatabaseHelper.CONVERSATIONS_TABLE,
    327                         conversationValues,
    328                         "_id=?", new String[]{String.valueOf(conversationId)});
    329                 Assert.isTrue(updatedCount == 1);
    330             }
    331         }
    332     }
    333 
    334     public static List<MessagePartData> getTestDraftAttachments() {
    335         final MessagePartData[] retParts = new MessagePartData[] {
    336                 new MessagePartData(ContentType.IMAGE_JPEG, Uri.parse("content://image"),
    337                         100, 100),
    338                 new MessagePartData(ContentType.VIDEO_3GPP, Uri.parse("content://video"),
    339                         100, 100),
    340                 new MessagePartData(ContentType.TEXT_VCARD, Uri.parse("content://vcard"),
    341                         0, 0),
    342                 new MessagePartData(ContentType.AUDIO_3GPP, Uri.parse("content://audio"),
    343                         0, 0)
    344         };
    345         return Arrays.asList(retParts);
    346     }
    347 }
    348