aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml3
-rw-r--r--TEST_MAPPING15
-rw-r--r--res/drawable-hdpi/app_icon.pngbin3169 -> 0 bytes
-rw-r--r--res/drawable-mdpi/app_icon.pngbin2062 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/app_icon.pngbin4430 -> 0 bytes
-rw-r--r--res/drawable-xxhdpi/app_icon.pngbin7228 -> 0 bytes
-rw-r--r--res/drawable-xxxhdpi/app_icon.pngbin10065 -> 0 bytes
-rw-r--r--res/values-de/strings.xml2
-rw-r--r--res/values-eu/strings.xml2
-rw-r--r--res/values-fa/strings.xml2
-rw-r--r--res/values-hi/strings.xml8
-rw-r--r--res/values-ja/strings.xml2
-rw-r--r--res/values-ky/strings.xml2
-rw-r--r--res/values-lo/strings.xml2
-rw-r--r--res/values-mk/strings.xml2
-rw-r--r--res/values-ml/strings.xml4
-rw-r--r--res/values-ta/strings.xml2
-rw-r--r--src/com/android/providers/contacts/CallLogProvider.java6
-rw-r--r--src/com/android/providers/contacts/ContactsProvider2.java296
-rw-r--r--src/com/android/providers/contacts/MetadataEntryParser.java20
-rw-r--r--src/com/android/providers/contacts/VoicemailContentProvider.java20
-rw-r--r--test_common/src/com/android/providers/contacts/testutil/DatabaseAsserts.java14
-rw-r--r--tests/src/com/android/providers/contacts/ContactsActor.java15
-rw-r--r--tests/src/com/android/providers/contacts/ContactsProvider2Test.java221
24 files changed, 368 insertions, 270 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index cd7de03c..0748e0ff 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -11,6 +11,7 @@
<uses-permission android:name="android.permission.PROCESS_PHONE_ACCOUNT_REGISTRATION" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.SEND_CALL_LOG_CHANGE" />
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
@@ -25,8 +26,8 @@
<application android:process="android.process.acore"
android:label="@string/app_label"
- android:icon="@drawable/app_icon"
android:allowBackup="false"
+ android:forceQueryable="true"
android:usesCleartextTraffic="false">
<provider android:name="ContactsProvider2"
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 00000000..c66ff24b
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "ContactsProviderTests"
+ },
+ {
+ "name": "CtsProviderTestCases",
+ "options": [
+ {
+ "include-filter": "android.provider.cts.contacts."
+ }
+ ]
+ }
+ ]
+}
diff --git a/res/drawable-hdpi/app_icon.png b/res/drawable-hdpi/app_icon.png
deleted file mode 100644
index 64eff002..00000000
--- a/res/drawable-hdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/app_icon.png b/res/drawable-mdpi/app_icon.png
deleted file mode 100644
index b4ee8215..00000000
--- a/res/drawable-mdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/app_icon.png b/res/drawable-xhdpi/app_icon.png
deleted file mode 100644
index 6feeadfb..00000000
--- a/res/drawable-xhdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/app_icon.png b/res/drawable-xxhdpi/app_icon.png
deleted file mode 100644
index 01a3fde9..00000000
--- a/res/drawable-xxhdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/app_icon.png b/res/drawable-xxxhdpi/app_icon.png
deleted file mode 100644
index 328e067e..00000000
--- a/res/drawable-xxxhdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index a7259534..eb68085d 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -26,7 +26,7 @@
<string name="local_invisible_directory" msgid="705244318477396120">"Sonstige"</string>
<string name="voicemail_from_column" msgid="435732568832121444">"Mailboxnachricht von "</string>
<string name="debug_dump_title" msgid="4916885724165570279">"Kontaktdatenbank kopieren"</string>
- <string name="debug_dump_database_message" msgid="406438635002392290">"Du 1) erstellst eine Kopie deiner Datenbank, die alle Kontaktinformationen und Anruflisten auf dem internen Speicher enthält, und 2) sendest diese Kopie per E-Mail. Denke daran, die Kopie so schnell wie möglich zu löschen, nachdem du sie vom Gerät kopiert hast oder die E-Mail empfangen wurde."</string>
+ <string name="debug_dump_database_message" msgid="406438635002392290">"Du 1) erstellst eine Kopie deiner Datenbank, die alle Kontaktinformationen und Anruflisteneinträge auf dem internen Speicher enthält, und 2) sendest diese Kopie per E-Mail. Denke daran, die Kopie so schnell wie möglich zu löschen, nachdem du sie vom Gerät kopiert hast oder die E-Mail empfangen wurde."</string>
<string name="debug_dump_delete_button" msgid="7832879421132026435">"Jetzt löschen"</string>
<string name="debug_dump_start_button" msgid="2837506913757600001">"Starten"</string>
<string name="debug_dump_email_sender_picker" msgid="3534420908672176460">"Programm zum Senden der Datei auswählen"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index e9f97d2a..b1c74313 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -24,7 +24,7 @@
<string name="upgrade_out_of_memory_notification_text" msgid="2581831842693151968">"Sakatu bertsio-berritzea osatzeko."</string>
<string name="default_directory" msgid="93961630309570294">"Kontaktuak"</string>
<string name="local_invisible_directory" msgid="705244318477396120">"Beste bat"</string>
- <string name="voicemail_from_column" msgid="435732568832121444">"Honen ahots-mezua: "</string>
+ <string name="voicemail_from_column" msgid="435732568832121444">"Mezu bat utzi du erantzungailuan honek: "</string>
<string name="debug_dump_title" msgid="4916885724165570279">"Kopiatu kontaktuen datu-basea"</string>
<string name="debug_dump_database_message" msgid="406438635002392290">"Bi gauza egitera zoaz: 1) kontaktuekin erlazionatutako informazio guztia eta deien erregistro osoa jasotzen dituen datu-basearen kopia bat egingo duzu eta barneko memorian gordeko duzu eta 2) posta elektronikoz bidaliko duzu. Gogoratu kopia ezabatu behar duzula gailutik kopiatu edo mezu elektronikoa jaso bezain laster."</string>
<string name="debug_dump_delete_button" msgid="7832879421132026435">"Ezabatu"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 4af29ec9..9fa5c9bc 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -17,7 +17,7 @@
<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">"حافظه مخاطبین"</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_title" msgid="8888171924684998531">"ارتقا حافظه برای مخاطبین"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index a9b20257..478e5ce5 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -19,17 +19,17 @@
<string name="sharedUserLabel" msgid="8024311725474286801">"Android Core Apps"</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="upgrade_out_of_memory_notification_text" msgid="2581831842693151968">"अपग्रेड पूरा करने के लिए टैप करें."</string>
<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_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>
<string name="debug_dump_email_subject" msgid="108188398416385976">"संपर्क Db अनुलग्न है"</string>
- <string name="debug_dump_email_body" msgid="4577749800871444318">"मेरी समस्त संपर्क जानकारी के साथ मेरा संपर्क डेटाबेस अनुलग्न है. सावधानी से कार्य करें."</string>
+ <string name="debug_dump_email_body" msgid="4577749800871444318">"मेरी समस्त संपर्क जानकारी के साथ मेरा संपर्क डेटाबेस अनुलग्न है. सावधानी से काम करें."</string>
</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 1756ab8a..4e7a44cd 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -26,7 +26,7 @@
<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_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-ky/strings.xml b/res/values-ky/strings.xml
index d8251c52..27032f2b 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -26,7 +26,7 @@
<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_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-lo/strings.xml b/res/values-lo/strings.xml
index b75c8161..1efef338 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="sharedUserLabel" msgid="8024311725474286801">"ແອັບພລິເຄຊັນຫຼັກຂອງ Android"</string>
<string name="app_label" msgid="3389954322874982620">"ບ່ອນຈັດເກັບຂໍ້ມູນລາຍຊື່ຜູ່ຕິດຕໍ່"</string>
- <string name="provider_label" msgid="6012150850819899907">"ລາຍຊື່ຜູ່ຕິດຕໍ່"</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_text" msgid="2581831842693151968">"ແຕະເພື່ອສຳເລັດການອັບເກຣດ."</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index dc1a07a9..84ff8712 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -17,7 +17,7 @@
<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"</string>
- <string name="app_label" msgid="3389954322874982620">"Меморирање контакти"</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_title" msgid="8888171924684998531">"Надградување меморија за контакти"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index dc2abdf9..1ed08d23 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -18,11 +18,11 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="sharedUserLabel" msgid="8024311725474286801">"Android കോർ അപ്ലിക്കേഷനുകൾ"</string>
<string name="app_label" msgid="3389954322874982620">"കോൺടാക്റ്റുകളുടെ സ്റ്റോറേജ്"</string>
- <string name="provider_label" msgid="6012150850819899907">"വിലാസങ്ങൾ"</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_text" msgid="2581831842693151968">"അപ്‌ഗ്രേഡ് പൂർത്തിയാക്കാൻ ടാപ്പുചെയ്യുക."</string>
- <string name="default_directory" msgid="93961630309570294">"വിലാസങ്ങൾ"</string>
+ <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>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 1116f19f..c6e25390 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -16,7 +16,7 @@
<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 முக்கிய பயன்பாடுகள்"</string>
+ <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>
diff --git a/src/com/android/providers/contacts/CallLogProvider.java b/src/com/android/providers/contacts/CallLogProvider.java
index f9aa4843..ebe111f1 100644
--- a/src/com/android/providers/contacts/CallLogProvider.java
+++ b/src/com/android/providers/contacts/CallLogProvider.java
@@ -314,6 +314,7 @@ public class CallLogProvider extends ContentProvider {
Log.v(TAG, "query: uri=" + uri + " projection=" + Arrays.toString(projection) +
" selection=[" + selection + "] args=" + Arrays.toString(selectionArgs) +
" order=[" + sortOrder + "] CPID=" + Binder.getCallingPid() +
+ " CUID=" + Binder.getCallingUid() +
" User=" + UserUtils.getCurrentUserHandle(getContext()));
}
@@ -488,7 +489,8 @@ public class CallLogProvider extends ContentProvider {
private Uri insertInternal(Uri uri, ContentValues values) {
if (VERBOSE_LOGGING) {
Log.v(TAG, "insert: uri=" + uri + " values=[" + values + "]" +
- " CPID=" + Binder.getCallingPid());
+ " CPID=" + Binder.getCallingPid() +
+ " CUID=" + Binder.getCallingUid());
}
waitForAccess(mReadAccessLatch);
checkForSupportedColumns(sCallsProjectionMap, values);
@@ -521,6 +523,7 @@ public class CallLogProvider extends ContentProvider {
Log.v(TAG, "update: uri=" + uri +
" selection=[" + selection + "] args=" + Arrays.toString(selectionArgs) +
" values=[" + values + "] CPID=" + Binder.getCallingPid() +
+ " CUID=" + Binder.getCallingUid() +
" User=" + UserUtils.getCurrentUserHandle(getContext()));
}
waitForAccess(mReadAccessLatch);
@@ -568,6 +571,7 @@ public class CallLogProvider extends ContentProvider {
Log.v(TAG, "delete: uri=" + uri +
" selection=[" + selection + "] args=" + Arrays.toString(selectionArgs) +
" CPID=" + Binder.getCallingPid() +
+ " CUID=" + Binder.getCallingUid() +
" User=" + UserUtils.getCurrentUserHandle(getContext()));
}
waitForAccess(mReadAccessLatch);
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index b92a9178..5159fb94 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -16,6 +16,10 @@
package com.android.providers.contacts;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.OnAccountsUpdateListener;
@@ -214,7 +218,6 @@ public class ContactsProvider2 extends AbstractContactsProvider
private static final String READ_PERMISSION = "android.permission.READ_CONTACTS";
private static final String WRITE_PERMISSION = "android.permission.WRITE_CONTACTS";
- private static final String INTERACT_ACROSS_USERS = "android.permission.INTERACT_ACROSS_USERS";
/* package */ static final String PHONEBOOK_COLLATOR_NAME = "PHONEBOOK";
@@ -532,23 +535,6 @@ public class ContactsProvider2 extends AbstractContactsProvider
" SET " + RawContacts.DIRTY + "=1" +
" WHERE " + RawContacts._ID + " IN (";
- /** Sql for updating METADATA_DIRTY flag on multiple raw contacts */
- private static final String UPDATE_RAW_CONTACT_SET_METADATA_DIRTY_SQL =
- "UPDATE " + Tables.RAW_CONTACTS +
- " SET " + RawContacts.METADATA_DIRTY + "=1" +
- " WHERE " + RawContacts._ID + " IN (";
-
- // Sql for updating MetadataSync.DELETED flag on multiple raw contacts.
- // When using this sql, add comma separated raw contacts ids and "))".
- private static final String UPDATE_METADATASYNC_SET_DELETED_SQL =
- "UPDATE " + Tables.METADATA_SYNC
- + " SET " + MetadataSync.DELETED + "=1"
- + " WHERE " + MetadataSync._ID + " IN "
- + "(SELECT " + MetadataSyncColumns.CONCRETE_ID
- + " FROM " + Tables.RAW_CONTACTS_JOIN_METADATA_SYNC
- + " WHERE " + RawContactsColumns.CONCRETE_DELETED + "=1 AND "
- + RawContactsColumns.CONCRETE_ID + " IN (";
-
/** Sql for updating VERSION on multiple raw contacts */
private static final String UPDATE_RAW_CONTACT_SET_VERSION_SQL =
"UPDATE " + Tables.RAW_CONTACTS +
@@ -2433,14 +2419,6 @@ public class ContactsProvider2 extends AbstractContactsProvider
for (long rawContactId : mTransactionContext.get().getInsertedRawContactIds()) {
mDbHelper.get().updateRawContactDisplayName(db, rawContactId);
mAggregator.get().onRawContactInsert(mTransactionContext.get(), db, rawContactId);
- if (mMetadataSyncEnabled) {
- updateMetadataOnRawContactInsert(db, rawContactId);
- }
- }
- if (mMetadataSyncEnabled) {
- for (long rawContactId : mTransactionContext.get().getBackupIdChangedRawContacts()) {
- updateMetadataOnRawContactInsert(db, rawContactId);
- }
}
final Set<Long> dirtyRawContacts = mTransactionContext.get().getDirtyRawContactIds();
@@ -2461,29 +2439,8 @@ public class ContactsProvider2 extends AbstractContactsProvider
db.execSQL(mSb.toString());
}
- final Set<Long> metadataDirtyRawContacts =
- mTransactionContext.get().getMetadataDirtyRawContactIds();
- if (!metadataDirtyRawContacts.isEmpty() && mMetadataSyncEnabled) {
- mSb.setLength(0);
- mSb.append(UPDATE_RAW_CONTACT_SET_METADATA_DIRTY_SQL);
- appendIds(mSb, metadataDirtyRawContacts);
- mSb.append(")");
- db.execSQL(mSb.toString());
- mSyncToMetadataNetWork = true;
- }
-
final Set<Long> changedRawContacts = mTransactionContext.get().getChangedRawContactIds();
ContactsTableUtil.updateContactLastUpdateByRawContactId(db, changedRawContacts);
- if (!changedRawContacts.isEmpty() && mMetadataSyncEnabled) {
- // For the deleted raw contact, set related metadata as deleted
- // if metadata flag is enabled.
- mSb.setLength(0);
- mSb.append(UPDATE_METADATASYNC_SET_DELETED_SQL);
- appendIds(mSb, changedRawContacts);
- mSb.append("))");
- db.execSQL(mSb.toString());
- mSyncToMetadataNetWork = true;
- }
// Update sync states.
for (Map.Entry<Long, Object> entry : mTransactionContext.get().getUpdatedSyncStates()) {
@@ -2502,49 +2459,6 @@ public class ContactsProvider2 extends AbstractContactsProvider
mMetadataSyncEnabled = enabled;
}
- interface MetadataSyncQuery {
- String TABLE = Tables.RAW_CONTACTS_JOIN_METADATA_SYNC;
- String[] COLUMNS = new String[] {
- MetadataSyncColumns.CONCRETE_ID,
- MetadataSync.DATA
- };
- int METADATA_SYNC_ID = 0;
- int METADATA_SYNC_DATA = 1;
- String SELECTION = MetadataSyncColumns.CONCRETE_DELETED + "=0 AND " +
- RawContactsColumns.CONCRETE_ID + "=?";
- }
-
- /**
- * Fetch the related metadataSync data column for the raw contact id.
- * Returns null if there's no metadata for the raw contact.
- */
- private String queryMetadataSyncData(SQLiteDatabase db, long rawContactId) {
- String metadataSyncData = null;
- mSelectionArgs1[0] = String.valueOf(rawContactId);
- final Cursor cursor = db.query(MetadataSyncQuery.TABLE,
- MetadataSyncQuery.COLUMNS, MetadataSyncQuery.SELECTION,
- mSelectionArgs1, null, null, null);
- try {
- if (cursor.moveToFirst()) {
- metadataSyncData = cursor.getString(MetadataSyncQuery.METADATA_SYNC_DATA);
- }
- } finally {
- cursor.close();
- }
- return metadataSyncData;
- }
-
- private void updateMetadataOnRawContactInsert(SQLiteDatabase db, long rawContactId) {
- // Read metadata from MetadataSync table for the raw contact, and update.
- final String metadataSyncData = queryMetadataSyncData(db, rawContactId);
- if (TextUtils.isEmpty(metadataSyncData)) {
- return;
- }
- final MetadataEntry metadataEntry = MetadataEntryParser.parseDataToMetaDataEntry(
- metadataSyncData);
- updateFromMetaDataEntry(db, metadataEntry);
- }
-
/**
* Appends comma separated IDs.
* @param ids Should not be empty
@@ -2566,10 +2480,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
protected void notifyChange(boolean syncToNetwork, boolean syncToMetadataNetwork) {
getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null,
- syncToNetwork || syncToMetadataNetwork);
-
- getContext().getContentResolver().notifyChange(MetadataSync.METADATA_AUTHORITY_URI,
- null, syncToMetadataNetwork);
+ syncToNetwork);
}
protected void setProviderStatus(int status) {
@@ -2606,7 +2517,8 @@ public class ContactsProvider2 extends AbstractContactsProvider
protected Uri insertInTransaction(Uri uri, ContentValues values) {
if (VERBOSE_LOGGING) {
Log.v(TAG, "insertInTransaction: uri=" + uri + " values=[" + values + "]" +
- " CPID=" + Binder.getCallingPid());
+ " CPID=" + Binder.getCallingPid() +
+ " CUID=" + Binder.getCallingUid());
}
final SQLiteDatabase db = mDbHelper.get().getWritableDatabase();
@@ -2836,7 +2748,6 @@ public class ContactsProvider2 extends AbstractContactsProvider
values.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
}
- final boolean needToUpdateMetadata = shouldMarkMetadataDirtyForRawContact(values);
// Databases that were created prior to the 906 upgrade have a default of Int.MAX_VALUE
// for RawContacts.PINNED. Manually set the value to the correct default (0) if it is not
// set.
@@ -2848,14 +2759,6 @@ public class ContactsProvider2 extends AbstractContactsProvider
final SQLiteDatabase db = mDbHelper.get().getWritableDatabase();
final long rawContactId = db.insert(Tables.RAW_CONTACTS, RawContacts.CONTACT_ID, values);
- if (needToUpdateMetadata) {
- mTransactionContext.get().markRawContactMetadataDirty(rawContactId,
- /* isMetadataSyncAdapter =*/false);
- }
- // If the new raw contact is inserted by a sync adapter, mark mSyncToMetadataNetWork as true
- // so that it can trigger the metadata syncing from the server.
- mSyncToMetadataNetWork |= callerIsSyncAdapter;
-
final int aggregationMode = getIntValue(values, RawContacts.AGGREGATION_MODE,
RawContacts.AGGREGATION_MODE_DEFAULT);
mAggregator.get().markNewForAggregation(rawContactId, aggregationMode);
@@ -3550,6 +3453,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
Log.v(TAG, "deleteInTransaction: uri=" + uri +
" selection=[" + selection + "] args=" + Arrays.toString(selectionArgs) +
" CPID=" + Binder.getCallingPid() +
+ " CUID=" + Binder.getCallingUid() +
" User=" + UserUtils.getCurrentUserHandle(getContext()));
}
@@ -3802,15 +3706,25 @@ public class ContactsProvider2 extends AbstractContactsProvider
}
private int deleteContact(long contactId, boolean callerIsSyncAdapter) {
+ ArrayList<Long> localRawContactIds = new ArrayList();
+
final SQLiteDatabase db = mDbHelper.get().getWritableDatabase();
mSelectionArgs1[0] = Long.toString(contactId);
Cursor c = db.query(Tables.RAW_CONTACTS, new String[] {RawContacts._ID},
RawContacts.CONTACT_ID + "=?", mSelectionArgs1,
null, null, null);
+
+ // Raw contacts need to be deleted after the contact so just loop through and mark
+ // non-local raw contacts as deleted and collect the local raw contacts that will be
+ // deleted after the contact is deleted.
try {
while (c.moveToNext()) {
long rawContactId = c.getLong(0);
- markRawContactAsDeleted(db, rawContactId, callerIsSyncAdapter);
+ if (rawContactIsLocal(rawContactId)) {
+ localRawContactIds.add(rawContactId);
+ } else {
+ markRawContactAsDeleted(db, rawContactId, callerIsSyncAdapter);
+ }
}
} finally {
c.close();
@@ -3819,6 +3733,10 @@ public class ContactsProvider2 extends AbstractContactsProvider
mProviderStatusUpdateNeeded = true;
int result = ContactsTableUtil.deleteContact(db, contactId);
+
+ // Now purge the local raw contacts
+ deleteRawContactsImmediately(db, localRawContactIds);
+
scheduleBackgroundTask(BACKGROUND_TASK_CLEAN_DELETE_LOG);
return result;
}
@@ -3842,19 +3760,19 @@ public class ContactsProvider2 extends AbstractContactsProvider
c.close();
}
+ // When a raw contact is deleted, a sqlite trigger deletes the parent contact.
+ // TODO: all contact deletes was consolidated into ContactTableUtil but this one can't
+ // because it's in a trigger. Consider removing trigger and replacing with java code.
+ // This has to happen before the raw contact is deleted since it relies on the number
+ // of raw contacts.
final boolean contactIsSingleton =
ContactsTableUtil.deleteContactIfSingleton(db, rawContactId) == 1;
final int count;
if (callerIsSyncAdapter || rawContactIsLocal(rawContactId)) {
- // When a raw contact is deleted, a SQLite trigger deletes the parent contact.
- // TODO: all contact deletes was consolidated into ContactTableUtil but this one can't
- // because it's in a trigger. Consider removing trigger and replacing with java code.
- // This has to happen before the raw contact is deleted since it relies on the number
- // of raw contacts.
- db.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null);
- count = db.delete(Tables.RAW_CONTACTS, RawContacts._ID + "=" + rawContactId, null);
- mTransactionContext.get().markRawContactChangedOrDeletedOrInserted(rawContactId);
+ ArrayList<Long> rawContactsIds = new ArrayList<>();
+ rawContactsIds.add(rawContactId);
+ count = deleteRawContactsImmediately(db, rawContactsIds);
} else {
count = markRawContactAsDeleted(db, rawContactId, callerIsSyncAdapter);
}
@@ -3865,6 +3783,43 @@ public class ContactsProvider2 extends AbstractContactsProvider
}
/**
+ * Returns the number of raw contacts that were deleted immediately -- we don't merely set
+ * the DELETED column to 1, the entire raw contact row is deleted straightaway.
+ */
+ private int deleteRawContactsImmediately(SQLiteDatabase db, List<Long> rawContactIds) {
+ if (rawContactIds == null || rawContactIds.isEmpty()) {
+ return 0;
+ }
+
+ // Build the where clause for the raw contacts to be deleted
+ ArrayList<String> whereArgs = new ArrayList<>();
+ StringBuilder whereClause = new StringBuilder(rawContactIds.size() * 2 - 1);
+ whereClause.append(" IN (?");
+ whereArgs.add(String.valueOf(rawContactIds.get(0)));
+ for (int i = 1; i < rawContactIds.size(); i++) {
+ whereClause.append(",?");
+ whereArgs.add(String.valueOf(rawContactIds.get(i)));
+ }
+ whereClause.append(")");
+
+ // Remove presence rows
+ db.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + whereClause.toString(),
+ whereArgs.toArray(new String[0]));
+
+ // Remove raw contact rows
+ int result = db.delete(Tables.RAW_CONTACTS, RawContacts._ID + whereClause.toString(),
+ whereArgs.toArray(new String[0]));
+
+ if (result > 0) {
+ for (Long rawContactId : rawContactIds) {
+ mTransactionContext.get().markRawContactChangedOrDeletedOrInserted(rawContactId);
+ }
+ }
+
+ return result;
+ }
+
+ /**
* Returns whether the given raw contact ID is local (i.e. has no account associated with it).
*/
private boolean rawContactIsLocal(long rawContactId) {
@@ -3964,6 +3919,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
Log.v(TAG, "updateInTransaction: uri=" + uri +
" selection=[" + selection + "] args=" + Arrays.toString(selectionArgs) +
" values=[" + values + "] CPID=" + Binder.getCallingPid() +
+ " CUID=" + Binder.getCallingUid() +
" User=" + UserUtils.getCurrentUserHandle(getContext()));
}
@@ -4498,7 +4454,6 @@ public class ContactsProvider2 extends AbstractContactsProvider
final boolean isDataSetChanging = values.containsKey(RawContacts.DATA_SET);
final boolean isAccountChanging =
isAccountNameChanging || isAccountTypeChanging || isDataSetChanging;
- final boolean isBackupIdChanging = values.containsKey(RawContacts.BACKUP_ID);
int previousDeleted = 0;
long accountId = 0;
@@ -4561,32 +4516,6 @@ public class ContactsProvider2 extends AbstractContactsProvider
if (aggregationMode != RawContacts.AGGREGATION_MODE_DEFAULT) {
aggregator.markForAggregation(rawContactId, aggregationMode, false);
}
- if (shouldMarkMetadataDirtyForRawContact(values)) {
- mTransactionContext.get().markRawContactMetadataDirty(
- rawContactId, callerIsMetadataSyncAdapter);
- }
- if (isBackupIdChanging) {
- Cursor cursor = db.query(Tables.RAW_CONTACTS,
- new String[] {RawContactsColumns.CONCRETE_METADATA_DIRTY},
- selection, mSelectionArgs1, null, null, null);
- int metadataDirty = 0;
- try {
- if (cursor.moveToFirst()) {
- metadataDirty = cursor.getInt(0);
- }
- } finally {
- cursor.close();
- }
-
- if (metadataDirty == 1) {
- // Re-notify metadata network if backup_id is updated and metadata is dirty.
- mTransactionContext.get().markRawContactMetadataDirty(
- rawContactId, callerIsMetadataSyncAdapter);
- } else {
- // Merge from metadata sync table if backup_id is updated and no dirty change.
- mTransactionContext.get().markBackupIdChangedRawContact(rawContactId);
- }
- }
if (flagExists(values, RawContacts.STARRED)) {
if (!callerIsSyncAdapter) {
updateFavoritesMembership(rawContactId, flagIsSet(values, RawContacts.STARRED));
@@ -4760,10 +4689,6 @@ public class ContactsProvider2 extends AbstractContactsProvider
// Mark dirty when changing starred to trigger sync.
values.put(RawContacts.DIRTY, 1);
}
- if (mMetadataSyncEnabled && (hasStarredValue || hasPinnedValue || hasVoiceMailValue)) {
- // Mark dirty to trigger metadata syncing.
- values.put(RawContacts.METADATA_DIRTY, 1);
- }
mSelectionArgs1[0] = String.valueOf(contactId);
db.update(Tables.RAW_CONTACTS, values, RawContacts.CONTACT_ID + "=?"
@@ -4781,11 +4706,6 @@ public class ContactsProvider2 extends AbstractContactsProvider
flagIsSet(values, RawContacts.STARRED));
mSyncToNetwork |= !callerIsSyncAdapter;
}
-
- if (hasStarredValue || hasPinnedValue || hasVoiceMailValue) {
- mTransactionContext.get().markRawContactMetadataDirty(rawContactId,
- false /*callerIsMetadataSyncAdapter*/);
- }
}
} finally {
cursor.close();
@@ -4863,21 +4783,12 @@ public class ContactsProvider2 extends AbstractContactsProvider
aggregator.aggregateContact(mTransactionContext.get(), db, rawContactId1);
aggregator.aggregateContact(mTransactionContext.get(), db, rawContactId2);
- mTransactionContext.get().markRawContactMetadataDirty(rawContactId1,
- callerIsMetadataSyncAdapter);
- mTransactionContext.get().markRawContactMetadataDirty(rawContactId2,
- callerIsMetadataSyncAdapter);
// The return value is fake - we just confirm that we made a change, not count actual
// rows changed.
return 1;
}
- private boolean shouldMarkMetadataDirtyForRawContact(ContentValues values) {
- return (flagExists(values, RawContacts.STARRED) || flagExists(values, RawContacts.PINNED)
- || flagExists(values, RawContacts.SEND_TO_VOICEMAIL));
- }
-
@Override
public void onAccountsUpdated(Account[] accounts) {
scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS);
@@ -5441,6 +5352,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
Log.v(TAG, "query: uri=" + uri + " projection=" + Arrays.toString(projection) +
" selection=[" + selection + "] args=" + Arrays.toString(selectionArgs) +
" order=[" + sortOrder + "] CPID=" + Binder.getCallingPid() +
+ " CUID=" + Binder.getCallingUid() +
" User=" + UserUtils.getCurrentUserHandle(getContext()));
}
@@ -5454,10 +5366,12 @@ public class ContactsProvider2 extends AbstractContactsProvider
return null;
}
- // Check enterprise policy if caller does not come from same profile
- if (!(isCallerFromSameUser() || mEnterprisePolicyGuard.isCrossProfileAllowed(uri))) {
- return createEmptyCursor(uri, projection);
+ // If caller does not come from same profile, Check if it's privileged or allowed by
+ // enterprise policy
+ if (!queryAllowedByEnterprisePolicy(uri)) {
+ return null;
}
+
// Query the profile DB if appropriate.
if (mapsToProfileDb(uri)) {
switchToProfileMode();
@@ -5477,9 +5391,46 @@ public class ContactsProvider2 extends AbstractContactsProvider
}
}
+ private boolean queryAllowedByEnterprisePolicy(Uri uri) {
+ if (isCallerFromSameUser()) {
+ // Caller is on the same user; query allowed.
+ return true;
+ }
+ if (!doesCallerHoldInteractAcrossUserPermission()) {
+ // Cross-user and the caller has no INTERACT_ACROSS_USERS; don't allow query.
+ // Technically, in a cross-profile sharing case, this would be a valid query.
+ // But for now we don't allow it. (We never allowe it and no one complained about it.)
+ return false;
+ }
+ if (isCallerAnotherSelf()) {
+ // The caller is the other CP2 (which has INTERACT_ACROSS_USERS), meaning the reuest
+ // is on behalf of a "real" client app.
+ // Consult the enterprise policy.
+ return mEnterprisePolicyGuard.isCrossProfileAllowed(uri);
+ }
+ return true;
+ }
+
private boolean isCallerFromSameUser() {
- return Binder.getCallingUserHandle().getIdentifier() == UserUtils
- .getCurrentUserHandle(getContext());
+ return UserHandle.getUserId(Binder.getCallingUid()) == UserHandle.myUserId();
+ }
+
+ /**
+ * Returns true if called by a different user's CP2.
+ */
+ private boolean isCallerAnotherSelf() {
+ // Note normally myUid is always different from the callerUid in the code path where
+ // this method is used, except during unit tests, where the caller is always the same
+ // process.
+ final int myUid = android.os.Process.myUid();
+ final int callingUid = Binder.getCallingUid();
+ return (myUid != callingUid) && UserHandle.isSameApp(myUid, callingUid);
+ }
+
+ private boolean doesCallerHoldInteractAcrossUserPermission() {
+ final Context context = getContext();
+ return context.checkCallingPermission(INTERACT_ACROSS_USERS_FULL) == PERMISSION_GRANTED
+ || context.checkCallingPermission(INTERACT_ACROSS_USERS) == PERMISSION_GRANTED;
}
private Cursor queryDirectoryIfNecessary(Uri uri, String[] projection, String selection,
@@ -5526,7 +5477,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
private String getRealCallerPackageName(Uri queryUri) {
// If called by another CP2, then the URI should contain the original package name.
- if (calledByAnotherSelf()) {
+ if (isCallerAnotherSelf()) {
final String passedPackage = queryUri.getQueryParameter(
Directory.CALLER_PACKAGE_PARAM_KEY);
if (TextUtils.isEmpty(passedPackage)) {
@@ -5541,18 +5492,6 @@ public class ContactsProvider2 extends AbstractContactsProvider
}
}
- /**
- * Returns true if called by a different user's CP2.
- */
- private boolean calledByAnotherSelf() {
- // Note normally myUid is always different from the callerUid in the code path where
- // this method is used, except during unit tests, where the caller is always the same
- // process.
- final int myUid = android.os.Process.myUid();
- final int callerUid = Binder.getCallingUid();
- return (myUid != callerUid) && UserHandle.isSameApp(myUid, callerUid);
- }
-
private Cursor queryDirectoryAuthority(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder, String directory,
final CancellationSignal cancellationSignal) {
@@ -8525,9 +8464,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
if (!isDirectoryParamValid(uri)){
return null;
}
- if (!isCallerFromSameUser() /* From differnt user */
- && !mEnterprisePolicyGuard.isCrossProfileAllowed(uri)
- /* Policy not allowed */){
+ if (!queryAllowedByEnterprisePolicy(uri)) {
return null;
}
waitForAccess(mode.equals("r") ? mReadAccessLatch : mWriteAccessLatch);
@@ -8545,6 +8482,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
if (VERBOSE_LOGGING) {
Log.v(TAG, "openAssetFile uri=" + uri + " mode=" + mode + " success=" + success +
" CPID=" + Binder.getCallingPid() +
+ " CUID=" + Binder.getCallingUid() +
" User=" + UserUtils.getCurrentUserHandle(getContext()));
}
}
diff --git a/src/com/android/providers/contacts/MetadataEntryParser.java b/src/com/android/providers/contacts/MetadataEntryParser.java
index 1a630a33..2fe423a8 100644
--- a/src/com/android/providers/contacts/MetadataEntryParser.java
+++ b/src/com/android/providers/contacts/MetadataEntryParser.java
@@ -60,8 +60,11 @@ public class MetadataEntryParser {
@NeededForTesting
public static class UsageStats {
+ @NeededForTesting
final String mUsageType;
+ @NeededForTesting
final long mLastTimeUsed;
+ @NeededForTesting
final int mTimesUsed;
@NeededForTesting
@@ -74,9 +77,13 @@ public class MetadataEntryParser {
@NeededForTesting
public static class FieldData {
+ @NeededForTesting
final String mDataHashId;
+ @NeededForTesting
final boolean mIsPrimary;
+ @NeededForTesting
final boolean mIsSuperPrimary;
+ @NeededForTesting
final ArrayList<UsageStats> mUsageStatsList;
@NeededForTesting
@@ -91,9 +98,13 @@ public class MetadataEntryParser {
@NeededForTesting
public static class RawContactInfo {
+ @NeededForTesting
final String mBackupId;
+ @NeededForTesting
final String mAccountType;
+ @NeededForTesting
final String mAccountName;
+ @NeededForTesting
final String mDataSet;
@NeededForTesting
@@ -108,8 +119,11 @@ public class MetadataEntryParser {
@NeededForTesting
public static class AggregationData {
+ @NeededForTesting
final RawContactInfo mRawContactInfo1;
+ @NeededForTesting
final RawContactInfo mRawContactInfo2;
+ @NeededForTesting
final String mType;
@NeededForTesting
@@ -123,11 +137,17 @@ public class MetadataEntryParser {
@NeededForTesting
public static class MetadataEntry {
+ @NeededForTesting
final RawContactInfo mRawContactInfo;
+ @NeededForTesting
final int mSendToVoicemail;
+ @NeededForTesting
final int mStarred;
+ @NeededForTesting
final int mPinned;
+ @NeededForTesting
final ArrayList<FieldData> mFieldDatas;
+ @NeededForTesting
final ArrayList<AggregationData> mAggregationDatas;
@NeededForTesting
diff --git a/src/com/android/providers/contacts/VoicemailContentProvider.java b/src/com/android/providers/contacts/VoicemailContentProvider.java
index 1ced1be6..daecd973 100644
--- a/src/com/android/providers/contacts/VoicemailContentProvider.java
+++ b/src/com/android/providers/contacts/VoicemailContentProvider.java
@@ -22,6 +22,7 @@ import static com.android.providers.contacts.util.DbQueryUtils.concatenateClause
import static com.android.providers.contacts.util.DbQueryUtils.getEqualityClause;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.ContentProvider;
import android.content.ContentValues;
@@ -118,24 +119,24 @@ public class VoicemailContentProvider extends ContentProvider
}
@Override
- protected int enforceReadPermissionInner(Uri uri, String callingPkg, IBinder callerToken)
- throws SecurityException {
+ protected int enforceReadPermissionInner(Uri uri, String callingPkg,
+ @Nullable String featureId, IBinder callerToken) throws SecurityException {
// Permit carrier-privileged apps regardless of ADD_VOICEMAIL permission state.
if (mVoicemailPermissions.callerHasCarrierPrivileges()) {
return MODE_ALLOWED;
}
- return super.enforceReadPermissionInner(uri, callingPkg, callerToken);
+ return super.enforceReadPermissionInner(uri, callingPkg, featureId, callerToken);
}
@Override
- protected int enforceWritePermissionInner(Uri uri, String callingPkg, IBinder callerToken)
- throws SecurityException {
+ protected int enforceWritePermissionInner(Uri uri, String callingPkg,
+ @Nullable String featureId, IBinder callerToken) throws SecurityException {
// Permit carrier-privileged apps regardless of ADD_VOICEMAIL permission state.
if (mVoicemailPermissions.callerHasCarrierPrivileges()) {
return MODE_ALLOWED;
}
- return super.enforceWritePermissionInner(uri, callingPkg, callerToken);
+ return super.enforceWritePermissionInner(uri, callingPkg, featureId, callerToken);
}
@VisibleForTesting
@@ -179,7 +180,8 @@ public class VoicemailContentProvider extends ContentProvider
public Uri insert(Uri uri, ContentValues values) {
if (VERBOSE_LOGGING) {
Log.v(TAG, "insert: uri=" + uri + " values=[" + values + "]" +
- " CPID=" + Binder.getCallingPid());
+ " CPID=" + Binder.getCallingPid() +
+ " CUID=" + Binder.getCallingUid());
}
UriData uriData = checkPermissionsAndCreateUriDataForWrite(uri, values);
return getTableDelegate(uriData).insert(uriData, values);
@@ -198,6 +200,7 @@ public class VoicemailContentProvider extends ContentProvider
Log.v(TAG, "query: uri=" + uri + " projection=" + Arrays.toString(projection) +
" selection=[" + selection + "] args=" + Arrays.toString(selectionArgs) +
" order=[" + sortOrder + "] CPID=" + Binder.getCallingPid() +
+ " CUID=" + Binder.getCallingUid() +
" User=" + UserUtils.getCurrentUserHandle(getContext()));
}
UriData uriData = checkPermissionsAndCreateUriDataForRead(uri);
@@ -213,6 +216,7 @@ public class VoicemailContentProvider extends ContentProvider
Log.v(TAG, "update: uri=" + uri +
" selection=[" + selection + "] args=" + Arrays.toString(selectionArgs) +
" values=[" + values + "] CPID=" + Binder.getCallingPid() +
+ " CUID=" + Binder.getCallingUid() +
" User=" + UserUtils.getCurrentUserHandle(getContext()));
}
UriData uriData = checkPermissionsAndCreateUriDataForWrite(uri, values);
@@ -228,6 +232,7 @@ public class VoicemailContentProvider extends ContentProvider
Log.v(TAG, "delete: uri=" + uri +
" selection=[" + selection + "] args=" + Arrays.toString(selectionArgs) +
" CPID=" + Binder.getCallingPid() +
+ " CUID=" + Binder.getCallingUid() +
" User=" + UserUtils.getCurrentUserHandle(getContext()));
}
UriData uriData = checkPermissionsAndCreateUriDataForWrite(uri);
@@ -254,6 +259,7 @@ public class VoicemailContentProvider extends ContentProvider
if (VERBOSE_LOGGING) {
Log.v(TAG, "openFile uri=" + uri + " mode=" + mode + " success=" + success +
" CPID=" + Binder.getCallingPid() +
+ " CUID=" + Binder.getCallingUid() +
" User=" + UserUtils.getCurrentUserHandle(getContext()));
}
}
diff --git a/test_common/src/com/android/providers/contacts/testutil/DatabaseAsserts.java b/test_common/src/com/android/providers/contacts/testutil/DatabaseAsserts.java
index 2af98299..e0a7836b 100644
--- a/test_common/src/com/android/providers/contacts/testutil/DatabaseAsserts.java
+++ b/test_common/src/com/android/providers/contacts/testutil/DatabaseAsserts.java
@@ -16,6 +16,7 @@
package com.android.providers.contacts.testutil;
+import android.accounts.Account;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.net.Uri;
@@ -50,12 +51,21 @@ public class DatabaseAsserts {
}
/**
- * Create a contact and assert that the record exists.
+ * Create a contact in the local account and assert that the record exists.
*
* @return The created contact id pair.
*/
public static ContactIdPair assertAndCreateContact(ContentResolver resolver) {
- long rawContactId = RawContactUtil.createRawContactWithName(resolver);
+ return assertAndCreateContact(resolver, null);
+ }
+
+ /**
+ * Create a contact in the given account and assert that the record exists.
+ *
+ * @return The created contact id pair.
+ */
+ public static ContactIdPair assertAndCreateContact(ContentResolver resolver, Account account) {
+ long rawContactId = RawContactUtil.createRawContactWithName(resolver, account);
long contactId = RawContactUtil.queryContactIdByRawContactId(resolver, rawContactId);
MoreAsserts.assertNotEqual(CommonDatabaseUtils.NOT_FOUND, contactId);
diff --git a/tests/src/com/android/providers/contacts/ContactsActor.java b/tests/src/com/android/providers/contacts/ContactsActor.java
index 89f296be..804e79a9 100644
--- a/tests/src/com/android/providers/contacts/ContactsActor.java
+++ b/tests/src/com/android/providers/contacts/ContactsActor.java
@@ -96,6 +96,8 @@ public class ContactsActor {
public static final String PACKAGE_GREEN = "com.example.green";
public static final String PACKAGE_BLUE = "org.example.blue";
+ private static final int DEFAULT_USER_ID = 0;
+
public Context context;
public String packageName;
public MockContentResolver resolver;
@@ -158,11 +160,8 @@ public class ContactsActor {
public static class MockUserManager extends UserManager {
public static UserInfo createUserInfo(String name, int id, int groupId, int flags) {
- final UserInfo ui = new UserInfo();
- ui.name = name;
- ui.id = id;
+ final UserInfo ui = new UserInfo(id, name, flags | UserInfo.FLAG_INITIALIZED);
ui.profileGroupId = groupId;
- ui.flags = flags | UserInfo.FLAG_INITIALIZED;
return ui;
}
@@ -173,7 +172,7 @@ public class ContactsActor {
public static final UserInfo SECONDARY_USER = createUserInfo("2nd", 11, 11, 0);
/** "My" user. Set it to change the current user. */
- public int myUser = 0;
+ public int myUser = DEFAULT_USER_ID;
private ArrayList<UserInfo> mUsers = new ArrayList<>();
@@ -399,7 +398,11 @@ public class ContactsActor {
@Override
public int getUserId() {
- return mockUserManager.getUserHandle();
+ if (mockUserManager != null) {
+ return mockUserManager.getUserHandle();
+ } else {
+ return DEFAULT_USER_ID;
+ }
}
@Override
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
index 6421c8f2..d5643d25 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
@@ -3061,16 +3061,16 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
long rawContactId = RawContactUtil.createRawContactWithBackupId(mResolver, backupId,
account);
Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
- // Check if the raw contact is updated.
+ // Check if the raw contact is not updated since Lychee is removed.
assertStoredValue(rawContactUri, RawContacts._ID, rawContactId);
assertStoredValue(rawContactUri, RawContacts.ACCOUNT_TYPE, accountType);
assertStoredValue(rawContactUri, RawContacts.ACCOUNT_NAME, accountName);
assertStoredValue(rawContactUri, RawContacts.BACKUP_ID, backupId);
- assertStoredValue(rawContactUri, RawContacts.SEND_TO_VOICEMAIL, "1");
- assertStoredValue(rawContactUri, RawContacts.STARRED, "1");
- assertStoredValue(rawContactUri, RawContacts.PINNED, "1");
- // Notify metadata network on raw contact insertion
- assertMetadataNetworkNotified(true);
+ assertStoredValue(rawContactUri, RawContacts.SEND_TO_VOICEMAIL, "0");
+ assertStoredValue(rawContactUri, RawContacts.STARRED, "0");
+ assertStoredValue(rawContactUri, RawContacts.PINNED, "0");
+ // No metadata network notify.
+ assertMetadataNetworkNotified(false);
}
public void testUpdateMetadataOnRawContactBackupIdChange() throws Exception {
@@ -3128,15 +3128,15 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
ContentValues updatedValues = new ContentValues();
updatedValues.put(RawContacts.BACKUP_ID, backupId);
mResolver.update(RawContacts.CONTENT_URI, updatedValues, null, null);
- // Check if the raw contact is updated because of backup_id change.
+ // Check if the raw contact is still not updated.
assertStoredValue(rawContactUri, RawContacts._ID, rawContactId);
assertStoredValue(rawContactUri, RawContacts.ACCOUNT_TYPE, accountType);
assertStoredValue(rawContactUri, RawContacts.ACCOUNT_NAME, accountName);
- assertStoredValue(rawContactUri, RawContacts.SEND_TO_VOICEMAIL, "1");
- assertStoredValue(rawContactUri, RawContacts.STARRED, "1");
- assertStoredValue(rawContactUri, RawContacts.PINNED, "1");
- // Notify metadata network because of the changed raw contact.
- assertMetadataNetworkNotified(true);
+ assertStoredValue(rawContactUri, RawContacts.SEND_TO_VOICEMAIL, "0");
+ assertStoredValue(rawContactUri, RawContacts.STARRED, "0");
+ assertStoredValue(rawContactUri, RawContacts.PINNED, "0");
+ // No metadata network notify.
+ assertMetadataNetworkNotified(false);
}
public void testDeleteMetadataOnRawContactDelete() throws Exception {
@@ -3186,12 +3186,12 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
// Delete raw contact.
mResolver.delete(rawContactUri, null, null);
- // Check if the metadata is deleted.
- assertStoredValue(metadataUri, MetadataSync.DELETED, "1");
+ // Check if the metadata is not deleted.
+ assertStoredValue(metadataUri, MetadataSync.DELETED, "0");
// check raw contact metadata_dirty column is not changed on raw contact deletion
assertMetadataDirty(rawContactUri, false);
- // Notify metadata network on raw contact deletion
- assertMetadataNetworkNotified(true);
+ // Lychee removed. Will not notify it.
+ assertMetadataNetworkNotified(false);
// Add another rawcontact and metadata, and don't delete them.
// Insert a raw contact.
@@ -3215,10 +3215,10 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
// Check if the metadata is not marked as deleted.
assertStoredValue(metadataUri2, MetadataSync.DELETED, "0");
- // check raw contact metadata_dirty column is changed on raw contact update
- assertMetadataDirty(rawContactUri2, true);
- // Notify metadata network on raw contact update
- assertMetadataNetworkNotified(true);
+ // Will not set metadata_dirty since Lychee is removed.
+ assertMetadataDirty(rawContactUri2, false);
+ // Will not notify Lychee since it's removed.
+ assertMetadataNetworkNotified(false);
}
public void testPostalsQuery() {
@@ -5210,16 +5210,16 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
updateSendToVoicemailAndRingtone(contactId, true, "foo");
assertSendToVoicemailAndRingtone(contactId, true, "foo");
assertNetworkNotified(false);
- assertMetadataNetworkNotified(true);
+ assertMetadataNetworkNotified(false);
assertDirty(rawContactUri, false);
- assertMetadataDirty(rawContactUri, true);
+ assertMetadataDirty(rawContactUri, false);
updateSendToVoicemailAndRingtoneWithSelection(contactId, false, "bar");
assertSendToVoicemailAndRingtone(contactId, false, "bar");
assertNetworkNotified(false);
- assertMetadataNetworkNotified(true);
+ assertMetadataNetworkNotified(false);
assertDirty(rawContactUri, false);
- assertMetadataDirty(rawContactUri, true);
+ assertMetadataDirty(rawContactUri, false);
}
public void testSendToVoicemailAndRingtoneAfterAggregation() {
@@ -5297,10 +5297,10 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
assertDirty(rawContactUri1, false);
assertDirty(rawContactUri2, false);
- assertMetadataDirty(rawContactUri1, true);
- assertMetadataDirty(rawContactUri2, true);
+ assertMetadataDirty(rawContactUri1, false);
+ assertMetadataDirty(rawContactUri2, false);
assertNetworkNotified(false);
- assertMetadataNetworkNotified(true);
+ assertMetadataNetworkNotified(false);
}
public void testStatusUpdateInsert() {
@@ -6901,7 +6901,7 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
assertDirty(rawContactUri, false);
assertMetadataDirty(rawContactUri, false);
assertNetworkNotified(true);
- assertMetadataNetworkNotified(true);
+ assertMetadataNetworkNotified(false);
// When inserting a rawcontact with metadata.
ContentValues values = new ContentValues();
@@ -6910,9 +6910,9 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
values.put(ContactsContract.RawContacts.ACCOUNT_TYPE, mAccount.type);
Uri rawContactId2Uri = mResolver.insert(RawContacts.CONTENT_URI, values);
assertDirty(rawContactId2Uri, false);
- assertMetadataDirty(rawContactId2Uri, true);
+ assertMetadataDirty(rawContactId2Uri, false);
assertNetworkNotified(true);
- assertMetadataNetworkNotified(true);
+ assertMetadataNetworkNotified(false);
}
public void testRawContactDirtyAndVersion() {
@@ -6934,8 +6934,8 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
assertDirty(uri, false);
assertNetworkNotified(false);
- assertMetadataDirty(uri, true);
- assertMetadataNetworkNotified(true);
+ assertMetadataDirty(uri, false);
+ assertMetadataNetworkNotified(false);
Uri emailUri = insertEmail(rawContactId, "goo@woo.com");
assertDirty(uri, true);
@@ -7005,9 +7005,8 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
long rawContactId = ContentUris.parseId(mResolver.insert(uri, new ContentValues()));
Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
assertMetadataDirty(rawContactUri, false);
- // If the raw contact is inserted by sync adapter, it will notify metadata change no matter
- // if there is any metadata change.
- assertMetadataNetworkNotified(true);
+ // Will not notify Lychee since it's removed.
+ assertMetadataNetworkNotified(false);
}
public void testMarkAsMetadataDirtyForRawContactMetadataChange() {
@@ -7025,8 +7024,8 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
assertStoredValue(contactUri, Contacts.STARRED, 1);
Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
- assertMetadataDirty(rawContactUri, true);
- assertMetadataNetworkNotified(true);
+ assertMetadataDirty(rawContactUri, false);
+ assertMetadataNetworkNotified(false);
clearMetadataDirty(rawContactUri);
values = new ContentValues();
@@ -7034,8 +7033,8 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
mResolver.update(contactUri, values, null, null);
assertStoredValue(contactUri, Contacts.PINNED, 1);
- assertMetadataDirty(rawContactUri, true);
- assertMetadataNetworkNotified(true);
+ assertMetadataDirty(rawContactUri, false);
+ assertMetadataNetworkNotified(false);
clearMetadataDirty(rawContactUri);
values = new ContentValues();
@@ -7043,8 +7042,8 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
mResolver.update(contactUri, values, null, null);
assertStoredValue(contactUri, Contacts.SEND_TO_VOICEMAIL, 1);
- assertMetadataDirty(rawContactUri, true);
- assertMetadataNetworkNotified(true);
+ assertMetadataDirty(rawContactUri, false);
+ assertMetadataNetworkNotified(false);
}
public void testMarkAsMetadataDirtyForRawContactBackupIdChange() {
@@ -7059,15 +7058,15 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
ContentValues values = new ContentValues();
values.put(RawContacts.SEND_TO_VOICEMAIL, "1");
mResolver.update(rawContactUri, values, null, null);
- assertMetadataDirty(rawContactUri, true);
+ assertMetadataDirty(rawContactUri, false);
// Update the backup_id and check metadata network should be notified.
values = new ContentValues();
values.put(RawContacts.BACKUP_ID, "newBackupId");
mResolver.update(rawContactUri, values, null, null);
assertStoredValue(rawContactUri, RawContacts.BACKUP_ID, "newBackupId");
- assertMetadataDirty(rawContactUri, true);
- assertMetadataNetworkNotified(true);
+ assertMetadataDirty(rawContactUri, false);
+ assertMetadataNetworkNotified(false);
}
public void testMarkAsMetadataDirtyForAggregationExceptionChange() {
@@ -7082,10 +7081,10 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
rawContactId1, rawContactId2);
assertMetadataDirty(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1),
- true);
+ false);
assertMetadataDirty(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2),
- true);
- assertMetadataNetworkNotified(true);
+ false);
+ assertMetadataNetworkNotified(false);
}
public void testMarkAsMetadataNotDirtyForUsageStatsChange() {
@@ -7113,8 +7112,8 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
assertStoredValue(mailUri11, Data.IS_PRIMARY, 1);
assertStoredValue(mailUri11, Data.IS_SUPER_PRIMARY, 1);
assertMetadataDirty(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1),
- true);
- assertMetadataNetworkNotified(true);
+ false);
+ assertMetadataNetworkNotified(false);
}
public void testMarkAsMetadataDirtyForDataPrimarySettingUpdate() {
@@ -7133,8 +7132,8 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
mResolver.update(mailUri1, values, null, null);
assertMetadataDirty(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
- true);
- assertMetadataNetworkNotified(true);
+ false);
+ assertMetadataNetworkNotified(false);
}
public void testMarkAsMetadataDirtyForDataDelete() {
@@ -7148,8 +7147,8 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
mResolver.delete(mailUri1, null, null);
assertMetadataDirty(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
- true);
- assertMetadataNetworkNotified(true);
+ false);
+ assertMetadataNetworkNotified(false);
}
public void testDeleteContactWithoutName() {
@@ -7190,6 +7189,98 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
assertEquals(1, mResolver.delete(lookupUri, null, null));
}
+ public void testDeleteContactComposedOfSingleLocalRawContact() {
+ // Create a raw contact in the local (null) account
+ long rawContactId = RawContactUtil.createRawContact(mResolver, null);
+ DataUtil.insertStructuredName(mResolver, rawContactId, "John", "Smith");
+
+ // Delete the contact
+ long contactId = queryContactId(rawContactId);
+ Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
+ assertEquals(1, mResolver.delete(contactUri, null, null));
+
+ // Assert that the raw contact was removed
+ Cursor c1 = queryRawContact(rawContactId);
+ assertEquals(0, c1.getCount());
+ c1.close();
+
+ // Assert that the contact was removed
+ Cursor c2 = mResolver.query(contactUri, null, null, null, "");
+ assertEquals(0, c2.getCount());
+ c2.close();
+ }
+
+ public void testDeleteContactComposedOfTwoLocalRawContacts() {
+ // Create a raw contact in the local (null) account
+ long rawContactId1 = RawContactUtil.createRawContact(mResolver, null);
+ DataUtil.insertStructuredName(mResolver, rawContactId1, "John", "Smith");
+
+ // Create another local raw contact with the same name
+ long rawContactId2 = RawContactUtil.createRawContact(mResolver, null);
+ DataUtil.insertStructuredName(mResolver, rawContactId2, "John", "Smith");
+
+ // Join the two raw contacts explicitly
+ setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
+ rawContactId1, rawContactId2);
+
+ // Check that the two raw contacts are aggregated together
+ assertAggregated(rawContactId1, rawContactId2, "John Smith");
+
+ // Delete the aggregate contact
+ long contactId = queryContactId(rawContactId1);
+ Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
+ assertEquals(1, mResolver.delete(contactUri, null, null));
+
+ // Assert that both of the local raw contacts were removed completely
+ Cursor c1 = queryRawContact(rawContactId1);
+ assertEquals(0, c1.getCount());
+ c1.close();
+
+ Cursor c2 = queryRawContact(rawContactId2);
+ assertEquals(0, c2.getCount());
+ c2.close();
+
+ // Assert that the contact was removed
+ Cursor c3 = queryContact(contactId);
+ assertEquals(0, c3.getCount());
+ c3.close();
+ }
+
+ public void testDeleteContactComposedOfSomeLocalRawContacts() {
+ // Create a raw contact in the local (null) account
+ long rawContactId1 = RawContactUtil.createRawContact(mResolver, null);
+ DataUtil.insertStructuredName(mResolver, rawContactId1, "John", "Smith");
+
+ // Create another one in a non-local account with the same name
+ long rawContactId2 = RawContactUtil.createRawContact(mResolver, mAccount);
+ DataUtil.insertStructuredName(mResolver, rawContactId2, "John", "Smith");
+
+ // Check that the two new raw contacts are aggregated together
+ assertAggregated(rawContactId1, rawContactId2, "John Smith");
+
+ // Delete the aggregate contact
+ long contactId = queryContactId(rawContactId1);
+ Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
+ assertEquals(1, mResolver.delete(contactUri, null, null));
+
+ // Assert that the local raw contact was removed completely
+ Cursor c1 = queryRawContact(rawContactId1);
+ assertEquals(0, c1.getCount());
+ c1.close();
+
+ // Assert that the non-local raw contact is still present just marked as deleted
+ Cursor c2 = queryRawContact(rawContactId2);
+ assertEquals(1, c2.getCount());
+ assertTrue(c2.moveToFirst());
+ assertEquals(1, c2.getInt(c2.getColumnIndex(RawContacts.DELETED)));
+ c2.close();
+
+ // Assert that the contact was removed
+ Cursor c3 = queryContact(contactId);
+ assertEquals(0, c3.getCount());
+ c3.close();
+ }
+
public void testQueryContactWithEscapedUri() {
ContentValues values = new ContentValues();
values.put(RawContacts.SOURCE_ID, "!@#$%^&*()_+=-/.,<>?;'\":[]}{\\|`~");
@@ -8889,7 +8980,7 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
}
public void testContactDelete_marksRawContactsForDeletion() {
- DatabaseAsserts.ContactIdPair ids = assertContactCreateDelete();
+ DatabaseAsserts.ContactIdPair ids = assertContactCreateDelete(mAccount);
String[] projection = new String[]{ContactsContract.RawContacts.DIRTY,
ContactsContract.RawContacts.DELETED};
@@ -8903,7 +8994,7 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
}
public void testContactDelete_checkRawContactContactId() {
- DatabaseAsserts.ContactIdPair ids = assertContactCreateDelete();
+ DatabaseAsserts.ContactIdPair ids = assertContactCreateDelete(mAccount);
String[] projection = new String[]{ContactsContract.RawContacts.CONTACT_ID};
String[] record = RawContactUtil.queryByRawContactId(mResolver, ids.mRawContactId,
@@ -8929,9 +9020,9 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
ContactUtil.update(mResolver, ids.mContactId, values);
assertDirty(rawContactUri, false);
- assertMetadataDirty(rawContactUri, true);
+ assertMetadataDirty(rawContactUri, false);
assertNetworkNotified(false);
- assertMetadataNetworkNotified(true);
+ assertMetadataNetworkNotified(false);
}
public void testContactUpdate_updatesContactUpdatedTimestamp() {
@@ -9144,13 +9235,23 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
}
/**
- * Create a contact. Assert it's not present in the delete log. Delete it.
- * And assert that the contact record is no longer present.
+ * Creates a contact in the local account. Assert it's not present in the delete log.
+ * Delete it. And assert that the contact record is no longer present.
*
* @return The contact id and raw contact id that was created.
*/
private DatabaseAsserts.ContactIdPair assertContactCreateDelete() {
- DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver);
+ return assertContactCreateDelete(null);
+ }
+
+ /**
+ * Creates a contact in the given account. Assert it's not present in the delete log.
+ * Delete it. And assert that the contact record is no longer present.
+ * @return The contact id and raw contact id that was created.
+ */
+ private DatabaseAsserts.ContactIdPair assertContactCreateDelete(Account account) {
+ DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver,
+ account);
assertEquals(CommonDatabaseUtils.NOT_FOUND,
DeletedContactUtil.queryDeletedTimestampForContactId(mResolver, ids.mContactId));