From 450a605729a2d45710e988e5ff4855eb36137e8f Mon Sep 17 00:00:00 2001 From: Sarmad Hashmi Date: Tue, 9 Feb 2016 18:54:26 -0800 Subject: Add voicemail_archive_table to dialer database. Stores the voicemail content and call log information for all the voicemails that have been archived. BUG=22797391 Change-Id: I1b5d98ab17d3d6f32d6797c2c51b50bcd29cd5fa (cherry picked from commit ca67dbe4b04a6eaaa106d40c199bc86d64d94e40) --- .../dialer/database/DialerDatabaseHelper.java | 49 ++++- .../dialer/database/VoicemailArchiveContract.java | 201 ++++++++++++++++++++ .../dialer/database/VoicemailArchiveProvider.java | 211 +++++++++++++++++++++ 3 files changed, 460 insertions(+), 1 deletion(-) create mode 100644 src/com/android/dialer/database/VoicemailArchiveContract.java create mode 100644 src/com/android/dialer/database/VoicemailArchiveProvider.java (limited to 'src') diff --git a/src/com/android/dialer/database/DialerDatabaseHelper.java b/src/com/android/dialer/database/DialerDatabaseHelper.java index 1f926c140..5edfb270d 100644 --- a/src/com/android/dialer/database/DialerDatabaseHelper.java +++ b/src/com/android/dialer/database/DialerDatabaseHelper.java @@ -39,6 +39,7 @@ import android.util.Log; import com.android.contacts.common.util.PermissionsUtil; import com.android.contacts.common.util.StopWatch; import com.android.dialer.database.FilteredNumberContract.FilteredNumberColumns; +import com.android.dialer.database.VoicemailArchiveContract.VoicemailArchive; import com.android.dialer.R; import com.android.dialer.dialpad.SmartDialNameMatcher; import com.android.dialer.dialpad.SmartDialPrefix; @@ -75,7 +76,7 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { * 0-98 KitKat * */ - public static final int DATABASE_VERSION = 8; + public static final int DATABASE_VERSION = 9; public static final String DATABASE_NAME = "dialer.db"; /** @@ -94,6 +95,8 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { static final String SMARTDIAL_TABLE = "smartdial_table"; /** Saves all possible prefixes to refer to a contacts.*/ static final String PREFIX_TABLE = "prefix_table"; + /** Saves all archived voicemail information. */ + static final String VOICEMAIL_ARCHIVE_TABLE = "voicemail_archive_table"; /** Database properties for internal use */ static final String PROPERTIES = "properties"; } @@ -434,6 +437,8 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { + FilteredNumberColumns.TYPE + " INTEGER," + FilteredNumberColumns.SOURCE + " INTEGER" + ");"); + + createVoicemailArchiveTable(db); setProperty(db, DATABASE_VERSION_PROPERTY, String.valueOf(DATABASE_VERSION)); if (!mIsTestInstance) { resetSmartDialLastUpdatedTime(); @@ -445,6 +450,7 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { db.execSQL("DROP TABLE IF EXISTS " + Tables.SMARTDIAL_TABLE); db.execSQL("DROP TABLE IF EXISTS " + Tables.PROPERTIES); db.execSQL("DROP TABLE IF EXISTS " + Tables.FILTERED_NUMBER_TABLE); + db.execSQL("DROP TABLE IF EXISTS " + Tables.VOICEMAIL_ARCHIVE_TABLE); } @Override @@ -486,6 +492,12 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { oldVersion = 8; } + if (oldVersion < 9) { + db.execSQL("DROP TABLE IF EXISTS " + Tables.VOICEMAIL_ARCHIVE_TABLE); + createVoicemailArchiveTable(db); + oldVersion = 9; + } + if (oldVersion != DATABASE_VERSION) { throw new IllegalStateException( "error upgrading the database to version " + DATABASE_VERSION); @@ -652,6 +664,41 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { SmartDialDbColumns.LAST_SMARTDIAL_UPDATE_TIME + " > " + last_update_time, null); } + /** + * All columns excluding MIME_TYPE, _DATA, ARCHIVED, SERVER_ID, are the same as + * the columns in the {@link android.provider.CallLog.Calls} table. + * + * @param db Database pointer to the dialer database. + */ + private void createVoicemailArchiveTable(SQLiteDatabase db) { + db.execSQL("CREATE TABLE " + Tables.VOICEMAIL_ARCHIVE_TABLE + " (" + + VoicemailArchive._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + VoicemailArchive.NUMBER + " TEXT," + + VoicemailArchive.DATE + " LONG," + + VoicemailArchive.DURATION + " LONG," + + VoicemailArchive.MIME_TYPE + " TEXT," + + VoicemailArchive.COUNTRY_ISO + " TEXT," + + VoicemailArchive._DATA + " TEXT," + + VoicemailArchive.GEOCODED_LOCATION + " TEXT," + + VoicemailArchive.CACHED_NAME + " TEXT," + + VoicemailArchive.CACHED_NUMBER_TYPE + " INTEGER," + + VoicemailArchive.CACHED_NUMBER_LABEL + " TEXT," + + VoicemailArchive.CACHED_LOOKUP_URI + " TEXT," + + VoicemailArchive.CACHED_MATCHED_NUMBER + " TEXT," + + VoicemailArchive.CACHED_NORMALIZED_NUMBER + " TEXT," + + VoicemailArchive.CACHED_PHOTO_ID + " LONG," + + VoicemailArchive.CACHED_FORMATTED_NUMBER + " TEXT," + + VoicemailArchive.ARCHIVED + " INTEGER," + + VoicemailArchive.NUMBER_PRESENTATION + " INTEGER," + + VoicemailArchive.ACCOUNT_COMPONENT_NAME + " TEXT," + + VoicemailArchive.ACCOUNT_ID + " TEXT," + + VoicemailArchive.FEATURES + " INTEGER," + + VoicemailArchive.SERVER_ID + " INTEGER," + + VoicemailArchive.TRANSCRIPTION + " TEXT," + + VoicemailArchive.CACHED_PHOTO_URI + " TEXT" + + ");"); + } + /** * Removes all entries in the smartdial contact database. */ diff --git a/src/com/android/dialer/database/VoicemailArchiveContract.java b/src/com/android/dialer/database/VoicemailArchiveContract.java new file mode 100644 index 000000000..92d9c17ef --- /dev/null +++ b/src/com/android/dialer/database/VoicemailArchiveContract.java @@ -0,0 +1,201 @@ +/* + * 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.net.Uri; +import android.provider.BaseColumns; +import android.provider.CallLog; +import android.provider.OpenableColumns; + +/** + * Contains definitions for the supported URIs and columns for the voicemail archive table. + * All the fields excluding MIME_TYPE, _DATA, ARCHIVED, SERVER_ID, mirror the fields in the + * contract provided in {@link CallLog.Calls}. + */ +public final class VoicemailArchiveContract { + + /** The authority used by the voicemail archive provider. */ + public static final String AUTHORITY = "com.android.dialer.database.voicemailarchiveprovider"; + + /** A content:// style uri for the voicemail archive provider */ + public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY); + + public static final class VoicemailArchive implements BaseColumns, OpenableColumns { + + public static final String VOICEMAIL_ARCHIVE_TABLE = "voicemail_archive_table"; + + public static final Uri CONTENT_URI = Uri.withAppendedPath( + AUTHORITY_URI, + VOICEMAIL_ARCHIVE_TABLE); + + /** + * @see android.provider.CallLog.Calls#NUMBER + * TYPE: TEXT + */ + public static final String NUMBER = CallLog.Calls.NUMBER; + + /** + * @see android.provider.CallLog.Calls#DATE + * TYPE: LONG + */ + public static final String DATE = CallLog.Calls.DATE; + + /** + * @see android.provider.CallLog.Calls#DURATION + * TYPE: LONG + */ + public static final String DURATION = CallLog.Calls.DURATION; + + /** + * The mime type of the archived voicemail file. + * TYPE: TEXT + */ + public static final String MIME_TYPE = "mime_type"; + + /** + * @see android.provider.CallLog.Calls#COUNTRY_ISO + * TYPE: LONG + */ + public static final String COUNTRY_ISO = CallLog.Calls.COUNTRY_ISO; + + /** + * The path of the archived voicemail file. + * TYPE: TEXT + */ + public static final String _DATA = "_data"; + + /** + * @see android.provider.CallLog.Calls#GEOCODED_LOCATION + * TYPE: TEXT + */ + public static final String GEOCODED_LOCATION = CallLog.Calls.GEOCODED_LOCATION; + + /** + * @see android.provider.CallLog.Calls#CACHED_NAME + * TYPE: TEXT + */ + public static final String CACHED_NAME = CallLog.Calls.CACHED_NAME; + + /** + * @see android.provider.CallLog.Calls#CACHED_NUMBER_TYPE + * TYPE: INTEGER + */ + public static final String CACHED_NUMBER_TYPE = CallLog.Calls.CACHED_NUMBER_TYPE; + + /** + * @see android.provider.CallLog.Calls#CACHED_NUMBER_LABEL + * TYPE: TEXT + */ + public static final String CACHED_NUMBER_LABEL = CallLog.Calls.CACHED_NUMBER_LABEL; + + /** + * @see android.provider.CallLog.Calls#CACHED_LOOKUP_URI + * TYPE: TEXT + */ + public static final String CACHED_LOOKUP_URI = CallLog.Calls.CACHED_LOOKUP_URI; + + /** + * @see android.provider.CallLog.Calls#CACHED_MATCHED_NUMBER + * TYPE: TEXT + */ + public static final String CACHED_MATCHED_NUMBER = CallLog.Calls.CACHED_MATCHED_NUMBER; + + /** + * @see android.provider.CallLog.Calls#CACHED_NORMALIZED_NUMBER + * TYPE: TEXT + */ + public static final String CACHED_NORMALIZED_NUMBER = + CallLog.Calls.CACHED_NORMALIZED_NUMBER; + + /** + * @see android.provider.CallLog.Calls#CACHED_PHOTO_ID + * TYPE: LONG + */ + public static final String CACHED_PHOTO_ID = CallLog.Calls.CACHED_PHOTO_ID; + + /** + * @see android.provider.CallLog.Calls#CACHED_FORMATTED_NUMBER + * TYPE: TEXT + */ + public static final String CACHED_FORMATTED_NUMBER = CallLog.Calls.CACHED_FORMATTED_NUMBER; + + /** + * If the voicemail was archived by the user by pressing the archive button, this is set to + * 1 (true). If the voicemail was archived for the purpose of forwarding to other + * applications, this is set to 0 (false). + * TYPE: INTEGER + */ + public static final String ARCHIVED = "archived_by_user"; + + /** + * @see android.provider.CallLog.Calls#NUMBER_PRESENTATION + * TYPE: INTEGER + */ + public static final String NUMBER_PRESENTATION = CallLog.Calls.NUMBER_PRESENTATION; + + /** + * @see android.provider.CallLog.Calls#PHONE_ACCOUNT_COMPONENT_NAME + * TYPE: TEXT + */ + public static final String ACCOUNT_COMPONENT_NAME = + CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME; + + /** + * @see android.provider.CallLog.Calls#PHONE_ACCOUNT_ID + * TYPE: TEXT + */ + public static final String ACCOUNT_ID = CallLog.Calls.PHONE_ACCOUNT_ID; + + /** + * @see android.provider.CallLog.Calls#FEATURES + * TYPE: INTEGER + */ + public static final String FEATURES = CallLog.Calls.FEATURES; + + /** + * The id of the voicemail on the server. + * TYPE: INTEGER + */ + public static final String SERVER_ID = "server_id"; + + /** + * @see android.provider.CallLog.Calls#TRANSCRIPTION + * TYPE: TEXT + */ + public static final String TRANSCRIPTION = CallLog.Calls.TRANSCRIPTION; + + /** + * @see android.provider.CallLog.Calls#CACHED_PHOTO_URI + * TYPE: TEXT + */ + public static final String CACHED_PHOTO_URI = CallLog.Calls.CACHED_PHOTO_URI; + + /** + * The MIME type of a {@link #CONTENT_URI} single voicemail. + */ + public static final String CONTENT_ITEM_TYPE = + "vnd.android.cursor.item/voicmail_archive_table"; + + public static final Uri buildWithId(int id) { + return Uri.withAppendedPath(CONTENT_URI, Integer.toString(id)); + } + + /** Not instantiable. */ + private VoicemailArchive() { + } + } +} diff --git a/src/com/android/dialer/database/VoicemailArchiveProvider.java b/src/com/android/dialer/database/VoicemailArchiveProvider.java new file mode 100644 index 000000000..ae73670b8 --- /dev/null +++ b/src/com/android/dialer/database/VoicemailArchiveProvider.java @@ -0,0 +1,211 @@ +/* + * 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 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(); + + // Update the row's _data column with a file path in the voicemails folder + Uri newUri = ContentUris.withAppendedId(uri, id); + File voicemailFile = new File(directory, Long.toString(id)); + 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); + } +} -- cgit v1.2.3