1 /* 2 * Copyright (C) 2017 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.internal.telephony.ims; 17 18 import static android.provider.Telephony.RcsColumns.CONTENT_AND_AUTHORITY; 19 import static android.provider.Telephony.RcsColumns.Rcs1To1ThreadColumns.RCS_1_TO_1_THREAD_URI_PART; 20 import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.CONTENT_TYPE_COLUMN; 21 import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.CONTENT_URI_COLUMN; 22 import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.DURATION_MILLIS_COLUMN; 23 import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.FILE_SIZE_COLUMN; 24 import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.FILE_TRANSFER_URI; 25 import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.FILE_TRANSFER_URI_PART; 26 import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.HEIGHT_COLUMN; 27 import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.PREVIEW_TYPE_COLUMN; 28 import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.PREVIEW_URI_COLUMN; 29 import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.SESSION_ID_COLUMN; 30 import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.SUCCESSFULLY_TRANSFERRED_BYTES; 31 import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.TRANSFER_STATUS_COLUMN; 32 import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.WIDTH_COLUMN; 33 import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.RCS_GROUP_THREAD_URI_PART; 34 import static android.provider.Telephony.RcsColumns.RcsIncomingMessageColumns.INCOMING_MESSAGE_URI; 35 import static android.provider.Telephony.RcsColumns.RcsIncomingMessageColumns.INCOMING_MESSAGE_URI_PART; 36 import static android.provider.Telephony.RcsColumns.RcsMessageColumns.GLOBAL_ID_COLUMN; 37 import static android.provider.Telephony.RcsColumns.RcsMessageColumns.MESSAGE_ID_COLUMN; 38 import static android.provider.Telephony.RcsColumns.RcsMessageColumns.ORIGINATION_TIMESTAMP_COLUMN; 39 import static android.provider.Telephony.RcsColumns.RcsMessageColumns.STATUS_COLUMN; 40 import static android.provider.Telephony.RcsColumns.RcsMessageColumns.SUB_ID_COLUMN; 41 import static android.provider.Telephony.RcsColumns.RcsMessageDeliveryColumns.DELIVERY_URI_PART; 42 import static android.provider.Telephony.RcsColumns.RcsOutgoingMessageColumns.OUTGOING_MESSAGE_URI; 43 import static android.provider.Telephony.RcsColumns.RcsOutgoingMessageColumns.OUTGOING_MESSAGE_URI_PART; 44 import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.RCS_PARTICIPANT_ID_COLUMN; 45 import static android.provider.Telephony.RcsColumns.RcsThreadColumns.RCS_THREAD_ID_COLUMN; 46 import static android.provider.Telephony.RcsColumns.RcsUnifiedMessageColumns.MESSAGE_TYPE_COLUMN; 47 import static android.provider.Telephony.RcsColumns.RcsUnifiedMessageColumns.MESSAGE_TYPE_INCOMING; 48 import static android.provider.Telephony.RcsColumns.RcsUnifiedMessageColumns.MESSAGE_TYPE_OUTGOING; 49 import static android.provider.Telephony.RcsColumns.RcsUnifiedMessageColumns.UNIFIED_MESSAGE_URI; 50 import static android.telephony.ims.RcsQueryContinuationToken.QUERY_CONTINUATION_TOKEN; 51 52 import android.content.ContentResolver; 53 import android.content.ContentValues; 54 import android.database.Cursor; 55 import android.net.Uri; 56 import android.os.Bundle; 57 import android.os.RemoteException; 58 import android.telephony.ims.RcsFileTransferCreationParams; 59 import android.telephony.ims.RcsMessageCreationParams; 60 import android.telephony.ims.RcsMessageQueryResultParcelable; 61 import android.telephony.ims.RcsQueryContinuationToken; 62 63 import com.android.ims.RcsTypeIdPair; 64 65 import java.util.ArrayList; 66 import java.util.List; 67 68 /** 69 * A helper class focused on querying RCS messages from the 70 * {@link com.android.providers.telephony.RcsProvider} 71 */ 72 class RcsMessageQueryHelper { 73 74 private final ContentResolver mContentResolver; 75 RcsMessageQueryHelper(ContentResolver contentResolver)76 RcsMessageQueryHelper(ContentResolver contentResolver) { 77 mContentResolver = contentResolver; 78 } 79 performMessageQuery(Bundle bundle)80 RcsMessageQueryResultParcelable performMessageQuery(Bundle bundle) throws RemoteException { 81 RcsQueryContinuationToken continuationToken = null; 82 List<RcsTypeIdPair> messageTypeIdPairs = new ArrayList<>(); 83 84 try (Cursor cursor = mContentResolver.query(UNIFIED_MESSAGE_URI, null, bundle, null)) { 85 if (cursor == null) { 86 throw new RemoteException("Could not perform message query, bundle: " + bundle); 87 } 88 89 while (cursor != null && cursor.moveToNext()) { 90 boolean isIncoming = cursor.getInt(cursor.getColumnIndex(MESSAGE_TYPE_COLUMN)) 91 == MESSAGE_TYPE_INCOMING; 92 int messageId = cursor.getInt(cursor.getColumnIndex(MESSAGE_ID_COLUMN)); 93 94 messageTypeIdPairs.add(new RcsTypeIdPair( 95 isIncoming ? MESSAGE_TYPE_INCOMING : MESSAGE_TYPE_OUTGOING, messageId)); 96 } 97 98 if (cursor != null) { 99 Bundle cursorExtras = cursor.getExtras(); 100 if (cursorExtras != null) { 101 continuationToken = 102 cursorExtras.getParcelable(QUERY_CONTINUATION_TOKEN); 103 } 104 } 105 } 106 107 return new RcsMessageQueryResultParcelable(continuationToken, messageTypeIdPairs); 108 } 109 createContentValuesForGenericMessage(ContentValues contentValues, int threadId, RcsMessageCreationParams rcsMessageCreationParams)110 void createContentValuesForGenericMessage(ContentValues contentValues, int threadId, 111 RcsMessageCreationParams rcsMessageCreationParams) { 112 contentValues.put(GLOBAL_ID_COLUMN, rcsMessageCreationParams.getRcsMessageGlobalId()); 113 contentValues.put(SUB_ID_COLUMN, rcsMessageCreationParams.getSubId()); 114 contentValues.put(STATUS_COLUMN, rcsMessageCreationParams.getMessageStatus()); 115 contentValues.put(ORIGINATION_TIMESTAMP_COLUMN, 116 rcsMessageCreationParams.getOriginationTimestamp()); 117 contentValues.put(RCS_THREAD_ID_COLUMN, threadId); 118 } 119 getMessageInsertionUri(boolean isIncoming)120 Uri getMessageInsertionUri(boolean isIncoming) { 121 return isIncoming ? INCOMING_MESSAGE_URI : OUTGOING_MESSAGE_URI; 122 } 123 getMessageDeletionUri(int messageId, boolean isIncoming, int rcsThreadId, boolean isGroup)124 Uri getMessageDeletionUri(int messageId, boolean isIncoming, int rcsThreadId, boolean isGroup) { 125 return CONTENT_AND_AUTHORITY.buildUpon().appendPath( 126 isGroup ? RCS_GROUP_THREAD_URI_PART : RCS_1_TO_1_THREAD_URI_PART).appendPath( 127 Integer.toString(rcsThreadId)).appendPath( 128 isIncoming ? INCOMING_MESSAGE_URI_PART : OUTGOING_MESSAGE_URI_PART).appendPath( 129 Integer.toString(messageId)).build(); 130 } 131 getMessageUpdateUri(int messageId, boolean isIncoming)132 Uri getMessageUpdateUri(int messageId, boolean isIncoming) { 133 return getMessageInsertionUri(isIncoming).buildUpon().appendPath( 134 Integer.toString(messageId)).build(); 135 } 136 getDeliveryParticipantsForMessage(int messageId)137 int[] getDeliveryParticipantsForMessage(int messageId) throws RemoteException { 138 int[] participantIds; 139 140 try (Cursor cursor = mContentResolver.query(getMessageDeliveryQueryUri(messageId), null, 141 null, null)) { 142 if (cursor == null) { 143 throw new RemoteException( 144 "Could not query deliveries for message, messageId: " + messageId); 145 } 146 147 participantIds = new int[cursor.getCount()]; 148 149 for (int i = 0; cursor.moveToNext(); i++) { 150 participantIds[i] = cursor.getInt(cursor.getColumnIndex(RCS_PARTICIPANT_ID_COLUMN)); 151 } 152 } 153 154 return participantIds; 155 } 156 getMessageDeliveryUri(int messageId, int participantId)157 Uri getMessageDeliveryUri(int messageId, int participantId) { 158 return Uri.withAppendedPath(getMessageDeliveryQueryUri(messageId), 159 Integer.toString(participantId)); 160 } 161 getLongValueFromDelivery(int messageId, int participantId, String columnName)162 long getLongValueFromDelivery(int messageId, int participantId, 163 String columnName) throws RemoteException { 164 try (Cursor cursor = mContentResolver.query(getMessageDeliveryUri(messageId, participantId), 165 null, null, null)) { 166 if (cursor == null || !cursor.moveToFirst()) { 167 throw new RemoteException( 168 "Could not read delivery for message: " + messageId + ", participant: " 169 + participantId); 170 } 171 172 return cursor.getLong(cursor.getColumnIndex(columnName)); 173 } 174 } 175 getMessageDeliveryQueryUri(int messageId)176 private Uri getMessageDeliveryQueryUri(int messageId) { 177 return getMessageInsertionUri(false).buildUpon().appendPath( 178 Integer.toString(messageId)).appendPath(DELIVERY_URI_PART).build(); 179 } 180 getContentValuesForFileTransfer( RcsFileTransferCreationParams fileTransferCreationParameters)181 ContentValues getContentValuesForFileTransfer( 182 RcsFileTransferCreationParams fileTransferCreationParameters) { 183 ContentValues contentValues = new ContentValues(); 184 contentValues.put(SESSION_ID_COLUMN, 185 fileTransferCreationParameters.getRcsFileTransferSessionId()); 186 contentValues.put(CONTENT_URI_COLUMN, 187 fileTransferCreationParameters.getContentUri().toString()); 188 contentValues.put(CONTENT_TYPE_COLUMN, fileTransferCreationParameters.getContentMimeType()); 189 contentValues.put(FILE_SIZE_COLUMN, fileTransferCreationParameters.getFileSize()); 190 contentValues.put(SUCCESSFULLY_TRANSFERRED_BYTES, 191 fileTransferCreationParameters.getTransferOffset()); 192 contentValues.put(TRANSFER_STATUS_COLUMN, 193 fileTransferCreationParameters.getFileTransferStatus()); 194 contentValues.put(WIDTH_COLUMN, fileTransferCreationParameters.getWidth()); 195 contentValues.put(HEIGHT_COLUMN, fileTransferCreationParameters.getHeight()); 196 contentValues.put(DURATION_MILLIS_COLUMN, 197 fileTransferCreationParameters.getMediaDuration()); 198 contentValues.put(PREVIEW_URI_COLUMN, 199 fileTransferCreationParameters.getPreviewUri().toString()); 200 contentValues.put(PREVIEW_TYPE_COLUMN, fileTransferCreationParameters.getPreviewMimeType()); 201 202 return contentValues; 203 } 204 getFileTransferInsertionUri(int messageId)205 Uri getFileTransferInsertionUri(int messageId) { 206 return UNIFIED_MESSAGE_URI.buildUpon().appendPath(Integer.toString(messageId)).appendPath( 207 FILE_TRANSFER_URI_PART).build(); 208 } 209 getFileTransferUpdateUri(int partId)210 Uri getFileTransferUpdateUri(int partId) { 211 return Uri.withAppendedPath(FILE_TRANSFER_URI, Integer.toString(partId)); 212 } 213 } 214