diff options
10 files changed, 396 insertions, 133 deletions
diff --git a/src/com/android/providers/contacts/CallLogProvider.java b/src/com/android/providers/contacts/CallLogProvider.java index c42c810..e45c1c2 100644 --- a/src/com/android/providers/contacts/CallLogProvider.java +++ b/src/com/android/providers/contacts/CallLogProvider.java @@ -177,7 +177,7 @@ public class CallLogProvider extends ContentProvider { SQLiteDatabase db = mDbHelper.getWritableDatabase(); mCallsInserter = new DatabaseUtils.InsertHelper(db, Tables.CALLS); } - long rowId = mCallsInserter.insert(values); + long rowId = getDatabaseModifier(mCallsInserter).insert(values); if (rowId > 0) { notifyChange(); return ContentUris.withAppendedId(uri, rowId); @@ -211,7 +211,8 @@ public class CallLogProvider extends ContentProvider { throw new UnsupportedOperationException("Cannot update URL: " + uri); } - int count = db.update(Tables.CALLS, values, selectionBuilder.build(), selectionArgs); + int count = getDatabaseModifier(db).update(Tables.CALLS, values, + selectionBuilder.build(), selectionArgs); if (count > 0) { notifyChange(); } @@ -227,7 +228,8 @@ public class CallLogProvider extends ContentProvider { final int matchedUriId = sURIMatcher.match(uri); switch (matchedUriId) { case CALLS: - int count = db.delete(Tables.CALLS, selectionBuilder.build(), selectionArgs); + int count = getDatabaseModifier(db).delete(Tables.CALLS, + selectionBuilder.build(), selectionArgs); if (count > 0) { notifyChange(); } @@ -247,6 +249,20 @@ public class CallLogProvider extends ContentProvider { return mCountryMonitor.getCountryIso(); } + // Work around to let the test code override the context. getContext() is final so cannot be + // overridden. + protected Context context() { + return getContext(); + } + + private DatabaseModifier getDatabaseModifier(SQLiteDatabase db) { + return new DbModifierWithVmNotification(Tables.CALLS, db, context()); + } + + private DatabaseModifier getDatabaseModifier(DatabaseUtils.InsertHelper insertHelper) { + return new DbModifierWithVmNotification(Tables.CALLS, insertHelper, context()); + } + private boolean hasVoicemailValue(ContentValues values) { return values.containsKey(Calls.TYPE) && values.getAsInteger(Calls.TYPE).equals(Calls.VOICEMAIL_TYPE); diff --git a/src/com/android/providers/contacts/DatabaseModifier.java b/src/com/android/providers/contacts/DatabaseModifier.java new file mode 100644 index 0000000..3f5a402 --- /dev/null +++ b/src/com/android/providers/contacts/DatabaseModifier.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 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.providers.contacts; + +import android.content.ContentValues; +import android.database.DatabaseUtils; +import android.database.sqlite.SQLiteDatabase; + +/** + * An interface which wraps key database modify operations (insert, update, delete) to perform + * additional tasks before or after the database modification operation. A typical use case is to + * generate notification when a database is modified. + */ +public interface DatabaseModifier { + /** + * Use this method to insert a value which you would otherwise do using the + * {@link SQLiteDatabase#insert(String, String, ContentValues)} method. + */ + public abstract long insert(String table, String nullColumnHack, ContentValues values); + /** + * Use this method to insert a value which you would otherwise do using the + * {@link DatabaseUtils.InsertHelper#insert(ContentValues)} method. + */ + public abstract long insert(ContentValues values); + /** + * Use this method to update a table which you would otherwise do using the + * {@link SQLiteDatabase#update(String, ContentValues, String, String[])} method. + */ + public abstract int update(String table, ContentValues values, + String whereClause, String[] whereArgs); + /** + * Use this method to delete entries from a table which you would otherwise do using the + * {@link SQLiteDatabase#delete(String, String, String[])} method. + */ + public abstract int delete(String table, String whereClause, String[] whereArgs); +} diff --git a/src/com/android/providers/contacts/DbModifierWithVmNotification.java b/src/com/android/providers/contacts/DbModifierWithVmNotification.java new file mode 100644 index 0000000..b71819e --- /dev/null +++ b/src/com/android/providers/contacts/DbModifierWithVmNotification.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2011 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.providers.contacts; + +import static android.Manifest.permission.READ_WRITE_OWN_VOICEMAIL; +import static com.android.providers.contacts.Manifest.permission.READ_WRITE_ALL_VOICEMAIL; + +import com.android.providers.contacts.ContactsDatabaseHelper.Tables; +import com.android.providers.contacts.util.DbQueryUtils; +import com.google.android.collect.Lists; + +import android.content.ComponentName; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ResolveInfo; +import android.database.Cursor; +import android.database.DatabaseUtils.InsertHelper; +import android.database.sqlite.SQLiteDatabase; +import android.net.Uri; +import android.os.Binder; +import android.provider.VoicemailContract; +import android.provider.VoicemailContract.Status; +import android.provider.VoicemailContract.Voicemails; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * An implementation of {@link DatabaseModifier} for voicemail related tables which additionally + * generates necessary notifications after the modification operation is performed. + */ +public class DbModifierWithVmNotification implements DatabaseModifier { + private static final String TAG = "DbModifierWithVmNotification"; + + private static final String[] PROJECTION = new String[] { + VoicemailContract.SOURCE_PACKAGE_FIELD + }; + private static final int SOURCE_PACKAGE_COLUMN_INDEX = 0; + private static final String NON_NULL_SOURCE_PACKAGE_SELECTION = + VoicemailContract.SOURCE_PACKAGE_FIELD + " IS NOT NULL"; + + private final String mTableName; + private final SQLiteDatabase mDb; + private final InsertHelper mInsertHelper; + private final Context mContext; + private final Uri mBaseUri; + private final boolean mIsVoicemailContentTable; + private final VoicemailPermissions mVoicemailPermissions; + + public DbModifierWithVmNotification(String tableName, SQLiteDatabase db, Context context) { + this(tableName, db, null, context); + } + + public DbModifierWithVmNotification(String tableName, InsertHelper insertHelper, + Context context) { + this(tableName, null, insertHelper, context); + } + + private DbModifierWithVmNotification(String tableName, SQLiteDatabase db, + InsertHelper insertHelper, Context context) { + mTableName = tableName; + mDb = db; + mInsertHelper = insertHelper; + mContext = context; + mBaseUri = mTableName.equals(Tables.VOICEMAIL_STATUS) ? + Status.CONTENT_URI : Voicemails.CONTENT_URI; + mIsVoicemailContentTable = !mTableName.equals(Tables.VOICEMAIL_STATUS); + mVoicemailPermissions = new VoicemailPermissions(mContext); + } + + @Override + public long insert(String table, String nullColumnHack, ContentValues values) { + Set<String> packagesModified = getModifiedPackages(values); + long rowId = mDb.insert(table, nullColumnHack, values); + if (rowId > 0 && packagesModified.size() != 0) { + notifyOnInsert(ContentUris.withAppendedId(mBaseUri, rowId), packagesModified); + } + return rowId; + } + + @Override + public long insert(ContentValues values) { + Set<String> packagesModified = getModifiedPackages(values); + long rowId = mInsertHelper.insert(values); + if (rowId > 0 && packagesModified.size() != 0) { + notifyOnInsert(ContentUris.withAppendedId(mBaseUri, rowId), packagesModified); + } + return rowId; + } + + private void notifyOnInsert(Uri notificationUri, Set<String> packagesModified) { + if (mIsVoicemailContentTable) { + notifyChange(notificationUri, packagesModified, VoicemailContract.ACTION_NEW_VOICEMAIL, + Intent.ACTION_PROVIDER_CHANGED); + } else { + notifyChange(notificationUri, packagesModified, Intent.ACTION_PROVIDER_CHANGED); + } + } + + @Override + public int update(String table, ContentValues values, String whereClause, String[] whereArgs) { + Set<String> packagesModified = getModifiedPackages(whereClause, whereArgs); + packagesModified.addAll(getModifiedPackages(values)); + int count = mDb.update(table, values, whereClause, whereArgs); + if (count > 0 && packagesModified.size() != 0) { + notifyChange(mBaseUri, packagesModified, Intent.ACTION_PROVIDER_CHANGED); + } + return count; + } + + @Override + public int delete(String table, String whereClause, String[] whereArgs) { + Set<String> packagesModified = getModifiedPackages(whereClause, whereArgs); + int count = mDb.delete(table, whereClause, whereArgs); + if (count > 0 && packagesModified.size() != 0) { + notifyChange(mBaseUri, packagesModified, Intent.ACTION_PROVIDER_CHANGED); + } + return count; + } + + /** + * Returns the set of packages affected when a modify operation is run for the specified + * where clause. When called from an insert operation an empty set returned by this method + * implies (indirectly) that this does not affect any voicemail entry, as a voicemail entry is + * always expected to have the source package field set. + */ + private Set<String> getModifiedPackages(String whereClause, String[] whereArgs) { + Set<String> modifiedPackages = new HashSet<String>(); + Cursor cursor = mDb.query(mTableName, PROJECTION, + DbQueryUtils.concatenateClauses(NON_NULL_SOURCE_PACKAGE_SELECTION, whereClause), + whereArgs, null, null, null); + while(cursor.moveToNext()) { + modifiedPackages.add(cursor.getString(SOURCE_PACKAGE_COLUMN_INDEX)); + } + return modifiedPackages; + } + + /** + * Returns the source package that gets affected (in an insert/update operation) by the supplied + * content values. An empty set returned by this method also implies (indirectly) that this does + * not affect any voicemail entry, as a voicemail entry is always expected to have the source + * package field set. + */ + private Set<String> getModifiedPackages(ContentValues values) { + Set<String> impactedPackages = new HashSet<String>(); + if(values.containsKey(VoicemailContract.SOURCE_PACKAGE_FIELD)) { + impactedPackages.add(values.getAsString(VoicemailContract.SOURCE_PACKAGE_FIELD)); + } + return impactedPackages; + } + + private void notifyChange(Uri notificationUri, Set<String> modifiedPackages, + String... intentActions) { + // Notify the observers. + // Must be done only once, even if there are multiple broadcast intents. + mContext.getContentResolver().notifyChange(notificationUri, null, true); + Collection<String> callingPackages = getCallingPackages(); + // Now fire individual intents. + for (String intentAction : intentActions) { + // self_change extra should be included only for provider_changed events. + boolean includeSelfChangeExtra = intentAction.equals(Intent.ACTION_PROVIDER_CHANGED); + for (ComponentName component : + getBroadcastReceiverComponents(intentAction, notificationUri)) { + Intent intent = new Intent(intentAction, notificationUri); + intent.setComponent(component); + if (includeSelfChangeExtra && callingPackages != null) { + intent.putExtra(VoicemailContract.EXTRA_SELF_CHANGE, + callingPackages.contains(component.getPackageName())); + } + // If this package is not affected by the change then it shall receive the intent + // only if it has READ_WRITE_ALL_VOICEMAIL permissions. + String permissionNeeded = modifiedPackages.contains(component.getPackageName()) ? + READ_WRITE_OWN_VOICEMAIL : READ_WRITE_ALL_VOICEMAIL; + mContext.sendBroadcast(intent, permissionNeeded); + Log.v(TAG, String.format("Sent intent. act:%s, url:%s, comp:%s, perm:%s," + + " self_change:%s", intent.getAction(), intent.getData(), + component.getClassName(), permissionNeeded, + intent.hasExtra(VoicemailContract.EXTRA_SELF_CHANGE) ? + intent.getBooleanExtra(VoicemailContract.EXTRA_SELF_CHANGE, false) : + null)); + } + } + } + + /** Determines the components that can possibly receive the specified intent. */ + private List<ComponentName> getBroadcastReceiverComponents(String intentAction, Uri uri) { + Intent intent = new Intent(intentAction, uri); + List<ComponentName> receiverComponents = new ArrayList<ComponentName>(); + // For broadcast receivers ResolveInfo.activityInfo is the one that is populated. + for (ResolveInfo resolveInfo : + mContext.getPackageManager().queryBroadcastReceivers(intent, 0)) { + ActivityInfo activityInfo = resolveInfo.activityInfo; + receiverComponents.add(new ComponentName(activityInfo.packageName, activityInfo.name)); + } + return receiverComponents; + } + + /** + * Returns the package names of the calling process. If the calling process has more than + * one packages, this returns them all + */ + private Collection<String> getCallingPackages() { + int caller = Binder.getCallingUid(); + if (caller == 0) { + return null; + } + return Lists.newArrayList(mContext.getPackageManager().getPackagesForUid(caller)); + } +} diff --git a/src/com/android/providers/contacts/VoicemailContentProvider.java b/src/com/android/providers/contacts/VoicemailContentProvider.java index cbebb9c..e1f44ca 100644 --- a/src/com/android/providers/contacts/VoicemailContentProvider.java +++ b/src/com/android/providers/contacts/VoicemailContentProvider.java @@ -23,14 +23,9 @@ import com.android.providers.contacts.ContactsDatabaseHelper.Tables; import com.android.providers.contacts.util.SelectionBuilder; import com.android.providers.contacts.util.TypedUriMatcherImpl; -import android.content.ComponentName; import android.content.ContentProvider; -import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.ResolveInfo; import android.database.Cursor; import android.net.Uri; import android.os.Binder; @@ -40,7 +35,6 @@ import android.provider.VoicemailContract; import android.provider.VoicemailContract.Voicemails; import java.io.FileNotFoundException; -import java.util.ArrayList; import java.util.List; /** @@ -53,7 +47,6 @@ public class VoicemailContentProvider extends ContentProvider implements VoicemailTable.DelegateHelper { private static final String TAG = "VoicemailContentProvider"; - private ContentResolver mContentResolver; private VoicemailPermissions mVoicemailPermissions; private VoicemailTable.Delegate mVoicemailContentTable; private VoicemailTable.Delegate mVoicemailStatusTable; @@ -61,7 +54,6 @@ public class VoicemailContentProvider extends ContentProvider @Override public boolean onCreate() { Context context = context(); - mContentResolver = context.getContentResolver(); mVoicemailPermissions = new VoicemailPermissions(context); mVoicemailContentTable = new VoicemailContentTable(Tables.CALLS, context, getDatabaseHelper(context), this); @@ -91,12 +83,6 @@ public class VoicemailContentProvider extends ContentProvider } @Override - public int bulkInsert(Uri uri, ContentValues[] valuesArray) { - UriData uriData = checkPermissionsAndCreateUriData(uri, valuesArray); - return getTableDelegate(uriData).bulkInsert(uriData, valuesArray); - } - - @Override public Uri insert(Uri uri, ContentValues values) { UriData uriData = checkPermissionsAndCreateUriData(uri, values); return getTableDelegate(uriData).insert(uriData, values); @@ -234,35 +220,6 @@ public class VoicemailContentProvider extends ContentProvider @Override // VoicemailTable.DelegateHelper interface. - public void notifyChange(Uri notificationUri, String... intentActions) { - // Notify the observers. - mContentResolver.notifyChange(notificationUri, null, true); - String callingPackage = getCallingPackage(); - // Fire notification intents. - for (String intentAction : intentActions) { - // TODO: We can possibly be more intelligent here and send targeted intents based on - // what voicemail permission the package has. If possible, here is what we would like to - // do for a given broadcast intent - - // 1) Send it to all packages that have READ_WRITE_ALL_VOICEMAIL permission. - // 2) Send it to only the owner package that has just READ_WRITE_OWN_VOICEMAIL, if not - // already sent in (1). - for (ComponentName component : - getBroadcastReceiverComponents(intentAction, notificationUri)) { - Intent intent = new Intent(intentAction, notificationUri); - intent.setComponent(component); - // self_change extra should be included only for provider_changed events. - if (intentAction.equals(Intent.ACTION_PROVIDER_CHANGED)) { - intent.putExtra(VoicemailContract.EXTRA_SELF_CHANGE, - callingPackage.equals(component.getPackageName())); - } - context().sendBroadcast(intent, - android.Manifest.permission.READ_WRITE_OWN_VOICEMAIL); - } - } - } - - @Override - // VoicemailTable.DelegateHelper interface. public void checkAndAddSourcePackageIntoValues(UriData uriData, ContentValues values) { // If content values don't contain the provider, calculate the right provider to use. if (!values.containsKey(SOURCE_PACKAGE_FIELD)) { @@ -406,17 +363,4 @@ public class VoicemailContentProvider extends ContentProvider } return getEqualityClause(Voicemails.SOURCE_PACKAGE, getCallingPackage()); } - - /** Determines the components that can possibly receive the specified intent. */ - protected List<ComponentName> getBroadcastReceiverComponents(String intentAction, Uri uri) { - Intent intent = new Intent(intentAction, uri); - List<ComponentName> receiverComponents = new ArrayList<ComponentName>(); - // For broadcast receivers ResolveInfo.activityInfo is the one that is populated. - for (ResolveInfo resolveInfo : - context().getPackageManager().queryBroadcastReceivers(intent, 0)) { - ActivityInfo activityInfo = resolveInfo.activityInfo; - receiverComponents.add(new ComponentName(activityInfo.packageName, activityInfo.name)); - } - return receiverComponents; - } } diff --git a/src/com/android/providers/contacts/VoicemailContentTable.java b/src/com/android/providers/contacts/VoicemailContentTable.java index 19961c4..b9afbd7 100644 --- a/src/com/android/providers/contacts/VoicemailContentTable.java +++ b/src/com/android/providers/contacts/VoicemailContentTable.java @@ -25,7 +25,6 @@ import com.android.providers.contacts.util.CloseUtils; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; -import android.content.Intent; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; @@ -33,7 +32,6 @@ import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.os.ParcelFileDescriptor; import android.provider.CallLog.Calls; -import android.provider.VoicemailContract; import android.provider.VoicemailContract.Voicemails; import android.util.Log; @@ -81,26 +79,7 @@ public class VoicemailContentTable implements VoicemailTable.Delegate { } @Override - public int bulkInsert(UriData uriData, ContentValues[] valuesArray) { - int numInserted = 0; - for (ContentValues values : valuesArray) { - if (insertInternal(uriData, values, false) != null) { - numInserted++; - } - } - if (numInserted > 0) { - mDelegateHelper.notifyChange(uriData.getUri(), Intent.ACTION_PROVIDER_CHANGED); - } - return numInserted; - } - - @Override public Uri insert(UriData uriData, ContentValues values) { - return insertInternal(uriData, values, true); - } - - private Uri insertInternal(UriData uriData, ContentValues values, - boolean sendProviderChangedNotification) { checkForSupportedColumns(sVoicemailProjectionMap, values); ContentValues copiedValues = new ContentValues(values); checkInsertSupported(uriData); @@ -114,13 +93,9 @@ public class VoicemailContentTable implements VoicemailTable.Delegate { copiedValues.put(Calls.TYPE, Calls.VOICEMAIL_TYPE); SQLiteDatabase db = mDbHelper.getWritableDatabase(); - long rowId = db.insert(mTableName, null, copiedValues); + long rowId = getDatabaseModifier(db).insert(mTableName, null, copiedValues); if (rowId > 0) { Uri newUri = ContentUris.withAppendedId(uriData.getUri(), rowId); - mDelegateHelper.notifyChange(newUri, VoicemailContract.ACTION_NEW_VOICEMAIL); - if (sendProviderChangedNotification) { - mDelegateHelper.notifyChange(newUri, Intent.ACTION_PROVIDER_CHANGED); - } // Populate the 'voicemail_uri' field to be used by the call_log provider. updateVoicemailUri(db, newUri); return newUri; @@ -181,11 +156,8 @@ public class VoicemailContentTable implements VoicemailTable.Delegate { } // Now delete the rows themselves. - int count = db.delete(mTableName, combinedClause, selectionArgs); - if (count > 0) { - mDelegateHelper.notifyChange(uriData.getUri(), Intent.ACTION_PROVIDER_CHANGED); - } - return count; + return getDatabaseModifier(db).delete(mTableName, combinedClause, + selectionArgs); } @Override @@ -216,11 +188,8 @@ public class VoicemailContentTable implements VoicemailTable.Delegate { // URI that include message Id. I think we do want to support bulk update. String combinedClause = concatenateClauses(selection, uriData.getWhereClause(), getCallTypeClause()); - int count = db.update(mTableName, values, combinedClause, selectionArgs); - if (count > 0) { - mDelegateHelper.notifyChange(uriData.getUri(), Intent.ACTION_PROVIDER_CHANGED); - } - return count; + return getDatabaseModifier(db).update(mTableName, values, combinedClause, + selectionArgs); } private void checkUpdateSupported(UriData uriData) { @@ -277,4 +246,8 @@ public class VoicemailContentTable implements VoicemailTable.Delegate { private String getCallTypeClause() { return getEqualityClause(Calls.TYPE, String.valueOf(Calls.VOICEMAIL_TYPE)); } + + private DatabaseModifier getDatabaseModifier(SQLiteDatabase db) { + return new DbModifierWithVmNotification(mTableName, db, mContext); + } } diff --git a/src/com/android/providers/contacts/VoicemailStatusTable.java b/src/com/android/providers/contacts/VoicemailStatusTable.java index 1f1fa8b..504af46 100644 --- a/src/com/android/providers/contacts/VoicemailStatusTable.java +++ b/src/com/android/providers/contacts/VoicemailStatusTable.java @@ -23,7 +23,6 @@ import com.android.providers.contacts.VoicemailContentProvider.UriData; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; -import android.content.Intent; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; @@ -64,10 +63,9 @@ public class VoicemailStatusTable implements VoicemailTable.Delegate { SQLiteDatabase db = mDbHelper.getWritableDatabase(); ContentValues copiedValues = new ContentValues(values); mDelegateHelper.checkAndAddSourcePackageIntoValues(uriData, copiedValues); - long rowId = db.insert(mTableName, null, copiedValues); + long rowId = getDatabaseModifier(db).insert(mTableName, null, copiedValues); if (rowId > 0) { Uri newUri = ContentUris.withAppendedId(uriData.getUri(), rowId); - mDelegateHelper.notifyChange(newUri, Intent.ACTION_PROVIDER_CHANGED); return newUri; } else { return null; @@ -75,19 +73,11 @@ public class VoicemailStatusTable implements VoicemailTable.Delegate { } @Override - public int bulkInsert(UriData uriData, ContentValues[] valuesArray) { - throw new UnsupportedOperationException("bulkInsert is not supported for status table"); - } - - @Override public int delete(UriData uriData, String selection, String[] selectionArgs) { SQLiteDatabase db = mDbHelper.getWritableDatabase(); String combinedClause = concatenateClauses(selection, uriData.getWhereClause()); - int count = db.delete(mTableName, combinedClause, selectionArgs); - if (count > 0) { - mDelegateHelper.notifyChange(uriData.getUri(), Intent.ACTION_PROVIDER_CHANGED); - } - return count; + return getDatabaseModifier(db).delete(mTableName, combinedClause, + selectionArgs); } @Override @@ -112,11 +102,8 @@ public class VoicemailStatusTable implements VoicemailTable.Delegate { String[] selectionArgs) { SQLiteDatabase db = mDbHelper.getWritableDatabase(); String combinedClause = concatenateClauses(selection, uriData.getWhereClause()); - int count = db.update(mTableName, values, combinedClause, selectionArgs); - if (count > 0) { - mDelegateHelper.notifyChange(uriData.getUri(), Intent.ACTION_PROVIDER_CHANGED); - } - return count; + return getDatabaseModifier(db).update(mTableName, values, combinedClause, + selectionArgs); } @Override @@ -132,4 +119,8 @@ public class VoicemailStatusTable implements VoicemailTable.Delegate { public ParcelFileDescriptor openFile(UriData uriData, String mode) { throw new UnsupportedOperationException("File operation is not supported for status table"); } + + private DatabaseModifier getDatabaseModifier(SQLiteDatabase db) { + return new DbModifierWithVmNotification(mTableName, db, mContext); + } } diff --git a/src/com/android/providers/contacts/VoicemailTable.java b/src/com/android/providers/contacts/VoicemailTable.java index cab48fd..5af0cd0 100644 --- a/src/com/android/providers/contacts/VoicemailTable.java +++ b/src/com/android/providers/contacts/VoicemailTable.java @@ -35,7 +35,6 @@ public interface VoicemailTable { */ public interface Delegate { public Uri insert(UriData uriData, ContentValues values); - public int bulkInsert(UriData uriData, ContentValues[] valuesArray); public int delete(UriData uriData, String selection, String[] selectionArgs); public Cursor query(UriData uriData, String[] projection, String selection, String[] selectionArgs, String sortOrder); @@ -52,16 +51,6 @@ public interface VoicemailTable { */ public interface DelegateHelper { /** - * Notifies the content resolver and fires required broadcast intent(s) to notify about the - * change. - * - * @param notificationUri The URI that got impacted due to the change. This is the URI that - * is included in content resolver and broadcast intent notification. - * @param intentActions List of intent actions that needs to be fired. A separate intent is - * fired for each intent action. - */ - public void notifyChange(Uri notificationUri, String... intentActions); - /** * Inserts source_package field into ContentValues. Used in insert operations. */ public void checkAndAddSourcePackageIntoValues(UriData uriData, ContentValues values); diff --git a/tests/src/com/android/providers/contacts/CallLogProviderTest.java b/tests/src/com/android/providers/contacts/CallLogProviderTest.java index 12ca128..29a42dc 100644 --- a/tests/src/com/android/providers/contacts/CallLogProviderTest.java +++ b/tests/src/com/android/providers/contacts/CallLogProviderTest.java @@ -23,6 +23,9 @@ import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; +import android.content.ContextWrapper; +import android.content.Intent; +import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.provider.CallLog; @@ -342,6 +345,21 @@ public class CallLogProviderTest extends BaseContactsProvider2Test { protected String getCurrentCountryIso() { return "us"; } + + @Override + protected Context context() { + return new ContextWrapper(super.context()) { + @Override + public PackageManager getPackageManager() { + return new MockPackageManager("com.test.package1", "com.test.package2"); + } + + @Override + public void sendBroadcast(Intent intent, String receiverPermission) { + // Do nothing for now. + } + }; + } } } diff --git a/tests/src/com/android/providers/contacts/MockPackageManager.java b/tests/src/com/android/providers/contacts/MockPackageManager.java new file mode 100644 index 0000000..db1e79e --- /dev/null +++ b/tests/src/com/android/providers/contacts/MockPackageManager.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 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.providers.contacts; + +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ResolveInfo; + +import java.util.ArrayList; +import java.util.List; + +public class MockPackageManager extends android.test.mock.MockPackageManager { + private final String[] mPackages; + public MockPackageManager(String... packages) { + mPackages = packages; + } + + @Override + public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) { + List<ResolveInfo> resolveInfos = new ArrayList<ResolveInfo>(); + for (String pkg : mPackages) { + resolveInfos.add(createResolveInfo(pkg)); + } + return resolveInfos; + } + + private ResolveInfo createResolveInfo(String packageName) { + ActivityInfo activityInfo = new ActivityInfo(); + activityInfo.packageName = packageName; + activityInfo.name = "FooClass"; + ResolveInfo resolveInfo = new ResolveInfo(); + resolveInfo.activityInfo = activityInfo; + return resolveInfo; + } + + @Override + public String[] getPackagesForUid(int uid) { + return new String[] {mPackages[0]}; + } +} diff --git a/tests/src/com/android/providers/contacts/VoicemailProviderTest.java b/tests/src/com/android/providers/contacts/VoicemailProviderTest.java index baee751..e214f60 100644 --- a/tests/src/com/android/providers/contacts/VoicemailProviderTest.java +++ b/tests/src/com/android/providers/contacts/VoicemailProviderTest.java @@ -16,13 +16,13 @@ package com.android.providers.contacts; -import android.content.ComponentName; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; +import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.provider.CallLog.Calls; @@ -539,6 +539,10 @@ public class VoicemailProviderTest extends BaseContactsProvider2Test { public void sendBroadcast(Intent intent, String receiverPermission) { mDelgate.sendOrderedBroadcast(intent, receiverPermission); } + @Override + public PackageManager getPackageManager() { + return new MockPackageManager("com.test.package1", "com.test.package2"); + } }; } @@ -546,14 +550,6 @@ public class VoicemailProviderTest extends BaseContactsProvider2Test { protected String getCallingPackage() { return getContext().getPackageName(); } - - @Override - protected List<ComponentName> getBroadcastReceiverComponents(String intentAction, Uri uri) { - List<ComponentName> broadcastReceiverComponents = new ArrayList<ComponentName>(); - broadcastReceiverComponents.add(new ComponentName( - getContext().getPackageName(), "TestReceiverClass")); - return broadcastReceiverComponents; - } } /** Lazily construct the test directory when required. */ |