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 17 package com.google.android.sample.rcsclient.util; 18 19 import android.content.ContentProvider; 20 import android.content.ContentValues; 21 import android.content.Context; 22 import android.content.UriMatcher; 23 import android.database.Cursor; 24 import android.database.SQLException; 25 import android.database.sqlite.SQLiteDatabase; 26 import android.database.sqlite.SQLiteException; 27 import android.database.sqlite.SQLiteOpenHelper; 28 import android.database.sqlite.SQLiteQueryBuilder; 29 import android.net.Uri; 30 import android.provider.BaseColumns; 31 import android.text.TextUtils; 32 import android.util.Log; 33 34 /** A database to store chat message. */ 35 public class ChatProvider extends ContentProvider { 36 public static final Uri CHAT_URI = Uri.parse("content://rcsprovider/chat"); 37 public static final Uri SUMMARY_URI = Uri.parse("content://rcsprovider/summary"); 38 public static final String AUTHORITY = "rcsprovider"; 39 private static final String TAG = "TestRcsApp.ChatProvider"; 40 private static final int DATABASE_VERSION = 2; 41 private static final String CHAT_TABLE_NAME = "chat"; 42 private static final String SUMMARY_TABLE_NAME = "summary"; 43 44 private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); 45 private static final int URI_CHAT = 1; 46 private static final int URI_SUMMARY = 2; 47 private static final String QUERY_CHAT_TABLE = " SELECT * FROM " + CHAT_TABLE_NAME; 48 49 static { URI_MATCHER.addURI(AUTHORITY, R, URI_CHAT)50 URI_MATCHER.addURI(AUTHORITY, "chat", URI_CHAT); URI_MATCHER.addURI(AUTHORITY, R, URI_SUMMARY)51 URI_MATCHER.addURI(AUTHORITY, "summary", URI_SUMMARY); 52 } 53 54 private RcsDatabaseHelper mRcsHelper; 55 56 @Override onCreate()57 public boolean onCreate() { 58 mRcsHelper = new RcsDatabaseHelper(getContext()); 59 return true; 60 } 61 62 @Override query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)63 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 64 String sortOrder) { 65 SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 66 SQLiteDatabase db = mRcsHelper.getReadableDatabase(); 67 int match = URI_MATCHER.match(uri); 68 69 Log.d(TAG, "Query URI: " + match); 70 switch (match) { 71 case URI_CHAT: 72 qb.setTables(CHAT_TABLE_NAME); 73 return qb.query(db, projection, selection, selectionArgs, null, null, sortOrder); 74 case URI_SUMMARY: 75 qb.setTables(SUMMARY_TABLE_NAME); 76 return qb.query(db, projection, selection, selectionArgs, null, null, sortOrder); 77 default: 78 Log.e(TAG, "no such uri"); 79 return null; 80 } 81 } 82 83 @Override insert(Uri uri, ContentValues contentValues)84 public Uri insert(Uri uri, ContentValues contentValues) { 85 SQLiteDatabase db = mRcsHelper.getWritableDatabase(); 86 int match = URI_MATCHER.match(uri); 87 long id; 88 switch (match) { 89 case URI_CHAT: 90 id = db.insert(CHAT_TABLE_NAME, "", contentValues); 91 break; 92 case URI_SUMMARY: 93 id = db.insert(SUMMARY_TABLE_NAME, "", contentValues); 94 break; 95 default: 96 Log.e(TAG, "no such uri"); 97 throw new SQLException("no such uri"); 98 } 99 if (id > 0) { 100 Uri msgUri = Uri.withAppendedPath(uri, String.valueOf(id)); 101 getContext().getContentResolver().notifyChange(uri, null); 102 Log.i(TAG, "msgUri:" + msgUri); 103 return msgUri; 104 } else { 105 throw new SQLException("fail to add chat message"); 106 } 107 } 108 109 @Override delete(Uri uri, String s, String[] strings)110 public int delete(Uri uri, String s, String[] strings) { 111 return 0; 112 } 113 114 @Override update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs)115 public int update(Uri uri, ContentValues contentValues, String selection, 116 String[] selectionArgs) { 117 SQLiteDatabase db = mRcsHelper.getWritableDatabase(); 118 int match = URI_MATCHER.match(uri); 119 int result = 0; 120 String tableName = ""; 121 switch (match) { 122 case URI_CHAT: 123 tableName = CHAT_TABLE_NAME; 124 break; 125 case URI_SUMMARY: 126 tableName = SUMMARY_TABLE_NAME; 127 break; 128 } 129 if (!TextUtils.isEmpty(tableName)) { 130 result = db.updateWithOnConflict(tableName, contentValues, 131 selection, selectionArgs, SQLiteDatabase.CONFLICT_REPLACE); 132 getContext().getContentResolver().notifyChange(uri, null); 133 Log.d(TAG, "Update uri: " + match + " result: " + result); 134 } else { 135 Log.d(TAG, "Update. Not support URI."); 136 } 137 return result; 138 } 139 140 @Override getType(Uri uri)141 public String getType(Uri uri) { 142 return null; 143 } 144 145 /** Define columns for the chat table. */ 146 public static class RcsColumns implements BaseColumns { 147 public static final String SRC_PHONE_NUMBER = "source_phone_number"; 148 public static final String DEST_PHONE_NUMBER = "destination_phone_number"; 149 public static final String CHAT_MESSAGE = "chat_message"; 150 public static final String MSG_TIMESTAMP = "msg_timestamp"; 151 public static final String IS_READ = "is_read"; 152 public static final String RESULT = "result"; 153 } 154 155 /** Define columns for the summary table. */ 156 public static class SummaryColumns implements BaseColumns { 157 public static final String REMOTE_PHONE_NUMBER = "remote_phone_number"; 158 public static final String LATEST_MESSAGE = "latest_message"; 159 public static final String MSG_TIMESTAMP = "msg_timestamp"; 160 public static final String IS_READ = "is_read"; 161 } 162 163 /** Database helper */ 164 public static final class RcsDatabaseHelper extends SQLiteOpenHelper { 165 public static final String SQL_CREATE_RCS_TABLE = "CREATE TABLE " 166 + CHAT_TABLE_NAME 167 + " (" 168 + RcsColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " 169 + RcsColumns.SRC_PHONE_NUMBER + " Text DEFAULT NULL, " 170 + RcsColumns.DEST_PHONE_NUMBER + " Text DEFAULT NULL, " 171 + RcsColumns.CHAT_MESSAGE + " Text DEFAULT NULL, " 172 + RcsColumns.MSG_TIMESTAMP + " LONG DEFAULT NULL, " 173 + RcsColumns.IS_READ + " BOOLEAN DEFAULT false, " 174 + RcsColumns.RESULT + " BOOLEAN DEFAULT true);"; 175 176 public static final String SQL_CREATE_SUMMARY_TABLE = "CREATE TABLE " 177 + SUMMARY_TABLE_NAME 178 + " (" 179 + SummaryColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " 180 + SummaryColumns.REMOTE_PHONE_NUMBER + " Text DEFAULT NULL, " 181 + SummaryColumns.LATEST_MESSAGE + " Text DEFAULT NULL, " 182 + SummaryColumns.MSG_TIMESTAMP + " LONG DEFAULT NULL, " 183 + SummaryColumns.IS_READ + " BOOLEAN DEFAULT false);"; 184 private static final String DB_NAME = "RcsDatabase"; 185 RcsDatabaseHelper(Context context)186 public RcsDatabaseHelper(Context context) { 187 super(context, DB_NAME, null, DATABASE_VERSION); 188 } 189 190 @Override onCreate(SQLiteDatabase db)191 public void onCreate(SQLiteDatabase db) { 192 db.execSQL(SQL_CREATE_RCS_TABLE); 193 db.execSQL(SQL_CREATE_SUMMARY_TABLE); 194 } 195 196 @Override onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)197 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 198 Log.d(TAG, "DB upgrade from " + oldVersion + " to " + newVersion); 199 db.beginTransaction(); 200 try { 201 switch (oldVersion) { 202 case 1: 203 upgradeDatabaseToVersion2(db); 204 break; 205 default: // fall out 206 } 207 db.setTransactionSuccessful(); 208 } catch (Exception ex) { 209 Log.e(TAG, ex.getMessage(), ex); 210 } finally { 211 db.endTransaction(); 212 } 213 } 214 upgradeDatabaseToVersion2(SQLiteDatabase db)215 private static void upgradeDatabaseToVersion2(SQLiteDatabase db) { 216 try { 217 Log.d(TAG, "upgradeDatabaseToVersion2"); 218 String alterTable = "ALTER TABLE " + CHAT_TABLE_NAME + " ADD COLUMN "; 219 db.execSQL(alterTable + RcsColumns.RESULT + " BOOLEAN DEFAULT true"); 220 } catch (SQLiteException e) { 221 Log.w(TAG, "[upgradeDatabaseToVersion10] Exception adding column: " + e); 222 } 223 } 224 } 225 } 226