/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.dialer.database; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.os.ParcelFileDescriptor; import android.support.annotation.Nullable; import android.text.TextUtils; import android.webkit.MimeTypeMap; import com.android.dialerbind.DatabaseHelperManager; import com.google.common.annotations.VisibleForTesting; import java.io.File; import java.io.FileNotFoundException; /** * An implementation of the Voicemail Archive content provider. This class performs * all database level operations on the voicemail_archive_table. */ public class VoicemailArchiveProvider extends ContentProvider { private static final String TAG = "VMArchiveProvider"; private static final int VOICEMAIL_ARCHIVE_TABLE = 1; private static final int VOICEMAIL_ARCHIVE_TABLE_ID = 2; private static final String VOICEMAIL_FOLDER = "voicemails"; private DialerDatabaseHelper mDialerDatabaseHelper; private final UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); @Override public boolean onCreate() { mDialerDatabaseHelper = getDatabaseHelper(getContext()); if (mDialerDatabaseHelper == null) { return false; } mUriMatcher.addURI(VoicemailArchiveContract.AUTHORITY, VoicemailArchiveContract.VoicemailArchive.VOICEMAIL_ARCHIVE_TABLE, VOICEMAIL_ARCHIVE_TABLE); mUriMatcher.addURI(VoicemailArchiveContract.AUTHORITY, VoicemailArchiveContract.VoicemailArchive.VOICEMAIL_ARCHIVE_TABLE + "/#", VOICEMAIL_ARCHIVE_TABLE_ID); return true; } @VisibleForTesting protected DialerDatabaseHelper getDatabaseHelper(Context context) { return DatabaseHelperManager.getDatabaseHelper(context); } /** * Used by the test class because it extends {@link android.test.ProviderTestCase2} in which the * {@link android.test.IsolatedContext} returns /dev/null when getFilesDir() is called. * * @see android.test.IsolatedContext#getFilesDir */ @VisibleForTesting protected File getFilesDir() { return getContext().getFilesDir(); } @Nullable @Override public Cursor query(Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { SQLiteDatabase db = mDialerDatabaseHelper.getReadableDatabase(); SQLiteQueryBuilder queryBuilder = getQueryBuilder(uri); Cursor cursor = queryBuilder .query(db, projection, selection, selectionArgs, null, null, sortOrder); if (cursor != null) { cursor.setNotificationUri(getContext().getContentResolver(), VoicemailArchiveContract.VoicemailArchive.CONTENT_URI); } return cursor; } @Override public String getType(Uri uri) { return VoicemailArchiveContract.VoicemailArchive.CONTENT_ITEM_TYPE; } @Nullable @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = mDialerDatabaseHelper.getWritableDatabase(); long id = db.insert(DialerDatabaseHelper.Tables.VOICEMAIL_ARCHIVE_TABLE, null, values); if (id < 0) { return null; } notifyChange(uri); // Create the directory for archived voicemails if it doesn't already exist File directory = new File(getFilesDir(), VOICEMAIL_FOLDER); directory.mkdirs(); Uri newUri = ContentUris.withAppendedId(uri, id); // Create new file only if path is not provided to one if (!values.containsKey(VoicemailArchiveContract.VoicemailArchive._DATA)) { String fileExtension = MimeTypeMap.getSingleton().getExtensionFromMimeType( values.getAsString(VoicemailArchiveContract.VoicemailArchive.MIME_TYPE)); File voicemailFile = new File(directory, TextUtils.isEmpty(fileExtension) ? Long.toString(id) : id + "." + fileExtension); values.put(VoicemailArchiveContract.VoicemailArchive._DATA, voicemailFile.getPath()); } update(newUri, values, null, null); return newUri; } @Override public int delete(Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { SQLiteDatabase db = mDialerDatabaseHelper.getWritableDatabase(); SQLiteQueryBuilder queryBuilder = getQueryBuilder(uri); Cursor cursor = queryBuilder.query(db, null, selection, selectionArgs, null, null, null); // Delete all the voicemail files related to the selected rows while (cursor.moveToNext()) { deleteFile(cursor.getString(cursor.getColumnIndex( VoicemailArchiveContract.VoicemailArchive._DATA))); } int rows = db.delete(DialerDatabaseHelper.Tables.VOICEMAIL_ARCHIVE_TABLE, getSelectionWithId(selection, uri), selectionArgs); if (rows > 0) { notifyChange(uri); } return rows; } @Override public int update(Uri uri, ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { SQLiteDatabase db = mDialerDatabaseHelper.getWritableDatabase(); selection = getSelectionWithId(selection, uri); int rows = db.update(DialerDatabaseHelper.Tables.VOICEMAIL_ARCHIVE_TABLE, values, selection, selectionArgs); if (rows > 0) { notifyChange(uri); } return rows; } @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { if (mUriMatcher.match(uri) != VOICEMAIL_ARCHIVE_TABLE_ID) { throw new IllegalArgumentException("URI Invalid."); } return openFileHelper(uri, mode); } private void deleteFile(@Nullable String path) { if (TextUtils.isEmpty(path)) { return; } File file = new File(path); if (file.exists()) { file.delete(); } } private SQLiteQueryBuilder getQueryBuilder(Uri uri) { SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); queryBuilder.setTables(DialerDatabaseHelper.Tables.VOICEMAIL_ARCHIVE_TABLE); String selectionWithId = getSelectionWithId(null, uri); if (!TextUtils.isEmpty(selectionWithId)) { queryBuilder.appendWhere(selectionWithId); } return queryBuilder; } private String getSelectionWithId(String selection, Uri uri) { int match = mUriMatcher.match(uri); switch (match) { case VOICEMAIL_ARCHIVE_TABLE: return selection; case VOICEMAIL_ARCHIVE_TABLE_ID: String idStr = VoicemailArchiveContract.VoicemailArchive._ID + "=" + ContentUris.parseId(uri); return TextUtils.isEmpty(selection) ? idStr : selection + " AND " + idStr; default: throw new IllegalArgumentException("Unknown uri: " + uri); } } private void notifyChange(Uri uri) { getContext().getContentResolver().notifyChange(uri, null); } }