1 /* 2 * Copyright (C) 2019 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.Rcs1To1ThreadColumns.RCS_1_TO_1_THREAD_URI; 19 import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.GROUP_ICON_COLUMN; 20 import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.GROUP_NAME_COLUMN; 21 import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.RCS_GROUP_THREAD_URI; 22 import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.RCS_PARTICIPANT_ID_COLUMN; 23 import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.RCS_PARTICIPANT_URI_PART; 24 import static android.provider.Telephony.RcsColumns.RcsThreadColumns.RCS_THREAD_ID_COLUMN; 25 import static android.provider.Telephony.RcsColumns.RcsThreadColumns.RCS_THREAD_URI; 26 import static android.provider.Telephony.RcsColumns.RcsUnifiedThreadColumns.THREAD_TYPE_1_TO_1; 27 import static android.provider.Telephony.RcsColumns.RcsUnifiedThreadColumns.THREAD_TYPE_COLUMN; 28 import static android.provider.Telephony.RcsColumns.RcsUnifiedThreadColumns.THREAD_TYPE_GROUP; 29 import static android.telephony.ims.RcsQueryContinuationToken.QUERY_CONTINUATION_TOKEN; 30 31 import android.content.ContentResolver; 32 import android.content.ContentValues; 33 import android.database.Cursor; 34 import android.net.Uri; 35 import android.os.Bundle; 36 import android.os.RemoteException; 37 import android.telephony.ims.RcsQueryContinuationToken; 38 import android.telephony.ims.RcsThreadQueryResultParcelable; 39 40 import com.android.ims.RcsTypeIdPair; 41 42 import java.util.ArrayList; 43 import java.util.List; 44 45 // TODO optimize considering returned threads do not contain query information 46 47 /** 48 * A helper class focused on querying RCS threads from the 49 * {@link com.android.providers.telephony.RcsProvider} 50 */ 51 class RcsThreadQueryHelper { 52 private static final int THREAD_ID_INDEX_IN_INSERTION_URI = 1; 53 54 private final ContentResolver mContentResolver; 55 private final RcsParticipantQueryHelper mParticipantQueryHelper; 56 RcsThreadQueryHelper(ContentResolver contentResolver, RcsParticipantQueryHelper participantQueryHelper)57 RcsThreadQueryHelper(ContentResolver contentResolver, 58 RcsParticipantQueryHelper participantQueryHelper) { 59 mContentResolver = contentResolver; 60 mParticipantQueryHelper = participantQueryHelper; 61 } 62 performThreadQuery(Bundle bundle)63 RcsThreadQueryResultParcelable performThreadQuery(Bundle bundle) throws RemoteException { 64 RcsQueryContinuationToken continuationToken = null; 65 List<RcsTypeIdPair> rcsThreadIdList = new ArrayList<>(); 66 try (Cursor cursor = mContentResolver.query(RCS_THREAD_URI, null, bundle, null)) { 67 if (cursor == null) { 68 throw new RemoteException("Could not perform thread query, bundle: " + bundle); 69 } 70 71 while (cursor.moveToNext()) { 72 boolean isGroup = cursor.getInt(cursor.getColumnIndex(THREAD_TYPE_COLUMN)) 73 == THREAD_TYPE_GROUP; 74 75 if (isGroup) { 76 int threadId = cursor.getInt(cursor.getColumnIndex(RCS_THREAD_ID_COLUMN)); 77 rcsThreadIdList.add(new RcsTypeIdPair(THREAD_TYPE_GROUP, threadId)); 78 } else { 79 int threadId = cursor.getInt(cursor.getColumnIndex(RCS_THREAD_ID_COLUMN)); 80 rcsThreadIdList.add(new RcsTypeIdPair(THREAD_TYPE_1_TO_1, threadId)); 81 } 82 } 83 84 // If there is a continuation token, add it to the query result. 85 Bundle cursorExtras = cursor.getExtras(); 86 if (cursorExtras != null) { 87 continuationToken = cursorExtras.getParcelable(QUERY_CONTINUATION_TOKEN); 88 } 89 } 90 return new RcsThreadQueryResultParcelable(continuationToken, rcsThreadIdList); 91 } 92 create1To1Thread(int participantId)93 int create1To1Thread(int participantId) throws RemoteException { 94 ContentValues contentValues = new ContentValues(1); 95 contentValues.put(RCS_PARTICIPANT_ID_COLUMN, participantId); 96 Uri insertionUri = mContentResolver.insert(RCS_1_TO_1_THREAD_URI, contentValues); 97 98 if (insertionUri == null) { 99 throw new RemoteException("Rcs1To1Thread creation failed"); 100 } 101 102 String threadIdAsString = insertionUri.getLastPathSegment(); 103 int threadId = Integer.parseInt(threadIdAsString); 104 105 if (threadId <= 0) { 106 throw new RemoteException("Rcs1To1Thread creation failed"); 107 } 108 109 return threadId; 110 } 111 createGroupThread(String groupName, Uri groupIcon)112 int createGroupThread(String groupName, Uri groupIcon) throws RemoteException { 113 // Create the group 114 ContentValues contentValues = new ContentValues(1); 115 contentValues.put(GROUP_NAME_COLUMN, groupName); 116 if (groupIcon != null) { 117 contentValues.put(GROUP_ICON_COLUMN, groupIcon.toString()); 118 } 119 120 Uri groupUri = mContentResolver.insert(RCS_GROUP_THREAD_URI, 121 contentValues); 122 if (groupUri == null) { 123 throw new RemoteException("RcsGroupThread creation failed"); 124 } 125 126 // get the thread id from group URI 127 String threadIdAsString = groupUri.getPathSegments().get(THREAD_ID_INDEX_IN_INSERTION_URI); 128 int threadId = Integer.parseInt(threadIdAsString); 129 130 return threadId; 131 } 132 get1To1ThreadUri(int rcsThreadId)133 static Uri get1To1ThreadUri(int rcsThreadId) { 134 return Uri.withAppendedPath(RCS_1_TO_1_THREAD_URI, Integer.toString(rcsThreadId)); 135 } 136 getGroupThreadUri(int rcsThreadId)137 static Uri getGroupThreadUri(int rcsThreadId) { 138 return Uri.withAppendedPath(RCS_GROUP_THREAD_URI, Integer.toString(rcsThreadId)); 139 } 140 getAllParticipantsInThreadUri(int rcsThreadId)141 static Uri getAllParticipantsInThreadUri(int rcsThreadId) { 142 return RCS_GROUP_THREAD_URI.buildUpon().appendPath(Integer.toString(rcsThreadId)) 143 .appendPath(RCS_PARTICIPANT_URI_PART).build(); 144 } 145 getParticipantInThreadUri(int rcsThreadId, int participantId)146 static Uri getParticipantInThreadUri(int rcsThreadId, int participantId) { 147 return RCS_GROUP_THREAD_URI.buildUpon().appendPath(Integer.toString(rcsThreadId)) 148 .appendPath(RCS_PARTICIPANT_URI_PART).appendPath(Integer.toString( 149 participantId)).build(); 150 } 151 } 152