1 /* 2 * Copyright (C) 2020 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 package com.android.car.messenger.impl.datamodels.util; 17 18 import static android.provider.BaseColumns._ID; 19 import static android.provider.Telephony.BaseMmsColumns.CONTENT_TYPE; 20 import static android.provider.Telephony.BaseMmsColumns.MESSAGE_BOX; 21 import static android.provider.Telephony.MmsSms.CONTENT_CONVERSATIONS_URI; 22 import static android.provider.Telephony.TextBasedSmsColumns.ADDRESS; 23 import static android.provider.Telephony.TextBasedSmsColumns.BODY; 24 import static android.provider.Telephony.TextBasedSmsColumns.SUBSCRIPTION_ID; 25 import static android.provider.Telephony.TextBasedSmsColumns.THREAD_ID; 26 import static android.provider.Telephony.TextBasedSmsColumns.TYPE; 27 import static android.provider.Telephony.ThreadsColumns.DATE; 28 import static android.provider.Telephony.ThreadsColumns.READ; 29 import static android.provider.Telephony.ThreadsColumns.RECIPIENT_IDS; 30 31 import android.content.ContentResolver; 32 import android.content.Context; 33 import android.database.Cursor; 34 import android.net.Uri; 35 import android.provider.Telephony; 36 37 import androidx.annotation.NonNull; 38 import androidx.annotation.Nullable; 39 40 import com.android.car.messenger.core.interfaces.AppFactory; 41 42 /** Cursor Utils to get quick cursor or uri telephony information */ 43 public class CursorUtils { CursorUtils()44 private CursorUtils() {} 45 // This URI provides all the metadata for a thread. 46 // Appending simple=true is important to get the recipient_ids for the conversation. 47 @NonNull 48 public static final Uri THREAD_INFO_URI = 49 CONTENT_CONVERSATIONS_URI.buildUpon().appendQueryParameter("simple", "true").build(); 50 51 @NonNull protected static final String[] THREAD_INFO_PROJECTION = {_ID, RECIPIENT_IDS, READ}; 52 53 @NonNull 54 protected static final String[] CONTENT_CONVERSATION_PROJECTION = { 55 _ID, TYPE, DATE, READ, CONTENT_TYPE, BODY, ADDRESS, THREAD_ID, SUBSCRIPTION_ID, MESSAGE_BOX 56 }; 57 58 /** Provides the default sort order for items in database. Default is DESC order by Date. */ 59 @NonNull 60 public static final String DEFAULT_SORT_ORDER = Telephony.TextBasedSmsColumns.DATE + " DESC"; 61 62 /** 63 * Get simplified thread cursor with metadata information on the thread, such as recipient ids 64 */ 65 @Nullable getThreadCursor(@onNull String threadId)66 public static Cursor getThreadCursor(@NonNull String threadId) { 67 Context context = AppFactory.get().getContext(); 68 ContentResolver contentResolver = context.getContentResolver(); 69 return contentResolver.query( 70 THREAD_INFO_URI, 71 THREAD_INFO_PROJECTION, 72 _ID + "=" + threadId, 73 /* selectionArgs= */ null, 74 DEFAULT_SORT_ORDER); 75 } 76 77 /** 78 * Get the message cursor in descending order for 79 * 80 * @param conversationId The conversation or thread id for the conversation 81 * @param limit The maximum number of message rows to fetch 82 * @param offset The starting point in timestamp in millisecond to fetch for data 83 */ 84 @Nullable getMessagesCursor(@onNull String conversationId, int limit, long offset)85 public static Cursor getMessagesCursor(@NonNull String conversationId, int limit, long offset) { 86 Context context = AppFactory.get().getContext(); 87 ContentResolver contentResolver = context.getContentResolver(); 88 return contentResolver.query( 89 getConversationUri(conversationId), 90 CONTENT_CONVERSATION_PROJECTION, 91 DATE + " > " + offset, 92 /* selectionArgs= */ null, 93 DEFAULT_SORT_ORDER + " LIMIT " + limit); 94 } 95 96 /** Gets the Conversation Uri for the Conversation with specified conversationId */ 97 @NonNull getConversationUri(@onNull String conversationId)98 public static Uri getConversationUri(@NonNull String conversationId) { 99 return CONTENT_CONVERSATIONS_URI.buildUpon().appendPath(conversationId).build(); 100 } 101 102 /** Returns a cursor query with the uri provided, with no filtering or projection */ 103 @Nullable simpleQuery(@onNull Context context, @NonNull Uri uri)104 public static Cursor simpleQuery(@NonNull Context context, @NonNull Uri uri) { 105 return context.getContentResolver().query(uri, null, null, null, null); 106 } 107 108 /** Returns a cursor query given a uri and projection */ 109 @Nullable simpleQueryWithProjection( @onNull Context context, @NonNull Uri uri, @Nullable String[] projection)110 public static Cursor simpleQueryWithProjection( 111 @NonNull Context context, @NonNull Uri uri, @Nullable String[] projection) { 112 return context.getContentResolver().query(uri, projection, null, null, null); 113 } 114 115 /** Returns a cursor query given a uri and selection */ 116 @Nullable simpleQueryWithSelection( @onNull Context context, @NonNull Uri uri, @Nullable String selection)117 public static Cursor simpleQueryWithSelection( 118 @NonNull Context context, @NonNull Uri uri, @Nullable String selection) { 119 return context.getContentResolver().query(uri, null, selection, null, null); 120 } 121 } 122