diff options
author | Abhijith Shastry <ashastry@google.com> | 2016-01-23 22:16:39 -0800 |
---|---|---|
committer | Abhijith Shastry <ashastry@google.com> | 2016-01-25 12:54:45 -0800 |
commit | 35676f9095853d4a5ac15875a9ddb1aea6b0b809 (patch) | |
tree | 647c7e55747ba17226766250a1fe095890cf4e26 | |
parent | 9f7cfe71be8d9b844b0423c283a923a090bc5d7c (diff) | |
download | BlockedNumberProvider-35676f9095853d4a5ac15875a9ddb1aea6b0b809.tar.gz |
Changes to BlockedNumberProvider:
1. Remove STRIPPED_PHONE_NUMBER column.
2. Temporarily permit system apps to access provider.
3. Notify changes to content so that ListViews work well with the provider.
4. Use DE storage.
BUG: 26232372
Change-Id: Ib7fad2c3971a7b7b74c86c46fe3514330c22334c
5 files changed, 100 insertions, 63 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index d9bd2c9..dd8522c 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -18,17 +18,12 @@ package="com.android.providers.blockednumber" android:sharedUserId="android.uid.shared"> -<!-- - TODO: Make it DE. Add the following to <application>. See go/android-fbe-apis - android:encryptionAware=”true” - android:forceDeviceEncrypted=”true” ---> - <application android:process="android.process.acore" android:label="@string/app_label" - android:allowBackup="false" - android:usesCleartextTraffic="false"> + android:usesCleartextTraffic="false" + android:encryptionAware="true" + android:forceDeviceEncrypted="true"> <provider android:name="BlockedNumberProvider" android:authorities="com.android.blockednumber" diff --git a/src/com/android/providers/blockednumber/BlockedNumberDatabaseHelper.java b/src/com/android/providers/blockednumber/BlockedNumberDatabaseHelper.java index 005c918..ac3e94d 100644 --- a/src/com/android/providers/blockednumber/BlockedNumberDatabaseHelper.java +++ b/src/com/android/providers/blockednumber/BlockedNumberDatabaseHelper.java @@ -24,7 +24,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; public class BlockedNumberDatabaseHelper { - private static final int DATABASE_VERSION = 1; + private static final int DATABASE_VERSION = 2; private static final String DATABASE_NAME = "blockednumbers.db"; @@ -46,23 +46,30 @@ public class BlockedNumberDatabaseHelper { @Override public void onCreate(SQLiteDatabase db) { + createTables(db); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if (oldVersion < 2) { + db.execSQL("DROP TABLE IF EXISTS blocked"); + createTables(db); + } + } + + private void createTables(SQLiteDatabase db) { db.execSQL("CREATE TABLE " + Tables.BLOCKED_NUMBERS + " (" + BlockedNumbers.COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + BlockedNumbers.COLUMN_ORIGINAL_NUMBER + " TEXT NOT NULL UNIQUE," + - BlockedNumbers.COLUMN_STRIPPED_NUMBER + " TEXT NOT NULL," + BlockedNumbers.COLUMN_E164_NUMBER + " TEXT" + ")"); - db.execSQL("CREATE INDEX blocked_number_idx_stripped ON " + Tables.BLOCKED_NUMBERS + - " (" + BlockedNumbers.COLUMN_STRIPPED_NUMBER + ");"); + db.execSQL("CREATE INDEX blocked_number_idx_original ON " + Tables.BLOCKED_NUMBERS + + " (" + BlockedNumbers.COLUMN_ORIGINAL_NUMBER + ");"); db.execSQL("CREATE INDEX blocked_number_idx_e164 ON " + Tables.BLOCKED_NUMBERS + " (" + BlockedNumbers.COLUMN_E164_NUMBER + ");"); } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - } } @VisibleForTesting diff --git a/src/com/android/providers/blockednumber/BlockedNumberProvider.java b/src/com/android/providers/blockednumber/BlockedNumberProvider.java index 72a0c93..2c8cffe 100644 --- a/src/com/android/providers/blockednumber/BlockedNumberProvider.java +++ b/src/com/android/providers/blockednumber/BlockedNumberProvider.java @@ -19,6 +19,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.*; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; @@ -58,7 +60,6 @@ public class BlockedNumberProvider extends ContentProvider { private static final ProjectionMap sBlockedNumberColumns = ProjectionMap.builder() .add(BlockedNumberContract.BlockedNumbers.COLUMN_ID) .add(BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER) - .add(BlockedNumberContract.BlockedNumbers.COLUMN_STRIPPED_NUMBER) .add(BlockedNumberContract.BlockedNumbers.COLUMN_E164_NUMBER) .build(); @@ -112,7 +113,9 @@ public class BlockedNumberProvider extends ContentProvider { final int match = sUriMatcher.match(uri); switch (match) { case BLOCKED_LIST: - return insertBlockedNumber(values); + Uri blockedUri = insertBlockedNumber(values); + getContext().getContentResolver().notifyChange(blockedUri, null); + return blockedUri; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } @@ -123,7 +126,6 @@ public class BlockedNumberProvider extends ContentProvider { */ private Uri insertBlockedNumber(ContentValues cv) { throwIfSpecified(cv, BlockedNumberContract.BlockedNumbers.COLUMN_ID); - throwIfSpecified(cv, BlockedNumberContract.BlockedNumbers.COLUMN_STRIPPED_NUMBER); final String phoneNumber = cv.getAsString( BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER); @@ -133,14 +135,15 @@ public class BlockedNumberProvider extends ContentProvider { BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER); } - // Sanitize the input and fill in with autogenerated columns. - final String strippedNumber = Utils.stripPhoneNumber(phoneNumber); - final String e164Number = Utils.getE164Number(getContext(), strippedNumber, + // Fill in with autogenerated columns. + final String e164Number = Utils.getE164Number(getContext(), phoneNumber, cv.getAsString(BlockedNumberContract.BlockedNumbers.COLUMN_E164_NUMBER)); - - cv.put(BlockedNumberContract.BlockedNumbers.COLUMN_STRIPPED_NUMBER, strippedNumber); cv.put(BlockedNumberContract.BlockedNumbers.COLUMN_E164_NUMBER, e164Number); + if (DEBUG) { + Log.d(TAG, String.format("inserted blocked number: %s", cv)); + } + // Then insert. final long id = mDbHelper.getWritableDatabase().insertOrThrow( BlockedNumberDatabaseHelper.Tables.BLOCKED_NUMBERS, null, cv); @@ -176,14 +179,19 @@ public class BlockedNumberProvider extends ContentProvider { enforceWritePermission(); final int match = sUriMatcher.match(uri); + int numRows; switch (match) { case BLOCKED_LIST: - return deleteBlockedNumber(selection, selectionArgs); + numRows = deleteBlockedNumber(selection, selectionArgs); + break; case BLOCKED_ID: - return deleteBlockedNumberWithId(ContentUris.parseId(uri), selection); + numRows = deleteBlockedNumberWithId(ContentUris.parseId(uri), selection); + break; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } + getContext().getContentResolver().notifyChange(uri, null); + return numRows; } /** @@ -228,16 +236,22 @@ public class BlockedNumberProvider extends ContentProvider { enforceReadPermission(); final int match = sUriMatcher.match(uri); + Cursor cursor; switch (match) { case BLOCKED_LIST: - return queryBlockedList(projection, selection, selectionArgs, sortOrder, + cursor = queryBlockedList(projection, selection, selectionArgs, sortOrder, cancellationSignal); + break; case BLOCKED_ID: - return queryBlockedListWithId(ContentUris.parseId(uri), projection, selection, + cursor = queryBlockedListWithId(ContentUris.parseId(uri), projection, selection, cancellationSignal); + break; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } + // Tell the cursor what uri to watch, so it knows when its source data changes + cursor.setNotificationUri(getContext().getContentResolver(), uri); + return cursor; } /** @@ -295,38 +309,33 @@ public class BlockedNumberProvider extends ContentProvider { } private boolean isBlocked(String phoneNumber) { - final String inStripped = Utils.stripPhoneNumber(phoneNumber); - if (TextUtils.isEmpty(inStripped)) { + if (TextUtils.isEmpty(phoneNumber)) { return false; } - final String inE164 = Utils.getE164Number(getContext(), inStripped, null); // may be empty. + final String inE164 = Utils.getE164Number(getContext(), phoneNumber, null); // may be empty. if (DEBUG) { - Log.d(TAG, String.format("isBlocked: in=%s, stripped=%s, e164=%s", phoneNumber, - inStripped, inE164)); + Log.d(TAG, String.format("isBlocked: in=%s, e164=%s", phoneNumber, inE164)); } final Cursor c = mDbHelper.getReadableDatabase().rawQuery( "SELECT " + BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER + "," + - BlockedNumberContract.BlockedNumbers.COLUMN_STRIPPED_NUMBER + "," + BlockedNumberContract.BlockedNumbers.COLUMN_E164_NUMBER + " FROM " + BlockedNumberDatabaseHelper.Tables.BLOCKED_NUMBERS + - " WHERE " + BlockedNumberContract.BlockedNumbers.COLUMN_STRIPPED_NUMBER + "=?1" + + " WHERE " + BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER + "=?1" + " OR (?2 != '' AND " + BlockedNumberContract.BlockedNumbers.COLUMN_E164_NUMBER + "=?2)", - new String[] {inStripped, inE164} + new String[] {phoneNumber, inE164} ); try { while (c.moveToNext()) { if (DEBUG) { final String original = c.getString(0); - final String stripped = c.getString(1); - final String e164 = c.getString(2); + final String e164 = c.getString(1); - Log.d(TAG, String.format(" match found: original=%s, stripped=%s, e164=%s", - original, stripped, e164)); + Log.d(TAG, String.format("match found: original=%s, e164=%s", original, e164)); } return true; } @@ -378,6 +387,17 @@ public class BlockedNumberProvider extends ContentProvider { Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED) { return; } + + // TODO: Add an explicit permission instead. + try { + ApplicationInfo applicationInfo = getContext(). + getPackageManager().getPackageInfo(callingPackage, 0).applicationInfo; + if (applicationInfo.isPrivilegedApp() || applicationInfo.isSystemApp()) { + return; + } + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "package not found: " + e); + } } throw new SecurityException("Caller must be system, default dialer or default SMS app"); } diff --git a/src/com/android/providers/blockednumber/Utils.java b/src/com/android/providers/blockednumber/Utils.java index e890634..6aaf178 100644 --- a/src/com/android/providers/blockednumber/Utils.java +++ b/src/com/android/providers/blockednumber/Utils.java @@ -48,23 +48,6 @@ public class Utils { } /** - * Strip formatting characters and the non-phone number portion from a phone number. e.g. - * "+1-408-123-4444;123" to "+14081234444". - * - * <p>Special case: if a number contains '@', it's considered as an email address and returned - * unmodified. - */ - public static @NonNull String stripPhoneNumber(@Nullable String phoneNumber) { - if (TextUtils.isEmpty(phoneNumber)) { - return ""; - } - if (phoneNumber.contains("@")) { - return phoneNumber; - } - return PhoneNumberUtils.extractNetworkPortion(phoneNumber); - } - - /** * Converts a phone number to an E164 number, assuming the current country. If {@code * incomingE16Number} is provided, it'll just strip it and returns. If the number is not valid, * it'll return "". @@ -78,7 +61,7 @@ public class Utils { return rawNumber; } if (!TextUtils.isEmpty(incomingE16Number)) { - return stripPhoneNumber(incomingE16Number); + return incomingE16Number; } if (TextUtils.isEmpty(rawNumber)) { return ""; diff --git a/tests/src/com/android/providers/blockednumber/BlockedNumberProviderTest.java b/tests/src/com/android/providers/blockednumber/BlockedNumberProviderTest.java index fb9a81a..0ceb684 100644 --- a/tests/src/com/android/providers/blockednumber/BlockedNumberProviderTest.java +++ b/tests/src/com/android/providers/blockednumber/BlockedNumberProviderTest.java @@ -19,6 +19,7 @@ import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; +import android.database.ContentObserver; import android.database.Cursor; import android.database.sqlite.SQLiteConstraintException; import android.database.sqlite.SQLiteException; @@ -29,6 +30,9 @@ import android.test.AndroidTestCase; import android.test.MoreAsserts; import junit.framework.Assert; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + /** * m BlockedNumberProviderTest && adb install -r * ${ANDROID_PRODUCT_OUT}/data/app/BlockedNumberProviderTest/BlockedNumberProviderTest.apk && adb @@ -40,7 +44,9 @@ public class BlockedNumberProviderTest extends AndroidTestCase { private MyMockContext mMockContext; private ContentResolver mResolver; - /** Whether the country detector thinks the device is in USA. */ + /** + * Whether the country detector thinks the device is in USA. + */ private boolean mInUSA; @Override @@ -66,7 +72,7 @@ public class BlockedNumberProviderTest extends AndroidTestCase { final ContentValues ret = new ContentValues(); for (int i = 1; i < namesAndValues.length; i += 2) { final String name = namesAndValues[i - 1].toString(); - final Object value = namesAndValues[i]; + final Object value = namesAndValues[i]; if (value == null) { ret.putNull(name); } else if (value instanceof String) { @@ -104,7 +110,6 @@ public class BlockedNumberProviderTest extends AndroidTestCase { insertExpectingFailure(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, null)); insertExpectingFailure(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "")); insertExpectingFailure(cv(BlockedNumbers.COLUMN_ID, 1)); - insertExpectingFailure(cv(BlockedNumbers.COLUMN_STRIPPED_NUMBER, 1)); insertExpectingFailure(cv(BlockedNumbers.COLUMN_E164_NUMBER, "1")); insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123")); @@ -128,6 +133,30 @@ public class BlockedNumberProviderTest extends AndroidTestCase { // TODO Check the table content. } + public void testChangesNotified() throws Exception { + Cursor c = mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null); + + final CountDownLatch latch = new CountDownLatch(2); + ContentObserver contentObserver = new ContentObserver(null) { + @Override + public void onChange(boolean selfChange) { + Assert.assertFalse(selfChange); + latch.notify(); + } + }; + c.registerContentObserver(contentObserver); + + try { + Uri uri = insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "14506507000")); + mResolver.delete(uri, null, null); + latch.await(10, TimeUnit.SECONDS); + } catch (Exception e) { + fail(e.toString()); + } finally { + c.unregisterContentObserver(contentObserver); + } + } + private Uri insert(ContentValues cv) { final Uri uri = mResolver.insert(BlockedNumbers.CONTENT_URI, cv); assertNotNull(uri); @@ -210,16 +239,19 @@ public class BlockedNumberProviderTest extends AndroidTestCase { insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-500-454-2222")); insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "045-111-2222", - BlockedNumbers.COLUMN_E164_NUMBER, "+81-45-111-2222")); + BlockedNumbers.COLUMN_E164_NUMBER, "+81451112222")); insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "abc.def@gmail.com")); // Check + assertIsBlocked(false, ""); + assertIsBlocked(false, null); assertIsBlocked(true, "123"); assertIsBlocked(false, "1234"); assertIsBlocked(true, "+81451112222"); assertIsBlocked(true, "+81 45 111 2222"); - assertIsBlocked(true, "045 111 2222"); + assertIsBlocked(true, "045-111-2222"); + assertIsBlocked(false, "045 111 2222"); if (mInUSA) { // Probably won't work outside of the +1 region. |