diff options
author | Anne Rong <annerong@google.com> | 2015-08-19 20:48:41 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-08-19 20:48:41 +0000 |
commit | 822b243845a04067809f2cbc05dc163b4635db0a (patch) | |
tree | b2187b1dfc46b5529805f87c08a3fd72cb12246d | |
parent | c1c1e05fe291b6cb7db9df46d27dd72888739862 (diff) | |
parent | 6fcdcc15f3b8786e0ecab5886324eeb212c58699 (diff) |
Merge "Create local database table + ContentProvider for filtered numbers"
-rw-r--r-- | AndroidManifest.xml | 7 | ||||
-rw-r--r-- | src/com/android/dialer/database/DialerDatabaseHelper.java | 100 | ||||
-rw-r--r-- | src/com/android/dialer/database/FilteredNumberContract.java | 149 | ||||
-rw-r--r-- | src/com/android/dialer/database/FilteredNumberProvider.java | 199 | ||||
-rw-r--r-- | tests/src/com/android/dialer/database/FilteredNumberProviderTest.java | 227 |
5 files changed, 651 insertions, 31 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 7a1238627..bc78f18c2 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -305,5 +305,12 @@ <action android:name="android.telecom.InCallService"/> </intent-filter> </service> + + <provider + android:name=".database.FilteredNumberProvider" + android:authorities="com.android.dialer" + android:exported="false" + android:multiprocess="false" + /> </application> </manifest> diff --git a/src/com/android/dialer/database/DialerDatabaseHelper.java b/src/com/android/dialer/database/DialerDatabaseHelper.java index eec24f5bc..8fcbb9208 100644 --- a/src/com/android/dialer/database/DialerDatabaseHelper.java +++ b/src/com/android/dialer/database/DialerDatabaseHelper.java @@ -38,6 +38,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.R; import com.android.dialer.dialpad.SmartDialNameMatcher; import com.android.dialer.dialpad.SmartDialPrefix; @@ -60,6 +61,7 @@ import java.util.concurrent.atomic.AtomicBoolean; public class DialerDatabaseHelper extends SQLiteOpenHelper { private static final String TAG = "DialerDatabaseHelper"; private static final boolean DEBUG = false; + private boolean mIsTestInstance = false; private static DialerDatabaseHelper sSingleton = null; @@ -73,7 +75,7 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { * 0-98 KitKat * </pre> */ - public static final int DATABASE_VERSION = 4; + public static final int DATABASE_VERSION = 5; public static final String DATABASE_NAME = "dialer.db"; /** @@ -86,6 +88,8 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { private static final int MAX_ENTRIES = 20; public interface Tables { + /** Saves a list of numbers to be blocked.*/ + static final String FILTERED_NUMBER_TABLE = "filtered_numbers_table"; /** Saves the necessary smart dial information of all contacts. */ static final String SMARTDIAL_TABLE = "smartdial_table"; /** Saves all possible prefixes to refer to a contacts.*/ @@ -334,7 +338,12 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { */ @VisibleForTesting static DialerDatabaseHelper getNewInstanceForTest(Context context) { - return new DialerDatabaseHelper(context, null); + return new DialerDatabaseHelper(context, null, true); + } + + protected DialerDatabaseHelper(Context context, String databaseName, boolean isTestInstance) { + this(context, databaseName, DATABASE_VERSION); + mIsTestInstance = isTestInstance; } protected DialerDatabaseHelper(Context context, String databaseName) { @@ -358,36 +367,51 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { private void setupTables(SQLiteDatabase db) { dropTables(db); - db.execSQL("CREATE TABLE " + Tables.SMARTDIAL_TABLE + " (" + - SmartDialDbColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + - SmartDialDbColumns.DATA_ID + " INTEGER, " + - SmartDialDbColumns.NUMBER + " TEXT," + - SmartDialDbColumns.CONTACT_ID + " INTEGER," + - SmartDialDbColumns.LOOKUP_KEY + " TEXT," + - SmartDialDbColumns.DISPLAY_NAME_PRIMARY + " TEXT, " + - SmartDialDbColumns.PHOTO_ID + " INTEGER, " + - SmartDialDbColumns.LAST_SMARTDIAL_UPDATE_TIME + " LONG, " + - SmartDialDbColumns.LAST_TIME_USED + " LONG, " + - SmartDialDbColumns.TIMES_USED + " INTEGER, " + - SmartDialDbColumns.STARRED + " INTEGER, " + - SmartDialDbColumns.IS_SUPER_PRIMARY + " INTEGER, " + - SmartDialDbColumns.IN_VISIBLE_GROUP + " INTEGER, " + - SmartDialDbColumns.IS_PRIMARY + " INTEGER" + - ");"); - - db.execSQL("CREATE TABLE " + Tables.PREFIX_TABLE + " (" + - PrefixColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + - PrefixColumns.PREFIX + " TEXT COLLATE NOCASE, " + - PrefixColumns.CONTACT_ID + " INTEGER" + - ");"); - - db.execSQL("CREATE TABLE " + Tables.PROPERTIES + " (" + - PropertiesColumns.PROPERTY_KEY + " TEXT PRIMARY KEY, " + - PropertiesColumns.PROPERTY_VALUE + " TEXT " + - ");"); - + db.execSQL("CREATE TABLE " + Tables.SMARTDIAL_TABLE + " (" + + SmartDialDbColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + SmartDialDbColumns.DATA_ID + " INTEGER, " + + SmartDialDbColumns.NUMBER + " TEXT," + + SmartDialDbColumns.CONTACT_ID + " INTEGER," + + SmartDialDbColumns.LOOKUP_KEY + " TEXT," + + SmartDialDbColumns.DISPLAY_NAME_PRIMARY + " TEXT, " + + SmartDialDbColumns.PHOTO_ID + " INTEGER, " + + SmartDialDbColumns.LAST_SMARTDIAL_UPDATE_TIME + " LONG, " + + SmartDialDbColumns.LAST_TIME_USED + " LONG, " + + SmartDialDbColumns.TIMES_USED + " INTEGER, " + + SmartDialDbColumns.STARRED + " INTEGER, " + + SmartDialDbColumns.IS_SUPER_PRIMARY + " INTEGER, " + + SmartDialDbColumns.IN_VISIBLE_GROUP + " INTEGER, " + + SmartDialDbColumns.IS_PRIMARY + " INTEGER" + + ");"); + + db.execSQL("CREATE TABLE " + Tables.PREFIX_TABLE + " (" + + PrefixColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + PrefixColumns.PREFIX + " TEXT COLLATE NOCASE, " + + PrefixColumns.CONTACT_ID + " INTEGER" + + ");"); + + db.execSQL("CREATE TABLE " + Tables.PROPERTIES + " (" + + PropertiesColumns.PROPERTY_KEY + " TEXT PRIMARY KEY, " + + PropertiesColumns.PROPERTY_VALUE + " TEXT " + + ");"); + + // This will need to also be updated in setupTablesForFilteredNumberTest and onUpgrade. + // Hardcoded so we know on glance what columns are updated in setupTables, + // and to be able to guarantee the state of the DB at each upgrade step. + db.execSQL("CREATE TABLE " + Tables.FILTERED_NUMBER_TABLE + " (" + + FilteredNumberColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + FilteredNumberColumns.NORMALIZED_NUMBER + " TEXT," + + FilteredNumberColumns.COUNTRY_ISO + " TEXT," + + FilteredNumberColumns.TIMES_FILTERED + " INTEGER," + + FilteredNumberColumns.LAST_TIME_FILTERED + " LONG," + + FilteredNumberColumns.CREATION_TIME + " LONG," + + FilteredNumberColumns.TYPE + " INTEGER," + + FilteredNumberColumns.SOURCE + " INTEGER" + + ");"); setProperty(db, DATABASE_VERSION_PROPERTY, String.valueOf(DATABASE_VERSION)); - resetSmartDialLastUpdatedTime(); + if (!mIsTestInstance) { + resetSmartDialLastUpdatedTime(); + } } public void dropTables(SQLiteDatabase db) { @@ -414,6 +438,20 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { return; } + if (oldVersion < 5) { + db.execSQL("CREATE TABLE " + Tables.FILTERED_NUMBER_TABLE + " (" + + FilteredNumberColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + FilteredNumberColumns.NORMALIZED_NUMBER + " TEXT," + + FilteredNumberColumns.COUNTRY_ISO + " TEXT," + + FilteredNumberColumns.TIMES_FILTERED + " INTEGER," + + FilteredNumberColumns.LAST_TIME_FILTERED + " LONG," + + FilteredNumberColumns.CREATION_TIME + " LONG," + + FilteredNumberColumns.TYPE + " INTEGER," + + FilteredNumberColumns.SOURCE + " INTEGER" + + ");"); + oldVersion = 5; + } + if (oldVersion != DATABASE_VERSION) { throw new IllegalStateException( "error upgrading the database to version " + DATABASE_VERSION); diff --git a/src/com/android/dialer/database/FilteredNumberContract.java b/src/com/android/dialer/database/FilteredNumberContract.java new file mode 100644 index 000000000..1fb2363d0 --- /dev/null +++ b/src/com/android/dialer/database/FilteredNumberContract.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2015 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; + +/** + * <p> + * The contract between the filtered number provider and applications. Contains + * definitions for the supported URIs and columns. + * Currently only accessible within Dialer. + * </p> + */ +public final class FilteredNumberContract { + + /** The authority for the filtered numbers provider */ + public static final String AUTHORITY = "com.android.dialer"; + + /** A content:// style uri to the authority for the filtered numbers provider */ + public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY); + + /** The type of filtering to be applied, e.g. block the number or whitelist the number. */ + public interface FilteredNumberTypes { + static final int UNDEFINED = 0; + /** + * Dialer will disconnect the call without sending the caller to voicemail. + */ + static final int BLOCKED_NUMBER = 1; + } + + /** The original source of the filtered number, e.g. the user manually added it. */ + public interface FilteredNumberSources { + static final int UNDEFINED = 0; + /** + * The user manually added this number through Dialer (e.g. from the call log or InCallUI). + */ + static final int USER = 1; + } + + public interface FilteredNumberColumns { + // TYPE: INTEGER + static final String _ID = "id"; + /** + * Represents the number to be filtered, normalized to compare phone numbers for equality. + * + * TYPE: TEXT + */ + static final String NORMALIZED_NUMBER = "normalized_number"; + /** + * The country code representing the country detected when + * the phone number was added to the database. + * Most numbers don't have the country code, so a best guess is provided by + * the country detector system. The country iso is also needed in order to format + * phone numbers correctly. + * + * TYPE: TEXT + */ + static final String COUNTRY_ISO = "country_iso"; + /** + * The number of times the number has been filtered by Dialer. + * When this number is incremented, LAST_TIME_FILTERED should also be updated to + * the current time. + * + * TYPE: INTEGER + */ + static final String TIMES_FILTERED = "times_filtered"; + /** + * Set to the current time when the phone number is filtered. + * When this is updated, TIMES_FILTERED should also be incremented. + * + * TYPE: LONG + */ + static final String LAST_TIME_FILTERED = "last_time_filtered"; + // TYPE: LONG + static final String CREATION_TIME = "creation_time"; + /** + * Indicates the type of filtering to be applied. + * + * TYPE: INTEGER + * See {@link FilteredNumberTypes} + */ + static final String TYPE = "type"; + /** + * Integer representing the original source of the filtered number. + * + * TYPE: INTEGER + * See {@link FilteredNumberSources} + */ + static final String SOURCE = "source"; + } + + /** + * <p> + * Constants for the table of filtered numbers. + * </p> + * <h3>Operations</h3> + * <dl> + * <dt><b>Insert</b></dt> + * <dd>Required fields: NORMALIZED_NUMBER, TYPE, SOURCE. + * A default value will be used for the other fields if left null.</dd> + * <dt><b>Update</b></dt> + * <dt><b>Delete</b></dt> + * <dt><b>Query</b></dt> + * <dd>{@link #CONTENT_URI} can be used for any query, append an ID to + * retrieve a specific filtered number entry.</dd> + * </dl> + */ + public static class FilteredNumber implements BaseColumns { + + public static final String FILTERED_NUMBERS_TABLE = "filtered_numbers_table"; + + public static final Uri CONTENT_URI = Uri.withAppendedPath( + AUTHORITY_URI, + FILTERED_NUMBERS_TABLE); + + /** + * This utility class cannot be instantiated. + */ + private FilteredNumber () {} + + /** + * The MIME type of {@link #CONTENT_URI} providing a directory of + * filtered numbers. + */ + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/filtered_numbers_table"; + + /** + * The MIME type of a {@link #CONTENT_URI} single filtered number. + */ + public static final String CONTENT_ITEM_TYPE = + "vnd.android.cursor.item/filtered_numbers_table"; + + } +} diff --git a/src/com/android/dialer/database/FilteredNumberProvider.java b/src/com/android/dialer/database/FilteredNumberProvider.java new file mode 100644 index 000000000..2bacd89b2 --- /dev/null +++ b/src/com/android/dialer/database/FilteredNumberProvider.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2015 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.Binder; +import android.text.TextUtils; +import android.text.format.Time; +import android.util.Log; + +import com.android.contacts.common.GeoUtil; +import com.android.dialer.database.FilteredNumberContract.FilteredNumberColumns; +import com.android.dialerbind.DatabaseHelperManager; +import com.google.common.annotations.VisibleForTesting; + +import java.util.Arrays; + +/** + * Filtered number content provider. + */ +public class FilteredNumberProvider extends ContentProvider { + + private static String TAG = FilteredNumberProvider.class.getSimpleName(); + + private DialerDatabaseHelper mDialerDatabaseHelper; + + private static final int FILTERED_NUMBERS_TABLE = 1; + private static final int FILTERED_NUMBERS_TABLE_ID = 2; + + private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + static { + sUriMatcher.addURI(FilteredNumberContract.AUTHORITY, + FilteredNumberContract.FilteredNumber.FILTERED_NUMBERS_TABLE, + FILTERED_NUMBERS_TABLE); + sUriMatcher.addURI(FilteredNumberContract.AUTHORITY, + FilteredNumberContract.FilteredNumber.FILTERED_NUMBERS_TABLE + "/#", + FILTERED_NUMBERS_TABLE_ID); + } + + @Override + public boolean onCreate() { + mDialerDatabaseHelper = getDatabaseHelper(getContext()); + if (mDialerDatabaseHelper == null) { + return false; + } + return true; + } + + @VisibleForTesting + protected DialerDatabaseHelper getDatabaseHelper(Context context) { + return DatabaseHelperManager.getDatabaseHelper(context); + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + Log.d(TAG, "query: uri=" + uri + " projection=" + Arrays.toString(projection) + + " selection=[" + selection + "] args=" + Arrays.toString(selectionArgs) + + " order=[" + sortOrder + "] CPID=" + Binder.getCallingPid()); + + final SQLiteDatabase db = mDialerDatabaseHelper.getReadableDatabase(); + SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); + qb.setTables(DialerDatabaseHelper.Tables.FILTERED_NUMBER_TABLE); + final int match = sUriMatcher.match(uri); + switch (match) { + case FILTERED_NUMBERS_TABLE: + break; + case FILTERED_NUMBERS_TABLE_ID: + qb.appendWhere(FilteredNumberColumns._ID + "=" + ContentUris.parseId(uri)); + break; + default: + throw new IllegalArgumentException("Unknown uri: " + uri); + } + final Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, null); + if (c != null) { + c.setNotificationUri(getContext().getContentResolver(), + FilteredNumberContract.FilteredNumber.CONTENT_URI); + } else { + Log.d(TAG, "CURSOR WAS NULL"); + } + return c; + } + + @Override + public String getType(Uri uri) { + return FilteredNumberContract.FilteredNumber.CONTENT_ITEM_TYPE; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + SQLiteDatabase db = mDialerDatabaseHelper.getWritableDatabase(); + setDefaultValues(values); + long id = db.insert(DialerDatabaseHelper.Tables.FILTERED_NUMBER_TABLE, null, values); + if (id < 0) { + return null; + } + notifyChange(uri); + return ContentUris.withAppendedId(uri, id); + } + + @VisibleForTesting + protected long getCurrentTimeMs() { + Time timeNow = new Time(); + timeNow.setToNow(); + return timeNow.toMillis(false); + } + + private void setDefaultValues(ContentValues values) { + if (values.getAsString(FilteredNumberColumns.COUNTRY_ISO) == null) { + values.put(FilteredNumberColumns.COUNTRY_ISO, + GeoUtil.getCurrentCountryIso(getContext())); + } + if (values.getAsInteger(FilteredNumberColumns.TIMES_FILTERED) == null) { + values.put(FilteredNumberContract.FilteredNumberColumns.TIMES_FILTERED, 0); + } + if (values.getAsLong(FilteredNumberColumns.CREATION_TIME) == null) { + values.put(FilteredNumberColumns.CREATION_TIME, getCurrentTimeMs()); + } + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + SQLiteDatabase db = mDialerDatabaseHelper.getWritableDatabase(); + final int match = sUriMatcher.match(uri); + switch (match) { + case FILTERED_NUMBERS_TABLE: + break; + case FILTERED_NUMBERS_TABLE_ID: + selection = getSelectionWithId(selection, ContentUris.parseId(uri)); + break; + default: + throw new IllegalArgumentException("Unknown uri: " + uri); + } + int rows = db.delete(DialerDatabaseHelper.Tables.FILTERED_NUMBER_TABLE, + selection, + selectionArgs); + if (rows > 0) { + notifyChange(uri); + } + return rows; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + SQLiteDatabase db = mDialerDatabaseHelper.getWritableDatabase(); + final int match = sUriMatcher.match(uri); + switch (match) { + case FILTERED_NUMBERS_TABLE: + break; + case FILTERED_NUMBERS_TABLE_ID: + selection = getSelectionWithId(selection, ContentUris.parseId(uri)); + break; + default: + throw new IllegalArgumentException("Unknown uri: " + uri); + } + int rows = db.update(DialerDatabaseHelper.Tables.FILTERED_NUMBER_TABLE, + values, + selection, + selectionArgs); + if (rows > 0 ) { + notifyChange(uri); + } + return rows; + } + + private String getSelectionWithId(String selection, long id) { + if (TextUtils.isEmpty(selection)) { + return FilteredNumberContract.FilteredNumberColumns._ID + "=" + id; + } else { + return selection + "AND " + FilteredNumberContract.FilteredNumberColumns._ID + "=" + id; + } + } + + private void notifyChange(Uri uri) { + getContext().getContentResolver().notifyChange(uri, null); + } +} diff --git a/tests/src/com/android/dialer/database/FilteredNumberProviderTest.java b/tests/src/com/android/dialer/database/FilteredNumberProviderTest.java new file mode 100644 index 000000000..94bf6e6c2 --- /dev/null +++ b/tests/src/com/android/dialer/database/FilteredNumberProviderTest.java @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2015 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.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.net.Uri; +import android.test.ProviderTestCase2; + +public class FilteredNumberProviderTest extends + ProviderTestCase2<FilteredNumberProviderTest.TestFilteredNumberProvider> { + private ContentResolver mResolver; + + private static final String TIME_ZONE_AMERICA_LOS_ANGELES = "America/Los_Angeles"; + private static final String DEFAULT_TIMEZONE = TIME_ZONE_AMERICA_LOS_ANGELES; + private static final String DEFAULT_COUNTRY_ISO = "US"; + private static final String TEST_NUMBER = "+1234567890"; + private static final long TEST_TIME = 1439936706; + + public FilteredNumberProviderTest () { + super(TestFilteredNumberProvider.class, FilteredNumberContract.AUTHORITY); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + mResolver = getMockContentResolver(); + } + + public void testInsert() { + // Insert row + Uri uri = mResolver.insert( + FilteredNumberContract.FilteredNumber.CONTENT_URI, + getTestValues(null)); + assertNotNull(uri); + long id = ContentUris.parseId(uri); + assertTrue(id > 0); + } + + public void testQuery() { + Cursor cursor = mResolver.query( + FilteredNumberContract.FilteredNumber.CONTENT_URI, null, null, null, null); + assertNotNull(cursor); + assertEquals(cursor.getCount(), 0); + cursor.close(); + } + + public void testInsertAndQuery() { + // Insert row + ContentValues testValues = getTestValues(null); + Uri uri = mResolver.insert(FilteredNumberContract.FilteredNumber.CONTENT_URI, testValues); + + // Query + Cursor cursor = mResolver.query(uri, null, null, null, null); + assertNotNull(cursor); + assertEquals(cursor.getCount(), 1); + + cursor.moveToFirst(); + assertCursorValues(cursor, testValues); + cursor.close(); + } + + public void testIllegalUri() { + try { + mResolver.query( + Uri.withAppendedPath( + FilteredNumberContract.FilteredNumber.CONTENT_URI, + "ILLEGAL"), null, null, null, null); + fail("Expecting exception but none was thrown."); + } catch (IllegalArgumentException e) { + } + } + + public void testQueryWithId() { + // Insert row + ContentValues testValues = getTestValues(null); + Uri uri = mResolver.insert(FilteredNumberContract.FilteredNumber.CONTENT_URI, testValues); + long id = ContentUris.parseId(uri); + + // Query + Cursor cursor = mResolver.query( + ContentUris.withAppendedId( + FilteredNumberContract.FilteredNumber.CONTENT_URI, + id), null, null, null, null); + assertNotNull(cursor); + assertEquals(cursor.getCount(), 1); + + cursor.moveToFirst(); + assertCursorValues(cursor, testValues); + cursor.close(); + } + + public void testDelete() { + // Insert row + Uri uri = mResolver.insert( + FilteredNumberContract.FilteredNumber.CONTENT_URI, + getTestValues(null)); + long id = ContentUris.parseId(uri); + + // Delete row + int rows = mResolver.delete( + FilteredNumberContract.FilteredNumber.CONTENT_URI, + "id = ?", + new String[]{Long.toString(id)}); + assertEquals(rows, 1); + + // Query + Cursor cursor = mResolver.query(uri, null, null, null, null); + assertNotNull(cursor); + assertEquals(cursor.getCount(), 0); + cursor.close(); + } + + public void testUpdate() { + // Insert row + Uri uri = mResolver.insert( + FilteredNumberContract.FilteredNumber.CONTENT_URI, + getTestValues(null)); + + // Update row + ContentValues v = new ContentValues(); + v.put(FilteredNumberContract.FilteredNumberColumns.TIMES_FILTERED, 3); + v.put(FilteredNumberContract.FilteredNumberColumns.LAST_TIME_FILTERED, TEST_TIME); + int rows = mResolver.update(FilteredNumberContract.FilteredNumber.CONTENT_URI, v, + FilteredNumberContract.FilteredNumberColumns.NORMALIZED_NUMBER + " = ?", + new String[]{TEST_NUMBER}); + assertEquals(rows, 1); + + ContentValues expected = getTestValues(TEST_TIME); + expected.put(FilteredNumberContract.FilteredNumberColumns.TIMES_FILTERED, 3); + expected.put(FilteredNumberContract.FilteredNumberColumns.LAST_TIME_FILTERED, TEST_TIME); + + // Re-query + Cursor cursor = mResolver.query(uri, null, null, null, null); + assertNotNull(cursor); + assertEquals(cursor.getCount(), 1); + cursor.moveToFirst(); + assertCursorValues(cursor, expected); + cursor.close(); + } + + public void testInsertDefaultValues() { + // Insert row + ContentValues v = getTestValues(null); + Uri uri = mResolver.insert(FilteredNumberContract.FilteredNumber.CONTENT_URI, v); + assertNotNull(uri); + long id = ContentUris.parseId(uri); + assertTrue(id > 0); + + // Query + Cursor cursor = mResolver.query(uri, null, null, null, null); + assertNotNull(cursor); + assertEquals(cursor.getCount(), 1); + + int creationTimeIndex = + cursor.getColumnIndex(FilteredNumberContract.FilteredNumberColumns.CREATION_TIME); + cursor.moveToFirst(); + assertEquals(cursor.getLong(creationTimeIndex), TEST_TIME); + cursor.close(); + } + + @Override + protected void tearDown() throws Exception { + getProvider().closeDb(); + super.tearDown(); + } + + private ContentValues getTestValues(Long timeNow) { + ContentValues v = new ContentValues(); + v.putNull(FilteredNumberContract.FilteredNumberColumns._ID); + v.put(FilteredNumberContract.FilteredNumberColumns.NORMALIZED_NUMBER, TEST_NUMBER); + v.put(FilteredNumberContract.FilteredNumberColumns.COUNTRY_ISO, DEFAULT_COUNTRY_ISO); + v.put(FilteredNumberContract.FilteredNumberColumns.TIMES_FILTERED, 0); + v.putNull(FilteredNumberContract.FilteredNumberColumns.LAST_TIME_FILTERED); + v.put(FilteredNumberContract.FilteredNumberColumns.CREATION_TIME, timeNow); + v.put(FilteredNumberContract.FilteredNumberColumns.SOURCE, 1); + v.put(FilteredNumberContract.FilteredNumberColumns.TYPE, 1); + return v; + } + + private void assertCursorValues(Cursor cursor, ContentValues expectedValues) { + ContentValues v = new ContentValues(); + DatabaseUtils.cursorRowToContentValues(cursor, v); + v.remove(FilteredNumberContract.FilteredNumberColumns._ID); + expectedValues.remove(FilteredNumberContract.FilteredNumberColumns._ID); + assertEquals(v.toString(), expectedValues.toString()); + } + + public static class TestFilteredNumberProvider extends FilteredNumberProvider { + private DialerDatabaseHelper mDialerDatabaseHelper; + + @Override + protected DialerDatabaseHelper getDatabaseHelper(Context context) { + if (mDialerDatabaseHelper == null) { + mDialerDatabaseHelper = DialerDatabaseHelper.getNewInstanceForTest(context); + } + return mDialerDatabaseHelper; + } + + protected void closeDb() { + mDialerDatabaseHelper.close(); + } + + @Override + protected long getCurrentTimeMs() { + return TEST_TIME; + } + } +} |