summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFred Quintana <fredq@google.com>2009-10-15 15:50:31 -0700
committerFred Quintana <fredq@google.com>2009-10-15 15:50:31 -0700
commit8dfb33315538e53c0425ae7614b5d4de3600e914 (patch)
tree80b3d5cf91a9b2a5a30585b9699d0ac10e131702
parent54791a59e2dc18ffe9a68ab525f547c2e6aeb8ff (diff)
downloadGoogleContactsProvider-8dfb33315538e53c0425ae7614b5d4de3600e914.tar.gz
remove the old ContactsSyncAdapter and GoogleContactsProvider
-rw-r--r--Android.mk20
-rw-r--r--AndroidManifest.xml33
-rwxr-xr-xres/drawable-hdpi/app_icon.pngbin6818 -> 0 bytes
-rw-r--r--res/drawable-mdpi/app_icon.pngbin2995 -> 0 bytes
-rw-r--r--res/values-cs/strings.xml19
-rw-r--r--res/values-da/strings.xml19
-rw-r--r--res/values-de/strings.xml19
-rw-r--r--res/values-el/strings.xml19
-rw-r--r--res/values-es-rUS/strings.xml19
-rw-r--r--res/values-es/strings.xml19
-rw-r--r--res/values-fr/strings.xml19
-rw-r--r--res/values-it/strings.xml19
-rw-r--r--res/values-ja/strings.xml19
-rw-r--r--res/values-ko/strings.xml19
-rw-r--r--res/values-nb/strings.xml19
-rw-r--r--res/values-nl/strings.xml19
-rw-r--r--res/values-pl/strings.xml19
-rw-r--r--res/values-pt-rPT/strings.xml19
-rw-r--r--res/values-pt/strings.xml19
-rw-r--r--res/values-ru/strings.xml19
-rw-r--r--res/values-sv/strings.xml19
-rw-r--r--res/values-tr/strings.xml19
-rw-r--r--res/values-zh-rCN/strings.xml19
-rw-r--r--res/values-zh-rTW/strings.xml19
-rw-r--r--res/values/strings.xml20
-rw-r--r--res/xml/syncadapter.xml26
-rw-r--r--src/com/android/providers/contacts/ContactsSyncAdapter.java1295
-rw-r--r--src/com/android/providers/contacts/ContactsSyncAdapterService.java29
-rw-r--r--src/com/android/providers/contacts/GoogleContactsProvider.java205
-rw-r--r--tests/Android.mk15
-rw-r--r--tests/AndroidManifest.xml27
-rw-r--r--tests/src/com/android/providers/contacts/ContactsSyncAdapterTest.java870
-rw-r--r--tests/src/com/android/providers/contacts/SyncContactsTest.java142
-rw-r--r--tests/src/com/android/providers/contactstests/SyncContactsInstrumentation.java22
34 files changed, 0 insertions, 3084 deletions
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index f59017c..0000000
--- a/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-contacts_provider_files := ../ContactsProvider/src/com/android/providers/contacts/ContactsProvider.java
-
-LOCAL_SRC_FILES := $(call all-java-files-under,src) $(contacts_provider_files)
-
-LOCAL_JAVA_LIBRARIES := ext
-
-# We depend on googlelogin-client also, but that is already being included by google-framework
-LOCAL_STATIC_JAVA_LIBRARIES := google-framework
-
-LOCAL_PACKAGE_NAME := GoogleContactsProvider
-LOCAL_CERTIFICATE := shared
-
-LOCAL_OVERRIDES_PACKAGES := ContactsProvider
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
deleted file mode 100644
index a66809f..0000000
--- a/AndroidManifest.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.providers.contacts"
- android:sharedUserId="android.uid.shared">
-
- <uses-permission android:name="android.permission.READ_CONTACTS" />
- <uses-permission android:name="android.permission.WRITE_CONTACTS" />
- <uses-permission android:name="android.permission.GET_ACCOUNTS" />
- <uses-permission android:name="android.permission.READ_SYNC_STATS" />
- <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
- <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.USE_CREDENTIALS" />
- <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
- <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.cp" />
- <uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_READ" />
- <uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE" />
-
- <application android:process="android.process.acore"
- android:label="@string/app_label"
- android:icon="@drawable/app_icon">
- <provider android:name="GoogleContactsProvider" android:authorities="contacts;call_log"
- android:syncable="true" android:multiprocess="false"
- android:readPermission="android.permission.READ_CONTACTS"
- android:writePermission="android.permission.WRITE_CONTACTS" />
- <service android:name="ContactsSyncAdapterService" android:exported="true">
- <intent-filter>
- <action android:name="android.content.SyncAdapter" />
- </intent-filter>
- <meta-data android:name="android.content.SyncAdapter"
- android:resource="@xml/syncadapter" />
- </service>
- </application>
-</manifest>
diff --git a/res/drawable-hdpi/app_icon.png b/res/drawable-hdpi/app_icon.png
deleted file mode 100755
index 0bcbca4..0000000
--- 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 826656f..0000000
--- a/res/drawable-mdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
deleted file mode 100644
index a76af52..0000000
--- a/res/values-cs/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Úložiště kontaktů"</string>
-</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
deleted file mode 100644
index c65fed4..0000000
--- a/res/values-da/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Lagring af kontakter"</string>
-</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
deleted file mode 100644
index 4a21e6e..0000000
--- a/res/values-de/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Kontakte-Speicher"</string>
-</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
deleted file mode 100644
index 31b89b4..0000000
--- a/res/values-el/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Χώρος αποθήκευσης επαφών"</string>
-</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
deleted file mode 100644
index 0170e69..0000000
--- a/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Espacio de almacenamiento para Contactos"</string>
-</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
deleted file mode 100644
index 3a0ebc7..0000000
--- a/res/values-es/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Información de los contactos"</string>
-</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
deleted file mode 100644
index d36d9ff..0000000
--- a/res/values-fr/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Liste des contacts"</string>
-</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
deleted file mode 100644
index fe2b515..0000000
--- a/res/values-it/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Archiviazione contatti"</string>
-</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
deleted file mode 100644
index ae23f6a..0000000
--- a/res/values-ja/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"アドレス帳"</string>
-</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
deleted file mode 100644
index ce2dc72..0000000
--- a/res/values-ko/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"주소록 저장소"</string>
-</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
deleted file mode 100644
index 14733fb..0000000
--- a/res/values-nb/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Kontaktlager"</string>
-</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
deleted file mode 100644
index 8117b29..0000000
--- a/res/values-nl/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Opslag contacten"</string>
-</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
deleted file mode 100644
index 969cfb1..0000000
--- a/res/values-pl/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Spis kontaktów"</string>
-</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
deleted file mode 100644
index 7e34855..0000000
--- a/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Armazenamento de contactos"</string>
-</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
deleted file mode 100644
index 81cd411..0000000
--- a/res/values-pt/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Armazenamento de contatos"</string>
-</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
deleted file mode 100644
index 9b296d9..0000000
--- a/res/values-ru/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Хранилище контактов"</string>
-</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
deleted file mode 100644
index 7cfd0e0..0000000
--- a/res/values-sv/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Kontakter"</string>
-</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
deleted file mode 100644
index f8db006..0000000
--- a/res/values-tr/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"Kişi Deposu"</string>
-</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
deleted file mode 100644
index 64b5bc8..0000000
--- a/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"联系人存储"</string>
-</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
deleted file mode 100644
index 14da964..0000000
--- a/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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="app_label" msgid="8174768630168497947">"聯絡人儲存空間"</string>
-</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
deleted file mode 100644
index 2ef1c9a..0000000
--- a/res/values/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- This is the label for the application that stores contacts data -->
- <string name="app_label">Contacts Storage</string>
-</resources>
diff --git a/res/xml/syncadapter.xml b/res/xml/syncadapter.xml
deleted file mode 100644
index d46be9a..0000000
--- a/res/xml/syncadapter.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?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.
- */
--->
-
-<!-- The attributes in this XML file provide configuration information -->
-<!-- for the SyncAdapter. -->
-
-<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
- android:contentAuthority="contacts"
- android:accountType="com.google"
-/>
diff --git a/src/com/android/providers/contacts/ContactsSyncAdapter.java b/src/com/android/providers/contacts/ContactsSyncAdapter.java
deleted file mode 100644
index c15f2da..0000000
--- a/src/com/android/providers/contacts/ContactsSyncAdapter.java
+++ /dev/null
@@ -1,1295 +0,0 @@
-/*
-** Copyright 2007, 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,
-** See the License for the specific language governing permissions and
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** limitations under the License.
-*/
-
-package com.android.providers.contacts;
-
-import com.google.android.collect.Sets;
-import com.google.android.gdata.client.AndroidGDataClient;
-import com.google.android.gdata.client.AndroidXmlParserFactory;
-import com.google.android.providers.AbstractGDataSyncAdapter;
-import com.google.wireless.gdata.client.GDataServiceClient;
-import com.google.wireless.gdata.client.QueryParams;
-import com.google.wireless.gdata.client.HttpException;
-import com.google.wireless.gdata.contacts.client.ContactsClient;
-import com.google.wireless.gdata.contacts.data.ContactEntry;
-import com.google.wireless.gdata.contacts.data.ContactsElement;
-import com.google.wireless.gdata.contacts.data.EmailAddress;
-import com.google.wireless.gdata.contacts.data.GroupEntry;
-import com.google.wireless.gdata.contacts.data.GroupMembershipInfo;
-import com.google.wireless.gdata.contacts.data.ImAddress;
-import com.google.wireless.gdata.contacts.data.Organization;
-import com.google.wireless.gdata.contacts.data.PhoneNumber;
-import com.google.wireless.gdata.contacts.data.PostalAddress;
-import com.google.wireless.gdata.contacts.parser.xml.XmlContactsGDataParserFactory;
-import com.google.wireless.gdata.data.Entry;
-import com.google.wireless.gdata.data.ExtendedProperty;
-import com.google.wireless.gdata.data.Feed;
-import com.google.wireless.gdata.data.MediaEntry;
-import com.google.wireless.gdata.parser.ParseException;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.SyncContext;
-import android.content.SyncResult;
-import android.content.SyncableContentProvider;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.SystemProperties;
-import android.provider.Contacts;
-import android.provider.Contacts.ContactMethods;
-import android.provider.Contacts.Extensions;
-import android.provider.Contacts.GroupMembership;
-import android.provider.Contacts.Groups;
-import android.provider.Contacts.Organizations;
-import android.provider.Contacts.People;
-import android.provider.Contacts.Phones;
-import android.provider.Contacts.Photos;
-import android.provider.SubscribedFeeds;
-import android.provider.SyncConstValue;
-import android.text.TextUtils;
-import android.util.Config;
-import android.util.Log;
-import android.accounts.AccountManager;
-import android.accounts.Account;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Implements a SyncAdapter for Contacts
- */
-public class ContactsSyncAdapter extends AbstractGDataSyncAdapter {
-
- private static final String USER_AGENT_APP_VERSION = "Android-GData-Contacts/1.1";
-
- private static final String CONTACTS_FEED_URL = "http://www.google.com/m8/feeds/contacts/";
- private static final String GROUPS_FEED_URL = "http://www.google.com/m8/feeds/groups/";
- private static final String PHOTO_FEED_URL = "http://www.google.com/m8/feeds/photos/media/";
-
- private final ContactsClient mContactsClient;
-
- private static final String[] sSubscriptionProjection =
- new String[] {
- SubscribedFeeds.Feeds._SYNC_ACCOUNT,
- SubscribedFeeds.Feeds.FEED,
- SubscribedFeeds.Feeds._ID};
-
- private static final HashMap<Byte, Integer> ENTRY_TYPE_TO_PROVIDER_PHONE;
- private static final HashMap<Byte, Integer> ENTRY_TYPE_TO_PROVIDER_EMAIL;
- private static final HashMap<Byte, Integer> ENTRY_TYPE_TO_PROVIDER_IM;
- private static final HashMap<Byte, Integer> ENTRY_TYPE_TO_PROVIDER_POSTAL;
- private static final HashMap<Byte, Integer> ENTRY_TYPE_TO_PROVIDER_ORGANIZATION;
- private static final HashMap<Integer, Byte> PROVIDER_TYPE_TO_ENTRY_PHONE;
- private static final HashMap<Integer, Byte> PROVIDER_TYPE_TO_ENTRY_EMAIL;
- private static final HashMap<Integer, Byte> PROVIDER_TYPE_TO_ENTRY_IM;
- private static final HashMap<Integer, Byte> PROVIDER_TYPE_TO_ENTRY_POSTAL;
- private static final HashMap<Integer, Byte> PROVIDER_TYPE_TO_ENTRY_ORGANIZATION;
-
- private static final HashMap<Byte, Integer> ENTRY_IM_PROTOCOL_TO_PROVIDER_PROTOCOL;
- private static final HashMap<Integer, Byte> PROVIDER_IM_PROTOCOL_TO_ENTRY_PROTOCOL;
-
- private static final int MAX_MEDIA_ENTRIES_PER_SYNC = 10;
-
- // Only valid during a sync operation.
- // If set then a getServerDiffs() was performed during this sync.
- private boolean mPerformedGetServerDiffs;
-
- // Only valid during a sync. If set then this sync was a forced sync request
- private boolean mIsManualSync;
-
- private int mPhotoDownloads;
- private int mPhotoUploads;
-
- private static final String IMAGE_MIME_TYPE = "image/*";
-
- static {
- HashMap<Byte, Integer> map;
-
- map = new HashMap<Byte, Integer>();
- map.put(ImAddress.PROTOCOL_AIM, ContactMethods.PROTOCOL_AIM);
- map.put(ImAddress.PROTOCOL_GOOGLE_TALK, ContactMethods.PROTOCOL_GOOGLE_TALK);
- map.put(ImAddress.PROTOCOL_ICQ, ContactMethods.PROTOCOL_ICQ);
- map.put(ImAddress.PROTOCOL_JABBER, ContactMethods.PROTOCOL_JABBER);
- map.put(ImAddress.PROTOCOL_MSN, ContactMethods.PROTOCOL_MSN);
- map.put(ImAddress.PROTOCOL_QQ, ContactMethods.PROTOCOL_QQ);
- map.put(ImAddress.PROTOCOL_SKYPE, ContactMethods.PROTOCOL_SKYPE);
- map.put(ImAddress.PROTOCOL_YAHOO, ContactMethods.PROTOCOL_YAHOO);
- ENTRY_IM_PROTOCOL_TO_PROVIDER_PROTOCOL = map;
- PROVIDER_IM_PROTOCOL_TO_ENTRY_PROTOCOL = swapMap(map);
-
- map = new HashMap<Byte, Integer>();
- map.put(EmailAddress.TYPE_HOME, ContactMethods.TYPE_HOME);
- map.put(EmailAddress.TYPE_WORK, ContactMethods.TYPE_WORK);
- map.put(EmailAddress.TYPE_OTHER, ContactMethods.TYPE_OTHER);
- map.put(EmailAddress.TYPE_NONE, ContactMethods.TYPE_CUSTOM);
- ENTRY_TYPE_TO_PROVIDER_EMAIL = map;
- PROVIDER_TYPE_TO_ENTRY_EMAIL = swapMap(map);
-
- map = new HashMap<Byte, Integer>();
- map.put(PhoneNumber.TYPE_HOME, Phones.TYPE_HOME);
- map.put(PhoneNumber.TYPE_MOBILE, Phones.TYPE_MOBILE);
- map.put(PhoneNumber.TYPE_PAGER, Phones.TYPE_PAGER);
- map.put(PhoneNumber.TYPE_WORK, Phones.TYPE_WORK);
- map.put(PhoneNumber.TYPE_HOME_FAX, Phones.TYPE_FAX_HOME);
- map.put(PhoneNumber.TYPE_WORK_FAX, Phones.TYPE_FAX_WORK);
- map.put(PhoneNumber.TYPE_OTHER, Phones.TYPE_OTHER);
- map.put(PhoneNumber.TYPE_NONE, Phones.TYPE_CUSTOM);
- ENTRY_TYPE_TO_PROVIDER_PHONE = map;
- PROVIDER_TYPE_TO_ENTRY_PHONE = swapMap(map);
-
- map = new HashMap<Byte, Integer>();
- map.put(PostalAddress.TYPE_HOME, ContactMethods.TYPE_HOME);
- map.put(PostalAddress.TYPE_WORK, ContactMethods.TYPE_WORK);
- map.put(PostalAddress.TYPE_OTHER, ContactMethods.TYPE_OTHER);
- map.put(PostalAddress.TYPE_NONE, ContactMethods.TYPE_CUSTOM);
- ENTRY_TYPE_TO_PROVIDER_POSTAL = map;
- PROVIDER_TYPE_TO_ENTRY_POSTAL = swapMap(map);
-
- map = new HashMap<Byte, Integer>();
- map.put(ImAddress.TYPE_HOME, ContactMethods.TYPE_HOME);
- map.put(ImAddress.TYPE_WORK, ContactMethods.TYPE_WORK);
- map.put(ImAddress.TYPE_OTHER, ContactMethods.TYPE_OTHER);
- map.put(ImAddress.TYPE_NONE, ContactMethods.TYPE_CUSTOM);
- ENTRY_TYPE_TO_PROVIDER_IM = map;
- PROVIDER_TYPE_TO_ENTRY_IM = swapMap(map);
-
- map = new HashMap<Byte, Integer>();
- map.put(Organization.TYPE_WORK, Organizations.TYPE_WORK);
- map.put(Organization.TYPE_OTHER, Organizations.TYPE_OTHER);
- map.put(Organization.TYPE_NONE, Organizations.TYPE_CUSTOM);
- ENTRY_TYPE_TO_PROVIDER_ORGANIZATION = map;
- PROVIDER_TYPE_TO_ENTRY_ORGANIZATION = swapMap(map);
- }
-
- private static <A, B> HashMap<B, A> swapMap(HashMap<A, B> originalMap) {
- HashMap<B, A> newMap = new HashMap<B,A>();
- for (Map.Entry<A, B> entry : originalMap.entrySet()) {
- final B originalValue = entry.getValue();
- if (newMap.containsKey(originalValue)) {
- throw new IllegalArgumentException("value " + originalValue
- + " was already encountered");
- }
- newMap.put(originalValue, entry.getKey());
- }
- return newMap;
- }
-
- protected ContactsSyncAdapter(Context context, SyncableContentProvider provider) {
- super(context, provider);
- mContactsClient = new ContactsClient(
- new AndroidGDataClient(context, USER_AGENT_APP_VERSION),
- new XmlContactsGDataParserFactory(new AndroidXmlParserFactory()));
- }
-
- protected GDataServiceClient getGDataServiceClient() {
- return mContactsClient;
- }
-
- @Override
- protected Entry newEntry() {
- throw new UnsupportedOperationException("this should never be used");
- }
-
- protected String getFeedUrl(Account account) {
- throw new UnsupportedOperationException("this should never be used");
- }
-
- protected Class getFeedEntryClass() {
- throw new UnsupportedOperationException("this should never be used");
- }
-
- protected Class getFeedEntryClass(String feed) {
- if (feed.startsWith(rewriteUrlforAccount(getAccount(), GROUPS_FEED_URL))) {
- return GroupEntry.class;
- }
- if (feed.startsWith(rewriteUrlforAccount(getAccount(), CONTACTS_FEED_URL))) {
- return ContactEntry.class;
- }
- return null;
- }
-
- @Override
- public void getServerDiffs(SyncContext context, SyncData baseSyncData,
- SyncableContentProvider tempProvider,
- Bundle extras, Object syncInfo, SyncResult syncResult) {
- mPerformedGetServerDiffs = true;
- GDataSyncData syncData = (GDataSyncData)baseSyncData;
-
- ArrayList<String> feedsToSync = new ArrayList<String>();
-
- if (extras != null && extras.containsKey("feed")) {
- feedsToSync.add((String) extras.get("feed"));
- } else {
- feedsToSync.add(getGroupsFeedForAccount(getAccount()));
- addContactsFeedsToSync(getContext().getContentResolver(), getAccount(), feedsToSync);
- feedsToSync.add(getPhotosFeedForAccount(getAccount()));
- }
-
- for (String feed : feedsToSync) {
- context.setStatusText("Downloading\u2026");
- if (getPhotosFeedForAccount(getAccount()).equals(feed)) {
- getServerPhotos(context, feed, MAX_MEDIA_ENTRIES_PER_SYNC, syncData, syncResult);
- } else {
- final Class feedEntryClass = getFeedEntryClass(feed);
- if (feedEntryClass != null) {
- getServerDiffsImpl(context, tempProvider, feedEntryClass,
- feed, null, getMaxEntriesPerSync(), syncData, syncResult);
- } else {
- if (Config.LOGD) {
- Log.d(TAG, "ignoring sync request for unknown feed " + feed);
- }
- }
- }
- if (syncResult.hasError()) {
- break;
- }
- }
- }
-
- /**
- * Look at the groups sync settings and the overall sync preference to determine which
- * feeds to sync and add them to the feedsToSync list.
- */
- public static void addContactsFeedsToSync(ContentResolver cr, Account account,
- Collection<String> feedsToSync) {
- boolean shouldSyncEverything = getShouldSyncEverything(cr, account);
- if (shouldSyncEverything) {
- feedsToSync.add(getContactsFeedForAccount(account));
- return;
- }
-
- Cursor cursor = cr.query(Contacts.Groups.CONTENT_URI, new String[]{Groups._SYNC_ID},
- "_sync_account=? AND _sync_account_type=? AND should_sync>0",
- new String[]{account.name, account.type}, null);
- try {
- while (cursor.moveToNext()) {
- feedsToSync.add(getContactsFeedForGroup(account, cursor.getString(0)));
- }
- } finally {
- cursor.close();
- }
- }
-
- private static boolean getShouldSyncEverything(ContentResolver cr, Account account) {
- // TODO(fredq) should be using account instead of null
- String value = Contacts.Settings.getSetting(cr, null, Contacts.Settings.SYNC_EVERYTHING);
- return !TextUtils.isEmpty(value) && !"0".equals(value);
- }
-
- private void getServerPhotos(SyncContext context, String feedUrl, int maxDownloads,
- GDataSyncData syncData, SyncResult syncResult) {
- final ContentResolver cr = getContext().getContentResolver();
- final Account account = getAccount();
- Cursor cursor = cr.query(
- Photos.CONTENT_URI,
- new String[]{Photos._SYNC_ID, Photos._SYNC_VERSION, Photos.PERSON_ID,
- Photos.DOWNLOAD_REQUIRED, Photos._ID}, ""
- + "_sync_account=? AND _sync_account_type=? AND download_required != 0",
- new String[]{account.name, account.type}, null);
- try {
- int numFetched = 0;
- while (cursor.moveToNext()) {
- if (numFetched >= maxDownloads) {
- break;
- }
- String photoSyncId = cursor.getString(0);
- String photoVersion = cursor.getString(1);
- long person = cursor.getLong(2);
- String photoUrl = feedUrl + "/" + photoSyncId;
- long photoId = cursor.getLong(4);
-
- try {
- context.setStatusText("Downloading photo " + photoSyncId);
- ++numFetched;
- ++mPhotoDownloads;
- InputStream inputStream = mContactsClient.getMediaEntryAsStream(
- photoUrl, getAuthToken());
- savePhoto(person, inputStream, photoVersion);
- syncResult.stats.numUpdates++;
- } catch (IOException e) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.d(TAG, "error downloading " + photoUrl, e);
- }
- syncResult.stats.numIoExceptions++;
- return;
- } catch (HttpException e) {
- switch (e.getStatusCode()) {
- case HttpException.SC_UNAUTHORIZED:
- if (Config.LOGD) {
- Log.d(TAG, "not authorized to download " + photoUrl, e);
- }
- syncResult.stats.numAuthExceptions++;
- return;
- case HttpException.SC_FORBIDDEN:
- case HttpException.SC_NOT_FOUND:
- final String exceptionMessage = e.getMessage();
- if (Config.LOGD) {
- Log.d(TAG, "unable to download photo " + photoUrl + ", "
- + exceptionMessage + ", ignoring");
- }
- ContentValues values = new ContentValues();
- values.put(Photos.SYNC_ERROR, exceptionMessage);
- Uri photoUri = Uri.withAppendedPath(
- ContentUris.withAppendedId(People.CONTENT_URI, photoId),
- Photos.CONTENT_DIRECTORY);
- cr.update(photoUri, values, null /* where */, null /* where args */);
- break;
- default:
- if (Config.LOGD) {
- Log.d(TAG, "error downloading " + photoUrl, e);
- }
- syncResult.stats.numIoExceptions++;
- return;
- }
- }
- }
- final boolean hasMoreToSync = numFetched < cursor.getCount();
- GDataSyncData.FeedData feedData =
- new GDataSyncData.FeedData(0 /* no update time */,
- numFetched, hasMoreToSync, null /* no lastId */,
- 0 /* no feed index */);
- syncData.feedData.put(feedUrl, feedData);
- } finally {
- cursor.close();
- }
- }
-
- @Override
- protected void getStatsString(StringBuffer sb, SyncResult result) {
- super.getStatsString(sb, result);
- if (mPhotoUploads > 0) {
- sb.append("p").append(mPhotoUploads);
- }
- if (mPhotoDownloads > 0) {
- sb.append("P").append(mPhotoDownloads);
- }
- }
-
- @Override
- public void sendClientDiffs(SyncContext context, SyncableContentProvider clientDiffs,
- SyncableContentProvider serverDiffs, SyncResult syncResult,
- boolean dontSendDeletes) {
- initTempProvider(clientDiffs);
-
- sendClientDiffsImpl(context, clientDiffs, new GroupEntry(), null /* no syncInfo */,
- serverDiffs, syncResult, dontSendDeletes);
-
- // lets go ahead and commit what we have if we successfully made a change
- if (syncResult.madeSomeProgress()) {
- return;
- }
-
- sendClientPhotos(context, clientDiffs, null /* no syncInfo */, syncResult);
-
- // lets go ahead and commit what we have if we successfully made a change
- if (syncResult.madeSomeProgress()) {
- return;
- }
-
- sendClientDiffsImpl(context, clientDiffs, new ContactEntry(), null /* no syncInfo */,
- serverDiffs, syncResult, dontSendDeletes);
- }
-
- protected void sendClientPhotos(SyncContext context, ContentProvider clientDiffs,
- Object syncInfo, SyncResult syncResult) {
- Entry entry = new MediaEntry();
-
- GDataServiceClient client = getGDataServiceClient();
- String authToken = getAuthToken();
- ContentResolver cr = getContext().getContentResolver();
- final Account account = getAccount();
-
- Cursor c = clientDiffs.query(Photos.CONTENT_URI, null /* all columns */,
- null /* no where */, null /* no where args */, null /* default sort order */);
- try {
- int personColumn = c.getColumnIndexOrThrow(Photos.PERSON_ID);
- int dataColumn = c.getColumnIndexOrThrow(Photos.DATA);
- int numRows = c.getCount();
- while (c.moveToNext()) {
- if (mSyncCanceled) {
- if (Config.LOGD) Log.d(TAG, "stopping since the sync was canceled");
- break;
- }
-
- entry.clear();
- context.setStatusText("Updating, " + (numRows - 1) + " to go");
-
- cursorToBaseEntry(entry, account, c);
- String editUrl = entry.getEditUri();
-
- if (TextUtils.isEmpty(editUrl)) {
- if (Config.LOGD) {
- Log.d(TAG, "skipping photo edit for unsynced contact");
- }
- continue;
- }
-
- // Send the request and receive the response
- InputStream inputStream = null;
- byte[] imageData = c.getBlob(dataColumn);
- if (imageData != null) {
- inputStream = new ByteArrayInputStream(imageData);
- }
- Uri photoUri = Uri.withAppendedPath(People.CONTENT_URI,
- c.getString(personColumn) + "/" + Photos.CONTENT_DIRECTORY);
- try {
- if (inputStream != null) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Updating photo " + entry.toString());
- }
- ++mPhotoUploads;
- client.updateMediaEntry(editUrl, inputStream, IMAGE_MIME_TYPE, authToken);
- } else {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Deleting photo " + entry.toString());
- }
- client.deleteEntry(editUrl, authToken);
- }
-
- // Mark that this photo is no longer dirty. The next time we sync (which
- // should be soon), we will get the new version of the photo and whether
- // or not there is a new one to download (e.g. if we deleted our version
- // yet there is an evergreen version present).
- ContentValues values = new ContentValues();
- values.put(Photos.EXISTS_ON_SERVER, inputStream == null ? 0 : 1);
- values.put(Photos._SYNC_DIRTY, 0);
- if (cr.update(photoUri, values,
- null /* no where */, null /* no where args */) != 1) {
- Log.e(TAG, "error updating photo " + photoUri + " with values " + values);
- syncResult.stats.numParseExceptions++;
- } else {
- syncResult.stats.numUpdates++;
- }
- continue;
- } catch (ParseException e) {
- Log.e(TAG, "parse error during update of " + ", skipping");
- syncResult.stats.numParseExceptions++;
- } catch (IOException e) {
- if (Config.LOGD) {
- Log.d(TAG, "io error during update of " + entry.toString()
- + ", skipping");
- }
- syncResult.stats.numIoExceptions++;
- } catch (HttpException e) {
- switch (e.getStatusCode()) {
- case HttpException.SC_UNAUTHORIZED:
- if (syncResult.stats.numAuthExceptions == 0) {
- if (Config.LOGD) {
- Log.d(TAG, "auth error during update of " + entry
- + ", skipping");
- }
- }
- syncResult.stats.numAuthExceptions++;
- AccountManager.get(getContext()).invalidateAuthToken(
- "com.google", authToken);
- return;
-
- case HttpException.SC_CONFLICT:
- if (Config.LOGD) {
- Log.d(TAG, "conflict detected during update of " + entry
- + ", skipping");
- }
- syncResult.stats.numConflictDetectedExceptions++;
- break;
- case HttpException.SC_BAD_REQUEST:
- case HttpException.SC_FORBIDDEN:
- case HttpException.SC_NOT_FOUND:
- case HttpException.SC_INTERNAL_SERVER_ERROR:
- default:
- if (Config.LOGD) {
- Log.d(TAG, "error " + e.getMessage() + " during update of "
- + entry.toString() + ", skipping");
- }
- syncResult.stats.numIoExceptions++;
- }
- }
- }
- } finally {
- c.close();
- }
- }
-
- @Override
- protected Cursor getCursorForTable(ContentProvider cp, Class entryClass) {
- return getCursorForTableImpl(cp, entryClass);
- }
-
- protected static Cursor getCursorForTableImpl(ContentProvider cp, Class entryClass) {
- if (entryClass == ContactEntry.class) {
- return cp.query(People.CONTENT_URI, null, null, null, null);
- }
- if (entryClass == GroupEntry.class) {
- return cp.query(Groups.CONTENT_URI, null, null, null, null);
- }
- throw new IllegalArgumentException("unexpected entry class, " + entryClass.getName());
- }
-
- @Override
- protected Cursor getCursorForDeletedTable(ContentProvider cp, Class entryClass) {
- return getCursorForDeletedTableImpl(cp, entryClass);
- }
-
- protected static Cursor getCursorForDeletedTableImpl(ContentProvider cp, Class entryClass) {
- if (entryClass == ContactEntry.class) {
- return cp.query(People.DELETED_CONTENT_URI, null, null, null, null);
- }
- if (entryClass == GroupEntry.class) {
- return cp.query(Groups.DELETED_CONTENT_URI, null, null, null, null);
- }
- throw new IllegalArgumentException("unexpected entry class, " + entryClass.getName());
- }
-
- @Override
- protected String cursorToEntry(SyncContext context, Cursor c, Entry baseEntry,
- Object syncInfo) throws ParseException {
- return cursorToEntryImpl(getContext().getContentResolver(), c, baseEntry, getAccount());
- }
-
- static protected String cursorToEntryImpl(ContentResolver cr, Cursor c, Entry entry,
- Account account) throws ParseException {
- cursorToBaseEntry(entry, account, c);
- String createUrl = null;
- if (entry instanceof ContactEntry) {
- cursorToContactEntry(account, cr, c, (ContactEntry) entry);
- if (entry.getEditUri() == null) {
- createUrl = getContactsFeedForAccount(account);
- }
- } else if (entry instanceof MediaEntry) {
- if (entry.getEditUri() == null) {
- createUrl = getPhotosFeedForAccount(account);
- }
- } else {
- cursorToGroupEntry(c, (GroupEntry) entry);
- if (entry.getEditUri() == null) {
- createUrl = getGroupsFeedForAccount(account);
- }
- }
-
- return createUrl;
- }
-
- private static void cursorToGroupEntry(Cursor c, GroupEntry entry) throws ParseException {
- if (!TextUtils.isEmpty(c.getString(c.getColumnIndexOrThrow(Groups.SYSTEM_ID)))) {
- throw new ParseException("unable to modify system groups");
- }
- entry.setTitle(c.getString(c.getColumnIndexOrThrow(Groups.NAME)));
- entry.setContent(c.getString(c.getColumnIndexOrThrow(Groups.NOTES)));
- entry.setSystemGroup(null);
- }
-
- private static void cursorToContactEntry(Account account, ContentResolver cr, Cursor c,
- ContactEntry entry)
- throws ParseException {
- entry.setTitle(c.getString(c.getColumnIndexOrThrow(People.NAME)));
- entry.setContent(c.getString(c.getColumnIndexOrThrow(People.NOTES)));
- entry.setYomiName(c.getString(c.getColumnIndexOrThrow(People.PHONETIC_NAME)));
-
- long syncLocalId = c.getLong(c.getColumnIndexOrThrow(SyncConstValue._SYNC_LOCAL_ID));
- addContactMethodsToContactEntry(cr, syncLocalId, entry);
- addPhonesToContactEntry(cr, syncLocalId, entry);
- addOrganizationsToContactEntry(cr, syncLocalId, entry);
- addGroupMembershipToContactEntry(account, cr, syncLocalId, entry);
- addExtensionsToContactEntry(cr, syncLocalId, entry);
- }
-
- @Override
- protected void deletedCursorToEntry(SyncContext context, Cursor c, Entry entry) {
- deletedCursorToEntryImpl(c, entry, getAccount());
- }
-
- protected boolean handleAllDeletedUnavailable(GDataSyncData syncData, String feed) {
- // Contacts has no way to clear the contacts for just a given feed so it is unable
- // to handle this condition itself. Instead it returns false, which tell the
- // sync framework that it must handle it.
- return false;
- }
-
- protected static void deletedCursorToEntryImpl(Cursor c, Entry entry, Account account) {
- cursorToBaseEntry(entry, account, c);
- }
-
- private static void cursorToBaseEntry(Entry entry, Account account, Cursor c) {
- String feedUrl;
- if (entry instanceof ContactEntry) {
- feedUrl = getContactsFeedForAccount(account);
- } else if (entry instanceof GroupEntry) {
- feedUrl = getGroupsFeedForAccount(account);
- } else if (entry instanceof MediaEntry) {
- feedUrl = getPhotosFeedForAccount(account);
- } else {
- throw new IllegalArgumentException("bad entry type: " + entry.getClass().getName());
- }
-
- String syncId = c.getString(c.getColumnIndexOrThrow(SyncConstValue._SYNC_ID));
- if (syncId != null) {
- String syncVersion = c.getString(c.getColumnIndexOrThrow(SyncConstValue._SYNC_VERSION));
- entry.setId(feedUrl + "/" + syncId);
- entry.setEditUri(entry.getId() + "/" + syncVersion);
- }
- }
-
- private static void addPhonesToContactEntry(ContentResolver cr, long personId,
- ContactEntry entry)
- throws ParseException {
- Cursor c = cr.query(Phones.CONTENT_URI, null, "person=" + personId, null, null);
- int numberIndex = c.getColumnIndexOrThrow(People.Phones.NUMBER);
- try {
- while (c.moveToNext()) {
- PhoneNumber phoneNumber = new PhoneNumber();
- cursorToContactsElement(phoneNumber, c, PROVIDER_TYPE_TO_ENTRY_PHONE);
- phoneNumber.setPhoneNumber(c.getString(numberIndex));
- entry.addPhoneNumber(phoneNumber);
- }
- } finally {
- if (c != null) c.close();
- }
- }
-
-
- static private void addContactMethodsToContactEntry(ContentResolver cr, long personId,
- ContactEntry entry) throws ParseException {
- Cursor c = cr.query(ContactMethods.CONTENT_URI, null,
- "person=" + personId, null, null);
- int kindIndex = c.getColumnIndexOrThrow(ContactMethods.KIND);
- int dataIndex = c.getColumnIndexOrThrow(ContactMethods.DATA);
- int auxDataIndex = c.getColumnIndexOrThrow(ContactMethods.AUX_DATA);
- try {
- while (c.moveToNext()) {
- int kind = c.getInt(kindIndex);
- switch (kind) {
- case Contacts.KIND_IM: {
- ImAddress address = new ImAddress();
- cursorToContactsElement(address, c, PROVIDER_TYPE_TO_ENTRY_IM);
- address.setAddress(c.getString(dataIndex));
- Object object = ContactMethods.decodeImProtocol(c.getString(auxDataIndex));
- if (object == null) {
- address.setProtocolPredefined(ImAddress.PROTOCOL_NONE);
- } else if (object instanceof Integer) {
- address.setProtocolPredefined(
- PROVIDER_IM_PROTOCOL_TO_ENTRY_PROTOCOL.get((Integer)object));
- } else {
- if (!(object instanceof String)) {
- throw new IllegalArgumentException("expected an String, " + object);
- }
- address.setProtocolPredefined(ImAddress.PROTOCOL_CUSTOM);
- address.setProtocolCustom((String)object);
- }
- entry.addImAddress(address);
- break;
- }
- case Contacts.KIND_POSTAL: {
- PostalAddress address = new PostalAddress();
- cursorToContactsElement(address, c, PROVIDER_TYPE_TO_ENTRY_POSTAL);
- address.setValue(c.getString(dataIndex));
- entry.addPostalAddress(address);
- break;
- }
- case Contacts.KIND_EMAIL: {
- EmailAddress address = new EmailAddress();
- cursorToContactsElement(address, c, PROVIDER_TYPE_TO_ENTRY_EMAIL);
- address.setAddress(c.getString(dataIndex));
- entry.addEmailAddress(address);
- break;
- }
- }
- }
- } finally {
- if (c != null) c.close();
- }
- }
-
- private static void addOrganizationsToContactEntry(ContentResolver cr, long personId,
- ContactEntry entry) throws ParseException {
- Cursor c = cr.query(Organizations.CONTENT_URI, null,
- "person=" + personId, null, null);
- try {
- int companyIndex = c.getColumnIndexOrThrow(Organizations.COMPANY);
- int titleIndex = c.getColumnIndexOrThrow(Organizations.TITLE);
- while (c.moveToNext()) {
- Organization organization = new Organization();
- cursorToContactsElement(organization, c, PROVIDER_TYPE_TO_ENTRY_ORGANIZATION);
- organization.setName(c.getString(companyIndex));
- organization.setTitle(c.getString(titleIndex));
- entry.addOrganization(organization);
- }
- } finally {
- if (c != null) c.close();
- }
- }
-
- private static void addGroupMembershipToContactEntry(Account account, ContentResolver cr,
- long personId, ContactEntry entry) throws ParseException {
- Cursor c = cr.query(GroupMembership.RAW_CONTENT_URI, null,
- "person=" + personId, null, null);
- try {
- int serverIdIndex = c.getColumnIndexOrThrow(GroupMembership.GROUP_SYNC_ID);
- int localIdIndex = c.getColumnIndexOrThrow(GroupMembership.GROUP_ID);
- while (c.moveToNext()) {
- String serverId = c.getString(serverIdIndex);
- if (serverId == null) {
- final Uri groupUri = ContentUris
- .withAppendedId(Groups.CONTENT_URI, c.getLong(localIdIndex));
- Cursor groupCursor = cr.query(groupUri, new String[]{Groups._SYNC_ID},
- null, null, null);
- try {
- if (groupCursor.moveToNext()) {
- serverId = groupCursor.getString(0);
- }
- } finally {
- groupCursor.close();
- }
- }
- if (serverId == null) {
- // the group hasn't been synced yet, we can't complete this operation since
- // we don't know what server id to use for the group
- throw new ParseException("unable to construct GroupMembershipInfo since the "
- + "group _sync_id isn't known yet, will retry later");
- }
- GroupMembershipInfo groupMembershipInfo = new GroupMembershipInfo();
- String groupId = getCanonicalGroupsFeedForAccount(account) + "/" + serverId;
- groupMembershipInfo.setGroup(groupId);
- groupMembershipInfo.setDeleted(false);
- entry.addGroup(groupMembershipInfo);
- }
- } finally {
- if (c != null) c.close();
- }
- }
-
- private static void addExtensionsToContactEntry(ContentResolver cr, long personId,
- ContactEntry entry) throws ParseException {
- Cursor c = cr.query(Extensions.CONTENT_URI, null, "person=" + personId, null, null);
- try {
- JSONObject jsonObject = new JSONObject();
- int nameIndex = c.getColumnIndexOrThrow(Extensions.NAME);
- int valueIndex = c.getColumnIndexOrThrow(Extensions.VALUE);
- if (c.getCount() == 0) return;
- while (c.moveToNext()) {
- try {
- jsonObject.put(c.getString(nameIndex), c.getString(valueIndex));
- } catch (JSONException e) {
- throw new ParseException("bad key or value", e);
- }
- }
- ExtendedProperty extendedProperty = new ExtendedProperty();
- extendedProperty.setName("android");
- final String jsonString = jsonObject.toString();
- if (jsonString == null) {
- throw new ParseException("unable to convert cursor into a JSON string, "
- + DatabaseUtils.dumpCursorToString(c));
- }
- extendedProperty.setXmlBlob(jsonString);
- entry.addExtendedProperty(extendedProperty);
- } finally {
- if (c != null) c.close();
- }
- }
-
- private static void cursorToContactsElement(ContactsElement element,
- Cursor c, HashMap<Integer, Byte> map) {
- final int typeIndex = c.getColumnIndexOrThrow("type");
- final int labelIndex = c.getColumnIndexOrThrow("label");
- final int isPrimaryIndex = c.getColumnIndexOrThrow("isprimary");
-
- element.setLabel(c.getString(labelIndex));
- element.setType(map.get(c.getInt(typeIndex)));
- element.setIsPrimary(c.getInt(isPrimaryIndex) != 0);
- }
-
- private static void contactsElementToValues(ContentValues values, ContactsElement element,
- HashMap<Byte, Integer> map) {
- values.put("type", map.get(element.getType()));
- values.put("label", element.getLabel());
- values.put("isprimary", element.isPrimary() ? 1 : 0);
- }
-
- /*
- * Takes the entry, casts it to a ContactEntry and executes the appropriate
- * actions on the ContentProvider to represent the entry.
- */
- protected void updateProvider(Feed feed, Long syncLocalId,
- Entry baseEntry, ContentProvider provider, Object syncInfo,
- GDataSyncData.FeedData feedSyncData) throws ParseException {
-
- // This is a hack to delete these incorrectly created contacts named "Starred in Android"
- if (baseEntry instanceof ContactEntry
- && "Starred in Android".equals(baseEntry.getTitle())) {
- Log.i(TAG, "Deleting incorrectly created contact from the server: " + baseEntry);
- GDataServiceClient client = getGDataServiceClient();
- try {
- client.deleteEntry(baseEntry.getEditUri(), getAuthToken());
- } catch (IOException e) {
- Log.i(TAG, " exception while deleting contact: " + baseEntry, e);
- } catch (com.google.wireless.gdata.client.HttpException e) {
- Log.i(TAG, " exception while deleting contact: " + baseEntry, e);
- }
- }
-
- updateProviderImpl(getAccount(), syncLocalId, baseEntry, provider);
- }
-
- protected static void updateProviderImpl(Account account, Long syncLocalId,
- Entry entry, ContentProvider provider) throws ParseException {
- // If this is a deleted entry then add it to the DELETED_CONTENT_URI
- ContentValues deletedValues = null;
- if (entry.isDeleted()) {
- deletedValues = new ContentValues();
- deletedValues.put(SyncConstValue._SYNC_LOCAL_ID, syncLocalId);
- final String id = entry.getId();
- final String editUri = entry.getEditUri();
- if (!TextUtils.isEmpty(id)) {
- deletedValues.put(SyncConstValue._SYNC_ID, lastItemFromUri(id));
- }
- if (!TextUtils.isEmpty(editUri)) {
- deletedValues.put(SyncConstValue._SYNC_VERSION, lastItemFromUri(editUri));
- }
- deletedValues.put(SyncConstValue._SYNC_ACCOUNT, account.name);
- deletedValues.put(SyncConstValue._SYNC_ACCOUNT_TYPE, account.type);
- }
-
- if (entry instanceof ContactEntry) {
- if (deletedValues != null) {
- provider.insert(People.DELETED_CONTENT_URI, deletedValues);
- return;
- }
- updateProviderWithContactEntry(account, syncLocalId, (ContactEntry) entry, provider);
- return;
- }
- if (entry instanceof GroupEntry) {
- if (deletedValues != null) {
- provider.insert(Groups.DELETED_CONTENT_URI, deletedValues);
- return;
- }
- updateProviderWithGroupEntry(account, syncLocalId, (GroupEntry) entry, provider);
- return;
- }
- throw new IllegalArgumentException("unknown entry type, " + entry.getClass().getName());
- }
-
- protected static void updateProviderWithContactEntry(Account account, Long syncLocalId,
- ContactEntry entry, ContentProvider provider) throws ParseException {
- final String name = entry.getTitle();
- final String notes = entry.getContent();
- final String yomiName = entry.getYomiName();
- final String personSyncId = lastItemFromUri(entry.getId());
- final String personSyncVersion = lastItemFromUri(entry.getEditUri());
-
- // Store the info about the person
- ContentValues values = new ContentValues();
- values.put(People.NAME, name);
- values.put(People.NOTES, notes);
- values.put(People.PHONETIC_NAME, yomiName);
- values.put(SyncConstValue._SYNC_ACCOUNT, account.name);
- values.put(SyncConstValue._SYNC_ACCOUNT_TYPE, account.type);
- values.put(SyncConstValue._SYNC_ID, personSyncId);
- values.put(SyncConstValue._SYNC_DIRTY, "0");
- values.put(SyncConstValue._SYNC_LOCAL_ID, syncLocalId);
- values.put(SyncConstValue._SYNC_TIME, personSyncVersion);
- values.put(SyncConstValue._SYNC_VERSION, personSyncVersion);
- Uri personUri = provider.insert(People.CONTENT_URI, values);
-
- // Store the photo information
- final boolean photoExistsOnServer = !TextUtils.isEmpty(entry.getLinkPhotoHref());
- final String photoVersion = lastItemFromUri(entry.getLinkEditPhotoHref());
- values.clear();
- values.put(Photos.PERSON_ID, ContentUris.parseId(personUri));
- values.put(Photos.EXISTS_ON_SERVER, photoExistsOnServer ? 1 : 0);
- values.put(SyncConstValue._SYNC_ACCOUNT, account.name);
- values.put(SyncConstValue._SYNC_ACCOUNT_TYPE, account.type);
- values.put(SyncConstValue._SYNC_ID, personSyncId);
- values.put(SyncConstValue._SYNC_DIRTY, 0);
- values.put(SyncConstValue._SYNC_LOCAL_ID, syncLocalId);
- values.put(SyncConstValue._SYNC_TIME, photoVersion);
- values.put(SyncConstValue._SYNC_VERSION, photoVersion);
- if (provider.insert(Photos.CONTENT_URI, values) == null) {
- Log.e(TAG, "error inserting photo row, " + values);
- }
-
- // Store each email address
- for (Object object : entry.getEmailAddresses()) {
- EmailAddress email = (EmailAddress) object;
- values.clear();
- contactsElementToValues(values, email, ENTRY_TYPE_TO_PROVIDER_EMAIL);
- values.put(ContactMethods.DATA, email.getAddress());
- values.put(ContactMethods.KIND, Contacts.KIND_EMAIL);
- Uri uri = Uri.withAppendedPath(personUri, People.ContactMethods.CONTENT_DIRECTORY);
- provider.insert(uri, values);
- }
-
- // Store each postal address
- for (Object object : entry.getPostalAddresses()) {
- PostalAddress address = (PostalAddress) object;
- values.clear();
- contactsElementToValues(values, address, ENTRY_TYPE_TO_PROVIDER_POSTAL);
- values.put(ContactMethods.DATA, address.getValue());
- values.put(ContactMethods.KIND, Contacts.KIND_POSTAL);
- Uri uri = Uri.withAppendedPath(personUri, People.ContactMethods.CONTENT_DIRECTORY);
- provider.insert(uri, values);
- }
-
- // Store each im address
- for (Object object : entry.getImAddresses()) {
- ImAddress address = (ImAddress) object;
- values.clear();
- contactsElementToValues(values, address, ENTRY_TYPE_TO_PROVIDER_IM);
- values.put(ContactMethods.DATA, address.getAddress());
- values.put(ContactMethods.KIND, Contacts.KIND_IM);
- final byte protocolType = address.getProtocolPredefined();
- if (protocolType == ImAddress.PROTOCOL_NONE) {
- // don't add anything
- } else if (protocolType == ImAddress.PROTOCOL_CUSTOM) {
- values.put(ContactMethods.AUX_DATA,
- ContactMethods.encodeCustomImProtocol(address.getProtocolCustom()));
- } else {
- Integer providerProtocolType =
- ENTRY_IM_PROTOCOL_TO_PROVIDER_PROTOCOL .get(protocolType);
- if (providerProtocolType == null) {
- throw new IllegalArgumentException("unknown protocol type, " + protocolType);
- }
- values.put(ContactMethods.AUX_DATA,
- ContactMethods.encodePredefinedImProtocol(providerProtocolType));
- }
- Uri uri = Uri.withAppendedPath(personUri, People.ContactMethods.CONTENT_DIRECTORY);
- provider.insert(uri, values);
- }
-
- // Store each organization
- for (Object object : entry.getOrganizations()) {
- Organization organization = (Organization) object;
- values.clear();
- contactsElementToValues(values, organization, ENTRY_TYPE_TO_PROVIDER_ORGANIZATION);
- values.put(Organizations.COMPANY, organization.getName());
- values.put(Organizations.TITLE, organization.getTitle());
- values.put(Organizations.COMPANY, organization.getName());
- Uri uri = Uri.withAppendedPath(personUri, Organizations.CONTENT_DIRECTORY);
- provider.insert(uri, values);
- }
-
- // Store each group
- for (Object object : entry.getGroups()) {
- GroupMembershipInfo groupMembershipInfo = (GroupMembershipInfo) object;
- if (groupMembershipInfo.isDeleted()) {
- continue;
- }
- values.clear();
- values.put(GroupMembership.GROUP_SYNC_ACCOUNT, account.name);
- values.put(GroupMembership.GROUP_SYNC_ACCOUNT_TYPE, account.type);
- values.put(GroupMembership.GROUP_SYNC_ID,
- lastItemFromUri(groupMembershipInfo.getGroup()));
- Uri uri = Uri.withAppendedPath(personUri, GroupMembership.CONTENT_DIRECTORY);
- provider.insert(uri, values);
- }
-
- // Store each phone number
- for (Object object : entry.getPhoneNumbers()) {
- PhoneNumber phone = (PhoneNumber) object;
- values.clear();
- contactsElementToValues(values, phone, ENTRY_TYPE_TO_PROVIDER_PHONE);
- values.put(People.Phones.NUMBER, phone.getPhoneNumber());
- values.put(People.Phones.LABEL, phone.getLabel());
- Uri uri = Uri.withAppendedPath(personUri, People.Phones.CONTENT_DIRECTORY);
- provider.insert(uri, values);
- }
-
- // Store the extended properties
- for (Object object : entry.getExtendedProperties()) {
- ExtendedProperty extendedProperty = (ExtendedProperty) object;
- if (!"android".equals(extendedProperty.getName())) {
- continue;
- }
- JSONObject jsonObject = null;
- try {
- jsonObject = new JSONObject(extendedProperty.getXmlBlob());
- } catch (JSONException e) {
- Log.w(TAG, "error parsing the android extended property, dropping, entry is "
- + entry.toString());
- continue;
- }
- Iterator jsonIterator = jsonObject.keys();
- while (jsonIterator.hasNext()) {
- String key = (String)jsonIterator.next();
- values.clear();
- values.put(Extensions.NAME, key);
- try {
- values.put(Extensions.VALUE, jsonObject.getString(key));
- } catch (JSONException e) {
- // this should never happen, since we just got the key from the iterator
- }
- Uri uri = Uri.withAppendedPath(personUri, People.Extensions.CONTENT_DIRECTORY);
- if (null == provider.insert(uri, values)) {
- Log.e(TAG, "Error inserting extension into provider, uri "
- + uri + ", values " + values);
- }
- }
- break;
- }
- }
-
- protected static void updateProviderWithGroupEntry(Account account, Long syncLocalId,
- GroupEntry entry, ContentProvider provider) throws ParseException {
- ContentValues values = new ContentValues();
- values.put(Groups.NAME, entry.getTitle());
- values.put(Groups.NOTES, entry.getContent());
- values.put(Groups.SYSTEM_ID, entry.getSystemGroup());
- values.put(Groups._SYNC_ACCOUNT, account.name);
- values.put(Groups._SYNC_ACCOUNT_TYPE, account.type);
- values.put(Groups._SYNC_ID, lastItemFromUri(entry.getId()));
- values.put(Groups._SYNC_DIRTY, 0);
- values.put(Groups._SYNC_LOCAL_ID, syncLocalId);
- final String editUri = entry.getEditUri();
- final String syncVersion = editUri == null ? null : lastItemFromUri(editUri);
- values.put(Groups._SYNC_TIME, syncVersion);
- values.put(Groups._SYNC_VERSION, syncVersion);
- provider.insert(Groups.CONTENT_URI, values);
- }
-
- private static String lastItemFromUri(String url) {
- return url.substring(url.lastIndexOf('/') + 1);
- }
-
- protected void savePhoto(long person, InputStream photoInput, String photoVersion)
- throws IOException {
- try {
- ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
- byte[] data = new byte[1024];
- while(true) {
- int bytesRead = photoInput.read(data);
- if (bytesRead < 0) break;
- byteStream.write(data, 0, bytesRead);
- }
-
- ContentValues values = new ContentValues();
- // we have to include this here otherwise the provider will set it to 1
- values.put(Photos._SYNC_DIRTY, 0);
- values.put(Photos.LOCAL_VERSION, photoVersion);
- values.put(Photos.DATA, byteStream.toByteArray());
- Uri photoUri = Uri.withAppendedPath(People.CONTENT_URI,
- "" + person + "/" + Photos.CONTENT_DIRECTORY);
- if (getContext().getContentResolver().update(photoUri, values,
- "_sync_dirty=0", null) > 0) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "savePhoto: updated " + photoUri + " with values " + values);
- }
- } else {
- Log.e(TAG, "savePhoto: update of " + photoUri + " with values " + values
- + " affected no rows");
- }
- } finally {
- try {
- if (photoInput != null) photoInput.close();
- } catch (IOException e) {
- // we don't care about exceptions here
- }
- }
- }
-
- /**
- * Make sure the contacts subscriptions we expect based on the current
- * accounts are present and that there aren't any extra subscriptions
- * that we don't expect.
- */
- @Override
- public void onAccountsChanged(Account[] accountsArray) {
- if (!"yes".equals(SystemProperties.get("ro.config.sync"))) {
- return;
- }
-
- ContentResolver cr = getContext().getContentResolver();
- for (Account account : accountsArray) {
- // TODO(fredq) should be using account instead of null
- String value = Contacts.Settings.getSetting(cr, null,
- Contacts.Settings.SYNC_EVERYTHING);
- if (value == null) {
- // TODO(fredq) should be using account instead of null
- Contacts.Settings.setSetting(cr, null, Contacts.Settings.SYNC_EVERYTHING, "1");
- }
- updateSubscribedFeeds(cr, account);
- }
- }
-
- /**
- * Returns the contacts feed url for a specific account.
- * @param account The account
- * @return The contacts feed url for a specific account.
- */
- public static String getContactsFeedForAccount(Account account) {
- String url = CONTACTS_FEED_URL + account.name + "/base2_property-android";
- return rewriteUrlforAccount(account, url);
- }
-
- /**
- * Returns the contacts group feed url for a specific account.
- * @param account The account
- * @param groupSyncId The group id
- * @return The contacts feed url for a specific account and group.
- */
- public static String getContactsFeedForGroup(Account account, String groupSyncId) {
- String groupId = getCanonicalGroupsFeedForAccount(account);
- try {
- groupId = URLEncoder.encode(groupId, "utf-8");
- } catch (UnsupportedEncodingException e) {
- throw new IllegalArgumentException("unable to url encode group: " + groupId);
- }
- return getContactsFeedForAccount(account) + "?group=" + groupId + "/" + groupSyncId;
- }
-
- /**
- * Returns the groups feed url for a specific account.
- * @param account The account
- * @return The groups feed url for a specific account.
- */
- public static String getGroupsFeedForAccount(Account account) {
- String url = GROUPS_FEED_URL + account.name + "/base2_property-android";
- return rewriteUrlforAccount(account, url);
- }
-
- /**
- * Returns the groups feed url for a specific account that should be
- * used as the foreign reference to this group, e.g. in the
- * group membership element of the ContactEntry. The canonical groups
- * feed always uses http (so it doesn't need to be rewritten) and it always
- * uses the base projection.
- * @param account The account
- * @return The groups feed url for a specific account.
- */
- public static String getCanonicalGroupsFeedForAccount(Account account) {
- return GROUPS_FEED_URL + account.name + "/base";
- }
-
- /**
- * Returns the photo feed url for a specific account.
- * @param account The account
- * @return The photo feed url for a specific account.
- */
- public static String getPhotosFeedForAccount(Account account) {
- String url = PHOTO_FEED_URL + account.name;
- return rewriteUrlforAccount(account, url);
- }
-
- protected static boolean getFeedReturnsPartialDiffs() {
- return true;
- }
-
- @Override
- protected void updateQueryParameters(QueryParams params, GDataSyncData.FeedData feedSyncData) {
- // we want to get the events ordered by last modified, so we can
- // recover in case we cannot process the entire feed.
- params.setParamValue("orderby", "lastmodified");
- params.setParamValue("sortorder", "ascending");
-
- // set showdeleted so that we get tombstones, only do this when we
- // are doing an incremental sync
- if (params.getUpdatedMin() != null) {
- params.setParamValue("showdeleted", "true");
- }
- }
-
- @Override
- public void onSyncStarting(SyncContext context, Account account, boolean manualSync,
- SyncResult result) {
- mPerformedGetServerDiffs = false;
- mIsManualSync = manualSync;
- mPhotoDownloads = 0;
- mPhotoUploads = 0;
- super.onSyncStarting(context, account, manualSync, result);
- }
-
- @Override
- public void onSyncEnding(SyncContext context, boolean success) {
- final ContentResolver cr = getContext().getContentResolver();
-
- if (success && mPerformedGetServerDiffs && !mSyncCanceled) {
- final Account account = getAccount();
- Cursor cursor = cr.query(
- Photos.CONTENT_URI,
- new String[]{Photos._SYNC_ID, Photos._SYNC_VERSION, Photos.PERSON_ID,
- Photos.DOWNLOAD_REQUIRED}, ""
- + "_sync_account=? AND _sync_account_type=? AND download_required != 0",
- new String[]{account.name, account.type}, null);
- try {
- if (cursor.getCount() != 0) {
- Bundle extras = new Bundle();
- extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, mIsManualSync);
- extras.putString("feed", ContactsSyncAdapter.getPhotosFeedForAccount(account));
- ContentResolver.requestSync(account, Contacts.AUTHORITY, extras);
- }
- } finally {
- cursor.close();
- }
- }
-
- super.onSyncEnding(context, success);
- }
-
- public static void updateSubscribedFeeds(ContentResolver cr, Account account) {
- Set<String> feedsToSync = Sets.newHashSet();
- feedsToSync.add(getGroupsFeedForAccount(account));
- addContactsFeedsToSync(cr, account, feedsToSync);
-
- Cursor c = SubscribedFeeds.Feeds.query(cr, sSubscriptionProjection,
- SubscribedFeeds.Feeds.AUTHORITY + "=?"
- + " AND " + SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?"
- + " AND " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?",
- new String[]{Contacts.AUTHORITY, account.name, account.type}, null);
- try {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "scanning over subscriptions with authority "
- + Contacts.AUTHORITY + " and account " + account);
- }
- c.moveToNext();
- while (!c.isAfterLast()) {
- String feedInCursor = c.getString(1);
- if (feedsToSync.contains(feedInCursor)) {
- feedsToSync.remove(feedInCursor);
- c.moveToNext();
- } else {
- c.deleteRow();
- }
- }
- c.commitUpdates();
- } finally {
- c.close();
- }
-
- // any feeds remaining in feedsToSync need a subscription
- for (String feed : feedsToSync) {
- SubscribedFeeds.addFeed(cr, feed, account, Contacts.AUTHORITY, ContactsClient.SERVICE);
-
- // request a sync of this feed
- Bundle extras = new Bundle();
- extras.putString("feed", feed);
- ContentResolver.requestSync(account, Contacts.AUTHORITY, extras);
- }
- }
-}
diff --git a/src/com/android/providers/contacts/ContactsSyncAdapterService.java b/src/com/android/providers/contacts/ContactsSyncAdapterService.java
deleted file mode 100644
index ee95153..0000000
--- a/src/com/android/providers/contacts/ContactsSyncAdapterService.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.android.providers.contacts;
-
-import android.app.Service;
-import android.os.IBinder;
-import android.content.Intent;
-import android.content.ContentProviderClient;
-import android.content.ContentProvider;
-import android.content.SyncableContentProvider;
-import android.provider.Contacts;
-
-public class ContactsSyncAdapterService extends Service {
- private ContentProviderClient mContentProviderClient = null;
-
- public void onCreate() {
- mContentProviderClient =
- getContentResolver().acquireContentProviderClient(Contacts.CONTENT_URI);
- }
-
- public void onDestroy() {
- mContentProviderClient.release();
- }
-
- public IBinder onBind(Intent intent) {
- ContentProvider contentProvider = mContentProviderClient.getLocalContentProvider();
- if (contentProvider == null) throw new IllegalStateException();
- SyncableContentProvider syncableContentProvider = (SyncableContentProvider)contentProvider;
- return syncableContentProvider.getTempProviderSyncAdapter().getISyncAdapter().asBinder();
- }
-}
diff --git a/src/com/android/providers/contacts/GoogleContactsProvider.java b/src/com/android/providers/contacts/GoogleContactsProvider.java
deleted file mode 100644
index 77bce2c..0000000
--- a/src/com/android/providers/contacts/GoogleContactsProvider.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2008 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.providers.contacts;
-
-import com.google.android.collect.Sets;
-import com.google.android.providers.AbstractGDataSyncAdapter;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SyncContext;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.os.SystemClock;
-import android.provider.Contacts;
-import android.text.TextUtils;
-import android.accounts.Account;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A subclass of the platform contacts provider that adds the Google contacts
- * sync adapter.
- */
-public class GoogleContactsProvider extends ContactsProvider {
- private static final int PURGE_CONTACTS_DELAY_IN_MS = 30000;
- private static final String ACTION_PURGE_CONTACTS =
- "com.android.providers.contacts.PURGE_CONTACTS";
-
- /**
- * SQL query that deletes all contacts for a given account that are not a member of
- * at least one group that has the "should_sync" column set to a non-zero value.
- */
- private static final String PURGE_UNSYNCED_CONTACTS_SQL = ""
- + "DELETE FROM people "
- + "WHERE (_id IN ("
- + " SELECT person "
- + " FROM ("
- + " SELECT MAX(should_sync) AS max_should_sync, person "
- + " FROM ("
- + " SELECT should_sync, person "
- + " FROM groupmembership AS gm "
- + " OUTER JOIN groups AS g "
- + " ON (gm.group_id=g._id "
- + " OR (gm.group_sync_id=g._sync_id "
- + " AND gm.group_sync_account=g._sync_account "
- + " AND gm.group_sync_account_type=g._sync_account_type))) "
- + " GROUP BY person) "
- + " WHERE max_should_sync=0)"
- + " OR _id NOT IN (SELECT person FROM groupmembership))"
- + " AND _sync_dirty=0 "
- + " AND _sync_account=? "
- + " AND _sync_account_type=?";
-
- private AlarmManager mAlarmService = null;
-
- @Override
- public boolean onCreate() {
- setTempProviderSyncAdapter(new ContactsSyncAdapter(getContext(), this));
- BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (ACTION_PURGE_CONTACTS.equals(intent.getAction())) {
- purgeContacts((Account) intent.getParcelableExtra("account"));
- }
- }
- };
- getContext().registerReceiver(receiver, new IntentFilter(ACTION_PURGE_CONTACTS));
- return super.onCreate();
- }
-
- @Override
- protected void onLocalChangesForAccount(final ContentResolver resolver, Account account,
- boolean groupsModified) {
- ContactsSyncAdapter.updateSubscribedFeeds(resolver, account);
- if (groupsModified) {
- schedulePurge(account);
- }
- }
-
- /**
- * Delete any non-sync_dirty contacts associated with the given account
- * that are not in any of the synced groups.
- */
- private void schedulePurge(Account account) {
- if (isTemporary()) {
- throw new IllegalStateException("this must not be called on temp providers");
- }
- ensureAlarmService();
- final Intent intent = new Intent(ACTION_PURGE_CONTACTS);
- intent.putExtra("account", account);
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(
- getContext(), 0 /* ignored */, intent, 0);
- mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + PURGE_CONTACTS_DELAY_IN_MS,
- pendingIntent);
- }
-
- private void ensureAlarmService() {
- if (mAlarmService == null) {
- mAlarmService = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
- }
- }
-
- @Override
- public void onSyncStop(SyncContext context, boolean success) {
- super.onSyncStop(context, success);
- purgeContacts(getSyncingAccount());
- }
-
- private void purgeContacts(Account account) {
- if (isTemporary()) {
- throw new IllegalStateException("this must not be called on temp providers");
- }
- SQLiteDatabase db = getDatabase();
- db.beginTransaction();
- try {
- // TODO(fredq) should be using account instead of null
- final String value = Contacts.Settings.getSetting(getContext().getContentResolver(),
- null, Contacts.Settings.SYNC_EVERYTHING);
- final boolean shouldSyncEverything = !TextUtils.isEmpty(value) && !"0".equals(value);
- if (!shouldSyncEverything) {
- db.execSQL(PURGE_UNSYNCED_CONTACTS_SQL, new String[]{account.name, account.type});
- }
-
- // remove any feeds in the SyncData that aren't in the current sync set.
- Set<String> feedsToSync = Sets.newHashSet();
- feedsToSync.add(ContactsSyncAdapter.getGroupsFeedForAccount(account));
- ContactsSyncAdapter.addContactsFeedsToSync(getContext().getContentResolver(), account,
- feedsToSync);
- AbstractGDataSyncAdapter.GDataSyncData syncData = readSyncData(account);
- if (syncData != null) {
- Iterator<Map.Entry<String, AbstractGDataSyncAdapter.GDataSyncData.FeedData>> iter =
- syncData.feedData.entrySet().iterator();
- boolean updatedSyncData = false;
- while (iter.hasNext()) {
- Map.Entry<String, AbstractGDataSyncAdapter.GDataSyncData.FeedData> entry =
- iter.next();
- if (!feedsToSync.contains(entry.getKey())) {
- iter.remove();
- updatedSyncData = true;
- }
- }
- if (updatedSyncData) {
- writeSyncData(account, syncData);
- }
- }
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
- }
-
- private AbstractGDataSyncAdapter.GDataSyncData readSyncData(Account account) {
- if (!getDatabase().inTransaction()) {
- throw new IllegalStateException("you can only call this from within a transaction");
- }
- Cursor c = getDatabase().query("_sync_state", new String[]{"data"},
- "_sync_account=? AND _sync_account_type=?",
- new String[]{account.name, account.type}, null, null, null);
- try {
- byte[] data = null;
- if (c.moveToNext()) data = c.getBlob(0);
- return ContactsSyncAdapter.newGDataSyncDataFromBytes(data);
- } finally {
- c.close();
- }
- }
-
- private void writeSyncData(Account account, AbstractGDataSyncAdapter.GDataSyncData syncData) {
- final SQLiteDatabase db = getDatabase();
- if (!db.inTransaction()) {
- throw new IllegalStateException("you can only call this from within a transaction");
- }
- db.delete("_sync_state", "_sync_account=? AND _sync_account_type=?",
- new String[]{account.name, account.type});
- ContentValues values = new ContentValues();
- values.put("data", ContactsSyncAdapter.newBytesFromGDataSyncData(syncData));
- values.put("_sync_account", account.name);
- values.put("_sync_account_type", account.type);
- db.insert("_sync_state", "_sync_account", values);
- }
-}
-
diff --git a/tests/Android.mk b/tests/Android.mk
deleted file mode 100644
index 7a93ffd..0000000
--- a/tests/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
-LOCAL_PACKAGE_NAME := GoogleContactsProviderTests
-LOCAL_CERTIFICATE := shared
-
-LOCAL_INSTRUMENTATION_FOR := GoogleContactsProvider
-
-include $(BUILD_PACKAGE)
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
deleted file mode 100644
index c06a5e6..0000000
--- a/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.providers.contactstests"
- android:sharedUserId="android.uid.shared">
-
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <uses-permission android:name="android.permission.READ_CONTACTS" />
- <uses-permission android:name="android.permission.WRITE_CONTACTS" />
- <uses-permission android:name="android.permission.USE_CREDENTIALS" />
- <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
- <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
- <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
- <uses-permission android:name="android.permission.READ_SYNC_STATS" />
-
- <instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.providers.contacts"
- android:label="ContactsProvider Isolated Tests">
- </instrumentation>
-
- <instrumentation android:name="SyncContactsInstrumentation"
- android:targetPackage="com.android.providers.contacts"
- android:label="Contacts Sync Test">
- </instrumentation>
-
-</manifest>
diff --git a/tests/src/com/android/providers/contacts/ContactsSyncAdapterTest.java b/tests/src/com/android/providers/contacts/ContactsSyncAdapterTest.java
deleted file mode 100644
index 018907a..0000000
--- a/tests/src/com/android/providers/contacts/ContactsSyncAdapterTest.java
+++ /dev/null
@@ -1,870 +0,0 @@
-package com.android.providers.contacts;
-
-import com.google.wireless.gdata.contacts.data.ContactEntry;
-import com.google.wireless.gdata.contacts.data.EmailAddress;
-import com.google.wireless.gdata.contacts.data.GroupEntry;
-import com.google.wireless.gdata.contacts.data.GroupMembershipInfo;
-import com.google.wireless.gdata.contacts.data.ImAddress;
-import com.google.wireless.gdata.contacts.data.Organization;
-import com.google.wireless.gdata.contacts.data.PhoneNumber;
-import com.google.wireless.gdata.contacts.data.PostalAddress;
-import com.google.wireless.gdata.data.Entry;
-import com.google.wireless.gdata.data.ExtendedProperty;
-import com.google.wireless.gdata.parser.ParseException;
-
-import android.content.ContentProvider;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.SyncContext;
-import android.content.SyncResult;
-import android.content.TempProviderSyncResult;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.net.Uri;
-import android.provider.Contacts;
-import android.provider.Contacts.ContactMethods;
-import android.provider.Contacts.GroupMembership;
-import android.provider.Contacts.Groups;
-import android.provider.Contacts.People;
-import android.provider.Contacts.Photos;
-import android.provider.SyncConstValue;
-import android.test.ProviderTestCase;
-import android.util.Log;
-import android.accounts.Account;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-public class ContactsSyncAdapterTest extends ProviderTestCase<ContactsProvider> {
- private static final Account ACCOUNT = new Account("testaccount@example.com", "example.type");
-
- private MockSyncContext mMockSyncContext = new MockSyncContext();
- private ContactsSyncAdapter mSyncAdapter = null;
-
- public ContactsSyncAdapterTest() {
- super(ContactsProvider.class, Contacts.AUTHORITY);
- }
-
- public void testUpdateProviderPeople() throws ParseException {
- final ContactsProvider serverDiffs = newTemporaryProvider();
-
- ContactEntry entry1 = newPerson("title1", "note1", "1", "a");
- ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 11L, entry1, serverDiffs);
-
- ContactEntry entry2 = newPerson("title2", "note2", "2", "b");
- ContactsSyncAdapter.updateProviderImpl(ACCOUNT, null, entry2, serverDiffs);
-
- ContactEntry entry3 = newPerson("title3", "note3", "3", "c");
- ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 13L, entry3, serverDiffs);
-
- ContactEntry entry4 = newPerson("title4", "note4", "4", "d");
- entry4.setDeleted(true);
- ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 14L, entry4, serverDiffs);
-
- ContactEntry entry5 = newDeletedPerson("5", "e");
- ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 15L, entry5, serverDiffs);
-
- checkTableIsEmpty(getProvider(), Contacts.ContactMethods.CONTENT_URI);
- checkTableIsEmpty(getProvider(), Contacts.Organizations.CONTENT_URI);
- checkTableIsEmpty(getProvider(), Contacts.Phones.CONTENT_URI);
-
- checkEntries(serverDiffs, false, entry1, 11L, entry2, null, entry3, 13L);
- checkEntries(serverDiffs, true, entry4, 14L, entry5, 15L);
-
- // Convert the provider back to an entry and check that they match
- Cursor cursor;
- cursor = ContactsSyncAdapter.getCursorForTableImpl(serverDiffs, ContactEntry.class);
- try {
- checkNextCursorToEntry(cursor, entry1);
- checkNextCursorToEntry(cursor, entry2);
- checkNextCursorToEntry(cursor, entry3);
- assertTrue(dumpCursor(cursor), cursor.isLast());
- } finally {
- cursor.close();
- }
-
- cursor = ContactsSyncAdapter.getCursorForDeletedTableImpl(serverDiffs, ContactEntry.class);
- try {
- checkNextDeletedCursorToEntry(cursor, entry4);
- checkNextDeletedCursorToEntry(cursor, entry5);
- assertTrue(dumpCursor(cursor), cursor.isLast());
- } finally {
- cursor.close();
- }
- }
-
- public void testUpdateProviderGroups() throws ParseException {
- final ContactsProvider serverDiffs = newTemporaryProvider();
-
- GroupEntry g1 = newGroup("g1", "n1", "i1", "v1");
- ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 21L, g1, serverDiffs);
-
- GroupEntry g2 = newGroup("g2", "n2", "i2", "v2");
- ContactsSyncAdapter.updateProviderImpl(ACCOUNT, null, g2, serverDiffs);
-
- GroupEntry g3 = newGroup("g3", "n3", "i3", "v3");
- g3.setDeleted(true);
- ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 23L, g3, serverDiffs);
-
- GroupEntry g4 = newDeletedGroup("i4", "v4");
- ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 24L, g4, serverDiffs);
-
- // confirm that the entries we expect are in the Groups and DeletedGroups
- // tables
- checkEntries(serverDiffs, false, g1, 21L, g2, null);
- checkEntries(serverDiffs, true, g3, 23L, g4, 24L);
-
- // Convert the provider back to an entry and check that they match
- Cursor cursor;
- cursor = ContactsSyncAdapter.getCursorForTableImpl(serverDiffs, GroupEntry.class);
- try {
- checkNextCursorToEntry(cursor, g1);
- checkNextCursorToEntry(cursor, g2);
- assertTrue(dumpCursor(cursor), cursor.isLast());
- } finally {
- cursor.close();
- }
-
- cursor = ContactsSyncAdapter.getCursorForDeletedTableImpl(serverDiffs, GroupEntry.class);
- try {
- checkNextDeletedCursorToEntry(cursor, g3);
- checkNextDeletedCursorToEntry(cursor, g4);
- assertTrue(dumpCursor(cursor), cursor.isLast());
- } finally {
- cursor.close();
- }
- }
-
- // The temp provider contains groups that mirror the GroupEntries
- // The temp provider contains people rows that mirrow the ContactEntry people portion
- // The temp provider contains groupmembership rows that mirror the group membership info
- // These groupmembership rows have people._id as a foreign key
- // and a group _sync_id, but not as a foreign key
-
- public void testUpdateProviderGroupMembership() throws ParseException {
- final ContactsProvider serverDiffs = newTemporaryProvider();
-
- ContactEntry p = newPerson("p1", "pn1", "pi1", "pv1");
-
- addGroupMembership(p, ACCOUNT, "gsi1");
- ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 31L, p, serverDiffs);
-
- // The provider should now have:
- // - a row in the people table
- // - a row in the groupmembership table
-
- checkEntries(serverDiffs, false, p, 31L);
-
- checkTableIsEmpty(serverDiffs, ContactsProvider.sPeopleTable);
- checkTableIsEmpty(serverDiffs, ContactsProvider.sGroupmembershipTable);
-
- // copy the server diffs into the provider
- getProvider().merge(mMockSyncContext, serverDiffs, null, new SyncResult());
- getProvider().getDatabase().execSQL("UPDATE people SET _sync_dirty=1");
- ContentProvider clientDiffs = getClientDiffs();
-
- // Convert the provider back to an entry and check that they match
- Cursor cursor = ContactsSyncAdapter.getCursorForTableImpl(clientDiffs, ContactEntry.class);
- try {
- checkNextCursorToEntry(cursor, p);
- assertTrue(dumpCursor(cursor), cursor.isLast());
- } finally {
- cursor.close();
- }
- }
-
- private static void addGroupMembership(ContactEntry p, Account account, String groupId) {
- GroupMembershipInfo groupInfo = new GroupMembershipInfo();
- final String serverId =
- ContactsSyncAdapter.getCanonicalGroupsFeedForAccount(account) + "/" + groupId;
- groupInfo.setGroup(serverId);
- p.addGroup(groupInfo);
- }
-
- public void testUpdateProviderContactMethods() throws ParseException {
- final String entryTitle = "title1";
- ContactEntry entry = newPerson(entryTitle, "note1", "2", "3");
-
- addEmail(entry, "a11111", false, EmailAddress.TYPE_HOME, null);
- addEmail(entry, "a22222", true, EmailAddress.TYPE_WORK, null);
- addEmail(entry, "a33333", false, EmailAddress.TYPE_OTHER, null);
- addEmail(entry, "a44444", false, EmailAddress.TYPE_NONE, "lucky");
-
- addPostal(entry, "b11111", false, PostalAddress.TYPE_HOME, null);
- addPostal(entry, "b22222", false, PostalAddress.TYPE_WORK, null);
- addPostal(entry, "b33333", true, PostalAddress.TYPE_OTHER, null);
- addPostal(entry, "b44444", false, PostalAddress.TYPE_NONE, "lucky");
-
- addIm(entry, "c11111", ImAddress.PROTOCOL_CUSTOM, "p1", false, ImAddress.TYPE_HOME, null);
- addIm(entry, "c22222", ImAddress.PROTOCOL_NONE, null, true, ImAddress.TYPE_WORK, null);
- addIm(entry, "c33333", ImAddress.PROTOCOL_SKYPE, null, false, ImAddress.TYPE_OTHER, null);
- addIm(entry, "c44444", ImAddress.PROTOCOL_ICQ, null, false, ImAddress.TYPE_NONE, "l2");
-
- final ContactsProvider provider = newTemporaryProvider();
- ContactsSyncAdapter.updateProviderImpl(ACCOUNT, null, entry, provider);
-
- checkTableIsEmpty(getProvider(), Contacts.Phones.CONTENT_URI);
- checkTableIsEmpty(getProvider(), Contacts.Organizations.CONTENT_URI);
-
- long personId = getSinglePersonId(provider, entryTitle);
-
- Cursor cursor;
- cursor = provider.query(Contacts.ContactMethods.CONTENT_URI, null, null, null,
- Contacts.ContactMethods.DATA);
- try {
- checkNextEmail(cursor, personId, "a11111",
- false, Contacts.ContactMethods.TYPE_HOME, null);
- checkNextEmail(cursor, personId, "a22222",
- true, Contacts.ContactMethods.TYPE_WORK, null);
- checkNextEmail(cursor, personId, "a33333",
- false, Contacts.ContactMethods.TYPE_OTHER, null);
- checkNextEmail(cursor, personId, "a44444",
- false, Contacts.ContactMethods.TYPE_CUSTOM, "lucky");
-
- checkNextPostal(cursor, personId, "b11111",
- false, Contacts.ContactMethods.TYPE_HOME, null);
- checkNextPostal(cursor, personId, "b22222",
- false, Contacts.ContactMethods.TYPE_WORK, null);
- checkNextPostal(cursor, personId, "b33333",
- true, Contacts.ContactMethods.TYPE_OTHER, null);
- checkNextPostal(cursor, personId, "b44444",
- false, Contacts.ContactMethods.TYPE_CUSTOM, "lucky");
-
- checkNextIm(cursor, personId, "c11111", ContactMethods.encodeCustomImProtocol("p1"),
- false, Contacts.ContactMethods.TYPE_HOME, null);
- checkNextIm(cursor, personId, "c22222", null,
- true, Contacts.ContactMethods.TYPE_WORK, null);
- checkNextIm(cursor, personId, "c33333",
- ContactMethods.encodePredefinedImProtocol(ContactMethods.PROTOCOL_SKYPE),
- false, Contacts.ContactMethods.TYPE_OTHER, null);
- checkNextIm(cursor, personId, "c44444",
- ContactMethods.encodePredefinedImProtocol(ContactMethods.PROTOCOL_ICQ),
- false, Contacts.ContactMethods.TYPE_CUSTOM, "l2");
-
- assertTrue(dumpCursor(cursor), cursor.isLast());
- } finally {
- cursor.close();
- }
-
- checkCursorToEntry(provider, entry);
- }
-
- public void testUpdateProviderPhones() throws ParseException {
- final String entryTitle = "title1";
- ContactEntry entry = newPerson(entryTitle, "note1", "2", "3");
- addPhoneNumber(entry, "11111", false, PhoneNumber.TYPE_HOME, null);
- addPhoneNumber(entry, "22222", false, PhoneNumber.TYPE_HOME_FAX, null);
- addPhoneNumber(entry, "33333", false, PhoneNumber.TYPE_MOBILE, null);
- addPhoneNumber(entry, "44444", true, PhoneNumber.TYPE_PAGER, null);
- addPhoneNumber(entry, "55555", false, PhoneNumber.TYPE_WORK, null);
- addPhoneNumber(entry, "66666", false, PhoneNumber.TYPE_WORK_FAX, null);
- addPhoneNumber(entry, "77777", false, PhoneNumber.TYPE_OTHER, null);
- addPhoneNumber(entry, "88888", false, PhoneNumber.TYPE_NONE, "lucky");
- final ContactsProvider provider = newTemporaryProvider();
- ContactsSyncAdapter.updateProviderImpl(ACCOUNT, null, entry, provider);
-
- checkTableIsEmpty(getProvider(), Contacts.ContactMethods.CONTENT_URI);
- checkTableIsEmpty(getProvider(), Contacts.Organizations.CONTENT_URI);
-
- long personId = getSinglePersonId(provider, entryTitle);
-
- Cursor cursor;
- cursor = provider.query(Contacts.Phones.CONTENT_URI, null, null, null,
- Contacts.Phones.NUMBER);
- try {
- checkNextNumber(cursor, personId, "11111", false, Contacts.Phones.TYPE_HOME, null);
- checkNextNumber(cursor, personId, "22222", false, Contacts.Phones.TYPE_FAX_HOME, null);
- checkNextNumber(cursor, personId, "33333", false, Contacts.Phones.TYPE_MOBILE, null);
- checkNextNumber(cursor, personId, "44444", true, Contacts.Phones.TYPE_PAGER, null);
- checkNextNumber(cursor, personId, "55555", false, Contacts.Phones.TYPE_WORK, null);
- checkNextNumber(cursor, personId, "66666", false, Contacts.Phones.TYPE_FAX_WORK, null);
- checkNextNumber(cursor, personId, "77777", false, Contacts.Phones.TYPE_OTHER, null);
- checkNextNumber(cursor, personId, "88888", false, Contacts.Phones.TYPE_CUSTOM, "lucky");
- assertTrue(dumpCursor(cursor), cursor.isLast());
- } finally {
- cursor.close();
- }
-
- checkCursorToEntry(provider, entry);
- }
-
- public void testUpdateProviderOrganization() throws ParseException {
- final String entryTitle = "title1";
- ContactEntry entry = newPerson(entryTitle, "note1", "2", "3");
- addOrganization(entry, "11111", "title1", true, Organization.TYPE_WORK, null);
- addOrganization(entry, "22222", "title2", false, Organization.TYPE_OTHER, null);
- addOrganization(entry, "33333", "title3", false, Organization.TYPE_NONE, "label1");
- final ContactsProvider provider = newTemporaryProvider();
- ContactsSyncAdapter.updateProviderImpl(ACCOUNT, null, entry, provider);
-
- checkTableIsEmpty(getProvider(), Contacts.ContactMethods.CONTENT_URI);
- checkTableIsEmpty(getProvider(), Contacts.Phones.CONTENT_URI);
-
- long personId = getSinglePersonId(provider, entryTitle);
-
- Cursor cursor;
- cursor = provider.query(Contacts.Organizations.CONTENT_URI, null, null, null,
- Contacts.Organizations.COMPANY);
- try {
- checkNextOrganization(cursor, personId, "11111", "title1", true,
- Contacts.Organizations.TYPE_WORK, null);
- checkNextOrganization(cursor, personId, "22222", "title2", false,
- Contacts.Organizations.TYPE_OTHER, null);
- checkNextOrganization(cursor, personId, "33333", "title3", false,
- Contacts.Organizations.TYPE_CUSTOM, "label1");
- assertTrue(dumpCursor(cursor), cursor.isLast());
- } finally {
- cursor.close();
- }
-
- checkCursorToEntry(provider, entry);
- }
-
- public void testUpdateProviderExtensions() throws ParseException {
- final String entryTitle = "title1";
- ContactEntry entry = newPerson(entryTitle, "note1", "2", "3");
- addExtendedProperty(entry, "android", null, "{\"other\":\"that\",\"more\":\"hello.mp3\"}");
- final ContactsProvider provider = newTemporaryProvider();
- ContactsSyncAdapter.updateProviderImpl(ACCOUNT, null, entry, provider);
-
- long personId = getSinglePersonId(provider, entryTitle);
-
- Cursor cursor;
- cursor = provider.query(Contacts.Extensions.CONTENT_URI, null, null, null,
- Contacts.Extensions.NAME);
- try {
- checkNextExtension(cursor, personId, "more", "hello.mp3");
- checkNextExtension(cursor, personId, "other", "that");
- assertTrue(dumpCursor(cursor), cursor.isLast());
- } finally {
- cursor.close();
- }
-
- checkCursorToEntry(provider, entry);
- }
-
- // test writing a photo via the content resolver
- public void testPhotoAccess() throws IOException, InterruptedException {
- // add a person to the real provider
- Uri p = addPerson(getProvider(), ACCOUNT, "si1", "p1");
- Uri ph = Uri.withAppendedPath(p, Contacts.Photos.CONTENT_DIRECTORY);
-
- ContentValues values = new ContentValues();
- values.put(Photos._SYNC_DIRTY, 1);
- values.put(Photos._SYNC_VERSION, "pv1");
- values.put(Photos.LOCAL_VERSION, "pv0");
- getMockContentResolver().update(ph, values, null, null);
- // check that the photos rows look correct
- Cursor cursor = getProvider().getDatabase().query(ContactsProvider.sPhotosTable,
- null, null, null, null, null, null);
- try {
- checkNextPhoto(cursor, true, "pv0", "pv1");
- assertFalse(cursor.moveToNext());
- } finally {
- cursor.close();
- }
-
- values.clear();
- values.put(Photos._SYNC_DIRTY, 0);
- getMockContentResolver().update(ph, values, null, null);
- // check that the photos rows look correct
- cursor = getProvider().getDatabase().query(ContactsProvider.sPhotosTable,
- null, null, null, null, null, null);
- try {
- checkNextPhoto(cursor, false, "pv0", "pv1");
- assertFalse(cursor.moveToNext());
- } finally {
- cursor.close();
- }
-
- // save a downloaded photo for that person using the ContactsSyncAdapter
- byte[] remotePhotoData = "remote photo data".getBytes();
- InputStream photoStream = new ByteArrayInputStream(remotePhotoData);
- mSyncAdapter.savePhoto(ContentUris.parseId(p), photoStream, "pv1");
-
- // check that the photos rows look correct
- cursor = getProvider().getDatabase().query(ContactsProvider.sPhotosTable,
- null, null, null, null, null, null);
- try {
- checkNextPhoto(cursor, false, "pv1", "pv1");
- assertFalse(cursor.moveToNext());
- } finally {
- cursor.close();
- }
-
- InputStream inputStream =
- Contacts.People.openContactPhotoInputStream(getMockContentResolver(), p);
- byte[] inputBytes = new byte[100];
- int totalBytesRead = 0;
- while (true) {
- int numBytesRead = inputStream.read(inputBytes, totalBytesRead,
- inputBytes.length - totalBytesRead);
- if (numBytesRead < 0) break;
- totalBytesRead += numBytesRead;
- }
- inputStream.close();
-
- assertByteArrayEquals(remotePhotoData, inputBytes, totalBytesRead);
- }
-
- private void assertByteArrayEquals(byte[] expected, byte[] actual, int lengthOfActual) {
- assertEquals(expected.length, lengthOfActual);
- for (int i = 0; i < expected.length; i++) assertEquals(expected[i], actual[i]);
- }
-
- private void checkNextPhoto(Cursor cursor, boolean expectedDirty, String expectedLocalVersion,
- String expectedServerVersion) {
- assertTrue(cursor.moveToNext());
- assertEquals(expectedDirty, getLong(cursor, Photos._SYNC_DIRTY) != 0);
- assertEquals(expectedLocalVersion, getString(cursor, Photos.LOCAL_VERSION));
- assertEquals(expectedServerVersion, getString(cursor, Photos._SYNC_VERSION));
- }
-
- private Uri addPerson(ContactsProvider provider, Account account,
- String name, String syncId) {
- ContentValues values = new ContentValues();
- values.put(People.NAME, name);
- values.put(People._SYNC_ACCOUNT, account.name);
- values.put(People._SYNC_ACCOUNT_TYPE, account.type);
- values.put(People._SYNC_ID, syncId);
- return provider.insert(People.CONTENT_URI, values);
- }
-
- private static GroupEntry newGroup(String title, String notes, String id, String version) {
- GroupEntry entry = new GroupEntry();
- entry.setTitle(title);
- entry.setContent(notes);
- entry.setId(ContactsSyncAdapter.getGroupsFeedForAccount(ACCOUNT) + "/" + id);
- entry.setEditUri(entry.getId() + "/" + version);
- return entry;
- }
-
- private static GroupEntry newDeletedGroup(String id, String version) {
- GroupEntry entry = new GroupEntry();
- entry.setDeleted(true);
- entry.setId(ContactsSyncAdapter.getGroupsFeedForAccount(ACCOUNT) + "/" + id);
- entry.setEditUri(entry.getId() + "/" + version);
- return entry;
- }
-
- private static void checkNextGroup(Cursor cursor, GroupEntry entry, Long syncLocalId) {
- assertTrue(cursor.moveToNext());
- assertEquals(dumpRow(cursor), entry.getId(),
- feedFromEntry(entry) + "/" + getString(cursor, SyncConstValue._SYNC_ID));
- assertEquals(dumpRow(cursor), entry.getEditUri(),
- entry.getId() + "/" + getString(cursor, SyncConstValue._SYNC_VERSION));
- assertEquals(dumpRow(cursor), ACCOUNT.name,
- getString(cursor, SyncConstValue._SYNC_ACCOUNT));
- assertEquals(dumpRow(cursor), ACCOUNT.type,
- getString(cursor, SyncConstValue._SYNC_ACCOUNT_TYPE));
- assertEquals(dumpRow(cursor), entry.getTitle(), getString(cursor, Groups.NAME));
- assertEquals(dumpRow(cursor), entry.getSystemGroup(), getString(cursor, Groups.SYSTEM_ID));
- assertEquals(dumpRow(cursor), entry.getContent(), getString(cursor, Groups.NOTES));
- if (syncLocalId != null) {
- assertEquals(dumpRow(cursor),
- syncLocalId, getString(cursor, SyncConstValue._SYNC_LOCAL_ID));
- }
- }
-
- private static ContactEntry newPerson(String title, String notes, String id, String version) {
- ContactEntry entry = new ContactEntry();
- entry.setTitle(title);
- entry.setContent(notes);
- entry.setId(ContactsSyncAdapter.getContactsFeedForAccount(ACCOUNT) + "/" + id);
- entry.setEditUri(entry.getId() + "/" + version);
- entry.setLinkEditPhoto(ContactsSyncAdapter.getContactsFeedForAccount(ACCOUNT)
- + "/" + id + "/v1", "image/jpg");
- return entry;
- }
-
- private static ContactEntry newDeletedPerson(String id, String version) {
- ContactEntry entry = new ContactEntry();
- entry.setDeleted(true);
- entry.setId(ContactsSyncAdapter.getContactsFeedForAccount(ACCOUNT) + "/" + id);
- entry.setEditUri(entry.getId() + "/" + version);
- return entry;
- }
-
- private void checkNextCursorToEntry(Cursor cursor, Entry expectedEntry)
- throws ParseException {
- Entry newEntry = newEmptyEntry(expectedEntry);
- assertTrue(cursor.moveToNext());
- String createUri = ContactsSyncAdapter.cursorToEntryImpl(getMockContentResolver(),
- cursor, newEntry, ACCOUNT);
- // since this is an update the createUri should be null
- assertNull(createUri);
- assertEquals(expectedEntry.getEditUri(), newEntry.getEditUri());
- if (expectedEntry instanceof ContactEntry) {
- ((ContactEntry)newEntry).setLinkEditPhoto(
- ((ContactEntry)expectedEntry).getLinkEditPhotoHref(),
- ((ContactEntry)expectedEntry).getLinkEditPhotoType());
- }
- final String expected = expectedEntry.toString();
- String actual = newEntry.toString();
- assertEquals("\nexpected:\n" + expected + "\nactual:\n" + actual, expected, actual);
- }
-
- private static void checkNextDeletedCursorToEntry(Cursor cursor, Entry expectedEntry)
- throws ParseException {
- Entry newEntry = newEmptyEntry(expectedEntry);
- assertTrue(cursor.moveToNext());
- ContactsSyncAdapter.deletedCursorToEntryImpl(cursor, newEntry, ACCOUNT);
- assertEquals(expectedEntry.getEditUri(), newEntry.getEditUri());
- }
-
- private static Entry newEmptyEntry(Entry expectedEntry) {
- if (expectedEntry instanceof ContactEntry) {
- return new ContactEntry();
- } else {
- return new GroupEntry();
- }
- }
-
- public static String feedFromEntry(Entry expectedEntry) {
- if (expectedEntry instanceof ContactEntry) {
- return ContactsSyncAdapter.getContactsFeedForAccount(ACCOUNT);
- } else {
- return ContactsSyncAdapter.getGroupsFeedForAccount(ACCOUNT);
- }
- }
-
- private static void checkNextPerson(ContactsProvider provider, Cursor cursor,
- ContactEntry entry, Long syncLocalId) {
- assertTrue(cursor.moveToNext());
- assertEquals(dumpRow(cursor), entry.getId(),
- feedFromEntry(entry) + "/" + getString(cursor, SyncConstValue._SYNC_ID));
- assertEquals(dumpRow(cursor), entry.getEditUri(),
- entry.getId() + "/" + getString(cursor, SyncConstValue._SYNC_VERSION));
- assertEquals(dumpRow(cursor), ACCOUNT.name,
- getString(cursor, SyncConstValue._SYNC_ACCOUNT));
- assertEquals(dumpRow(cursor), ACCOUNT.type,
- getString(cursor, SyncConstValue._SYNC_ACCOUNT_TYPE));
- assertEquals(dumpRow(cursor), entry.getTitle(), getString(cursor, People.NAME));
- assertEquals(dumpRow(cursor), entry.getContent(), getString(cursor, People.NOTES));
- if (syncLocalId != null) {
- assertEquals(dumpRow(cursor),
- syncLocalId, getString(cursor, SyncConstValue._SYNC_LOCAL_ID));
- }
-
- Cursor groupCursor = provider.getDatabase().query(ContactsProvider.sGroupmembershipTable,
- null, Contacts.GroupMembership.PERSON_ID + "=?",
- new String[]{getString(cursor, People._ID)}, null, null, null);
- try {
- for (Object object : entry.getGroups()) {
- GroupMembershipInfo groupMembership = (GroupMembershipInfo) object;
- assertTrue(groupCursor.moveToNext());
- assertEquals(groupMembership.getGroup(),
- ContactsSyncAdapter.getCanonicalGroupsFeedForAccount(ACCOUNT) + "/"
- + getString(groupCursor, GroupMembership.GROUP_SYNC_ID));
- }
- assertFalse(groupCursor.moveToNext());
- } finally {
- groupCursor.close();
- }
- }
-
- private static void checkNextDeleted(Cursor cursor, Entry entry, Long syncLocalId) {
- assertTrue(cursor.moveToNext());
- assertEquals(dumpRow(cursor), entry.getId(),
- feedFromEntry(entry) + "/" + getString(cursor, SyncConstValue._SYNC_ID));
- assertEquals(dumpRow(cursor), entry.getEditUri(),
- entry.getId() + "/" + getString(cursor, SyncConstValue._SYNC_VERSION));
- assertEquals(dumpRow(cursor), ACCOUNT.name,
- getString(cursor, SyncConstValue._SYNC_ACCOUNT));
- assertEquals(dumpRow(cursor), ACCOUNT.type,
- getString(cursor, SyncConstValue._SYNC_ACCOUNT_TYPE));
- if (syncLocalId != null) {
- assertEquals(dumpRow(cursor),
- syncLocalId.toString(), getString(cursor, SyncConstValue._SYNC_LOCAL_ID));
- }
- }
-
-
- private ContactsProvider newTemporaryProvider() {
- return (ContactsProvider)getProvider().getTemporaryInstance();
- }
-
- private void copyTempProviderToReal(ContactsProvider provider) {
- // copy the server diffs into the provider
- getProvider().merge(mMockSyncContext, provider, null, new SyncResult());
-
- // clear the _sync_id and _sync_local_id to act as if these are locally inserted
- ContentValues values = new ContentValues();
- values.put(SyncConstValue._SYNC_ID, (String)null);
- values.put(SyncConstValue._SYNC_LOCAL_ID, (String)null);
- values.put(SyncConstValue._SYNC_DIRTY, "1");
- getProvider().getDatabase().update("people", values, null, null);
- }
-
- private void checkCursorToEntry(ContactsProvider provider, ContactEntry entry)
- throws ParseException {
- copyTempProviderToReal(provider);
- final ContentProvider clientDiffsProvider = getClientDiffs();
-
- Cursor cursor = ContactsSyncAdapter.getCursorForTableImpl(clientDiffsProvider,
- entry.getClass());
- try {
- assertTrue(cursor.moveToFirst());
- assertEquals(dumpCursor(cursor), 1, cursor.getCount());
- ContactEntry newEntry = new ContactEntry();
- String editUrl = ContactsSyncAdapter.cursorToEntryImpl(getMockContentResolver(), cursor,
- newEntry, ACCOUNT);
- entry.setId(null);
- entry.setEditUri(null);
- entry.setLinkEditPhoto(null, null);
- final String expected = entry.toString();
- final String actual = newEntry.toString();
- assertEquals("\nexpected:\n" + expected + "\nactual:\n" + actual, expected, actual);
- } finally {
- cursor.close();
- }
- }
-
- private ContentProvider getClientDiffs() {
- // query the provider for the client diffs
- TempProviderSyncResult result = new TempProviderSyncResult();
- getProvider().merge(mMockSyncContext, null, result, new SyncResult());
- return result.tempContentProvider;
- }
-
- private static long getSinglePersonId(ContactsProvider provider, String entryTitle) {
- long personId;
- Cursor cursor;
- cursor = provider.query(People.CONTENT_URI, null, null, null, null);
- try {
- assertTrue(cursor.moveToFirst());
- assertEquals(dumpCursor(cursor), 1, cursor.getCount());
- assertEquals(dumpRow(cursor), entryTitle, getString(cursor, People.NAME));
- personId = getLong(cursor, People._ID);
- } finally {
- cursor.close();
- }
- return personId;
- }
-
- private static String dumpRow(Cursor cursor) {
- return DatabaseUtils.dumpCurrentRowToString(cursor);
- }
-
- private static String dumpCursor(Cursor cursor) {
- return DatabaseUtils.dumpCursorToString(cursor);
- }
-
- private static void checkNextNumber(Cursor cursor, long personId, String number,
- boolean isPrimary, int type, String label) {
- assertTrue(cursor.moveToNext());
- assertEquals(dumpRow(cursor), personId, getLong(cursor, Contacts.Phones.PERSON_ID));
- assertEquals(dumpRow(cursor), number, getString(cursor, Contacts.Phones.NUMBER));
- assertEquals(dumpRow(cursor), type, getLong(cursor, Contacts.Phones.TYPE));
- assertEquals(dumpCursor(cursor), isPrimary,
- getLong(cursor, Contacts.Phones.ISPRIMARY) != 0);
- assertEquals(dumpRow(cursor), label, getString(cursor, Contacts.Phones.LABEL));
- }
-
- private static long getLong(Cursor cursor, String column) {
- return cursor.getLong(cursor.getColumnIndexOrThrow(column));
- }
-
- private static String getString(Cursor cursor, String column) {
- return cursor.getString(cursor.getColumnIndexOrThrow(column));
- }
-
- private static boolean isNull(Cursor cursor, String column) {
- return cursor.isNull(cursor.getColumnIndexOrThrow(column));
- }
-
- private static void checkNextContactMethod(Cursor cursor, long personId, String data,
- String auxData, int kind, boolean isPrimary, int type, String label) {
- assertTrue(cursor.moveToNext());
- assertEquals(dumpRow(cursor), personId, getLong(cursor, Contacts.ContactMethods.PERSON_ID));
- assertEquals(dumpRow(cursor), kind, getLong(cursor, Contacts.ContactMethods.KIND));
- assertEquals(dumpRow(cursor), data, getString(cursor, Contacts.ContactMethods.DATA));
- assertEquals(dumpRow(cursor), auxData, getString(cursor, Contacts.ContactMethods.AUX_DATA));
- assertEquals(dumpCursor(cursor), isPrimary,
- getLong(cursor, Contacts.ContactMethods.ISPRIMARY) != 0);
- assertEquals(dumpRow(cursor), type, getLong(cursor, Contacts.ContactMethods.TYPE));
- assertEquals(dumpRow(cursor), label, getString(cursor, Contacts.ContactMethods.LABEL));
- }
-
- private static void addPhoneNumber(ContactEntry entry, String number, boolean isPrimary,
- byte rel, String label) {
- PhoneNumber phoneNumber = new PhoneNumber();
- phoneNumber.setPhoneNumber(number);
- phoneNumber.setIsPrimary(isPrimary);
- phoneNumber.setType(rel);
- phoneNumber.setLabel(label);
- entry.addPhoneNumber(phoneNumber);
- }
-
- private static void addPostal(ContactEntry entry, String address, boolean isPrimary, byte rel,
- String label) {
- PostalAddress item = new PostalAddress();
- item.setValue(address);
- item.setType(rel);
- item.setLabel(label);
- item.setIsPrimary(isPrimary);
- entry.addPostalAddress(item);
- }
-
- private static void checkNextPostal(Cursor cursor, long personId, String address,
- boolean isPrimary, int type, String label) {
- checkNextContactMethod(cursor, personId, address, null,
- Contacts.KIND_POSTAL, isPrimary, type, label);
- }
-
- private static void addIm(ContactEntry entry, String address, byte protocol,
- String protocolString, boolean isPrimary, byte rel,
- String label) {
- ImAddress item = new ImAddress();
- item.setAddress(address);
- item.setProtocolPredefined(protocol);
- item.setProtocolCustom(protocolString);
- item.setLabel(label);
- item.setType(rel);
- item.setIsPrimary(isPrimary);
- entry.addImAddress(item);
- }
-
- private static void checkNextIm(Cursor cursor, long personId, String address,
- String auxData, boolean isPrimary, int type, String label) {
- checkNextContactMethod(cursor, personId, address, auxData,
- Contacts.KIND_IM, isPrimary, type, label);
- }
-
- private static void addEmail(ContactEntry entry, String address, boolean isPrimary, byte rel,
- String label) {
- EmailAddress item = new EmailAddress();
- item.setAddress(address);
- item.setIsPrimary(isPrimary);
- item.setType(rel);
- item.setLabel(label);
- entry.addEmailAddress(item);
- }
-
- private static void checkNextEmail(Cursor cursor, long personId, String address,
- boolean isPrimary, int type, String label) {
- checkNextContactMethod(cursor, personId, address, null,
- Contacts.KIND_EMAIL, isPrimary, type, label);
- }
-
- private void checkTableIsEmpty(ContactsProvider provider, Uri uri) {
- Cursor cursor;
- cursor = getProvider().query(uri, null, null, null, null);
- try {
- assertEquals(0, cursor.getCount());
- } finally {
- cursor.close();
- }
- }
-
- private void checkTableIsEmpty(ContactsProvider provider, String table) {
- Cursor cursor;
- cursor = getProvider().getDatabase().query(table, null, null, null, null, null, null);
- try {
- assertEquals(DatabaseUtils.dumpCursorToString(cursor), 0, cursor.getCount());
- } finally {
- cursor.close();
- }
- }
-
- private static void addOrganization(ContactEntry entry, String name, String title,
- boolean isPrimary, byte type, String label) {
- Organization organization = new Organization();
- organization.setName(name);
- organization.setTitle(title);
- organization.setIsPrimary(isPrimary);
- organization.setType(type);
- organization.setLabel(label);
- entry.addOrganization(organization);
- }
-
- private static void addExtendedProperty(ContactEntry entry, String name, String value,
- String blob) {
- ExtendedProperty extendedProperty = new ExtendedProperty();
- extendedProperty.setName(name);
- extendedProperty.setValue(value);
- extendedProperty.setXmlBlob(blob);
- entry.addExtendedProperty(extendedProperty);
- }
-
- private static void checkNextOrganization(Cursor cursor, long personId, String company,
- String title, boolean isPrimary, int type, String label) {
- assertTrue(cursor.moveToNext());
- assertEquals(dumpRow(cursor), personId, getLong(cursor, Contacts.Organizations.PERSON_ID));
- assertEquals(dumpRow(cursor), company, getString(cursor, Contacts.Organizations.COMPANY));
- assertEquals(dumpRow(cursor), title, getString(cursor, Contacts.Organizations.TITLE));
- assertEquals(dumpRow(cursor), isPrimary,
- getLong(cursor, Contacts.Organizations.ISPRIMARY) != 0);
- assertEquals(dumpRow(cursor), type, getLong(cursor, Contacts.Phones.TYPE));
- assertEquals(dumpRow(cursor), label, getString(cursor, Contacts.Phones.LABEL));
- }
-
- private static void checkNextExtension(Cursor cursor, long personId,
- String name, String value) {
- assertTrue(cursor.moveToNext());
- assertEquals(dumpRow(cursor), personId, getLong(cursor, Contacts.Extensions.PERSON_ID));
- assertEquals(dumpRow(cursor), name, getString(cursor, Contacts.Extensions.NAME));
- assertEquals(dumpRow(cursor), value, getString(cursor, Contacts.Extensions.VALUE));
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mSyncAdapter = (ContactsSyncAdapter)getProvider().getTempProviderSyncAdapter();
- getProvider().onSyncStart(mMockSyncContext, ACCOUNT);
- }
-
- void checkEntries(ContactsProvider provider, boolean deleted,
- Object ... entriesAndLocalSyncIds) {
- String table;
- String sortOrder = deleted ? "_sync_id" : "name";
- final Entry firstEntry = (Entry)entriesAndLocalSyncIds[0];
- if (firstEntry instanceof GroupEntry) {
- if (deleted) {
- table = ContactsProvider.sDeletedGroupsTable;
- } else {
- table = ContactsProvider.sGroupsTable;
- }
- } else {
- if (deleted) {
- table = ContactsProvider.sDeletedPeopleTable;
- } else {
- table = ContactsProvider.sPeopleTable;
- }
- }
- Cursor cursor;
- cursor = provider.getDatabase().query(table, null, null, null, null, null, sortOrder);
- try {
- for (int i = 0; i < entriesAndLocalSyncIds.length; i += 2) {
- Entry entry = (Entry)entriesAndLocalSyncIds[i];
- Long syncLocalId = (Long)entriesAndLocalSyncIds[i+1];
- if (deleted) {
- checkNextDeleted(cursor, entry, syncLocalId);
- } else {
- if (firstEntry instanceof GroupEntry) {
- checkNextGroup(cursor, (GroupEntry)entry, null);
- } else {
- checkNextPerson(provider, cursor, (ContactEntry)entry, null);
- }
- }
- }
- assertTrue(dumpCursor(cursor), cursor.isLast());
- } finally {
- cursor.close();
- }
- }
-}
-
-class MockSyncContext extends SyncContext {
-
- MockSyncContext() {
- super(null);
- }
-
- @Override
- public void setStatusText(String text) {
- Log.i("SyncTest", text);
- }
-} \ No newline at end of file
diff --git a/tests/src/com/android/providers/contacts/SyncContactsTest.java b/tests/src/com/android/providers/contacts/SyncContactsTest.java
deleted file mode 100644
index 7456bfa..0000000
--- a/tests/src/com/android/providers/contacts/SyncContactsTest.java
+++ /dev/null
@@ -1,142 +0,0 @@
-package com.android.providers.contacts;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.provider.Contacts;
-import android.test.RenamingDelegatingContext;
-import android.test.SyncBaseInstrumentation;
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.OperationCanceledException;
-import android.accounts.AuthenticatorException;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.io.IOException;
-
-import com.google.android.collect.Maps;
-import com.google.android.googlelogin.GoogleLoginServiceConstants;
-
-public class SyncContactsTest extends SyncBaseInstrumentation {
- private Context mTargetContext;
- private String mAccount;
- private static final String PEOPLE_PHONE_JOIN =
- "people LEFT OUTER JOIN phones ON people.primary_phone=phones._id " +
- " LEFT OUTER JOIN contact_methods ON people.primary_email=contact_methods._id" +
- " LEFT OUTER JOIN organizations ON people.primary_organization=organizations._id" +
- " ORDER BY people._sync_id;";
-
- private static final Set<String> PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP = new HashSet<String>();
-
- static {
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.People._ID);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.People.PRIMARY_PHONE_ID);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.People._SYNC_MARK);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.People._SYNC_TIME);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.People._SYNC_LOCAL_ID);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.People._SYNC_VERSION);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.People._SYNC_DIRTY);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.People.TIMES_CONTACTED);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.People.LAST_TIME_CONTACTED);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.Phones._ID);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.Phones.PERSON_ID);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.People.PRIMARY_EMAIL_ID);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.People.PRIMARY_ORGANIZATION_ID);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.People.ContactMethods._ID);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.Organizations.PERSON_ID);
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP.add(Contacts.Organizations._ID);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mTargetContext = getInstrumentation().getTargetContext();
- mAccount = getAccount();
- }
-
- /**
- * A Simple test that syncs the contacts provider.
- * @throws Exception
- */
- public void testSync() throws Exception {
- cancelSyncsandDisableAutoSync();
- syncProvider(Contacts.CONTENT_URI, mAccount, Contacts.AUTHORITY);
- }
-
- private String getAccount() {
- try {
- String[] features = new String[]{GoogleLoginServiceConstants.FEATURE_HOSTED_OR_GOOGLE};
- Account[] accounts = AccountManager.get(mTargetContext).getAccountsByTypeAndFeatures(
- GoogleLoginServiceConstants.ACCOUNT_TYPE, features, null, null).getResult();
- if (accounts.length > 0) {
- return accounts[0].name;
- }
- } catch (OperationCanceledException e) {
- // handle below
- } catch (IOException e) {
- // handle below
- } catch (AuthenticatorException e) {
- // handle below
- }
- return null;
- }
-
- /**
- * This test compares the two contacts databases.
- * This works well with the puppetmaster automated script.
- * @throws Exception
- */
- public void testCompareResults() throws Exception {
- ContactsProvider incrementalContentProvider =
- RenamingDelegatingContext.providerWithRenamedContext(ContactsProvider.class,
- mTargetContext, "", true);
-
- ContactsProvider initialSyncContentProvider =
- RenamingDelegatingContext.providerWithRenamedContext(ContactsProvider.class,
- mTargetContext, "initialsync.", true);
-
- SQLiteDatabase incrementalDb = incrementalContentProvider.getDatabase();
- SQLiteDatabase initialSyncDb = initialSyncContentProvider.getDatabase();
-
- Cursor incrementalPeopleCursor = incrementalDb.rawQuery("select * from " +
- PEOPLE_PHONE_JOIN, null);
- Cursor initialPeopleCursor = initialSyncDb.rawQuery("select * from " +
- PEOPLE_PHONE_JOIN, null);
-
- assertNotSame("Incremental db has no values - check test configuration",
- incrementalPeopleCursor.getCount(), 0);
- try {
- compareCursors(incrementalPeopleCursor, initialPeopleCursor,
- PEOPLE_PHONES_JOIN_COLUMNS_TO_SKIP, "People");
- } finally {
- incrementalPeopleCursor.close();
- initialPeopleCursor.close();
- }
- }
-
- private void compareCursors(Cursor incrementalCursor,
- Cursor initialSyncCursor, Set<String> columnsToSkip,
- String tableName) {
-
- assertEquals(tableName + " count failed to match", incrementalCursor.getCount(),
- initialSyncCursor.getCount());
-
- String[] cols = incrementalCursor.getColumnNames();
- int length = cols.length;
- Map<String,String> row = Maps.newHashMap();
-
- while (incrementalCursor.moveToNext() && initialSyncCursor.moveToNext()) {
- for (int i = 0; i < length; i++) {
- String col = cols[i];
- if (columnsToSkip != null && columnsToSkip.contains(col)) {
- continue;
- }
- row.put(col, incrementalCursor.getString(i));
- assertEquals("Row: " + row + " .Column: " + cols[i] + " failed to match",
- incrementalCursor.getString(i), initialSyncCursor.getString(i));
- }
- }
- }
-}
diff --git a/tests/src/com/android/providers/contactstests/SyncContactsInstrumentation.java b/tests/src/com/android/providers/contactstests/SyncContactsInstrumentation.java
deleted file mode 100644
index 373523d..0000000
--- a/tests/src/com/android/providers/contactstests/SyncContactsInstrumentation.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.android.providers.contactstests;
-
-import com.android.providers.contacts.SyncContactsTest;
-
-import junit.framework.TestSuite;
-
-import android.test.InstrumentationTestRunner;
-import android.test.InstrumentationTestSuite;
-import android.test.suitebuilder.annotation.Suppress;
-
-@Suppress
-public class SyncContactsInstrumentation extends InstrumentationTestRunner {
- public TestSuite getAllTests() {
- TestSuite suite = new InstrumentationTestSuite(this);
- suite.addTestSuite(SyncContactsTest.class);
- return suite;
- }
-
- public ClassLoader getLoader() {
- return SyncContactsTest.class.getClassLoader();
- }
-}