Merge "Import translations. DO NOT MERGE" into oc-mr1-dev am: c169459bbd -s ours
am: 2e1f39300b -s ours
Change-Id: Ib5fad4c1470233853e59b535d6761a0538d57cbb
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index dc803da..49646f3 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -19,7 +19,7 @@
<string name="sharedUserLabel" msgid="8024311725474286801">"Android কোর অ্যাপ্লিকেশানগুলি"</string>
<string name="app_label" msgid="3389954322874982620">"পরিচিতিগুলির সংগ্রহস্থল"</string>
<string name="provider_label" msgid="6012150850819899907">"পরিচিতিগুলি"</string>
- <string name="upgrade_out_of_memory_notification_ticker" msgid="7638747231223520477">"পরিচিতিগুলি আপগ্রেড করার জন্য আরো সঞ্চয়স্থানের দরকার৷"</string>
+ <string name="upgrade_out_of_memory_notification_ticker" msgid="7638747231223520477">"পরিচিতিগুলি আপগ্রেড করার জন্য আরও সঞ্চয়স্থানের দরকার৷"</string>
<string name="upgrade_out_of_memory_notification_title" msgid="8888171924684998531">"পরিচিতিগুলির জন্য সঞ্চয়স্থান আপগ্রেড করা হচ্ছে"</string>
<string name="upgrade_out_of_memory_notification_text" msgid="2581831842693151968">"আপগ্রেড সম্পূর্ণ করতে আলতো চাপ দিন৷"</string>
<string name="default_directory" msgid="93961630309570294">"পরিচিতিগুলি"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 37bc150..e1fae51 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -26,7 +26,7 @@
<string name="local_invisible_directory" msgid="705244318477396120">"Ostalo"</string>
<string name="voicemail_from_column" msgid="435732568832121444">"Govorna pošta od "</string>
<string name="debug_dump_title" msgid="4916885724165570279">"Kopiraj bazu podataka kontakata"</string>
- <string name="debug_dump_database_message" msgid="406438635002392290">"Upravo ćete 1) napraviti kopiju svoje baze podataka koja sadrži sve informacije o kontaktima i sve popise poziva u unutrašnjoj pohrani i 2) poslati tu kopiju e-poštom. Ne zaboravite izbrisati kopiju čim je uspješno kopirate s uređaja ili čim primite poruku e-pošte."</string>
+ <string name="debug_dump_database_message" msgid="406438635002392290">"Upravo ćete 1) napraviti kopiju svoje baze podataka koja sadrži sve informacije o kontaktima i sve popise poziva u unutrašnjoj pohrani i 2) poslati tu kopiju e-poštom. Ne zaboravite izbrisati kopiju čim je uspješno kopirate s uređaja ili čim primite e-poruku."</string>
<string name="debug_dump_delete_button" msgid="7832879421132026435">"Izbriši sada"</string>
<string name="debug_dump_start_button" msgid="2837506913757600001">"Započni"</string>
<string name="debug_dump_email_sender_picker" msgid="3534420908672176460">"Odaberite program za slanje fajla"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..c62b699
--- /dev/null
+++ b/res/values-en-rCA/strings.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="sharedUserLabel" msgid="8024311725474286801">"Android Core Apps"</string>
+ <string name="app_label" msgid="3389954322874982620">"Contacts Storage"</string>
+ <string name="provider_label" msgid="6012150850819899907">"Contacts"</string>
+ <string name="upgrade_out_of_memory_notification_ticker" msgid="7638747231223520477">"Contact upgrade needs more memory."</string>
+ <string name="upgrade_out_of_memory_notification_title" msgid="8888171924684998531">"Upgrading storage for contacts"</string>
+ <string name="upgrade_out_of_memory_notification_text" msgid="2581831842693151968">"Tap to complete the upgrade."</string>
+ <string name="default_directory" msgid="93961630309570294">"Contacts"</string>
+ <string name="local_invisible_directory" msgid="705244318477396120">"Other"</string>
+ <string name="voicemail_from_column" msgid="435732568832121444">"Voicemail from "</string>
+ <string name="debug_dump_title" msgid="4916885724165570279">"Copy contacts database"</string>
+ <string name="debug_dump_database_message" msgid="406438635002392290">"You are about to 1) make a copy of your database which includes all contacts related information and all call log to the internal storage, and 2) email it. Remember to delete the copy as soon as you have successfully copied it off the device or the email is received."</string>
+ <string name="debug_dump_delete_button" msgid="7832879421132026435">"Delete now"</string>
+ <string name="debug_dump_start_button" msgid="2837506913757600001">"Start"</string>
+ <string name="debug_dump_email_sender_picker" msgid="3534420908672176460">"Choose a programme to send your file"</string>
+ <string name="debug_dump_email_subject" msgid="108188398416385976">"Contacts Db attached"</string>
+ <string name="debug_dump_email_body" msgid="4577749800871444318">"Attached is my contacts database with all my contacts information. Handle with care."</string>
+</resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..b7681dd
--- /dev/null
+++ b/res/values-en-rXC/strings.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="sharedUserLabel" msgid="8024311725474286801">"Android Core Apps"</string>
+ <string name="app_label" msgid="3389954322874982620">"Contacts Storage"</string>
+ <string name="provider_label" msgid="6012150850819899907">"Contacts"</string>
+ <string name="upgrade_out_of_memory_notification_ticker" msgid="7638747231223520477">"Contacts upgrade needs more memory."</string>
+ <string name="upgrade_out_of_memory_notification_title" msgid="8888171924684998531">"Upgrading storage for contacts"</string>
+ <string name="upgrade_out_of_memory_notification_text" msgid="2581831842693151968">"Tap to complete the upgrade."</string>
+ <string name="default_directory" msgid="93961630309570294">"Contacts"</string>
+ <string name="local_invisible_directory" msgid="705244318477396120">"Other"</string>
+ <string name="voicemail_from_column" msgid="435732568832121444">"Voicemail from "</string>
+ <string name="debug_dump_title" msgid="4916885724165570279">"Copy contacts database"</string>
+ <string name="debug_dump_database_message" msgid="406438635002392290">"You are about to 1) make a copy of your database which includes all contacts related information and all call log to the internal storage, and 2) email it. Remember to delete the copy as soon as you have successfully copied it off the device or the email is received."</string>
+ <string name="debug_dump_delete_button" msgid="7832879421132026435">"Delete now"</string>
+ <string name="debug_dump_start_button" msgid="2837506913757600001">"Start"</string>
+ <string name="debug_dump_email_sender_picker" msgid="3534420908672176460">"Choose a program to send your file"</string>
+ <string name="debug_dump_email_subject" msgid="108188398416385976">"Contacts Db attached"</string>
+ <string name="debug_dump_email_body" msgid="4577749800871444318">"Attached is my contacts database with all my contacts information. Handle with care."</string>
+</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 5fa4021..a9b2025 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -25,8 +25,8 @@
<string name="default_directory" msgid="93961630309570294">"संपर्क"</string>
<string name="local_invisible_directory" msgid="705244318477396120">"अन्य"</string>
<string name="voicemail_from_column" msgid="435732568832121444">"इनका ध्वनिमेल: "</string>
- <string name="debug_dump_title" msgid="4916885724165570279">"संपर्क डेटाबेस की प्रतिलिपि बनाएं"</string>
- <string name="debug_dump_database_message" msgid="406438635002392290">"आप 1) मोबाइल मेमोरी में अपने उस डेटाबेस की प्रतिलिपि बनाने वाले हैं जिसमें सभी संपर्कों संबंधी जानकारी और सभी कॉल लॉग शामिल हैं, और 2) उसे ईमेल करने वाले हैं. जैसे ही आप डिवाइस से इसकी प्रतिलिपि सफलतापूर्वक बना लें या ईमेल प्राप्त हो जाए तो प्रतिलिपि को हटाना न भूलें."</string>
+ <string name="debug_dump_title" msgid="4916885724165570279">"संपर्क डेटाबेस की कॉपी बनाएं"</string>
+ <string name="debug_dump_database_message" msgid="406438635002392290">"आप 1) मोबाइल मेमोरी में अपने उस डेटाबेस की कॉपी बनाने वाले हैं जिसमें सभी संपर्कों संबंधी जानकारी और सभी कॉल लॉग शामिल हैं, और 2) उसे ईमेल करने वाले हैं. जैसे ही आप डिवाइस से इसकी कॉपी सफलतापूर्वक बना लें या ईमेल प्राप्त हो जाए तो कॉपी को हटाना न भूलें."</string>
<string name="debug_dump_delete_button" msgid="7832879421132026435">"अभी हटाएं"</string>
<string name="debug_dump_start_button" msgid="2837506913757600001">"प्रारंभ करें"</string>
<string name="debug_dump_email_sender_picker" msgid="3534420908672176460">"अपनी फ़ाइल भेजने के लिए कोई प्रोग्राम चुनें"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 7e6d605..a4f324e 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -20,7 +20,7 @@
<string name="app_label" msgid="3389954322874982620">"संपर्क संचयन"</string>
<string name="provider_label" msgid="6012150850819899907">"संपर्क"</string>
<string name="upgrade_out_of_memory_notification_ticker" msgid="7638747231223520477">"संपर्क श्रेणीसुधारित करण्यास अधिक मेमरी आवश्यक आहे."</string>
- <string name="upgrade_out_of_memory_notification_title" msgid="8888171924684998531">"संपर्कांसाठी संचयन श्रेणीसुधारित करीत आहे"</string>
+ <string name="upgrade_out_of_memory_notification_title" msgid="8888171924684998531">"संपर्कांसाठी संचयन श्रेणीसुधारित करत आहे"</string>
<string name="upgrade_out_of_memory_notification_text" msgid="2581831842693151968">"श्रेणीसुधारणा पूर्ण करण्यासाठी टॅप करा."</string>
<string name="default_directory" msgid="93961630309570294">"संपर्क"</string>
<string name="local_invisible_directory" msgid="705244318477396120">"इतर"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 920511a..92bd391 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -21,7 +21,7 @@
<string name="provider_label" msgid="6012150850819899907">"Anwani"</string>
<string name="upgrade_out_of_memory_notification_ticker" msgid="7638747231223520477">"Kupandishwa gredi kwa anwani kunahitaji kumbukumbu zaidi."</string>
<string name="upgrade_out_of_memory_notification_title" msgid="8888171924684998531">"Inapandisha gredi hifadhi ya anwani"</string>
- <string name="upgrade_out_of_memory_notification_text" msgid="2581831842693151968">"Gonga ili ukamilishe kusasisha anwani."</string>
+ <string name="upgrade_out_of_memory_notification_text" msgid="2581831842693151968">"Gusa ili ukamilishe kusasisha anwani."</string>
<string name="default_directory" msgid="93961630309570294">"Anwani"</string>
<string name="local_invisible_directory" msgid="705244318477396120">"Nyingineyo"</string>
<string name="voicemail_from_column" msgid="435732568832121444">"Barua ya sauti kutoka "</string>
diff --git a/src/com/android/providers/contacts/CallLogProvider.java b/src/com/android/providers/contacts/CallLogProvider.java
index 59e9b14..76e207a 100644
--- a/src/com/android/providers/contacts/CallLogProvider.java
+++ b/src/com/android/providers/contacts/CallLogProvider.java
@@ -383,7 +383,7 @@
// Add the computed fields to the copied values.
mCallLogInsertionHelper.addComputedValues(copiedValues);
- long rowId = getDatabaseModifier(mCallsInserter).insert(copiedValues);
+ long rowId = createDatabaseModifier(mCallsInserter).insert(copiedValues);
if (rowId > 0) {
return ContentUris.withAppendedId(uri, rowId);
}
@@ -423,7 +423,7 @@
throw new UnsupportedOperationException("Cannot update URL: " + uri);
}
- return getDatabaseModifier(db).update(uri, Tables.CALLS, values, selectionBuilder.build(),
+ return createDatabaseModifier(db).update(uri, Tables.CALLS, values, selectionBuilder.build(),
selectionArgs);
}
@@ -445,7 +445,7 @@
case CALLS:
// TODO: Special case - We may want to forward the delete request on user 0 to the
// shadow provider too.
- return getDatabaseModifier(db).delete(Tables.CALLS,
+ return createDatabaseModifier(db).delete(Tables.CALLS,
selectionBuilder.build(), selectionArgs);
default:
throw new UnsupportedOperationException("Cannot delete that URL: " + uri);
@@ -460,15 +460,15 @@
* Returns a {@link DatabaseModifier} that takes care of sending necessary notifications
* after the operation is performed.
*/
- private DatabaseModifier getDatabaseModifier(SQLiteDatabase db) {
+ private DatabaseModifier createDatabaseModifier(SQLiteDatabase db) {
return new DbModifierWithNotification(Tables.CALLS, db, getContext());
}
/**
- * Same as {@link #getDatabaseModifier(SQLiteDatabase)} but used for insert helper operations
+ * Same as {@link #createDatabaseModifier(SQLiteDatabase)} but used for insert helper operations
* only.
*/
- private DatabaseModifier getDatabaseModifier(DatabaseUtils.InsertHelper insertHelper) {
+ private DatabaseModifier createDatabaseModifier(DatabaseUtils.InsertHelper insertHelper) {
return new DbModifierWithNotification(Tables.CALLS, insertHelper, getContext());
}
diff --git a/src/com/android/providers/contacts/ContactsDatabaseHelper.java b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
index 76fe173..9414ece 100644
--- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@ -136,9 +136,10 @@
* 1000-1099 M
* 1100-1199 N
* 1200-1299 O
+ * 1300-1399 P
* </pre>
*/
- static final int DATABASE_VERSION = 1202;
+ static final int DATABASE_VERSION = 1300;
private static final int MINIMUM_SUPPORTED_VERSION = 700;
@VisibleForTesting
@@ -1440,7 +1441,9 @@
Data.SYNC2 + " TEXT, " +
Data.SYNC3 + " TEXT, " +
Data.SYNC4 + " TEXT, " +
- Data.CARRIER_PRESENCE + " INTEGER NOT NULL DEFAULT 0 " +
+ Data.CARRIER_PRESENCE + " INTEGER NOT NULL DEFAULT 0, " +
+ Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME + " TEXT, " +
+ Data.PREFERRED_PHONE_ACCOUNT_ID + " TEXT " +
");");
db.execSQL("CREATE INDEX data_raw_contact_id ON " + Tables.DATA + " (" +
@@ -1924,6 +1927,8 @@
+ Data.DATA14 + ", "
+ Data.DATA15 + ", "
+ Data.CARRIER_PRESENCE + ", "
+ + Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME + ", "
+ + Data.PREFERRED_PHONE_ACCOUNT_ID + ", "
+ Data.SYNC1 + ", "
+ Data.SYNC2 + ", "
+ Data.SYNC3 + ", "
@@ -2666,6 +2671,12 @@
oldVersion = 1202;
}
+ if (isUpgradeRequired(oldVersion,newVersion, 1300)) {
+ upgradeToVersion1300(db);
+ upgradeViewsAndTriggers = true;
+ oldVersion = 1300;
+ }
+
// We extracted "calls" and "voicemail_status" at this point, but we can't remove them here
// yet, until CallLogDatabaseHelper moves the data.
@@ -3438,6 +3449,15 @@
+ "last_time_used = 0");
}
+ public void upgradeToVersion1300(SQLiteDatabase db) {
+ try {
+ db.execSQL("ALTER TABLE data ADD preferred_phone_account_component_name "
+ + "TEXT;");
+ db.execSQL("ALTER TABLE data ADD preferred_phone_account_id TEXT;");
+ } catch (SQLiteException ignore) {
+ }
+ }
+
/**
* This method is only used in upgradeToVersion1101 method, and should not be used in other
* places now. Because data15 is not used to generate hash_id for photo, and the new generating
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index a5af51f..1d5681a 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -754,6 +754,8 @@
.add(Data.DATA14)
.add(Data.DATA15)
.add(Data.CARRIER_PRESENCE)
+ .add(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME)
+ .add(Data.PREFERRED_PHONE_ACCOUNT_ID)
.add(Data.DATA_VERSION)
.add(Data.IS_PRIMARY)
.add(Data.IS_SUPER_PRIMARY)
@@ -4649,6 +4651,9 @@
if (flagExists(values, RawContacts.STARRED)) {
if (!callerIsSyncAdapter) {
updateFavoritesMembership(rawContactId, flagIsSet(values, RawContacts.STARRED));
+ mTransactionContext.get().markRawContactDirtyAndChanged(
+ rawContactId, callerIsSyncAdapter);
+ mSyncToNetwork |= !callerIsSyncAdapter;
}
aggregator.updateStarred(rawContactId);
aggregator.updatePinned(rawContactId);
@@ -4662,6 +4667,9 @@
SELECTION_STARRED_FROM_RAW_CONTACTS,
new String[] {Long.toString(rawContactId)});
updateFavoritesMembership(rawContactId, starred);
+ mTransactionContext.get().markRawContactDirtyAndChanged(
+ rawContactId, callerIsSyncAdapter);
+ mSyncToNetwork |= !callerIsSyncAdapter;
}
}
if (flagExists(values, RawContacts.SEND_TO_VOICEMAIL)) {
@@ -4832,6 +4840,7 @@
if (hasStarredValue) {
updateFavoritesMembership(rawContactId,
flagIsSet(values, RawContacts.STARRED));
+ mSyncToNetwork |= !callerIsSyncAdapter;
}
if (hasStarredValue || hasPinnedValue || hasVoiceMailValue) {
diff --git a/src/com/android/providers/contacts/DatabaseModifier.java b/src/com/android/providers/contacts/DatabaseModifier.java
index b11605b..60f9c7f 100644
--- a/src/com/android/providers/contacts/DatabaseModifier.java
+++ b/src/com/android/providers/contacts/DatabaseModifier.java
@@ -49,4 +49,10 @@
* {@link SQLiteDatabase#delete(String, String, String[])} method.
*/
public abstract int delete(String table, String whereClause, String[] whereArgs);
+
+ void startBulkOperation();
+
+ void yieldBulkOperation();
+
+ void finishBulkOperation();
}
diff --git a/src/com/android/providers/contacts/DbModifierWithNotification.java b/src/com/android/providers/contacts/DbModifierWithNotification.java
index 7e7b3e1..0babe1b 100644
--- a/src/com/android/providers/contacts/DbModifierWithNotification.java
+++ b/src/com/android/providers/contacts/DbModifierWithNotification.java
@@ -17,7 +17,6 @@
package com.android.providers.contacts;
-import static android.Manifest.permission.ADD_VOICEMAIL;
import static android.Manifest.permission.READ_VOICEMAIL;
import android.content.ComponentName;
@@ -25,8 +24,6 @@
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;
@@ -37,17 +34,15 @@
import android.provider.VoicemailContract.Status;
import android.provider.VoicemailContract.Voicemails;
import android.util.ArraySet;
-import android.util.Log;
import com.android.common.io.MoreCloseables;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.providers.contacts.CallLogDatabaseHelper.Tables;
import com.android.providers.contacts.util.DbQueryUtils;
import com.google.android.collect.Lists;
import com.google.common.collect.Iterables;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
import java.util.Set;
/**
@@ -57,6 +52,7 @@
* of then got affected by the change.
*/
public class DbModifierWithNotification implements DatabaseModifier {
+
private static final String TAG = "DbModifierWithNotify";
private static final String[] PROJECTION = new String[] {
@@ -73,8 +69,11 @@
private final Context mContext;
private final Uri mBaseUri;
private final boolean mIsCallsTable;
- private final VoicemailPermissions mVoicemailPermissions;
+ private final VoicemailNotifier mVoicemailNotifier;
+ private boolean mIsBulkOperation = false;
+
+ private static VoicemailNotifier sVoicemailNotifierForTest;
public DbModifierWithNotification(String tableName, SQLiteDatabase db, Context context) {
this(tableName, db, null, context);
@@ -94,7 +93,8 @@
mBaseUri = mTableName.equals(Tables.VOICEMAIL_STATUS) ?
Status.CONTENT_URI : Voicemails.CONTENT_URI;
mIsCallsTable = mTableName.equals(Tables.CALLS);
- mVoicemailPermissions = new VoicemailPermissions(mContext);
+ mVoicemailNotifier = sVoicemailNotifierForTest != null ? sVoicemailNotifierForTest
+ : new VoicemailNotifier(mContext, mBaseUri);
}
@Override
@@ -143,13 +143,21 @@
}
}
- private void notifyVoicemailChangeOnInsert(Uri notificationUri, Set<String> packagesModified) {
+ private void notifyVoicemailChangeOnInsert(
+ Uri notificationUri, Set<String> packagesModified) {
if (mIsCallsTable) {
- notifyVoicemailChange(notificationUri, packagesModified,
- VoicemailContract.ACTION_NEW_VOICEMAIL, Intent.ACTION_PROVIDER_CHANGED);
- } else {
- notifyVoicemailChange(notificationUri, packagesModified,
- Intent.ACTION_PROVIDER_CHANGED);
+ mVoicemailNotifier.addIntentActions(VoicemailContract.ACTION_NEW_VOICEMAIL);
+ }
+ notifyVoicemailChange(notificationUri, packagesModified);
+ }
+
+ private void notifyVoicemailChange(Uri notificationUri,
+ Set<String> modifiedPackages) {
+ mVoicemailNotifier.addUri(notificationUri);
+ mVoicemailNotifier.addModifiedPackages(modifiedPackages);
+ mVoicemailNotifier.addIntentActions(Intent.ACTION_PROVIDER_CHANGED);
+ if (!mIsBulkOperation) {
+ mVoicemailNotifier.sendNotification();
}
}
@@ -170,34 +178,27 @@
updateLastModified(table, whereClause, whereArgs);
}
if (isVoicemail) {
- // If a calling package is modifying its own entries, it means that the change came
- // from the server and thus is synced or "clean". Otherwise, it means that a local
- // change is being made to the database, so the entries should be marked as "dirty"
- // so that the corresponding sync adapter knows they need to be synced.
- int isDirty;
- Integer callerSetDirty = values.getAsInteger(Voicemails.DIRTY);
- if (callerSetDirty != null) {
- // Respect the calling package if it sets the dirty flag
- isDirty = callerSetDirty == 0 ? 0 : 1;
- } else {
- isDirty = isSelfModifyingOrInternal(packagesModified) ? 0 : 1;
- }
- values.put(VoicemailContract.Voicemails.DIRTY, isDirty);
-
- if (isDirty == 0 && values.containsKey(Calls.IS_READ) && getAsBoolean(values,
- Calls.IS_READ)) {
- // If the server has set the IS_READ, it should also unset the new flag
- if (!values.containsKey(Calls.NEW)) {
- values.put(Calls.NEW, 0);
- hasMarkedRead = true;
+ if (updateDirtyFlag(values, packagesModified)) {
+ if (values.containsKey(Calls.IS_READ)
+ && getAsBoolean(values,
+ Calls.IS_READ)) {
+ // If the server has set the IS_READ, it should also unset the new flag
+ if (!values.containsKey(Calls.NEW)) {
+ values.put(Calls.NEW, 0);
+ hasMarkedRead = true;
+ }
}
}
+ // updateDirtyFlag might remove the value and leave values empty.
+ if(values.isEmpty()){
+ return 0;
+ }
}
}
int count = mDb.update(table, values, whereClause, whereArgs);
if (count > 0 && isVoicemail) {
- notifyVoicemailChange(mBaseUri, packagesModified, Intent.ACTION_PROVIDER_CHANGED);
+ notifyVoicemailChange(mBaseUri, packagesModified);
}
if (count > 0 && mIsCallsTable) {
notifyCallLogChange();
@@ -213,6 +214,29 @@
return count;
}
+ private boolean updateDirtyFlag(ContentValues values, Set<String> packagesModified) {
+ // If a calling package is modifying its own entries, it means that the change came
+ // from the server and thus is synced or "clean". Otherwise, it means that a local
+ // change is being made to the database, so the entries should be marked as "dirty"
+ // so that the corresponding sync adapter knows they need to be synced.
+ int isDirty;
+ Integer callerSetDirty = values.getAsInteger(Voicemails.DIRTY);
+ if (callerSetDirty != null) {
+ // Respect the calling package if it sets the dirty flag
+ if (callerSetDirty == Voicemails.DIRTY_RETAIN) {
+ values.remove(Voicemails.DIRTY);
+ return false;
+ } else {
+ isDirty = callerSetDirty == 0 ? 0 : 1;
+ }
+ } else {
+ isDirty = isSelfModifyingOrInternal(packagesModified) ? 0 : 1;
+ }
+
+ values.put(Voicemails.DIRTY, isDirty);
+ return isDirty == 0;
+ }
+
private void updateLastModified(String table, String whereClause, String[] whereArgs) {
ContentValues values = new ContentValues();
values.put(Calls.LAST_MODIFIED, getTimeMillis());
@@ -247,7 +271,7 @@
}
if (count > 0 && isVoicemail) {
- notifyVoicemailChange(mBaseUri, packagesModified, Intent.ACTION_PROVIDER_CHANGED);
+ notifyVoicemailChange(mBaseUri, packagesModified);
}
if (count > 0 && mIsCallsTable) {
notifyCallLogChange();
@@ -255,6 +279,25 @@
return count;
}
+ @Override
+ public void startBulkOperation() {
+ mIsBulkOperation = true;
+ mDb.beginTransaction();
+ }
+
+ @Override
+ public void yieldBulkOperation() {
+ mDb.yieldIfContendedSafely();
+ }
+
+ @Override
+ public void finishBulkOperation() {
+ mDb.setTransactionSuccessful();
+ mDb.endTransaction();
+ mIsBulkOperation = false;
+ mVoicemailNotifier.sendNotification();
+ }
+
/**
* 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
@@ -266,7 +309,7 @@
Cursor cursor = mDb.query(mTableName, PROJECTION,
DbQueryUtils.concatenateClauses(NON_NULL_SOURCE_PACKAGE_SELECTION, whereClause),
whereArgs, null, null, null);
- while(cursor.moveToNext()) {
+ while (cursor.moveToNext()) {
modifiedPackages.add(cursor.getString(SOURCE_PACKAGE_COLUMN_INDEX));
}
MoreCloseables.closeQuietly(cursor);
@@ -281,7 +324,7 @@
*/
private Set<String> getModifiedPackages(ContentValues values) {
Set<String> impactedPackages = new ArraySet<>();
- if(values.containsKey(VoicemailContract.SOURCE_PACKAGE_FIELD)) {
+ if (values.containsKey(VoicemailContract.SOURCE_PACKAGE_FIELD)) {
impactedPackages.add(values.getAsString(VoicemailContract.SOURCE_PACKAGE_FIELD));
}
return impactedPackages;
@@ -290,7 +333,7 @@
/**
* @param packagesModified source packages that inserted the voicemail that is being modified
* @return {@code true} if the caller is modifying its own voicemail, or this is an internal
- * transaction, {@code false} otherwise.
+ * transaction, {@code false} otherwise.
*/
private boolean isSelfModifyingOrInternal(Set<String> packagesModified) {
final Collection<String> callingPackages = getCallingPackages();
@@ -301,59 +344,7 @@
// but allows us to mock the results for testing.
return packagesModified.size() == 1 && (callingPackages.contains(
Iterables.getOnlyElement(packagesModified))
- || callingPackages.contains(mContext.getPackageName()));
- }
-
- private void notifyVoicemailChange(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)) {
- // Ignore any package that is not affected by the change and don't have full access
- // either.
- if (!modifiedPackages.contains(component.getPackageName()) &&
- !mVoicemailPermissions.packageHasReadAccess(
- component.getPackageName())) {
- continue;
- }
-
- Intent intent = new Intent(intentAction, notificationUri);
- intent.setComponent(component);
- if (includeSelfChangeExtra && callingPackages != null) {
- intent.putExtra(VoicemailContract.EXTRA_SELF_CHANGE,
- callingPackages.contains(component.getPackageName()));
- }
- String permissionNeeded = modifiedPackages.contains(component.getPackageName()) ?
- ADD_VOICEMAIL : READ_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;
+ || callingPackages.contains(mContext.getPackageName()));
}
/**
@@ -393,4 +384,9 @@
}
return CallLogProvider.getTimeForTestMillis();
}
+
+ @VisibleForTesting
+ static void setVoicemailNotifierForTest(VoicemailNotifier notifier) {
+ sVoicemailNotifierForTest = notifier;
+ }
}
diff --git a/src/com/android/providers/contacts/VoicemailContentProvider.java b/src/com/android/providers/contacts/VoicemailContentProvider.java
index 160a1a9..01c1048 100644
--- a/src/com/android/providers/contacts/VoicemailContentProvider.java
+++ b/src/com/android/providers/contacts/VoicemailContentProvider.java
@@ -20,6 +20,7 @@
import static com.android.providers.contacts.util.DbQueryUtils.concatenateClauses;
import static com.android.providers.contacts.util.DbQueryUtils.getEqualityClause;
+import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.ContentProvider;
import android.content.ContentResolver;
@@ -157,6 +158,12 @@
}
@Override
+ public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) {
+ UriData uriData = checkPermissionsAndCreateUriDataForWrite(uri, values);
+ return getTableDelegate(uriData).bulkInsert(uriData, values);
+ }
+
+ @Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
if (VERBOSE_LOGGING) {
diff --git a/src/com/android/providers/contacts/VoicemailContentTable.java b/src/com/android/providers/contacts/VoicemailContentTable.java
index 09a8c1f..b295ac5 100644
--- a/src/com/android/providers/contacts/VoicemailContentTable.java
+++ b/src/com/android/providers/contacts/VoicemailContentTable.java
@@ -39,7 +39,6 @@
import com.android.providers.contacts.util.CloseUtils;
import com.google.common.collect.ImmutableSet;
-
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -52,10 +51,12 @@
private static final String TAG = "VmContentProvider";
private final ProjectionMap mVoicemailProjectionMap;
- /** The private directory in which to store the data associated with the voicemail. */
+ /**
+ * The private directory in which to store the data associated with the voicemail.
+ */
private static final String DATA_DIRECTORY = "voicemail-data";
- private static final String[] FILENAME_ONLY_PROJECTION = new String[] { Voicemails._DATA };
+ private static final String[] FILENAME_ONLY_PROJECTION = new String[] {Voicemails._DATA};
private static final ImmutableSet<String> ALLOWED_COLUMNS = new ImmutableSet.Builder<String>()
.add(Voicemails._ID)
@@ -83,6 +84,8 @@
.add(OpenableColumns.SIZE)
.build();
+ private static final int BULK_INSERTS_PER_YIELD_POINT = 50;
+
private final String mTableName;
private final CallLogDatabaseHelper mDbHelper;
private final Context mContext;
@@ -138,6 +141,30 @@
@Override
public Uri insert(UriData uriData, ContentValues values) {
+ DatabaseModifier modifier = createDatabaseModifier(mDbHelper.getWritableDatabase());
+ Uri uri = insertRow(modifier, uriData, values);
+ return uri;
+ }
+
+ @Override
+ public int bulkInsert(UriData uriData, ContentValues[] values) {
+ DatabaseModifier modifier = createDatabaseModifier(mDbHelper.getWritableDatabase());
+ modifier.startBulkOperation();
+ int count = 0;
+ for (ContentValues value : values) {
+ Uri uri = insertRow(modifier, uriData, value);
+ if (uri != null) {
+ count++;
+ }
+ if((count % BULK_INSERTS_PER_YIELD_POINT) == 0){
+ modifier.yieldBulkOperation();
+ }
+ }
+ modifier.finishBulkOperation();
+ return count;
+ }
+
+ private Uri insertRow(DatabaseModifier modifier, UriData uriData, ContentValues values) {
checkForSupportedColumns(mVoicemailProjectionMap, values);
ContentValues copiedValues = new ContentValues(values);
checkInsertSupported(uriData);
@@ -160,7 +187,7 @@
}
SQLiteDatabase db = mDbHelper.getWritableDatabase();
- long rowId = getDatabaseModifier(db).insert(mTableName, null, copiedValues);
+ long rowId = modifier.insert(mTableName, null, copiedValues);
if (rowId > 0) {
Uri newUri = ContentUris.withAppendedId(uriData.getUri(), rowId);
// Populate the 'voicemail_uri' field to be used by the call_log provider.
@@ -228,7 +255,7 @@
}
// Now delete the rows themselves.
- return getDatabaseModifier(db).delete(mTableName, combinedClause,
+ return createDatabaseModifier(db).delete(mTableName, combinedClause,
selectionArgs);
}
@@ -262,7 +289,7 @@
// URI that include message Id. I think we do want to support bulk update.
String combinedClause = concatenateClauses(selection, uriData.getWhereClause(),
getCallTypeClause());
- return getDatabaseModifier(db).update(uriData.getUri(), mTableName, values, combinedClause,
+ return createDatabaseModifier(db).update(uriData.getUri(), mTableName, values, combinedClause,
selectionArgs);
}
@@ -298,7 +325,7 @@
return getEqualityClause(Calls.TYPE, Calls.VOICEMAIL_TYPE);
}
- private DatabaseModifier getDatabaseModifier(SQLiteDatabase db) {
+ private DatabaseModifier createDatabaseModifier(SQLiteDatabase db) {
return new DbModifierWithNotification(mTableName, db, mContext);
}
diff --git a/src/com/android/providers/contacts/VoicemailNotifier.java b/src/com/android/providers/contacts/VoicemailNotifier.java
new file mode 100644
index 0000000..04a9bd6
--- /dev/null
+++ b/src/com/android/providers/contacts/VoicemailNotifier.java
@@ -0,0 +1,127 @@
+package com.android.providers.contacts;
+
+import static android.Manifest.permission.ADD_VOICEMAIL;
+import static android.Manifest.permission.READ_VOICEMAIL;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Binder;
+import android.provider.VoicemailContract;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.google.android.collect.Lists;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Aggregates voicemail broadcasts from multiple operations in to a single one. The URIs will be
+ * {@link VoicemailContract.Voicemails#DIR_TYPE} instead of {@link
+ * VoicemailContract.Voicemails#ITEM_TYPE} if multiple URIs is notified.
+ */
+public class VoicemailNotifier {
+
+ private final String TAG = "VoicemailNotifier";
+
+ private final Context mContext;
+ private final Uri mBaseUri;
+
+ private final VoicemailPermissions mVoicemailPermissions;
+
+ private final Set<String> mIntentActions = new ArraySet<>();
+ private final Set<String> mModifiedPackages = new ArraySet<>();
+ private final Set<Uri> mUris = new ArraySet<>();
+
+ public VoicemailNotifier(Context context, Uri baseUri) {
+ mContext = context;
+ mBaseUri = baseUri;
+ mVoicemailPermissions = new VoicemailPermissions(mContext);
+ }
+
+ public void addIntentActions(String action) {
+ mIntentActions.add(action);
+ }
+
+ public void addModifiedPackages(Collection<String> packages) {
+ mModifiedPackages.addAll(packages);
+ }
+
+ public void addUri(Uri uri) {
+ mUris.add(uri);
+ }
+
+ public void sendNotification() {
+ Uri uri = mUris.size() == 1 ? mUris.iterator().next() : mBaseUri;
+ mContext.getContentResolver().notifyChange(uri, null, true);
+ Collection<String> callingPackages = getCallingPackages();
+ // Now fire individual intents.
+ for (String intentAction : mIntentActions) {
+ // self_change extra should be included only for provider_changed events.
+ boolean includeSelfChangeExtra = intentAction.equals(Intent.ACTION_PROVIDER_CHANGED);
+ Log.i(TAG, "receivers for " + intentAction + " :" + getBroadcastReceiverComponents(
+ intentAction, uri));
+ for (ComponentName component :
+ getBroadcastReceiverComponents(intentAction, uri)) {
+ // Ignore any package that is not affected by the change and don't have full access
+ // either.
+ if (!mModifiedPackages.contains(component.getPackageName()) &&
+ !mVoicemailPermissions.packageHasReadAccess(
+ component.getPackageName())) {
+ continue;
+ }
+
+ Intent intent = new Intent(intentAction, uri);
+ intent.setComponent(component);
+ if (includeSelfChangeExtra && callingPackages != null) {
+ intent.putExtra(VoicemailContract.EXTRA_SELF_CHANGE,
+ callingPackages.contains(component.getPackageName()));
+ }
+ String permissionNeeded = mModifiedPackages.contains(component.getPackageName()) ?
+ ADD_VOICEMAIL : READ_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));
+ }
+ }
+ mIntentActions.clear();
+ mModifiedPackages.clear();
+ mUris.clear();
+ }
+
+ /**
+ * 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));
+ }
+
+ /**
+ * 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;
+ }
+}
diff --git a/src/com/android/providers/contacts/VoicemailStatusTable.java b/src/com/android/providers/contacts/VoicemailStatusTable.java
index f3008c0..5b03c8a 100644
--- a/src/com/android/providers/contacts/VoicemailStatusTable.java
+++ b/src/com/android/providers/contacts/VoicemailStatusTable.java
@@ -32,8 +32,6 @@
import com.android.common.content.ProjectionMap;
import com.android.providers.contacts.VoicemailContentProvider.UriData;
-import java.util.Set;
-
/**
* Implementation of {@link VoicemailTable.Delegate} for the voicemail status table.
*
@@ -78,7 +76,7 @@
SQLiteDatabase db = mDbHelper.getWritableDatabase();
// Try to update before insert.
String combinedClause = uriData.getWhereClause();
- int rowsChanged = getDatabaseModifier(db)
+ int rowsChanged = createDatabaseModifier(db)
.update(uriData.getUri(), mTableName, values, combinedClause, null);
if (rowsChanged != 0) {
final String[] selection = new String[] {Status._ID};
@@ -90,7 +88,7 @@
}
ContentValues copiedValues = new ContentValues(values);
mDelegateHelper.checkAndAddSourcePackageIntoValues(uriData, copiedValues);
- long rowId = getDatabaseModifier(db).insert(mTableName, null, copiedValues);
+ long rowId = createDatabaseModifier(db).insert(mTableName, null, copiedValues);
if (rowId > 0) {
return ContentUris.withAppendedId(uriData.getUri(), rowId);
} else {
@@ -100,11 +98,23 @@
}
@Override
+ public int bulkInsert(UriData uriData, ContentValues[] values) {
+ int count = 0;
+ for (ContentValues value : values) {
+ Uri uri = insert(uriData, value);
+ if (uri != null) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ @Override
public int delete(UriData uriData, String selection, String[] selectionArgs) {
synchronized (DATABASE_LOCK) {
SQLiteDatabase db = mDbHelper.getWritableDatabase();
String combinedClause = concatenateClauses(selection, uriData.getWhereClause());
- return getDatabaseModifier(db).delete(mTableName, combinedClause,
+ return createDatabaseModifier(db).delete(mTableName, combinedClause,
selectionArgs);
}
}
@@ -135,7 +145,7 @@
synchronized (DATABASE_LOCK) {
SQLiteDatabase db = mDbHelper.getWritableDatabase();
String combinedClause = concatenateClauses(selection, uriData.getWhereClause());
- return getDatabaseModifier(db)
+ return createDatabaseModifier(db)
.update(uriData.getUri(), mTableName, values, combinedClause, selectionArgs);
}
}
@@ -154,7 +164,7 @@
throw new UnsupportedOperationException("File operation is not supported for status table");
}
- private DatabaseModifier getDatabaseModifier(SQLiteDatabase db) {
+ private DatabaseModifier createDatabaseModifier(SQLiteDatabase db) {
return new DbModifierWithNotification(mTableName, db, mContext);
}
diff --git a/src/com/android/providers/contacts/VoicemailTable.java b/src/com/android/providers/contacts/VoicemailTable.java
index fcb653c..f71b50d 100644
--- a/src/com/android/providers/contacts/VoicemailTable.java
+++ b/src/com/android/providers/contacts/VoicemailTable.java
@@ -46,6 +46,8 @@
public ParcelFileDescriptor openFile(UriData uriData, String mode)
throws FileNotFoundException;
public ArraySet<String> getSourcePackages();
+
+ int bulkInsert(UriData uriData, ContentValues[] values);
}
/**
diff --git a/tests/Android.mk b/tests/Android.mk
index 8df1d6d..e0c6284 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -7,10 +7,9 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
ContactsProviderTestUtils \
android-support-test \
- mockito-target-minus-junit4 \
- legacy-android-test
+ mockito-target-minus-junit4
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
# Only compile source java files in this apk.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java b/tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java
index 185fa03..1832b4e 100644
--- a/tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java
+++ b/tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java
@@ -16,7 +16,6 @@
package com.android.providers.contacts;
-import static com.android.providers.contacts.TestUtils.createDatabaseSnapshot;
import static com.android.providers.contacts.TestUtils.cv;
import static com.android.providers.contacts.TestUtils.executeSqlFromAssetFile;
@@ -67,14 +66,6 @@
import com.android.providers.contacts.testutil.TestUtil;
import com.android.providers.contacts.util.PropertyUtils;
-import junit.framework.AssertionFailedError;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.HashMap;
-
/**
* Unit tests for database create/upgrade operations in {@link ContactsDatabaseHelper}.
*
@@ -376,6 +367,8 @@
new TableColumn(Data.SYNC3, TEXT, false, null),
new TableColumn(Data.SYNC4, TEXT, false, null),
new TableColumn(Data.CARRIER_PRESENCE, INTEGER, true, "0"),
+ new TableColumn(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, TEXT, false, null),
+ new TableColumn(Data.PREFERRED_PHONE_ACCOUNT_ID, TEXT, false, null),
};
private static final TableColumn[] PHONE_LOOKUP_COLUMNS = new TableColumn[] {
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
index 8930338..6c76709 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
@@ -16,7 +16,6 @@
package com.android.providers.contacts;
-import static com.android.providers.contacts.TestUtils.createDatabaseSnapshot;
import static com.android.providers.contacts.TestUtils.cv;
import static com.android.providers.contacts.TestUtils.dumpCursor;
@@ -420,6 +419,8 @@
Data.DATA14,
Data.DATA15,
Data.CARRIER_PRESENCE,
+ Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME,
+ Data.PREFERRED_PHONE_ACCOUNT_ID,
Data.SYNC1,
Data.SYNC2,
Data.SYNC3,
@@ -508,6 +509,8 @@
Data.DATA14,
Data.DATA15,
Data.CARRIER_PRESENCE,
+ Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME,
+ Data.PREFERRED_PHONE_ACCOUNT_ID,
Data.SYNC1,
Data.SYNC2,
Data.SYNC3,
@@ -590,6 +593,8 @@
Data.DATA14,
Data.DATA15,
Data.CARRIER_PRESENCE,
+ Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME,
+ Data.PREFERRED_PHONE_ACCOUNT_ID,
Data.SYNC1,
Data.SYNC2,
Data.SYNC3,
@@ -698,6 +703,8 @@
Data.DATA14,
Data.DATA15,
Data.CARRIER_PRESENCE,
+ Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME,
+ Data.PREFERRED_PHONE_ACCOUNT_ID,
Data.SYNC1,
Data.SYNC2,
Data.SYNC3,
@@ -6485,6 +6492,8 @@
values.put(Data.DATA14, "old14");
values.put(Data.DATA15, "old15");
values.put(Data.CARRIER_PRESENCE, 0);
+ values.put(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, "oldcomponentname");
+ values.put(Data.PREFERRED_PHONE_ACCOUNT_ID, "oldid");
Uri uri = mResolver.insert(Data.CONTENT_URI, values);
assertStoredValues(uri, values);
assertNetworkNotified(true);
@@ -6509,6 +6518,8 @@
values.put(Data.DATA14, "new14");
values.put(Data.DATA15, "new15");
values.put(Data.CARRIER_PRESENCE, Data.CARRIER_PRESENCE_VT_CAPABLE);
+ values.put(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, "newcomponentname");
+ values.put(Data.PREFERRED_PHONE_ACCOUNT_ID, "newid");
mResolver.update(Data.CONTENT_URI, values, Data.RAW_CONTACT_ID + "=" + rawContactId +
" AND " + Data.MIMETYPE + "='testmimetype'", null);
assertNetworkNotified(true);
@@ -7021,7 +7032,6 @@
values.put(ContactsContract.RawContacts.SEND_TO_VOICEMAIL, 1);
values.put(ContactsContract.RawContacts.AGGREGATION_MODE,
RawContacts.AGGREGATION_MODE_IMMEDIATE);
- values.put(ContactsContract.RawContacts.STARRED, 1);
assertEquals(1, mResolver.update(uri, values, null, null));
assertEquals(version, getVersion(uri));
@@ -7872,6 +7882,11 @@
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
assertStoredValue(contactUri, Contacts.STARRED, "0");
+ assertDirty(rawContactUri1, true);
+ assertDirty(rawContactUri2, true);
+ clearDirty(rawContactUri1);
+ clearDirty(rawContactUri2);
+
ContentValues values = new ContentValues();
values.put(RawContacts.STARRED, "1");
@@ -7880,20 +7895,41 @@
assertStoredValue(rawContactUri1, RawContacts.STARRED, "1");
assertStoredValue(rawContactUri2, RawContacts.STARRED, "0");
assertStoredValue(contactUri, Contacts.STARRED, "1");
+ assertDirty(rawContactUri1, true);
+ assertNetworkNotified(true);
+ clearDirty(rawContactUri1);
values.put(RawContacts.STARRED, "0");
mResolver.update(rawContactUri1, values, null, null);
assertStoredValue(rawContactUri1, RawContacts.STARRED, "0");
assertStoredValue(rawContactUri2, RawContacts.STARRED, "0");
assertStoredValue(contactUri, Contacts.STARRED, "0");
+ assertDirty(rawContactUri1, true);
+ assertNetworkNotified(true);
+ clearDirty(rawContactUri1);
values.put(Contacts.STARRED, "1");
mResolver.update(contactUri, values, null, null);
assertStoredValue(rawContactUri1, RawContacts.STARRED, "1");
assertStoredValue(rawContactUri2, RawContacts.STARRED, "1");
assertStoredValue(contactUri, Contacts.STARRED, "1");
+ assertDirty(rawContactUri1, true);
+ assertNetworkNotified(true);
+ }
+
+ public void testUpdateContactOptionsSetStarred() {
+ long rawContactId = RawContactUtil.createRawContact(mResolver);
+ long contactId = queryContactId(rawContactId);
+ String lookupKey = queryLookupKey(contactId);
+ ContentValues values =new ContentValues();
+ values.put(Contacts.STARRED, 1);
+
+ Uri contactLookupUri = ContentUris.withAppendedId(
+ Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), contactId);
+ mResolver.update(contactLookupUri, values, null, null);
+ assertNetworkNotified(true);
}
public void testSetAndClearSuperPrimaryEmail() {
@@ -9884,6 +9920,8 @@
values.put(Data.DATA14, "fourteen");
values.put(Data.DATA15, "fifteen".getBytes());
values.put(Data.CARRIER_PRESENCE, Data.CARRIER_PRESENCE_VT_CAPABLE);
+ values.put(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, "preferredcomponentname");
+ values.put(Data.PREFERRED_PHONE_ACCOUNT_ID, "preferredid");
values.put(Data.SYNC1, "sync1");
values.put(Data.SYNC2, "sync2");
values.put(Data.SYNC3, "sync3");
diff --git a/tests/src/com/android/providers/contacts/VoicemailProviderTest.java b/tests/src/com/android/providers/contacts/VoicemailProviderTest.java
index 4fa935f..1bf0d84 100644
--- a/tests/src/com/android/providers/contacts/VoicemailProviderTest.java
+++ b/tests/src/com/android/providers/contacts/VoicemailProviderTest.java
@@ -16,11 +16,13 @@
package com.android.providers.contacts;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
-import android.os.BatteryStats.Uid.Proc;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.provider.CallLog;
@@ -39,6 +41,7 @@
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
+import org.mockito.Mockito;
/**
* Unit tests for {@link VoicemailContentProvider}.
@@ -51,7 +54,12 @@
// TODO: Test that calltype and voicemail_uri are auto populated by the provider.
@SmallTest
public class VoicemailProviderTest extends BaseVoicemailProviderTest {
- /** Fields specific to call_log provider that should not be exposed by voicemail provider. */
+
+ private static final String SYSTEM_PROPERTY_DEXMAKER_DEXCACHE = "dexmaker.dexcache";
+
+ /**
+ * Fields specific to call_log provider that should not be exposed by voicemail provider.
+ */
private static final String[] CALLLOG_PROVIDER_SPECIFIC_COLUMNS = {
Calls.CACHED_NAME,
Calls.CACHED_NUMBER_LABEL,
@@ -60,23 +68,37 @@
Calls.VOICEMAIL_URI,
Calls.COUNTRY_ISO
};
- /** Total number of columns exposed by voicemail provider. */
+ /**
+ * Total number of columns exposed by voicemail provider.
+ */
private static final int NUM_VOICEMAIL_FIELDS = 24;
@Override
protected void setUp() throws Exception {
super.setUp();
setUpForOwnPermission();
+ System.setProperty(SYSTEM_PROPERTY_DEXMAKER_DEXCACHE, getContext().getCacheDir().getPath());
+ Thread.currentThread().setContextClassLoader(VoicemailContentProvider.class.getClassLoader());
addProvider(CallLogProviderTestable.class, CallLog.AUTHORITY);
}
- /** Returns the appropriate /voicemail URI. */
+ @Override
+ protected void tearDown() throws Exception {
+ System.clearProperty(SYSTEM_PROPERTY_DEXMAKER_DEXCACHE);
+ DbModifierWithNotification.setVoicemailNotifierForTest(null);
+ }
+
+ /**
+ * Returns the appropriate /voicemail URI.
+ */
private Uri voicemailUri() {
return mUseSourceUri ?
Voicemails.buildSourceUri(mActor.packageName) : Voicemails.CONTENT_URI;
}
- /** Returns the appropriate /status URI. */
+ /**
+ * Returns the appropriate /status URI.
+ */
private Uri statusUri() {
return mUseSourceUri ?
Status.buildSourceUri(mActor.packageName) : Status.CONTENT_URI;
@@ -118,6 +140,14 @@
}
}
+ public void testBulkInsert() {
+ VoicemailNotifier notifier = mock(VoicemailNotifier.class);
+ DbModifierWithNotification.setVoicemailNotifierForTest(notifier);
+ mResolver.bulkInsert(voicemailUri(),
+ new ContentValues[] {getTestVoicemailValues(), getTestVoicemailValues()});
+ verify(notifier, Mockito.times(1)).sendNotification();
+ }
+
// Test to ensure that media content can be written and read back.
public void testFileContent() throws Exception {
Uri uri = insertVoicemail();
@@ -172,7 +202,7 @@
public void testUpdateOwnPackageVoicemail_RemovesDirtyStatus() {
ContentValues values = getTestVoicemailValues();
values.put(Voicemails.DIRTY, "1");
- final Uri uri = mResolver.insert(voicemailUri(), getTestVoicemailValues());
+ final Uri uri = mResolver.insert(voicemailUri(), values);
mResolver.update(uri, new ContentValues(), null, null);
// At this point, the voicemail should be set back to not dirty.
@@ -181,6 +211,52 @@
assertStoredValues(uri, newValues);
}
+ public void testUpdateOwnPackageVoicemail_retainDirtyStatus_dirty() {
+ ContentValues values = getTestVoicemailValues();
+ values.put(Voicemails.DIRTY, "1");
+ final Uri uri = mResolver.insert(voicemailUri(), values);
+
+ ContentValues retainDirty = new ContentValues();
+ retainDirty.put(Voicemails.TRANSCRIPTION, "foo");
+ retainDirty.put(Voicemails.DIRTY, Voicemails.DIRTY_RETAIN);
+
+ mResolver.update(uri, retainDirty, null, null);
+ ContentValues newValues = getTestVoicemailValues();
+ newValues.put(Voicemails.DIRTY, "1");
+ newValues.put(Voicemails.TRANSCRIPTION, "foo");
+ assertStoredValues(uri, newValues);
+ }
+
+ public void testUpdateOwnPackageVoicemail_retainDirtyStatus_notDirty() {
+ ContentValues values = getTestVoicemailValues();
+ values.put(Voicemails.DIRTY, "0");
+ final Uri uri = mResolver.insert(voicemailUri(), values);
+
+ ContentValues retainDirty = new ContentValues();
+ retainDirty.put(Voicemails.TRANSCRIPTION, "foo");
+ retainDirty.put(Voicemails.DIRTY, Voicemails.DIRTY_RETAIN);
+
+ mResolver.update(uri, retainDirty, null, null);
+ ContentValues newValues = getTestVoicemailValues();
+ newValues.put(Voicemails.DIRTY, "0");
+ newValues.put(Voicemails.TRANSCRIPTION, "foo");
+ assertStoredValues(uri, newValues);
+ }
+
+ public void testUpdateOwnPackageVoicemail_retainDirtyStatus_noOtherValues() {
+ ContentValues values = getTestVoicemailValues();
+ values.put(Voicemails.DIRTY, "1");
+ final Uri uri = mResolver.insert(voicemailUri(), values);
+
+ ContentValues retainDirty = new ContentValues();
+ retainDirty.put(Voicemails.DIRTY, Voicemails.DIRTY_RETAIN);
+
+ mResolver.update(uri, retainDirty, null, null);
+ ContentValues newValues = getTestVoicemailValues();
+ newValues.put(Voicemails.DIRTY, "1");
+ assertStoredValues(uri, newValues);
+ }
+
public void testDeleteOwnPackageVoicemail_DeletesRow() {
setUpForFullPermission();
final Uri ownVoicemail = insertVoicemail();
diff --git a/tests2/Android.mk b/tests2/Android.mk
index bb4443f..4a0fdfb 100644
--- a/tests2/Android.mk
+++ b/tests2/Android.mk
@@ -22,10 +22,9 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
ContactsProviderTestUtils \
android-support-test \
- mockito-target-minus-junit4 \
- legacy-android-test
+ mockito-target-minus-junit4
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_SRC_FILES := $(call all-java-files-under, src)