aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--res/values-bn/strings.xml2
-rw-r--r--res/values-bs/strings.xml2
-rw-r--r--res/values-en-rCA/strings.xml35
-rw-r--r--res/values-en-rXC/strings.xml35
-rw-r--r--res/values-hi/strings.xml4
-rw-r--r--res/values-mr/strings.xml2
-rw-r--r--res/values-sw/strings.xml2
-rw-r--r--src/com/android/providers/contacts/CallLogProvider.java12
-rw-r--r--src/com/android/providers/contacts/ContactsDatabaseHelper.java24
-rw-r--r--src/com/android/providers/contacts/ContactsProvider2.java9
-rw-r--r--src/com/android/providers/contacts/DatabaseModifier.java6
-rw-r--r--src/com/android/providers/contacts/DbModifierWithNotification.java180
-rw-r--r--src/com/android/providers/contacts/VoicemailContentProvider.java7
-rw-r--r--src/com/android/providers/contacts/VoicemailContentTable.java41
-rw-r--r--src/com/android/providers/contacts/VoicemailNotifier.java127
-rw-r--r--src/com/android/providers/contacts/VoicemailStatusTable.java24
-rw-r--r--src/com/android/providers/contacts/VoicemailTable.java2
-rw-r--r--tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java11
-rw-r--r--tests/src/com/android/providers/contacts/ContactsProvider2Test.java42
-rw-r--r--tests/src/com/android/providers/contacts/VoicemailProviderTest.java88
20 files changed, 518 insertions, 137 deletions
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index dc803da9..49646f3f 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 37bc1502..e1fae510 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 00000000..c62b699a
--- /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 00000000..b7681dd5
--- /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 5fa4021e..a9b20257 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 7e6d6054..a4f324e0 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 920511ab..92bd391f 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 59e9b147..76e207a0 100644
--- a/src/com/android/providers/contacts/CallLogProvider.java
+++ b/src/com/android/providers/contacts/CallLogProvider.java
@@ -383,7 +383,7 @@ public class CallLogProvider extends ContentProvider {
// 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 @@ public class CallLogProvider extends ContentProvider {
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 @@ public class CallLogProvider extends ContentProvider {
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 @@ public class CallLogProvider extends ContentProvider {
* 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 76fe173d..9414ece8 100644
--- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@ -136,9 +136,10 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper {
* 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 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper {
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 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper {
+ 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 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper {
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 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper {
+ "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 a5af51fe..1d5681ac 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -754,6 +754,8 @@ public class ContactsProvider2 extends AbstractContactsProvider
.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 @@ public class ContactsProvider2 extends AbstractContactsProvider
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 @@ public class ContactsProvider2 extends AbstractContactsProvider
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 @@ public class ContactsProvider2 extends AbstractContactsProvider
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 b11605b4..60f9c7f1 100644
--- a/src/com/android/providers/contacts/DatabaseModifier.java
+++ b/src/com/android/providers/contacts/DatabaseModifier.java
@@ -49,4 +49,10 @@ public interface DatabaseModifier {
* {@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 7e7b3e17..0babe1b9 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.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;
@@ -37,17 +34,15 @@ import android.provider.VoicemailContract;
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 @@ import java.util.Set;
* 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 @@ public class DbModifierWithNotification implements DatabaseModifier {
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 @@ public class DbModifierWithNotification implements DatabaseModifier {
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 @@ public class DbModifierWithNotification implements DatabaseModifier {
}
}
- 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 @@ public class DbModifierWithNotification implements DatabaseModifier {
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 @@ public class DbModifierWithNotification implements DatabaseModifier {
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 @@ public class DbModifierWithNotification implements DatabaseModifier {
}
if (count > 0 && isVoicemail) {
- notifyVoicemailChange(mBaseUri, packagesModified, Intent.ACTION_PROVIDER_CHANGED);
+ notifyVoicemailChange(mBaseUri, packagesModified);
}
if (count > 0 && mIsCallsTable) {
notifyCallLogChange();
@@ -255,6 +279,25 @@ public class DbModifierWithNotification implements DatabaseModifier {
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 @@ public class DbModifierWithNotification implements DatabaseModifier {
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 @@ public class DbModifierWithNotification implements DatabaseModifier {
*/
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 @@ public class DbModifierWithNotification implements DatabaseModifier {
/**
* @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 @@ public class DbModifierWithNotification implements DatabaseModifier {
// 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 @@ public class DbModifierWithNotification implements DatabaseModifier {
}
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 160a1a99..01c10481 100644
--- a/src/com/android/providers/contacts/VoicemailContentProvider.java
+++ b/src/com/android/providers/contacts/VoicemailContentProvider.java
@@ -20,6 +20,7 @@ import static android.provider.VoicemailContract.SOURCE_PACKAGE_FIELD;
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 @@ public class VoicemailContentProvider extends ContentProvider
}
@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 09a8c1f0..b295ac54 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.VoicemailContentProvider.UriData;
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 @@ public class VoicemailContentTable implements VoicemailTable.Delegate {
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 @@ public class VoicemailContentTable implements VoicemailTable.Delegate {
.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 @@ public class VoicemailContentTable implements VoicemailTable.Delegate {
@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 @@ public class VoicemailContentTable implements VoicemailTable.Delegate {
}
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 @@ public class VoicemailContentTable implements VoicemailTable.Delegate {
}
// Now delete the rows themselves.
- return getDatabaseModifier(db).delete(mTableName, combinedClause,
+ return createDatabaseModifier(db).delete(mTableName, combinedClause,
selectionArgs);
}
@@ -262,7 +289,7 @@ 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());
- return getDatabaseModifier(db).update(uriData.getUri(), mTableName, values, combinedClause,
+ return createDatabaseModifier(db).update(uriData.getUri(), mTableName, values, combinedClause,
selectionArgs);
}
@@ -298,7 +325,7 @@ public class VoicemailContentTable implements VoicemailTable.Delegate {
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 00000000..04a9bd64
--- /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 f3008c0e..5b03c8a6 100644
--- a/src/com/android/providers/contacts/VoicemailStatusTable.java
+++ b/src/com/android/providers/contacts/VoicemailStatusTable.java
@@ -32,8 +32,6 @@ import android.util.ArraySet;
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 @@ public class VoicemailStatusTable implements VoicemailTable.Delegate {
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 @@ public class VoicemailStatusTable implements VoicemailTable.Delegate {
}
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 @@ public class VoicemailStatusTable implements VoicemailTable.Delegate {
}
@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 @@ public class VoicemailStatusTable implements VoicemailTable.Delegate {
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 @@ public class VoicemailStatusTable implements VoicemailTable.Delegate {
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 fcb653ce..f71b50de 100644
--- a/src/com/android/providers/contacts/VoicemailTable.java
+++ b/src/com/android/providers/contacts/VoicemailTable.java
@@ -46,6 +46,8 @@ public interface VoicemailTable {
public ParcelFileDescriptor openFile(UriData uriData, String mode)
throws FileNotFoundException;
public ArraySet<String> getSourcePackages();
+
+ int bulkInsert(UriData uriData, ContentValues[] values);
}
/**
diff --git a/tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java b/tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java
index 185fa031..1832b4e4 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.ContactsDatabaseHelper.Tables;
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 @@ public class ContactsDatabaseHelperUpgradeTest extends BaseDatabaseHelperUpgrade
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 8930338e..6c76709e 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 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
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 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
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 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
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 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
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 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
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 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
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 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
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 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
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 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
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 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
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 4fa935fa..1bf0d847 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.InputStream;
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 @@ import java.util.List;
// 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 @@ public class VoicemailProviderTest extends BaseVoicemailProviderTest {
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 class VoicemailProviderTest extends BaseVoicemailProviderTest {
}
}
+ 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 class VoicemailProviderTest extends BaseVoicemailProviderTest {
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 @@ public class VoicemailProviderTest extends BaseVoicemailProviderTest {
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();