1 /* 2 * Copyright (C) 2016 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.dialer.database; 18 19 import android.content.ContentProvider; 20 import android.content.ContentUris; 21 import android.content.ContentValues; 22 import android.content.Context; 23 import android.content.UriMatcher; 24 import android.database.Cursor; 25 import android.database.sqlite.SQLiteDatabase; 26 import android.database.sqlite.SQLiteQueryBuilder; 27 import android.net.Uri; 28 import android.os.ParcelFileDescriptor; 29 import android.support.annotation.Nullable; 30 import android.text.TextUtils; 31 import android.webkit.MimeTypeMap; 32 33 import com.android.dialerbind.DatabaseHelperManager; 34 import com.google.common.annotations.VisibleForTesting; 35 36 import java.io.File; 37 import java.io.FileNotFoundException; 38 39 /** 40 * An implementation of the Voicemail Archive content provider. This class performs 41 * all database level operations on the voicemail_archive_table. 42 */ 43 public class VoicemailArchiveProvider extends ContentProvider { 44 private static final String TAG = "VMArchiveProvider"; 45 private static final int VOICEMAIL_ARCHIVE_TABLE = 1; 46 private static final int VOICEMAIL_ARCHIVE_TABLE_ID = 2; 47 private static final String VOICEMAIL_FOLDER = "voicemails"; 48 49 private DialerDatabaseHelper mDialerDatabaseHelper; 50 private final UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 51 52 @Override 53 public boolean onCreate() { 54 mDialerDatabaseHelper = getDatabaseHelper(getContext()); 55 if (mDialerDatabaseHelper == null) { 56 return false; 57 } 58 mUriMatcher.addURI(VoicemailArchiveContract.AUTHORITY, 59 VoicemailArchiveContract.VoicemailArchive.VOICEMAIL_ARCHIVE_TABLE, 60 VOICEMAIL_ARCHIVE_TABLE); 61 mUriMatcher.addURI(VoicemailArchiveContract.AUTHORITY, 62 VoicemailArchiveContract.VoicemailArchive.VOICEMAIL_ARCHIVE_TABLE + "/#", 63 VOICEMAIL_ARCHIVE_TABLE_ID); 64 return true; 65 } 66 67 @VisibleForTesting 68 protected DialerDatabaseHelper getDatabaseHelper(Context context) { 69 return DatabaseHelperManager.getDatabaseHelper(context); 70 } 71 72 /** 73 * Used by the test class because it extends {@link android.test.ProviderTestCase2} in which the 74 * {@link android.test.IsolatedContext} returns /dev/null when getFilesDir() is called. 75 * 76 * @see android.test.IsolatedContext#getFilesDir 77 */ 78 @VisibleForTesting 79 protected File getFilesDir() { 80 return getContext().getFilesDir(); 81 } 82 83 @Nullable 84 @Override 85 public Cursor query(Uri uri, 86 @Nullable String[] projection, 87 @Nullable String selection, 88 @Nullable String[] selectionArgs, 89 @Nullable String sortOrder) { 90 SQLiteDatabase db = mDialerDatabaseHelper.getReadableDatabase(); 91 SQLiteQueryBuilder queryBuilder = getQueryBuilder(uri); 92 Cursor cursor = queryBuilder 93 .query(db, projection, selection, selectionArgs, null, null, sortOrder); 94 if (cursor != null) { 95 cursor.setNotificationUri(getContext().getContentResolver(), 96 VoicemailArchiveContract.VoicemailArchive.CONTENT_URI); 97 } 98 return cursor; 99 } 100 101 @Override 102 public String getType(Uri uri) { 103 return VoicemailArchiveContract.VoicemailArchive.CONTENT_ITEM_TYPE; 104 } 105 106 @Nullable 107 @Override 108 public Uri insert(Uri uri, ContentValues values) { 109 SQLiteDatabase db = mDialerDatabaseHelper.getWritableDatabase(); 110 long id = db.insert(DialerDatabaseHelper.Tables.VOICEMAIL_ARCHIVE_TABLE, 111 null, values); 112 if (id < 0) { 113 return null; 114 } 115 notifyChange(uri); 116 // Create the directory for archived voicemails if it doesn't already exist 117 File directory = new File(getFilesDir(), VOICEMAIL_FOLDER); 118 directory.mkdirs(); 119 Uri newUri = ContentUris.withAppendedId(uri, id); 120 121 // Create new file only if path is not provided to one 122 if (!values.containsKey(VoicemailArchiveContract.VoicemailArchive._DATA)) { 123 String fileExtension = MimeTypeMap.getSingleton().getExtensionFromMimeType( 124 values.getAsString(VoicemailArchiveContract.VoicemailArchive.MIME_TYPE)); 125 File voicemailFile = new File(directory, 126 TextUtils.isEmpty(fileExtension) ? Long.toString(id) : 127 id + "." + fileExtension); 128 values.put(VoicemailArchiveContract.VoicemailArchive._DATA, voicemailFile.getPath()); 129 } 130 update(newUri, values, null, null); 131 return newUri; 132 } 133 134 135 @Override 136 public int delete(Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { 137 SQLiteDatabase db = mDialerDatabaseHelper.getWritableDatabase(); 138 SQLiteQueryBuilder queryBuilder = getQueryBuilder(uri); 139 Cursor cursor = queryBuilder.query(db, null, selection, selectionArgs, null, null, null); 140 141 // Delete all the voicemail files related to the selected rows 142 while (cursor.moveToNext()) { 143 deleteFile(cursor.getString(cursor.getColumnIndex( 144 VoicemailArchiveContract.VoicemailArchive._DATA))); 145 } 146 147 int rows = db.delete(DialerDatabaseHelper.Tables.VOICEMAIL_ARCHIVE_TABLE, 148 getSelectionWithId(selection, uri), 149 selectionArgs); 150 if (rows > 0) { 151 notifyChange(uri); 152 } 153 return rows; 154 } 155 156 @Override 157 public int update(Uri uri, 158 ContentValues values, 159 @Nullable String selection, 160 @Nullable String[] selectionArgs) { 161 SQLiteDatabase db = mDialerDatabaseHelper.getWritableDatabase(); 162 selection = getSelectionWithId(selection, uri); 163 int rows = db.update(DialerDatabaseHelper.Tables.VOICEMAIL_ARCHIVE_TABLE, 164 values, 165 selection, 166 selectionArgs); 167 if (rows > 0) { 168 notifyChange(uri); 169 } 170 return rows; 171 } 172 173 @Override 174 public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 175 if (mUriMatcher.match(uri) != VOICEMAIL_ARCHIVE_TABLE_ID) { 176 throw new IllegalArgumentException("URI Invalid."); 177 } 178 return openFileHelper(uri, mode); 179 } 180 181 private void deleteFile(@Nullable String path) { 182 if (TextUtils.isEmpty(path)) { 183 return; 184 } 185 File file = new File(path); 186 if (file.exists()) { 187 file.delete(); 188 } 189 } 190 191 private SQLiteQueryBuilder getQueryBuilder(Uri uri) { 192 SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); 193 queryBuilder.setTables(DialerDatabaseHelper.Tables.VOICEMAIL_ARCHIVE_TABLE); 194 String selectionWithId = getSelectionWithId(null, uri); 195 if (!TextUtils.isEmpty(selectionWithId)) { 196 queryBuilder.appendWhere(selectionWithId); 197 } 198 return queryBuilder; 199 } 200 201 private String getSelectionWithId(String selection, Uri uri) { 202 int match = mUriMatcher.match(uri); 203 switch (match) { 204 case VOICEMAIL_ARCHIVE_TABLE: 205 return selection; 206 case VOICEMAIL_ARCHIVE_TABLE_ID: 207 String idStr = VoicemailArchiveContract.VoicemailArchive._ID + "=" + 208 ContentUris.parseId(uri); 209 return TextUtils.isEmpty(selection) ? idStr : selection + " AND " + idStr; 210 default: 211 throw new IllegalArgumentException("Unknown uri: " + uri); 212 } 213 } 214 215 private void notifyChange(Uri uri) { 216 getContext().getContentResolver().notifyChange(uri, null); 217 } 218 } 219